linux驱动开发 - 04_Linux 设备树学习 - DTS语法

news2024/10/5 11:21:05

文章目录

  • Linux 设备树学习 - DTS语法
    • 1 什么是设备树?
    • 2 DTS、DTB和DTC
    • 3 DTS 语法
      • 3.1 dtsi 头文件
      • 3.2 设备节点
      • 3.3 标准属性
        • 1、compatible 属性
        • 2、model 属性
        • 3、status 属性
        • 4、#address-cells 和#size-cells 属性
        • 5、reg 属性
        • 6、ranges 属性
        • 7、name 属性
        • 8、device_type 属性
    • 4 向节点追加或修改内容
    • 5 设备树在系统中的体现
        • 1、根节点“/”各个属性
        • 2、根节点“/”各子节点

Linux 设备树学习 - DTS语法

1 什么是设备树?

设备树(Device Tree),将这个词分开就是“设备”和“树”,描述设备树的文件叫做 DTS(DeviceTree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息,比如CPU 数量、 内存基地址、 IIC 接口上接了哪些设备、 SPI 接口上接了哪些设备等等
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t7Vzitnk-1681394085907)(pic/4-1 设备树结构示意图.png)]

在图中,树的主干就是系统总线,IIC 控制器、 GPIO 控制器、 SPI 控制器等都是接到系统主线上的分支。IIC 控制器有分为 IIC1 和 IIC2 两种,其中 IIC1 上接了 FT5206 和 AT24C02这两个 IIC 设备, IIC2 上只接了 MPU6050 这个设备。

2 DTS、DTB和DTC

  • 设备树源文件扩展名为.dts,在移植 Linux 的时候却一直在使用.dtb 文件,那么 DTS 和 DTB 这两个文件是什么关系呢? DTS 是设备树源码文件, DTB 是将DTS 编译以后得到的二进制文件。
  • 将.c 文件编译为.o 需要用到 gcc 编译器,那么将.dts 编译为.dtb需要什么工具呢?需要用到 DTC 工具! DTC 工具源码在 Linux 内核的 scripts/dtc 目录下,scripts/dtc/Makefile 文件内容如下:
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 这个主机文件。如果要编译 DTS 文件的话只需要进入到 Linux 源码根目录下,然后执行如下命令:

make all

或者:

make dtbs

“make all”命令是编译 Linux 源码中的所有东西,包括 zImage, .ko 驱动模块以及设备树,如果只是编译设备树的话建议使用“make dtbs”命令。

基于 ARM 架构的 SOC 有很多种,一种 SOC 又可以制作出很多款板子,每个板子都有一个对应的 DTS 文件,那么如何确定编译哪一个 DTS 文件呢?以 I.MX6ULL 这款芯片对应的板子为例来看一下,打开 arch/arm/boot/dts/Makefile,有如下内容:

dtb-$(CONFIG_SOC_IMX6UL) += \
	imx6ul-14x14-ddr3-arm2.dtb \
	imx6ul-14x14-ddr3-arm2-emmc.dtb	\
...
dtb-$(CONFIG_SOC_IMX6ULL) += \
...
	imx6ull-14x14-nand-4.3-480x272-c.dtb \
	imx6ull-14x14-nand-vga.dtb \
	imx6ull-14x14-nand-hdmi.dtb \
	imx6ull-alientek-emmc.dtb \
	imx6ull-alientek-nand.dtb \
	imx6ull-14x14-evk-usb-certi.dtb \
	imx6ull-9x9-evk.dtb \
...
dtb-$(CONFIG_SOC_IMX6SLL) += \
	imx6sll-lpddr2-arm2.dtb \
	imx6sll-lpddr3-arm2.dtb \
...

当选 中 I.MX6ULL 这个 SOC 以后(CONFIG_SOC_IMX6ULL=y),所有使用到I.MX6ULL 这个 SOC 的板子对应的.dts 文件都会被编译为.dtb。如果我们使用 I.MX6ULL 新做了一个板子,只需要新建一个此板子对应的.dts 文件,然后将对应的.dtb 文件名添加到 dtb-
$(CONFIG_SOC_IMX6ULL)下,这样在编译设备树的时候就会将对应的.dts 编译为二进制的.dtb文件。

