欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

I2C_SCL 时钟抖动问题之“if条件判断分支” 软件优化

程序员文章站 2023-12-25 08:29:09
...

I2C_SCL 时钟抖动问题之“if条件判断分支” 软件优化


一开始,我先给出一个比较常见的GPIO模拟的I2C的I2C_writeByte的代码,代码是从南京沁恒CH450的网站上download下来的推荐代码。

void CH450_I2c_WrByte(unsigned char dat) //写一个字节数据
{
 unsigned char i;
 CH450_SDA_D_OUT;   /* 设置SDA为输出方向 */
 for(i=0;i!=8;i++)  // 输出8位数据
 {
  if(dat&0x80) {CH450_SDA_SET;}
  else {
    CH450_SDA_CLR;
   }
  DELAY_0_1US;  // 可选延时,这边对应的为一个指令周期
  CH450_SCL_SET;
  dat<<=1;
  DELAY_0_1US;  // 可选延时,这边对应的为一个指令周期
  CH450_SCL_CLR;
 }
 CH450_SDA_D_IN;   /*设置SDA为输入方向 */
 CH450_SDA_SET;
 DELAY_0_1US;
 CH450_SCL_SET;  //接收应答
 DELAY_0_1US;
 CH450_SCL_CLR;
}

使用keil的逻辑分析工具,查看I2C波形,SCL一个周期内放大,发现仿真输出结果有差异。

I2C_SCL 时钟抖动问题之“if条件判断分支” 软件优化SDA为高变低的时候,CLK从之前拉高到之后拉高的周期时间,经历了14个指令周期(如上图所示,水平方向,1Grid=0.5us,即24M条件下的一个指令周期)
SCL从拉高,保持高,到拉低:5个指令周期
SCL从拉低(保持低)~SDA拉低,7个指令周期
SCL继续保持低~SCL拉高:2个指令周期
I2C_SCL 时钟抖动问题之“if条件判断分支” 软件优化

SDA为高变低的时候,CLK从之前拉高到之后拉高的周期时间,经历了16个指令周期(如上图所示,水平方向,1Grid=0.5us,即24M条件下的一个指令周期)
SCL从拉高,保持高,到拉低:5个指令周期
SCL从拉低(保持低)~SDA拉低,7个指令周期SCL继续保持低
SCL拉高:4个指令周期

对比两个情况的差异:SDA在SCL拉高以后第(5+7)个指令周期以后采样SDA的值时:
如果为低,则只执行2个汇编指令周期,
如果为高则后面运行4个汇编指令周期,

【原因分析】:汇编代码
中间的区别就是在判断分支上面的差异问题;
I2C_SCL 时钟抖动问题之“if条件判断分支” 软件优化
从上图中我们可以看到如果SDA检测为高,拉高SDA候,会运行SJMP C:095F指令,这个指令为两个指令周期,而else 也就是SDA为低时,拉低SDA候,程序自动就定位到C:095F 位置上,因此会导致差异!

【可能造成的不良影响】
实际上,虽然差异只有2个指令周期的时间,在24M时钟的情况下,Tclk的差异只有1us。但是这个CLK jitter是程序差异引入的,不是器件本身导致的,所以这个jitter是可以避免的。
另外,采样时,SDA高时,Tclk=14指令周期=7us; 对应T=142.857K
SDA低时,TCLK=16指令周期=8us;对应T=125K
差异,实际上已经很明显了!
更为关键的是,这个时钟抖动,其实跟晶振震荡关系不大,不管单片机用的是12M,或者11.0592M,亦或是24M,33M等,CLK抖动都是2个指令周期,以16个指令周期来算,变化率达到了1/8,12.5%的变化抖动,示波器应该是能够看出差异的。

【结论】
从上面分析的过程来看,由于单片机判断语句的分支差异,(我给出的示例if条件判断两个分支差异在汇编语句中,就差一个SJMP语句,也就是两个指令周期的时间)在驱动代码中的差异其实是不可忽略的,它会导致CLK产生时钟抖动的问题;

【解决方法&改善对策】
既然if条件判断,分支差异导致了2个指令周期的时间差异,我将SDA为低时的else语句中,增加了2个_NOP_()语句,从而弥补了差异。
I2C_SCL 时钟抖动问题之“if条件判断分支” 软件优化
这样,不管条件判断为真还是假,TCLK的时钟周期都是一样的,实际仿真的结果应该是一样的。

相关标签: 单片机

上一篇:

下一篇: