成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

實戰(zhàn)演練:設備樹(DTS)語法詳解 + LED控制實戰(zhàn)

開發(fā) 前端
在嵌入式系統的廣袤天地中,設備樹(Device Tree)宛如一座橋梁,橫跨在硬件與軟件之間,承擔著至關重要的溝通使命。

在嵌入式開發(fā)領域,設備樹(Device Tree)扮演著極為關鍵的角色。它如同一份精準的硬件說明書,讓操作系統能夠清晰識別并高效管理硬件資源。當我們著手為自定義硬件編寫設備樹時,就如同為新成員量身定制一套專屬 “檔案”,確保其能無縫融入系統 “大家庭”。

想象一下,你精心設計了一款獨特的硬件,滿心期待它在系統中發(fā)揮作用。但如果沒有正確編寫設備樹,操作系統很可能對其 “視而不見”,讓你的心血難以充分施展。那么,如何才能為自定義硬件編寫正確的設備樹呢?

接下來,我們將通過一系列實戰(zhàn)演練,帶你逐步攻克這一技術要點,從了解硬件配置的基礎信息,到精準修改設備樹源文件,再到生成可被系統讀取的二進制文件等,每一步都為你詳細拆解,助你在自定義硬件開發(fā)之路上穩(wěn)步前行 。

一、設備樹初印象:為何而生?

在嵌入式系統的廣袤天地中,設備樹(Device Tree)宛如一座橋梁,橫跨在硬件與軟件之間,承擔著至關重要的溝通使命。在設備樹出現之前,嵌入式系統的開發(fā)可沒少讓開發(fā)者們頭疼。就拿 ARM 架構來說,不同開發(fā)板的硬件信息就像一團亂麻,緊緊地與內核代碼交織在一起。想象一下,每更換一次開發(fā)板,那密密麻麻的內核代碼就得大改特改,移植工作不僅繁瑣,還極易出錯,維護成本更是高得嚇人。

為了化解這些難題,設備樹應運而生。它最早在 PowerPC 架構中嶄露頭角,隨后便在 ARM、MIPS 等多種架構中廣泛應用,迅速成為嵌入式開發(fā)的得力助手。設備樹的核心使命,就是將硬件描述從內核代碼中剝離出來,實現兩者的解耦。如此一來,內核變得更加通用,開發(fā)板相關的特定信息則由設備樹文件專門負責描述。當我們要將內核移植到新的開發(fā)板時,只需對設備樹文件進行修改,這極大地降低了移植的難度和工作量,就像是給復雜的開發(fā)工作找到了一條捷徑。

舉個例子,在一個基于 ARM 架構的智能家居控制系統開發(fā)中,以往若要適配不同廠家生產的開發(fā)板,每個開發(fā)板都有獨特的硬件配置,如不同的 GPIO 引腳分配、外設接口等。在沒有設備樹時,針對每一款開發(fā)板,內核代碼中都要硬編碼大量的硬件相關信息,這導致內核代碼臃腫不堪,且維護極為困難。一旦硬件稍有變動,例如更換了一個不同型號的傳感器,與之相連的引腳發(fā)生變化,就需要在冗長的內核代碼中四處尋找并修改相關配置,不僅容易遺漏,而且修改過程繁瑣,極易引入新的錯誤。

有了設備樹后,情況就大為不同。硬件相關信息被清晰地描述在設備樹文件中。若要適配新的開發(fā)板,或者更改硬件配置,只需在設備樹文件中相應節(jié)點處修改屬性值即可。比如,要更改傳感器連接的 GPIO 引腳,只需在設備樹中找到對應的傳感器節(jié)點,修改其 GPIO 屬性值,而無需對內核代碼進行大規(guī)模改動。這使得開發(fā)過程更加靈活高效,同時也提高了代碼的可維護性和可移植性 。

1.1設備樹在ARM架構的引入

