⑴ 求一个基于fpga的i2c总线控制器的源代码
// eeprom 24c02,08,16 radom byte read and write master
// author: jiajia.pi
// version: v1.2
// last modify date: 2014/08/19 change busy signal to ready
// clk_div range: 2~65535
// wr/rd bit is bit16 of wrdata, '0'=write, '1'=read
mole i2c_master(
clk, // global clock
reset_n, // global reset
scl, // i2c tri-state clock
sda, // i2c tri-state data
addr, // i2c word address
wrdata, // i2c 24bit write data, include device address, word address, 8bit write datas
rddata, // i2c 8bit read data
ready, // i2c ready output, assert high
ack // i2c acknowledge output
);
parameter [15:0] clk_div = 27_000_000/50_000-1; // i2c clock divsion
input clk;
input reset_n;
input wr;
input rd;
input [23:0]wrdata;
output [7:0]rddata;
output busy;
output ack;
inout scl;
inout sda;
reg [23:0]dat;
reg sco;
reg sdo;
reg [7:0]rddata;
reg busy;
reg ack1,ack2,ack3;
wire sda = sdo?1'bz:0;
wire scl = (sco|i2c_clk)?1'bz:0;
wire ready = !(wr||rd||busy);
wire rdnwr = dat[16];
wire ack = ack1|ack2|ack3;
reg[15:0] cnt;
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt <= 0;
else if(cnt<clk_div && busy)
cnt <= cnt + 1;
else
cnt <= 0;
wire i2c_clk_high_pos = (cnt==(clk_div>>2));
wire i2c_clk_low_pos = (cnt==(3*clk_div>>2));
wire i2c_dout_pos = (cnt==(clk_div));
wire i2c_din_pos = (cnt==(clk_div>>1));
reg i2c_clk;
always@(posedge clk or negedge reset_n)
if(!reset_n)
i2c_clk <= 0;
else if(i2c_clk_high_pos)
i2c_clk <= 1;
else if(i2c_clk_low_pos)
i2c_clk <= 0;
reg [5:0] sck_cnt;
always@(posedge clk or negedge reset_n)
if(!reset_n)
sck_cnt <= 63;
else if(rd|wr && !busy)
sck_cnt <= 0;
else if(!rdnwr && sck_cnt==19 && i2c_dout_pos)
sck_cnt <= 22;
else if(rdnwr && sck_cnt==30 && i2c_dout_pos)
sck_cnt <= 33;
else if(sck_cnt<44 && i2c_dout_pos)
sck_cnt <= sck_cnt + 1;
always@(posedge clk or negedge reset_n)
if(!reset_n)
dat <= 0;
else if(rd|wr && !busy)
dat <= wrdata;
always@(posedge clk or negedge reset_n)
if(!reset_n)
sdo <= 1;
else if(i2c_dout_pos)
case(sck_cnt)
0: sdo <= 1;
// write start
1: sdo <= 0;
// device address
2: sdo <= dat[23];
3: sdo <= dat[22];
4: sdo <= dat[21];
5: sdo <= dat[20];
6: sdo <= dat[19];
7: sdo <= dat[18];
8: sdo <= dat[17];
9: sdo <= 0; //device write
10: sdo <= 1; // ack1
// word address
11: sdo <= dat[15];
12: sdo <= dat[14];
13: sdo <= dat[13];
14: sdo <= dat[12];
15: sdo <= dat[11];
16: sdo <= dat[10];
17: sdo <= dat[9];
18: sdo <= dat[8];
19: sdo <= 1; // ack2
// read start
20: sdo <= 1;
21: sdo <= 0;
// write data
22: if(rdnwr) sdo <= dat[23]; else sdo <= dat[7];
23: if(rdnwr) sdo <= dat[22]; else sdo <= dat[6];
24: if(rdnwr) sdo <= dat[21]; else sdo <= dat[5];
25: if(rdnwr) sdo <= dat[20]; else sdo <= dat[4];
26: if(rdnwr) sdo <= dat[19]; else sdo <= dat[3];
27: if(rdnwr) sdo <= dat[18]; else sdo <= dat[2];
28: if(rdnwr) sdo <= dat[17]; else sdo <= dat[1];
29: if(rdnwr) sdo <= 1; else sdo <= dat[0];
30: sdo <= 1; // write ack3
// write stop
31: sdo <= 0;
32: sdo <= 1;
// read data
33: sdo <= 1; // bit 7
34: sdo <= 1; // bit 6
35: sdo <= 1; // bit 5
36: sdo <= 1; // bit 4
37: sdo <= 1; // bit 3
38: sdo <= 1; // bit 2
39: sdo <= 1; // bit 1
40: sdo <= 1; // bit 0
41: sdo <= 1; // read no ack
// read stop
42: sdo <= !rdnwr;
43: sdo <= 1;
endcase
always@(posedge clk or negedge reset_n)
if(!reset_n)
rddata <= 0;
else if(i2c_din_pos)
case(sck_cnt)
34: rddata[7]<= sda;
35: rddata[6]<= sda;
36: rddata[5]<= sda;
37: rddata[4]<= sda;
38: rddata[3]<= sda;
39: rddata[2]<= sda;
40: rddata[1]<= sda;
41: rddata[0]<= sda;
endcase
always@(posedge clk or negedge reset_n)
if(!reset_n)
ack1 <= 1;
else if(i2c_din_pos && sck_cnt==11)
ack1 <= sda;
always@(posedge clk or negedge reset_n)
if(!reset_n)
ack2 <= 1;
else if(i2c_din_pos && sck_cnt==20 && rdnwr) // read ack2
ack2 <= sda;
else if(i2c_din_pos && sck_cnt==22 && !rdnwr) // write ack2
ack2 <= sda;
always@(posedge clk or negedge reset_n)
if(!reset_n)
ack3 <= 1;
else if(i2c_din_pos && sck_cnt==31 && !rdnwr) // write ack3
ack3 <= sda;
else if(i2c_din_pos && sck_cnt==33 && rdnwr) // read ack3
ack3 <= sda;
always@(posedge clk or negedge reset_n)
if(!reset_n)
sco <= 1;
else if(sck_cnt==2 && i2c_clk_low_pos) // write start
sco <= 0;
else if(sck_cnt==21 && i2c_clk_low_pos && rdnwr) // read start high
sco <= 1;
else if(sck_cnt==22 && i2c_clk_low_pos && rdnwr) // read start low
sco <= 0;
else if(sck_cnt==32 && i2c_clk_low_pos && !rdnwr) // write stop
sco <= 1;
else if(sck_cnt==43 && i2c_clk_low_pos) // read stop
sco <= 1;
always@(posedge clk or negedge reset_n)
if(!reset_n)
busy <= 0;
else if(rd|wr && !busy)
busy <= 1;
else if(sck_cnt==44)
busy <= 0;
endmole
我自己写的,希望能帮到你
⑵ 如何使用linux的Documentation来写驱动
Linux I2C驱动是嵌入式Linux驱动开发人员经常需要编写的一种驱动,因为凡是系统中使用到的I2C设备,几乎都需要编写相应的I2C驱动去配置和控制它,例如 RTC实时时钟芯片、音视频采集芯片、音视频输出芯片、EEROM芯片、AD/DA转换芯片等等。
Linux I2C驱动涉及的知识点还是挺多的,主要分为Linux I2C的总线驱动(I2C BUS Driver)和设备驱动(I2C Clients Driver),本文主要关注如何快速地完成一个具体的I2C设备驱动(I2C Clients Driver)。关于Linux I2C驱动的整体架构、核心原理等可以在网上搜索其他相关文章学习。
本文主要参考了Linux内核源码目录下的 ./Documentation/i2c/writing-clients 文档。以手头的一款视频采集芯片TVP5158为驱动目标,编写Linux I2C设备驱动。
1. i2c_driver结构体对象
每一个I2C设备驱动,必须首先创造一个i2c_driver结构体对象,该结构体包含了I2C设备探测和注销的一些基本方法和信息,示例如下:
static struct i2c_driver tvp5158_i2c_driver = { .driver = { .name = "tvp5158_i2c_driver", }, .attach_adapter = &tvp5158_attach_adapter, .detach_client = &tvp5158_detach_client, .command = NULL, };
其中,name字段标识本驱动的名称(不要超过31个字符),attach_adapter和detach_client字段为函数指针,这两个函数在I2C设备注册的时候会自动调用,需要自己实现这两个函数,后面将详细讲述。
2. i2c_client 结构体对象
上面定义的i2c_driver对象,抽象为一个i2c的驱动模型,提供对i2C设备的探测和注销方法,而i2c_client结构体则是代表着一个具体的i2c设备,该结构体有一个data指针,可以指向任何私有的设备数据,在复杂点的驱动中可能会用到。示例如下:
struct tvp5158_obj{ struct i2c_client client; int users; // how many users using the driver }; struct tvp5158_obj* g_tvp5158_obj;
其中,users为示例,用户可以自己在tvp5158_obj这个结构体里面添加感兴趣的字段,但是i2c_client字段不可少。具体用法后面再详细讲。
3. 设备注册及探测功能
这一步很关键,按照标准的要求来写,则Linux系统会自动调用相关的代码去探测你的I2C设备,并且添加到系统的I2C设备列表中以供后面访问。
我们知道,每一个I2C设备芯片,都通过硬件连接设定好了该设备的I2C设备地址。因此,I2C设备的探测一般是靠设备地址来完成的。那么,首先要在驱动代码中声明你要探测的I2C设备地址列表,以及一个宏。示例如下:
static unsigned short normal_i2c[] = { 0xbc >> 1, 0xbe >> 1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD;
normal_i2c 数组包含了你需要探测的I2C设备地址列表,并且必须以I2C_CLIENT_END作为结尾,注意,上述代码中的0xbc和0xbe是我在硬件上为我的tvp5158分配的地址,硬件上我支持通过跳线将该地址设置为 0xbc 或者 0xbe,所以把这两个地址均写入到探测列表中,让系统进行探测。如果你的I2C设备的地址是固定的,那么,这里可以只写你自己的I2C设备地址,注意必须向右移位1。
宏 I2C_CLIENT_INSMOD 的作用网上有许多文章进行了详细的讲解,这里我就不详细描述了,记得加上就行,我们重点关注实现。
下一步就应该编写第1步中的两个回调函数,一个用于注册设备,一个用于注销设备。探测函数示例如下:
static int tvp5158_attach_adapter(struct i2c_adapter *adapter) { return i2c_probe(adapter, &addr_data, &tvp5158_detect_client); }
这个回调函数系统会自动调用,我们只需要按照上述代码形式写好就行,这里调用了系统的I2C设备探测函数,i2c_probe(),第三个参数为具体的设备探测回调函数,系统会在探测设备的时候调用这个函数,需要自己实现。示例如下:
static int tvp5158_detect_client(struct i2c_adapter *adapter,int address,int kind) { struct tvp5158_obj *pObj; int err = 0; printk(KERN_INFO "I2C: tvp5158_detect_client at address %x ...\n", address); if( g_tvp5158_obj != NULL ) { //already allocated,inc user count, and return the allocated handle g_tvp5158_obj->users++; return 0; } /* alloc obj */ pObj = kmalloc(sizeof(struct tvp5158_obj), GFP_KERNEL); if (pObj==0){ return -ENOMEM; } memset(pObj, 0, sizeof(struct tvp5158_obj)); pObj->client.addr = address; pObj->client.adapter = adapter; pObj->client.driver = &tvp5158_i2c_driver; pObj->client.flags = I2C_CLIENT_ALLOW_USE; pObj->users++; /* attach i2c client to sys i2c clients list */ if((err = i2c_attach_client(&pObj->client))){ printk( KERN_ERR "I2C: ERROR: i2c_attach_client fail! address=%x\n",address); return err; } // store the pObj g_tvp5158_obj = pObj; printk( KERN_ERR "I2C: i2c_attach_client ok! address=%x\n",address); return 0; }
到此为止,探测并且注册设备的代码已经完成,以后对该 I2C 设备的访问均可以通过 g_tvp5158_obj 这个全局的指针进行了。
首先树莓派得安装 python-smbus, i2c-tools,
然后修改文件:sudo nano /etc/moles,添加上 i2c-bcm2708 和i2c-dev 这两行,Raspbian还需要在raspi-config中激活i2c.
用 sudo i2cdetect -y 1 查看设备地址,
例子1:LCD2004,设备地址 为0x27;
先写个驱动调用程序 i2c_driver_lcd.py
import smbus
from time import *
# LCD Address
ADDRESS = 0x27
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
# set init LCD BACKLIGHT ON or OFF
def lcd_backlight(lcdbl=1):
if lcdbl == 0 :
return LCD_NOBACKLIGHT
return LCD_BACKLIGHT
En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit
class lcd(object):
#initializes objects and lcd
def __init__(self,lcd_bl,port=1):
self.addr = ADDRESS
self.bus = smbus.SMBus(port)
self.lcd_bl = lcd_bl
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x02)
self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)
⑷ 求嵌入式 linux 大师!
i2c工具在网上搜一下i2c-tools,开源的,交叉编译进你的系统,会有几个命令,i2c开头的 如:
i2c-stub-from-mp i2cmp i2cset
i2cdetect i2cget
然后使用就行了,希望能帮到你
⑸ 哪位兄台来点I2C的LCD使用方法
在Arino下正常使用,这说明LCD的地址就是0x27没错。但Pi下不能正常使用#include #include LiquidCrystal_I2C lcd(0x27,16,2);void setup(){ lcd.init(); lcd.backlight(); lcd.print("Hello, world!");}void loop(){}
⑹ 每次开机都有OSDTpDetect.exe和OOBEI2CTpOnOffDetect.exe报错说配置分析错误,求解决办法。神舟战神Z7系
使用360安全卫士,启动进程管理选项,找到这两个直接禁用掉。
禁用后再次开机看看,如果还是有卡顿黑屏,建议重新安装系统。
⑺ linux下怎么直接使用iic接口
利用Linux中IIC设备子系统移植IIC设备驱动
背景描述
IIC总线在嵌入式系统中应用十分广泛,常见的有eeprom,rtc。一般的处理器会包含IIC的控制器,用来完成IIC时序的控制;另外一方面,由于IIC的时序简单,使用GPIO口来模拟时序也是常见的做法。面对不同的IIC控制器,各种各样的芯片以及linux源码,如何更快做好IIC设备驱动。
问题描述
在我们的方案中,我们会用到eeprom,rtc以及tw2865。由于Hi3520的IIC控制器设计有问题,无法正常使用。而IIC控制器的SDA和SCL管脚正好是和两个GPIO管脚复用的。Hisi将控制gpio来实现IIC的时序,从而对IIC设备进行操作。这种设计方式简单明了,但使用IIC子系统,可以更方便的移植和维护其他的设备驱动。
问题分析
Hisi对于gpio口,rtc芯片以及tw2865的处理方式如下:将gpio口做成一个模块化的驱动,该驱动模拟IIC时序,并向外提供一些函数接口,比如:EXPORT_SYMBOL(gpio_i2c_read_tw2815);等。对于具体的rtc芯片,将其注册为一个misc设备,并利用gpio模块导出的函数进行rtc芯片的配置操作。
其实对于linux-2.6.24\drivers\i2c目录下代码,我们可以加以利用。
Linux的IIC字结构分为三个组成部分:
IIC核心
IIC核心提供了IIC总线驱动和设备驱动的注册、注销方法,IICalgorithm上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码。
IIC总线驱动
IIC总线驱动是对IIC硬件体系结构中适配器端的实现。
IIC设备驱动
IIC设备驱动是对IIC硬件体系总设备端的实现。
我们查看下该目录下的makefile和kconfig:
obj-$(CONFIG_I2C_BOARDINFO) +=i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) +=i2c-dev.o
obj-y +=busses/ chips/ algos/
i2c-core.c就是IIC核心,buses中的文件是主流处理器中IIC总线的总线驱动,而chips中的文件就是常用芯片的驱动,algos中的文件实现了一些总线适配器的algorithm,其中就包括我们要用到的i2c-algo-bit.c文件。
我们首先利用i2c-gpio.c和i2c-algo-bit.c做好总线驱动。
在i2c-gpio.c中,mole_initi2c_gpio_initplatform_driver_probe(&i2c_gpio_driver,i2c_gpio_probe);
将其注册为platform虚拟总线的驱动。
在staticint __init i2c_gpio_probe(struct platform_device *pdev)中,
定义了如下三个结构体:
structi2c_gpio_platform_data *pdata;//平台相关的gpio的设置
structi2c_algo_bit_data *bit_data;//包含algorithm的具体函数,setor
get SDA和SCL
structi2c_adapter *adap;//适配器
i2c_gpio_probe主要做了下面几件事:
填充bit_data结构的各个函数指针,关联到具体的操作SDA和SCl函数。
填充adap结构,adap->algo_data= bit_data;
pdata= pdev->dev.platform_data;
bit_data->data= pdata;
pdev->dev->driver_data= adap;
在i2c-core中注册适配器类型。
inti2c_bit_add_numbered_bus(struct i2c_adapter *adap)
在staticint i2c_bit_prepare_bus(struct i2c_adapter *adap)中
adap->algo= &i2c_bit_algo;
将i2c_bit_algo与adap关联上。
static const structi2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
其中,master_xfer函数指针就是IIC传输函数指针。
I2c-algo-bit.c还实现了IIC开始条件,结束条件的模拟,发送字节,接收字节以及应答位的处理。
i2c-gpio.c中的i2c_gpio_setsda_val等函数是与具体平台gpio相关的。
修改对应arch-hi3520v100目录下的gpio.h中的各个函数,这些函数是通过操作寄存器来控制gpio的方向和值。
在对应mach-hi3520v100中的platform-devices.c中添加如下:
static structi2c_gpio_platform_data pdata = {
.sda_pin = 1<<0,
.sda_is_open_drain = 1,
.scl_pin = 1<<1,
.scl_is_open_drain = 1,
.udelay = 4, /* ~100 kHz */
};
static struct platform_devicehisilicon_i2c_gpio_device = {
.name = "i2c-gpio",
.id = -1,
.dev.platform_data = &pdata,
};
static struct platform_device*hisilicon_plat_devs[] __initdata = {
&hisilicon_i2c_gpio_device,
};
int __inithisilicon_register_platform_devices(void)
{
platform_add_devices(hisilicon_plat_devs,ARRAY_SIZE (hisilicon_plat_devs));
return 0;
}
通过platform添加devices和driver,使得pdev->dev.platform_data=pdata
综合上面的过程,我们完成了adapter的注册,并将用gpio口模拟的algorithm与adapter完成了关联。
这样,在rtc-x1205.c中,x1205_attach函数利用i2c核心完成client和adap的关联。
在x1205_probe函数中填充i2c_client结构体,并调用i2c_attach_client通知iic核心。
接着注册rtc驱动。
最后我们要读取时间,就需要构造i2c_msg结构体,如下所示:
struct i2c_msg msgs[] = {
{ client->addr, 0, 2,dt_addr }, /* setup read ptr */
{ client->addr, I2C_M_RD,8, buf }, /* read date */
};
/* read date registers */
if((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
dev_err(&client->dev,"%s: read error\n", __FUNCTION__);
return -EIO;
}
dt_addr是寄存器的地址,I2C_M_RD表示iicread。
⑻ 求一个AT24C08的驱动程序
linux-2.6.22源码分析\linux-2.6.22\drivers\i2c\chips\eeprom.c为例,分析i2c设备驱动程序的原理
1.从驱动的入口函数开始分析
eeprom_init
>i2c_add_driver(&eeprom_driver)
>i2c_register_driver(THIS_MODULE, driver)
>is_newstyle_driver(driver) //这是一处宏定义:#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
/*用于判断是否是新风格的驱动,新风格的驱动i2c_driver成员的probe与remove函数指针都为空*/
接下来填充i2c_driver的owner与bus成员
>driver_register(&driver->driver)
>bus_add_driver(&driver->driver)也就是(struct device_driver * drv)//添加成功返回0
>list_add_tail(&driver->list,&drivers)//把该i2c_driver添加到链表drivers全局变量中
>list_for_each_entry(adapter, &adapters, list) //遍历adapters适配器链表的所有成员
{driver->attach_adapter(adapter);} //调用i2c_driver->attach_adapter
在eeprom.c中定义了一个全局变量:
static struct i2c_driver eeprom_driver = {
.driver = {
.name = "eeprom",
},
.id = I2C_DRIVERID_EEPROM,
.attach_adapter = eeprom_attach_adapter,
.detach_client = eeprom_detach_client,
};
2.i2c设备的探测过程分析
在1中遍历调用了适配器链表中的每一个成员的attach_adapter成员函数,来完成i2c设备的探测
driver->attach_adapter(adapter)
等效于
eeprom_attach_adapter
>i2c_probe(adapter, &addr_data, eeprom_detect)
//当探测到i2c设备后会调用第三个参数所指的函数:也就是函数eeprom_detect。
/*在i2c.h头文件中定义了addr_data全局变量
*static struct i2c_client_address_data addr_data = { \
* .normal_i2c = normal_i2c, \
* .probe = probe, \
* .ignore = ignore, \
* .forces = forces, \
*}
*/
⑼ linux i2c驱动 什么时候调用 detect
1、使用linux系统i2c体系,包括设备驱动,总线驱动,一般总线驱动已经写好了,需要你写一个设备驱动 2、使用gpio模拟i2c协议 3、望采纳 4、谢谢