本文主要介紹基于zynq的IIC的驅(qū)動(dòng)架構(gòu),通過代碼編寫來深入了解IIC驅(qū)動(dòng)的內(nèi)容和機(jī)制。
1. IIC驅(qū)動(dòng)架構(gòu)
IIC驅(qū)動(dòng)包含兩部分:IIC總線驅(qū)動(dòng)和設(shè)備驅(qū)動(dòng)??偩€驅(qū)動(dòng)是對(duì)硬件設(shè)備適配器端的實(shí)現(xiàn),主要包含i2c_adapter,i2c_algorithm和控制i2c適配器產(chǎn)生通信信號(hào)的函數(shù)。I2c_adapter和一套i2c讀寫algorithm綁定,i2c_algorithm包含對(duì)i2c總線的訪問方式。IIC總線驅(qū)動(dòng)完成i2c_driver的注冊(cè),IO空間分配,IIC硬件設(shè)備時(shí)鐘的設(shè)定,主從模式以及收發(fā)模式的設(shè)定等。通過i2c_adapter可以控制I2C總線上開始,結(jié)束等信號(hào)的產(chǎn)生。
IIC設(shè)備驅(qū)動(dòng)提供用戶空間和i2c總線驅(qū)動(dòng)的交互,其定義了i2c_client數(shù)據(jù)結(jié)構(gòu)以及文件操作ioctrl,open,write等。I2c_client依附于i2c_adapter,用戶通過i2c_client結(jié)構(gòu)來調(diào)用相應(yīng)的i2c_adapter,來實(shí)現(xiàn)IIC控制。具體層次結(jié)構(gòu)如下:
User ioctrl--------->
I2c_client------------>
I2c_adapter------------>
I2c_algorithm--------------->
IIC硬件
2. zynq上IIC驅(qū)動(dòng)試驗(yàn)
基于黑金的zynq7020開發(fā)板,通過IIC來讀寫EEPROM,首先在PS端選擇IIC端口,導(dǎo)出到PL端,分配引腳。
代碼分析:
首先定義一個(gè)i2c_dev,用于綁定到platfrom總線上。結(jié)構(gòu)體中包含i2c_adapter,以及用于收發(fā)數(shù)據(jù)的buffer(p_send_buf和p_recv_buf),completion用于等待數(shù)據(jù)發(fā)送過程。
struct eeprom_i2c_dev{
struct device *dev;
struct i2c_adapter adapter;
unsigned long size;
void __iomem *baddr;
struct i2c_msg *p_msg;
unsigned char *p_send_buf;
unsigned char *p_recv_buf;
unsigned int recv_cnt;
unsigned int send_cnt;
int hold_falg;
int irq;
struct completion msg_completion;
spinlock_t xfer_lock;
u32 i2c_clk;
u32 input_clk;
struct clk *clk;
u32 ctrl_reg;
};
I2c_driver中主要包含了驅(qū)動(dòng)注冊(cè)和卸載函數(shù)。
static struct platform_driver eeprom_i2c_driver = {
.driver={
.name=DRIVER_NAME,
.owner=THIS_MODULE,
.of_match_table=eeprom_i2c_of_match,
},
.probe=eeprom_i2c_probe,
.remove=eeprom_i2c_remove,
};
現(xiàn)在分析probe函數(shù):
首先從設(shè)備樹中獲得內(nèi)存地址以及中斷號(hào),并分配IO虛擬內(nèi)存。
static int eeprom_i2c_probe(struct platform_device *pdev){
……
res=platform_get_resource(pdev, IORESOURCE_MEM, 0);
……
base=ioremap(res->start, resource_size(res));
……
res=platform_get_resource(pdev, IORESOURCE_IRQ, 0);
指定i2c_adapter的i2c_algorithm。
idev->adapter.owner = THIS_MODULE;
idev->adapter.dev.of_node = pdev->dev.of_node;
idev->baddr=base;
idev->irq=irq;
idev->size=size;
idev->dev=&pdev->dev;
idev->adapter.timeout=msecs_to_jiffies(1000);
idev->adapter.algo=&eeprom_i2c_algo;
idev->adapter.algo_data = idev;
idev->adapter.dev.parent = &pdev->dev;
snprintf(idev->adapter.name, sizeof(idev->adapter.name), "EEPROM I2C at %08lx", strt_addr);
根據(jù)設(shè)備樹中時(shí)鐘配置IIC硬件中的時(shí)鐘寄存器。
idev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(idev->clk)) {
dev_err(&pdev->dev, "input clock not found./n");
return PTR_ERR(idev->clk);
} ret=clk_prepare_enable(idev->clk);
if(ret)
dev_err(&pdev->dev, "unable to enable clcok/n");
idev->input_clk=clk_get_rate(idev->clk);
idev->ctrl_reg = EEPROM_I2C_CR_ACK_EN | EEPROM_I2C_CR_NEA | EEPROM_I2C_CR_MS;
ret=eeprom_i2c_setclk(idev->input_clk, idev);
IIC接收數(shù)據(jù)要申請(qǐng)中斷。
ret=devm_request_irq(&pdev->dev, irq, eeprom_i2c_irq, 0, DRIVER_NAME, idev);
i2c_add_adapter用于將i2c_adapter加入到總線中。這個(gè)時(shí)候i2c_dev.c是可以通過通知連來檢測(cè)到這個(gè)i2c_adapter的,并能為其分配設(shè)備號(hào)。然后用戶就可以通過直接操作這個(gè)設(shè)備來實(shí)現(xiàn)IIC讀寫了。
接下來看i2c_algorithm:
static const struct i2c_algorithm eeprom_i2c_algo = {
.master_xfer=eeprom_i2c_master_xfer,
.functionality=eeprom_i2c_func,
};
eeprom_i2c_master_xfer是通信函數(shù),其中有:
eeprom_i2c_mrcv用于處理接收到IIC設(shè)備數(shù)據(jù),eeprom_i2c_msend用于處理發(fā)送數(shù)據(jù),函數(shù)主要通過配置IIC硬件設(shè)備中寄存器來實(shí)現(xiàn)。
現(xiàn)在來看用戶如何操作IIC:
i2c_rdwr_ioctl_data是i2c_dev.c中用于存儲(chǔ)的收發(fā)數(shù)據(jù)的結(jié)構(gòu),通過它可以傳遞數(shù)據(jù)。在work_queue中的msgs中設(shè)定好slave_addr,len等值,然后通過ioctrl可以讀寫IIC了。
編輯:hfy
-
IIC總線
+關(guān)注
關(guān)注
1文章
66瀏覽量
20414 -
Zynq
+關(guān)注
關(guān)注
10文章
610瀏覽量
47328 -
IIC驅(qū)動(dòng)程序
+關(guān)注
關(guān)注
0文章
2瀏覽量
5061
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
基于Zynq的OLED驅(qū)動(dòng)設(shè)計(jì)
ZYNQ PS端IIC接口使用筆記分享
ZYNQ PS端IIC接口使用筆記分享
ARM-Linux-IIC設(shè)備的添加與驅(qū)動(dòng)實(shí)現(xiàn)
![ARM-Linux-<b class='flag-5'>IIC</b>設(shè)備的添加與<b class='flag-5'>驅(qū)動(dòng)</b>實(shí)現(xiàn)](https://file.elecfans.com/web2/M00/49/5F/pYYBAGKhtEqAIjveAAAP4TJY8Is419.jpg)
iic驅(qū)動(dòng)
IIC總線初始化基本驅(qū)動(dòng)參考程序應(yīng)用代碼免費(fèi)下載
![<b class='flag-5'>IIC</b>總線初始化基本<b class='flag-5'>驅(qū)動(dòng)</b>參考程序應(yīng)用代碼免費(fèi)下載](https://file.elecfans.com/web1/M00/82/FE/pIYBAFw-4ieABa4-AAF_wxoD9yo995.png)
使用51單片機(jī)進(jìn)行IIC和EEPROM的驅(qū)動(dòng)程序免費(fèi)下載
![使用51單片機(jī)進(jìn)行<b class='flag-5'>IIC</b>和EEPROM的<b class='flag-5'>驅(qū)動(dòng)</b>程序免費(fèi)下載](https://file.elecfans.com/web1/M00/96/DF/pIYBAF0HTjWAZhksAAC4YXNZSIM864.png)
使用IIC24C04芯片驅(qū)動(dòng)數(shù)碼管的程序和仿真電路圖
![使用<b class='flag-5'>IIC</b>24C04芯片<b class='flag-5'>驅(qū)動(dòng)</b>數(shù)碼管的程序和仿真電路圖](https://file.elecfans.com/web1/M00/C0/73/o4YBAF8IDe-AdV8SAANSuJSZ99U204.png)
Zynq-7000 PS端IIC接口使用筆記
![<b class='flag-5'>Zynq</b>-7000 PS端<b class='flag-5'>IIC</b>接口使用筆記](https://file.elecfans.com/web1/M00/DB/AA/o4YBAGAKISaAMFqHAAE3qBBBrho962.png)
ZYNQ PS端IIC接口使用筆記
![<b class='flag-5'>ZYNQ</b> PS端<b class='flag-5'>IIC</b>接口使用筆記](https://file.elecfans.com/web1/M00/DB/AA/o4YBAGAKISaAMFqHAAE3qBBBrho962.png)
STM32開發(fā)中使用C語言實(shí)現(xiàn)IIC驅(qū)動(dòng)
使用IIC去驅(qū)動(dòng)MPU6050時(shí)為什么總讀取失敗
![使用<b class='flag-5'>IIC</b>去<b class='flag-5'>驅(qū)動(dòng)</b>MPU6050時(shí)為什么總讀取失敗](https://file.elecfans.com/web2/M00/1B/9A/poYBAGGF5USAb5eFAAA0VasJyJM151.png)
STM32開發(fā)中使用C語言實(shí)現(xiàn)IIC驅(qū)動(dòng)
![STM32開發(fā)中使用C語言實(shí)現(xiàn)<b class='flag-5'>IIC</b><b class='flag-5'>驅(qū)動(dòng)</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評(píng)論