在之前使用 S3C2440 開發(fā)板移植 Linux 3.4.2 內核時,修改了很多關于 c 文件去適配開發(fā)板,和開發(fā)板相關的文件放在arch/arm/mxch-xxx目錄下,因此 linux 內核 arm 架構下添加了很多開發(fā)板的適配文件:

圖片圖片

這些 c 文件僅僅用來適配某款開發(fā)板,對于 Linux 內核來說并沒有提交什么新功能,但是每適配一款新的開發(fā)板就需要一堆文件,導致 Linux 內核越來越臃腫:

圖片圖片

終于 Linus 忍不住天天 merge 這些鬼東西,向 arm 社區(qū)發(fā)出了一封郵件,第一句話就足矣表現不滿:"This whole ARM thing is a f*cking pain in the ass"。

因此,Arm 社區(qū)開始引入之前 powerPC 架構就采用的設備樹,將描述這些板級信息的文件與 Linux 內核代碼分離,Linux 4.x 版本幾乎都支持設備樹,所有開發(fā)板的設備樹文件統一放在arch/arm/boot/dts目錄中。

1.2什么是設備樹

設備樹全稱 Device Tree,是一種數據結構,用來描述板級設備信息,比如 CPU 數量、外設基地址、總線設備等,如圖:

圖片圖片

DTS、DTB、DTC三種文件的區(qū)別

  • DTS 是設備樹源碼文件
  • DTB 是將DTS 編譯以后得到的二進制文件
  • DTC工具是將dts文件變成編譯成dtb的工具,就像.c文件變成成.o需要用到gcc編譯器一樣。

1.3 設備樹編譯

①簡單粗暴,編譯內核

make

②編譯全部設備樹文件

make dtbs

③編譯指定的設備樹文件

make <xxx.dtb>

二、設備樹語法

2.1設備樹相關術語全解析

在深入探索設備樹的世界之前,先來認識一下那些頻繁出現的術語,它們就像是開啟設備樹大門的鑰匙。

DT(Device Tree,設備樹):這是一種用于描述計算機系統硬件布局的數據結構,它將系統中的各類硬件組件及其連接關系,以層次化的樹狀結構呈現出來。可以把它想象成是硬件的 “戶口簿”,詳細記錄著每個硬件設備的 “身份信息” 以及它們之間的 “親屬關系” ,為內核提供了清晰的硬件信息,讓內核能夠有條不紊地初始化和操作硬件設備。

FDT(Flattened Device Tree,扁平設備樹):FDT 是設備樹的二進制表示形式,就像是設備樹的 “壓縮包”。它由設備樹編譯器(dtc)精心打造而成,是 dts 文件編譯后的產物。這種緊湊的存儲方式,使其在系統啟動時能夠快速加載和解析,大大提高了系統啟動的效率 ,就好比將一本厚厚的書壓縮成了一個小巧的文件,攜帶和讀取都更加便捷。

dts(Device Tree Source,設備樹源文件):dts 文件是設備樹的源文件,以通俗易懂的文本格式編寫,是硬件開發(fā)人員或系統集成商施展拳腳的舞臺。他們通過編寫 dts 文件,詳細描述系統中的硬件設備及其屬性,就像建筑師繪制建筑藍圖一樣,為后續(xù)的硬件實現和系統開發(fā)奠定基礎。這個文件就像是設備樹的 “初稿”,記錄著最原始的硬件描述信息。

dtsi(Device Tree Source Include,設備樹源包含文件):dtsi 文件類似于編程中的頭文件,是設備樹源文件的得力助手。它通常包含一些被多個 dts 文件共享的硬件描述,通過 #include 指令巧妙地融入到具體的 dts 文件中。這樣一來,不僅避免了重復代碼,還讓硬件描述的管理和維護變得更加輕松,就像是一個公共的資源庫,各個 dts 文件都可以按需取用其中的內容 。

