DSP

STM32 I2C 总线占用问题解析

2019-07-13 15:29发布

这几天解决 STM32 MCU的I2C 总线占用(BUSY) 问题,觉得是不错的Lesson Learn,分享给大家。


问题描述
  1. STM32F207 MCU有三组I2C,在Pre-ES1使用I2C1接上DSP/Codec/EEPROM,运作良好
  2. 新硬件(ES1)把Codec/EEPROM移到I2C3,DSP还是留在I2C1,发现在I2C3有机率性的BUSY,MCU无法开始传资料
  3. 查MCU datasheet,BUSY意思为register I2C3_SR2[bit1]=1,代表SCL/SDA曾经 low而且没出现stop condition



  4. I2C3 BUSY和timing有关,在程序加个delay就莫名PASS,再加delay又莫名BUSY,有些image是机率性发生BUSY

分析方向
  1. 观察I2C3 SCL/SDA波形
  2. I2C3在Pre-ES1没用过,初始化是否有问题?
  3. 观察BUSY时机,何时开始,何时结束
  4. 和chip有关?将 Codec和Flash断开
  5. 和I2C bus有关?将Codec接到 I2C1测试
  6. 为何Pre-ES1没问题?


分析过程
  1. 刚开始不太稳定,莫名的连续一直BUSY,有时一直PASS,而且LED时亮时暗
    > 量电压发现VDD3.3V不稳,high > low > high > low 震荡
    > 加大LDO之后VDD3.3V稳定了(Solution1),但I2C3还是BUSY 

  2. 东改西改,发现一版100% PASS的软件,和另一版100% FAIL的软件,只差在delay,应该还有其他问题

  3. 量波形,I2C1(DSP)很正常,I2C1 init之后一直FREE,只有传资料期间才BUSY



  4. 100% BUSY的软件,在I2C3 初始化之后SCL/SDA停在2.6V,当VDD3.3V ON 后才升到3.3V


  5. 100% PASS的软件,波形同上,但之后开LED时因为LDO供电不足,SCL/SDA被短暂下拉,马上回到3.3V

    应是因为SCL/SDA短暂下拉,误打误撞造成SCL/SDA high > low > high离开BUSY,有两个证据
    证据一,如果没下拉,I2C3就一直BUSY:
      a. 断开小板(上面有LED) 以降低VDD3.3V电流,不会短暂下拉 > 100% PASS的软件变成100% FAIL
      b. 断开小版LED以降低VDD3.3V电流,不会短暂下拉 > 100% PASS的软件变成100% FAIL
      c. 软件关闭LED以降低VDD3.3V电流,不会短暂下拉 > 100% PASS的软件变成100% FAIL
    证据二,如果有下拉,I2C3从BUSY恢复成FREE:
      a. BUSY时设SCL/SDA为GPIO out,拉low > high > low > high,重新初始化SCL/SDA (workaround)  > 离开BUSY并可传I2C指令
      b. BUSY时手动把SCL拉电线接地  离开BUSY并可传I2C指令
      c. 100% BUSY软件就是因为没下拉波形才会100% FAIL
    PS: 开LED造成电流超出LDO负荷也是问题,须加大LED电阻或更换LDO

  6. SCL/SDA短暂下拉不是造成BUSY的原因,重点在SCL/SDA有0.8s处于2.6V不正常电压,原因可能有:
    - flash/codec去拉SCL/SDA
    - MCU去拉SCL/SDA
    - SCL/SDA上拉电阻不正确
    - SCL/SDA的上拉电路接在stby3.3v,可能stby3.3v不稳


  7. 断开flash还是BUSY,而且SCL/SDA还是有0.8秒被下拉到2.6v
    > 和flash无关

  8. 断开codec后,SCL/SDA不会下拉到2.6v,但I2C3还是BUSY
    > 怀疑Codec供电不正确,检查I2C3初始化当下的VDD3.3v (供给Codec电压),发现VDD3.3V本应处于无电状态(0V),但实际量得2.7V,对codec是不正常电压,可能造成工作异常
    > MCU将VDD3.3V提早开电(得到3.3V),确保I2c3初始化时Codec正常工作,SCL/SDA下拉电压消失 (Solution2)
    > I2C3还是BUSY,其实还需要下个Solution


  9. 比较I2C1和I2C3初始化,发现重要差异:
       I2C1 pins(PB7, PB6)都在GPIO group B,共用一组GPIO register,填一次register可初始化两根pin
       I2C3 pins(PA8, PC9)分在GPIO group A和C,必须分两次初始化,先SDA再SDL
       > 怀疑初始化顺序错误,I2C3先初始化SCL再SDA,终于PASS!(Solution3)

 
其他实验
  1. 基本电路检查: SCL/SDA pull high电阻都是4.7KR,Stby3.3v是稳定3.3V,SCL/SDA没接反,Codec的25Mhz clock稳定
  2. 将Codec从I2C3移到I2C1,可正常传输 > 被误导以为和Codec无关
结论
  1. 三个Solution
    a. 加大LDO让VDD3.3V稳定供电
    b. I2C3先初始化SCL再SDA。虽然datasheet没写此限制,但sample code确实依照此顺序执行初始化。
    c. 为确保Codec在I2C3 初始化时有正常电压(VDD3.3v=3.3v),将VDD3.3V移到I2C3初始化之前
  2. 一个workaround
    - 为确保BUSY时可恢复,当BUSY时将SCL/SDA设为GPIO out,然后pull low > high > low > high,再重新初始化I2C3
  3. Pre-ES1没问题是因为
    a. Pre-ES1 LDO较强力,无供电问题
    b. Pre-ES1的VDD3.3v无法由MCU开关,而是由stby3.3v稳定供电,因此无SCL/SDA 2.7V问题
    c. Pre-ES1只用I2C1,没用I2C3。I2C1两根pin在同一个GPIO group,无SCL/SDA初始化顺序问题

以后I2C问题可检查
  1. 电路:pull high电阻,pull high电压,slave device供电
  2. 软件:I2C SCL/SDA初始化,slave device初始化timing
  3. SCL/SDA检查:SCL是否稳定,SCL/SDA电压,slave device有回ACK? 传输资料是否正确
  4. 断开I2C3 chip做测试
  5. 量测slave device期望的timing和MCU送出得是否一样