Zephyr -- Board Porting Guide

Board/ 添加自定义的board:boards/<arch>/<board>/ boards/<ARCH>/plank ├── board.cmake ├── CMakeLists.txt ├── doc │ ├── plank.png │ └── index.rst ├── Kconfig.board ├── Kconfig.defconfig ├── plank_defconfig ├── plank.dts └── plank.yaml 必须要有的文件: plank.dts:设备树。 Kconfig.board, Kconfig.defconfig, plank_defconfig: Kconfig文件。 可选文件: board.cmake: 用于west flash和west debug。 CMakeLists.txt: 如果在board/下加其他*.c的话需要。 doc/: 文档。 plank.yaml: Test Runner(Twister)需要使用。 Kconfig.board: 至少需要config BOARD_PLANK选项。 config BOARD_PLANK bool "Plank board" depends on SOC_SERIES_YOUR_SOC_SERIES_HERE select SOC_PART_NUMBER_ABCDEFGH Kconfig.defconfig: 板子的一些固定Kconfig选项,需要包括在 if BOARD_PLANK/endif中间。通常是invisible Kconfig Symbol,没有prompt。需要依赖default值或者其他Kconfig依赖,无法在配置菜单中选择。 if BOARD_PLANK # Always set CONFIG_BOARD here. This isn't meant to be customized, # but is set as a "default" due to Kconfig language restrictions....

2024-02-01 · 1 min

Zephyr -- Misc

生成compile_commands.json 执行如下命令, 再编译后, build目录下生成 compile_commands.json, 可以帮忙IDE进行代码的诊断, 补全和跳转: west config build.cmake-args -- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 编译过程保留.i文件 west build -- -DCMAKE_C_FLAGS="-save-temps=obj" 会保存到build/目录下各层级的CMakeFiles中。 全局变量分析 利用puncover工具,build完之后运行: west build -t puncover Test命令 编译检查: west twister -p rts5816 -T fingerprint/apps/usbfp 在板子上运行测试(需要host和板子连接): west twister -p rts5816 -T fingerprint/tests --device-testing --device-serial /dev/ttyUSB0 --device-serial-baud 57600 单元测试: west twister -p unit_testing -T fingerprint/tests

2024-01-31 · 1 min

Zephyr -- Kconfig

Setting Kconfig configuration values 生成的配置文件: zephyr/build/.config: for CMake use. zephyr/build/zephyr/include/generated/autoconf.h: for c file use. 所有的Kconfig配置会merge如下路径的Kconfig files: board/<arch>/<BOARD>/<BOARD>_defconfig CMake中定义的CONFIG_XXX Application configuration(APP 目录下的Kconfig相关文件) 第三点Application configuration又会从如下路径获取Kconfig,默认使用prj.conf: 如果定义了CONF_FILE, 会把该文件的Kconfig merge进来。CONF_FILE可以在如下定义 App的CMakeLists.txt, 在find_package(zephyr)前定义。 west直接传入-DCONF_FILE=<conf file(s)> From the CMake variable cache 如果未定义CONF_FILE, 如果存在prj_<BOARD>.conf,merge进prj.conf。 如果存在board/<BOARD>.conf,merge进prj.conf。 如果存在board/<BOARD>_<revision>.conf,merge进prj.conf。 merge必须有的prj.conf。 如果board/下的<BOARD>_defconfig和APP/下的Kconfig冲突了,以APP的为准。

2024-01-31 · 1 min

Zephyr -- Kernel Init

Vector_table.S 以arm cortex-M系列的启动流程为例,arch/arm/core/cortex_m: vector_table.S: 定义了中断向量表_vector_table。其中arm cortex-M规定0x0地址存放栈的起始地址(栈顶)。0x4开始存放reset handler,… 没看到定义外部中断的地址 上电后跳转至z_arm_reset函数,进入reset.S。 Reset.S 目前大部分的宏定义都没打开。这里关注下通用的一些流程: movs.n r0, #_EXC_IRQ_DEFAULT_PRIO msr BASEPRI, r0 设置BASEPRI寄存器, 中断的base prioriity, 低于或等于该优先级的中断都会被屏蔽。 这里#_EXC_IRQ_DEFAULT_PRIO宏展开为3,说明中断优先级只能配置为0/1/2。 ldr r0, =z_interrupt_stacks ldr r1, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE adds r0, r0, r1 msr PSP, r0 // write r0 to PSP mrs r0, CONTROL // read CONTROL to r0 movs r1, #2 orrs r0, r1 /* CONTROL_SPSEL_Msk */ msr CONTROL, r0 // write 0x2 to CONTROL isb bl z_arm_prep_c 1....