dtb(Device Tree Blob,設備樹二進制文件):dtb 文件是 dts 文件經過編譯后生成的二進制文件,包含了設備樹的扁平表示形式(FDT)。在系統啟動的關鍵時刻,引導加載程序(如 U-Boot)會將 dtb 文件從存儲設備中加載到內存,并恭敬地傳遞給操作系統內核。內核則依據 dtb 文件中描述的信息,對硬件進行初始化操作,它就像是一份被加密后的硬件說明書,只有內核能夠讀懂并依據它來配置硬件 。

dtc(Device Tree Compiler,設備樹編譯器):dtc 是設備樹世界中的 “翻譯官”,它肩負著將 dts 文件編譯為 dtb 文件的重任。不僅如此,在調試和修改設備樹時,它還能將 dtb 文件反編譯為 dts 文件,為開發(fā)者提供了極大的便利。就好比一個語言專家,能夠在不同格式的設備樹文件之間自由轉換 。

這些術語相互協作,共同構建起設備樹的生態(tài)系統。dts 和 dtsi 文件是設備樹的源代碼基礎,dtc 編譯器將它們轉換為內核能夠識別的 dtb 文件,而 FDT 則是 dtb 文件內部的一種高效存儲結構,DT 則是整個硬件描述概念的統稱 。

2.2設備樹源碼藏身何處

在 Linux 內核源碼的龐大體系中,設備樹源碼有著自己專屬的 “棲息地”。對于 32 位系統而言,設備樹源碼通常存放在 “源碼 /arch/arm/boot/dts” 目錄下;而在 64 位系統中,它們則位于 “源碼 /arch/arm64/boot/dts” 目錄 。

在這些目錄中,你能找到眾多以.dts 和.dtsi 為擴展名的文件,它們就像是隱藏在代碼海洋中的寶藏,記錄著硬件設備的詳細信息 。不同架構的設備樹文件存放位置和命名規(guī)則可能會略有差異,所以在探索時,一定要查閱對應架構的文檔或源碼,這樣才能準確找到所需的設備樹文件 。

2.3DTC 工具的神奇用法

DTC 工具作為設備樹編譯和反編譯的利器,掌握它的使用方法至關重要。下面就來看看如何使用 DTC 工具進行設備樹的編譯和反編譯操作 。

(1)編譯設備樹

基本的編譯命令格式為 “dtc -I dts -O dtb -o output_file.dtb input_file.dts”。其中,“dtc” 是調用設備樹編譯器;“-I dts” 明確指定輸入文件的格式為設備樹源文件(DTS),就像是告訴編譯器要處理的是哪種類型的 “原材料”;“-O dtb” 指定輸出文件的格式為設備樹二進制文件(DTB),也就是確定了 “成品” 的格式;“-o output_file.dtb” 則指定了輸出文件的名稱,讓編譯器知道要把生成的文件保存成什么名字;“input_file.dts” 自然就是指定輸入的設備樹源文件了 。

例如,我們有一個名為 “my_device.dts” 的設備樹源文件,想要將其編譯成二進制文件 “my_device.dtb”,就可以在命令行中輸入 “dtc -I dts -O dtb -o my_device.dtb my_device.dts”,按下回車鍵,DTC 工具就會迅速行動,將 dts 文件編譯成 dtb 文件 。

(2)反編譯設備樹

反編譯的命令格式為 “dtc -I dtb -O dts -o example.dts example.dtb”。這里的參數含義與編譯時類似,只是輸入和輸出的格式進行了互換。“-I dtb” 表示輸入文件是設備樹二進制文件(DTB),“-O dts” 表示輸出文件為設備樹源文件(DTS) 。

假設我們有一個 “example.dtb” 的二進制文件,想要查看其原始的設備樹描述內容,就可以使用 “dtc -I dtb -O dts -o example.dts example.dtb” 命令,將 dtb 文件反編譯成 dts 文件,方便我們進行查看和修改 。

