简介
记录树莓派上baremetal
调试I2C的一些点
协议
总览
-
I2C一个master可以接多个slave
-
I2C总线使用两条线在master跟slave之间传输数据,SCL串行时钟线,SDA串行数据线
-
SCL跟SDA需要接上拉电阻,一般是4.7K,总线空闲时SCL和SDA处于高电平
-
标准模式
100Kbits/s
,快速模式400Kbit/s
起始与结束
- 当 SCL 线是高电平时 SDA 线从高电平向低电平切换,这个情况表示通讯的起始。
- 当 SCL 是高电平时 SDA 线由低电平向高电平切换,表示通讯的停止。
示波器抓到的开始信号跟停止信号如下
数据传输
I2C 总线在数据传输的时候要保证在 SCL 高电平期间,SDA 上的数据稳定,因此 SDA 上 的数据变化只能在 SCL 低电平期间发生,所以数据的采集需要看I2C高电平的时候SDA线的状态
ACK跟NACK
- SDA线上,ACK信号(应答)是低电平,NACK信号(非应答)是高电平。这部分比较好理解,因为空闲的时候总线上的上拉电阻会让SDA线为高。
- 对于SDA线,master跟slave都可以控制其为输入或者输出状态
- ACK/NACK的发生在发送完SDA线上发送8bit的data或者是7bit addr + 1bit rw之后,也即是每次传输的时候的第9个bit
- ACK产生的情况:数据接收端(master/slave)如果希望对方继续发送数据,则发送ACK信号
- NACK产生的情况:数据接收端希望结束数据传输,则对对方发送NACK信号,发送端收到该信号后会生成stop信号,结束此次传输
- 当然如果是一个不存在的地址,自然SDA线再第九个时钟的时候自然是拉高的
读写过程
基本一帧的传输格式如下,每传输一个字节的内容,都要等1bit
的应答信号
Read
的时候为高电平,Write
的时候为低电平
当然连续读,连续写的时候,不一定每次都要Start
跟Stop
信号都要来一遍
比如下面的波形图,先是发送器件地址,然后读了两个字节,返回结果分别是0x2
跟0xa9
Start
信号也可以重复,一般比如说读跟写交错这种情况(个人认为)
如图,这是参考的网上的图
尖峰毛刺
这个貌似比较容易出现,是一种控制真空的状态
本次波形情况是主设备向从设备写数据,在寻址结束确认应答后,从设备会拉低总线,在SCL切换到低电平时,立即释放SDA,主设备还没有反应过来,造成了“控制真空”,这时SDA被上拉电阻拉高,而如果下一步主设备将传输低电平数据位,就会造成这个尖峰毛刺,原理如下图所示。
具体波形
在baremetal
代码中,实现了i2c_detect
,其原理是向总线上所有地址都读一个字节,如下是从器件被扫描到的时候抓的波形
SDA
线上的变化如下
其中读方向以及ACK
放大,如下所示
最后的NACK
以及Stop
信号放大如下所示
而如下所示为扫描一个不存在的从机的波形
没有0x63
这个从机,第9个bit的时候SDA
就是高电平,也即NACK
编码
controller
使用I2C1
gpio
使用GPIO2
跟GPIO3
寄存器
控制器寄存器比较简单
其中关于Status
寄存器的描述,手册还是挺有意思的
总之就是RXF
,TXE
,RXR
,TXW
这四个跟中断的一些条件配合使用
RXD
,TXD
则是比较简单,查询模式用
控制器的代码主要参考这个链接
问题记录
在跑代码的时候,对一个局部数组进行初始化,触发了异常
从汇编一条条的跟,出问题的指令是xzr ,[sp, #34]
而ARM64
必须要保证栈指针是8字节对齐的,这里是把SP+34
的地址清零,所以这里触发了一个异常,不过现在也没有解决这个问题。反而单独对数组中的元素进行操作确实正常的,不理解。
参考链接
代办
-
10bit
寻址 SMBUS
- 中断模式,
DMA
模式 - 总线挂死恢复
- 总线仲裁参考
gpio
模拟