arm linux uboot通用IO模拟i2c,linux io模拟i2c通用iO i2c

关键字: linux i2c,IO模拟i2c, u-boot i2c, uboot i2c, 通用i2c


1. 这几天高lkt芯片,北京凌安的,你懂的,然后需要i2c, 而且是在u-boot下面的,

很多u-boot已经自动i2c的驱动了,但是不排除有部分不带的,例如rk的。

我之前在3288, 3399上就发现rk偷懒没做i2c uboot下的接口,也有可能是我的版本太久,

但不管怎样,做一个通用的i2c io模拟驱动多好??

其实我已经做了,而且这个驱动是经过实践的,非常好用,稳定的,而且移植性很强。既可以用在u-boot,也可以稍加修改,用在内核甚至应用层程序中,

源码里面都有注释。

现在把他记下来。



2. 废话少说,直接贴代码,通用的,自己注意改一下io定义。


#include

#include

#include

#include "lkt4106.h"

#include "des.h"

#define lkt_4106_slave_addr 0x50

#define PDU_MAX_LEN 256

//#define Lin_Dbg////调试用的打印

#ifdef Lin_Dbg

        #define PDBG(fmt, args...)  printf(fmt, ## args)

        #else

        #define PDBG(fmt, args...) /* empty debug slot */

#endif

void hex_str_to_uchar(unsigned char *dst, char *src, int len);

unsigned short get_crc16(unsigned char *pucFrame, unsigned short usLen);

#define I2C_SCL_PIN_NUM 102

#define I2C_SDA_PIN_NUM 103

#define I2C7_SDA_H  do{ gpio_direction_output(I2C_SDA_PIN_NUM, 1);gpio_set_value(I2C_SDA_PIN_NUM, 1);} while(0);//gpio2 b0, sda

#define I2C7_SDA_L  do{ gpio_direction_output(I2C_SDA_PIN_NUM, 0);gpio_set_value(I2C_SDA_PIN_NUM, 0);} while(0);//gpio2 b0, sda

#define I2C7_SCL_H  do{ gpio_direction_output(I2C_SCL_PIN_NUM, 1);gpio_set_value(I2C_SCL_PIN_NUM, 1);} while(0);//gpio2 A7, scl

#define I2C7_SCL_L  do{ gpio_direction_output(I2C_SCL_PIN_NUM, 0);gpio_set_value(I2C_SCL_PIN_NUM, 0);} while(0);//gpio2 A7, scl

int I2C7_IO_read_sda()

{

static int ret = -1;

gpio_direction_input(I2C_SDA_PIN_NUM);

udelay(1);

ret = gpio_get_value(I2C_SDA_PIN_NUM);

return ret;

}

/**

* I2C_start - 启动I2C传输

* @void: none

*/

void I2C_start(void)

{

I2C7_SDA_H; //发送起始条件的数据信号

udelay(1);

I2C7_SCL_H; //发送起始条件的时钟信号

udelay(4);//起始条件建立时间大于4.7us,不能少于

I2C7_SDA_L; //发送起始信号,起始条件锁定时间大于4us,这里也必须大于4us

    udelay(5);

I2C7_SCL_L; //钳住I2C总线,准备发送或接收

    udelay(2);

}

/**

* I2C_stop - 停止I2C传输

* @void: none

*/

void I2C_stop(void) //释放I2C总线

{

I2C7_SDA_L;//发送停止条件的数据信号

udelay(2);

I2C7_SCL_H;

udelay(4);//起始条件建立时间大于4us

I2C7_SDA_H;//发送I2C总线停止信号

udelay(5);//停止条件锁定时间大于4us

}

/**

* I2C_stop - 停止I2C传输

* @ackBit: 主机对从机发送的应答信号,在数据显示,1 bit,应答为0,非应答为1

* 例如发送I2C_send_ack(0)表示不应答

*/

void I2C_send_ack(int ackBit)

{

//发送的应答或非应答信号

if(ackBit){

I2C7_SDA_H;

}else{

I2C7_SDA_L;

}

udelay(2);

I2C7_SCL_H;//置时钟线为高使应答位有效

udelay(4);//时钟高周期大于4us,不同于器件发送到主机的应答信号

I2C7_SCL_L;

udelay(2);

}

/**

* I2C_write_one_byte - 向I2C发送一个字节的数据

* @ucData: 无符号8位,要发送的数据

*

* return: bAck,成功写入返回1,否则,失败返回0

*/

int I2C_write_one_byte(unsigned char ucData)

{

static int bACK = 0;

unsigned char i;

i=8;

while(i--){//8 位没发送完继续发送

if((ucData & 0x80)==0x80){

I2C7_SDA_H;//I2C MSB高位先发

}else{

I2C7_SDA_L;

}

udelay(2);

I2C7_SCL_H;//置时钟线为高通知被控器开始接收数据位

udelay(2);

I2C7_SCL_L;

ucData=ucData<<1;

}

udelay(1);

I2C7_SDA_H; //8位数据发送完,释放I2C总线,准备接收应答位

udelay(2);

I2C7_SCL_H;//开始接收应答信号

udelay(4);

if(1 == I2C7_IO_read_sda()){//应答只需普通最小数据锁存的延时时间

bACK=0;//高电平说明无应答

}else{

bACK=1;//低电平有应答

}

I2C7_SCL_L;//发送结束钳住总线准备下一步发送或接收数据

gpio_direction_output(I2C_SDA_PIN_NUM, 1);

udelay(2);

return(bACK);//正确应答返回1

}

