RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【i.MX6ULL】驅(qū)動開發(fā)5——設(shè)備樹原理與點亮LED

碼農(nóng)愛學習 ? 來源:碼農(nóng)愛學習 ? 作者:碼農(nóng)愛學習 ? 2022-05-21 21:41 ? 次閱讀

上篇文章(【i.MX6ULL】驅(qū)動開發(fā)4--點亮LED(寄存器版))介紹了在驅(qū)動程序中,直接操作寄存器了點亮LED。本篇,介紹另外一種點亮LED的方式——設(shè)備樹,該方式的本質(zhì)也是操作寄存器,只是寄存器的相關(guān)信息放在了設(shè)備樹中,配置寄存器時需要使用OF函數(shù)從設(shè)備樹中讀取處寄存器數(shù)據(jù)后再進行配置。

1 什么是設(shè)備樹

1.1 背景介紹

Linux3.x之前是沒有設(shè)備樹的,設(shè)備樹是用來描述一個硬件平臺的板級細節(jié)。對應(yīng)ARM-Linux開發(fā),這些板級描述文件存放在linux內(nèi)核的 /arch/arm/plat-xxx和/arch/arm/mach-xxx 中。隨著ARM硬件設(shè)備的種類增多,與板子相關(guān)的設(shè)備文件也越來越多,這就導致Linux內(nèi)核越來越大,而實際這些ARM硬件相關(guān)的板級信息與Linux內(nèi)核并無相關(guān)關(guān)系。

2011年,Linux之父Linus Torvalds發(fā)現(xiàn)這個問題后,就通過郵件向ARM-Linux開發(fā)社區(qū)發(fā)了一封郵件,不禁的發(fā)出了一句“This whole ARM thing is a f*cking pain in the ass”。之后,ARM社區(qū)就引入了PowerPC等架構(gòu)已經(jīng)采用的設(shè)備樹(Flattened Device Tree)機制,將板級信息內(nèi)容都從Linux內(nèi)核中分離開來,用一個專屬的文件格式來描述,即現(xiàn)在的.dts文件。

poYBAGKI6LGAS9MzAAH1OTNPFEE751.png

1.2 設(shè)備樹介紹

設(shè)備樹的作用就是描述硬件平臺的硬件資源。它可以被bootloader傳遞到內(nèi)核,內(nèi)核可以從設(shè)備樹中獲取硬件信息。

設(shè)備樹描述硬件資源時有兩個特點:

以樹狀結(jié)構(gòu)描述硬件資源。以系統(tǒng)總線為樹的主干,掛載到系統(tǒng)地總線的IIC控制器、SPI控制器等為樹的枝干,IIC控制器下的IIC設(shè)備資源,又可以再分IIC1和IIC2,而IIC1上又可以連接MPU6050這類的IIC器件...

可以像頭文件那樣,一個設(shè)備樹文件引用另外一個設(shè)備樹文件,實現(xiàn)代碼重用。例如多個硬件平臺都使用i.MX6ULL作為主控芯片,可以將 i.MX6ULL 芯片的硬件資源寫到一個單獨的設(shè)備樹文件中(.dtsi文件)。

pYYBAGKI6LmAT0VEAADvtS9Yakk301.png

1.3 DTS、DTSI、DTB、DTC

poYBAGKI6MCABo6SAABN6VFYebY423.png

DTS ,Device Tree Source,是設(shè)備樹源碼文件

DTSI ,Device Tree Source Include,是設(shè)備樹源碼文件要用到的頭文件

DTB ,Device Tree Binary,是將DTS 編譯以后得到的二進制文件

DTC ,Device Tree Compiler,是將.dts 編譯為.dtb需要用到的編譯工具

DTC工具源碼在Linux內(nèi)核的scripts/dtc目錄下,scripts/dtc/文件夾下Makefile的內(nèi)容為:

  • hostprogs-y:= dtc
    always:= $(hostprogs-y)
    ?
    dtc-objs:= dtc.o flattree.o fstree.o data.o livetree.o treesource.o srcpos.o checks.o util.o
    dtc-objs+= dtc-lexer.lex.o dtc-parser.tab.o
    ......省略

可以看出,DTC工具依賴于dtc.c、flattree.c、fstree.c等文件,最終編譯并鏈接出DTC這個主機文件

2 設(shè)備樹框架與DTS語法

2.1 設(shè)備樹代碼分析

在學習設(shè)備樹時,可以先看一下NXP關(guān)于i.MX6ULL已有的設(shè)備樹文件,來大致了解一下設(shè)備樹文件是什么樣子的。

2.1.1 imx6ull-14x14-evk-emmc.dts

下面是/arch/arm/boot/dts/imx6ull-14x14-evk-emmc.dts

#include "imx6ull-14x14-evk.dts"

&usdhc2 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc2_8bit>;
	pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
	bus-width = <8>;
	non-removable;
	status = "okay";
};

該文件就這幾行,描述了emmc版本板子的usdhc信息。該文件的主要的功能是通過頭文件的形式包含了另一個imx6ull-14x14-evk.dts設(shè)備樹文件。

DTS語法:設(shè)備樹是可以使用“#include”引用其它文件(.dts、.h、.dtsi)。

2.1.2 imx6ull-14x14-evk.dts

下面是/arch/arm/boot/dts/imx6ull-14x14-evk.dts

/dts-v1/;

#include 
#include "imx6ull.dtsi"

/ {
	model = "Freescale i.MX6 ULL 14x14 EVK Board";
	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";

	chosen {
		stdout-path = &uart1;
	};

	memory {
		reg = <0x80000000 0x20000000>;
	};

	reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

		linux,cma {
			compatible = "shared-dma-pool";
			reusable;
			size = <0x14000000>;
			linux,cma-default;
		};
	};

	backlight {
		compatible = "pwm-backlight";
		pwms = <&pwm1 0 5000000>;
		brightness-levels = <0 4 8 16 32 64 128 255>;
		default-brightness-level = <6>;
		status = "okay";
	};

	pxp_v4l2 {
		compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";
		status = "okay";
	};

	regulators {
		compatible = "simple-bus";
		//省略...
	};
	
	//省略...
};

&cpu0 {
	arm-supply = ;
	soc-supply = ;
	dc-supply = ;
};

&clks {
	assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
	assigned-clock-rates = <786432000>;
};

//省略...

&wdog1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_wdog>;
	fsl,wdog_b;
};

該文件也是先包含一些頭文件,然后是一個斜杠+一些大括號,后面還出現(xiàn)了&符號。

DTS語法:

/ {?} 斜杠+大括號,表示根節(jié)點,一個設(shè)備只有一個根節(jié)點

(注:一個dts包含另一個dts,兩個文件里的根節(jié)點,其實也是同一個根節(jié)點)

xxx {?} 根節(jié)點內(nèi)部單獨的大括號,表示子節(jié)點,如reserved-memory {...}、pxp_v4l2 {...}等

&xxx {?} 根節(jié)點外部單獨的&符號與大括號,表示節(jié)點的追加內(nèi)容,如&cpu0 {...}等

2.1.3 imx6ull.dtsi

#include 
#include "imx6dl-pinfunc.h"
#include "imx6qdl.dtsi"

/ {
	aliases {
		i2c3 = &i2c4;
	};

	cpus {
		#address-cells = <1>;
		#size-cells = <0>;

		cpu0: cpu@0 {
			compatible = "arm,cortex-a9";
			device_type = "cpu";
			//省略...
		};

		cpu@1 {
			compatible = "arm,cortex-a9";
			device_type = "cpu";
			reg = <1>;
			next-level-cache = <&L2>;
		};
	};

	reserved-memory {
		//省略...
	};

	soc {
		//省略...
		ocram: sram@00905000 {
			compatible = "mmio-sram";
			reg = <0x00905000 0x1B000>;
			clocks = <&clks IMX6QDL_CLK_OCRAM>;
		};
		//省略...
	};
};

//省略...

&vpu_fsl {
	iramsize = <0>;
};

該文件是設(shè)備樹的頭文件,其格式與設(shè)備樹基本相同。

DTS語法:節(jié)點標簽

節(jié)點名“cpu”前面多了個“cpu0”, 這個“cpu0”就是我們所說的節(jié)點標簽。通常節(jié)點標簽是節(jié)點名的簡寫,它的作用是當其它位置需要引用時可以使用節(jié)點標簽來向該節(jié)點中追加內(nèi)容。

2.2 設(shè)備節(jié)點基本格式

設(shè)備樹是采用樹形結(jié)構(gòu)來描述板子上的設(shè)備信息的文件,每個設(shè)備都是一個節(jié)點,叫做設(shè)備節(jié)點,每個節(jié)點都通過一些屬性信息來描述節(jié)點信息,屬性就是鍵-值對。

node-name@unit-address{
	屬性1 = ...
	屬性2 = ...
	子節(jié)點...
}

2.2.1 節(jié)點名稱

node-name用于指定節(jié)點名稱,其長度為1~31個字符:

數(shù)字:0~9

字母:a~z A~Z

英文符號:, . _ + -

節(jié)點名應(yīng)使用字母開頭,并能描述設(shè)備類別(根節(jié)點用斜杠表示,不需要節(jié)點名)

2.2.2 單元地址

@unit-address用于指定單元地址,其中@符號表示一個分隔符,unit-address是實際的單元地址,它的值要和節(jié)點reg屬性的第一個地址一致,如果沒有reg屬性值,則可以省略單元地址

2.2.3 節(jié)點屬性

在節(jié)點的大括號“{}”中包含的內(nèi)容是節(jié)點屬性, 一個節(jié)點可以包含多個屬性信息,例如根節(jié)點的屬性model = "Freescale i.MX6 ULL 14x14 EVK Board",編寫設(shè)備樹最主要的內(nèi)容是編寫節(jié)點的節(jié)點屬性。屬性包括自定義屬性標準屬性,下面來看幾個標準屬性:

model屬性:用于指定設(shè)備的制造商型號,多個字符串使用“,”分隔開

compatible 屬性:由一個或多個字符串組成,是用來查找節(jié)點的方法之一

status屬性:用于指示設(shè)備的“操作狀態(tài)” ,通過status可以禁用或啟用設(shè)備

reg屬性:描述設(shè)備資源在其父總線定義的地址空間內(nèi)的地址,通常情況下用于表示一塊寄存器的起始地址(偏移地址)和長度

#address-cells 和 #size-cells:這兩個屬性同時存在,在設(shè)備樹ocrams結(jié)構(gòu)中,用在有子節(jié)點的設(shè)備節(jié)點,用于設(shè)置子節(jié)的“reg”屬性的“書寫格式”

ranges屬性:它是一個地址映射/轉(zhuǎn)換表,由子地址、父地址和地址空間長度這三部分組成:

child-bus-address: 子總線地址空間的物理地址, 由父節(jié)點的#address-cells 確定此物理地址所占用的字長

parent-bus-address:父總線地址空間的物理地址,同樣由父節(jié)點的#address-cells 確定此物理地址所占用的字長

length:子地址空間的長度,由父節(jié)點的#size-cells 確定此地址長度所占用的字長

2.2.4 特殊節(jié)點

aliases子節(jié)點:其作用是為其他節(jié)點起一個別名,例如:

  • aliases {
    i2c3 = &i2c4;
    };

chosen子節(jié)點:該節(jié)點位于根節(jié)點下,它不代表實際硬件, 它主要用于給內(nèi)核傳遞參數(shù),例如:

  • chosen {
    stdout-path = &uart1;
    };

表示系統(tǒng)標準輸出 stdout 使用串口 uart1。

3 設(shè)備樹編程之OF函數(shù)

內(nèi)核提供了一系列函數(shù)用于從設(shè)備節(jié)點獲取設(shè)備節(jié)點中定義的屬性,這些函數(shù)以 of_ 開頭,稱為OF函數(shù)。在編寫設(shè)備樹版的LED驅(qū)動時,在進行硬件配置方面,就是要用這些OF函數(shù),將寄存器地址等信息從設(shè)備樹文件中獲取出來,然后進行GPIO配置。

先來列舉一下這些函數(shù):

poYBAGKI6fOARKSHAAKYzv0jvRg056.png

3.1 查找節(jié)點的OF函數(shù)

of_find_node_by_name

通過節(jié)點名字查找指定的節(jié)點

/**
 * from: 開始查找的節(jié)點,若為NULL表示從根節(jié)點開始查找整個設(shè)備樹
 * name: 要查找的節(jié)點名字
 * return: 找到的節(jié)點,若為NULL表示查找失敗
 */
struct device_node *of_find_node_by_name(struct device_node *from, const char *name); 

of_find_compatible_node

根據(jù)device_type和compatible這兩個屬性查找指定的節(jié)點

/**
 * from: 開始查找的節(jié)點,若為NULL表示從根節(jié)點開始查找整個設(shè)備樹
 * type: 要查找的節(jié)點對應(yīng)的type字符串,也就是device_type屬性值
 * return: 找到的節(jié)點,若為NULL表示查找失敗
 */
struct device_node *of_find_node_by_type(struct device_node *from, const char *type) 

of_find_matching_node_and_match

通過of_device_id匹配表來查找指定的節(jié)點

