1、前言
这段时间一直在折腾自己的毕设,第二块板子到手基本上调通了所有的内容,还有几块芯片还在写测试代码。
其中有一块BMP280气压传感器,这块芯片在第一块板子中是完全能用的,因此可以排除是代码以及原理图的问题。
在这一版的设计中,BMP280单独占用了一组I2C1,但是在焊接之后测试过程中发现不能与BMP280建立完整的通讯。
由于我所有的器件都是手焊的,并且该器件属于QFN封装,在焊接上重复了好几遍,并且也更换过了器件,但是依旧无法解决问题。
昨天晚上突发奇想,干脆把I2C1的SCL和SDA线飞到临近的一组I2C上,接着在初始化的过程中取消掉I2C1的功能将其空置。
居然莫名其妙的能够通讯了。
但是这样子实在是太丑了,于是今天尝试能不能解决掉原来I2C1为什么不能通讯的问题。
2、奇怪的引脚状态
在GPIO中有一个只读寄存器IDR,它记录芯片主控测得的引脚电平。
查询IDR寄存器的地址值(STM32U0中GPIO的基地址是0x50000000,GPIOB的偏移地址是0x400,IDR寄存器的偏移地址是0x10,因此GPIOB的IDR寄存器的位置是0x50000410)发现其值是0x3EE2
PB6和PB7初始化都是正常的高电平状态,但是使用过I2C之后。
该值变成了0x3E22,对应着PB7/6始终为低电平。
并且将I2C1总线释放后,将其配置为普通的GPIO模式,开漏输出上拉,强制拉高,其值依旧为0。
可能正是这种异常状态,导致了I2C1不能正常使用。
3、硬件I2C的死锁?
在论坛和平时的了解中,偶尔有人会提到STM32系列的硬件I2C出现死锁问题。
大体的原因是在数据传输过程中,主接收器在接收到最后一个字节后会发送ACK信号,这会导致从机持续等待数据,从而造成总线死锁,这据说是STM32的硬件I2C为了避开飞利浦的I2C专利而不得已留下的BUG。
但是I2C的专利在早些年就已经过期了,如果是在F103中遇到的这种问题我还能理解(103的硬件I2C我好像也没遇到死锁的问题)。
但是STM32U0作为较新的产品,出现I2C死锁的BUG感觉是不太应该。
4、解决办法
后来为了测试电压到底是多少,在I2C初始化之后,发现实际的情况居然是SCL(PB6)的电压为2.5V+
这是一个非常经典的空置电压,这说明SCL引脚并没有被上拉。由于我一般没有习惯接上拉电阻,都是靠GPIO的内部上拉来充当上拉电阻。
那么显然问题就是SCL引脚的内部上拉出现了问题。
但是明明代码中很明显的写的是内部上拉,而且非常奇怪的是I2C4明明是配置的内部上拉模式,但是I2C1飞到I2C4的时候(飞线)依旧无法使用I2C1。并且如果使能I2C1的话会同样的导致I2C4瘫痪出现同样的问题。
查询芯片手册得知GPIO的PUPDR寄存器记录引脚的上下拉状态,查询该地址的值发现PB6,PB7均是正常的上拉,但是引脚悬空确实实打实存在的问题。于是看看能不能通过外接上拉电阻的情况来解决问题。
当在I2C1中接入4.9K的上拉电阻后,发现BMP280正常使用。
并且使用完I2C后,IDR寄存器的值也是正常的显示高电平。
5、疑问
主要是奇怪为什么同样的I2C总线,一组I2C1不能使用,其他的I2C总线可以正常使用。
而且如果同时开启I2C1并且和其他I2C总线连接到一起,会导致其他I2C总线的SCL引脚处于悬空状态,从而让其他的I2C总线失效~~~很奇怪。