你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32硬件I2C调试

[复制链接]
STMCU小助手 发布时间:2022-1-27 22:49
调试情况1
现象:主I2C发送数据而没有收到应答,则下一次不能正常发送数据

637417-20181110164400145-1024558856.png

637417-20181110164410368-577421352.png

背景:主I2C每次应该都能正常发送数据
硬件:野火STM32-MINI,1主0从,SCL和SDA直接上拉
软件:按键触发中断,主I2C发送一次数据,中断优先级,按键最低,I2C最高,且主I2C中有TIMEOUT计时
  1. void PB_K2_IRQ_HANDLER(void)
  2. {
  3.     if(EXTI_GetITStatus(PB_K2_EXTILINE) != RESET)
  4.     {
  5.         EXTI_ClearITPendingBit(PB_K2_EXTILINE);
  6.         
  7.         mini_i2c_write(0x22, 0x47);
  8.         LED_D5_TOGGLE;
  9. //        printf("Push button K2 clicked!\r\n");
  10.     }
  11. }
复制代码
  1. #define PB_PREPRIO                        3
  2. #define PB_SUBPRIO                        3
复制代码
  1. #define SLAVER_I2C_PRIPRIO                0
  2. #define SLAVER_I2C_SUBPRIO                0
复制代码
优先级分组均为2
  1. void mini_uart_config(void)
  2. {
  3.     // structure define
  4.     USART_InitTypeDef usart_struct;
  5.     GPIO_InitTypeDef gpio_struct;
  6.     NVIC_InitTypeDef nvic_struct;
  7.    
  8.     // clock enable
  9.     DEBUG_UART_RCC_CMD(DEBUG_UART_RCC, ENABLE);
  10.     GPIO_RCC_CMD(DEBUG_UART_GPIO_RCC, ENABLE);
  11.    
  12.     // GPIO initialization
  13.     gpio_struct.GPIO_Mode = GPIO_Mode_AF_PP;
  14.     gpio_struct.GPIO_Speed = GPIO_Speed_50MHz;
  15.     gpio_struct.GPIO_Pin = DEBUG_UART_TX;
  16.     GPIO_Init(DEBUG_UART_GPIO, &gpio_struct);
  17.    
  18.     gpio_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  19.     gpio_struct.GPIO_Pin = DEBUG_UART_RX;
  20.     GPIO_Init(DEBUG_UART_GPIO, &gpio_struct);
  21.    
  22.     // NVIC    initialization
  23.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  24.     nvic_struct.NVIC_IRQChannel = DEBUG_UART_IRQ;
  25.     nvic_struct.NVIC_IRQChannelPreemptionPriority = DEBUG_UART_PRIPRIO;
  26.     nvic_struct.NVIC_IRQChannelSubPriority = DEBUG_UART_SUBPRIO;
  27.     nvic_struct.NVIC_IRQChannelCmd = ENABLE;
  28.     NVIC_Init(&nvic_struct);
  29.    
  30.     // USART initialization
  31.     usart_struct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
  32.     usart_struct.USART_Parity = USART_Parity_No;
  33.     usart_struct.USART_StopBits = USART_StopBits_1;
  34.     usart_struct.USART_WordLength = USART_WordLength_8b;
  35.     usart_struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  36.     usart_struct.USART_BaudRate = DEBUG_UART_BAUDRATE;
  37.     USART_Init(DEBUG_UART, &usart_struct);
  38.    
  39.     USART_Cmd(DEBUG_UART, ENABLE);
  40.    
  41.     USART_ITConfig(DEBUG_UART, USART_IT_RXNE, ENABLE);
  42. }
复制代码
  1. void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)
  2. {
  3.     uint32_t timeout;
  4.    
  5.     I2C_GenerateSTART(MASTER_I2C, ENABLE);
  6.     timeout = I2C_TIMEOUT;
  7.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET)
  8.     {
  9.         if(timeout-- == 0)
  10.         {
  11.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);
  12.             break;
  13.         }
  14.     }
  15.    
  16.     // device address
  17.     I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
  18.     timeout = I2C_TIMEOUT;
  19.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
  20.     {
  21.         if(timeout-- == 0)
  22.         {
  23.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);
  24.             break;
  25.         }
  26.     }
  27.    
  28.     I2C_SendData(MASTER_I2C, reg_addr);
  29.     timeout = I2C_TIMEOUT;
  30.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET)
  31.     {
  32.         if(timeout-- == 0)
  33.         {
  34.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);
  35.             break;
  36.         }
  37.     }
  38.    
  39.     I2C_SendData(MASTER_I2C, wdata);
  40.     timeout = I2C_TIMEOUT;
  41.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET)
  42.     {
  43.         if(timeout-- == 0)
  44.         {
  45.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);
  46.             break;
  47.         }
  48.     }
  49.    
  50.     I2C_GenerateSTOP(MASTER_I2C, ENABLE);
  51. }
