近来对 amigo 开发期间的遇到 I2C 问题做一下总结。
我们发现有一些 I2C 设备搜索不到,主要原因是 DATA 的信号衰减,也可能是 I2C 的总线被拉住了。
软件层面的问题
例如在实现 Amigo 音频设备,录音与播放切换和重入功能实现,主要问题是 I2C 的传输超时问题。
如 amigo 的 ES8374 在通过 I2C 配置设备播放后,一条 4 设备的 I2C 变得很不稳定,排查后,发现通信失败后, SDA 脚失败后持续为低,理论上 I2C 驱动应该在判断接收数据失败后,恢复为 高, 但实际上没有,所以现在的解决方法是重新配置为 GPIO 后手动拉高,然后就可以重新继续工作了。
这个问题是因为 I2C 从机端 K210 给出数据,从机应答了,并且拉低的数据线表示我知道了,要返回数据,但实际上并没有返回,而造成的结果就是,主机在等待从机的应答数据,从机也在等待主机的下一次读取请求,但谁也没办法继续运行了,理论上 K210 端在发现超时退出后应当恢复 I2C 总线的现场准备下一次的请求读取,但实际并没有进行这样预期的处理,所以临时的修复方案可以如下图。
附带代码:
# read reg value
def _readReg(self, regAddr):
while True:
try:
self.i2c_bus.writeto(self.i2c_addr, bytes([regAddr]))
return (self.i2c_bus.readfrom(self.i2c_addr, 1))[0]
except OSError as e:
#print(e)
from fpioa_manager import fm
from Maix import GPIO
tmp = fm.fpioa.get_Pin_num(fm.fpioa.I2C1_SDA)
fm.register(tmp, fm.fpioa.GPIOHS15)
sda = GPIO(GPIO.GPIOHS15, GPIO.OUT)
sda.value(1)
fm.register(tmp, fm.fpioa.I2C1_SDA, force=True)
# write value to reg
def _writeReg(self, regAddr, data):
while True:
try:
return self.i2c_bus.writeto_mem(self.i2c_addr, regAddr, data, mem_size=8)
except OSError as e:
#print(e)
from fpioa_manager import fm
from Maix import GPIO
tmp = fm.fpioa.get_Pin_num(fm.fpioa.I2C1_SDA)
fm.register(tmp, fm.fpioa.GPIOHS15)
sda = GPIO(GPIO.GPIOHS15, GPIO.OUT)
sda.value(1)
fm.register(tmp, fm.fpioa.I2C1_SDA, force=True)
需要注意的是,这个问题,应该迟早要在 BSP SDK 层面得到解决,内部的资源执行方式出了问题,考虑不周全。
硬件层面的问题
刚才我们说的是从软件的角度发现问题,而另一种情况是完全于软件无关的情况。
同一份代码,如下读取 RGB Sensor 的代码,在 ESP32 上可以正常工作,但在 K210 上则无法正常工作,操作逻辑保持一致,也不受到执行时序的影响,从逻辑分析上出现的结果如下图。
可以看到后者 K210 的信号发出后,从机并没有做出 ACK 操作 DATA 线的应答,那此时的问题会是什么呢?
我们接一台示波器就可以发现了,主要原因是实际的信号有差异。
嗯,衰减的那个就是 K210 的(时好时坏),这种信号从机芯片不一定可以识别得到,实际输出的信号与 下方 ESP32 输出的信号对比一下就存在差距。
剩下就自己想想有什么办法了,通常来说芯片 IO 上拉能力不够可能会有这种现象,但实际是不是这样呢?我们还是得检讨一下硬件线路和软件IO配置才能解决具体的问题了,这已经超过了我对本质问题的理解,等我之后能完美解决再做出解答吧。
注意,最近得到了解到 I2C 的总线上存在上拉电阻的差异,通常 I2C 都是开漏输出,所以需要一个外部的弱上拉电阻,那上拉电阻应该要多少呢,这里有一个参考 IIC为什么绝大多数时候都是带有上拉电阻呢? , 这件事早在 STM32 时期就存在这些现象了,大多数人不会用硬件的 I2C ,然后都用 软 I2C 的 GPIO 的推挽输出来解决问题了,但实际上只是不了解应该要如何配合那个硬 I2C 的上拉。
如果使用 GPIO 上拉就可以将它恢复到最开始的状态。
下次再说说 SPI 存在的问题吧~。