在實際操作過程中,還可能會用到其他一些參數。比如,“-q” 參數可以讓編譯過程更加安靜,減少不必要的提示信息;“-i” 參數可以添加搜索包含文件的路徑,方便在編譯時找到所需的 dtsi 文件等 。掌握這些參數的用法,能夠讓我們更加靈活地使用 DTC 工具,應對各種設備樹處理的需求 。

三、深入設備樹語法殿堂

3.1節(jié)點:設備樹的基石

節(jié)點是設備樹的基本組成單元,就像是樹狀結構中的一個個 “樹枝分叉點” ,每個節(jié)點都代表著一個硬件設備或組件。節(jié)點的命名遵循特定規(guī)則,通常以 “node-name@unit-address” 的形式出現 。其中,“node-name” 是節(jié)點的名稱,一般由字母、數字和下劃線組成,用來描述節(jié)點所代表的設備類型或功能,如 “uart” 代表串口設備,“i2c” 代表 I2C 總線設備等 。

“unit-address” 則是設備的單元地址,通常表示設備在內存空間或總線上的地址,像 “0x10000000” 這樣的十六進制數,它與設備的 “reg” 屬性密切相關 。若節(jié)點沒有地址相關信息,“@unit-address” 部分可以省略 。

每個節(jié)點內部可以包含多個屬性和子節(jié)點。屬性以鍵值對的形式存在,用于描述節(jié)點的各種特性;子節(jié)點則進一步細化硬件設備的層次結構 。例如,在描述一個 SPI 控制器時,可能會有如下節(jié)點:

spi@12340000 {
    compatible = "fsl,imx6ul-spi";
    reg = <0x12340000 0x1000>;
    interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
    #address-cells = <1>;
    #size-cells = <0>;

    spi_device: spi@0 {
        compatible = "my_spi_device";
        reg = <0>;
        spi-max-frequency = <5000000>;
    };
};

在這個例子中,“spi@12340000” 是 SPI 控制器節(jié)點,包含了描述其兼容性、地址、中斷等屬性 。而 “spi_device: spi@0” 則是 SPI 控制器下的一個子節(jié)點,表示連接在該 SPI 總線上的一個設備,有自己的兼容性、設備地址和最大工作頻率等屬性 。

3.2屬性:描述設備的關鍵

屬性是節(jié)點的重要組成部分,以 “name = value” 的形式存在,用于詳細描述節(jié)點所代表設備的各種特性 。屬性的值可以是多種數據類型,常見的有以下幾種:

  1. 32 位無符號整數:用尖括號 “<>” 括起來,如 “interrupts = <17 0xc>”,表示該設備的中斷號為 17,觸發(fā)方式為 0xc(具體含義根據中斷控制器的定義) 。
  2. 字符串:用雙引號 “""” 括起來,如 “compatible ="arm,cortex-a7"”,“compatible” 屬性用于驅動與設備的匹配,這里表示該設備與 “arm,cortex-a7” 類型兼容 。
  3. 字節(jié)數組:用方括號 “[]” 括起來,每個字節(jié)用兩個十六進制數表示,如 “l(fā)ocal-mac-address = [00 00 12 34 56 78]”,用于表示設備的本地 MAC 地址 。
  4. 復合類型:可以是多種值的組合,用逗號 “,” 隔開,如 “example = <0xf00f0000 19>, "a strange property format"” 。

在眾多屬性中,“compatible” 和 “reg” 屬性尤為常用 。“compatible” 屬性就像是設備的 “身份證”,用于設備與驅動程序的匹配 。內核在尋找設備驅動時,會根據設備節(jié)點的 “compatible” 屬性值,在驅動列表中查找與之匹配的驅動 。例如,“compatible = "fsl,imx6ul-spi", "spi-gpio"”,表示該設備首先嘗試匹配 “fsl,imx6ul-spi” 驅動,若找不到,則嘗試匹配 “spi-gpio” 驅動 。

