This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430FR2355:I2C 接收 CAN#39;t get working??

Guru**** 2526700 points
Other Parts Discussed in Thread: MSP430FR2355

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1119607/msp430fr2355-i2c-receive-can-t-get-working

器件型号:MSP430FR2355

下面是我的 i2c ISR 代码的两个副本。  第一个副本仅传输、看起来运行良好(我可能已经看到锁定(即数据线被拉低、从未释放一次或两次)。  第二个副本是尝试向其添加接收。  接收只允许一个寄存器读取、写入允许多次写入。  第二个代码块不断崩溃。  我经常只得到时钟输出的地址和 LCD 从机的 NACK……从机有电源,我在 SDA、SCL 线路上有4.75k Ω 的上拉电阻。  主器件是 MSP430FR2355开发板。  问题:

1. 是否有人可以告诉我、我是否通过发出 I2C 停止来适当地处理时钟低电平和 NACK?

2. 有人能告诉我我我是否有任何问题?

仅具有 TX 的 ISR:(请注意、虽然我处理时钟低电平、但我在这里不处理 NACK)

    switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
    {
      case USCI_NONE: break;
      case USCI_I2C_UCALIFG: break;
      case USCI_I2C_UCNACKIFG: break;
      case USCI_I2C_UCSTTIFG: break;
      case USCI_I2C_UCSTPIFG:
          ISR.I2CComplete = T;
          LPM3_EXIT;
          break;
      case USCI_I2C_UCRXIFG3: break;
      case USCI_I2C_UCTXIFG3: break;
      case USCI_I2C_UCRXIFG2: break;
      case USCI_I2C_UCTXIFG2: break;
      case USCI_I2C_UCRXIFG1: break;
      case USCI_I2C_UCTXIFG1: break;
      case USCI_I2C_UCRXIFG0:
        break;
      case USCI_I2C_UCTXIFG0:
          applicationI2C.pSysCommsB->UCBxTXBUF = *pI2CStream;
          pI2CStream++;
          break;
      case USCI_I2C_UCBCNTIFG: break;
      case USCI_I2C_UCCLTOIFG:
          applicationI2C.pSysCommsB->UCBxIFG |= UCSTPIFG;
          break;
      case USCI_I2C_UCBIT9IFG: break;
      default: break;
    }

具有 rcv 功能的 ISR:

    switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
    {
      case USCI_NONE: break;
      case USCI_I2C_UCALIFG: break;
      case USCI_I2C_UCNACKIFG:
          applicationI2C.pSysCommsB->UCBxIFG |= UCSTPIFG;
          break;
      case USCI_I2C_UCSTTIFG: break;
      case USCI_I2C_UCSTPIFG:
          applicationUART.pSysCommsA->UCAxIE |= UCTXIE;
          ISR.I2CComplete = T;
          LPM3_EXIT;
          break;
      case USCI_I2C_UCRXIFG3: break;
      case USCI_I2C_UCTXIFG3: break;
      case USCI_I2C_UCRXIFG2: break;
      case USCI_I2C_UCTXIFG2: break;
      case USCI_I2C_UCRXIFG1: break;
      case USCI_I2C_UCTXIFG1: break;
      case USCI_I2C_UCRXIFG0:
          applicationUART.pSysCommsA->UCAxTXBUF = applicationI2C.pSysCommsB->UCBxRXBUF;
          applicationI2C.pSysCommsB->UCBxIE &= ~UCRXIE0;
          applicationI2C.pSysCommsB->UCBxIFG |= UCSTPIFG;
          break;
      case USCI_I2C_UCTXIFG0:
          if (applicationI2C.pSysCommsB->UCBxCTLW[0] & UCTR)
          {
              applicationI2C.pSysCommsB->UCBxTXBUF = *pI2CStream;
              pI2CStream++;
              /*
               * UART ASCII --> 2 chars
               * a read will be two UART
               * chars representing address
               */
              if (mssgLength < 3)
              {
                  applicationI2C.pSysCommsB->UCBxCTLW[0] &= ~UCTR;
                  applicationI2C.pSysCommsB->UCBxCTLW[0] |= UCTXSTT;
                  applicationI2C.pSysCommsB->UCBxIE &= ~UCTXIE;
              }
          //}
          break;
      case USCI_I2C_UCBCNTIFG: break;
      case USCI_I2C_UCCLTOIFG:
          applicationI2C.pSysCommsB->UCBxIFG |= UCSTPIFG;
          break;
      case USCI_I2C_UCBIT9IFG: break;
      default: break;
    }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    24.3.5.2.2 -

    "一个停止条件要么由自动停止生成产生、要么通过置位 UCTXSTP 位来产生。
    从器件接收到的下一个字节后跟一个 NACK 和一个停止条件。 发生该 NACK
    如果 eUSCI_B 模块当前正在等待 UCBxRXBUF 被读取、则立即执行此操作。"

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    当发送自动停止信号时,在上面的第一个和第二个 ISR (UCASTPx=10)中都使用了。。。。。这是在一个低驱动器中完成的,没有显示。。。。。。但是当我在 UCASTPx=00以上的第二个 ISR 中执行 rcv 时。  我不使用它。  我发送地址+w、寄存器然后地址+读取,应该这会将我放在 ISR 的 Rx 部分,该部分应该会生成时钟。  然后、主器件应在第9个周期生成 NACK。  上面的语句对我没有什么帮助...我在地址+W 阶段之后得到了一个否定应答、这将由从器件而不是主器件生成、而不是等待 UXBxRXBUF 被读取。  您是否建议我在进入此 ISR 之前可能需要清除 Rx 缓冲区、以防它中有垃圾?

    另一个注意事项是、如果我删除了 NACK 中的停止标志设置、我仍然有相同的问题

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您指的是您尚未显示的代码位。 我不能就此发表评论。

    我可以指出、在向 TXBUF 中输入数据后、您无需等待即可发出重新启动命令。 这不会很好地解决问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这是一个要做的事情...谢谢你,我会研究它...我也找到了(通过另一个线程) 使用停止 IFG 在总线上创建停止条件是不正确的,必须使用 UCTXSTP...如果我在代码中将其更改出来,并在 NACK 情况下删除停止,那么我现在似乎可以正常传输...所以现在我将重点介绍这一点 根据您的评论获取数据的发送地址。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Steve、

    从 LCD 发出一个地址 NACK 后、一个重复的 START 或者 STOP 条件应该都是可以接受的。

    对于时钟低电平超时条件、如果 其 MSP 保持总线低电平、我希望能够生成 STOP、但如果其是 I2C 或其他外设器件、您可以看到线路仍然卡滞。 我还看到 过在时钟超时时时 eUSCI 模块被复位的情况、但同样需要注意的是。   

    [~ userid="393571" URL"μ A/support/microcontroller /msp-lust-power-microcontroller 组/msp430/f/msp-lust-microcontroller -forum/1119607/msp430fr2355-i2c-receive-ca-t-get-working"]我经常只得到计时地址并且从 LCD 上拉电阻器、SC75kL 上拉电阻器。。。。。。。。  [/报价]

    您是否在示波器上探测过这些线路? 添加对 NACK 和超时条件的处理是一个好主意、但如果硬件原因导致这种情况、我会谨慎地在软件中解决这一问题。  

    此致、
    Brandon Fisher

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Brandon。。。

    是的,我在总线上有一个逻辑分析器...我似乎看到的问题是(SDA 不是 SCL) LCD 有时会将 SDA 拉低(可能是因为我在代码中做一些错误操作),并且永远不会释放它。  我必须切断 LCD 的电源并将 LCD 电源与接地连接短接、然后再重新供电、我将看到线路再次变高...我的想法????

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我不知道我缺少什么...代码如下所示。  我使用 UART 来捕获字符、并基于我读取或写入 RGB 或 LCD 的第一个字符。  我似乎能够顺利进行写入(在写入时、我使用字节计数器和自动停止)。  但是、当我想读取寄存器(开始、addr + w、从器件 ACK、寄存器地址、从器件 ACK、 重新启动、addr + r、从器件 ACK、从器件发送的数据、主器件 NACK、 STOP)我从不会看到写入地址仅输出读取地址、然后从最后一个写入地址获取两个数据字节。这些字节重复、第一个字节获得 ACK、 第二个字节获得 NACK。   

    例如,我发出一个10345、104ab、105e4 (3次独立写入 RGB,添加3、4、5)...我转到执行读取(303、从地址3读取 RGB) 总线只输出读取地址(C5)、然后输出18个 CLKS、这是 E4数据两次(第一个带有 ACK、第二个带有 NACK)...E4是最后已知的写入地址。

    问题:  

    1. 有人能在我的代码中看到为什么我看不到上面的结构,而只得到我写的最后一个地址的响应吗? (如果我在代码中放置一个断点,我会看到 C4 (写入地址,但没有中断,我只能看到这里的图片)...我得到的只是读取地址,RGB 返回两次数据????  我看不到写入寄存器和重新启动的写入地址。  我看到的最大区别是,当我写入时,我使用字节计数器和自动停止,但当我读取时,我只想读取一个寄存器,所以我手动停止,而不使用字节计数器......

    然而,如果我执行一个写操作看起来一切正常...这里是对 LCD 的多次写操作,它们正在工作(即我看到 LCD 响应)

    代码:

    uint8_t config_I2CGetData(I2C_txHandle_t *p)
    {
        /*
         * Within ISR set up TXIE0 and CNTIE and NACKIE
         */
        uint8_t err = 0;
        if (p->size != 1)
            err = 1;
    
        p->pSysCommsB->UCBxCTLW[0] |= UCSWRST;
        p->pSysCommsB->UCBxCTLW[1] &= ~UCASTP;
        p->pSysCommsB->UCBxCTLW[1] |= UCCLTO_3;
        p->pSysCommsB->UCBxCTLW[0] &= ~UCSWRST;
        p->pSysCommsB->UCBxIFG &= ~(UCTXIFG | UCNACKIFG | UCSTPIFG | UCCLTOIFG | UCRXIFG);
        p->pSysCommsB->UCBxIE |= UCRXIE0 | UCTXIE0 | UCNACKIE | UCSTPIE | UCCLTOIE;
    
        return err;
    }
    
    
    uint8_t config_I2CSendData(I2C_txHandle_t *p)
    {
        /*
         * Within ISR set up TXIE0 and CNTIE and NACKIE
         */
        uint8_t err = 0;
    
        p->pSysCommsB->UCBxCTLW[0] |= UCSWRST;
        p->pSysCommsB->UCBxCTLW[1] |= (UCASTP1 | UCCLTO_3);
        p->pSysCommsB->UCBxTBCNT = (p->size);
        p->pSysCommsB->UCBxCTLW[0] &= ~UCSWRST;
        p->pSysCommsB->UCBxIFG &= ~(UCBCNTIFG | UCTXIFG | UCNACKIFG | UCSTPIFG | UCCLTOIFG);
        p->pSysCommsB->UCBxIE &= ~UCRXIE0;
        p->pSysCommsB->UCBxIE |= UCBCNTIE | UCTXIE0 | UCNACKIE | UCSTPIE | UCCLTOIE;
    
        return err;
    }

    uint8_t sendI2CData(I2C_txHandle_t *pVal, uint8_t addr)
    {
    
        pVal->pSysCommsB = applicationI2C.pSysCommsB;
        pVal->pSysCommsB->UCBxI2CSA = addr;
        pVal->size = mssgLength / 2;
        config_I2CSendData(pVal);
        pVal->pSysCommsB->UCBxCTLW[0] |= UCTR | UCTXSTT;
        return 0;
    }
    
    uint8_t getI2CData(I2C_txHandle_t *pVal, uint8_t addr)
    {
        uint8_t err = 0;
        pVal->pSysCommsB = applicationI2C.pSysCommsB;
        pVal->pSysCommsB->UCBxI2CSA = addr;
        pVal->size = mssgLength / 2;
        if (!(ERR_INIT_LCD == config_I2CGetData(pVal)))
            pVal->pSysCommsB->UCBxCTLW[0] |= UCTR | UCTXSTT;
        else
            err = 1;
        return err;
    }
    

    #pragma vector = USCI_B0_VECTOR
    __interrupt void I2C_ISR(void)
    {
        switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
        {
          case USCI_NONE: break;
          case USCI_I2C_UCALIFG: break;
          case USCI_I2C_UCNACKIFG:
              i2cstate = I2CNACK;
              break;
          case USCI_I2C_UCSTTIFG: break;
          case USCI_I2C_UCSTPIFG:
              applicationUART.pSysCommsA->UCAxIE |= UCTXIE;
              ISR.I2CComplete = T;
              LPM3_EXIT;
              break;
          case USCI_I2C_UCRXIFG3: break;
          case USCI_I2C_UCTXIFG3: break;
          case USCI_I2C_UCRXIFG2: break;
          case USCI_I2C_UCTXIFG2: break;
          case USCI_I2C_UCRXIFG1: break;
          case USCI_I2C_UCTXIFG1: break;
          case USCI_I2C_UCRXIFG0:
              applicationUART.pSysCommsA->UCAxTXBUF = applicationI2C.pSysCommsB->UCBxRXBUF;
              applicationI2C.pSysCommsB->UCBxIE &= ~UCRXIE0;
              applicationI2C.pSysCommsB->UCBxCTLW[0] |= UCTXSTP;
              i2cstate = I2CRX;
              break;
          case USCI_I2C_UCTXIFG0:
              if (applicationI2C.pSysCommsB->UCBxCTLW[0] & UCTR)
              {
                  applicationI2C.pSysCommsB->UCBxTXBUF = *pI2CStream;
                  pI2CStream++;
                  i2cstate = I2CDEFAULT;
                  /*
                   * UART ASCII --> 2 chars
                   * a read will be two UART
                   * chars representing address
                   */
                  if (mssgLength < 3)
                  {
                      applicationI2C.pSysCommsB->UCBxIE &= ~UCTXIE;
                      i2cstate = I2CRESTART;
                      LPM3_EXIT;
                  }
              }
              break;
          case USCI_I2C_UCBCNTIFG: break;
          case USCI_I2C_UCCLTOIFG:
              applicationI2C.pSysCommsB->UCBxCTLW[0] |= UCTXSTP;
              i2cstate = I2CCLK_LOW;
              break;
          case USCI_I2C_UCBIT9IFG: break;
          default: break;
        }
    }
    

    将 UART 消息组合在一起并且 pI2CStream 已填充数据后的主段:(我验证了指针的值是否正确)....  

                else if (buffer[0] == 0x33)
                {
                    getI2CData(&pI2Cdata, RGB_12C_ADDRESS);
                    while ((applicationI2C.pSysCommsB->UCB0STATW_L & UCBBUSY) && (i2cstate != I2CRESTART));
                    applicationI2C.pSysCommsB->UCBxCTLW[0] &= ~UCTR;
                    applicationI2C.pSysCommsB->UCBxCTLW[0] |= UCTXSTT;
                }
    
            }
    
            if (ISR.I2CComplete)
            {
                ISR.I2CComplete = F;
                memset((void *)buffer, 0, sizeof(buffer));
                mssgLength = 0;
                monitor = 0; //re-arm timeout counter
                free(pI2CStream);
                applicationUART.pSysCommsA->UCAxIFG &= ~UCRXIFG;
                applicationUART.pSysCommsA->UCAxIE |= UCRXIE;
            }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    问题已解决....

    事实上、在 TX ISR 中、您必须发送命令、 设置一个标志和中断...这会将你从设置为 txifg 的 ISR 中退出...你回到 TX ISR 中,现在该标志被设置了,你不会发送任何东西,但这次你会更改为主 RCVR 并执行重新启动....