文章目录
1.问题背景
在STM8S平台使用I2C Slave模式,参考STM8S的标准库的Sample Code,但是只要Master Controller Read/Write多个Bytes时,就会存在中断一直被触发的问题。因为中断对应的I2C State Register没有被正确的清除,所以中断一直被触发导致I2C通信失败。
参考STM8S的标准库的Sample Code路径如下:
STM8S_StdPeriph_Lib\Project\STM8S_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange\Slave\
2.I2C Slave模式
下面是STM8S I2C Slave模式的参考代码,我这边验证目前没有遇到问题。
#define I2C_DATA_SIZE 8
#if ((I2C_DATA_SIZE > 0) && ((I2C_DATA_SIZE & (I2C_DATA_SIZE - 1)) != 0))
#error I2C_DATA_SIZE isnt a power of 2.
#endif
#define uint8_bits_def(x) union \
{\
unsigned char x; \
struct \
{\
unsigned char x##_Bit0:1, \
x##_Bit1:1, \
x##_Bit2:1, \
x##_Bit3:1, \
x##_Bit4:1, \
x##_Bit5:1, \
x##_Bit6:1, \
x##_Bit7:1; \
};\
}
uint8_bits_def(tagI2C);
uint8_t i2c_addr = 0;
uint8_t i2c_data[I2C_DATA_SIZE] = {
0x00};
void I2C_Slave_IRQHandler(void)
{
volatile I2C_Event_TypeDef Event = I2C_GetLastEvent();
/* Slave address matched with the address sent by master */
/* EV1: ADDR = 1, 顺序读SR1,SR3寄存器清除此标志位 */
if(Event == (I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED))
{
tagI2C_Bit0 = 1;
}
/* Slave received the data byte from master */
/* EV2: RxNE = 1, 读DR寄存器清除此位 */
else if(Event == (I2C_EVENT_SLAVE_BYTE_RECEIVED))
{
uint8_t ch = I2C_ReceiveData();
if(tagI2C_Bit0){
tagI2C_Bit0 = 0;
i2c_addr = ch;
}else{
i2c_data[i2c_addr++ & (I2C_DATA_SIZE - 1)] = ch;
}
}
/* Slave received STOP byte from master */
/* EV4: STOPF = 1,读SR1寄存器后再写CR2清除 */
else if(Event == (I2C_EVENT_SLAVE_STOP_DETECTED))
{
I2C_GetFlagStatus(I2C_FLAG_STOPDETECTION);
I2C_GenerateSTOP(DISABLE);
}
/* SLAVE TRANSMITTER */
/* Data transmited from slave to master */
/* EV3: TxE = 1, 写DR寄存器清除DR */
else if((Event == (I2C_EVENT_SLAVE_BYTE_TRANSMITTED)) ||
(Event == (I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED)))
{
uint8_t ch = i2c_data[i2c_addr++ & (I2C_DATA_SIZE - 1)];
I2C_SendData(ch);
}
/* Acknowledge failure */
/* EV3-2: AF = 1, AF is cleared by writing '0' in AF bit of SR2 register */
else if(Event == (I2C_EVENT_SLAVE_ACK_FAILURE))
{
I2C_ClearFlag(I2C_FLAG_ACKNOWLEDGEFAILURE);
}
}
void I2C_Slave_Init(void)
{
I2C_DeInit();
/* Initialize I2C peripheral */
I2C_Init(400000, SLAVE_ADDRESS, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, 16);
/* Enable Error Interrupt*/
I2C_ITConfig((I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF), ENABLE);
}
【备注】:
I2C_Slave_IRQHandler
是在stm8s_it.c文件中的INTERRUPT_HANDLER(I2C_IRQHandler, 19)
中被调用的。
3.分析验证
为了方便验证问题,在I2C_Slave_IRQHandler
函数中保存了所有的Event,如下:
+uint16_t event_rx_buf[50] = {
0x00};
+uint16_t event_count = 0;
void I2C_Slave_IRQHandler(void)
{
volatile I2C_Event_TypeDef Event = I2C_GetLastEvent();
+ if(event_count < 50){
+ event_rx_buf[event_count++] = Event;
+ }
...
}
- Master端write 2个byte产生的Event,如下:
【备注】上面截图出现了3次
0x240
,因为是1个Register addr + 2个data
,所以其实是write3个数据。 - Master端read 2个byte产生的Event,如下:
【备注】
0x680
是在发送数据中,中断函数中不做任何处理,等待发送完成。