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.

[参考译文] MSP430F247:MSP 低功耗微控制器论坛

Guru**** 655270 points
Other Parts Discussed in Thread: BQ76940, MSP430F247
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1162028/msp430f247-msp-low-power-microcontroller-forum

器件型号:MSP430F247
主题中讨论的其他器件:BQ76940

您好!

我使用247与 I2C 器件 bq76940进行通信。  247无法与 I2C 器件通信。 我已经把这个问题提到了 bq 支持小组很久了。  此过程导致  认为问题在系统的主侧。 我们的设计是使用 msp430f247 MCU 作为 mastor 与 bq76940作为从器件进行通信。 处理 I2C 部分代码的固件来自 ti 命令的演示代码。 下面是我的问题、

调试快照

实际代码如下所示、

静态 INT8_t I2CSendBytes (uint8_t I2CSlaveAddress、uint8_t *数据缓冲区、uint16_t ByteCount、uint16_t * pSentByte)

 uint16_t DelayCounter = 0;
 uint16_t NumberOfBytesSent = 0;
 uint8_t *DataPointer;

 UCB0I2CSA = I2CSlaveAddress;
 DataPointer = pDataBuffer;

 //设置到传输方向,生成起始位
 UCB0CTL1 |= UCTR;
 UCB0CTL1 |= UCTXSTT;
 //等待生成起始条件和发送从机地址
 while (!(IFG2 & UCB0TXIFG))
 {
  DelayCounter ++;
  IF (DelayCounter >= Delay_Limit)
   中断;
 }

 //如果产生起始条件超时,则发送停止位
 IF (DelayCounter >= Delay_Limit)
 {
  *pSentByte = NumberOfBytesSent;
  UCB0CTL1 |= UCTXSTP;
  返回-1;
 }


 //起始位和从器件地址已成功发送,
 //接下来发送数据缓冲区中的所有数据
 for (NumberOfBytesSent = 0;NumberOfBytesSent < ByteCount;NumberOfBytesSent++)
 {
  UCB0TXBUF=*DataPointer;

  DelayCounter = 0;
  //检查字节是否已发送
  while (DelayCounter < DELAY_LIMIT &&(!(IFG2和 UCB0TXIFG)||(UCB0CTL1和 UCTXSTT)))
  {
   DelayCounter++;
  }
  //检查是否发生 NACK 条件
  if (DelayCounter >= delay_limit)
  {
   *pSentByte = NumberOfBytesSent;
   //发送停止条件
   UCB0CTL1 |= UCTXSTP;
   返回-1;
  }

  //此处已成功发送一个字节
  DataPointer++;
 }

 //发送所有数据,清除 TX 标志,发送停止位
 IFG2 &=~UCB0TXIFG;
 UCB0CTL1 |= UCTXSTP;
 DelayCounter = 0;
 while (DelayCounter < DELAY_LIMIT &&((UCB0CTL1 & UCTXSTP)))
 {
  DelayCounter++;
 }
 *pSentByte = NumberOfBytesSent;
 //检查是否发生 NACK 条件
 IF (DelayCounter >= Delay_Limit)
 {
  UCB0CTL1 |= UCSWRST;
  返回-1;
 }
 其他
 返回0;

我的问题是当在中断点停止执行时、为什么 UCTXSTP 位和 UCTXSTT 位 已经置位?