/**
 * from: 開始查找的節(jié)點,若為NULL表示從根節(jié)點開始查找整個設(shè)備樹
 * type: 要查找的節(jié)點對應(yīng)的type字符串,也就是device_type屬性值,為NULL表示忽略掉device_type屬性
 * compatible: 要查找的節(jié)點所對應(yīng)的compatible屬性列表
 * return: 找到的節(jié)點,若為NULL表示查找失敗
 */
struct device_node *of_find_compatible_node(struct device_node *from,  
                                             const char *type,  
                                             const char *compatible)  

of_find_node_by_path

通過路徑來查找指定的節(jié)點

/**
 * path: 帶有全路徑的節(jié)點名
 * return: 找到的節(jié)點,若為NULL表示查找失敗
 */
inline struct device_node *of_find_node_by_path(const char *path) 

3.2 查找父/子節(jié)點的OF函數(shù)

of_get_parent

用于查找父節(jié)點

/**
 * node: 要查找的父節(jié)點的節(jié)點
 * return: 找到的父節(jié)點
 */
struct device_node *of_get_parent(const struct device_node *node) 

of_get_next_child

用迭代的方式查找子節(jié)點

/**
 * node: 父節(jié)點
 * prev: 前一個子節(jié)點,也就是從哪一個子節(jié)點開始迭代的查找下一個子節(jié)點,為NULL表示從第一個子節(jié)點開始
 * return: 找到的下一個子節(jié)點
 */
struct device_node *of_get_next_child(const struct device_node *node, 
                                            struct device_node *prev) 

3.3 提取屬性值的OF函數(shù)

of_find_property

查找指定的屬性

/**
 * np: 設(shè)備節(jié)點
 * name: 屬性名字
 * lenp: 屬性值的字節(jié)數(shù)
 * return: 找到的屬性
 */
property *of_find_property(const struct device_node *np, 
                                         const char *name, 
                                                int *lenp) 

of_property_count_elems_of_size

用于獲取屬性中元素的數(shù)量

/**
 * np: 設(shè)備節(jié)點
 * propname: 屬性名字
 * elem_size: 元素長度
 * return: 屬性元素數(shù)量
 */
int of_property_count_elems_of_size(const struct device_node *np, 
                                                  const char *propname,  
                                                         int elem_size) 

of_property_read_u32_index

用于從屬性中獲取指定標號的u32類型數(shù)據(jù)值

/**
 * np: 設(shè)備節(jié)點
 * propname: 屬性名字
 * index: 要讀取的值標號
 * out_value: 讀取到的值 
 * return: 0讀取成功,負值讀取失敗
 */
nt of_property_read_u32_index(const struct device_node *np, 
                                            const char *propname, 
                                                   u32 index,  
                                                   u32 *out_value) 

of_property_read_u8_array

用于讀取屬性中 u8類型的數(shù)組數(shù)據(jù)(類似的函數(shù)還有u16、u32 和 u64)

/**
 * np: 設(shè)備節(jié)點
 * propname: 屬性名字
 * out_values: 讀取到的數(shù)組值
 * return: 0讀取成功,負值讀取失敗
 */
int of_property_read_u8_array(const struct device_node *np, 
                                            const char *propname,  
                                                    u8 *out_values,  
                                                size_t sz) 

of_property_read_u8

用于讀取只有一個整形值的屬性(類似的函數(shù)還有u16、u32 和 u64)

/**
 * np: 設(shè)備節(jié)點
 * propname: 屬性名字
 * out_values: 讀取到的數(shù)組值
 * return: 0讀取成功,負值讀取失敗
 */
int of_property_read_u8(const struct device_node *np,  
                                      const char *propname, 
                                              u8 *out_value)

of_property_read_string

用于讀取屬性中字符串值

/**
 * np: 設(shè)備節(jié)點
 * propname: 屬性名字
 * out_values: 讀取到的字符串值
 * return: 0讀取成功,負值讀取失敗
 */
int of_property_read_string(struct device_node *np,  
                                    const char *propname, 
                                    const char **out_string) 

of_n_addr_cells

用于獲取#address-cells 屬性值

/**
 * np: 設(shè)備節(jié)點
 * return: 獲取到的#address-cells屬性值
 */
int of_n_addr_cells(struct device_node *np)

of_n_size_cells

用于獲取#size-cells 屬性值

/**
 * np: 設(shè)備節(jié)點
 * return: 獲取到的#size-cells屬性值
 */
int of_n_size_cells(struct device_node *np) 

