Other Parts Discussed in Thread: MSP430FR2311
我在现场测试中遇到了一个奇怪的问题、我们在测试中发现一个 MSP430从器件同时将 SCL 和 SDA 拉低的单元。 我知道这是因为在我们移除 MSP430从器件后、SCL 和 SDA 都返回高电平、所以我知道 MSP430从器件正在驱动总线。 我不确定它是如何进入这种状态的。 遗憾的是、我们没有使用调试器、也没有任何方法让器件回到处于该状态的实验中。 我在下面添加了 I2C 从设备代码。 它基于 MSP430FR2311 SDK 中的示例代码。 我今天刚刚添加了未经测试的代码来实现时钟低电平超时、希望这可以是最后一项工作、至少可以释放 SCL、我想它还可以释放 SDA、因为我们重置了整个 I2C 模块。
几个问题:
- 当 USCI_I2C_UCSTPIFG 被置位时、我应该做更多的事情吗? 我想知道一个事务可能会如何损坏、主设备会发送一个停止信号、但我不会重置状态机以接收命令地址。
- 我的时钟低电平超时配置是否正确?
谢谢
void initI2C()
{
UCB0CTLW0 = UCSWRST; //软件复位被启用
UCB0CTLW0 |= UCMODE_3 | UCSYNC; // I2C 模式、同步模式
UCB0CTLW1 |= UCCLTO_1;// 28ms 时钟低电平超时
UCB0I2COA0 = SLAVE_ADDR | UCOAEN; //自有地址和使能
UCB0CTLW0 &=~UCSWRST; //清除复位寄存器
UCB0IE |= UCRXIE + UCSTPIE + UCCLTOIE;//启用 RX 中断、停止中断、时钟低电平超时中断
}
//
// I2C 中断
//
#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_icc_)
#pragma vector = USCI_B0_vector
__interrupt void USCI_B0_ISR (void)
#Elif defined (__GNU__)
void __attribute__(interrupt (USCI_B0_vector)#USCI_ISR vector (void
)(void)#USCI_ISR vector 0!
#endif
{
//必须从 UCB0RXBUF
uint8_t Rx_val 读取;
switch (_even_in_range (UCB0IV、USCI_I2C_UCBIT9IFG)
){
USCI_NONE 案例: 中断; //向量0:无中断
USCI_I2C_UCALIFG 案例:中断; //向量2:ALIFG
USCI_I2C_UCNACKIFG 案例: //向量4:NACKIFG
中断;
案例 USCI_I2C_UCSTTIFG:中断; //向量6:STTIFG
案例 USCI_I2C_UCSTPIFG:
//如果我们得到一个停止、我们应该在这里做更多的事情???? 例如、重置状态机? 返回 RX_REG_ADDRESS 模式?
UCB0IFG &=~(UCTXIFG0);
中断; //向量8:STPIFG
USCI_I2C_UCRXIFG3案例:中断; //向量10:RXIFG3
USCI_I2C_UCTXIFG3案例:中断; //向量12:TXIFG3
USCI_I2C_UCRXIFG2案例:中断; //向量14:RXIFG2
USCI_I2C_UCTXIFG2案例:中断; //向量16:TXIFG2
USCI_I2C_UCRXIFG1案例:中断; //向量18:RXIFG1
USCI_I2C_UCTXIFG1案例:中断; //向量20:TXIFG1
USCI_I2C_UCRXIFG0案例: //向量22:RXIFG0
RX_val = UCB0RXBUF;
切换(SlaveMode)
{
情况(RX_REG_ADDRESS_MODE):
ReceiveRegAddr = Rx_val;
I2C_Slave_ProcessCMD (ReceiveRegAddr);
中断;
情况(RX_DATA_MODE):
ReceiveBuffer[ReceiveIndex++]= Rx_val;
RXByteCtr---;
IF (RXByteCtr = 0)
{
//完成接收 MSG
SlaveMode = RX_REG_ADDRESS_MODE;
UCB0IE &=~(UCTXIE);
UCB0IE |= UCRXIE; //启用 RX 中断
I2C_Slave_TransactionDone (ReceiveRegAddr);
i2cFlag = 1;//将标志设置为向 main 发出一个要处理的新命令的信号
__BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//在 RETI 上退出 LPM0
}
中断;
默认值:
__no_operation();
中断;
}
中断;
USCI_I2C_UCTXIFG0案例: //向量24:TXIFG0
//切换(SlaveMode)
//{
//case (TX_DATA_MODE):
UCB0TXBUF =传输缓冲器[TransmitIndex++];
TXByteCtr --;
IF (TXByteCtr = 0)
{
//完成发送 MSG
//SlaveMode = RX_REG_ADDRESS_MODE;
SlaveMode = TX_REG_ADDRESS_MODE;
UCB0IE &=~(UCTXIE);//禁用 TX 中断
UCB0IE |= UCRXIE; //启用 RX 中断
I2C_Slave_TransactionDone (ReceiveRegAddr);
}
//中断;
//默认:
//__no_operation();
//中断;
//}
中断; //中断矢量:I2C 模式:UCTXIFG
情况 UCCLTOIFG:
//如果时钟一直处于低电平则重置 I2C (我们可能出于一些愚蠢的原因而将其保持在低电平...)
UCB0CTLW0 = UCSWRST;//将 I2C 置于复位
SlaveMode = RX_REG_ADDRESS_MODE;//复位状态机
UCB0IE &=~(UCTXIE);//禁用 TX 中断
UCB0IE |= UCRXIE; //启用 RX 中断
UCB0CTLW0 &=~UCSWRST;//使 I2C 退出复位
中断;
默认值:break;
}
void I2C_Slave_ProcessCMD (uint8_t cmd)
{
ReceiveIndex = 0;
TransmitIndex = 0;
RXByteCtr = 0;
TXByteCtr = 0;
uint16_t ui16Value;
开关(cmd)
{
案例(CMD_RD_ID): //无运动强度设定点
ui16Value = id;
中断;
情况(CMD_RD_FW): //无运动强度设定点
ui16Value = FW;
中断;
情况(CMD_RD_D): //如果我们接收到要注册的数据复制缓冲区
ui16Value = d;
中断;
情况(CMD_RD_Strength): //如果我们接收到要注册的数据复制缓冲区
ui16Value =强度;
中断;
情况(CMD_RD_TEMRATURE): //如果我们接收到要注册的数据复制缓冲区
ui16Value =温度;
中断;
情况(CMD_RW_D_E): //如果我们接收到要注册的数据复制缓冲区
ui16Value = d_e;
中断;
默认值:
__no_operation();
中断;
}
setupRXDataMode();
CopyArrayUINT (ui16Value、TransmitBuffer);
}
void I2C_Slave_TransactionDone (uint8_t cmd)
{
//允许写入 FRAM
//获取先前的写保护设置
uint8_t state = HWREG8 (SYS_base + OFS_SYSCFG0_L);
#ifdef DFWP
uint8_t WP = DFWP | PFWP;
其他
uint8_t wp = PFwp;
#endif
ifdef FRWPPW
HWREG16 (SYS_BASE + OFS_SYSCFG0)=~PW |(状态和 Δ V WP);
其他
HWREG8 (SYS_BASE + OFS_SYSCFG0_L)&&~WP;
#endif
uint16_t temp = CopyTwoByteToUINT (ReceiveBuffer);
开关(cmd)
{
案例(CMD_RD_ID):
中断;
情况(CMD_RD_FW):
中断;
情况(CMD_RD_D):
中断;
情况(CMD_RD_Strength):
中断;
情况(CMD_RD_TEMRATURE):
中断;
案例(CMD_RW_CNTL): //控制寄存器
IF (SlaveMode = RX_REG_ADDRESS_MODE) //如果我们接收到要注册的数据复制缓冲区
{
CNTL = temp;//接收新值
}
中断;// wm
情况(CMD_RW_D_E): //控制寄存器
IF (SlaveMode = RX_REG_ADDRESS_MODE) //如果我们接收到要注册的数据复制缓冲区
{
D_e = temp;//接收新值
}
中断;
默认值:
__no_operation();
中断;
}
//恢复以前的写保护设置
ifdef FRWPPW
HWREG16 (SYS_BASE + OFS_SYSCFG0)= FWPW | STUARY;
其他
HWREG8 (SYS_BASE + OFS_SYSCFG0_L)=状态;
#endif
if (SlaveMode!= RX_REG_ADDRESS_MODE)
{
SlaveMode = RX_REG_ADDRESS_MODE; //结束传输模式
}
}
void setupRXDataMode (void)
{
//设置 i2c 以接收数据或传输数据。 将在 RX 模式下继续、但也会启用发送中断标志。 如果 TX 中断标志有一个写标志被置位的重复启动、然后将进行发送
SlaveMode = RX_DATA_MODE;
TXByteCtr = TYPE_1_LENGTH;
RXByteCtr = TYPE_1_LENGTH;
UCB0IE |= UCTXIE; //启用 TX 中断
UCB0IE |= UCRXIE; //启用 RX 中断
}