“reg” 屬性用于描述設備的寄存器地址范圍,其值是一系列的 “address size” 對 。“address” 表示設備寄存器的起始地址,“size” 表示地址范圍的大小 。這兩個值的表示方式由其父節(jié)點的 “#address-cells” 和 “#size-cells” 屬性決定 。比如,在下面的例子中:

soc {
    #address-cells = <1>;
    #size-cells = <1>;

    spi@12340000 {
        reg = <0x12340000 0x1000>;
        ...
    };
};

由于 “soc” 節(jié)點的 “#address-cells = <1>” 和 “#size-cells = <1>”,所以 “spi@12340000” 節(jié)點的 “reg” 屬性中,“0x12340000” 用 1 個 32 位整數表示起始地址,“0x1000” 用 1 個 32 位整數表示地址范圍大小 。

3.3包含文件:代碼復用的利器

在設備樹開發(fā)中,為了提高代碼的復用性和可維護性,常常會使用包含文件(dtsi) 。dtsi 文件類似于 C 語言中的頭文件,用于存放被多個 dts 文件共享的設備樹描述 。通過使用包含文件,可以避免在多個 dts 文件中重復編寫相同的硬件描述代碼 。

在 dts 文件中,可以使用 “#include” 指令來引用 dtsi 文件 。例如:

#include "common.dtsi"

這樣,“common.dtsi” 文件中的內容就會被包含到當前 dts 文件中 。除了 dtsi 文件,設備樹源文件也可以包含標準的 C 頭文件(.h) 。這在需要使用一些宏定義或常量時非常方便 。例如,在 dts 文件中可能會包含如下頭文件:

#include <dt-bindings/gpio/gpio.h>

通過包含這個頭文件,可以在設備樹中使用其中定義的 GPIO 相關宏,如 “GPIO_ACTIVE_HIGH”“GPIO_ACTIVE_LOW” 等 。這樣不僅提高了代碼的可讀性,還減少了人為錯誤 。

3.4節(jié)點路徑:精準定位節(jié)點

在設備樹這個龐大的 “家族樹” 中,每個節(jié)點都有其唯一的路徑,就像每個人在家族族譜中都有獨特的位置標識一樣 。節(jié)點路徑是從根節(jié)點開始,通過各級子節(jié)點的名稱和地址,以 “/” 分隔組成的 。例如,對于前面提到的 SPI 控制器節(jié)點,其路徑為 “/soc/spi@12340000” 。

通過節(jié)點路徑,我們可以在設備樹中精準地訪問特定節(jié)點 。在 Linux 內核中,提供了一系列函數來通過節(jié)點路徑查找節(jié)點 。例如,“of_find_node_by_path (const char *path)” 函數,它接收一個節(jié)點路徑作為參數,返回對應節(jié)點的指針 。假設我們要獲取 SPI 控制器節(jié)點的信息,就可以使用如下代碼:

#include <linux/of.h>
#include <linux/device.h>

struct device_node *spi_node;
spi_node = of_find_node_by_path("/soc/spi@12340000");
if (spi_node) {
    // 在這里可以對找到的節(jié)點進行操作,如獲取屬性等
    of_node_put(spi_node);
}

在實際應用中,節(jié)點路徑常用于設備驅動開發(fā) 。驅動程序需要根據設備樹中節(jié)點的信息來初始化和操作硬件設備,通過節(jié)點路徑可以快速準確地找到對應的設備節(jié)點,從而獲取設備的屬性和配置信息 。

3.5別名:便捷訪問節(jié)點

別名就像是設備樹節(jié)點的 “昵稱”,為了更方便地訪問設備樹中的節(jié)點而存在 。通過定義別名,可以使用一個簡短的名稱來代替冗長的節(jié)點路徑 。別名的定義通常在設備樹的根節(jié)點下,使用 “aliases” 屬性 。例如:

aliases {
    spi0 = &spi@12340000;
    uart1 = &uart@101f0000;
};