3 DTS 语法

3.1 dtsi 头文件

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

#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"

在.dts 设备树文件中,可以通过“#include”来引用.h、 .dtsi 和.dts 文件。

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

#include <dt-bindings/clock/imx6ul-clock.h>
#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;
		can1 = &flexcan2;
......
	};

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

		cpu0: cpu@0 {
			compatible = "arm,cortex-a7";
			device_type = "cpu";
......
		};
	};

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

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

		ckil: clock@0 {
			compatible = "fixed-clock";
			reg = <0>;
			#clock-cells = <0>;
			clock-frequency = <32768>;
			clock-output-names = "ckil";
		};
......
	};

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

		busfreq {
			compatible = "fsl,imx_busfreq";
......
		};

		pmu {
			compatible = "arm,cortex-a7-pmu";
			interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
			status = "disabled";
		};

cpu0 这个设备节点信息,这个节点信息描述了I.MX6ULL 这颗 SOC 所使用的 CPU 信息,比如架构是 cortex-A7,频率支持 996MHz、 792MHz、528MHz、396MHz 和 198MHz 等等。在 imx6ull.dtsi 文件中不仅仅描述了 cpu0 这一个节点信息,I.MX6ULL 这颗 SOC 所有的外设都描述的清清楚楚,比如 ecspi1~4、 uart1~8、 usbphy1~2、 i2c1~4等等

3.2 设备节点

设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键—值对。以下是从imx6ull.dtsi 文件中缩减出来的设备树文件内容:

/ {
	aliases {
		can0 = &flexcan1;
	};

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

		cpu0: cpu@0 {
			compatible = "arm,cortex-a7";
			device_type = "cpu";
			reg = <0>;
		};
	};

	intc: interrupt-controller@00a01000 {
		compatible = "arm,cortex-a7-gic";
		#interrupt-cells = <3>;
		interrupt-controller;
		reg = <0x00a01000 0x1000>,
		      <0x00a02000 0x100>;
	};
}
  • 第 1 行,“/”是根节点,每个设备树文件只有一个根节点。imx6ull.dtsi和 imx6ull-alientek-emmc.dts 这两个文件都有一个“/”根节点,这两个“/”根节点的内容会合并成一个根节点。

  • 第 2、 6 和 17 行, aliases、 cpus 和 intc 是三个子节点,在设备树中节点命名格式如下:

node-name@unit-address

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

另外的命名方式,节点命名却如下所示:

cpu0:cpu@0

上述命令并不是“node-name@unit-address”这样的格式,而是用“:”隔开成了两部分,“:”前面的是节点标签(label),“:”后面的才是节点名字,格式如下所示:

label: node-name@unit-address

引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过&cpu0 就可以访问“cpu@0”这个节点,而不需要输入完整的节点名字。 再比如节点 “intc:interrupt-controller@00a01000”,节点 label 是 intc,而节点名字就很长了,为“ interruptcontroller@00a01000”。很明显通过&intc 来访问“interrupt-controller@00a01000”这个节点要方便很多

  • **第 10 行, cpu0 也是一个节点,只是 cpu0 是 cpus 的子节点。 **

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

①、字符串

compatible = "arm,cortex-a7";

上述代码设置 compatible 属性的值为字符串“arm,cortex-a7”

②、 32 位无符号整数

reg = <0>;

上述代码设置 reg 属性的值为 0, reg 的值也可以设置为一组值,比如:

reg = <0 0x123456 100>;

③、字符串列表
属性值也可以为字符串列表,字符串和字符串之间采用“,”隔开,如下所示:

compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";

上述代码设置属性 compatible 的值为“fsl,imx6ull-gpmi-nand”和“fsl, imx6ul-gpmi-nand”。

3.3 标准属性

节点是由一堆的属性组成,节点都是具体的设备,不同的设备需要的属性不同,用户可以自定义属性。除了用户自定义属性,有很多属性是标准属性, Linux 下的很多外设驱动都会使用这些标准属性,本节我们就来学习一下几个常用的标准属性。

1、compatible 属性

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

