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.

[参考译文] MSP430F5529:MSP430F5529 I2C 从器件在中断期间随机挂起

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/939622/msp430f5529-msp430f5529-i2c-slave-random-hang-while-in-interrupt

器件型号:MSP430F5529
主题中讨论的其他器件: LM75A

大家好、我将使用具有 msp430f5529的定制板。 MSP 具有多个 i2c 从器件(通过 LTC4315f 总线缓冲器连接的单个板载 LM75A 和两个非板载 LM75A)。

MSP 本身也是 Raspberry PI4的从器件。 I2C 主器件和从器件分别为 USCI_B0和 B1。

问题是:Raspberry 会启动循环(while true)命令、例如询问非板载 LM75A。 系统在一段时间内正常工作(例如5个周期或6分钟不间断、它未固定)、然后它挂起。 主机等待10秒超时、但 MSP 挂起忙。

MSP 的 I2C_MASTER 代码从官方库中的 MSP430F55xx_USCI_i2c_standard_master.c 复制。

下面的主 Init 代码。 时钟源为 SMCLK:

void I2C_init()
{
//initClockTo16MHz();

I2C_INIT_GPIO();

UCB0CTL1 |= UCSWRST; //启用 SW 复位
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C 主设备,同步模式
UCB0CTL1 = UCSSEL_2 + UCSWRST; //使用 SMCLK、保持软件复位
UCB0BR0 = 10;//160; //1.01/10 ~100kHz // fSCL = SMCLK/160 =~100kHz
UCB0BR1 = 0;
UCB0CTL1 &=~UCSWRST; //清除 SW 复位,恢复操作
UCB0IE |= UCNACKIE;

} 

I2C 从设备是定制的:

void initGPIO()
{
//I2C 引脚
P4SEL |= BIT1 | BIT2;
}

void initI2C()
{
UCB1CTL1 |= UCSWRST; //启用 SW 复位
UCB1CTL0 = UCMODE_3 + UCSYNC; // I2C 主设备,同步模式
UCB1CTL1 = UCSSEL_2 + UCSWRST; //使用 SMCLK、保持软件复位
UCB1I2COA = SLAVE_ADDR; //自有地址
UCB1BR0 = 1;//160;
UCB1BR1 = 0;
UCB1CTL1 &=~UCSWRST; //清除 SW 复位,恢复操作
UCB1IE |=(UCRXIE | UCTXIE| UCSTPIE | UCSTTIE | UCALIE | UCNACKIE);
}

int I2C_SLAVE_INIT (void){
initGPIO();
initi2C();
返回0;
}


//*********
// I2C 中断
//

enum i2c_slave_Stage{waiting_for_start、receive_REG_ADDR、
waiting_for_data_or_restart、transmit 数据、waiting for _stop};
enum i2c_slave_Stage = waiting_for_start;

void read_i2c_data(){
uint8_t temp = UCB1RXBUF;
if (stage== receive_REG_ADDR){
I2C_offset =(temp > sizeof (i2c_interface_struct))? sizeof (i2c_interface_struct):temp;
Stage = WAITING_OR_DATA_OR_RESTART;
}否则、如果(STAGE = WAITING_OR_DATA_OR_RESTART)为{
(*(((uint8_t*)(&i2c_interface_struct))+i2c_offset))= temp;
Stage = WAITING_FAND_STOP;
}否则{
//生成 NAK
UCB1CTL1 |= UCTXNACK;
}


#if Defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector=USCI_B1_Vector
__interrupt void USCI_B1_ISR (void)
#Elif Defined (__GISR__)__USCI_B1_COMPILE_INTERRUCTB1_ERROR


(void)(USCI_BI_BIST_BINC_BIST_ERROR)(UB1)(UBINC_COMPLE= UBIST_ERROR)(UBIST_BIST_BIST_ERROR)
#endif
{
volatile uint8_t temp;

switch (__evo_in_range (UCB1IV、0xC)
){
USCI_NONE 案例:
中断; //向量0 -无中断
USCI_I2C_UCALIFG 案例:
中断; //中断矢量:I2C 模式:UCALIFG
USCI_I2C_UCNACKIFG 案例:
中断; //中断矢量:I2C 模式:UCNACKIFG
USCI_I2C_UCSTTIFG 案例:
如果(阶段= WAITING_OR_RESTART)
阶段=传输数据;
其他
阶段=接收_REG_ADDR;
中断; //中断矢量:I2C 模式:UCSTTIFG
USCI_I2C_UCSTPIFG 案例:
//修复:写入事务中的停止可能先于数据
IF (UCB1IFG 和 UCRXIFG){
//(*((((uint8_t*)(&i2c_interface_struct))+i2c_offset))= UCB1RXBUF;
read_i2c_data();
}
I2C_OFFSET=0;
阶段= WAITING_FAND_START;
中断; //中断矢量:I2C 模式:UCSTPIFG
USCI_I2C_UCRXIFG 案例:
read_i2c_data();
中断; //中断矢量:I2C 模式:UCRXIFG
USCI_I2C_UCTXIFG 案例:
//修复:不要检查 stage=transmit 数据(在 regAddr 之前可能会在写事务中重新启动)
UCB1TXBUF =*(((uint8_t*)(&i2c_interface_struct))+ i2c_offset);
while (UCB1IFG 和 UCTXIFG);
中断; //中断矢量:I2C 模式:UCTXIFG
默认值:中断;
}
} 

代码在第88行挂起( while (UCB1IFG & UCTXIFG); )  *未确定突出显示的工作方式*

以下是传感器检查代码。 首先、通过缓冲器建立线路、然后读取传感器、然后关闭总线。

if (LTC4315_BUS_ENABLE (LTC4315_I2C_address、LTC4315_BUS2)){// 41 - LTC
if (LM75A_Read_temperature1 (&temp))){
temp_storage.device2_temperature_storage =(uint32_t) temp;
}
}
LTC4315_BUS_DISABLE (LTC4315_I2C_ADDRESS、LTC4315_BUS2); 

