ARTICLE · 1104727
使用I2C硬件模块优于软件模拟
使用I2C硬件模块优于软件模拟 前面一篇文章提到尽量使用单片机的I2C硬件模块,避免使用软件方式模拟I2C接口,这篇继续探讨。欢迎评论区留言指正。 AI工具会给出某个芯片I2C驱动的代码示例,以软件模拟I2C通讯,代码放到工程里改改就能跑,屏蔽了MCU的硬件配置细节。一些开源项目和书籍中给出的一些代码样例也经常是软件模拟I2C通讯。这些示例大多已经过时或者延续了过时的代码。出现软件模拟方案的一个主要原因是硬件I2C配置的繁琐和容易出错,比如一些8位单片机,需要配置寄存器进行硬件初始化,I2C的原子命令和读写字节操作也都要包装成函数,如果单片机厂商不提供库,写这些指令函数需要非常小心,处理超时和应对信号干扰故障需要考虑周全,这个过程做起来比较耗时,但是软件模拟的I2C命令拿来稍微修改就能用。除了8位单片机外,也会看到一些开源STM32项目用软件模拟I2C通讯,不可否认的是一些老型号确实存在瑕疵和BUG,但大多是为了演示功能,省去硬件配置上的麻烦和问题,让提供的例子可以跑起来。还有因为I2C硬件配置或PCB设计上的缺陷导致I2C通讯偶发故障,改用软件模拟I2C通讯,以更好控制时序和恢复故障。极少数是因为走线和引脚接口限制,不得已用软件模拟I2C通讯。总之是为了省事,I2C通讯根本的问题没有解决。 先说说软件模拟I2C的优势,简单能用就不说了,主要优势是通过软件控制时序和主机SDA电平读写,可控性一目了然,出现总线锁死可以直接通过GPIO操作来恢复,不需要切换硬件模块和配置寄存器。条件允许,模拟I2C的SCL可以使用推挽模式,信号强,更好抗干扰。如果是自己手写实现代码,也可以对I2C的信号采样和输出有更深入的理解,方便排查通讯故障。软件模拟方式可以让单片机通过GPIO扩展出I2C接口,以连接更多的设备,这对只有1路I2C接口的单片机来说有时是必须的操作,隔离不同的器件到不同的总线可以隔离故障和排查原因。 软件模拟I2C的劣势比优势要更多。采用软件模拟方式,会占用更多CPU时间,模拟I2C时序过程中依靠软件延迟不容易把控时间粒度,很容易拉长等待时间,即使利用定时器实现延迟也会因其他中断的响应导致超出预定的延迟,直接后果就是I2C的通讯速度被降低。I2C是电平采样,所以延迟越长,电平持续时间越长,小的信号干扰甚至可以被过滤,有时看到的现象反而可能是通讯更稳,但速度可以被拉低到20K。这也隐藏了软件模拟过程中需要持续霸占CPU时间的诉求,一旦CPU被更高优先级的事件抢占,比如中断,I2C模拟的时序就会偏差,单片机和从机都可能出现误判,I2C通讯是一连串指令组成,在RTOS和抢占调度下,问题可能更容易出现,I2C总线死锁发生的概率会大增。问题出现的概率也受从设备的状态机设计和超时限额的影响。通过软件延迟霸占CPU会浪费计算资源,软件模拟方式无法使用DMA实现异步通讯,有些I2C从设备收到指令后需要几百毫秒执行任务后将结构输出到缓冲区,这个过程如果用软件模拟就很难利用这么长的等待时间去让CPU干其他的事。要使用DMA和中断实现异步通讯和减少CPU负担,只能使用硬件I2C模块。 使用软件模拟I2C主要的原因是不想去配置硬件寄存器,不想封装通讯函数和处理超时和故障逻辑。其实很多现代MCU早就解决了这个痛点,芯片厂商提供标准封装好的库函数,数据手册给出配置样例,像stm32甚至可以通过MX通过GUI界面进行傻瓜式配置,并且自动生成初始化代码。 现代MCU的算力越来越高,软件模拟似乎不消耗太多计算能力,但随着中断、DMA、操作系统的引入,可以充分利用这些资源利用硬件I2C模块实现I2C快速稳定的通讯,同时让多任务环境有更好的并发性能。除非是芯片本身确实存在瑕疵,能用硬件I2C还是用硬件的好。