"manufacturer,model"
  • 其中 manufacturer 表示厂商, model 一般是模块对应的驱动名字

  • 比如 imx6ull-alientekemmc.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”和“fsl,imx-audio-wm8960”,其中“fsl”表示厂商是飞思卡尔,“imx6ul-evk-wm8960”和“imx-audio-wm8960”表示驱动模块名字。

sound这个设备首先使用第一个兼容值在 Linux 内核里面查找,看看能不能找到与之匹配的驱动文件,如果没有找到的话就使用第二个兼容值查。

一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。比如在文件 imx-wm8960.c 中有如下内容

tatic const struct of_device_id imx_wm8960_dt_ids[] = {
	{ .compatible = "fsl,imx-audio-wm8960", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_wm8960_dt_ids);

static struct platform_driver imx_wm8960_driver = {
	.driver = {
		.name = "imx-wm8960",
		.pm = &snd_soc_pm_ops,
		.of_match_table = imx_wm8960_dt_ids,
	},
	.probe = imx_wm8960_probe,
	.remove = imx_wm8960_remove,
};

数组 imx_wm8960_dt_ids 就是 imx-wm8960.c 这个驱动文件的匹配表,此匹配表只有一个匹配值“fsl,imx-audio-wm8960”。如果在设备树中有哪个节点的 compatible 属性值与此相等,那么这个节点就会使用此驱动文件。

wm8960 采用了 platform_driver 驱动模式。此行设置.of_match_table 为 imx_wm8960_dt_ids,也就是设置这个 platform_driver 所使用的OF 匹配表。

2、model 属性

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

model = "wm8960-audio";

3、status 属性

status 属性是和设备状态有关的, status 属性值也是字符串,字符串是设备的状态信息,可选的状态如表

描述
“okay”表明设备是可操作的。
“disabled”表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备 插入以后。至于 disabled 的具体含义还要看设备的绑定文档。
“fail”表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可 操作。
“fail-sss”含义和“fail”相同,后面的 sss 部分是检测到的错误内容。

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

这两个属性的值都是无符号 32 位整形, #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 这个数据所占用的字长,比如:

spi4 {
    compatible = "spi-gpio";
    #address-cells = <1>;
    #size-cells = <0>;

    gpio_spi: gpio_spi@0 {
        compatible = "fairchild,74hc595";
        reg = <0>;
    };
};

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>;
    };
};
  • 第 3, 4 行,节点 spi4 的**#address-cells = <1>, #size-cells = <0>**,说明 spi4 的子节点 reg 属性中起始地址所占用的字长为 1,地址长度所占用的字长为 0。

  • 第 8 行,子节点 gpio_spi: gpio_spi@0 的 reg 属性值为 <0>,因为父节点设置了#addresscells = <1>, #size-cells = <0>,因此 addres=0,没有 length 的值,相当于设置了起始地址,而没有设置地址长度。

  • 第 14, 15 行,设置 aips3: aips-bus@02200000 节点#address-cells = <1>, #size-cells = <1>,说明 aips3: aips-bus@02200000 节点起始地址长度所占用的字长为 1,地址长度所占用的字长也为 1。

  • 第 19 行,子节点 dcp: dcp@02280000 的 reg 属性值为<0x02280000 0x4000>,因为父节点设置了#address-cells = <1>, #size-cells = <1>, address= 0x02280000, length= 0x4000,相当于设置了起始地址为 0x02280000,地址长度为 0x40000。

5、reg 属性

reg 属性的值一般是(address, length)对。 **reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息,**比如在 imx6ull.dtsi 中有如下内容:

uart1: serial@02020000 {
    compatible = "fsl,imx6ul-uart",
    	"fsl,imx6q-uart", "fsl,imx21-uart";
    reg = <0x02020000 0x4000>;
    interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clks IMX6UL_CLK_UART1_IPG>,
    	<&clks IMX6UL_CLK_UART1_SERIAL>;
    clock-names = "ipg", "per";
    status = "disabled";
};

上述代码是节点 uart1, uart1 节点描述了 I.MX6ULL 的 UART1 相关信息。其中 uart1 的父节点 aips1: aips-bus@02000000 设置了#address-cells = <1>、 #sizecells = <1>,因此 reg 属性中address=0x02020000, length=0x4000。