3.4 其他常用的OF函數(shù)

of_device_is_compatible

用于查看節(jié)點的compatible屬性是否有包含compat指定的字符串,也就是檢查設(shè)備節(jié)點的兼容性

/**
 * device: 設(shè)備節(jié)點
 * compat: 要查看的字符串
 * return: 0不包含,正數(shù)包含
 */
int of_device_is_compatible(const struct device_node *device, 
                                          const char *compat) 

of_get_address

用于獲取地址相關(guān)屬性

/**
 * dev: 設(shè)備節(jié)點
 * index: 要讀取的地址標號
 * size: 要讀取的地址標號
 * flags: 參數(shù)
 * return: 讀取到的地址數(shù)據(jù)首地址,NULL表示失敗
 */
const __be32 *of_get_address(struct device_node *dev,  
                                            int index,  
                                            u64 *size, 
                                   unsigned int *flags) 

of_translate_address

用于將設(shè)備樹讀取到的地址轉(zhuǎn)換為物理地址

/**
 * dev 設(shè)備節(jié)點
 * in_addr: 要轉(zhuǎn)換的地址
 * return: 得到的物理地址
 */
u64 of_translate_address(struct device_node *dev,  
                               const __be32 *in_addr) 

of_address_to_resource

用于將reg屬性值,轉(zhuǎn)換為resource結(jié)構(gòu)體類型

/**
 * dev: 設(shè)備節(jié)點
 * index: 地址資源標號
 * r: 得到的 resource 類型的資源值
 * return: 0成功,負值失敗
 */
int of_address_to_resource(struct device_node *dev,  
                                          int index, 
                              struct resource *r) 

of_iomap

用于直接內(nèi)存映射

/**
 * np: 設(shè)備節(jié)點
 * index: reg屬性中要完成內(nèi)存映射的段
 * return: 經(jīng)過內(nèi)存映射后的虛擬內(nèi)存首地址,為NULL表示失敗
 */
void __iomem *of_iomap(struct device_node *np,  
                                      int index) 

4 設(shè)備樹LED驅(qū)動程序與實驗

回憶之前的LED字符設(shè)備驅(qū)動的編寫方法:直接在驅(qū)動文件regled.c中定義有關(guān)寄存器物理地址,然后使用io_remap函數(shù)進行內(nèi)存映射得到對應(yīng)的虛擬地址,最后操作寄存器對應(yīng)的虛擬地址完成對GPIO的初始化

使用設(shè)備樹編寫字符設(shè)備驅(qū)動,主要的一點區(qū)別是:使用設(shè)備樹向Linux內(nèi)核傳遞相關(guān)的寄存器物理地址,Linux驅(qū)動文件使用OF函數(shù)從設(shè)備樹中獲取所需的屬性值,然后使用獲取到的屬性值來初始化相關(guān)的IO,所以,其本質(zhì)還是配置寄存器。

所以,使用設(shè)備樹進行LED驅(qū)動,需要的修改主要為:

修改imx6ull-myboard.dts設(shè)備樹文件,在其中添加RGB-LED的設(shè)備節(jié)點

編寫RGB-LED驅(qū)動程序,獲取設(shè)備樹中的相關(guān)屬性值,并使用相關(guān)的屬性值進行GPIO的初始化

編寫RGB-LED應(yīng)用程序,控制RGB-LED的亮滅

4.1 修改設(shè)備樹文件

/ {
	model = "Freescale i.MX6 ULL 14x14 EVK Board";
	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
    
    //省略...
    
	/*myboard led*/
	myboardled {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "myboard-led";
		status = "okay";
		reg = < 0X020C406C 0x04    /*CCM_CCGR1_BASE*/	
                0X02290014 0x04    /*SW_MUX_SNVS_TAMPER3_BASE*/
				0X02290058 0x04    /*SW_PAD_SNVS_TAMPER3_BASE*/
				0X020AC000 0x04    /*GPIO5_DR_BASE*/
				0X020AC004 0x04 >; /*GPIO5_GDIR_BASE*/
	};
};

編譯設(shè)備樹,在內(nèi)核源碼的根目錄下(我的是~/myTest/imx6ull/kernel/nxp_kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga),執(zhí)行如下make命令即可單獨編譯自己修改的設(shè)備樹

make imx6ull-myboard.dtb

4.2 測試設(shè)備樹

4.2.1 測試環(huán)境切換

