天天看點

NCS-OS系列3 :devicetree介紹NCS-OS系列3 :devicetree介紹前言一、devicetree概念二、文法和結構三、Unit address示例四、重要屬性介紹五、Aliases and chosen nodes六、輸入輸出檔案

NCS-OS系列3 :devicetree介紹

文章目錄

  • NCS-OS系列3 :devicetree介紹
  • 前言
  • 一、devicetree概念
  • 二、文法和結構
  • 三、Unit address示例
    • 3.1 記憶體映射外設
    • 3.2 I2C外設
    • 3.3 SPI外設
    • 3.4 存儲器
    • 3.5 記憶體映射flash
    • 3.6 記憶體分區
  • 四、重要屬性介紹
    • 4.1 compatible
    • 4.2 label
    • 4.3 reg
    • 4.4 status
    • 4.5 interrupts
  • 五、Aliases and chosen nodes
  • 六、輸入輸出檔案
    • 6.1 輸入檔案
    • 6.2 腳本和工具
    • 6.3 輸出檔案
    • 6.4 寫屬性值

前言

ncs 相關文章,部分為原始文檔翻譯,水準有限,如果有錯誤,歡迎指出。

本文參考連結:

https://docs.zephyrproject.org/latest/guides/dts/intro.html

一、devicetree概念

devicetree

是描述硬體的階層化的資料結構。Devicetree specification定義了它的源代碼和二進制表示。Zephyr使用

devicetree

來描述其支援的單闆上可用的硬體,以及該硬體的初始配置。

有兩種類型的

devicetree

輸入檔案:

devicetree sources

devicetree bindings

devicetree sources

包含

devicetree

本身。

devicetree bindings

描述它的内容,包括資料類型。編譯系統使用

devicetree sources

devicetree bindings

來建立一個生成的C頭檔案。生成的頭檔案的内容被

devicetree.h

API分離出來,可以使用該API從

devicetree

中擷取資訊。

下面是一個簡單的示例圖:

NCS-OS系列3 :devicetree介紹NCS-OS系列3 :devicetree介紹前言一、devicetree概念二、文法和結構三、Unit address示例四、重要屬性介紹五、Aliases and chosen nodes六、輸入輸出檔案

所有Zephyr和應用程式的源代碼檔案都可以include并使用

devicetree.h

。這包括裝置驅動程式、應用程式、測試、核心等。

API本身是基于C宏定義的。宏名都以

DT_

開頭。通常,在Zephyr源檔案中看到一個以

DT_

開頭的宏,那麼它可能是一個

devicetree.h

宏。生成的C頭檔案也包含以

DT_

開頭的宏,這些可能會在編譯器的錯誤資訊中看到。生成的宏和非生成的宏可以通過這種方式來區分:生成的宏有一些小寫字母,而

devicetree.h

宏的名字都是大寫字母。

二、文法和結構

如名字所示,

devicetree

是一個樹型結構,這個樹的人類可讀的文本格式稱為DTS(用于

devicetree source

),并在Devicetree specification中定義。

下面是一個示例的DTS檔案:

/dts-v1/;
/ {
        a-node {
                subnode_label: a-sub-node {
                        foo = <3>;
                };
        };
};
           

/ dts-v1 /;

表示檔案的内容是使用DTS文法的版本1,它取代了現在已經過時的“版本0”。

這個樹有三個節點:

  • 1個根節點:

    /

  • 一個根節點的子節點,名字為:

    a-node

  • 一個

    a-node

    的子節點,名字為:

    a-sub-node

    節點可以

節點可以被賦予

labels

,标簽是用來在裝置樹的其他地方引用标簽節點的唯一的簡寫。上面的DTS檔案中,

a-sub-node

label

就是

subnode_label

。一個節點可以有0、1或多個節點

label

Devicetree節點具有辨別其在樹中的位置的路徑。與Unix檔案系統路徑一樣,Devicetree路徑是由斜杠(

/

)分隔的字元串,根節點的路徑是單個斜杠:

/