无论是否连接了调试器、都会捕获挂起。 有时我在_bis_SR_register (LPM0_bits + GIE)上捕获到调试器;I2C_Master_WriteReg 的字符串、无法关闭 LTC 行、但调试器说 UCB1_ISR 正在使用(从站)。 那么、我想知道、UCB0_ISR 和 UCB1_ISR 之间是否会有冲突? 或者、我只是看不到它是不是太多了?

也许很重要:系统在 main 的 while (1)循环中工作。 还有 UART、SPI 和 RTC_A 工作正常。 此外、我尝试从 I2C 主设备删除 LPM0、但后来无法使用 LTC 执行读取操作、无法打开链接。

感谢你的帮助。

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

    第88行(SPIN 等待 TXIFG=0)尝试执行什么操作? 我的第一个想法是它不应该存在。

    您刚刚馈送了 TXBUF、因此 TXIFG 在该线之前变为0。 此时:

    1) 1) TXIFG=0 (正如预期的那样)、在这种情况下、测试是多余的。

    2) 2)您通过某种方式设法使 TXIFG 的尾端变为=0 (我不确定这是否可行)、在这种情况下、测试是多余的。

    3) 3) TXIFG 同时返回到1 (通过一些偶然情况)、在这种情况下、你不会再次为 TXBUF 提供数据、因此它将保持=1并且你的 ISR 一直被卡住。

    摘要:尝试删除第88行。

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

    已经尝试过。 完全移除这条线只会中断系统-它在我填充缓冲区的前一行上挂起、即使是第一次传输也无法完成。

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

    前一行(87)是一个分配"UCB1TXBUF="。 我不知道它怎么会在这条线路上挂起。 我想知道调试器是否会产生某种幻象。

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

    首先、感谢您删除支票的想法。

    我昨天似乎是“幸运”-删除此检查真的会使系统在第87行挂起,而不是在第一笔交易上。 我猜的是、在分配缓冲区后 MSP 实际上需要一段时间、因此我使用了一些管道胶带并插入了一个__delay_cycles (100);在这里进行了检查。

    这似乎解决了问题、但中断内部存在延迟。 这个误差的性质看起来仍然不干净、并且在 I2C 每次变化后需要检查系统的稳定性对于快速解决方案来说是一个过高的价格。

    是否有什么想法可能会导致它或一些解决方法?

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

    据我所知、TXBUF 写入时 TXIFG 立即变为0、不过如果移位寄存器(之前)为空、它可能很快恢复运行。

    您如何确定它悬挂在第87行?

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

    当 MSP 停止响应时、调试暂停。

    下面是 USCI 寄存器的样子。 连接丢失后大约5-7秒。 如果我等待更多的时间、例如一分钟、Disassembly 只指向一些无法访问的内存

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

    仍然非常感谢合格的帮助!

    事实证明、延迟实际上不起任何作用。 我怀疑 UCB0和 UCB1中断之间可能存在一些干扰、但没有线索知道如何处理。

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

    我没有答案。 上周末我花了一些时间尝试复制这种情况、但我使用的是非常简单的从属设备、而不是您的代码。 一些观察结果:

    1) 1)从机 ISR 可能会呈现多个 IFG、尤其是在加载时、并且 IV 优先级不一定反映时间顺序。 例如、您可以一次性看到 STTIFG、STPIFG 和 TXIFG、但这不是它们到达的顺序。 我检查了一些情况、但我仍然想知道是否有某种组合会使您的状态机产生混乱。

    2) 2) TXNACK 是一件有趣的事情-它只在某些情况下使用(可能只使用 RXIFG?) 如果在"错误"时间设置、则会"挂起"、直到稍后。 鉴于(1)这似乎是一种可能性。

    3) 3)我对您的确切症状还不清楚:我知道没有机制可以挂起一个简单的分配、因此我想它会反复循环 ISR 触发 TXIFG。 但是、您的寄存器显示 STTIFG、它的优先级高于 TXIFG、因此应该是先看到的。 (这也可能是调试器的幻想。)

    我首先尝试将主器件减慢为诊断。 这将至少降低(1)的概率。