STM32F103硬件IIC在HAL库下入坑指南

        最近在BMS,电压采样芯片用的是TI的bq76940,监测9-15路电压,可进行充、放电控制,数据通信采用IIC模式,我MCU采用的是STM32F103RCT6。

        ST采用HAL库,因为之前搞过HAL库的429,比较熟悉,网上又有里程,就直接copy使用了。关于ST的硬件IIC网上绝大部分的文章再说bug太大,都不建议使用,但是同时也有人分享一些使用成功的解决方案,我决定自己摸索一下,顺便挑战一下自己(现在觉得真有病)。

        写好代码准备调试,

        __HAL_RCC_GPIOB_CLK_ENABLE();                
        __HAL_RCC_AFIO_CLK_ENABLE();
        __HAL_RCC_I2C2_CLK_ENABLE(); 
        
        GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;     //IIC2
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;//GPIO_MODE_AF_OD;  GPIO_MODE_OUTPUT_PP                                         GPIO_MODE_AF_PP         
        GPIO_InitStruct.Pull = GPIO_NOPULL;        //自加nsj
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;//GPIO_SPEED_FREQ_HIGH;    GPIO_SPEED_HIGH
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 

结果发现程序死在  

        if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG) != HAL_OK) ,

这就是网上说的busy死锁问题,我也终究是逃不过去。经过

最近在BMS,电压采样芯片用的是TI的bq76940,监测9-15路电压,可进行充、放电控制,数据通信采用IIC模式,我MCU采用的是STM32F103RCT6。

ST采用HAL库,因为之前搞过HAL库的429,比较熟悉,网上又有里程,就直接copy使用了。关于ST的硬件IIC网上绝大部分的文章再说bug太大,都不建议使用,但是同时也有人分享一些使用成功的解决方案,我决定自己摸索一下,顺便挑战一下自己(现在觉得真有病)。

写好配置代码准备调试,

       __HAL_RCC_GPIOB_CLK_ENABLE();              

        __HAL_RCC_AFIO_CLK_ENABLE();

        __HAL_RCC_I2C2_CLK_ENABLE();

        GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;     //IIC2

        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;//手册中要求配置成开漏模式     

        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

结果发现程序死在  

if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG) != HAL_OK)

这就是网上说的busy死锁问题,我也终究是逃不过去。经过查看IIC的SR2寄存器发现只要把GPIO初始化为IIC,busy标志位就会置位。于是我尝试了使用大家普遍的解决方案,在初始化前先对CR1的SWRST复位,如下,发现于事无补。

   I2C2->CR1 |= 0x8000;

    I2C2->CR1 &= ~0x8000;

后来认为应该在IIC初始化之后再对SWRST进行复位,这样才能彻底清除busy位。经过尝试仍然不行。查阅手册发现

STM32F103硬件IIC在HAL库下入坑指南_第1张图片

只要是监测有低电平该位就会置1,我把IO设置成了开漏输出,IO口肯定不能输出高电平,接着我又查阅了bq76940的推荐电路(原理图按照推荐电路设计)

STM32F103硬件IIC在HAL库下入坑指南_第2张图片

我发现也没有上拉电阻,我靠,我马上查阅了bq76940芯片是否有内部上拉,然而并没有。没办法,只能刮开电路板,在铜线上焊出了一个上拉电阻,结果发现真的跳过了busy的坑!注意初始化IO之后还是需要复位SWRST的。

先小小高兴了一下,继续调试,发现还是不能进行通信,经过串口打印发现在地址发送之后居然返回的是HAL_ERROR,这说明地址发送未成功。经过查阅手册发现这是与bq76940没有“握手成功”。原因可能有

  1. 芯片出现故障
  2. 引脚连接错误或者虚焊
  3. IIC的地址引脚不对。

首先排查第1点,直接更换了2套全新的板子,发现故障依旧。接着是第二点,检查了连线和焊盘,都没问题。就剩下第三条地址不对了。我查阅资料发现STM32F103硬件IIC在HAL库下入坑指南_第3张图片

我的IIC配置也是7位的地址

STM32F103硬件IIC在HAL库下入坑指南_第4张图片

我自认为设置并没有问题,但查阅ST的底层发现,我里个去。。。想骂人的心都有

底层中并没有把设备的地址左移,而是直接把最低位改为“0”或“1”!这真实欺负我们这些不看底层的人啊,于是自己把器件地址偷偷的左移了一位。

但是发现仍然不行。我已经快顶不住了,身心俱疲,忽然想到我们还有协议分析仪,一下子激动起来,立刻接上去试验。发现发送的地址、读写位是正确的,跟随的ACK也是有的,但是接下来发送的数据解读出来确认红色的ERROR。

我发现ACK之后的高电平仅有2us左右,而且后面没有出现start信号,于是把IIC的频率从100k降低到50k。哈哈,协议分析仪的数据终于正常了,读写的值也是没有问题的。紧接着用串口打印出读取的数据,与分析仪一对比发现完全不一样(全是0),顿时头大,继续查吧。查来查去,发现自己在进行CRC校验的时候又把地址偷偷的左移了一位

CRCInput[0] = (I2CSlaveAddress << 1) + 1;

     CRCInput[1] = ReadData[0];

这导致了最终的CRC校验错误,读取的数值没有传输到相应的寄存器中。果断把左移去掉,发现打印的数据终于正确了,长长的舒了一口气。

 

STM32F103硬件IIC在HAL库下入坑指南_第5张图片

STM32F103硬件IIC在HAL库下入坑指南_第6张图片

调试到现在通讯终于正常了,但据说后面还有好多的坑,比如中断、意外断电。好在现在找到了坑的边缘,可以一点一点慢慢向上爬了。

 

 

 

你可能感兴趣的:(STM32F103硬件IIC在HAL库下入坑指南)