。每個節點的路徑将由節點祖先節點的名稱與節點自己的名稱(用斜杠分隔)連接配接而成。例如,到

a-sub-node

的全路徑為

“/a-node/a-sub-node”

節點

a-sub-node

有一個名為

foo

的屬性,它的值是一個值為

3

的單元。

foo

值的大小和類型由DTS中的尖括号(

<和>

)包含。有關更多屬性值的示例,請參閱下面的 Writing property values 部分。

在實際應用中,

devicetree

節點通常對應于某些硬體,節點的層次結構反映了硬體的實體布局。假設一塊闆,它有三個I2C外設連接配接到一個SoC上的I2C總線控制器上,如下所示:

NCS-OS系列3 :devicetree介紹NCS-OS系列3 :devicetree介紹前言一、devicetree概念二、文法和結構三、Unit address示例四、重要屬性介紹五、Aliases and chosen nodes六、輸入輸出檔案

對應的I2C總線控制器和每個I2C外圍裝置的節點将出現在

devicetree

中。反映硬體的布局,I2C外設節點将是總線控制器節點的子節點。類似的規則也适用于表示其他類型的硬體。

上面的DTS檔案将會如下所示:

/dts-v1/;
/ {
        soc {
                i2c-bus-controller {
                        i2c-peripheral-1 {
                        };
                        i2c-peripheral-2 {
                        };
                        i2c-peripheral-3 {
                        };
                };
        };
};
           

屬性在實際應用中用于描述或配置節點表示的硬體。例如,I2C外設節點具有一個屬性,其值是總線上的外設位址。

下面是一個和上面功能一樣的樹,但其中包含使用I2C裝置時可能看到的真實節點名稱和屬性:

NCS-OS系列3 :devicetree介紹NCS-OS系列3 :devicetree介紹前言一、devicetree概念二、文法和結構三、Unit address示例四、重要屬性介紹五、Aliases and chosen nodes六、輸入輸出檔案

上面的

devicetree

轉換成DTS檔案如下所示:

/dts-v1/;

/ {
        soc {
                i2c@40003000 {
                        compatible = "nordic,nrf-twim";
                        label = "I2C_0";
                        reg = <0x40003000 0x1000>;

                        apds9960@39 {
                                compatible = "avago,apds9960";
                                label = "APDS9960";
                                reg = <0x39>;
                        };
                        ti_hdc@43 {
                                compatible = "ti,hdc", "ti,hdc1010";
                                label = "HDC1010";
                                reg = <0x43>;
                        };
                        mma8652fc@1d {
                                compatible = "nxp,fxos8700", "nxp,mma8652fc";
                                label = "MMA8652FC";
                                reg = <0x1d>;
                        };
                };
        };
};
           

除了顯示更真實的名稱和屬性外,上面的示例還引入了一個新的

devicetree

概念:

unit addresses

unit addresses

是在“at”符号(

@

)之後的節點名的部分,如

[email protected]

中的

40003000

,或

[email protected]

中的

39

unit addresses

是可選的:soc節點沒有

unit addresses

三、Unit address示例

devicetree

中,

Unit address

給出了在其父節點的位址空間中的節點位址。下面是一些不同類型硬體的

Unit address

示例

3.1 記憶體映射外設

外設的寄存器映射基位址。例如,名稱為

[email protected]

的節點代表一個寄存器映射基地位址為

0x40003000

的I2C控制器。

3.2 I2C外設

I2C總線上的外設位址。例如,上一節中I2C控制器的子節點

[email protected]

的I2C位址是

0x39

3.3 SPI外設

代表外圍裝置的晶片

CS線

的索引。(如果沒有晶片

CS線

,則使用0。)

3.4 存儲器

實體起始位址。例如,一個名為

[email protected]

的節點表示從實體位址

0x2000000

開始的RAM。

3.5 記憶體映射flash

像RAM一樣,實體起始位址。例如,名稱為

[email protected]

的節點代表實體起始位址為

0x8000000

的flash裝置。

3.6 記憶體分區

這适用于

devicetree

用于存儲flash分區表的時候。

unit address

flash

