zephyr之i2C 和SCCB设备驱动

本文通过分析I2C和SCCB协议内容,说明为何I2C可以用于驱动SCCB设备,并给出了Zephyr下的实现代码。
本文所介绍的I2C和SCCB协议内容只是为了说明为何I2C可以驱动SCCB设备,这些内容只是其原本协议的一小部分,更多详细的内容请参考文后链接。

I2C和SCCB
由于SCCB在数据传输上几乎和I2C一致,大多数情况下大家都将SCCB当作I2C来使用,其实质上二者还是有一定区别的。

I2C
I2C是飞利浦推出的一种总线协议,最早是在使用在电视上的设备,后面被推广到其它设备。I2C总线由SDA和SCL两条线组成,SDA传输数据信号,SCL传输时钟信号,数据在Master和Salve进行双向同步传输。

I2C的基本信号
起始位:Master发送,开始一次传输,SCL高,SDA从高到底

结束位:Master发送,结束一次传输,SCL高,SDA从低到高

5ce8e26a574a571e348c113b8810ce0a.png

 

数据位:Master/Salve发送,有效数据bit,SCL高时,SDA的数据有效

ACK:Salve每接收到一个字节发送一个ACK,SCL高,SDA低

257c5c34c20ece74fdee519d06ef0982.png

 

NACK:Master/Salve不再接收下一个字节,SCL高,SDA高

6a35c8b35735592b81cdaec046912ee3.png

 

I2C的传输

6ea4ac754dcd02455fceb063a3ea6e31.png

 


I2C最基本的两种传输结构如下写数据
起始位+7bit从设备地址+1bit 0 + 1bit ACK + N*(8bit数据 + 1bit ACK) + 8bit数据 + 1bit ACK/NACK + 停止位

6ea4ac754dcd02455fceb063a3ea6e31.png

 

读数据
起始位+7bit从设备地址+1bit 1 + 1bit ACK + N*(8bit数据 + 1bit ACK) + 8bit数据 + 1bit NACK + 停止位

可见在传输过程中:第一个字节的高7bit指定Salve地址,最低的1bit指定读写方向,0表示写,1表示读。每发送/接收一个字节,就需要有一个ACK。最后一个字节传输完后有一个ACK/NACK,如果是Master写ACK和NACK可选,如果是Master读必须是NACK。

SCCB
SCCB全称叫Serial Camera Control Bus,是OmniVision推出专门用于摄像头控制的总线协议,在数据通信格式上和I2C非常类似,但SCCB和I2C是两个不一样的协议。

硬件
SCCB总线在硬件上是三线,除了数据和时钟外还有一条片选信号

5fa0619e8b1a04a5d1e6db3f5fc478eb.png
SCCB在简化情况下,可以只使用时钟和数据两条信号线,这也是可以将SCCB当作I2C使用的原因之一。

 

SCCB的基本信号
SCCB和I2C一样有起始位,结束位,数据位。
SCCB没有定义ACK和NACK。在SCCB Master写完8bit数据后, 第9bit时Salve会可以选择将数据线拉低,也可以选择让数据线处于浮动状态,数据线处于浮动状态的情况下Master并不会取读(关心)第9bit,因此叫Don’t Care bit。在SCCB Master在读完8bit数据后,第9bit把数据线拉高,叫做NA。
OV的摄像头支持Don’t care bit拉低,在这种情况下Don’t care与I2C的ACK的定义一致。而NA与I2C的NACK定义一致。这也就是为什么可以用I2C来驱动SCCB设备的原因。
但请注意,Don’t care bit有第二种用法,Salve让Don’t care处于浮动时,Salve接收发生错误时会在内部寄存器记录该错误状态,SCCB Master可以通过主动读该寄存器了解传输是否成功。该部分内容可以阅读SCCB spec进行详细了解.

SCCB的传输
SCCB将传输定义为3种: Phase 3, Phase 2 write, Phase 2 read,Phase 3传输3个字节,用于写数据:

2cc45fbee4eaf082b5bf5329d7908316.png

 

Phase 2 write传输2个字节,用于写访问的寄存器地址

1a623f4aa623b02eafef3727a9a7c921.png

Phase 2 read传输2个字节,用于读访问的寄存器地址

cf2a27dfd335a519029921e3af6a439c.png

 

通常情况下Phase2 Write后跟随Phase2 Read来完成一次SCCB完整的读。

I2C驱动SCCB
通过上面的分析,可以得到以下结论:SCCB简化为2线通信后,当Salve支持Don’t care bit 数据信号拉低,SCCB的基本信号和I2C完全一致,而SCCB的传输可以视作I2C传输的组合。那么在Zephyr下我们就可以使用I2C来驱动这种SCCB设备了。

有了前面的分析原理,代码实现很简单,见下面注释:

int sccb_write(struct device *i2c, unsigned char addr, unsigned int reg_addr, unsigned char reg_addr_size, unsigned char *buf, unsigned char size)

{ 
    //直接实现phase 3 
 struct i2c_msg msgs[2]; 
 msgs[0].buf = (uint8_t *)&reg_address; 
 msgs[0].len = reg_addr_size; 
 msgs[0].flags = I2C_MSG_WRITE; 
 msgs[1].buf = (uint8_t *)buf;
 msgs[1].len = size; 
 msgs[1].flags = I2C_MSG_WRITE | I2C_MSG_STOP; 
 return i2c_transfer(i2c, msgs, 2, addr);
}

int sccb_read(struct device *i2c, unsigned char addr, unsigned int reg_addr, unsigned char reg_addr_size, unsigned char *buf, unsigned char size)
{ 
struct i2c_msg msgs[2]; //Phase 2写 
msgs[0].buf = (uint8_t *)&reg_address;
 msgs[0].len = reg_addr_size; 
msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP; 
//Phase 2读 
msgs[1].buf = (uint8_t *)buf; 
msgs[1].len = size; 
msgs[1].flags = I2C_MSG_READ | I2C_MSG_STOP | I2C_MSG_RESTART; return i2c_transfer(i2c, msgs, 2, addr);
}


实际运行在OV7725上面的时序图:
写寄存器,典型的Phase 3

d9741ceb3ecaf0afd49bb5ce0aab9d8c.png
读寄存器,Phase 2 Write + Phase 2 Read

 49f945900872885d130c8f45017fae6c.png

 

参考
https://www.nxp.com/docs/en/user-guide/UM10204.pdf
http://www4.cs.umanitoba.ca/~jacky/Teaching/Courses/74.795-LocalVision/ReadingList/ov-sccb.pdf
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值