查阅《I.MX6ULL 参考手册》可知, I.MX6ULL 的 UART1 寄存器首地址为 0x02020000,但是 UART1 的地址长度(范围)并没有 0x4000 这么多,这里我们重点是获取 UART1 寄存器首地址。

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 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换 。

7、name 属性

name 属性值为字符串, name 属性用于记录节点名字, name 属性已经被弃用,不推荐使用name 属性,一些老的设备树文件可能会使用此属性。

8、device_type 属性

device_type 属性值为字符串,此属性只能用于 cpu 节点或者 memory 节点。imx6ull.dtsi 的 cpu0 节点用到了此属性,内容如下所示:

cpu0: cpu@0 {
    compatible = "arm,cortex-a7";
    device_type = "cpu";
    reg = <0>;

4 向节点追加或修改内容

产品开发过程中可能面临着频繁的需求更改,比如第一版硬件上有一个 IIC 接口的六轴芯片 MPU6050,第二版硬件又要把这个 MPU6050 更换为 MPU9250 等。一旦硬件修改了,就要同步的修改设备树文件,毕竟设备树是描述板子硬件信息的文件。

假设现在有个六轴芯片fxls8471, fxls8471 要接到 I.MX6U-ALPHA 开发板的 I2C1 接口上,那么相当于需要在 i2c1 这个节点上添加一个 fxls8471 子节点。先看一下 I2C1 接口对应的节点,打开文件 imx6ull.dtsi 文件,找到如下所示内容:

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: 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";
    
    //fxls8471 子节点
	fxls8471@1e {
        compatible = "fsl,fxls8471";
        reg = <0x1e>;
	};
};

但是这样会有个问题! i2c1 节点是定义在 imx6ull.dtsi 文件中的,而 imx6ull.dtsi 是设备树头文件,其他所有使用到 I.MX6ULL这颗 SOC 的板子都会引用 imx6ull.dtsi 这个文件。直接在 i2c1 节点中添加 fxls8471 就相当于在其他的所有板子上都添加了 fxls8471 这个设备,样写肯定是不行的。

I.MX6U-ALPHA 开发板使用的设备树文件为 imx6ull-alientek-emmc.dts,因此我们需要在imx6ull-alientek-emmc.dts 文件中完成数据追加的内容,方式如下:

&i2c1 {
	/* 要追加或修改的内容 */
};

&i2c1 表示要访问 i2c1 这个 label 所对应的节点,也就是 imx6ull.dtsi 中的“i2c1:i2c@021a0000”。

**花括号内就是要向 i2c1 这个节点添加的内容,包括修改某些属性的值。**打开 imx6ull-alientek-emmc.dts,找到如下所示内容:

&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";

	mag3110@0e {
		compatible = "fsl,mag3110";
		reg = <0x0e>;
		position = <2>;
	};

	fxls8471@1e {
		compatible = "fsl,fxls8471";
        reg = <0x1e>;
        position = <0>;
        interrupt-parent = <&gpio5>;
        interrupts = <0 8>;
    };
};
  • 属性“clock-frequency”就表示 i2c1 时钟为 100KHz。“clock-frequency”就是新添加的属性。

  • 将 status 属性的值由原来的 disabled 改为 okay。

  • i2c1 子节点 mag3110,

  • i2c1 子节点 fxls8471

这个就是向节点追加或修改内容,重点就是通过&label 来访问节点,然后直接在里面编写要追加或者修改的内容。

5 设备树在系统中的体现

Linux 内核启动的时候会解析设备树中各个节点的信息,并且在根文件系统的/proc/devicetree 目录下根据节点名字创建不同文件夹
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rV4rycaj-1681394085909)(pic/4-2 根节点的属性以及子节点.png)]

目录/proc/device-tree 目录下的内容, /proc/device-tree 目录下是根节点“/”的所有属性和子节点

1、根节点“/”各个属性