中分區的開始偏移量。例如,以這個閃存裝置及其分區為例:

flash@8000000 {
    /* ... */
    partitions {
            partition@0 { /* ... */ };
            partition@20000 {  /* ... */ };
            /* ... */
    };
};
           

名為

[email protected]

的節點從其flash裝置的開始處偏移量為0,是以其基址為

0x8000000

。類似地,名為

[email protected]

的節點的基址是

0x8020000

四、重要屬性介紹

4.1 compatible

compatible

是節點所代表的硬體裝置的名稱,推薦的格式是

"vendor,device"

,如

“avago,apds9960”

,或這些的序列,如

“ti,hdc”

“ti,hdc1010”

。vendor部分是廠商名稱的縮寫。檔案

dts/bindings/vendor-prefixes.txt

中包含了一個通用的的供應商名稱清單。device部分通常取自裝置的datasheet。

當硬體的表現是通用的時,它也可以是像

gpio-keys

mmio-sram

fixed-clock

這樣的值。

編譯系統使用

compatible

屬性為節點找到正确的

bindings

。裝置驅動程式使用

devicetree.h

來查找具有相關

compatibles

的節點,以便确定要管理的可用硬體。

compatible

屬性可以有多個值。當裝置是一個通用系列的特定執行個體時,會使用附加值以允許系統從最特定的裝置驅動程式到最不特定的裝置驅動程式比對。

在Zephyr的綁定文法中,此屬性的類型為

string-array

4.2 label

label

是根據Zephyr的裝置驅動程式模型實作的裝置的名稱。這個值可以傳遞給

device_get_binding()

來檢索相應的驅動程式級結構

device*

。這個指針可以通過應用程式代碼傳遞給正确的裝置驅動程式API來與裝置互動。例如,調用

device_get_binding("I2C_0")

将傳回一個指向裝置結構的指針,該結構可以傳遞給

I2C API

函數,如

i2c_transfer()

。生成的C頭檔案同樣會包含一個可以描述這個字元串的宏。

4.3 reg

reg

是用于給裝置尋址的資訊。該值是給到特定裝置的(即根據

compatible

屬性不同而不同)。

reg

屬性是一個由

(address, length)

對組成的序列。每一對被稱為一個

“register block”

。下面是一些常見的模式:

  • 通過記憶體映射I/O寄存器通路的裝置(如

    [email protected]

    ):

    address

    通常是I/O寄存器空間的基址,而

    length

    是寄存器所占用的位元組數。
  • I2C裝置(如

    [email protected]

    及其系列):

    address

    是I2C總線上的從位址。沒有

    length

    值。
  • SPI裝置:

    address

    是晶片CS線,沒有

    length

    上面描述的

    reg

    屬性和

    unit addresses

    之間有一些相似之處,

    reg

    屬性可以被看作是裝置中比

    unit addresses

    更詳細的可尋址資源。

4.4 status

status

是描述節點是否啟用的字元串,devicetree規範允許該屬性的值可以為

“okay”

“disabled”

“reserved”

“fail”

“fail-sss”

。目前隻有

“okay”

“disabled”

值與Zephyr相關,使用其他值會導緻未定義的行為。

如果一個節點的

status

屬性是

“okay”

或者沒有定義(即在

devicetree source

中不存在),那麼它就被認為是

enabled

。狀态為

“disabled”

的節點被顯式禁用。(為了向後相容,值

“ok”

被視為與

“okay”

相同,但這種用法已棄用),在配置設定和初始化Zephyr驅動模型中的相應

struct device

時,必須啟用與實體裝置對應的Devicetree節點。

4.5 interrupts

interrupts

是由裝置産生的中斷的資訊,編碼為一個或多個中斷訓示符的數組。每個中斷訓示符都有一定數量的單元。更多細節請參見 Devicetree Specification release v0.3中section 2.4, Interrupts and Interrupt Mapping章節。

五、Aliases and chosen nodes

除了

node label

之外,還有另外兩種方法可以引用特定的節點,而無需指定其整個路徑: 通過

alias

chosen node

下面的devicetree使用了這兩個概念:

