介绍
SCCB(OmniVision serial camera control bus),即串行摄像机控制总线。OmniVision 公司已经定义和采纳的SCCB总线是一种三线结构的串行总线,用于完成对绝大多数OmniVision 系列图像传芯片功能的控制。它与IIC协议类似,但是不完全相同。
SCCB协议有两线也有三线的,两线的只能有一个主机一个从机,三线的可以有一个主机多个从机。在STM32的例程里用的是两线的,以下的时序是三线,在使用两线时只需要忽略SCCB_E就可以了,其他时序都是一样的。
与IIC的区别
1、SCCB是简化的I2C协议,SIO-l是串行时钟输入线,SIO-O是串行双向数据线,分别相当于I2C协议的SCL和SDA。
2、SCCB的总线时序与I2C基本相同,它的响应信号ACK被称为一个传输单元的第9位,分为Don’t care和NA。Don’t care位由从机产生;NA位由主机产生,由于SCCB不支持多字节的读写,NA位必须为高电平。
3、SCCB没有重复起始的概念,因此在SCCB的读周期中,当主机发送完片内寄存器地址后,必须发送总线停止条件。不然在发送读命令时,从机将不能产生Don’t care响应信号。
4、SCCB的写周期直接使用I2C总线协议的写周期时序;而SC-CB的读周期,则增加一个总线停止条件。
5、SCCB总线通信协议只支持100Kb/s或400Kb/s的传输速度。
引脚介绍
SCCB_E:输出(主机发出,单向),低电平有效,总线空闲时主机驱动此引脚为1,驱动为0时表示开始传输。
SIO_C:输出(主机发出,单向),总线空闲时主机驱动此引脚为1;当驱动SIO_E为0时,主机驱动此引脚为0或1;当挂起时主机驱动SIO_C为0,相当于时钟线。
SIO_D:IO口(双向),用于传输数据,当总线空闲时保持浮动,当系统挂起时保持低电平。
PWDN:输出(主机发出,单向),挂起引脚,当从机接受PWDN为0时,系统进入挂起状态。
具体时序图
1、如何传输一相数据
SCCB 3线时序图―总图
在不进行传输时 SCCB_E 与 SIO_C 处于高电平,SIO_D 处于高阻态
SCCB 3线时序图―开始时序图
将SIO_D和SIO_C拉高
将SCCB_E拉低
1.25us后将SIO_D拉低
50us后将SIO_C拉低
完成起始信号
SCCB 3线时序图―结束时序图
拉低SIO_D、拉高SIO_C
拉高SIO_D
0~1ns后拉高SCCB_E
SCCB_E维持高电平15ns
完成结束时序
先发送起始信号,而后 SIO_D 的数据在SIO_C处于低电平时改变,在SIO_C处于高电平时被传输,如此发送一相数据后,紧跟着发送结束信号,完成一相数据的传输。
2、发送什么样的数据
首先要说的是,一相包含9bit数据,8bit的数据和1bit的控制位。对OV摄像头寄存器进行配置的写操作需要三相,对其进行读取的读操作需要四相。
先介绍一下配置寄存器的 写操作:(最重要也是最有用的)
写操作需要传输三相数据,第一相为OV摄像头设备ID地址,第二相为所要配置的寄存器地址,第三相为所要写入的数据。尤其需要重视的是,设备ID地址只占7位,从D7到D1,第一相写设备ID地址的第8位数据是读写控制位R/W,0表示写,1表示读。
之后是配置寄存器的 读操作:
读操作由二相写操作和二相读操作构成,先进行二相写操作,向从机发送要读的寄存器地址,而后进行二相读操作,从机会把寄存器的值放在读操作的第二相中。二相写操作,其数据传输时序与三相写操作相同;二相读操作,所要注意的是,在读取数据后,主机要在第9个时钟低电平期间拉高数据线SIO_D,发送不应答信号NA。
不关心位:
写数据操作的一相数据的第9位为不关心位,它的目的是保证数据的完整性,其值为0表示数据发送成功,由从机发出,主机接收。
NAλ
读数据操作的一相数据的第9位为NA位,其值应该为1,主机发出。
硬件连接
1、一个主机一个从机
2、一个主机多个从机
此时应该与IIC一样,各从机并联,并保持SIO_D的电阻,该电阻保证了总线争用时不会发生短路。
挂起模式(低功耗)
有的摄像头具有挂起模式功能,对于OV系列来说挂起功能由引脚PWDN控制,在主机将PWDN拉低,随后50ns将SCCB_E、SIO_D、SIO_C 三个拉低,从机进入挂起状态。之后的唤醒需要先拉高SCCB_E、SIO_D、SIO_C ,50ns之后拉高PWDN。
STM32程序
#define SCCB_SCL PDout(3) //SCL #define SCCB_SDA PGout(13) //SDA #define SCCB_SDA_IN() {GPIOG->CRH&=0XFF0FFFFF;GPIOG->CRH|=0X00800000;} #define SCCB_SDA_OUT() {GPIOG->CRH&=0XFF0FFFFF;GPIOG->CRH|=0X00300000;} #define SCCB_SCL PDout(3) //SCL #define SCCB_SDA PGout(13) //SDA #define SCCB_READ_SDA PGin(13) #define SCCB_ID 0X42 //初始化SCCB接口 //CHECK OK void SCCB_Init(void) { RCC->APB2ENR|=1<<8;//使能PORT G时钟 RCC->APB2ENR|=1<<5;//使能PORT D时钟 //PORTG13 IN GPIOG->CRH&=0XFF0FFFFF; GPIOG->CRH|=0X00800000; GPIOG->ODR|=1<<13; //PD3 OUT GPIOD->CRL&=0XFFFF0FFF; GPIOD->CRL|=0X00003000; GPIOD->ODR|=1<<3; SCCB_SDA_OUT(); } //SCCB起始信号 //当时钟为高时,数据线由高到低,为起始信号 //在激活状态下,SDA与SCL均为低电平 void SCCB_Start(void) { SCCB_SDA=1; SCCB_SCL=1; delay_us(50); SCCB_SDA=0; delay_us(50); SCCB_SCL=0;//数据恢复低电平,单操作函数必要 } //SCCB停止信号 //当时钟为高时,数据线由低到高,为停止信号 //在空闲状态下,SDA与SCL均为高电平 void SCCB_Stop(void) { SCCB_SDA=0; delay_us(50); SCCB_SCL=1; delay_us(50); SCCB_SDA=1; delay_us(50); } //产生NA信号 void SCCB_No_Ack(void) { delay_us(50); SCCB_SDA=1; SCCB_SCL=1; delay_us(50); SCCB_SCL=0; delay_us(50); SCCB_SDA=0; delay_us(50); } //SCCB,写入一个字节 //返回0表示成功 u8 SCCB_WR_Byte(u8 dat) { u8 j,res; for(j=0;j<8;j++) //循环8次发送数据 { if(dat&0x80)SCCB_SDA=1; else SCCB_SDA=0; dat<<=1; delay_us(50); SCCB_SCL=1; delay_us(50); SCCB_SCL=0; } SCCB_SDA_IN(); delay_us(50); SCCB_SCL=1;//接收第9位,判断是否发送成功 delay_us(50); if(SCCB_READ_SDA)res=1; //SDA=1发送失败 else res=0; //SDA=0发送成功 SCCB_SCL=0; SCCB_SDA_OUT(); return res; } //SCCB 读取一个字节 //在SCL的上升沿,数据锁存 //返回值:读到的数据 u8 SCCB_RD_Byte(void) { u8 temp=0,j; SCCB_SDA_IN(); for(j=8;j>0;j--) //循环8次接收数据 { delay_us(50); SCCB_SCL=1; temp=temp<<1; if(SCCB_READ_SDA)temp++; delay_us(50); SCCB_SCL=0; } SCCB_SDA_OUT(); return temp; } //写寄存器 //返回值:0成功 u8 SCCB_WR_Reg(u8 reg,u8 data) { u8 res=0; SCCB_Start(); //起始信号 if(SCCB_WR_Byte(SCCB_ID))res=1; //写器件ID delay_us(100); if(SCCB_WR_Byte(reg))res=1; //写寄存器地址 delay_us(100); if(SCCB_WR_Byte(data))res=1; //写数据 SCCB_Stop(); //停止信号 return res; } //读寄存器 u8 SCCB_RD_Reg(u8 reg) { u8 val=0; SCCB_Start(); //起始信号 SCCB_WR_Byte(SCCB_ID); //写器件ID delay_us(100); SCCB_WR_Byte(reg); //写寄存器地址 delay_us(100); SCCB_Stop(); delay_us(100); //设置寄存器地址后才是读 SCCB_Start(); SCCB_WR_Byte(SCCB_ID|0X01); //发送读命令 delay_us(100); val=SCCB_RD_Byte(); //读数据 SCCB_No_Ack(); //发送NA SCCB_Stop(); //停止信号 return val; }
来源:51CTO
作者:Do_Not_Ask_Me
链接:https://blog.csdn.net/Do_Not_Ask_Me/article/details/100712311