根节点属性属性表现为一个个的文件,比如图 中“#address-cells”、“#size-cells”、“compatible”、“model”和“name”这 5 个文件,它们在设备树中就是根节点的 5个属性。既然是文件那么肯定可以查看其内容,输入 cat 命令来查看 model和 compatible 这两个文件的内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cNmLqLoJ-1681394085909)(pic/4-3 model 和 compatible 文件内容.png)]

2、根节点“/”各子节点

各个文件夹就是根节点“/”的各个子节点,比如“aliases”、“ backlight”、“ chosen”和“ clocks”等等

/proc/device-tree 目录就是设备树在根文件系统中的体现,同入/proc/device-tree/soc 目录中就可以看到 soc 节点的所有子节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DOzTD5cT-1681394085910)(pic/4-4 soc 节点的所有属性和子节点.png)]

和根节点“/”一样,图中的所有文件分别为 soc 节点的属性文件和子节点文件夹。查看一下这些属性文件的内容是否和 imx6ull.dtsi 中 soc 节点的属性值相同,也可以进入“busfreq”这样的文件夹里面查看 soc 节点的子节点信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/421521.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FreeRTOS 任务切换

文章目录一、PendSV 异常二、FreeRTOS 任务切换场合1. 执行系统调用 taskYIELD()2. 系统滴答定时器(SysTick)中断 SysTick_Handler三、PendSV 中断服务函数 PendSV_Handler()四、查找下一个要运行的任务 vTaskSwitchContext()五、FreeRTOS 时间片调度六、时间片调度实验RTOS 系…

ECF机制:信号 (Signal)

&#x1f4ad; 写在前面&#xff1a;ECF (异常控制流) 机制是存在于系统的所有层级中的&#xff0c;所以这一块的知识我们需要系统地去学习。前几章我们探讨过了异常 (Exceptions)&#xff0c;由硬件触发&#xff0c;在内核代码中处理。讲解了进程的上下文切换 (Process Contex…

Shiro整合SpringBoot项目实战

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

阿里入局,通义千问备受期待

目录官宣内测体验内容鸟鸟分鸟后言继百度文心一言发布三周之后&#xff0c;4月7日阿里通义大模型终于推出通义千问&#xff0c;阿里正式加入ChatGPT战局。下午市场一片大热&#xff0c;对于深耕NLP多年的阿里&#xff0c;大家有足够的期待。 官宣内测 “你好&#xff0c;我叫通…

【SpringBoot】springboot启动热部署

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ SpringBoot——手工启动热部署一、pom.xml导入…

Kotlin 是后端开发的未来

Kotlin 是后端开发的未来 严格类型、命名参数、多范式语言 您今天遇到的每个后端开发人员都会说他们使用 JavaScript、Python、PHP 或 Ruby 编写代码。近年来&#xff0c;您会遇到一小部分人转而使用 Kotlin 作为他们创建 Web 服务器的语言选择。由于我在学习Ktor&#xff0c;所…

深度学习12. CNN经典网络 VGG16

深度学习12. CNN经典网络 VGG16一、简介1. VGG 来源2. VGG分类3. 不同模型的参数数量4. 3x3卷积核的好处5. 关于学习率调度6. 批归一化二、VGG16层分析1. 层划分2. 参数展开过程图解3. 参数传递示例4. VGG 16各层参数数量三、代码分析1. VGG16模型定义2. 训练3. 测试一、简介 …

Html5版音乐游戏制作及分享(H5音乐游戏)

这里实现了Html5版的音乐游戏的核心玩法。 游戏的制作借鉴了&#xff0c;很多经典的音乐游戏玩法&#xff0c;通过简单的代码将音乐的节奏与操作相结合。 可以通过手机进行游戏&#xff0c;准确点击下落时的目标&#xff0c;进行得分。 点击试玩 游戏内的下落数据是通过手打记…

【Pytorch】使用pytorch进行张量计算、自动求导和神经网络构建

本文参加新星计划人工智能(Pytorch)赛道&#xff1a;https://bbs.csdn.net/topics/613989052 这是目录张量计算张量的属性和方法&#xff0c;如何使用它们来获取或修改张量的信息和形状张量之间的运算和广播机制&#xff0c;如何使用torch.add(), torch.sub(), torch.mul(), to…

【Redis7】Redis7 持久化(重点:RDB与AOF重写机制)

