场景:
在I2C总线通信的时候,如果对端器件没有复位端,在通信过程中CPU异常,导致数据没传输完,可能会造成类似挂死的状态
挂死场景:
1、SCL挂死
2、SDA挂死
触发SDA挂死必现条件:
1、CPU读取对端数据(如果是往对端写数据,总线是CPU拉着的,这时候CPU异常复位,总线也会跟着复位,触发不了挂死)
2、读取的数据都为0(保证总线一直处于低电平状态)
SCL挂死解决方案:
1、SCL挂死,只能通过硬件去拉宽时钟去解决
SDA挂死解决方案:
1、在芯片设计时,可使用IOMUX使GPIO管脚与I2C管脚复用
2、当挂死时,可通过配置IOMUX寄存器切换管脚模式,从I2C模式切换成GPIO模式
3、通过配置高低电平,把还没发送完的时钟(为了保证一定能恢复,发送9个脉冲)重新补回去
4、总线恢复
驱动实现:
1、当时我所在的项目是通过ACPI的方式去上报硬件节点信息,并不是通过DTS
2、在驱动里,会通过调用内核的接口(接口名字已经忘记了)去调用BIOS上报的Method(实际都是配置寄存器,只不过把对应的寄存器地址在BIOS上报,驱动去调用),去实现切换
3、内核接口只能去调用BIOS的Method,真正切换是在BIOS里面去实现的
其他:
1、CPU异常复位可在使用i2ctransfer读取对端数据的过程中,配置软复位寄存器触发挂死
2、IOMUX可以理解为一个选择器,通过在内部集成多个模块,对外是一个引出的PAD管脚;只需要配置寄存器,可切换不同的模块,按照模块协议发送对应的脉冲去模拟对应的总线信号
备注:
1、该方案描述可能有点粗糙,但是方案大致是可以这样实现
2、该方案是已经得到验证的,但是可能限制比较多
3、触发的场景比较难实现,需要特定的条件
4、可能有些产品遇到这种直接更换器件(甚至现在市场上大部分对端器件都有复位端)或者整个单板下电即可恢复,实现该方案对于产品本身意义不大
5、该方案只是一个更优化的方案,是一个可选方案,并不是一个必须方案