本帖最后由 wangqy_ic 于 2022-2-15 13:13 编辑
#申请原创#
@21小跑堂
Zephyr-RTOS 简介
Zephyr Project 是托管于 Linux 基金会的一个嵌入式相关项目。主要的目标是提供一个供小型嵌入式系统使用的实时操作系统系统(Zephyr-RTOS),以及相关的工具软件(west 等)。
官网:https://www.zephyrproject.org/
官方介绍:
The Zephyr OS is based on a small-footprint kernel designed for use on resource-constrained and embedded systems: from simple embedded environmental sensors and LED wearables to sophisticated embedded controllers, smart watches, and IoT wireless applications.
Zephyr-RTOS 的开发,类似 Linux 系统/应用程序的开发,包括 KConfig ,Devicetree 等工具。
Zephyr-RTOS 的特性有:- 多种内核服务:多任务,动态内存管理,线程同步,电源管理等
- 多种调度算法:协作式和抢占式调度,时间片,最早截止日期优先等
- 高度可配置
- 支持多种处理器架构:ARM,ARM64,RISC-V,Xtensa,X86……
- 内存保护
- 编译期间定义资源(这个不好翻译,作用是可以有效缩小固件尺寸)
- 设备驱动模型
- 支持 Devicetree
- 原生的网络协议栈,支持多种网络协议
- BLE 5.0
- 原生支持 Linux, macOS, Windows 开发
- VFS 支持(LittleFS 和 FATFS)
- 强大的日志系统
- 功能完善的 Shell
- NVS 支持
- 兼容 POSIX
这么多的特性,全用上的话,固件尺寸当然也不会太小……
缘起
据我了解,这个操作系统目前在国内使用也不是很广泛,相对于 FreeRTOS,RT-Thread 等更是知者甚少。
我大概是在 2018 年接触到这个系统,对于它非常接近 Linux 系统的开发方式,觉得非常有意思,就一直保持着兴趣。
2021 年起,我逐渐在工作中引入了这个系统,并且成功使用在 STM32 的系统上运行一直非常稳定。灵活的配置方式,也非常便于切换到新的硬件系统。
去年底,因为项目需要我们打算切入国产 MCU。经过评估,我们选择了国民技术的 MCU。对于国内的 MCU,Zephyr 目前官方支持的只有兆易创新(gigadevice)和乐鑫科技(espressif)的一部分热门 MCU。看到 21IC 和国民技术在搞活动,也也就有了这个移植项目。
国民技术简介
官网:https://www.nationstech.com/
官方介绍
国民技术股份有限公司于2000年源于国家“909”集成电路专项工程成立,2010年创业板上市(股票代码:300077),是中国安全芯片、通用MCU领军企业,国家级**技术企业,拥有国内首个企业独立安全芯片攻防技术实验室,博士后科研工作站。总部位于深圳,在北京、上海、武汉、西安、香港、新加坡等地设有分支机构。主营产品包括:安全芯片、通用MCU、可信计算芯片、智能卡芯片、非接读写芯片、蓝牙芯片、RCC创新产品等,广泛应用于网络安全认证、电子银行、电子证照、移动支付与移动安全、物联网、工业联网及工业控制、智能家电及智能家庭物联网终端、消费电子、电机驱动、电池及能源管理、智能表计、医疗电子、汽车电子、安防、生物识别、通讯、传感器、机器自动化等应用方向。
移植目标
我在活动中申请拿到的开发板是 N32G45XVL-STB,MCU 是 N32G457VEL7,所以移植的目标是 N32G4567 系列。
移植过程介绍
准备工作
开发 Zephyr-RTOS 至少需要:CMake,Ninja,Python,Git以及编译套件(我使用的是 GNU ARMEmbedded)。具体安装方法,可以参考官方的说明:https://docs.zephyrproject.org/latest/getting_started/index.html,也可以参考我自己整理的简要说明:https://www.yuque.com/quincy/zephyr/gyq03s。
确保开发环境正常,就可以正式的移植工作。
一些说明
在我看来,Zephyr-RTOS 的灵活性有一个重要的体现 Out-of-tree-development:在 Zephyr-RTOS 主干代码外进行开发。大白话就是移植和开发的工作完全独立于Zephyr-RTOS 的官方代码,不会影响和干扰官方代码。
我的移植工作就是基于这种特性,而不需要在 Zephyr-RTOS 的代码中开新的分支,也不会存在代码合并等一系列麻烦事。
代码目录介绍
代码已经在 Gitee 上的仓库:https://gitee.com/quincyzh/zephyr-rtos-for-n32-mcu欢迎点赞。另外有个彩蛋,我实际使用的是 N32WB031 系列芯片,所以代码仓库也包含 N32WB031 系列芯片的移植。这个是不是可以奖励双倍 @21小跑堂 2本文只是介绍 N32G4567 的移植。
代码目录结构:
boards :开发板代码
CMakeLists.txt :CMake 配置文件
drivers :适配 Zephyr 驱动代码
dts :Devicetree 支持
hal_library :国民技术提供的代码库
include :头文件目录
Kconfig :KConfig 配置文件
modules :Zephyr 构建配置
README.md :README 文件
soc :N32 SOC 移植代码
zephyr :Zephyr 构建配置
移植说明
主要步骤:
- 创建代码目录
- SOC 相关代码
- 驱动相关代码
- 开发板相关代码
- 测试
1. 创建代码目录
按 “代码目录介绍” 一节介绍,建立目录及相关文件。各个文件的目录,后续会说明。
2. SOC 相关代码
SOc 目录的详细结构如下:
├─soc
│ └─arm
│ └─nationstech_n32
│ ├─common
│ ├─n32g4
│ └─n32wb03
这个目录结构是按 Zephyr 要求建立,不能随意调整,否则不能编译。
soc/arm/nationstech_n32/n32g4目录及其内容就是对应 N32G4567 这个 MCU,内容有:
CMakeLists.txt
Kconfig.defconfig.n32g457x
Kconfig.defconfig.series
Kconfig.series
Kconfig.soc
linker.ld
soc.c
soc.h
Kconfig 一系列文件,是 KConfig 配置文件,目的是向 KConfig 系统提供与 N32G4567 相关的配置项目.
CMakeLists.txt 是 CMake 配置文件,决定那些文件参与构建.
linker.ld 是链接说明,这个文件是从 Zephyr 代码库复制而来,基本上每个架构的 MCU 都差不多。
soc.c soc.h 是 MCU 最基本的初始化代码,这里主要是初始化基本的时钟系统。soc.c 的主要代码:
static intn32g0_init(const struct device *arg)
{
uint32_t key;
ARG_UNUSED(arg);
key = irq_lock();
SystemInit();
NMI_INIT();
irq_unlock(key);
SystemCoreClockUpdate();
return 0;
}
这个目录内容正确的话,会在配置期间看到以下两个的效果。
一是在 Soc/CPU/Configuration Selection 目录下可以看到 N32G4 Series MCU:
二是在 Hardware Configuration → N32G4 MCU Selection 目录下可以看到类似内容:
需要注意的是:这些选项默认是隐藏的,要按键盘 "A" 才会显示。
file:///C:/Users/Zoro/AppData/Local/Temp/msohtmlclip1/01/clip_image003.png
其他的驱动适配,结构基本相当,不再赘述。具体可参见代码仓库:https://gitee.com/quincyzh/zephyr-rtos-for-n32-mcu。需要注意的点是,每种驱动的 api 结构定义是不一样的,可参考 Zephyr 的 driver 文件在的各种平台的实现。
3. 驱动相关代码
目前已经实现驱动 clock_ctrl, pinmux, GPIO, Uart 这四个驱动。这里已 clock_ctrl 为例,说明移植的步骤。
创建文件夹 drivers\clock_control,创建3个文件:
- drivers\clock_control\clock_control_n32.c
- drivers\clock_control\CMakeLists.txt
- drivers\clock_control\Kconfig
- drivers\CMakeLists.txt
drivers\clock_control\clock_control_n32.c 文件是适配 Zephyr 系统的驱动框架,主要代码:
static const struct clock_control_driver_api n32_cc_api = {
.on = n32_cc_on,
.off = n32_cc_off,
.get_rate = n32_cc_get_subsys_rate,
};
static int n32_cc_init(const struct device *dev)
{
return 0;
}
DEVICE_DT_DEFINE(DT_NODELABEL(rcc),
&n32_cc_init,
NULL,
NULL, NULL,
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
&n32_cc_api);
- n32_cc_api 这个结构体是填充相关的操作 api 函数指针;
- n32_cc_init 函数是时钟初始化
- DEVICE_DT_DEFINE 这个宏,是向系统注册 clock_ctrl 设备。
系统启动期间,这些内容是这样使用的:
1. 依据优先级,DEVICE_DT_DEFINE 宏里的 PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY。
2. 调用设备注册的初始化函数,也就是 n32_cc_init。
3. 使用相关 API 时,就会调用 n32_cc_api 结构体的那些函数(指针)。例如 获取某个子系统的时钟频率就是这样调用:clock_control_get_rate(cc_dev, subsys, &rate); 这个函数最终会调用 n32_cc_get_subsys_rate。
drivers\clock_control\CMakeLists.txt 文件是 CMake 配置文件,决定构建内容:
zephyr_library_amend()
zephyr_library_sources_ifdef(CONFIG_CLOCK_CTRL_N32 clock_control_n32.c)
zephyr_library_amend 函数会把这个目录下的代码,链接至驱动相关代码块。
drivers\clock_control\Kconfig 是KConfig 配置文件。
menuconfig CLOCK_CTRL_N32
bool "CLOCK_CTRL Driver for N32 family of MCUs"
depends on SOC_FAMILY_N32
select USE_NS_STD_LIB_RCC
help
Enable CLOCK_CTRL driver for N32 MCUs
这个会增加一个配置目录,让用户选择是否启用该配置。实际的效果是在配置界面中 Modules → Nationstech N32 Porting 目录下,看到如下,空格键切换是否启用:
其他的驱动适配,结构基本相当,不再赘述。具体可参见代码仓库:https://gitee.com/quincyzh/zephyr-rtos-for-n32-mcu 。需要注意的点是,每种驱动的 api 结构定义是不一样的,可参考 Zephyr 的 driver 文件在的各种平台的实现。
4. 开发板相关代码
boards\arm\n32g45xvl_stb目录就是 N32G45XVL-STB这个开发板的配置说明:
board.cmake
Kconfig.board
Kconfig.defconfig
n32g45xvl_stb.dts
n32g45xvl_stb.yaml
n32g45xvl_stb_defconfig
boards\arm\n32g45xvl_stb\board.cmake文件配置
Kconfig 系列文件是增加板级 KConfig 配置选项。选项可以在配置界面 BoardSelection 目录下看到。
boards\arm\n32g45xvl_stb\n32g45xvl_stb.dts文件是设备树(Devicetree)描述文件:
/*
* N32G45XVL-STB
*
* Copyright (c) 2022 Quincy<wangqyfm@foxmail.com>
* SPDX-License-Identifier: Apache-2.0
*/
/dts-v1/;
#include<nationstech/g4/n32g457xE.dtsi>
#include <nationstech/g4/n32g4-pinctrl.dtsi>
/ {
model = "N32G45XVL-STB";
compatible = "nationstech,n32g45xvl_stb";
chosen {
/* ... */
};
leds {
compatible = "gpio-leds";
/* ... */
};
gpio_keys {
compatible = "gpio-keys";
/* ... */
};
aliases {
led0 = &green_led;
/* ... */
};
};
&rcc {
status = "okay";
};
&pinmux {
status = "okay";
};
&gpioa {
status = "okay";
};
&gpiob {
status = "okay";
};
&usart1 {
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>;
};
具体的语法,可以参考:https://docs.zephyrproject.org/latest/guides/dts/index.html
boards\arm\n32g45xvl_stb\n32g45xvl_stb.yaml文件开发板描述。描述开发板的一些特性:mcu 及架构,支持的外设等。
boards\arm\n32g45xvl_stb\n32g45xvl_stb_defconfig文件是 KConfig 的选项文件,这个文件是代替手动选择 KConfig 选项:
# N32G45XVL-STB
#
# Copyright (c) 2022 Quincy<wangqyfm@foxmail.com>
# SPDX-License-Identifier:Apache-2.0
CONFIG_SOC_SERIES_N32G4=y
CONFIG_SOC_N32G45X=y
CONFIG_BOARD_N32G45XVL_STB=y
#enable MPU
CONFIG_MPU=n
CONFIG_ARM_MPU=n
# Enable HW stack protection
CONFIG_HW_STACK_PROTECTION=y
# Enable Clocks
CONFIG_CLOCK_CONTROL=y
CONFIG_CLOCK_CTRL_N32=y
# enable pinmux
CONFIG_PINMUX=y
CONFIG_PINMUX_N32=y
# enable GPIO
CONFIG_GPIO=y
CONFIG_GPIO_N32=y
# enable uart driver
CONFIG_SERIAL=y
CONFIG_UART_N32=y
# console
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
# LOG
CONFIG_LOG=y
# enable FLASH
CONFIG_FLASH=y
CONFIG_FLASH_N32=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=24000000
每个文件的详细内容可以参考代码仓库。
5. 测试
可以运行 do_build.bat 构建编译测试的代码,如果一切没有问题的话,最后有类似的构建信息:
Memory region Used Size Region Size %age Used
FLASH: 21404 B 512 KB 4.08%
SRAM: 6960 B 48 KB 14.16%
IDT_LIST: 0 GB 2 KB 0.00%
这个脚本使用的 Zephyr 自带的hello_world 例程,打印 HelloWorld! 后结束运行。
结语
Zephyr-RTOS 的高可配置性,完善的构建工具,使得移植工作显得条理清晰,排查问题也比较容易。建议大家多多尝试~也希望国内 MCU 厂家积极适配更多 RTOS,让用户由更多的可选项,也让广大工程师能轻松工作,少加班~~~
最后的最后,第一次在 21IC 发这么长的帖子,希望兄弟姐妹们多多回复,给些支持~~~ |
博主,你好我按照你的方法,构建了一个板子,但是输出信息说,没有这个板子