GD32 MCU I2C通讯总线卡死问题解决方案
PDA一直低电平,SCL一直高电平。BUSY标志一直置位。有人说STM32核支持I2C不好,这个卡死不如用软I2C模拟解决。这个恐怕不能照搬GD的例程引脚设置,开漏还是推挽输出看电路设计。
想用软I2C模拟替换硬I2C可以搜我发的资源:GD32F103 软件模拟 I2C 发送。
如果在使用GD32 MCU的IIC通信过程中遇到总线卡死的情况,可以尝试以下两种软件方法来解决:
方法一:将SDA和SCL配置为推挽输出,强制输出stop信号
在I2C主机复位后,如果主机检测到I2C总线一直为BUSY状态,并且超过设定的时间,就会锁死总线。可以通过将I2C的SCL和SDA引脚初始化为普通GPIO功能,并配置为推挽输出。首先将SCL信号拉高,然后拉高SDA信号,模拟产生一个STOP信号,最后再将引脚配置为I2C的引脚复用功能。代码示例如下:
void i2c_bus_reset() {
GPIO_BC(GPIOB) |= GPIO_PIN_6 | GPIO_PIN_7;
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6|GPIO_PIN_7);
__nop();
__nop();
__nop();
__nop();
__nop();
GPIO_BOP(GPIOB) |= GPIO_PIN_6;
__nop();
__nop();
__nop();
__nop();
__nop();
GPIO_BOP(GPIOB) |= GPIO_PIN_7;
gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
}
void check_bus_status(void) {
while(i2c_flag_get(I2C0,I2C_FLAG_I2CBSY)) {
if(--time_out == 0){
i2c_bus_reset();
}
}
}
方法二:将SCL配置为推挽输出,强制输出9个clk
在I2C主机中增加一个I2C总线恢复程序,在每次I2C主设备复位后,如果检测到SDA数据线被拉低,就控制I2C中的SCL时钟线产生9个时钟脉冲(针对8位数据的情况),让I2C从设备完成被挂起的操作,从死锁状态中恢复过来。首先将SCL引脚初始化为普通GPIO功能,并配置为推挽输出,发送连续的9个时钟脉冲。为保证后续的I2C正常通信,先将I2C模块复位,再置位,最后再将引脚配置为I2C的引脚复用功能。代码示例如下:
void i2c_bus_reset() {
uint8_t i = 0;
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6); /* SCL output clock signal */
for(i = 0; i < 10; i++){
gpio_bit_reset(GPIOB, GPIO_PIN_6);
delay_1us(2);
gpio_bit_set(GPIOB, GPIO_PIN_6);
delay_1us(2);
}
/* reset I2C */
i2c_software_reset_config(I2C0, I2C_SRESET_RESET);
i2c_software_reset_config(I2C0, I2C_SRESET_SET);
gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
}
void check_bus_status(void) {
while(i2c_flag_get(I2C0,I2C_FLAG_I2CBSY)) {
if(--time_out == 0){
i2c_bus_reset();
}
}
}
以上就是解决GD32 MCU碰到IIC总线卡死的两种软件方法,可以根据具体情况选择合适的方法来解决问题。如果还有其他问题或建议,欢迎在评论区讨论。
作者:Aist-memory