在這個例子中,為 “spi@12340000” 節(jié)點定義了別名 “spi0”,為 “uart@101f0000” 節(jié)點定義了別名 “uart1” 。這樣,在設備樹的其他部分,或者在驅動程序中,就可以使用這些別名來代替完整的節(jié)點路徑 。例如,在驅動程序中,可以使用 “of_find_node_by_phandle (of_parse_phandle (aliases, "spi0", 0))” 來通過別名 “spi0” 找到對應的 SPI 控制器節(jié)點 。

別名的使用不僅提高了設備樹的可讀性,還使代碼更加簡潔和易于維護 。特別是在大型設備樹中,當需要頻繁訪問某些節(jié)點時,使用別名可以大大減少代碼中冗長路徑的出現,降低出錯的概率 。

3.6復合節(jié)點與定義引用:復雜關系的處理

在描述復雜的硬件設備關系時,復合節(jié)點和定義引用發(fā)揮著重要作用 。復合節(jié)點是指一個節(jié)點可以包含多個子節(jié)點,這些子節(jié)點共同描述一個復雜的硬件設備或功能 。例如,在描述一個包含多個功能模塊的芯片時,可能會有如下復合節(jié)點:

chip@10000000 {
    compatible = "my_chip";
    reg = <0x10000000 0x10000>;

    module1: submodule@1000 {
        compatible = "module1_type";
        reg = <0x1000 0x100>;
    };

    module2: submodule@2000 {
        compatible = "module2_type";
        reg = <0x2000 0x200>;
    };
};

在這個例子中,“chip@10000000” 是一個復合節(jié)點,包含了 “module1” 和 “module2” 兩個子節(jié)點,分別描述芯片中的兩個不同功能模塊 。

定義引用則是通過 “&label” 的方式來引用其他節(jié)點 。例如,在前面的例子中,如果有另一個節(jié)點需要使用 “module1” 節(jié)點的信息,可以這樣引用:

other_node {
    depends_on = <&module1>;
    // 其他屬性和子節(jié)點
};

這里的 “depends_on = <&module1>” 表示 “other_node” 節(jié)點依賴于 “module1” 節(jié)點 。通過這種方式,可以清晰地表達硬件設備之間的依賴關系 。

在實際應用中,復合節(jié)點和定義引用常用于描述復雜的硬件系統,如片上系統(SoC) 。SoC 通常包含多個處理器核心、各種外設控制器等,通過復合節(jié)點和定義引用,可以準確地描述這些組件之間的層次結構和相互關系,為內核提供完整的硬件信息 。

四、實戰(zhàn):設備樹實例深度剖析

4.1GPIO設備樹實例詳解

以某款基于 ARM 架構的開發(fā)板為例,其設備樹中 GPIO 設備樹節(jié)點如下:

gpio0: gpio@10000000 {
    compatible = "fsl,imx6ul-gpio", "gpio-generic";
    reg = <0x10000000 0x1000>;
    interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
    gpio-controller;
    #gpio-cells = <2>;
};

在這個節(jié)點中,“compatible” 屬性表明該 GPIO 控制器與 “fsl,imx6ul-gpio” 和 “gpio-generic” 兼容,這使得內核能夠準確找到與之匹配的驅動程序 。“reg” 屬性指定了 GPIO 控制器的寄存器地址范圍,起始地址為 0x10000000,大小為 0x1000 字節(jié) 。“interrupts” 屬性描述了 GPIO 控制器的中斷信息,使用 GIC_SPI 類型的中斷,中斷號為 66,觸發(fā)方式為高電平觸發(fā) 。

“gpio-controller” 屬性標識該節(jié)點為 GPIO 控制器 。“#gpio-cells = <2>” 則表示在引用該 GPIO 控制器時,需要兩個 32 位的參數 。第一個參數表示 GPIO 的編號,第二個參數表示 GPIO 的觸發(fā)類型 。例如,在其他節(jié)點中引用該 GPIO 控制器的某個引腳時,可能會這樣寫:

my_device {
    gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>;
    ...
};