由于這次是修改了設(shè)備樹文件,而我的板子已經(jīng)燒錄了固件到emmc,因此,這次實驗,重新將板子設(shè)為從SD卡啟動uboot并從網(wǎng)絡(luò)啟動NFS文件系統(tǒng)的方式,方便修改測試設(shè)備樹。(板子從網(wǎng)絡(luò)啟動的方式,可參考之前的文章i.MX6ULL嵌入式Linux開發(fā)4-根文件系統(tǒng)構(gòu)建),若之前SD的uboot配置還在,將板子切換到SD卡啟動,并確保網(wǎng)絡(luò)暢通,即可從網(wǎng)絡(luò)啟動。

若nfs服務(wù)器(ubuntu虛擬器)的IP發(fā)生變化,需要和之前一樣進行類似如下的bootargs和bootcmd配置:

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.5.104:/home/xxpcb/myTest/nfs/rootfs,proto=tcp,nfsvers=4 rw ip=192.168.5.102:192.168.5.104:192.168.5.1:255.255.255.0::eth1:off' 
setenv bootcmd 'tftp 80800000 nxp/zImage; tftp 83000000 nxp/imx6ull-myboard.dtb; bootz 80800000 - 83000000' 
saveenv
boot

注意這里的192.168.5.104是我的ubuntu的IP,192.168.5.102是板子的IP。

4.2.2 設(shè)備樹修改后的效果

在測試設(shè)備樹之前,可以先看一下目前板子的設(shè)備樹中都有什么:

poYBAGKI6weAJ82hAAAhBz5FlOk271.png

將編譯后的dtb文件放到網(wǎng)絡(luò)啟動位置,比如我的是復制到這里:

xxpcb@ubuntuTest:~/myTest/imx6ull/kernel/nxp_kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/arch/arm/boot/dts$ cp imx6ull-myboard.dtb ~/myTest/tftpboot/nxp/

然后重啟板子,再次查看/proc/device-tree/目錄:

poYBAGKI6xqAYtJ_AABrX1plbTM354.png

可以看到,出現(xiàn)了新加的myboardled節(jié)點,進入myboardled目錄下,可以看到其屬性信息。

4.3 修改LED驅(qū)動程序

驅(qū)動程序整體框架和上一篇的寄存器版配置程序基本相同,主要的不同是修改硬件配置的方式,

/*
 * @description   : LED硬件初始化(IO映射、時鐘、GPIO配置)
 * @param         : 無
 * @return        : 0 成功;其他 失敗
 */
static int dtsled_hardware_init(void)
{
    u32 val = 0;
    int ret;
    u32 regdata[14];
    const char *str;
    struct property *proper;

    /* 獲取設(shè)備樹中的屬性數(shù)據(jù) */
    /* 1、獲取設(shè)備節(jié)點:myboardled */
    dtsled.nd = of_find_node_by_path("/myboardled");
    if(dtsled.nd == NULL) 
    {
        printk("myboardled node nost find!\r\n");
        return -EINVAL;
    } 
    else 
    {
        printk("myboardled node find!\r\n");
    }

    /* 2、獲取compatible屬性內(nèi)容 */
    proper = of_find_property(dtsled.nd, "compatible", NULL);
    if(proper == NULL) 
    {
        printk("compatible property find failed\r\n");
    } 
    else 
    {
        printk("compatible = %s\r\n", (char*)proper->value);
    }

    /* 3、獲取status屬性內(nèi)容 */
    ret = of_property_read_string(dtsled.nd, "status", &str);
    if(ret < 0)
    {
        printk("status read failed!\r\n");
    } 
    else 
    {
        printk("status = %s\r\n",str);
    }

    /* 4、獲取reg屬性內(nèi)容 */
    ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);
    if(ret < 0) 
    {
        printk("reg property read failed!\r\n");
    } 
    else 
    {
        u8 i = 0;
        printk("reg data:\r\n");
        for(i = 0; i < 10; i++)
        {
            printk("%#X ", regdata[i]);
        }
        printk("\r\n");
    }

    /* 初始化LED */
#if 0
    /* 1、寄存器地址映射(使用ioremap) */
    IMX6U_CCM_CCGR1      = ioremap(regdata[0], regdata[1]);
    SW_MUX_SNVS_TAMPER3  = ioremap(regdata[2], regdata[3]);
    SW_PAD_SNVS_TAMPER3  = ioremap(regdata[4], regdata[5]);
    GPIO5_DR             = ioremap(regdata[6], regdata[7]);
    GPIO5_GDIR           = ioremap(regdata[8], regdata[9]);