复制代码

问题所在:主I2C在未收到ACK应答,会产生应答错误,SR1的AF位置1,在TIMEOUT时间后,上面的用户代码会调用I2C_GenerateSTOP(MASTER_I2C, ENABLE)函数,CR1的STOP为会被置位,导致出错
调试代码,用串口打印状态寄存器及控制寄存器的值
  1. void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)
  2. {
  3.     if((MASTER_I2C->SR1 != 0) || (MASTER_I2C->SR2 != 0))
  4.     {
  5.         printf("Master I2C SR1 is %x and SR2 is %x\r\n", MASTER_I2C->SR1, MASTER_I2C->SR2);
  6.         printf("Master I2C CR1 is %x and CR2 is %x\r\n", MASTER_I2C->CR1, MASTER_I2C->CR2);
  7. //        mini_i2c_config();
  8.         MASTER_I2C->CR1 ^= 0x0200;
  9.         printf("Master I2C SR1 is %x and SR2 is %x\r\n", MASTER_I2C->SR1, MASTER_I2C->SR2);
  10.         printf("Master I2C CR1 is %x and CR2 is %x\r\n", MASTER_I2C->CR1, MASTER_I2C->CR2);
  11.     }
  12.    
  13.     uint32_t timeout;
  14.    
  15.     I2C_GenerateSTART(MASTER_I2C, ENABLE);
  16.     timeout = I2C_TIMEOUT;
  17.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET)
  18.     {
  19.         if(timeout-- == 0)
  20.         {
  21.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);
  22.             break;
  23.         }
  24.     }
  25.    
  26.     // device address
  27.     I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
  28.     timeout = I2C_TIMEOUT;
  29.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
  30.     {
  31.         if(timeout-- == 0)
  32.         {
  33.             I2C_GenerateSTOP(MASTER_I2C, ENABLE);
  34.             break;
  35.         }
  36.     }
复制代码

经验证,重新初始化I2C或复位CR1的STOP可以排除对下次发送数据的干扰,串口打印消息如下
  1. // Using mini_i2c_config()Program started!
  2. Master I2C SR1 is 400 and SR2 is 0
  3. Master I2C CR1 is 601 and CR2 is 24
  4. Master I2C SR1 is 0 and SR2 is 0
  5. Master I2C CR1 is 401 and CR2 is 24// Using MASTER_I2C->CR1 ^= 0x0200
  6. Program started!
  7. Master I2C SR1 is 400 and SR2 is 0
  8. Master I2C CR1 is 601 and CR2 is 24
  9. Master I2C SR1 is 400 and SR2 is 0
  10. Master I2C CR1 is 401 and CR2 is 24
复制代码

解决方案:使能主I2C错误中断,在中断中重新初始化I2C,并设置一个变量使主I2C发送函数提前终止
  
  1.     nvic_struct.NVIC_IRQChannel = MASTER_I2C_ER_IRQ;
  2.     NVIC_Init(&nvic_struct);
复制代码
  1.     I2C_ITConfig(MASTER_I2C, I2C_IT_ERR, ENABLE);
复制代码
  1. void MASTER_I2C_ER_IRQ_HANDLER(void)
  2. {
  3.     if(I2C_GetITStatus(MASTER_I2C, I2C_IT_AF) != RESET)
  4.     {
  5.         I2C_ClearITPendingBit(MASTER_I2C, I2C_IT_AF);
  6.         
  7.         mini_i2c_config();
  8.         master_i2c_af = 1;
  9.     }
  10. }
复制代码
  1. void mini_i2c_write(uint8_t reg_addr, uint8_t wdata)
  2. {
  3.     master_i2c_af = 0;
  4.    
  5.     I2C_GenerateSTART(MASTER_I2C, ENABLE);
  6.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_MODE_SELECT) == RESET);
  7.    
  8.     // device address
  9.     I2C_Send7bitAddress(MASTER_I2C, SLAVER_I2C_OWN_ADDR, I2C_Direction_Transmitter);
  10.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == RESET)
  11.     {
  12.         if(master_i2c_af)
  13.         {
  14.             master_i2c_af = 0;
  15.             return;    // maybe there is a solution here
  16.         }
  17.     }
  18.    
  19.     I2C_SendData(MASTER_I2C, reg_addr);
  20.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET);
  21.    
  22.     I2C_SendData(MASTER_I2C, wdata);
  23.     while(I2C_CheckEvent(MASTER_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == RESET);
  24.    
  25.     I2C_GenerateSTOP(MASTER_I2C, ENABLE);
  26. }
复制代码





收藏 评论0 发布时间:2022-1-27 22:49

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版