Zephyr镜像存储区域配置-基于RT1062的实例

Creative Commons
本作品采用知识共享署名

本文举例说明如何配置Zephyr可执行程序中代码和数据的存储区域。

一般情况下嵌入式程序在执行的时候存储区域可以分为下面三类:

  • 代码区/RODATA: 存放程序指令和常量,只读
  • 数据区:存放程序变量,读写
  • 堆/栈区:堆和栈使用,读写

对于嵌入式设备的应用镜像,常见的有如下几种运行方式:

  • 单一应用镜像Flash上XIP运行
    • 代码区/RODATA: 放在Flash
    • 数据区/堆/栈区 放在RAM或SDRAM
  • bootloader+应用镜像Flash XIP运行
    • 代码区/RODATA: 放在Flash
    • 数据区/堆/栈区 放在RAM或SDRAM
  • bootloader+应用镜像内存运行
    • 代码区/RODATA: 放在RAM或SDRAM
    • 数据区/堆/栈区 放在RAM或SDRAM

这些不同的运行方式要求应用镜像对应的存储区域和存储地址不一样,Zephyr可以通过其灵活的配置选项简单的完成这些工作。本文以mm_feather为基础说明如何配置zephyr执行时的存储区域。

RT1062 存储区域

一般的嵌入式SOC上都有一段只读的boot rom,当中可以包含各种boot启动方式, RT1062提供了如下启动方式:

  • Serial NOR Flash via FlexSPI
  • Serial NAND Flash via FlexSPI
  • Parallel NOR Flash via SEMC
  • RAWNAND Flash via SEMC
  • SD/MMC via uSDHC
  • SPI NOR/EEPROM via LPSPI

本文的硬件&Fuse设计配置选择RT1062从Serial NOR Flash via FlexSPI启动,启动概况如下:

  • SOC上电后,内部boot rom以较低的速度初始化QSPI接口
  • boot rom从SPI NOR Flash上读出header信息, header里面包含QSPI NOR Flash配置信息,外部SDRAM配置信息,image加载信息
  • 配置QSPI NOR Flash和SDRAM
  • 加载image并跳转运行

mm_feather使用的是RT1062配置,搭配片内外存储映射如下:
QSPI NOR Flash(片外): 0x60000000 8M
SEMC SDRAM(片外): 0x80000000 32M
ITCM(片内):0x00000000 128K
DTCM(片内): 0x20000000 128k
OCRAM(片内): 0x20200000 768K

单一应用镜像XIP运行

存储区分配:

  • 应用镜像存储在Flash的0处
  • 在Flash上执行
  • RAM使用SDRAM

配置文件指定XIP

1
CONFIG_XIP=y

由于board/arm/mm_feather/kcofig.defconfig已经默认选择了CODE_FLEXSPI,因此无需另做配置代码区会被放到FLEXSPI

设备树添加flash和sdram的节点,指定zephyr,sramsdram0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/ {
chosen {
zephyr,sram = &sdram0;
};

sdram0: memory@80000000 {
/* Micron MT48LC16M16A2B4-6AIT:G */
device_type = "memory";
reg = <0x80000000 DT_SIZE_M(32)>;
};
}

&flexspi {
reg = <0x402a8000 0x4000>, <0x60000000 DT_SIZE_M(8)>;
is25wp064: is25wp064@0 {
compatible = "nxp,imx-flexspi-nor";
size = <67108864>;
label = "IS25WP064";
reg = <0>;
spi-max-frequency = <133000000>;
status = "okay";
jedec-id = [9d 70 17];
};
};

编译好的镜像内代码段的符号被定址到以0x60000000开始的位置,数据段的符号被定址到以0x80000000开始的位置
编译完成zephyr的应用镜像烧写在Flash的0地址处,SOC上电后会读取0x60000000处header(Flash的0地址处)配置SPI NOR Flash和SDRAM,之后从header之后的偏移处的向量表中读出MSP和reset并跳转到reset处执行

bootloader+应用镜像XIP运行

存储区分配:

  • bootloader存储在Flash的0处
  • 应用镜像存储在Flash的0x40000处
  • 在Flash上执行
  • RAM使用OCRAM