#else
    /* 1、寄存器地址映射(直接使用of_iomap) */
    IMX6U_CCM_CCGR1      = of_iomap(dtsled.nd, 0);
    SW_MUX_SNVS_TAMPER3  = of_iomap(dtsled.nd, 1);
    SW_PAD_SNVS_TAMPER3  = of_iomap(dtsled.nd, 2);
    GPIO5_DR             = of_iomap(dtsled.nd, 3);
    GPIO5_GDIR           = of_iomap(dtsled.nd, 4);
#endif

    /* 2、使能GPIO1時鐘 */
    //省略... 后面的配置與上一篇的相同
}

上面的程序修改部分,從整個LED驅(qū)動的框架來看,修改的只是如下圖中的黃色框部分:

pYYBAGKI6yuAUHczAAHJtFqyndM608.png

4.4 實驗測試

編譯設(shè)備樹版的LED驅(qū)動程序,并將編譯好的ko文件發(fā)送到nfs文件系統(tǒng)對應(yīng)的文件夾下。

LED是應(yīng)用程序不需要修改,仍使用上一篇文章中的程序即可。

poYBAGKI6zWAUIZzAAHMb0RRzhE854.png

測試方法與之前基本相同:

poYBAGKI6z2AL_VoAACIdMUcgOg160.png

使用設(shè)備樹的方式,再次點亮LED:

pYYBAGKI60aAYOiNAAC-QqGhKlk901.png

5 總結(jié)

本篇介紹了設(shè)備樹的基本原理以及設(shè)備樹的使用方法,在上一篇點亮LED的代碼基礎(chǔ)上,通過設(shè)備樹的方式,實現(xiàn)了LED點燈,總結(jié)一下主要的修改就是先在設(shè)備樹中添加LED節(jié)點,然后在驅(qū)動文件中通過OF函數(shù)來讀取設(shè)備樹中的寄存器信息,再進行GPIO的初始化,其它部分的程序與上一篇的基本一樣。

poYBAGKI602AaQxgAAB98U7Hbag233.png

審核編輯:符乾江

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5082

    文章

    19084

    瀏覽量

    304454
  • 驅(qū)動
    +關(guān)注

    關(guān)注

    12

    文章

    1837

    瀏覽量

    85241
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11261

    瀏覽量

    209217