【大家好&#xff0c;我是爱干饭的猿&#xff0c;本文重点介绍Redis7 持久化&#xff08;重点&#xff1a;RDB与AOF重写机制&#xff09;。 后续会继续分享Redis7和其他重要知识点总结&#xff0c;如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下吧】 …

Java项目实战笔记(瑞吉外卖)-4

公共字段自动填充功能 问题分析 前面已经完成了后台系统的员工管理功能开发&#xff0c;在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段&#xff0c;在编辑员工时需要设置修改时间和修改人等字段。这些字段属于公共字段&#xff0c;也就是很多表中都有这些字段…

前端搭建小人逃脱游戏(内附源码)

The sand accumulates to form a pagoda✨ 写在前面✨ 功能介绍✨ 页面搭建✨ 样式设置✨ 逻辑部分✨ 写在前面 上周我们实通过前端基础实现了打字通&#xff0c;当然很多伙伴再评论区提出了想法&#xff0c;后续我们会考虑实现的&#xff0c;今天还是继续按照我们原定的节奏来…

对决:Kubernetes vs Docker Swarm - 谁才是最优秀的容器编排方案?

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 文章目录一、介绍1. 什么是Kubernetes2. 什么是Docker Swarm3. 为什么需要容器编排&#xff1f;二、 架构比较1. Kubern…

Spring框架——IOC、DI

本篇博客主要介绍Java中的IOC和DI&#xff0c;以及在String框架中的应用。首先&#xff0c;我们将对IOC和DI进行概念介绍&#xff0c;然后讲解它们的关系及在String框架中的应用&#xff0c;最后通过一个实例来展示它们的具体用法。 IOC和DI的概念介绍 IOC&#xff08;Invers…

热更新方案 HybridCLR 学习教程 |(一)原理及准备工作

文章目录 热更新方案 HybridCLR 学习教程(一)HybridCLR原理及准备工作前言一、学前准备1.1 资源下载1.2 文档参考学习二、关于HybridCLR2.1 HybridCLR特性:2.2 HybridCLR工作原理2.3 与其他流行的c#热更新方案的区别2.4 兼容性2.5 原理流程介绍三、快速上手(重要)3.1 体验…

Linux下实现的 HTTP 服务器

项目功能&#xff1a;&#xff08;1&#xff09;能接收客户端的GET请求&#xff1b;&#xff08;2&#xff09;能够解析客户端的请求报文&#xff0c;根据客户端要求找到相应的资源&#xff1b;&#xff08;2&#xff09;能够回复http应答报文&#xff1b;&#xff08;3&#x…

MySQL实验四:数据更新

MySQL实验四&#xff1a;数据更新 目录MySQL实验四&#xff1a;数据更新导读表结构sql建表语句模型图1、 SQL更新&#xff1a;将所有学生的年龄增加1岁代码2、SQL更新&#xff1a;修改“高等数学”课程倒数三名成绩&#xff0c;在原来分数上减5分代码解析3、SQl更新&#xff1a…

docker详解

一、docker相关命令 1、docker进程相关命令 启动docker服务&#xff1a;systemctl start docker 停止docker服务&#xff1a;systemctl stop docker 重启docker服务&#xff1a;systemctl restart docker 查看docker服务状态&#xff1a;systemctl status docker 设置…

可变形卷积(Deformable Conv)原理解析与torch代码实现

1. 可变形卷积原理解析 1.1 普通卷积原理 传统的卷积操作是将特征图分成一个个与卷积核大小相同的部分&#xff0c;然后进行卷积操作&#xff0c;每部分在特征图上的位置都是固定的。 图1 普通卷积过程 图1所示为普通卷积在输入特征图上进行卷积计算的过程&#xff0c;卷积核…

4.3-4.4学习总结

文章目录 目录 文章目录 1.集合的概念 2.Set集合 1.HashSet类 2.LinkedHashSet类 3.TreeSet类 4.EnumSet类 一、Java集合 1.集合的概念 Java集合类是一种特别有用的工具类 , 可用于存贮数量不等的对象 , 并可以实现经常用的数据结构 , 同时集合还可用于保存具有映射关系的关…