配置文件指定XIP,指定使用Flash上的partition
由于bootloader会初始化SPI Flash和SDRAM,因此生成的应用镜像不需要加header,所以配置CONFIG_NXP_IMX_RT_BOOT_HEADER=n

1
2
3
CONFIG_XIP=y
CONFIG_USE_DT_CODE_PARTITION=y
CONFIG_NXP_IMX_RT_BOOT_HEADER=n

设备树添加sdram的节点,指定zephyr,sramocram
设备树添加flash的节点,并划分分区,指定使用app_partition为代码区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/ {
chosen {
zephyr,flash-controller = &flexspi;
zephyr,flash = &is25wp064;
zephyr,code-partition = &app_partition;
zephyr,sram = &ocram;
};
}

&flexspi {
reg = <0x402a8000 0x4000>, <0x60000000 DT_SIZE_M(8)>;
is25wp064: is25wp064@0 {
compatible = "nxp,imx-flexspi-nor";
size = <67108864>;
label = "IS25WP064";
reg = <0>;
spi-max-frequency = <133000000>;
status = "okay";
jedec-id = [9d 70 17];

partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;

boot_partition: partition@0 {
label = "bootloader";
reg = <0x00000000 DT_SIZE_K(128)>;
};

swift_partition: partition@40000 {
label = "switf-app";
reg = <0x00040000 DT_SIZE_M(6)>;
};
};
};
};

编译好的镜像内代码段的符号被定址到以0x60040000开始的位置,数据段的符号被定址到以0x20200000开始的位置
编译完成zephyr的应用镜像烧写在Flash的0x40000地址处,SOC上电后先执行FLash 0地址处bootloader对SPI NOR Flash和SDRAM初始化,bootloader从0x60040000(Flash的0x40000)的向量表中读出MSP和reset并跳转到reset处执行。

bootloader+应用镜像内存运行

存储分配1

  • bootloader存储在Flash的0处
  • 应用镜像存储在Flash的0x20000处
  • 在ITCM上执行
  • RAM使用DTCM

在ITCM上执行,但数据段是在DTCM中,需要搬运,这也是一种XIP形式,因此要配置XIP,同时配置CODE_ITCM

1
2
CONFIG_XIP=y
CONFIG_CODE_ITCM=y

设备树只需要指定sram使用dtcm即可

1
2
3
4
5
/ {
chosen {
zephyr,sram = &dtcm;
};
};

编译好的镜像内代码段的符号被定址到以0x00000000开始的位置,数据段的符号被定址到以0x20000000开始的位置
编译完成zephyr的应用镜像烧写在Flash的0x20000地址处,SOC上电后先执行FLash 0地址处bootloader对SPI NOR Flash和SDRAM初始化,bootloader将0x6002000处应用镜像(Flash中0x20000处)拷贝到0x00000000(ITCM中),从0x00000000的向量表中读出MSP和reset并跳转到reset处执行。

存储分配2

  • bootloader存储在Flash的0处
  • 应用镜像存储在SD卡上
  • 应用镜像在SDRAM上执行
  • RAM使用SDRAM

在SDRAM上执行,配置非XIP执行,通过CODE_SEMC指定在外部SDRAM上

1
2
CONFIG_XIP=n
CONFIG_CODE_SEMC=y

设备树添加sdram节点,并指定zephyr,sram使用sdram

1
2
3
4
5
6
7
8
9
10
11
/ {
chosen {
zephyr,sram = &sdram0;
};

sdram0: memory@80000000 {
/* Micron MT48LC16M16A2B4-6AIT:G */
device_type = "memory";
reg = <0x80000000 DT_SIZE_M(32)>;
};
}

编译好的镜像内代码段和数据段的符号均被定址到以0x80000000开始的位置
编译完成zephyr的应用镜像被放到SD卡内,SOC上电后先执行FLash 0地址处bootloader对SPI NOR Flash和SDRAM初始化,在初始化SD后bootloader从SD卡内读出应用镜像放到0x8000000处,从0x80000000的中断向量表中读出MSP和reset并跳转到reset处执行。

最后

以上是几种常见的分配配置方式,根据实际的硬件和应用情况需要来指定不同的存储方式,在zephyr下都可以方便使用配置文件和DTS来完成。