/dts-v1/;

/ {
     chosen {
             zephyr,console = &uart0;
     };
     aliases {
             my-uart = &uart0;
     };
     soc {
             uart0: serial@12340000 {
                     ...
             };
     };
};
           

/alias

/chosen

節點并不指向實際的硬體裝置,它們的目的是指定

devicetree

中的其他節點。

上面的dts檔案中,

my_uart

是路徑為

/soc/[email protected]

的裝置的alias,通過使用它的

node label

uart0

zephyr,console

這個

chosen node

被設定為同樣的值。

Zephyr示例應用程式有時使用别名以允許以通用方式來取代應用程式使用的特定硬體裝置。例如,Blinky例程使用這個來抽象LED通過

led0 alias

閃爍。

/chosen

節點屬性用于配置系統或子系統範圍的值。更多資訊,請參閱Chosen nodes。

六、輸入輸出檔案

本節更詳細地描述了本介紹開頭的圖中所示的輸入和輸出檔案。

NCS-OS系列3 :devicetree介紹NCS-OS系列3 :devicetree介紹前言一、devicetree概念二、文法和結構三、Unit address示例四、重要屬性介紹五、Aliases and chosen nodes六、輸入輸出檔案

6.1 輸入檔案

有四種類型的devicetree輸入檔案:

  • sources (.dts)
  • includes (.dtsi)
  • overlays (.overlay)
  • bindings (.yaml)

ncs目錄中的裝置樹檔案是這樣的:

ncs/zephyr/boards/<ARCH>/<BOARD>/<BOARD>.dts
ncs/zephyr/dts/common/skeleton.dtsi
ncs/zephyr/dts/<ARCH>/.../<SOC>.dtsi
ncs/zephyr/dts/bindings/.../binding.yaml
           

還有:

ncs/nrf/boards/<ARCH>/<BOARD>/<BOARD>.dts
ncs/nrf/dts/bindings/.../binding.yaml
           

一般來說,每一個支援的

BOARD

,都要有一個對應的

BOARD.dts

檔案來描述它的硬體結構,例如

reel_board

的dts檔案為

boards/arm/reel_board/reel_board.dts

BOARD.dts

包括一個或多個

.dtsi

檔案,這些

.dtsi

檔案或者通過

include

其他

.dtsi

檔案來描述運作Zephyr的CPU或片上系統。它們還可以描述由多個闆共享的其他常見硬體特征。除了這些,

BOARD.dts

也描述了闆子的具體硬體。

dts/common

目錄包含

skeleton.dtsi

skeleton.dtsi

是用于定義完整

devicetree

的最小包含檔案。特定體系結構的子目錄(

dts/<ARCH>

)包含了針對

CPUs

SoCs

的對

skeleton.dtsi

擴充的

.dtsi

檔案。

C預處理器在所有

devicetree

檔案上運作以展開宏引用,而

include

通常使用

#include <filename>

指令來完成,即使DTS有

/include/ "<filename>"

文法。

BOARD.dts

可以使用

overlays

檔案進行擴充或修改。Overlay也是DTS檔案,

overlay

擴充隻是一個是目的更明确的慣例。Overlays調整基礎的

devicetree

以适應不同的目的:

  • Zephyr應用程式可以使用

    overlay

    來啟用預設禁用的外圍裝置,為特定的應用程式選擇闆上的傳感器,等等。通過使用

    Kconfig

    ,可以重新配置核心和裝置驅動程式,而無需修改源代碼。
  • 在定義

    Shields

    時也使用

    Overlays

    編譯系統自動擷取存儲在特定位置的

    .overlay

    檔案。也可以通過

    DTC_OVERLAY_FILE

    這個CMake變量顯式列出要包含的

    overlays

    。詳情參見Set devicetree overlay。

編譯系統将

BOARD.dts

和其他

.overlay

檔案進行合并,

overlay

放在最後,這依賴于DTS允許合并

devicetree

中節點的重複定義的文法。見示例:FRDM-K64F and Hexiwear K64,這是一個在

.dtsi

檔案的環境中如何工作的示例,但原理與

