Linux驱动开发:设备树dts详解

这篇具有很好参考价值的文章主要介绍了Linux驱动开发:设备树dts详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:掌握设备树是 Linux 驱动开发人员必备的技能!因为在新版本的 Linux 中,ARM 相关的驱动全部采用了设备树(也有支持老式驱动的,比较少),最新出的 CPU 其驱动开发也基本都是基于设备树的,比如 ST 新出的 STM32MP157、NXP 的 I.MX8 系列等。本篇博客核心是系统性的学习设备树的语法,并懂得如何运用设备树进行 Linux 驱动开发!

实验硬件:imx6ull;Linux内核版本:4.1.15

一、什么是设备树?

1.1 设备树概述 

设备树(Device Tree),将这个词分开就是“设备”和“树”,描述设备树的文件叫做 DTS(Device Tree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息,比如 CPU 数量、 内存基地址、IIC 接口上接了哪些设备、SPI 接口上接了哪些设备等等,如下图所示:

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

树的主干就是系统总线,IIC 控制器、GPIO 控制器、SPI 控制器等都是接到系统主线上的分支。IIC 控制器有分为 IIC1 IIC2 两种,其中 IIC1 上接了 FT5206AT24C02 这两个 IIC 设备,IIC2 上只接了 MPU6050 这个设备。DTS 文件的主要功能就是按照图所示的结构来描述板子上的设备信息,DTS 文件描述设备信息是有相应的语法规则要求的,稍后我们会详细的讲解 DTS 语法规则。

设备树由一系列的节点和属性组成,节点可包含子节点。在设备树中,可描述的信息包括:

  • CPU数量和类型
  • 内存基地址和大小
  • 总线和桥
  • 外设连接
  • 中断控制器和中断使用情况
  • GPIO控制器和GPIO使用情况
  • 时钟控制器和时钟使用情况

bootload 会将这些信息传递给内核,内核开始识别这些树,并解析成 Linux 内核中 platform_device, i2c_client, spi_device等设备,而这些设备使用的内存资源,中断等信息也传递给内核。内核会将这些资源绑定给相应的设备。

设备树相关的包含 3 部分:DTSDTCDTB

DTS 是设备树源码文件, DTB 是将 DTS 编译以后得到的二进制文件。那么将 .dts 编译为 .dtbn 需要什么工具呢?需要用到 DTC 工具

1.2 设备树语法

.dts 是一种 ASCII 文本格式的设备树描述。基本上一个 .dts 文件对应一个 ARM 设备,一般放置在arch/arm/boot/dts/ 目录中。

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

设备树也支持头文件,设备树的头文件扩展名为 .dtsi。在 imx6ull-alientekemmc.dts 中有如下所示内容:

#include <dt-bindings/input/input.h>//引用.h文件
#include "imx6ull.dtsi" //引用“imx6ull.dtsi”这个.dtsi 头文件

一般 .dtsi 文件用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UARTIIC 等等。
比如 imx6ull.dtsi 就是描述 I.MX6ULL 这颗 SOC 内部外设情况信息。

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "imx6ull-pinfunc.h"
#include "imx6ull-pinfunc-snvs.h"
#include "skeleton.dtsi"

/ {
	aliases {
		can0 = &flexcan1;
		...
	};
	cpus {
		#address-cells = <1>;
		#size-cells = <0>;

		cpu0: cpu@0 {
			compatible = "arm,cortex-a7";
			device_type = "cpu";
			reg = <0>;
			clock-latency = <61036>; /* two CLK32 periods */
			operating-points = <
				/* kHz	uV */
				996000	1275000
				792000	1225000
				528000	1175000
				396000	1025000
				198000	950000
			>;
							/* kHz	uV */
				996000	1275000
				792000	1225000
				528000	1175000
				396000	1025000
			...
	};

	intc: interrupt-controller@00a01000 {
		compatible = "arm,cortex-a7-gic";
		#interrupt-cells = <3>;
		interrupt-controller;
		reg = <0x00a01000 0x1000>,
		<0x00a02000 0x100>;
	};
		...

文件描述了 CPU arm,cortex-a7 ,支持 996MHz792MHz等频率, 时钟一些信息。

  • “/”是根节点,每个设备树文件只有一个根节点
  • “/”是根节点,每个设备树文件只有一个根节点
node-name@unit-address

其中 “node-name” 是节点名字,为 ASCII 字符串,节点名字应该能够清晰的描述出节点的功能,比如 “uart1” 就表示这个节点是 UART1 外设。“unit-address” 一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话 “unit-address” 可以不要,比如 “cpu@0”“interrupt-controller@00a01000”

label: node-name@unit-address

引入 label 的目的就是为了方便访问节点,可以直接通过 &label 来访问这个节点,比如通过&cpu0 就可以访问 “cpu@0” 这个节点。很明显通过 &intc 来访问 “interrupt-controller@00a01000” 这个节点要方便很多!

每个节点都有不同属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流。设备树源码中常用的几种数据形式如下所示:

1、字符串

compatible = "fairchild,74hc595";

2、32 位无符号整数

reg = <0 0x123456 100>;

3、字符串列表

compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";

二、设备树详解

2.1 标准属性

1、compatible 属性

compatible 属性也叫做“兼容性”属性,这是非常重要的一个属性! compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序,compatible 属性的值格式如下所示:

"manufacturer,model"

其中 manufacturer 表示厂商,model 一般是模块对应的驱动名字。比如 imx6ull-alientek-emmc.dts 中 sound 节点是 I.MX6U-ALPHA 开发板的音频设备节点,I.MX6U-ALPHA 开发板上的音频芯片采用的欧胜(WOLFSON)出品的 WM8960,sound 节点的 compatible 属性值如下:

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

其中 “fsl” 表示厂商是飞思卡尔,“imx6ul-evk-wm8960” “imx-audio-wm8960” 表示驱动模块名字。设备首先使用第一个兼容值在 Linux 内核里面查找,如果没有找到的话就使用第二个兼容值查。

2、 model 属性

model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比如:

model = "wm8960-audio";

3、status 属性

status 属性看名字就知道是和设备状态有关的,status 属性值也是字符串,字符串是设备的状态信息,可选的状态如下表所示:

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

4、★#address-cells 和#size-cells 属性

#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位)
#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)
#address-cells#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度, reg 属性的格式一为:

reg = <address1 length1 address2 length2 address3 length3……>

每个 “address length” 组合表示一个地址范围,其中 address 是起始地址, length 是地址长度.
#address-cells 表明 address 这个数据所占用的字长, #size-cells 表明 length 这个数据所占用的字长 

aips3: aips-bus@02200000 {
	compatible = "fsl,aips-bus", "simple-bus";
	#address-cells = <1>;
	#size-cells = <1>;
	
	dcp: dcp@02280000 {
		compatible = "fsl,imx6sl-dcp";
		reg = <0x02280000 0x4000>;
	};
};

说明 aips3: aips-bus@02200000 节点起始地址长度所占用的字长为 1,地址长度所占用的字长也为 1
子节点 dcp: dcp@02280000 的 reg 属性值为<0x02280000 0x4000>相当于设置了起始地址为 0x02280000,地址长度为 0x40000,但是 dcp的地址长度(范围)并没有 0x4000 这么多

5、 ★reg 属性

reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息,一般是(address, length)组成,详情如上所述!

6、ranges 属性

ranges 属性值可以为空或者按照 (child-bus-address,parent-bus-address,length) 格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:

child-bus-address:子总线地址空间的物理地址,由父节点的 #address-cells 确定此物理地址所占用的字长。
parent-bus-address:父总线地址空间的物理地址,同样由父节点的 #address-cells 确定此物理地址所占用的字长。
length:子地址空间的长度,由父节点的 #size-cells 确定此地址长度所占用的字长。

如果 ranges 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换,例程如下:

soc {
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "simple-bus";
	interrupt-parent = <&gpc>;
	ranges;//为空

ranges 属性不为空的示例代码如下所示:

soc {
	compatible = "simple-bus";
	#address-cells = <1>;
	#size-cells = <1>;
	ranges = <0x0 0xe0000000 0x00100000>;
	
	serial {
		device_type = "serial";
		compatible = "ns16550";
		reg = <0x4600 0x100>;
		clock-frequency = <0>;
		interrupts = <0xA 0x8>;
		interrupt-parent = <&ipic>;
	};
};

节点 soc 定义的 ranges 属性,值为 <0x0 0xe0000000 0x00100000>,此属性值指定了一个 1024KB(0x00100000)的地址范围,子地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000。

serial 是串口设备节点,reg 属性定义了 serial 设备寄存器的起始地址为 0x4600,寄存器长度为 0x100。经过地址转换,serial 设备可以从 0xe0004600 开始进行读写操作,0xe0004600=0x4600+0xe0000000

2.2 向节点追加或修改内容

imx6ull.dtsi 有以下内容,表示 I2C 节点。不同的 I2C 设备有不通的详细属性,采用追加节点方法不会对共有信息带来污染。

i2c1: i2c@021a0000 {
	#address-cells = <1>;
	#size-cells = <0>;
	compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
	reg = <0x021a0000 0x4000>;
	interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_I2C1>;
	status = "disabled";
};

现在要在 i2c1 节点下创建一个子节点,这个子节点就是 fxls8471,最简单的方法就是在 i2c1 下直接添加一个名为 fxls8471 的子节点,如下所示: 

&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";
	
	fxls8471@1e {
		compatible = "fsl,fxls8471";
		reg = <0x1e>;
		position = <0>;
		interrupt-parent = <&gpio5>;
		interrupts = <0 8>;
};

子节点可以修改增加一些属性;
比如子节点中 clock-frequency 新增加的属性。
status 状态由disabled变成 okay 

2.3 设备树在目录中的体现

运行 cd /proc/device-tree 后,ls -a 查询当前目录下的文本情况

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

1、在当前目录下执行 cat model

model 的内容是 “Freescale i.MX6 ULL 14x14 EVK Board”

compatible 的内容为 “fsl,imx6ull-14x14-evkfsl,imx6ull”

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

打开文件 imx6ull-alientek-emmc.dts 查看一下,这正是根节点 “/”model compatible 属性值

2、soc子节点

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

3、aliases 子节点

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

 与imx6ull.dtsi中的 aliases一致

4、chosen 子节点

chosen 并不是一个真实的设备, chosen 节点主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数,一般.dts 文件中 chosen 节点通常为空或者内容很少, imx6ull-alientekemmc.dts 中 chosen 节点内容如下所示:

chosen {
	stdout-path = &uart1;
}

chosen 节点仅仅设置了属性 “stdout-path”,表示标准输出使用 uart1

root@ATK-IMX6U:/proc/device-tree/chosen# ls
bootargs  name  stdout-path

我们可以发现 chosen 内存在 boot 的启动参数 bootargs

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

cat 查看确实是启动信息
1,我们并没有在设备树中设置 chosen 节点的 bootargs 属性,那么 bootargs这个属性是怎么产生的如何关联起来的呢?
2,为什么和 uboot 中的参数不一致?

chosen 节点的 bootargs 属性不是我们在设备树里面设置的,那么只有一种可能,那就是 uboot 自己在 chosen 节点里面添加了 bootargs 属性,并且设置 bootargs 属性的值为 bootargs环境变量的值。

uboot 源码中搜索 “chosen”,在文件 common/fdt_support.c 

int fdt_chosen(void *fdt)
{
	 //寻找chosen节点
	nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
	
	if (nodeoffset < 0)
		return nodeoffset;
	//读取bootargs环境
	str = getenv("bootargs");
}

2.4 Linux 内核解析 DTB 文件 

启动内核流程函数

Linux驱动开发:设备树dts详解,Linux驱动开发,Linux,设备树,嵌入式

start_kernel 函数中最终调用了函数为 unflatten_dt_node(很多初始化操作都在start_kernel )!

2.5 帮助文档信息

设备树是用来描述板子上的设备信息的,不同的设备其信息不同,反映到设备树中就是属性不同。那么我们在设备树中添加一个硬件对应的节点的时候从哪里查阅相关的说明呢?路径为:Linux 源码目录 /Documentation/devicetree/bindings

比如我们现在要想在 I.MX6ULL 这颗 SOC 的 I2C 下添加一个节点,那么就可以查看Documentation/devicetree/bindings/i2c/i2c-imx.txt,此文档详细的描述了 I.MX 系列的 SOC 如何在设备树中添加 I2C 设备节点,文档内容如下所示:

root@ubuntu:/home/wy/imx6ul/kernel/Documentation/devicetree/bindings/i2c# cat i2c-imx.txt
* Freescale Inter IC (I2C) and High Speed Inter IC (HS-I2C) for i.MX

Required properties:
- compatible :
  - "fsl,imx1-i2c" for I2C compatible with the one integrated on i.MX1 SoC
  - "fsl,imx21-i2c" for I2C compatible with the one integrated on i.MX21 SoC
  - "fsl,vf610-i2c" for I2C compatible with the one integrated on Vybrid vf610 SoC
- reg : Should contain I2C/HS-I2C registers location and length
- interrupts : Should contain I2C/HS-I2C interrupt
- clocks : Should contain the I2C/HS-I2C clock specifier

Optional properties:
- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
  The absence of the propoerty indicates the default frequency 100 kHz.
- dmas: A list of two dma specifiers, one for each entry in dma-names.
- dma-names: should contain "tx" and "rx".

Examples:

i2c@83fc4000 { /* I2C2 on i.MX51 */
	compatible = "fsl,imx51-i2c", "fsl,imx21-i2c";
	reg = <0x83fc4000 0x4000>;
	interrupts = <63>;
};

i2c@70038000 { /* HS-I2C on i.MX51 */
	compatible = "fsl,imx51-i2c", "fsl,imx21-i2c";
	reg = <0x70038000 0x4000>;
	interrupts = <64>;
	clock-frequency = <400000>;
};

i2c0: i2c@40066000 { /* i2c0 on vf610 */
	compatible = "fsl,vf610-i2c";
	reg = <0x40066000 0x1000>;
	interrupts =<0 71 0x04>;
	dmas = <&edma0 0 50>,
		<&edma0 0 51>;
	dma-names = "rx","tx";
};

三、设备树节点的操作函数

Linux 驱动程序往往需要去读取到 Linux 内核中附带的 dts 文件,并操作设备树 DTS 的相关节点!接下来我们来学习一下,如何进行设备树节点操作! 

1、查找节点的 of 函数

Linux 内核使用 device_node 结构体来描述一个节点

1、 of_find_node_by_name 函数

//通过节点名字查找指定的节点
struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
//from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
//name:要查找的节点名字

2、of_find_node_by_type 函数

//通过device_type查找指定的节点
struct device_node *of_find_node_by_type(struct device_node *from, const char *type)

3、 of_find_compatible_node 函数

device_type 和 compatible 这两个属性查找指定的节点
struct device_node *of_find_compatible_node(struct device_node *from,
											const char *type,
											const char *compatible)

4、of_find_matching_node_and_match 函数

//通过 of_device_id 匹配表来查找指定的节点
struct device_node *of_find_matching_node_and_match(struct device_node *from,
						const struct of_device_id *matches,
						const struct of_device_id **match)

5、of_find_node_by_path 函数

struct device_node *of_get_parent(const struct device_node *node)
//node 要查找的父节点的节点

2、查找父/子节点的 OF 函数

1、of_get_parent 函数
用于获取指定节点的父节点

struct device_node *of_get_parent(const struct device_node *node)
//node 要查找的父节点的节点

2、of_get_next_child 函数

//用迭代的查找子节点
struct device_node *of_get_next_child(const struct device_node *node,
						              struct device_node *prev)
//node:父节点。
//prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子//节点。可以设置为NULL,表示从第一个子节点开始。
//返回 找到的下一个子节点。

3、提取属性值的 OF 函数

property 结构体,此结构体定义在文件 include/linux/of.h

struct property {
	char *name; /* 属性名字 */
	int length; /* 属性长度 */
	void *value; /* 属性值 */
	struct property *next; /* 下一个属性 */
	unsigned long _flags;
	unsigned int unique_id;
	struct bin_attribute attr;
};

1、 of_find_property 函数

property *of_find_property(const struct device_node *np,
						   const char *name,
						   int *lenp)
//np:设备节点。
//name: 属性名字。
//lenp:属性值的字节数
//返回找到的属性

2、 of_property_count_elems_of_size 函数
用于获取属性中元素的数量,比如 reg 属性值是一个数组,那么使用此函数可以获取到这个数组的大小

int of_property_count_elems_of_size(const struct device_node *np,
							        const char *propname,
							        int elem_size)
//np:设备节点。
//proname: 需要统计元素数量的属性名字。
//elem_size:元素长度。
//返回 得到的属性元素数量

3、 of_property_read_u32_index 函数
从属性中获取指定标号的 u32 类型数据值(无符号 32 位),比如某个属性有多个 u32 类型的值,那么就可以使用此函数来获取指定标号的数据值

int of_property_read_u32_index(const struct device_node *np,
					           const char *propname,
					           u32 index,
					           u32 *out_value)

4、of_property_read_u8_array 函数
      of_property_read_u16_array 函数
      of_property_read_u32_array 函数
      of_property_read_u64_array 函数

分别是读取属性中 u8、 u16、 u32 和 u64 类型的数组数据,比如大多数的 reg 属性都是数组数据,可以使用这 4 个函数一次读取出 reg 属性中的所有数据

5、 of_property_read_string 函数

//用于读取属性中字符串值
int of_property_read_string(struct device_node *np,
                            const char *propname,
                            const char **out_string)

6、 of_n_addr_cells 函数
用于获取#address-cells 属性值

7、 of_n_size_cells 函数
of_size_cells 函数用于获取#size-cells 属性值

8、of_iomap 函数
采用设备树以后就可以直接通过 of_iomap 函数来获取内存地址所对应的虚拟地址,不需要使用 ioremap 函数了

四、作者有话

设备树的熟练掌握是每个 Linux 驱动开发工程师必须掌握的技能,特别是如今的 Linux 内核版本都是支持设备树的。设备树的出现极大的方便了各种设备的驱动代码编写,同时降低了 Linux 内核的冗余。设备节点操作函数有很多,其功能也各不相同,但是常用的函数就那么几个,希望大家可以好好掌握!!!文章来源地址https://www.toymoban.com/news/detail-583015.html

到了这里,关于Linux驱动开发:设备树dts详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【嵌入式Linux内核驱动】04_Jetson nano GPIO应用 | 驱动开发 | 官方gpiolib、设备树与chip_driver

    0.暴露给应用层 应用 解决调试目录为空的问题 调试信息 1.最简读写文件(在/SYS下) 设备树 验证测试 编译文件 驱动 of_get_named_gpio_flags //获取设备树节点的属性 gpio_is_valid //判断是否合法 devm_gpio_request //申请使用gpio,并调用设置pinctrl device_create_file //根据设备树节点属性,创建

    2024年02月07日
    浏览(61)
  • 嵌入式Linux(8):字符设备驱动--注册字符类设备

    杂项设备 注册杂项设备: 注销杂项设备: 字符类设备 文件:include/linux/cdev.h 步骤流程: 定义一个cdev结构体。 使用cdev_init函数初始化cdev结构体成员变量。 参数: 第一个:要初始化的cdev结构体 第二个:文件操作集: cdev-ops = fops;//实际就是把文件操作集写ops 使用cdev_add函数

    2023年04月22日
    浏览(51)
  • Linux驱动开发:设备树dts详解

    前言: 掌握设备树是 Linux 驱动开发人员必备的技能!因为在新版本的 Linux 中, ARM 相关的驱动全部采用了设备树(也有支持老式驱动的,比较少),最新出的 CPU 其驱动开发也基本都是基于设备树的,比如 ST 新出的 STM32MP157、NXP 的 I.MX8 系列等。本篇博客核心是系统性的学习设

    2024年02月17日
    浏览(59)
  • 【嵌入式Linux学习笔记】platform设备驱动和input子系统

    对于Linux这种庞大的操作系统,代码重用性非常重要,所以需要有相关的机制来提升效率,去除重复无意义的代码,尤其是对于驱动程序,所以就有了platform和INPUT子系统这两种工作机制。 学习视频地址:【正点原子】STM32MP157开发板 platform 驱动框架分为总线、设备和驱动。总

    2024年02月07日
    浏览(60)
  • 韦东山嵌入式Liunx入门驱动开发一(Hello 驱动编程、GPIO基础知识、LED驱动、总线设备驱动模型)

    本人学习完韦老师的视频,因此来复习巩固,写以笔记记之。 韦老师的课比较难,第一遍不知道在说什么,但是坚持看完一遍,再来复习,基本上就水到渠成了。 看完视频复习的同学观看最佳! 基于 IMX6ULL-PRO 参考视频 Linux快速入门到精通视频 参考资料 :01_嵌入式Linux应用

    2024年04月25日
    浏览(81)
  • 嵌入式Linux驱动开发之点灯

      使用驱动开发的方式点亮一个LED灯。看看两者有啥区别不? 首先查看原理图,看看我们的板子上的LED等接在哪一个IO口上面。 好了,看原理图我们知道LED灯接在芯片的GPIO1的第三个引脚上面,也就是GPIO1_IO03。 先掌握三个名词 CCM: Clock Controller Module (时钟控制模块) IOMUXC : I

    2024年02月01日
    浏览(101)
  • 嵌入式Linux开发-USB驱动

    哥们马上就要被裁了,总得整理一下技术方面的积累,准备开始下一轮的面试和找工作之旅了。。。。 通用串行总线(USB)是主机和外围设备之间的一种连接。 从拓扑上来看,是一颗由几个点对点的连接构建而成的树。这些连接是连接设备和集线器(hub)的四线电缆(底线、电源线

    2024年02月20日
    浏览(73)
  • 正点原子嵌入式linux驱动开发——Linux CAN驱动

    CAN是目前应用非常广泛的现场总线之一,主要应用于汽车电子和工业领域 ,尤其是汽车领域,汽车上大量的传感器与模块都是通过CAN总线连接起来的。CAN总线目前是自动化领域发展的热点技术之一,由于其高可靠性,CAN总线目前广泛的应用于工业自动化、船舶、汽车、医疗和

    2024年02月06日
    浏览(79)
  • 正点原子嵌入式linux驱动开发——Linux WIFI驱动

    WIFI的使用已经很常见了,手机、平板、汽车等等,虽然可以使用有线网络,但是有时候很多设备存在布线困难的情况,此时WIFI就是一个不错的选择。 正点原子STM32MP1开发板支持USB和SDIO这两种接口的WIFI ,本章就来学习一下如何在STM32MP1开发板上使用USB和SDIO这两种WIFI。 正点原

    2024年02月05日
    浏览(71)
  • 嵌入式Linux驱动开发——常见框架梳理

    本文主要介绍了Linux驱动开发中一些常用的驱动框架,platform、input、iic、spi等,硬件平台使用的是正点原子的imx6ull开发板。 不管什么框架最后都是要追溯到配置IO的电气属性和复用功能 如果要使用外部中断,设备树节点中还需添加相关信息,什么边沿触发 1:module_init和mod

    2024年02月15日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包