⑴ 求一個基於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、謝謝