overlays

相同,把

.overlay

檔案的内容放在最後允許它們覆寫

BOARD.dts

Devicetree bindings(

YAML檔案

)本質上是

glue

。它們以一種允許編譯系統生成裝置驅動程式和應用程式可用的C宏的方式來描述

devicetree sources

,

includes

, 和

overlays

的内容。

dts/bindings

目錄包含了相關的

bindings

資訊。

Zephyr目前使用

dts_fixup.h

檔案将

devicetree_unfixed.h

中的宏重命名為C代碼目前使用的名稱。預設情況下,建構系統在

zephyr/boards/

zephyr/soc/

目錄中查找修複檔案。修複檔案的存在是由于曆史原因,新代碼通常應該避免使用它們。

6.2 腳本和工具

下面的庫和腳本位于

scripts/dts/

中,它們使用輸入檔案來建立輸出檔案。

dtlib.py : 底層DTS解析庫

edtlib.py : 位于dtlib之上的庫,它使用

bindings

來解析屬性,并提供

devicetree

的更高層次視圖,使用dtlib進行DTS解析。

gen_defines.py :使用edtlib從

devicetree

bindings

生成C預處理器宏的腳本

另外,如果在您的系統上安裝了标準的dtc(

devicetree compiler

)工具,那麼它将在最終的

devicetree

上運作,這是為了捕獲錯誤或警告。輸出資訊沒有被使用。闆子可能需要傳遞dtc附加标志,例如

warning suppression

。單闆目錄中可以包含一個名為

pre_dt_board.cmake

的檔案,它配置了這些額外的标志,像這樣:

6.3 輸出檔案

下面這些是在應用程式編譯檔案夾中建立的

<build>/zephyr/include/generated/devicetree_unfixed.h

生成的宏和描述

devicetree

的附加注釋,通過

devicetree.h

進行

include

<build>/zephyr/include/generated/devicetree_fixups.h

dts_fix.h

檔案的内容,通過

devicetree.h

進行

include

<build>/zephyr/zephyr.dts

最終合并後的

devicetree

。這個檔案由

gen_definitions .py

輸出,作為調試目的使用,沒有其他用處。

<build>/zephyr/<BOARD>.dts.pre.tmp

預處理和連接配接的DTS

sources

overlays

。這是一個中間輸出檔案,用于建立

zephyr.dts

devicetree_unfixed.h

6.4 寫屬性值

下面是一些以DTS格式寫入屬性值的示例方法。為了盡量簡單,省略了一些細節;如果對細節感興趣,請參閱devicetree specification。

32位無符号整數數組或

cells

,可以寫在尖括号(

<和>

)之間,并用空格分隔:

foo屬性值有三個

cells

,值依次為

0xdeadbeef

1234

。注意,這裡允許使用十六進制數和十進制數,并且可以混合使用。由于Zephyr将DTS轉換為C源檔案,是以沒有必要在這裡指定單個cell的位元組順序。

64位整數按大端順序寫成兩個32位單元格。值

0xaaaa0000bbbb1111

寫為

<0xaaaa0000 0xbbbb1111>

允許使用圓括号、算術操作符和位操作符。下面

bar

屬性包含一個值為64的單元格:

字元串用雙引号括起來:

字元串數組用逗号分隔:

位元組數組以十六進制形式寫入,方括号(

[和]

)之間不包含前導0x。下面的屬性

a-byte-array

是三個位元組0x00, 0x01, 0xab:

屬性可以通過它們的

phandles

引用

devicetree

中的其他節點。可以使用

&label

寫一個

phandle

,就像在這個

devicetree

片段中:

baz: device@0 {
        /* ... */
};
device@1 {
        sibling = <&baz 1 2>;
        /* ... */
};
           

節點

[email protected]

sibling

屬性包含三個單元格:

  • [email protected]

    節點的

    phandle

    。每個

    phandle

    占據1個cell。

    baz

    标簽用于在

    sibling

    屬性中寫入phandle值

    &baz

  • 值1和2,每個都按照這個順序在自己的單元格中。