最新獲取網(wǎng)站訪客qq接口成人職業(yè)技術(shù)培訓學校
一、起源
減少垃圾代碼
減輕驅(qū)動開發(fā)工作量
驅(qū)動代碼和設備信息分離
參考Open Fireware設計
用來記錄硬件平臺中各種硬件設備的屬性信息
二、基本組成
兩種源文件:
-
xxxxx.dts dts是device tree source的縮寫
-
xxxxx.dtsi dtsi是device tree source include的縮寫,意味著這樣源文件用于被dts文件包含用
實際使用時,需要把dts文件編譯成對應的二進制文件(.dtb文件,dtb是device tree binary的縮寫 )便于運行時存放在內(nèi)存加快讀取信息的速度
三、基本語法
dts文件主體內(nèi)容由多個節(jié)點組成
每個節(jié)點可以包含0或多個子節(jié)點,形成樹狀關(guān)系
每個dts文件都有一個根節(jié)點,其它節(jié)點都是它的子孫
根節(jié)點一般來描述整個開發(fā)板硬件平臺,其它節(jié)點用來表示具體設備、總線的屬性信息
各個節(jié)點可以有多個屬性,每個屬性用key-value鍵值對來表示
節(jié)點語法:
[label:] node-name[@unit-address] { ? ?[properties definitions]; ? ?[child nodes]; }; ? label: 可選項,節(jié)點別名,為了縮短節(jié)點訪問路徑,后續(xù)節(jié)點中可以使用 ?&label 來表示引用指定節(jié)點 node-name: 節(jié)點名 unit-address: 設備地址,一般填寫該設備寄存器組或內(nèi)存塊的首地址 properties definitions:屬性定義 child nodes:子節(jié)點
屬性語法:
[label:] property-name = value; [label:] property-name; ? 屬性可以無值 有值的屬性,可以有三種取值: 1. arrays of cells(1個或多個32位數(shù)據(jù), 64位數(shù)據(jù)使用2個32位數(shù)據(jù)表示,空格分隔),用尖括號表示<> 2. string(字符串), 用雙引號表示 " " 3. bytestring(1個或多個字節(jié),空格分隔),用方括號表示[] 4. 用,分隔的多值
四、特殊節(jié)點
4.1 根節(jié)點
根節(jié)點表示整塊開發(fā)板的信息
#address-cells ? // 在子節(jié)點的reg屬性中, 使用多少個u32整數(shù)來描述地址(address) #size-cells ? ? ?// 在子節(jié)點的reg屬性中, 使用多少個u32整數(shù)來描述大小(size) compatible ? ? ? // 定義一系列的字符串, 用來指定內(nèi)核中哪個machine_desc可以支持本設備,即描述其兼容哪些平臺 ? ? ? ? ? ? ? ? ? ? ? ? model ? ? ? ? ? ?// 比如有2款板子配置基本一致, 它們的compatible是一樣的,那么就通過model來分辨這2款板子
4.2 /memory
所有設備樹文件的必需節(jié)點,它定義了系統(tǒng)物理內(nèi)存的 layout
device_type = "memory"; reg ? ? ? ? ? ? //用來指定內(nèi)存的地址、大小
4.3 /chosen
傳遞內(nèi)核啟動時使用的參數(shù)parameter
bootargs //字符串,內(nèi)核啟動參數(shù), 跟u-boot中設置的bootargs作用一樣
4.4 /cpus 多核CPU支持
/cpus節(jié)點下有1個或多個cpu子節(jié)點, cpu子節(jié)點中用reg屬性用來標明自己是哪一個cpu
所以 /cpus 中有以下2個屬性:
#address-cells ? // 在它的子節(jié)點的reg屬性中, 使用多少個u32整數(shù)來描述地址(address) #size-cells ? ? // 在它的子節(jié)點的reg屬性中, 使用多少個u32整數(shù)來描述大小(size) 必須設置為0
五、常用屬性
5.1 phandle
數(shù)字形式的節(jié)點標識,在后續(xù)節(jié)點中屬性值性質(zhì)表示某節(jié)點時,可以引用對應節(jié)點
如:
pic@10000000 { ? ?phandle = <1>; ? ?interrupt-controller; }; another-device-node { ? ?interrupt-parent = <1>; ? // 使用phandle值為1來引用上述節(jié)點 };
5.2 地址 --------------- 重要
reg屬性:表示內(nèi)存區(qū)域region,語法:
reg = <address1 length1 [address2 length2] [address3 length3]>;
#address-cells:reg屬性中, 使用多少個u32整數(shù)來描述地址(address),語法:
#address-cells = <數(shù)字>;
#size-cells:reg屬性中, 使用多少個u32整數(shù)來描述大小(size),語法:
#size-cells = <數(shù)字>;
5.3 compatible --------------- 重要
驅(qū)動和設備(設備節(jié)點)的匹配依據(jù),compatible(兼容性)的值可以有不止一個字符串以滿足不同的需求,語法:
compatible = "字符串1","字符串2",...;
5.4 中斷 --------------- 重要
a. 中斷控制器節(jié)點用的屬性:
interrupt-controller 一個無值空屬性用來聲明這個node接收中斷信號,表示該節(jié)點是一個中斷控制器
#interrupt-cells 這是中斷控制器節(jié)點的屬性,用來標識這個控制器需要幾個單位做中斷描述符
b. 中斷源設備節(jié)點用的屬性:
interrupt-parent:標識此設備節(jié)點屬于哪一個中斷控制器,如果沒有設置這個屬性,會自動依附父節(jié)點的,語法:
interrupt-parent = <引用某中斷控制器節(jié)點>
interrupts 一個中斷標識符列表,表示每一個中斷輸出信號,語法:
interrupts = <中斷號 觸發(fā)方式> ? 1 low-to-high 上升沿觸發(fā) 2 high-to-low 下降沿觸發(fā) 4 high level 高電平觸發(fā) 8 low level ? 低電平觸發(fā)
5.5 gpio --------------- 重要
gpio也是最常見的IO口,常用的屬性有:
a. 對于GPIO控制器:
gpio-controller,無值空屬性,用來說明該節(jié)點描述的是一個gpio控制器
#gpio-cells,用來表示要用幾個cell描述一個 GPIO引腳
b. 對于GPIO使用者節(jié)點:
gpio使用節(jié)點的屬性
xxx-gpio = <&引用GPIO控制器 GPIO標號 工作模式> 工作模式: 1 低電平有效 GPIO_ACTIVE_HIGH 0 高電平有效 GPIO_ACTIVE_LOW
5.6 屬性設置套路
一般來說,每一種設備的節(jié)點屬性設置都會有一些套路,比如可以設置哪些屬性?屬性值怎么設置?那怎么知道這些套路呢,有兩種思路:
-
抄類似的dts,比如我們自己項目的平臺是4412,那么就可以抄exynos4412-tiny4412.dts、exynos4412-smdk4412.dts這類相近的dts
-
查詢內(nèi)核中的文檔,比如Documentation/devicetree/bindings/i2c/i2c-imx.txt就描述了imx平臺的i2c屬性設置方法;Documentation/devicetree/bindings/fb就描述了lcd、lvds這類屬性設置方法
六、常用接口
struct device_node 對應設備樹中的一個節(jié)點 struct property 對應節(jié)點中一個屬性
6.1 of_find_node_by_path
/** include/of.h of_find_node_by_path - 通過路徑查找指定節(jié)點 @path - 帶全路徑的節(jié)點名,也可以是節(jié)點的別名 成功:得到節(jié)點的首地址;失敗:NULL */ struct device_node * of_find_node_by_path(const char *path);
6.2 of_find_property
/* include/of.h of_find_property - 提取指定屬性的值 @np - 設備節(jié)點指針 @name - 屬性名稱 @lenp - 屬性值的字節(jié)數(shù) 成功:屬性值的首地址;失敗:NULL */ struct property *of_find_property(const struct device_node *np, const char *name, int *lenp);
6.3 of_get_named_gpio
/*** include/of_gpio.h* of_get_named_gpio - 從設備樹中提取gpio口* @np - 設備節(jié)點指針* @propname - 屬性名* @index - gpio口引腳標號?* 成功:得到GPIO口編號;失敗:負數(shù),絕對值是錯誤碼*/ int of_get_named_gpio(struct device_node *np, const char *propname, int index);
6.4 irq_of_parse_and_map
/*功能:獲得設備樹中的中斷號并進行映射參數(shù):node:設備節(jié)點index:序號返回值:成功:中斷號 失敗:錯誤碼 */ unsigned int irq_of_parse_and_map(struct device_node *node, int index);
6.5 讀屬性值
of_property_read_string
/* of_property_read_string - 提取字符串(屬性值) @np - 設備節(jié)點指針 @propname - 屬性名稱 @out_string - 輸出參數(shù),指向字符串(屬性值) 成功:0;失敗:負數(shù),絕對值是錯誤碼 */ int of_property_read_string(struct device_node *np, const char *propname, const char **out_string);
讀數(shù)值
int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value)int of_property_read_u16(const struct device_node *np,const char *propname,u16 *out_value)int of_property_read_u32(const struct device_node *np,const char *propname,u32 *out_value)
判斷屬性是否存在
int of_property_read_bool(const struct device_node *np,const char *propname)
讀數(shù)組
int of_property_read_u32_array(const struct device_node *np,const char *propname,u32 *out_value,size_t sz)
七、GPIO接口
7.1 向內(nèi)核申請GPIO
int gpio_request(unsigned gpio,const char *label)
功能:其實就是讓內(nèi)核檢查一下該GPIO引腳是否被其它設備占用,如果沒有占用則返回0并用label做一下標記,表示被本設備占用,否則返回負數(shù)
void gpio_free(unsigned gpio)
功能:去除本設備對該GPIO的占用標記,表示本設備向內(nèi)核歸還對該GPIO引腳的使用權(quán),此后其它設備可占用該GPIO引腳
7.2 設置GPIO方向
int gpio_direction_input(unsigned gpio)
int gpio_direction_output(unsigned gpio,int value)
7.3 讀寫GPIO數(shù)據(jù)
int gpio_get_value(unsigned gpio)
int gpio_set_value(unsigned gpio,int value)
八、led驅(qū)動設備樹版
-
在設備樹源文件的根節(jié)點下添加本設備的節(jié)點(該節(jié)點中包含本設備用到的資源信息)
..../linux3.14/arch/arm/boot/dts/exynos4412-fs4412.dts
fs4412-leds {compatible = "fs4412,led2-5";led2-gpio = <&gpx2 7 0>;led3-gpio = <&gpx1 0 0>;led4-gpio = <&gpf3 4 0>;led5-gpio = <&gpf3 5 0>; };
-
在linux內(nèi)核源碼的頂層目錄下執(zhí)行:make dtbs (生成對應的dtb文件)
-
cp ?????.dtb /tftpboot
-
編寫驅(qū)動代碼:
a. 通過本設備在設備樹中的路徑找到對應節(jié)點(struct device_node類型的地址值)
b. 調(diào)用 of_get_named_gpio 函數(shù)得到某個GPIO的編號
c. struct leddev結(jié)構(gòu)體中記錄所有用到的GPIO編號
d. 使用某個GPIO引腳前需先通過gpio_request函數(shù)向內(nèi)核申請占用該引腳,不用該引腳時可通過gpio_free歸還給內(nèi)核
e. 通過gpio_direction_input和gpio_direction_output函數(shù)來設置某個GPIO的作用
f. 通過gpio_get_value函數(shù)可以獲取某個GPIO引腳的當前電平
g. 通過gpio_set_value函數(shù)可以改變某個GPIO引腳的電平