/**

* I2C_read_one_byte - 向I2C读取一个字节的数据

* @void: none

*

* return: 返回一个读到的数据,1个字节

*/

unsigned char I2C_read_one_byte(void)

{

static unsigned char i=0,byteData=0;

gpio_direction_input(I2C_SDA_PIN_NUM);//置数据线为输入方式

i=8;

while(i--){

udelay(1);

I2C7_SCL_L; //置钟线为零准备接收数据

udelay(2);//时钟低周期大于4.7us

I2C7_SCL_H;//置时钟线为高使数据线上数据有效

udelay(1);

byteData=byteData<<1;

if(1==I2C7_IO_read_sda()) {++byteData;}

udelay(1);

}

I2C7_SCL_L;//8 位接收完置时钟线和数据线为低准备发送应答或非应答信号

udelay(1);

return(byteData);

}

/**

* I2C_read_str - 从I2C设备读入一串数据

* @ucSla: slave,从器件地址

* @ucAddress: 器件里面,要读的寄存器地址

* @ucBuf: 要读入的buf,读到数据存在这里

* @ucCount: 计划读入的字节数

*

* return: 读入数成功返回读到字节数,否则返回0

*/

unsigned int I2C_read_str(unsigned char ucSla,unsigned char ucAddress,unsigned char *ucBuf,unsigned int ucCount)

{

int i=0;

// I2C_start();

///////////////这段代码用在i2c eeprom上面//////////////////////

// if(1 != I2C_write_one_byte(ucSla)){//write one byte里包含应答

// I2C_stop();

// return 0;//选从器件的地址

// }

// printf("I2C_read_str, sla addr: %02x. \n", ucSla);

// if(1 != I2C_write_one_byte(ucAddress)){//选第一个寄存器地址

// I2C_stop();

// return 0;

// }

// printf("I2C_read_str, sla ucAddress: %02x. \n", ucAddress);

///////////////这段代码用在i2c eeprom上面//////////////////////

I2C_start();

//printf("I2C_read_str, i2c start.\n");

if(1 != I2C_write_one_byte(ucSla+1)){//发送读器件命令,ucSla+1表示要读的器件是ucSla

I2C_stop();

return 0;

}

//printf("I2C_read_str, I2C_write_one_byte:%02x.\n", ucSla+1);

i=ucCount;

while(i--){//执行ucount次,最后还要执行一次递减,例如,i=3,那么i=2,1,0, 跳出循环等于-1;

*ucBuf=I2C_read_one_byte();//读从器件寄存器

if(i)

I2C_send_ack(0);//未接收完所有字节,发送应答信号, 低电平应答,i2c飞利浦很低调

ucBuf++;

}

I2C_send_ack(1);//接收完所有字节,发送非应答信号, 1表示不应答

I2C_stop();

//printf("read str, finished, uCount:%d, i:%d. \n", ucCount, i);

return ucCount;

}

/**

* I2C_write_str - 向I2C设备写入一串数据

* @ucSla: slave,从器件地址

* @ucAddress: 器件里面,要读的寄存器地址

* @ucData: 要写入的数据数组

* @ucNo: 期望写入的个数

*

* return: 正确返回写入字节数,否则返回0

*/

unsigned int I2C_write_str(unsigned char ucSla,unsigned char ucAddress,unsigned char *ucData,unsigned int ucNo)

{

int i;

I2C_start();

if(1 != I2C_write_one_byte(ucSla)){

I2C_stop();//写入失败,直接发停止命令

return 0;//往I2C写命令

}

///////////////这段代码用在i2c eeprom上面//////////////////////

// if(1 != I2C_write_one_byte(ucAddress)){//

// I2C_stop();

// return 0;//写寄存器地址

// }

/////////////////这个加密芯片,不能用//////////////////////////

i=ucNo;

while(i--){

if(1 != I2C_write_one_byte(*ucData)){

I2C_stop();

return 0;//写数据

}

ucData++;

}

I2C_stop();//最后停止,返回1表示成功写入数组

//printf("read str, finished, uCount:%d, i:%d. \n", ucNo, i);

return ucNo;

}






 3. 使用方法:


#define lkt_4106_slave_addr 0x50

unsigned char test_cmd[] = {0x00, 0x05, 0x00, 0x84, 0x00, 0x00, 0x08};

int ret;

ret = I2C_write_str(lkt_4106_slave_addr, 0, test_cmd, sizeof(test_cmd));

if(!ret) {

printf("lkt41062 test cmd error %d.\n", ret);

} else {

printf("lkt41062 test cmd success.\n");

}


你可能感兴趣的:(arm linux uboot通用IO模拟i2c,linux io模拟i2c通用iO i2c)