這里表示使用 “gpio0” 控制器的第 10 號引腳,觸發(fā)類型為高電平有效 。這種屬性設置方式,為系統中其他設備使用 GPIO 提供了清晰的規(guī)范和接口 。

4.2LED設備樹實例全解析

假設我們要在開發(fā)板上實現一個 LED 驅動,首先在設備樹中定義 LED 節(jié)點:

leds {
    compatible = "gpio-leds";
    pinctrl-names = "default";
    pinctrl-0 = <&led_pins>;

    led_red: red_led {
        label = "red_led";
        gpios = <&gpio1 18 GPIO_ACTIVE_LOW>;
        default-state = "off";
    };
};

pinctrl: pinctrl@10000400 {
    compatible = "fsl,imx6ul-pinctrl";
    reg = <0x10000400 0x1000>;

    led_pins: ledgrp {
        fsl,pins = <
            MX6UL_PAD_GPIO1_IO18__GPIO1_IO18 0x10b0
        >;
    };
};

在這個設備樹實例中,“l(fā)eds” 節(jié)點的 “compatible = "gpio-leds"” 屬性表明這是一個基于 GPIO 的 LED 設備 。“pinctrl-names” 和 “pinctrl-0” 屬性用于引腳控制,通過引用 “l(fā)ed_pins” 節(jié)點來配置 LED 所使用的引腳 。

“l(fā)ed_red” 子節(jié)點定義了一個紅色 LED,“l(fā)abel” 屬性為其命名,“gpios” 屬性指定該 LED 連接到 “gpio1” 控制器的 18 號引腳,且為低電平有效 。“default-state = "off"” 表示 LED 默認處于熄滅狀態(tài) 。

在驅動開發(fā)中,內核驅動會根據 “compatible” 屬性找到對應的 LED 驅動程序 。在驅動的 probe 函數中,通過設備樹 API 函數來獲取設備樹節(jié)點信息 。例如,使用 “of_find_node_by_path” 函數找到 “l(fā)eds” 節(jié)點,再通過 “of_get_child_by_name” 函數獲取 “l(fā)ed_red” 子節(jié)點 。

然后,利用 “of_property_read_u32_array” 函數讀取 “gpios” 屬性的值,從而獲取 LED 所連接的 GPIO 引腳信息 。最后,根據這些信息進行 GPIO 的初始化和 LED 的控制操作 。

4.3自定義設備樹節(jié)點與驅動匹配實例

假設我們要添加一個自定義的溫度傳感器設備,首先在設備樹中創(chuàng)建自定義節(jié)點:

temperature_sensor: sensor@1234 {
    compatible = "mycompany,temperature-sensor";
    reg = <0x1234 0x100>;
    sensor_type = "temperature";
    sampling_rate = <100>;
};

這個自定義節(jié)點 “temperature_sensor” 的 “compatible” 屬性設置為 “mycompany,temperature-sensor”,用于與驅動程序進行匹配 。“reg” 屬性指定了傳感器的寄存器地址范圍 。“sensor_type” 和 “sampling_rate” 是自定義屬性,分別表示傳感器類型和采樣率 。

接下來編寫對應的內核驅動:

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>

static int my_sensor_probe(struct platform_device *pdev) {
    struct device_node *np = pdev->dev.of_node;
    u32 reg_val, sampling_rate;
    const char *sensor_type;

    if (!np)
        return -EINVAL;

    // 讀取reg屬性
    if (of_property_read_u32(np, "reg", ?_val) != 0) {
        dev_err(&pdev->dev, "Failed to read reg property\n");
        return -EINVAL;
    }

    // 讀取sensor_type屬性
    if (of_property_read_string(np, "sensor_type", &sensor_type) != 0) {
        dev_err(&pdev->dev, "Failed to read sensor_type property\n");
        return -EINVAL;
    }

    // 讀取sampling_rate屬性
    if (of_property_read_u32(np, "sampling_rate", &sampling_rate) != 0) {
        dev_err(&pdev->dev, "Failed to read sampling_rate property\n");
        return -EINVAL;
    }

    // 這里可以根據讀取到的屬性進行傳感器的初始化和操作
    dev_info(&pdev->dev, "Sensor initialized: reg = 0x%x, type = %s, sampling_rate = %d\n", reg_val, sensor_type, sampling_rate);

    return 0;
}

