小小的串口也能当I2C
FT232R作为一个质量比较好的串口,很多搞嵌入式的手头都会有一个,价格在20元左右,支持BITBANG模式也就意味着可以调试I2C
,做这个小东西的想法很久了,把手头的FT232串口发挥到极致。每次一个新的I2C
传感器或者摄像头的SCCB
想要调试总是太麻烦了,还要先写一个单片机或者拿到树莓派上用i2c-tools
。终于熬过期末考试,在家休息两天,做好后拖了几天才开始写博客,主要是写了也没什么人会看,一直再考虑是否要当一个UP主,没有写下去的动力,算是沽名钓誉,也是想的分享一下知识有所肯定。
后续还要扩展EEPROM
的支持和SPI FLASH
的读取和烧写,以后也会坚持更新。
前情提要
上一篇文章:FT232R(FDTI最常用和廉价的芯片之一)的BITABNG三种模式,即为本篇功能实现基础
源码链接:github:rede97/tinyboard-tools
这份代码已经基本实现了
i2c-tools
,原本是linux上非常实用的工具可惜windows是没有的,可以扫描I2C总线上的所有设备,读取8bit寄存器的数据,16bit还没有实现,我拿了GY91试验了下,发现是没有问题的,手头也没有更多的I2C模块了。
线路连接
TX->SCL
,RX<-->SDA
,直接连接就可以使用,不需要额外的连接之前想的太复杂了。
,
那两个10K的上拉电阻没有也是可以用的,毕竟这玩意没有开漏输出,之前还搞了一个肖特基二极管把推完变成了开漏输出,还有模有样4.7Kohm上拉电阻,当了回讲究怪。RX
用来控制和读取SDA
的电平,BITBANG
模式是没有办法中途切换输入输出模式的,所以需要两个引脚并到一起,TX
用来发生SCL
的时钟,接线就是这个样子。
最终成果
这里只接了GY91
,参数0
是第0个FTDI设备,0x68
是MPU9250
,0x76
是气压计BMP280
PS ~> .\i2cdetect.exe 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --
i2cdump
用来扫描0x68
设备的寄存器,0x75
寄存器who am i
也就是0x71
。
PS ~> .\i2cdump.exe 0 0x68
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: c5 ce e0 0e a0 17 25 cf fa f0 fb fd 00 5a 5b 77
10: bf b9 a5 00 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 01 e3 9c e3 7c cd
40: 6c fa 60 ff 1f 00 3b ff f0 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 1f 89
70: 00 00 00 00 00 71 00 15 fa 00 eb 12 00 22 82 00
80: c5 ce e0 0e a0 17 25 cf fa f0 fb fd 00 5a 5b 77
90: bf b9 a5 00 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 01 e3 9c e3 68 cc
c0: 24 fa 80 ff 15 00 2b ff a0 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 21 22
f0: 00 00 00 00 00 71 00 15 fa 00 eb 12 00 22 82 00
原理
配置FT232环境那一部分就不说了,上一篇文章里安排的明明白白,FT232R插上USB就是干!
芯片的配置
0x03
对应0b0011
,D0(TX-->SCL)
和D1(RX<-->SDA)
为输出。配制成其他管脚也是没有问题的。同步BITBANG模式都是先读取再输出电平,但是一开始配置为读取就只能读取没办法输出电平了。
ftStatus = FT_SetBitMode(handle, 0x03, FT_BITMODE_SYNC_BITBANG);
实际波特率是写进去波特率的6倍,IO的输出速率并不是真的只有9.6kHz。
ftStatus = FT_SetBaudRate(handle, 9600);
清理RX缓冲区,如果之前的程序退出的时候,接收缓冲的数据没有读取完,这次就会被原模原样读出来,不会被清空的。不清空出了bug我可不负责哦~
FT_Purge(handle, FT_PURGE_RX);
下面是扫描0x68
地址的ACK
信号判断的MPU9250
是否存在,可以照着这个思路理解源码的其他部分。这里I2C
序列生成的API
可以参考Arduino
的API
,基本是一致的。
至于为什么使用序列,需要注意的是,FTDI的驱动将序列发送个FT232芯片输出是需要一段时间的,序列不宜太短,这样会降低通信的效率,必须生成一段足够长的序列,然后读回结果然后判断解析。
uint8_t seq[64] = {0}; //波形序列
uint32_t nbytes;
uint32_t idx = i2c_begin(seq, 0x68); // begin序列
idx += i2c_stop(seq + idx); //stop序列
print_wave(seq, idx, 2); //输出WaveDrom支持的序列格式
FT_Write(handle, seq, idx, (LPDWORD)&nbytes);
FT_Read(handle, seq, nbytes, (LPDWORD)&nbytes);
print_wave(seq, idx, 2); //输出最终的响应后的序列结果
看看最终的输出结果吧!
# 生成用于输出的序列
1..0.10.10.10.10.10.10.10.10.10.1
1.0.1.....0..1..0.............10.
# 最终接收到的序列
1..0.10.10.10.10.10.10.10.10.10.1
1.0.1.....0..1..0...........1..0.
如果数字看起来够直观,就把他转换成时序图,这个图是有WaveDrom
生成的,SDAO
是第一个要输出的序列,SDAI
是读入的第二个序列。I2C
的begin
是start
加上send
发送addr|w|ack
,send
后都会跟一个SDA
高电平周期,用来接收从机的ACK
,stop
是高电平拉高SDA
复位I2C
总线,具体参考I2C
标准。
start
信号是将SDA
在SCL
高电平期间拉低。
然后发送地址0x68
和写信号0
。
这里是ack
信号和stop
信号,可以看出这里两个信号的区别,原本SDAO
输出的高电平在ACK
周期被拉低,说明这个设备地址在I2C
总线上是存在的。stop
信号则是SCL
高电平器件被拉高,stop
信号后的电平是需要多发送一个序列才可以读取到的,实际上没有我补充出来了。