收藏 人收藏

    評論

    相關(guān)推薦

    i.MX6ULL 驅(qū)動開發(fā)7—按鍵輸入捕獲與GPIO輸入配置與高低電平讀取

    本篇主要介紹了i.MX6ULL的按鍵檢測的使用,主要的知識點是設(shè)備的修改,以及GPIO的輸入配置與高低電平的讀取。
    的頭像 發(fā)表于 05-24 09:11 ?6185次閱讀
    <b class='flag-5'>i.MX6ULL</b> <b class='flag-5'>驅(qū)動</b><b class='flag-5'>開發(fā)</b>7—按鍵輸入捕獲與GPIO輸入配置與高低電平讀取

    使用i.MX6ULL開發(fā)板進行Linux根文件系統(tǒng)的完善

    上一篇推文講了怎么移植根文件系統(tǒng),并在i.MX6ULL開發(fā)板中運行起來,但是會出現(xiàn)一些提示,現(xiàn)在來進行根文件的完善。
    發(fā)表于 10-17 11:13 ?782次閱讀

    移植NXP官方linux 5.4內(nèi)核到i.MX6ULL開發(fā)

    本文描述移植NXP官方 linux 5.4 內(nèi)核到i.MX6ULL開發(fā)板。
    發(fā)表于 12-19 11:10 ?2020次閱讀

    移植5.4內(nèi)核到迅為I.MX6ULL開發(fā)

    ),選擇5.4.3內(nèi)核編譯生成的對應(yīng)鏡像和設(shè)備文件(關(guān)于i.MX6ULL終結(jié)者開發(fā)板鏡像的燒寫,大家可以參考開發(fā)板使用手冊的:第六章
    發(fā)表于 06-29 10:13

    i.MX6ULL開發(fā)板硬件資源

    迅為i.MX6ULL 終結(jié)者開發(fā)板硬件資源非常豐富,幾乎將 i.MX6ULL 芯片的所有資源都擴展引出到底板上了,底板提供了豐富的外設(shè)接口,開發(fā)板的尺寸是 190mm*125mm,充分
    發(fā)表于 12-29 06:18

    初識 i.MX6ULL 寄存器

    裸機開發(fā)_L1_匯編LED實驗0. 本節(jié)目標1. 硬件層電路2. 初識 i.MX6ULL 寄存器2.1 i.MX6ULL 時鐘控制寄存器2.2 i.
    發(fā)表于 12-20 07:13

    關(guān)于i.MX6ULL配置GPIO

    正如學習C語言時寫的第一段代碼都是“HelloWorld!”,接觸一款新的處理器時往往是從點亮一個LED開始;而點亮一個LED,則需要操作這款芯片的GPIO外設(shè)。那么作為廣受歡迎的
    發(fā)表于 08-05 10:37

    I.MX6ULL無法枚舉USB2514是為什么?

    你好目前,I.MX6ULL開發(fā)存在一些問題。其中之一是OTG USB2無法正常掛載USB2514,無法正確枚舉下游設(shè)備,只顯示設(shè)備id。usb設(shè)計要注意什么。
    發(fā)表于 04-03 06:55

    如何在i.MX6ULL上為PF1510配置i2c?

    我們計劃將 PF1510 與 i.MX6ULL 處理器一起使用。我看到這個設(shè)備示例: https://github.com/Freescale/linux-fslc/blob
    發(fā)表于 05-17 14:02

    基于NXP i.MX6ULL處理器的FETMX6ULL-C核心板

    合作伙伴,飛凌不負美譽,基于i.MX6ULL匠心打造的FETMX6ULL-S核心板一經(jīng)問世便好評不斷,且已有數(shù)百家來自工業(yè)、醫(yī)療、電力、物聯(lián)網(wǎng)等行業(yè)的用戶采用此款核心板快速完成了整機產(chǎn)品的開發(fā)上市。
    發(fā)表于 04-11 15:05 ?1151次閱讀
    基于NXP <b class='flag-5'>i.MX6ULL</b>處理器的FETMX<b class='flag-5'>6ULL</b>-C核心板

    i.MX6ULL驅(qū)動開發(fā)4——點亮LED(寄存器版)

    本篇主要介紹了如何通過操作寄存器來點亮i.MX6ULL開發(fā)板上的led,通過編寫LED對應(yīng)的驅(qū)動
    的頭像 發(fā)表于 05-21 21:26 ?2965次閱讀
    【<b class='flag-5'>i.MX6ULL</b>】<b class='flag-5'>驅(qū)動</b><b class='flag-5'>開發(fā)</b>4——<b class='flag-5'>點亮</b><b class='flag-5'>LED</b>(寄存器版)

    基于i.MX6ULL點亮LED

    都說入門一款芯片的第一步是點亮LED,但是i.MX6ULL入門門檻比較高,特別是通過自學入門的,這個系列已經(jīng)寫了好久了,最近打算在項目不急的時候加快一下學習進度,現(xiàn)在就開始學習一下怎么點亮
    的頭像 發(fā)表于 03-06 09:09 ?808次閱讀

    【北京迅為】i.MX6ULL開發(fā)板移植 Debian 文件系統(tǒng)

    【北京迅為】i.MX6ULL開發(fā)板移植 Debian 文件系統(tǒng)
    的頭像 發(fā)表于 02-10 15:34 ?1133次閱讀
    【北京迅為】<b class='flag-5'>i.MX6ULL</b><b class='flag-5'>開發(fā)</b>板移植 Debian 文件系統(tǒng)

    基于i.MX6ULL的掉電檢測設(shè)計與軟件測試

    基于i.MX6ULL的掉電檢測設(shè)計與軟件測試基于i.MX6ULL平臺設(shè)計實現(xiàn)掉電檢測功能,首先選擇一路IO,利用IO電平變化觸發(fā)中斷,在編寫驅(qū)動時捕獲該路GPIO的中斷,然后在中斷響應(yīng)函數(shù)中發(fā)
    的頭像 發(fā)表于 11-09 10:40 ?828次閱讀
    基于<b class='flag-5'>i.MX6ULL</b>的掉電檢測設(shè)計與軟件測試

    【迅為電子】i.MX6UL和i.MX6ULL芯片區(qū)別與開發(fā)板對比

    【迅為電子】i.MX6UL和i.MX6ULL芯片區(qū)別與開發(fā)板對比
    的頭像 發(fā)表于 11-28 14:31 ?268次閱讀
    【迅為電子】<b class='flag-5'>i.MX6</b>UL和<b class='flag-5'>i.MX6ULL</b>芯片區(qū)別與<b class='flag-5'>開發(fā)</b>板對比
    RM新时代网站-首页