static int my_sensor_remove(struct platform_device *pdev) {
    // 清理操作
    return 0;
}

static const struct of_device_id my_sensor_of_match[] = {
    {.compatible = "mycompany,temperature-sensor"},
    {},
};
MODULE_DEVICE_TABLE(of, my_sensor_of_match);

static struct platform_driver my_sensor_driver = {
   .probe = my_sensor_probe,
   .remove = my_sensor_remove,
   .driver = {
       .name = "mycompany-temperature-sensor-driver",
       .of_match_table = my_sensor_of_match,
    },
};

module_platform_driver(my_sensor_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Custom Temperature Sensor Driver");

在這個驅動程序中,“my_sensor_of_match” 數組用于匹配設備樹中自定義節(jié)點的 “compatible” 屬性 。“my_sensor_probe” 函數在設備探測時被調用,通過設備樹 API 函數讀取設備樹節(jié)點的屬性信息,并進行相應的初始化操作 。這樣,通過 “compatible” 屬性,設備樹中的自定義節(jié)點與內核驅動成功匹配,驅動能夠正確解析設備樹屬性并對設備進行控制 。

責任編輯:武曉燕 來源: 深度Linux
相關推薦

2022-12-21 14:39:35

機器學習案發(fā)決策樹

2024-08-09 10:15:34

2009-09-18 14:31:33

CLR觸發(fā)器

2022-08-25 09:00:00

Python編程語言開源庫

2024-10-29 11:54:25

2012-11-09 09:35:18

Win 8

2024-08-05 09:31:00

MySQLDTS數據

2025-06-26 04:00:00

Spring數據綁定技術

2010-05-26 18:16:31

MySQL數據庫安裝

2024-11-22 09:21:18

WinForm

2024-07-17 08:17:20

2024-08-07 08:32:30

2023-02-10 14:54:20

編譯工具cmake

2017-04-26 08:51:36

MongoDB集群實戰(zhàn)

2023-11-07 10:22:26

自動駕駛技術

2024-07-15 09:13:48

2010-01-21 11:51:11

2017-11-23 15:24:35

Python速覽實戰(zhàn)

2025-05-28 08:45:00

2021-09-05 06:06:52

網絡安全實戰(zhàn)攻防演練網絡攻擊
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级免费毛片 | 成人深夜福利在线观看 | 精品国产乱码久久久久久果冻传媒 | 99免费在线观看视频 | 五月槐花香 | 日本午夜免费福利视频 | 亚洲一区二区三区四区五区午夜 | 国产精品久久久久久久粉嫩 | 欧美一区二区久久 | 国产99久久久国产精品下药 | 九色91视频 | 激情视频中文字幕 | av免费网站在线观看 | 亚洲精品一级 | www.一级片 | 理论片免费在线观看 | 国产xxx在线观看 | 亚洲欧洲一区二区 | 欧美片网站免费 | 99精品电影 | 日韩精品在线一区 | av色在线| 精品国产一级片 | 91传媒在线观看 | 国产日产欧产精品精品推荐蛮挑 | 999精品在线 | 免费成人高清在线视频 | 成人二区 | 亚洲精品乱码久久久久久按摩观 | 精品久久久久久 | 欧美亚洲综合久久 | 国产一区二区三区四区三区四 | 国产伦精品一区二区三区四区视频 | 精品一区二区三区四区在线 | 国产婷婷在线视频 | 91成人精品| 精品一区二区三区中文字幕 | 宅男噜噜噜66一区二区 | 亚洲精品久久久蜜桃 | 日日网| 日韩成人在线播放 |