STM8S I2C Slave模式错误解决

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是在发送数据中,中断函数中不做任何处理,等待发送完成。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页