Zephyr 快速入门
DTS 快速入门
DTS 详细介绍请参考 DTS 介绍
DTS 语法和使用简介
修改 DTS 配置
Zephyr 中 DTS 是分散在多个文件中的,详见 Zephyr 中 DTS 组织,修改 DTS 时修改哪个文件要视情况而定
到对应 test/sample 源码目录下(test 通常是
zephyr/tests/*/boards,sample 通常是zephyr/samples/*/boards)新增对应 board 的 overlay 文件(如果尚不存在)并进行修改如下 overlay 例子是增加一个 led 节点,设置相关 gpio 口,并为该节点取别名
led0:
/ {
aliases {
led0 = &led_0;
};
gpio-led {
compatible = "gpio-leds";
led_0: led_0 {
gpios = <&gpioa 25 0>;
};
};
};
如下例子是修改已有 DTS 中的配置(将
status改为okay)
&gpioa {
status = "okay";
};
在对应 board 级 dts 目录新增 overlay 文件,文件命名规则:
<origin_board_dts_basename>_<revision>.overlay,其中revision支持多种形式修改同目录下的
revision.cmake(如果没有则创建),通过DEFAULT_REVISION参数指定对应 overlay 文件
board_check_revision(
FORMAT LETTER
DEFAULT_REVISION D # <revision> is D
)
board_check_revision(
FORMAT MAJOR.MINOR.PATCH
DEFAULT_REVISION 2.0.0 # <revision> is 2.0.0
)
board_check_revision(
FORMAT NUMBER
DEFAULT_REVISION 2 # <revision> is 2
)
如何确认 DTS 最终配置是否正确
Zephyr DTS 因为涉及多个文件,同一个配置项可能会被多处设置或重置,所以直接看某个文件不能反映最终的结果,需要:
检查修改(overlay)是否生效
检查某个设备的状态(
okay或disabled)或属性设置是否符合预期
此时可以查看 build/zephyr/zephyr.dts 文件,它是最终生成的 DTS 文件
如何查看某个设备的 binding 文件
binding 文件介绍请参考 DTS binding
到定义设备的 dts 中找到其 compatible 字段,如:
compatible = "realtek,ameba-rcc";查找名为
realtek,ameba-rcc.yaml文件,确认其中compatible值为"realtek,ameba-rcc",则该文件为对应 binding 文件
注意
只有当 binding 文件的命名遵循了与 compatible 字段相同的规则时,才能使用该方法;但此规则在 Zephyr 中并非强制,若命名不一致,需要通过方法 2
定位到
devicetree_generated.h文件,在文件开头位置找到所需设备完整节点名称,如/soc/gpio@41010000
* Node dependency ordering (ordinal and path):
* 0 /
* 1 /aliases
* 2 /chosen
* 3 /soc
* 4 /soc/interrupt-controller@e000e100
* 5 /soc/gpio@41010000
* 6 /buttons
* 7 /buttons/button_0
* 8 /clocks
* 9 /clocks/clk_sys
* 10 /cpus
继续在文件中检索
Devicetree node: /soc/gpio@41010000,找到如下位置:
/*
* Devicetree node: /soc/gpio@41010000
*
* Node identifier: DT_N_S_soc_S_gpio_41010000
*
* Binding (compatible = realtek,ameba-gpio):
* $ZEPHYR_BASE/dts/bindings/gpio/realtek,ameba-gpio.yaml
*
* (Descriptions have moved to the Devicetree Bindings Index
* in the documentation.)
*/
第 7 行就是该设备所用的 binding 文件的完整路径
在代码中如何访问 DTS
访问 DTS 通常是为了获取某个节点的属性或者驱动,可以参照如下步骤:
假如有 DTS 内容如下:
/ {
soc {
serial0: serial@40002000 {
reg = <0x40002000 0x100>;
status = "okay";
current-speed = <115200>;
/* ... */
};
};
aliases {
my-serial = &serial0;
};
chosen {
zephyr,console = &serial0;
};
};
首先获取某个节点标识符。DTS 中有多种方法标识一个节点,所以也对应多种方法获取节点标识符:
/* Option 1: by node label */
#define MY_SERIAL DT_NODELABEL(serial0)
/* Option 2: by alias */
#define MY_SERIAL DT_ALIAS(my_serial)
/* Option 3: by chosen node */
#define MY_SERIAL DT_CHOSEN(zephyr_console)
/* Option 4: by path */
#define MY_SERIAL DT_PATH(soc, serial_40002000)
上述代码中宏
MY_SERIAL即表示节点标识符,利用它可以进一步得到节点属性或驱动
/* Demo 1: conditional compilation based on node status */
#if DT_NODE_HAS_STATUS(MY_SERIAL, okay)
//Desired code when node is okay(enabled)
#endif
/* Demo 2: get normal property */
uint32_t speed = DT_PROP(MY_SERIAL, current_speed); //=115200
/* NOTE: some properties have an exclusive macro */
/* Demo 3: get reg info */
uint32_t addr = DT_REG_ADDR(MY_SERIAL); //=0x40002000
uint32_t size = DT_REG_SIZE(MY_SERIAL); //=0x100
const struct device *const dev = DEVICE_DT_GET(MY_SERIAL);
if (!device_is_ready(dev)) {
/* Not ready, do not use */
return -ENODEV;
}
uart_poll_out(dev, 'a');
更多进阶用法参考 扩展阅读
在 Kconfig 中如何访问 DTS
参考:Kconfig 快速入门
在 CMake 中如何访问 DTS
参考:CMake 快速入门
如何定位 undefined reference 的 DTS 符号问题
DTS 中定义的节点会在驱动代码中被定义为某个符号,其标识符是按照某些编码规范生成,如
__device_dts_ord_22实际使用中可能会遇到类似如下的编译错误:
/opt/rtk-toolchain/asdk-12.3.1-4431/linux/newlib/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld.bfd: app/libapp.a(test_counter.c.obj):(.rodata.devices+0x0): undefined reference to `__device_dts_ord_22'
出现该问题的原因通常是驱动层之上的代码引用了一个符号(驱动实例),但链接时没有找到该驱动实例的符号定义(代码实现)
这里无法直接通过名字
__device_dts_ord_22定位到相关的代码区域,下面给出一个针对上述错误的排查流程
首先定位出问题的 DTS 节点:通过
test_counter.c.obj可以确定引用该符号的源文件是test_counter.c,此时可以选择直接查看该文件,分如下两种情况:如果只有一个驱动实例引用,就可以通过代码确定对应的 DTS 节点信息(节点名称,label 等),例如可能有如下代码:
#define I2C_DEV_NODE DT_ALIAS(i2c_0) const struct device *const i2c_dev = DEVICE_DT_GET(I2C_DEV_NODE);
此时可以很容易判断是
i2c_0这个 DTS 节点对应设备的驱动定义有问题如果代码复杂,有多个驱动实例引用或复杂的预处理逻辑,则可以通过生成预处理文件直接精确定位 DTS 节点,步骤如下
在文件
build/compile_commands.json中查找test_counter.c.obj,可以定位到如下一个位置(其中 xxx 表示被省略的部分内容):{ "directory": "/xxx/build", "command": "/xxx/arm-none-eabi-gcc xxx -o CMakeFiles/app.dir/src/test_counter.c.obj -c /xxx/zephyr/tests/drivers/counter/counter_basic_api/src/test_counter.c", "file": "/xxx/zephyr/tests/drivers/counter/counter_basic_api/src/test_counter.c", "output": "CMakeFiles/app.dir/src/test_counter.c.obj" },
其中
command字段是编译test_counter.c的完整命令,需要对完整的该命令稍作修改:-o后的输出路径改为新文件名(如 test_counter.i),-c改为-E,然后在终端执行:/xxx/arm-none-eabi-gcc xxx -o test_counter.i -E /xxx/zephyr/tests/drivers/counter/counter_basic_api/src/test_counter.c",
此时会在执行目录生成一个文件
test_counter.i,打开该文件搜索未定义符号__device_dts_ord_22可以找到如下内容:static const struct device *const devices[] = { # 63 "/xxx/zephyr/tests/drivers/counter/counter_basic_api/src/test_counter.c" # 124 "/xxx/zephyr/tests/drivers/counter/counter_basic_api/src/test_counter.c" (&__device_dts_ord_22), (&__device_dts_ord_23), (&__device_dts_ord_24), (&__device_dts_ord_25), # 144 "/xxx/zephyr/tests/drivers/counter/counter_basic_api/src/test_counter.c" };
通过上述第 4,5 行可知
__device_dts_ord_22是在源文件 124 行引用的,定位到该行代码如下:#ifdef CONFIG_COUNTER_TMR_AMEBA DEVS_FOR_DT_COMPAT(realtek_ameba_counter) #endif
由此可知是
compatible为realtek,ameba-counter的 DTS 节点对应设备的驱动定义有问题
排查 DTS 节点对应的驱动定义问题,可以参考以下思路:
DTS 节点不存在或未使能(
status未设置为okay),可以参考 如何确认 DTS 最终配置是否正确DTS 节点对应驱动代码未加入编译,这里要检查相关驱动的
CMakeLists.txt或 Kconfig 配置DTS 节点驱动代码中编码问题,例如
DT_DRV_COMPAT宏定义是否正确等
Kconfig 快速入门
在 Kconfig 中获取 DTS 信息
Zephyr 提供了一系列接口,用于在 Kconfig 中访问 DTS 信息,更多内容请参考 Devicetree-related Functions。
使用示例如下:
config AMEBA_PSRAM
def_bool y if $(dt_nodelabel_enabled,psram) # init bool value by node state
config AMEBA_PSRAM_SIZE
hex
depends on AMEBA_PSRAM
default $(dt_nodelabel_reg_size_hex,psram) # init hex value by node reg's size cell
对应的 DTS 配置如下:
psram: memory@60000000 {
compatible = "zephyr,memory-region";
device_type = "memory";
reg = <0x60000000 DT_SIZE_M(4)>; /* dt_nodelabel_reg_size_hex reads size from here */
zephyr,memory-region = "PSRAM";
status = "disabled"; /* dt_nodelabel_enabled reads status from here */
};
CMake 快速入门
在 CMake 中获取 DTS 信息
Zephyr 提供了一系列接口,用于在 CMake 中访问 DTS 信息,具体实现可参考 zephyr/cmake/modules/extensions.cmake。
常用 API 说明如下:
API |
Description |
|---|---|
|
Function for retrieving the node path for the node having nodelabel |
|
Get a node path for an /aliases node property |
|
Tests whether a node with path <path> exists in the devicetree |
|
Tests whether <path> refers to a node which exists in the devicetree, and has a status property matching the <status> argument |
|
Get a devicetree property value. The value will be returned in the <var> parameter |
|
Get a list of paths for the nodes with the given compatible. The value will be returned in the <var> parameter |
|
Get the number of register blocks in the node's reg property |
|
Get the base address of the register block at index <idx>, or with name <name> |
|
Get the size of the register block at index <idx>, or with name <name> |
|
Test if the devicetree's /chosen node has a given property <prop> which contains the path to a node |
|
Get a node path for a /chosen node property |
NVIC 快速入门
NVIC 详细介绍请参考 NVIC 介绍
Zephyr 中断使用说明
在 Zephyr 中开发驱动使用中断需要完成几个关键步骤,即可正常响应中断。
下面将给出一个使用示例,并列举其中的关键步骤。
代码示例
DTS 配置:
中断设备树配置示例1nvic: interrupt-controller@e000e100 { 2 #address-cells = < 0x1 >; 3 compatible = "arm,v8.1m-nvic"; 4 reg = < 0xe000e100 0xc00 >; 5 interrupt-controller; 6 #interrupt-cells = < 0x2 >; 7 arm,num-irq-priority-bits = < 0x3 >; 8 phandle = < 0x1 >; 9}; 10timer0: counter@40819000 { 11 compatible = "realtek,ameba-counter"; 12 reg = <0x40819000 0x30>; 13 clocks = <&rcc AMEBA_LTIM0_CLK>; 14 interrupts = <7 0>; 15 clock-frequency = <32768>; 16 status = "disabled"; 17};
C 代码实现:
中断驱动代码实现示例1#define DT_DRV_COMPAT realtek_ameba_counter 2... 3 4void counter_ameba_isr(const struct device *dev) 5{ 6} 7 8#define TIMER_IRQ_CONFIG(n) \ 9 static void irq_config_##n(const struct device *dev) \ 10 { \ 11 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), counter_ameba_isr, \ 12 DEVICE_DT_INST_GET(n), 0); \ 13 irq_enable(DT_INST_IRQN(n)); \ 14 } 15 16#define AMEBA_COUNTER_INIT(n) \ 17 TIMER_IRQ_CONFIG(n) \ 18 ... 19 20DT_INST_FOREACH_STATUS_OKAY(AMEBA_COUNTER_INIT);
关键步骤
确认硬件支持, DTS 中配置中断信息。
如上 中断设备树配置示例 中高亮行 14 行所示设置驱动的中断属性,
interrupts有两个入参,第一个是中断号,第二个是中断优先级。驱动代码中实现中断服务函数,注册中断时需要用到,如上 中断驱动代码实现示例 4-6 行。
驱动代码中从 DTS 获取中断优先级等属性,注册中断时需要用到,如上 中断驱动代码实现示例 11 行。 详细介绍请参考 获取中断属性。
/*获取中断号*/ DT_INST_IRQN(n); /*获取中断优先级*/ DT_INST_IRQ(n, priority);
驱动代码中注册中断,如上 中断驱动代码实现示例 11 行。 详细介绍请参考 中断注册。
驱动代码中启用中断,如上 中断驱动代码实现示例 13 行。 详细介绍请参考 启用/关闭中断。
文件系统 快速入门
文件系统详细介绍请参考 文件系统介绍
LittleFS on FLASH
示例路径: zephyr/samples/subsys/fs/littlefs/
使用以下命令编译 LittleFS on FLASH 示例(将 <BOARD> 替换为实际开发板名称):
./nuwa.py build zephyr/samples/subsys/fs/littlefs -b <BOARD>
如需自定义 DTS,请参考 LittleFS on FLASH 示例 进行配置。
可通过最终生成的 DTS 文件 build/zephyr/zephyr.dts 验证 DTS 配置是否正确:
spic 的 status = "okay"
LittleFS 使用的 partition 起始地址和大小符合预期
遇到链接错误时,通常是某些 Kconfig 选项未启用。
可通过 build/zephyr/include/generated/zephyr/autoconf.h 检查当前的 Kconfig 配置。
LittleFS on FLASH 需要在 prj.conf 中启用以下配置:
CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
FatFS on SD
示例路径: zephyr/samples/subsys/fs/fs_sample/
使用以下命令编译 FatFS on SD 示例(将 <BOARD> 替换为实际开发板名称):
./nuwa.py build zephyr/samples/subsys/fs/fs_sample -b <BOARD>
遇到链接错误时,通常是某些 Kconfig 选项未启用。
可通过 build/zephyr/include/generated/zephyr/autoconf.h 检查当前的 Kconfig 配置。
FatFS on SD 需要在 prj.conf 中启用以下配置:
CONFIG_FILE_SYSTEM=y
CONFIG_FAT_FILESYSTEM_ELM=y
CONFIG_DISK_ACCESS=y
CONFIG_DISK_DRIVERS=y
Settings 快速入门
Settings 详细介绍请参考 Settings 介绍
示例路径: zephyr/samples/subsys/settings/
使用以下命令编译 Settings 示例:
./nuwa.py build zephyr/samples/subsys/settings -b <BOARD>
可参考 Settings 配置 配置 DTS。
Debug 快速入门
Debug 详细介绍请参考 Debug 介绍
Debug 简介
Debug 包括两部分:
离线调试:不直接连接正在运行的目标。通过采集日志、coredump、跟踪数据、性能采样文件等离线数据,在本地或分析工具中复盘问题。
在线调试:调试工具直接连接到正在运行的目标系统(例如通过 JTAG/SWD、GDB 远程、网络/串口),在真实环境中进行断点、单步、变量查看与修改、寄存器/内存访问等操作。
离线调试
下面介绍一种分析 coredump 日志的离线调试方法。
配置
配置详细介绍可查看 coredump 配置
配置示例:
CONFIG_DEBUG_COREDUMP=y #启用 coredump 模块
CONFIG_DEBUG_COREDUMP_BACKEND_LOGGING=y #使用日志模块获取 coredump 输出
CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN=y #仅转储异常线程的堆栈、其线程结构以及一些其他最基本的必要数据
获取 coredump
转储内容详细介绍可查看 转储格式
根据已启用的后端,从设备获取 coredump 信息。比如启用的日志后端,可以通过日志工具保存打印的日志,获取日志文件 coredump.log。
解析
解析详细介绍可查看 解析步骤
使用日志后端解析 coredump 步骤如下:
运行 coredump 串行日志转换器,提取 coredump.log 中 coredump 部分数据,生成 coredump.bin :
./zephyr/scripts/coredump/coredump_serial_log_parser.py coredump.log coredump.bin
启动自定义 GDB 服务器,解析 zephyr.elf 和 coredump.bin,获取符号表和异常堆栈等信息,以供 gdb 调试器查询:
./zephyr/scripts/coredump/coredump_gdbserver.py build/zephyr/zephyr.elf coredump.bin
启动 GDB 调试器:
arm-none-eabi-gdb build/zephyr/zephyr.elf
在 GDB 内部,通过端口 1234 连接到 GDB 服务器:
(gdb) target remote localhost:1234
也可以从 GDB 内部启动 GDB 服务器:
启动 GDB :
arm-none-eabi-gdb build/zephyr/zephyr.elf
在 GDB 内部,使用以下选项启动 GDB 服务器
--pipe:(gdb) target remote | ./scripts/coredump/coredump_gdbserver.py --pipe build/zephyr/zephyr.elf coredump.bin
然后就可以使用 gdb 命令查看异常信息,比如:
检查 CPU 寄存器:
info registers查看回溯信息:
bt
在线调试
在线调试详细介绍可查看 在线调试
下面介绍使用 gdb 进行在线调试的方法,需要使用 Jlink 连接开发板和电脑,介绍三种典型场景。
使用 gdb 命令行调试的方式:
备注
PA18、PA19 不能被占用。
代码在 windows 电脑,开发板通过 jlink 与 windows 电脑连接,使用
west debug调试。直接在 windows 上使用west debug命令:west debug
输出如下:
PS D:\code\nuwa> west debug -- west debug: rebuilding ninja: no work to do. -- west debug: using runner jlink -- runners.jlink: reset after flashing requested -- runners.jlink: JLink version: 8.40 -- runners.jlink: J-Link GDB server running on port 2335; no thread info available GNU gdb (Realtek ASDK-12.3.1 Build 4431) 12.1.90.20221114-git Copyright (C) 2022 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-w64-mingw32 --target=arm-none-eabi". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from D:\code\nuwa\build\zephyr\zephyr.elf... Remote debugging using :2335 __enable_irq () at D:/code/nuwa/modules/hal/cmsis_6/CMSIS/Core/Include/cmsis_gcc.h:800 800 __ASM volatile ("cpsie i" : : : "memory"); Resetting target (gdb)
代码在 linux 服务器,开发板通过 jlink 与 windows 电脑连接,使用 gdb 命令行工具调试。
在 windows 手动启动 JLinkGDBServer 连接开发板;
可以使用
sdk/amebagreen2_gcc_project/utils/jlink_script/ap_jlinkGDBSever.bat启动 JLinkGDBServer,脚本中已经有一些配置,可以直接连接 AP 核,双击脚本即可启动。备注
ap_jlinkGDBSever.bat脚本默认使用-device Cortex-M33。由于 rtl8721f 使用 Cortex-M55 核,运行脚本前需要将其改为-device Cortex-M55,或者直接使用west debug命令(它会通过board.cmake自动使用正确的 CPU 型号)。在 linux 服务器启动 gdb 调试器连接 JLinkGDBServer。
~/code/nuwa$ arm-none-eabi-gdb build/zephyr/zephyr.elf (gdb) target remote <windows-ip>:2335
代码在 linux 服务器,开发板通过 jlink 与 windows 电脑连接,使用
west debug命令行调试。
MCUboot 快速入门
MCUboot 详细介绍请参考 MCUboot 介绍
编译 MCUboot 示例
本节以 zephyr/samples/sysbuild/with_mcuboot 为例,它是启用 MCUboot 的最小工程,仅包含必要的配置。
编译,执行命令:
./nuwa.py build -b rtl872xda_evb//mcuboot zephyr/samples/sysbuild/with_mcuboot --sysbuild
固件位于 SDK 根目录的
images/目录下,烧录方法参考 固件下载。通过 Trace Tool 查看串口日志,看到如下日志即表示
km0和km4两个 CPU 都成功运行:[MAIN-I] KM0 OS START *** Booting Zephyr OS build f998faa02fe0 *** Hello sysbuild with mcuboot! rtl872xda_evb
编译,执行命令:
./nuwa.py build -b rtl8730e_evb//mcuboot zephyr/samples/sysbuild/with_mcuboot --sysbuild
固件位于 SDK 根目录的
images/目录下,烧录方法参考 固件下载。通过 Trace Tool 查看串口日志,看到如下日志即表示
km0、km4和ca32三个 CPU 都成功运行:[MAIN-I] KM0 OS START [MAIN-I] KM4 MAIN [MAIN-I] KM4 START SCHEDULER *** Booting Zephyr OS build f998faa02fe0 *** Hello sysbuild with mcuboot! rtl8730e_evb
编译:
./nuwa.py build -b rtl8721f_evb//mcuboot zephyr/samples/sysbuild/with_mcuboot --sysbuild
固件位于 SDK 根目录的
images/目录下,烧录方法参考 固件下载。通过 Trace Tool 查看串口日志,看到如下日志即表示
km4ns和km4tz两个 CPU 都成功运行:[MAIN-I] NP OS START *** Booting Zephyr OS build f998faa02fe0 *** Hello sysbuild with mcuboot! rtl8721f_evb
备注
通过 ImageTool 下载固件时,每个固件的 Start Addr 和 End Addr 必须与 DTS 中 flash layout 配置一致,地址计算方式见 Flash Layout。
创建自己的应用
将上面的示例目录整体拷贝到自定义位置(记为 <APP_DIR>),按需修改后编译,编译命令中的工程路径替换为该 <APP_DIR> 即可。
sysbuild 编译时可通过两个配置文件调整 MCUboot 相关配置:
<APP_DIR>/sysbuild.conf:sysbuild(整机)层级配置,用于设置SB_CONFIG_*选项。例如选择 OTA 升级模式(不指定时顶层默认 swap_using_move,也可指定 swap_using_offset 等其它模式):SB_CONFIG_MCUBOOT_MODE_SWAP_USING_OFFSET=y
<APP_DIR>/sysbuild/mcuboot.conf:仅作用于 MCUboot bootloader 固件的 Kconfig 片段,合并在板级配置(zephyr/boards/realtek/<board>/<board>_mcuboot_defconfig等)之后,可覆盖其默认值。
固件签名
MCUboot 在启动 app 前会校验其签名,校验不通过则拒绝启动。签名以 TLV 形式附加在 固件尾部,bootloader 内置对应公钥用于校验。Ameba 平台支持两种签名密钥来源。
使用 MCUboot 自带密钥签名
Zephyr/MCUboot 的默认方式,通过 sysbuild 配置选择签名算法与密钥文件:
签名算法:
SB_CONFIG_BOOT_SIGNATURE_TYPE_RSA/SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256/SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519(默认 RSA)。密钥文件:
SB_CONFIG_BOOT_SIGNATURE_KEY_FILE指定签名私钥(PEM)。不指定时使用 MCUboot 自带的示例密钥(如root-ec-p256.pem),仅供开发调试,量产须替换为自己的密钥。
使用 manifest.json5 中的密钥签名
Ameba ROM 使用 manifest.json5 中的密钥对 bootloader 进行签名(secure boot)。为便于维护,app 的 MCUboot 签名可复用同一套密钥(仅支持 ECDSA_P256 与 ED25519)。步骤如下:
<APP_DIR>/sysbuild/mcuboot.conf中添加:CONFIG_AMEBA_USING_MANIFEST_KEY=y<APP_DIR>/sysbuild.conf中添加:SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="\${APP_DIR}/my.key"在
manifest.json5中更新你的密钥执行编译。cmake 会自动把
manifest.json5中 app(image2)的密钥按所选算法转换为 MCUboot 所需的 PEM 格式,输出到上面指定的$APP_DIR/my.key供签名使用
固件加密
Ameba 平台支持两种相互独立的固件加密方式。
使用 MCUboot 自带加密
即 MCUboot 的 encrypted images 特性,主要用于加密 OTA 升级固件:固件体以 AES-CTR 加密,AES 密钥再用非对称算法(ECIES-P256、ECIES-X25519、RSA-OAEP、AES-KW 之一)封装后随固件下发,设备在搬运/升级时解密。仅适用于 swap、overwrite-only 等需要搬运固件的升级模式(不支持 direct-XIP)。
通过
SB_CONFIG_BOOT_ENCRYPTION启用,SB_CONFIG_BOOT_ENCRYPTION_KEY_FILE指定加密密钥(PEM),SB_CONFIG_BOOT_ENCRYPTION_ALG_AES_128/SB_CONFIG_BOOT_ENCRYPTION_ALG_AES_256选择 AES 密钥长度。启用后编译会额外输出加密固件
zephyr.signed.encrypted.bin。
使用 RSIP 加密
RSIP 是 Ameba 的硬件 flash 加密:固件以密文烧录到 flash,运行时由硬件在总线上实时解密,XIP 场景无需先解密到 RAM。详细介绍和配置步骤可参考
安全固件保护(RSIP)
。相关配置位于 manifest.json5`(:file:`modules/hal/realtek/ameba/<SOC_NAME>/manifest.json5),在其中设置 rsip_enable、加密模式(XTS/CTR)与密钥等;编译时其 IV 会以自定义 TLV 附加到固件上。
Twister 快速入门
Twister 详细介绍请参考 Twister 介绍。
运行 Twister 的基本步骤如下:
参考 Twister 环境搭建 完成环境准备。
确保开发板能进入烧录状态,以便 Twister 在每轮测试之间自动烧录固件:
对于支持硬件进入烧录状态的板子,无需额外配置。
其它板子需要预先烧录一个支持
reboot uartburn命令(配置CONFIG_SHELL=y)的固件,Twister 通过该命令让板子进入烧录状态。
可先在 tracetool 上手动输入
reboot uartburn验证该命令是否生效,期望看到以下回显:uart:~$ reboot uartburn [BOOT-I] ROM:[V1.0] [BOOT-I] FLASH RATE:1, Pinmux:0 [BOOT-I] BOOT FROM NOR Flash Download Start在 nuwa 工作区根目录下跑一个基础的 kernel 测试套件,验证 Twister 编译、烧录流程是否正确。例如:
Linux (Ubuntu):./nuwa.py twister --device-testing \ --flash-before --west-flash="--port=/dev/ttyUSB0" --device-serial /dev/ttyUSB0 --device-serial-baud 1500000 \ --platform rtl8721f_evb \ -T zephyr/tests/kernel/threads/dynamic_thread_stack/ \ --test kernel.threads.dynamic_thread.stack.no_pool.no_alloc.no_user
Windows:python nuwa.py twister --short-build-path --device-testing ` --flash-before --west-flash="--port=COM12" --device-serial COM12 --device-serial-baud 1500000 ` --platform rtl8721f_evb ` -T zephyr/tests/kernel/threads/dynamic_thread_stack/ ` --test kernel.threads.dynamic_thread.stack.no_pool.no_alloc.no_user
备注
根据实际情况,替换上述命令中
--west-flash和--device-serial指定的串口,以及--platform指定的平台。在输出界面上,期望看到以下的 passed 信息:
INFO - Total complete: 1/ 1 100% built (not run): 0, filtered: 0, failed: 0, error: 0 INFO - 1 test scenarios (1 configurations) selected, 0 configurations filtered (0 by static filter, 0 at runtime). INFO - 1 of 1 executed test configurations passed (100.00%), 0 built (not run), 0 failed, 0 errored, with no warnings in 394.83 seconds. INFO - 1 of 1 executed test cases passed (100.00%) on 1 out of total 1118 platforms (0.09%). INFO - 3 selected test cases not executed: 3 skipped. INFO - 1 test configurations executed on platforms, 0 test configurations were only built. Hardware distribution summary: | Board | ID | Counter | Failures | |-----------------------|------|-----------|------------| | rtl8721f_evb/rtl8721f | | 1 | 0 | INFO - Saving reports... ......
如果遇到错误,可以参考 Twister 测试失败定位 。
上述步骤通过后,可认为 Twister 的基本流程已经打通。接下来可以进一步运行指定的测试用例。
如何通过命令行参数选择测试用例范围,详见 Twister 使用方法。
如何批量运行自定义测试集,详见 自定义批量测试集。