谢谢

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

    1.您的优化级别是什么?

    2.使用此代码时是否遇到任何问题?

    3.您能否使用示波器捕获波形以查看它是否生成停止位?

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

    我看不到您在哪里将 P3.1-2的替代函数设置为 UCB0SDA/SCL、类似于:

    根据  数据表(SLAS547I)表23、> P3SEL |=(BIT1 | BIT2);// P3.1-2作为 UCB0SDA/SCL

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

    您好、Bruce、

    下面是 I2C 的设置

    void I2C_Initialize()

     UCB0CTL1 |= UCSSEL_2+UCSWRST;//启用软件复位,使用 SMCLK 作为 USCI 时钟源
     //UCB0CTL1 |= UCSSEL_1+UCSWRST;//启用软件复位,使用 ACLK 作为 USCI 时钟源
     UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;//设置为 I2C 主控模式
     UCB0BR0 = 20;// 92.16KHz @0.9216MHz 的 Aclk、确保 SCLK 不超过100KHz
     UCB0BR1 = 0;
     UCB0I2CIE = 0;//禁用 NACK、检测到停止条件、检测到启动条件、仲裁丢失中断
     IE2 &=~(UCB0TXIE + UCB0RXIE);//禁用 Tx&Rx 中断
     UCB0CTL1 &=~UCSWRST;//从复位状态释放
     bqI2CError = false;//清除 i2c 故障错误标志
     bqI2CStatusReadError = NO_ACTIVICE_INASIONY_STATUS_4;

    静态空 gpioInit (空)

     P1DIR |= 0xdf;
     P1OUT |= 0;

     P2SEL |= 0x20;
     P2DIR |= 0xf7;
     P2OUT |= 0;

     P3SEL |= 0x36;
     P3DIR |= 0xd9;
     P3OUT = 0;

     P4DIR |= 0xff;
     P4OUT = 0;

     P5SEL |= 0x0F;
     P5DIR |= 0xfa;
     P5OUT =(SPI_CS_BIT+RED_LED_BIT+GRN_LED_BIT);

     P6SEL |= 0xff;
     P6DIR |= 0x00;

    静态空 DCO_init (空)

     //选择最大 DCO 抽头
     DCOCTL = DCO0+DCO1+DCO2;

     //打开 OSC
     _BIC_SR (OSCOFF);

     //RSEL0+RSEL1+RSEL2、选择范围7
     //XTS、HF 模式
     ACLK 的//分频器为2、FRG:921600!!!!!!!!!!!!
     BCSCTL1 =(XTS+XT2OFF+DIV_1+RSEL0+RSEL1+RSEL2);

     //MCLK 源为 DCOCLK
     针对 MCLK 的//Divider 1.
     来自 LFXT1CLK 的//SMCLK 源
     SMCLK 的//Divider:2、FRQ:921600
     //DCO 电阻器选择外部电阻器
     BCSCTL2=DCOR+DIVS0+SELS;

     //当 XTS=1时、LFXT1S_1 1-3MHz 晶振
     BCSCTL3 =(LFXT1S_1 + XCAP_0);

     执行{
      IFG1 &=~OFIFG;
      for (unsigned int i = 255;i>0;i--);
     } while ((IFG1 & OFIFG));

    注意事项

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

    您好、伊斯天、

    这是我的优化设置

    这是捕获的波形、

    您可以在时钟(黄色)或数据(蓝色)上看到没有信号。

    因此、我执行了以原始形式发布的调试过程、

    我发现 UCTXSTT 和 UCTXSTP 位从  I2CSendBytes 例程调用的开始到结束都设置为1、听起来不对。

    我对编译代码没有任何问题。

    最恰当的考虑。

    谢谢

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

    我希望 STT 和 STP 都被置位的原因是之前的操作失败(超时)。 由于 UCTR = 0、该操作大概是读取的。 是否有相应的 I2CReadBytes()?

    此外:在另一个线程中、您说"我使用 TI 评估软件测试了电路板上的 BQ76940、BQ76940运行良好。"  您使用的是哪种 TI 评估软件?

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

    您好、Bruce、

    这是读取 I2C 字节函数

    int8_t I2CReadBytes (uint8_t I2CSlaveAddress、uint8_t *数据缓冲器、uint16_t ExpectedBytes、uint16_t * pNumberOfReceivedBytes)

     uint16_t DelayCounter = 0;
     uint8_t *DataPointer;
     uint16_t * NumberOfReceivedBytesPointer;

     NumberOfReceivedBytesPointer = pNumberOfReceivedBytes;
     *NumberOfReceivedBytesPointer = 0;
     DataPointer = pDataBuffer;
     UCB0I2CSA = I2CSlaveAddress;

     //接收方向上的数据,生成起始条件

     UCB0CTL1 &=~(UCTR);
     UCB0CTL1 |= UCTXSTT;
     while (((UCB0CTL1 & UCTXSTT))
     {
      DelayCounter ++;
      IF (DelayCounter >= Delay_Limit)
      中断;
     }


     如果(DelayCounter >= Delay_Limit || UCB0STAT 和 UCNACKIFG)//检查是否发生 NACK 条件
      返回-1;

     对于(* NumberOfReceivedBytesPointer = 0;* NumberOfReceivedBytesPointer < ExpectedByteNumber;(* NumberOfReceivedBytesPointer)++)
     {
      if (* NumberOfReceivedBytesPointer + 1 = ExpectedByteNumber)
      UCB0CTL1 |= UCTXSTP;
      DelayCounter = 0;
      while (DelayCounter < DELAY_LIMIT &&!(IFG2 & UCB0RXIFG))
      {
       DelayCounter++;
      }

      如果(DelayCounter = delay_limit)
      {
       UCB0CTL1 |= UCSWRST;//如果发生 I2C 超时条件、则复位 I2C 引擎
       返回-1;
      }
      *DataPointer = UCB0RXBUF;
      DataPointer++;
     }

     DelayCounter = 0;
     while (DelayCounter < DELAY_LIMIT &&(UCB0CTL1 & UCTXSTP))
     {
      DelayCounter++;
     }

     IF (DelayCounter >= Delay_Limit)
     {
      UCB0CTL1 |= UCSWRST;
      返回-1;
     }
     返回0;

    INT8_t I2CReadRegisterByteWithCRC (uint8_t I2CSlaveAddress、uint8_t 寄存器、uint8_t *数据)

     UINT8_t TargetRegister =寄存器;
     uint16_t SentByte = 0;
     uint8_t ReadData[2];
     uint16_t ReadDataCount = 0;
     uint8_t CRCInput[2];
     uint8_t CRC = 0;
     INT8_t ReadStatus = 0;
     INT8_t WriteStatus = 0;

     WriteStatus = I2CSendBytes (I2CSlaveAddress、&TargetRegister、1、&SentByte);

     ReadStatus = I2CReadBytes (I2CSlaveAddress、ReadData、2、ReadDataCount);

     if (ReadStatus!= 0 || WriteStatus!= 0)
     {
      返回-1;
     }

     CRCInput[0]=(I2CSlaveAddress << 1)+ 1;
     CRCInput[1]= ReadData[0];

     CRC = CRC8 (CRCINPIN、2、CRC_KEY);

     if (CRC!= ReadData[1])
      返回-1;

     *数据= ReadData[0];
     返回0;

    从上面可以看到、无论您执行写入寄存器还是读取寄存器操作、  I2CSendBytes (I2CSlaveAddress、&TargetRegister、1、&SentByte)函 数始终被首先调用。 因此、我不同意 STT 位和 STP 位是由之前的读取操作置位的。

    这是我使用的 bq769x0评估软件

    最恰当的考虑

    谢谢

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

    硬件不会自行设置 TXSTT 或 TXSTP、因此您的程序中必须包含一些内容。 由于您在设置任何一个之前显示的呼叫(调试器屏幕)已停止、因此它必须是之前的呼叫。

    超时请求的技巧是、您永远不知道总线处于什么状态。 因此、如果一个操作失败、下一个操作可能会启动/超时/停止并继续执行、从而保持 TXSTT 和 TXSTP 的设置。 因此、捕获第一个故障(可能是第一个事务)很有用。

    此外、如果在停止(TXSTP)仍处于挂起状态时请求启动(TXSTT)、则 EUSCI (因此我怀疑 USCI) I2C 单元有问题; 当我在 EUSCI 中看到这种情况时、总线会被卡住、SCL (正如我回忆的那样)处于低电平、但运行方式可能与 USCI 略有不同。

    看起来您正在  从 ISR 发出 I2C 请求(通过 BqGetRegisterByte 和 BqSetRegisterByte)。 您是否确信在运行另一个事务时永远不会发生这种情况?

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

    您好、Bruce、

    这是第一个被捕获的事务,

    正如您描述的、这两个位是通过对自身进行编程来设置的、我跟踪 了 UCB0CTL1寄存器的值。

    然后出现问题、正如菜单所说、

    1>当 START 位置位时、i2c 模块将生成星型条件并发送从器件地址字节、并且在 START 条件和地址信息发送完成后、START 位将自动清零。

    2>.当停止位被置位时、i2c 模块将生成停止条件 、 并且在生成停止后 UCTXSTP 将自动清零。

     I2C 模块为什么不自动清除这两个位? 是否因为从器件没有应答而产生?  硬件问题?

    在绿色的断点处失败的点、主要原因是 UCB0TXIFG 未设置。

    我确实看到了到中断点之间的 IFG2寄存器解决方案变化

    有什么建议吗?

    请注意、

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

    您好、Bruce、

    我很确定我没有使用任何与 I2C 相关的中断。

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

    您好、Bruce、

    我有一个 ISR、

    //port1中断服务例程
    #pragma vector=Port1_vector
    _interrupt void ISR_PORT_1 (void)

     中频(P1IFG 和 BIT5)
     {
      //读取 SYS_STAT 字节
      bqI2CError = no_significance;
      bqStatus.StatusByte = BqGetRegisterByte (SYS_STAT);
      bqI2CStatusReadError = bqI2CError;
      BqSetRegisterByte (SYS_STAT、STAT_CC_READY);
      P1IFG &=~BIT4;//清除中断标志
     }

    我在执行调试时禁用 ISR。

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

    如果 TXSTT 或 TXSTP 未自动清零、则表明总线出现了错误、从而导致启动或停止设置。 (I2C 单元有一个总线监视器、此监视器检查其总线操作是否有效。) 这与您的始终高范围跟踪一起、是我第一次怀疑您忘记了 P3SEL 位的原因。

    "有问题"涵盖了许多情况、通常的嫌疑人是(1)缺少上拉电阻(2)物理断开连接(3) SDA 和/或 SCL 保持低电平。

    当您使用 TI GUI 时、您如何进入电路板? 我在您发布的原理图片段中看不到任何跳线。

    delay_limit 和 I2CSlaveAddress 设置为什么?

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

    您好、Bruce、

     DELAY_LIMIT 为0xFFFF、从器件地址为8。

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

    您似乎甚至没有成功发送 I2C 地址。 我想尝试一下这个示例代码、看看您是否可以在 bus.e2e.ti.com/.../msp430x24x_5F00_uscib0_5F00_i2c_5F00_01.ce2e.ti.com/.../msp430x24x_5F00_uscib0_5F00_i2c_5F00_04.c 上捕获一些波形

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

    我刚刚注意到、您的示波器跟踪显示"1.00kS/s"。 是这样吗? 在100kHz 时钟下,一个字节大约需要(8+1)*0.01ms,因此您可以将整个事务处理时间调整为1ms。

    是否有办法在您的范围上提高分辨率? 或者(或许更简单?) 通过设置例如 br0=100、将总线减慢。

    TXSTT/TXSTP 的行为仍然表明总线有问题、但较高的"放大倍数"可能会告诉我们一些问题。

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

    Bruce、奕迅、

    我有一个好消息。 现在有人在说。 事实证明、问题出在时钟设置中。  最初 SMCLK 源 来自外部晶振、然后 SMCLK 被选为 I2C 时钟。 这不适用于 I2C 功能。 我从 DCO 获取 SMCLK 源、然后我仍然选择 SMCLK 作为 I2C 时钟、这是正常工作的。

    最后、我使用 ACLK 作为 I2C 时钟、它也在工作。  在此线程可以关闭之前、我仍然有一个问题。

    在我的固件中、有一个中断例程来处理 bq76940触发信号。 在例程的同时、我对 I2C 操作进行两次调用。

    //port1中断服务例程
    #pragma vector=Port1_vector
    _interrupt void ISR_PORT_1 (void)

     //DIS_P1INT();
     中频(P1IFG 和 BIT5)
     {
      //读取 SYS_STAT 字节
      bqStatus.StatusByte = BqGetRegisterByte (SYS_STAT);
      bqI2CStatusReadError = bqI2CError;
      //清除 CC 读数位
      BqSetRegisterByte (SYS_STAT、STAT_FLAGS|STAT_CC_READY);
     }
     P1IFG &=~BIT4;//清除中断标志

    当它开始运行很短的时间时、执行最终会停止。

    如果可能、您能向我解释一下这种情绪背后的原因吗?

    再次感谢 Bruce、奕迅的帮助。

    最棒的地方!

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

    "最终执行会消失"是什么意思? 您是指 PC 跳转到不需要的位置吗?

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

    是的、程序会消失。

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

    您能否帮助在运行哪个代码后检查程序是否停止运行? 可能对阵列的访问超出范围。

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

    您好、伊斯天、

    //port1中断服务例程
    #pragma vector=Port1_vector
    _interrupt void ISR_PORT_1 (void)

     //DIS_P1INT();
     中频(P1IFG 和 BIT5)
     {
      //读取 SYS_STAT 字节
      bqStatus.StatusByte = BqGetRegisterByte (SYS_STAT);
      bqI2CStatusReadError = bqI2CError;
      //清除 CC 读数位
      BqSetRegisterByte (SYS_STAT、STAT_FLAGS|STAT_CC_READY);
     }
     P1IFG &= ~BIT4;//清除中断标志

    我相信执行会与上面的中断例程同时运行、我会删除要读取/写入 I2C 的代码、而在某些中断服务例程之外 、执行永远不会终止。

    注意事项。

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

    您能否在调试模式下测试此情况并在 IRQ 的开头设置断点?

    我想检查这个问题是发生在 IRQ 跳转还是 IRQ 中的代码上。

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

    在 ISR 中运行 I2C (或任何实际外设)的两个主要危险:

    1) 1)如果您的 I2C 代码使用中断、大概会在某个位置设置 GIE=1。 如果是通过 ISR 完成的、很容易就能最终得到(a) ISR 递归、从而导致(b)堆栈溢出、从而导致(c)"分支到别处"。 我看不到您的代码执行此操作、但症状与您的描述相匹配。

    2) 2)如果中断在 MAIN ()处于 I2C 操作的中间时发生、ISR 将进入并与正在进行的操作的寄存器发生混乱。 这可能会导致其操作失败,或者只是为操作 main()处于中间状态留下不一致的状态。 这里的常见症状是一个无限循环(在 ISR 中或在 main()中),但在给定所示代码的情况下,这似乎是更可能的故障。

    您可能会考虑在每个 I2C 操作开始时禁用 P1IE.5、然后在结束时重新启用它(便宜的保险)。 这将使警报保持挂起 状态、直到可以安全地复位 CC_READY。

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

    Bruce、奕迅、

    我仍在使用旧方法来处理来自 bq76940的警报信号,例如,

    //port1中断服务例程
    #pragma vector=Port1_vector
    _interrupt void ISR_PORT_1 (void)

     中频(P1IFG 和 BIT5)
     {
      //读取 SYS_STAT 字节
      bqStatus.StatusByte = BqGetRegisterByte (SYS_STAT);
      bqI2CStatusReadError = bqI2CError;
      //清除 CC 读数位
      BqSetRegisterByte (SYS_STAT、STAT_CC_READY);
     }
     P1IFG &=~BIT4;//清除中断标志

    但我确实在  INT8_t I2CSendBytes (uint8_t I2CSlaveAddress、uint8_t *数据缓冲区、uint16_t ByteCount、uint16_t * pSentByte)的开头放置了禁用端口1 I/O 中断的代码、

    和 INT8_t I2CReadBytes (uint8_t I2CSlaveAddress、uint8_t * pDataBuffer、uint16_t ExpectedByteNumber、uint16_t * pNumberOfReceivedBytes) I2C 例程、

    并在这些 I2C 例程调用结束时启用端口1 I/O 中断。

    现在工作正常。  

    这样、系统可以大幅降低功耗、因为当警报信号处于活动状态时、电源电流将增加约25uA。 较长的时间周期警报保持高电平、 消耗的功率越大。

    对不起,伊斯迅不能重现此问题。 不知道原因。

    最恰当的考虑