2022/11/20
最近发现一些碎片化的知识,学完很快就忘了,想着写写博客,能加深一下理解,若日后有用得上的地方可以快速地拾掇起来。
–参考正点原子《领航者ZYNQ之嵌入式SDK开发指南》–
首先是I2C协议,有SCL,SDA两根线,在硬件上要确保这两根线上拉。
SCCB协议与I2C协议基本相同,可以看做是简化后的I2C协议,具体的区别在于I2C协议在数据位后跟着应答位,而SCCB应答位不关心,也就是默认从机应答了。再有就是I2C支持连续写,而SCCB不支持。
arm的sccb时序驱动代码
//产生sccb起始信号
void sccb_start(void)
{
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);
XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, 1);
usleep(4);
XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, 0); //START:when CLK is high,DATA change form high to low
usleep(4);
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0); //钳住I2C总线,准备发送或接收数据
}
//产生sccb停止信号
void sccb_stop(void)
{
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
XGpioPs_WritePin(&gpiops_inst,EMIO_SDA_NUM, 0); //STOP:when CLK is high DATA change form low to high
usleep(4);
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);
usleep(4);
XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, 1); //发送I2C总线结束信号
}
//产生ACK应答
void sccb_ack(void)
{
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, 0);
usleep(4);
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);
usleep(4);
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
usleep(4);
}
//sccb发送一个字节
void sccb_send_byte(u8 txd)
{
u8 t;
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0); //拉低时钟开始数据传输,时钟低电平数据有效
for(t=0; t<8; t++)
{
XGpioPs_WritePin(&gpiops_inst, EMIO_SDA_NUM, (txd&0x80)>>7);//取最高位,最高位最先发送
txd<<=1;
usleep(4);
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);
usleep(4);
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
usleep(4);
}
}
//SCCB接收一个字节
u8 sccb_rece_byte(void)
{
unsigned char i=0 , rxd=0;
XGpioPs_SetOutputEnablePin(&gpiops_inst, EMIO_SDA_NUM, 0);
XGpioPs_SetDirectionPin(&gpiops_inst, EMIO_SDA_NUM, 0);
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
usleep(4);
for(i=0;i<8;i++ )
{
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 1);//在时钟高电平读数据
usleep(2);
rxd <<= 1;
if( XGpioPs_ReadPin(&gpiops_inst, EMIO_SDA_NUM) ) {//高位首先接收
rxd = rxd | 0x01;
}
usleep(2);
XGpioPs_WritePin(&gpiops_inst, EMIO_SCL_NUM, 0);
usleep(4);
}
XGpioPs_SetDirectionPin(&gpiops_inst, EMIO_SDA_NUM, 1); //SDA设置为输出
XGpioPs_SetOutputEnablePin(&gpiops_inst, EMIO_SDA_NUM, 1);
return rxd;
}
#快速使用
时序写好了,重点在于怎么使用。(以ov7725的操作为例)
1.找到器件
2.找到器件的寄存器
3.写或读数据
//SCCB写寄存器
void sccb_write_reg8(u8 addr , u8 data)
{
sccb_start();//开始
sccb_send_byte(OV7725_DEV_ID);//找到器件
sccb_ack();//器件应答,SCCB不care
sccb_send_byte(addr);//找到寄存器
sccb_ack();//寄存器应答,SCCB不care
sccb_send_byte(data);//写寄存器
sccb_ack();
sccb_stop();//结束
}
//SCCB读寄存器
u8 sccb_read_reg8(u8 addr )
{
u8 rxd;
sccb_start();
sccb_send_byte(OV7725_DEV_ID);//先来一次虚写操作,找到器件和寄存器
sccb_ack();
sccb_send_byte(addr);
sccb_ack();
sccb_stop();
sccb_start();
sccb_send_byte(OV7725_DEV_ID | 0x01);//改为读操作
sccb_ack();
rxd = sccb_rece_byte();
sccb_ack();
sccb_stop();
return rxd ;
}