最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Zynq linux的I2C驅(qū)動(dòng)學(xué)習(xí)筆記

2021-11-18 11:33 作者:Vecloud_  | 我要投稿



最近在用米爾的Z-TURN BOARD單板做小項(xiàng)目。順便也加強(qiáng)學(xué)習(xí)I2C驅(qū)動(dòng),記一篇做記錄。?
I2C總線知識(shí)非常簡(jiǎn)單,SDA,SCL,他們的時(shí)序規(guī)則是:I2C總線是由數(shù)據(jù)線SDA和時(shí)鐘SCL構(gòu)成的串行總線,可發(fā)送和接收數(shù)據(jù)。在CPU與被控IC之間、IC與IC之間進(jìn)行雙向傳送,最高傳送速率100kbps。各種被控制電路均并聯(lián)在這條總線上,但就像電話機(jī)一樣只有撥通各自的號(hào)碼才能工作,所以每個(gè)電路和模塊都有唯一的地址,在信息的傳輸過(guò)程中,I2C總線上并接的每一模塊電路既是主控器(或被控器),又是發(fā)送器(或接收器),這取決于它所要完成的功能。CPU發(fā)出的控制信號(hào)分為地址碼和控制量?jī)刹糠?,地址碼用來(lái)選址,即接通需要控制的電路,確定控制的種類;控制量決定該調(diào)整的類別(如對(duì)比度、亮度等)及需要調(diào)整的量。這樣,各控制電路雖然掛在同一條總線上,卻彼此獨(dú)立,互不相關(guān)。?
I2C總線在傳送數(shù)據(jù)過(guò)程中共有三種類型信號(hào), 它們分別是:開(kāi)始信號(hào)、結(jié)束信號(hào)和應(yīng)答信號(hào)。?
開(kāi)始信號(hào):SCL為高電平時(shí),SDA由高電平向低電平跳變,開(kāi)始傳送數(shù)據(jù)。?
結(jié)束信號(hào):SCL為高電平時(shí),SDA由低電平向高電平跳變,結(jié)束傳送數(shù)據(jù)。?
應(yīng)答信號(hào):接收數(shù)據(jù)的IC在接收到8bit數(shù)據(jù)后,向發(fā)送數(shù)據(jù)的IC發(fā)出特定的低電平脈沖,表示已收到數(shù)據(jù)。CPU向受控單元發(fā)出一個(gè)信號(hào)后,等待受控單元發(fā)出一個(gè)應(yīng)答信號(hào),CPU接收到應(yīng)答信號(hào)后,根據(jù)實(shí)際情況作出是否繼續(xù)傳遞信號(hào)的判斷。若未收到應(yīng)答信號(hào),由判斷為受控單元出現(xiàn)故障。?
在LINUX系統(tǒng)初始化的過(guò)程中,通過(guò)?i2c_register_board_info,將所需要的I2C從設(shè)備加入一個(gè)名為_(kāi)i2c_board_list雙向循環(huán)鏈表,系統(tǒng)在成功加載I2C主設(shè)備adapt后,就會(huì)對(duì)這張鏈表里所有I2C從設(shè)備逐一地完成?i2c_client的注冊(cè)。?
也就是說(shuō),i2c_client和i2c_adapter都是由i2c_core來(lái)維護(hù)的。?
在xilinx-linux中,i2c從設(shè)備是通過(guò)dts文件傳遞給內(nèi)核的,內(nèi)核通過(guò)zynq_init_machine函數(shù)注冊(cè)所有的i2c從設(shè)備,i2c_client.?
I2C的linux必須知道4個(gè)結(jié)構(gòu)體:i2c_adapter,i2c_algorithm,i2c_client,i2c_driver?
struct i2c_adapter {?
struct module owner;?
unsigned int class; / classes to allow probing for /?
const struct i2c_algorithm algo; / the algorithm to access the bus /?
void *algo_data;?
/ data fields that are valid for all devices /?
struct rt_mutex bus_lock;?
int timeout; / in jIFfies /?
int retries;?
struct device dev; / the adapter device /?
int nr;?
char name[48];?
struct completion dev_released;?
struct mutex userspace_clients_lock;?
struct list_head userspace_clients;?
struct i2c_bus_recovery_info *bus_recovery_info;?
};?
i2c總線控制器數(shù)據(jù)依附于algo_data,比如xi2cps,s3c24xx_i2c。?
struct device dev;成員表明i2c_adapter是一個(gè)硬件,對(duì)應(yīng)SoC上的I2C控制器。而i2c_algorithm則是這個(gè)I2C控制器的底層驅(qū)動(dòng)程序。?
同理:?
struct i2c_client {?
unsigned short flags; / div., see below /?
unsigned short addr; / chip address - NOTE: 7bit /?
/ addresses are stored in the /?
/ LOWER 7 bits /?
char name[I2C_NAME_SIZE];?
struct i2c_adapter adapter; / the adapter we sit on /?
struct i2c_driver driver; / and our access routines /?
struct device dev; / the device structure /?
int irq; / irq issued by device /?
struct list_head detected;?
};?
struct i2c_client代表一個(gè)掛載到i2c總線上的i2c從設(shè)備,該設(shè)備所需要的數(shù)據(jù)結(jié)構(gòu),其中包括?
該i2c從設(shè)備所依附的i2c主設(shè)備?struct i2c_adapter adapter?
該i2c從設(shè)備的驅(qū)動(dòng)程序struct i2c_driver driver?
作為i2c從設(shè)備所通用的成員變量,比如addr, name等?
該i2c從設(shè)備驅(qū)動(dòng)所特有的數(shù)據(jù),依附于dev->driver_data下,在i2c_driver中的probe函數(shù)中設(shè)置這個(gè)結(jié)構(gòu)體成員。比如eeprom的eeprom_data。?
所有i2c從設(shè)備組成的雙向鏈表:detected?
struct device dev表明struct i2c_client代表的是一個(gè)硬件,比如eeprom芯片,或則rtc芯片,通過(guò)i2c總線連接到i2c_adapter硬件上。?
而i2c_driver則是這個(gè)i2c_client芯片硬件的驅(qū)動(dòng)程序。?
我們一般會(huì)對(duì)每個(gè)I2C字符設(shè)備定義一個(gè)私有信息結(jié)構(gòu)體,而i2c_client一般被包含在這個(gè)私有信息結(jié)構(gòu)體中??催^(guò)LDR3源代碼的hacker應(yīng)該比較清楚。?
i2c_client依附于i2c_adapter,也就是I2C設(shè)備和I2C總線控制器的對(duì)應(yīng)關(guān)系,一個(gè)i2c_adapter可以掛接多個(gè)i2c_client,i2c_adapter的struct list_head userspace_clients;結(jié)構(gòu)成員就是所有client的鏈表。?
linux的最新版本基本上支持目前所有的I2C適配器硬件和I2C從設(shè)備,但是對(duì)于工程師來(lái)說(shuō),可能要面臨各種情況:為i2c_adapter和i2c_client編寫(xiě)驅(qū)動(dòng)程序。?
二、I2C核心?
I2C核心是源碼位于drivers/i2c/i2c-core.c,它并不依賴于硬件平臺(tái)的接口函數(shù),是I2C總線驅(qū)動(dòng)和設(shè)備驅(qū)動(dòng)的紐帶。?
增加/刪除i2c_adapter?
int i2c_add_adapter(struct i2c_adapter adapter) //調(diào)用i2c_register_adapter()?
int i2c_del_adapter(struct i2c_adapter adapter)?
增加/刪除i2c_driver?
int i2c_register_driver(struct module owner, struct i2c_driver driver)?
int i2c_add_driver(struct i2c_driver driver) //調(diào)用i2c_register_driver?
void i2c_del_driver(struct i2c_driver driver)?
增加/刪除i2c_client?
struct i2c_client i2c_new_device(struct i2c_adapter adap, struct i2c_board_info const info)?
void i2c_unregister_device(struct i2c_client client)?
注:在2.6.30版本之前使用的是i2c_attach_client()和i2c_detach_client()函數(shù)。之后attach被merge到了i2c_new_device中,而detach直接被unregister取代。實(shí)際上這兩個(gè)函數(shù)內(nèi)部都是調(diào)用了device_register()和device_unregister()?
I2C傳輸、發(fā)送接收?
int i2c_transfer(struct i2c_adapter adap, struct i2c_msg msgs, int num)?
int i2c_master_send(struct i2c_client client,const char buf ,int count)?
int i2c_master_recv(struct i2c_client client, char buf ,int count)?
i2c_transfer()函數(shù)用于進(jìn)行I2C?適配器和I2C?設(shè)備之間的一組消息交互,i2c_master_send()函數(shù)和i2c_master_recv()函數(shù)內(nèi)部會(huì)調(diào)用i2c_transfer()函數(shù)分別完成一條寫(xiě)消息和一條讀消息。?
i2c_transfer()本身不能和硬件完成消息交互,它尋找i2c_adapter對(duì)應(yīng)的i2c_algorithm,要實(shí)現(xiàn)數(shù)據(jù)傳送就要實(shí)現(xiàn)i2c_algorithm的master_xfer(),這個(gè)函數(shù)與具體的硬件有關(guān),大部分時(shí)間由廠商完成。?
i2c_transfer()通過(guò)調(diào)用__i2c_transfer()完成I2C通訊:?
int __i2c_transfer(struct i2c_adapter adap, struct i2c_msg msgs, int num)?
{?
unsigned long orig_jiffies;?
int ret, try;?
/ Retry automatically on arbitration loss /?
orig_jiffies = jiffies;?
for (ret = 0, try = 0; try <= adap->retries; try++) {?
ret = adap->algo->master_xfer(adap, msgs, num);?
if (ret != -EAGAIN)?
break;?
if (time_after(jiffies, orig_jiffies + adap->timeout))?
break;?
}?
return ret;?
}?
可見(jiàn)retries為重傳嘗試次數(shù),timeout為超時(shí)時(shí)間。?
三、Linux I2C總線驅(qū)動(dòng)?
1、I2C適配器的加載和卸除?
加載:申請(qǐng)硬件資源,比如IO地址,中斷號(hào),調(diào)用i2c_add_adapter加載適配器?
i2c_add_adapter中會(huì)調(diào)用i2c_register_adapter函數(shù)?
static int i2c_register_adapter(struct i2c_adapter *adap)?
{?
device_register(&adap->dev); //完成I2C主設(shè)備adapter的注冊(cè),即注冊(cè)object和發(fā)送uevent等?
i2c_scan_static_board_info(adap); //注冊(cè)i2c_clienlt?
}?
static void i2c_scan_static_board_info(struct i2c_adapter adapter)?
{?
struct i2c_devinfo devinfo;?
down_read(&__i2c_board_lock);?
list_for_each_entry(devinfo, &i2c_board_list, list) {?
if (devinfo->busnum == adapter->nr?
&& !i2c_new_device(adapter,?
&devinfo->board_info))?
dev_err(&adapter->dev,?
“Can’t create device at 0x%02x\n”,?
devinfo->board_info.addr);?
}?
up_read(&i2c_board_lock);?
}?
i2c_new_device調(diào)用device_register注冊(cè)i2c從設(shè)備。?
那么,這個(gè)I2C從設(shè)備組成的雙向循環(huán)鏈表,是什么時(shí)候通過(guò)什么方式建立起來(lái)的呢??
以?/arch/ARM/mach-pxa/saar.c?為例?
static void __init saar_init(void)?
{?
saar_init_i2c();?
}?
static void __init saar_init_i2c(void)?
{?
pxa_set_i2c_info(NULL);?
i2c_register_board_info(0, ARRAY_AND_SIZE(saar_i2c_info));?
}?
static struct i2c_board_info saar_i2c_info[] = {?
[0] = {?
.type = “da9034”,?
.addr = 0x34,?
.platform_data = &saar_da9034_info,?
.irq = PXA_GPIO_TO_IRQ(mfp_to_gpio(MFP_PIN_GPIO83)),?
},?
};?
/ drivers/i2c/i2c-boardinfo.c /?
int __init i2c_register_board_info(int busnum, structi2c_board_info const info, unsigned len)?
{?
struct i2c_devinfo devinfo;?
devinfo->board_info = *info;?
list_add_tail(&devinfo->list, &__i2c_board_list); //將I2C從設(shè)備加入該鏈表中

了解更多網(wǎng)絡(luò)知識(shí)關(guān)注:http://www.vecloud.com/

Zynq linux的I2C驅(qū)動(dòng)學(xué)習(xí)筆記的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
武城县| 哈尔滨市| 伊吾县| 宜章县| 青阳县| 扶风县| 尉氏县| 聂拉木县| 二连浩特市| 澜沧| 河东区| 长岛县| 呈贡县| 班玛县| 永年县| 杭州市| 徐闻县| 温宿县| 阳原县| 大丰市| 大田县| 曲阜市| 芦山县| 山丹县| 广河县| 达日县| 青铜峡市| 南澳县| 贵港市| 潮安县| 汉川市| 临沂市| 乌兰县| 波密县| 永胜县| 隆昌县| 绍兴市| 琼中| 阜新| 宜宾市| 白朗县|