目录
FlexIo模块I2C
功能概述
通过S32K FlexIo模块模拟如下的I2C通信时序
实战结果
使用0x12作为虚假的从机地址来验证时序是否正确。
示波器显示结果:
逻辑分析仪显示结果:
使用真实从机地址0xD0:
示波器显示结果:
逻辑分析仪显示结果:
FlexIo相关寄存器配置及效果展示
TIMCTL配置:
TRGSEL | 配置TIMER的触发源-->选择Shifter0 flag,当Shitfer0寄存器为空时 flag置位从而触发Timer开始 |
TRGPOL | 要和Timer enable及shifter flag强相关 由于TRGSEL选择的是shifter0 flag。 当数据写入shift buffer时 flag为0,当shift buffer为空时flag为1. 而timer enable希望在trigger为high时。这时TRGPOL的选择就很重要了。 TRGPOL-0:当flag为0时Trigger high,当flag为1时Trigger为Low TRGPOL-1:当Flag为1时Trigger Low,当flag为0时Trigger为High 所以如希望时钟在数据写入到Shift buffer时Timer开始,则TRGPOL要设置为1. |
TRGSRC | 根据Trigger类型配置 |
PINCFG | 配置TIMER关联的PIN的状态 |
PINSEL | 选择哪一个PIN和TIMER关联 |
PINPOL | 从上图中可以看出,PIN的输入和输出都和PINPOL做异或。所以PINPOL->0时,与真实反馈物理信号,当PINPOL为1时,与真实物理信号相反 |
TIMOD | Timer的工作模式 |
TIMCFG配置:
TIMOUT | 配置在Timer使能时,输出的状态,它的输出和PINPOL是相互关联的(如:当PINPOL设置为0 Active High,则当TIMOUT为1(Timer output is logic zero)) |
TIMDEC | TIMER计数器递减规则(SCL:FlexIO时钟,SDA关联的输入PIN) |
TIMRST | 可能在其他协议里面会用到I2C中目前用010b就可以了 |
TIMDIS | TIMER disable |
TIMENA | 使能TIMER |
TSTOP | 决定什么时机插入STOP bit |
TSTART | 决定是否插入Start bit |
相关参数配置及效果
TRGPOL | 1 |
PINPOL | 0 |
TIMOUT | 1 |
图1
TRGPOL | 1 |
PINPOL | 1 |
TIMOUT | 1 |
图2
TRGPOL | 1 |
PINPOL | 1 |
TIMOUT | 0 |
图3
TRGPOL | 1 |
PINPOL | 0 |
TIMOUT | 0 |
图4
TRGPOL | 0 |
PINPOL | 1 |
TIMOUT | 0 |
图5
TRGPOL | 0 |
PINPOL | 1 |
TIMOUT | 1 |
图6
配置结果分析
图5和图6没有数据输出,是由于产生CLK的TIMER没有被使能。
分析没有被使能的原因:
Trigger的机制与PINPOL的结构相同,都是进行异或操作。
SHIFTSTAT | TRGPOL | trigger |
1(shift buff为空) | 0 | high |
0(shift buff写入值) | 0 | low |
1 | 1 | low |
0 | 1 | high |
所以对于图1、图2,trigger为High,timer可以被enable。而图5、6 timer不能被使能,所以没有时钟输出从而数据也无法输出(数据的输出是由于CLK的时钟沿触发的)。
时钟起始电平及时钟沿个数分析
图1和图2可以看出由于PINPOL的不同,导致CLK输出的电平反相。图1中发送两个byte的时钟是18个clock。每个byte插入一个Stop位,所以发送一个byte需要9个clock。
图4中SDA线被快速拉起是由于SDA的数据是在TIMER的下降沿开始传输数据的。
由于图1和图2中发送数据是一致的,只所以示波器上第9位和第18位不同,主要是图1中从机将第9位和第18位拉低产生了ACK位。
TIMOUT和PINPOL决定了第一个时钟沿的高低,也是异或操作
TIMOUT | PINPOL | 第一个时钟信号 |
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 0 |
图1中第一个时钟信号为低,它将SCL线拉低。
图2中第一个时钟信号为高,它将SCL线拉高从而看起来多产生了一个时钟信号,由于数据的移位是由时钟沿决定了,所以图2中从第一个“时钟沿”的下降沿开始传数据,其实它并不是真实的时钟信号。
图3中发送2个Byte有20个时钟。主要是由于第一个时钟沿要是低的而SCL电平开始就是低,所以为了产生一下低电平,芯片会将SCL先拉高再拉低。第20个时钟是由于TIMER disable时要将SCL位低从而产生了一个时钟信号,因此第一个和最后一个时钟信号都是虚假的。
SHIFTCFG配置:
INSRC | Input source |
SSTOP | 控制Stop condition的产生时机(它可以用来产生相应的NACK标识) |
SSTART | 控制Start condition产生的时机 |
SHIFTCTL配置:
TIMSEL | 选择发送及接收的时钟 |
TIMPOL | 选择发送或接收数据的时机 |
PINCFG | 控制PIN的状态(输入,输出) |
PINSEL | 选择(输入、输出)PIN |
PINPOL | 选择控制(输入、输出)PIN的状态,它直接决定了使用的shift buffer的类型 |
SMOD | 选择Shifter是发送还是接收 |
如何产生期望的I2C控制时序
如何产生相应的NACK信号
ACK是由slave产生的。Master要产生NACK,所以在发送完每一个Byte数据后要产生NACK。
从芯片手册上可以得知,这个NACK可以由STOP bit来产生。
Stop bits可以在timer Compare或者timer disable时产生,所以可以通过控制输出Shift的Timer来控制。
如上图:
如果要连续传输3个byte每个byte传输完成后从机都会产生一个ACK位。则需要将Tx shift的数据大小设置为8(寄存器中写入15,计数器的递减模式是上下沿的),这样每传输一个byte都会产生一个stop bit。
如何发送数据
现在来解决在什么时机向Shift buff寄存器中写入更新的数据。
从下图中可以看出,在发送timer计数器为0时Shift buffer中的数据写入到shifter中。
如果在这时向Shift buffer中写入数据就太慢了。所以不能在这个时机写入更新的数据。需要在上一次的数据传入Shifter后Shift buffer为空时就要写入。
从SHIFTSTAT中可以看出当数据传入Shifter后,Shift buffer为空时,shift这个寄存器会被置位。
从SHIFTSDEN中可以看出,Shifter status flag的变化可以触发DMA,所以考虑使用DMA来更新数据。
DMA的配置Source Addr是要写和到Shift buffer中数据的存储的首地址,Destination Address是Shift buffer的地址。
需要注意的是由于先用的是shift statu flag这个slot,所以在配置DMAMUX时Trigger位是不能使能的。
DMA传输时,虽然每次有效的只有8个bit但是是以32bit来控制的。主要是由于Tx Shifter关联的时钟决定的。时钟每8个Bit来产生一个Stop位。
其实关于STOP Bit也可以通过发送Shitfter中数据来控制,而不是使用timer插入的Stop bit。由于使用的是32bit的寄存器来控制的8bit数据,所以可以在第9个bit的数据可以用来控制输出ACK/NACK,当然Clock的计数为9个clock。(第9个Clock用来读取第9个Bit产生ACK/NACK,个人测试也是可以通过的)。
关于如何产生Restart bit
从手册上可以看出发送寄存器会额外加载一个word的数据。如果要产生Stop位则这个数据为0x00,如果要产生repeated start则这个数据为0xFF,所以在使用DMA传输数据时要额外多一个数据来控制repeated start还是stop.
另外FlexIO DMA功能的使能时机也非常重要。因为DMA会被shifter status flag使能。从而导致数据一直发送。所以要在DMA major循环结束的中断中disable FlexIo DMA的功能。在重新发送数据时再次使能DMA功能。
含有Repeated Start的功能时,也可以看作时两次DMA传输。上一次DMA传输结果时,产生Repeated Start,而后一次结束时产生stop bit。