2024-01-30 · 2 min

Zephyr -- GPIO Subsystem

Device Tree dts/binding/gpio/gpio-controller.yaml描述了设备树中支持的属性。 gpio-controller节点: 其中gpio-controller和gpio-cells两个属性是必须的。 前者表示gpio controller节点,后者表示其他节点使用gpio specifier需要几个item来描述。 gpio: gpio@0x400ff000 { compatible = "nxp, kinetis-gpio"; status = "disabled"; reg = <0x400ff000 0x40>; interrupts = <59 2>; gpio-controller; #gpio-cells = <2>; ngpios = <32>; // optional, default 32 gpio-reserved-ranges = <3 2>, <10, 1>; // optional, <index size>表示第<index>起<size>个gpio不能使用。 }; consumer节点: xxx-gpios/gpios = <&<gpio-controller节点> <gpio_number> <配置属性>> xxx-gpios = <&gpio 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, <&gpio 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>; GPIO_ACTIVE_LOW表示逻辑电平和实际电平相反,逻辑1代表低电平。 配置属性可在include/zephyr/dt-bindings/gpio/gpio.h中查找。 Interrupt相关flags查阅gpio.h,是多个bit的组合,上图没有完全列出。 Consumer 方法一: 设备树API...

2024-01-26 · 5 min

Zephyr -- Interrupt Subsystem

Overview https://docs.zephyrproject.org/latest/kernel/services/interrupts.html Multi-level Interrupt Handling 如果要支持中断嵌套,需要打开CONFIG_MULTI_LEVEL_INTERRUPTS。CONFIG_2ND_LEVEL_INTERRUPTS, CONFIG_3RD_LEVEL_INTERRUPTS也需要根据硬件架构来选择是否打开。 9 4 2 0 _ _ _ _ _ _ _ _ _ _ _ _ _ (LEVEL 1) 5 3 | A | 2 _ _ _ _ _ _ _ _ _ _ _ _ _ _ (LEVEL 2) | C B _ _ _ _ _ _ _ (LEVEL 3) D Level 1第一级中断控制器有12条interrupt lines, 其中第2条和第9条接到了Level2优先级更高的中断控制器。第4条上接了设备A。 Level 2有两个中断控制器,左边的第3条interrupt line接了设备C, 第5条接到Level3中断控制器。 右边的第二条接了设备B。...

2024-01-26 · 2 min

Zephyr -- Pinctrl Subsystem

Device Tree Pinctrl controller节点: 所有可选的支持属性可以查阅/dts/bindings/pinctrl/pincfg-node.yaml,支持配置上下拉,驱动能力等等。具体支持属性要参考soc的yaml文件/dts/bindings/pinctrl/xxx.yaml 当设备节点调用perip0_default的时候,group1~N都会被apply。 /* board-pinctrl.dtsi */ #include <vnd-soc-pkgxx.h> &pinctrl { /* Node with pin configuration for default state */ periph0_default: periph0_default { group1 { /* Mappings: PERIPH0_SIGA -> PX0, PERIPH0_SIGC -> PZ1 */ pinmux = <PERIPH0_SIGA_PX0>, <PERIPH0_SIGC_PZ1>; /* Pins PX0 and PZ1 have pull-up enabled */ bias-pull-up; }; ... groupN { /* Mappings: PERIPH0_SIGB -> PY7 */ pinmux = <PERIPH0_SIGB_PY7>; }; }; }; 使用pinctrl的设备节点: &uart0 { pinctrl-0 = <&uart0_default>; pinctrl-1 = <&uart0_sleep>; pinctrl-names = "default", "sleep"; }; 默认支持default, sleep两种属性,也可以自定义属性,比如slow, fast,这样需要在具体driver中自定义PINCTRL_STATE_XXX, 比如...

2023-12-25 · 3 min

Zephyr -- System Call

C Prototype 系统调用函数必须以__syscall开头,在include/或SYSCALL_INCLUDE_DIRS目录下被声明。 scripts/build/parse_syscalls.py会parse__syscall这个标记,并且函数有以下限制: 参数不能传入数组,比如int foo[] or int foo[12], 必须用int *foo代替。 函数指针不能正常解析,需要先对函数指针typedef,再传入。 定义了系统调用的xxx.h头文件必须要文件末尾加上同名的#include <syscall/xxx.h>。 Invocation Context 调用上下文 如果定义了CONFIG_USERSPACE,所有的system call APIs都会直接调用对应的implementation function。 如果定义了__ZEPHYR_SUPERVISOR__,表示所有code都在supervisor mode下运行,直接调用对应的implementation function。 如果定义了__ZEPHYR_USER__ Implementation Detail 实现细节 scripts/build/gencalls.py会把parse到的system calls放进/build/include/generated/syscall_list.h中。以K_SYSCALL_前缀加上API。 所有可以调用的system calls被保存在syscall_dispatch.c中的_k_syscall_table中。 system calls的API实现被保存在了/build/include/generated/syscalls/xxx.h 这些文件被/include/xxx.h文件最后include进去,完成函数的定义。e.g // include/i2c.h __syscall int i2c_configure(const struct device *dev, uint32_t dev_config); //声明 static inline int z_impl_i2c_configure(const struct device *dev, uint32_t dev_config) { const struct i2c_driver_api *api = (const struct i2c_driver_api *)dev->api; return api->configure(dev, dev_config); } //... #include <syscalls/i2c....

2023-12-18 · 1 min

Zephyr -- SPI framework

DeviceTree spi0: spi@f0020000 { compatible = "snps,designware-spi"; #address-cells = <1>; #size-cells = <0>; reg = <0xf0020000 0x100>; interrupts = <40 1>; pinctrl-0 = <&spi2_default>; pinctrl-1 = <&spi2_sleep>; pinctrl-names = "default", "sleep"; fifo-depth = <32>; // 必须参数 clocks = <&sysclk>; // 和下面clock-frequency二选一,优先从&sysclk中获取clock-frequency clock-frequency = <200000000>; cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; // 用gpio代替cs,可选参数 status = "disabled"; slow@0 { // spi设备 compatible = "test-spi-loopback-slow"; reg = <0>; spi-max-frequency = <500000>; }; fast@0 { // @x 是指第几根片选 compatible = "test-spi-loopback-fast"; reg = <0>; // 0表示spi master controller,1表示spi slave controller spi-max-frequency = <1000000>; }; }; Consumer(应用层和其他driver如何调用spi接口) 方法1:...

2023-12-15 · 3 min

Zephyr -- I2C framework

Device Tree Consumer(应用层和其他driver如何调用i2c接口) 方法1: 设备树API // 获取i2c device node id #define I2C_DEV DT_COMPAT_GET_ANY_STATUS_OKAY(test_i2c) // i2c deivce的compatible,不是i2c bus // 通过I2C_DT_SPEC_GET宏从设备树获得i2c_dt_spec结构体 struct i2c_dt_spec { const struct device *bus; uint16_t addr; }; #define I2C_DT_SPEC_GET_ON_I2C(node_id) \ .bus = DEVICE_DT_GET(DT_BUS(node_id)), \ .addr = DT_REG_ADDR(node_id) static struct i2c_dt_spec i2c = I2C_DT_SPEC_GET(I2C_DEV); 可以调用i2c_xxx_dt进行i2c传输了 static inline int i2c_write_dt(const struct i2c_dt_spec *spec, const uint8_t *buf, uint32_t num_bytes) static inline int i2c_read_dt(const struct i2c_dt_spec *spec, uint8_t *buf, uint32_t num_bytes) static inline int i2c_write_read_dt(const struct i2c_dt_spec *spec, const void *write_buf, size_t num_write, void *read_buf, size_t num_read) 方法2:...

2023-12-15 · 3 min