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 <common.h>

#include <asm/gpio.h>

#include <i2c.h>

#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");

}


最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容