硬核首发:手把手教你用最新的CMSIS 6创建RTOS2应用程序(含强大的EventRecorder/SemiHosting用法,以及Keil的隐藏功能,含完整工程,无需VIP即可下载)
CMSIS 6是ARM推出的新一代嵌入式标准,相比CMSIS 5进行了架构重构和功能增强,主要特性包括:统一仓库管理、组件模块化、支持最新Cortex-M内核、移除旧编译器支持、新增CMSIS-Toolbox等核心组件。在RTOS方面,CMSIS-RTOS2提供统一API接口,支持进程隔离功能,兼容多种RTOS内核。文章详细介绍了在Keil MDK环境下创建基于CMSIS 6和RTOS2的工程配置
一、CMSIS 6 的主要更新特性及CMSIS-RTOS2简介
CMSIS 6已经发布一段时间了,但是目前绝大多数MDK应用还在使用CMSIS 5(对应ARM Compiler 5)。
CMSIS 6是ARM公司工具链和API的一次重大升级,其官方链接可参考:https://developer.arm.com/community/arm-community-blogs/b/tools-software-ides-blog/posts/cmsis-v6-is-here
安装方法见笔者历史帖子:
https://blog.csdn.net/NJPJI_Yang/article/details/156329889?spm=1011.2415.3001.5331
CMSIS 6 是面向 Cortex‑M/Armv8‑M 的新一代嵌入式标准,相比 CMSIS 5 做了架构重构、工具链升级、新增组件与安全 / AI 增强,核心是更现代、更模块化、更适配 CI/ML/ 安全。以下是最重要特性总结:
1、架构与仓库重构(基础变革)
单仓库统一管理:合并 Core (M) 与 Core (A),废弃分散仓库,适配 GitHub 与 CMSIS‑Pack 工作流ARM。
组件独立化:DSP/NN/RTOS2 等拆分为独立 CMSIS‑Pack,按需加载、独立更新ARM。
移除废弃特性:清理 CMSIS 5 中已弃用 API,精简代码、减少冗余arm-software.github.io。
2、CMSIS‑Core 升级(内核层)
全新头文件设计:对齐 Cortex‑M 官方 TRM,统一内核寄存器与中断定义,兼容性更强arm-software.github.io。
全面支持新内核:原生支持 Cortex‑M52/M55/M85、Armv8.1‑M(含 MVE 向量扩展)、STAR‑MC3 等最新内核。
编译器适配升级:
移除 Arm Compiler 5 支持,仅支持 Arm Compiler 6、GCC 10+、IAR 8+、LLVM/Clang 17+ 现代工具链ARM。
新增 GCC 对 picolibc 启动机制支持,优化跨编译器兼容性arm-software.github.io。
MPU / 安全增强:修复 Armv8‑M MPU 内存属性定义,完善 TrustZone 与安全启动相关接口arm-software.github.io。
3、新增核心组件(能力扩展)
1). CMSIS‑Toolbox(命令行工具链)
提供 pack 管理、项目创建、CMake 构建、CI 集成 全套命令行工具ARM。
支持 VS Code 等现代 IDE,打通 “命令行 + IDE” 混合开发流程。
2). CMSIS‑View(调试与可视化)
把 MDK 专属的 Event Recorder、Component Viewer 开放为标准组件ARM。
支持事件日志、性能分析、组件状态可视化,跨工具链可用ARM。
3). CMSIS‑Compiler(C 库重定向)
跨平台统一 printf/fopen/fwrite 等标准 C 函数重定向,可输出到串口、文件或 CMSIS‑View 事件记录器ARM。
解决不同编译器 C 库行为不一致问题,提升代码可移植性ARM。
4). CMSIS‑Stream(数据流优化)
专为 DSP/ML 应用 设计,优化数据块在处理节点间的流式传输ARM。
减少内存拷贝、提升 AI / 信号处理效率,适配边缘推理场景ARM。
4、CMSIS‑RTOS2 增强(实时系统)
新增 进程隔离(Process Isolation):支持内存 / 执行域隔离,保护关键任务免受其他模块故障影响(RTX 已实现)ARM。
兼容 6 种主流 RTOS 内核(FreeRTOS、RTX、Zephyr 等),API 统一、移植更简单ARM。
5、DSP/NN 与 AI 优化
CMSIS‑DSP:深度优化 MVE 向量指令,适配 Cortex‑M55/M85,算力提升显著。
CMSIS‑NN:强化边缘 AI 推理,与 CMSIS‑Stream 协同,低功耗下高效运行神经网络。
6、工具链与生态现代化
CMake 原生支持:构建系统标准化,适配 CI/CD 与自动化测试。
CMSIS‑Pack 增强:包管理更规范,支持快速部署、版本管理与依赖解析ARM。
跨工具链一致性:统一内核 API、启动代码与调试接口,降低厂商适配成本。
7、安全与可靠性提升
完善 Armv8‑M TrustZone、MPU、安全启动 接口,满足工业 / 车规 / 医疗安全要求。
强化内存保护、错误检测与故障分析能力,提升系统鲁棒性
8、CMSIS-RTOS2简介
CMSIS RTOS2的官网:
https://arm-software.github.io/CMSIS_6/latest/RTOS2/index.html
CMSIS-RTOS2 规定了在基于 Arm® Cortex® 处理器的设备上运行的实时操作系统内核上的通用 RTOS 接口。应用程序和中间件组件可以使用 CMSIS_RTOS2 API,以实现更好的代码复用,并在各种软件生态系统中更轻松地集成。
CMSIS-RTOS2 还为 RTOS 内核指定了一个标准的 操作系统节拍接口。它提供了多种操作系统节拍实现,以便将简单内核移植到不同的 Cortex-M 和 Cortex-A 处理器上。
二、安装Keil MDK最新版
安装盘见笔者的文章:https://blog.csdn.net/NJPJI_Yang/article/details/156329889?spm=1011.2415.3001.5331
三、创建及配置工程
**1.工程初始化 **
安装好最新的Keil MDK后,新建一个工程(新建工程的目录最好为全英文,且不超过128字符),按照如下配置输入Device 配置
2. 设置运行环境
在随后弹出的Manage Run-Time Environment窗口中选择如下几个选项:
在CMSIS下,选择CORE,以及RTOS2 (API) > Keil RTX5,注意格式必须为Source,不能是Library,否则无法调整代码。您还需要选择CMSIS > OS Tick (API) > SysTick。在Device下,选择Startup(C Startup)。
事件记录器和半主机(semihosting)也要打开,这样就可以无需屏幕,无需串口,。直接在PC上看到你要打印的信息。
必须严格按下图配置,否则程序无法正常运行。
这里面要注意,RTOS2本身并不是一个完整的操作系统,只是一个抽象,其底层是内核是Keil RTX5,也是ARM官方的唯一内核。
如果第一次没有选择正确,也可以通过选择如下菜单项重新调整
3. 设置编译选项
为完整使用CMSIS 6和ARM Compiler6 的特性,要打开如下开关:

4. 改名(可选)
然后给Target1换一个名字,Source Group1改为Source(可选)
5. 选择调试器
6. 定义内存映射
导航至Linker选项卡,然后取消选中Use Memory Layout from Target Dialog(因为您将创建自己的内存布局)。
创建内存散点分布文件RTOS.sct,定义内存的散点分布文件,这个文件来源于

LOAD 0x0 0x400000 {
ROOT 0x0 0x400000 {
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO) }
RAM 0x20000000 0x40000 {
.ANY (+RW +ZI) }
ARM_LIB_HEAP 0x20040000 EMPTY 0x10000 {}
ARM_LIB_STACK 0x20050000 EMPTY 0x10000 {}
}
该文件解释如下:
-
ROOT(运行地址 = 加载地址)
LOAD:定义一个加载区域(程序下载到 Flash/ROM 的位置)
加载基地址:0x0
最大大小:0x400000 = 4MB
ROOT:运行地址 = 下载地址,一般放中断向量、启动代码、只读代码
地址:0x0,最大 4MB
RESET +First:复位向量放在最开头(必须在 0x0)
InRoot$$Sections:编译器自动放的根段
+RO:所有只读数据 / 代码(code、const)都放这里 → 对应 Flash -
RAM(读写变量区)
运行地址:0x20000000(典型 Cortex‑M RAM 起始)
大小:0x40000 = 256KB
+RW:已初始化全局 / 静态变量
+ZI:未初始化变量(BSS 段,上电清 0)
→ 这一段是真正的内存变量区 -
ARM_LIB_HEAP :定义堆
起始:0x20040000
大小:0x10000 = 64KB
EMPTY:只占地址空间,不烧录内容
→ 给 malloc/free 使用 -
ARM_LIB_STACK :定义堆栈
起始:0x20050000
大小:0x10000 = 64KB
→ 函数调用、局部变量、中断现场保存
四、输入源码
- 1.创建main.c
如果要运行RTOS,必须提供main()的入口
// 包含RTE(Run-Time Environment)组件相关头文件
// RTE是MDK-ARM提供的运行时环境配置文件,自动生成,不能修改
#include "RTE_Components.h"
// 包含CMSIS标准设备头文件(由CMSIS自动根据芯片型号选择对应MCU头文件)
#include CMSIS_device_header
// 包含CMSIS-RTOS2实时操作系统核心API头文件
#include "cmsis_os2.h"
// 包含事件记录器(Event Recorder)头文件,用于调试、日志输出
#include "EventRecorder.h"
// 声明应用程序入口线程函数 app_main
// 该函数将作为RTOS的主线程被创建和执行
void app_main(void *);
// 主函数,__attribute__((noreturn)) 告诉编译器此函数不会返回
int __attribute__((noreturn)) main (void) {
// 更新系统核心时钟配置
// 完成系统时钟、总线时钟等初始化,确保系统时钟配置正确
SystemCoreClockUpdate();
// 初始化事件记录器(EventRecorder)
// EventRecordAll:开启所有级别的事件记录
// 1:表示立即启动事件记录器
EventRecorderInitialize(EventRecordAll, 1);
// 初始化CMSIS-RTOS2操作系统内核
// 完成RTOS内核数据结构、内存、调度器等基础初始化
osKernelInitialize();
// 创建应用程序主线程 app_main
// 参数1:线程入口函数 app_main
// 参数2:传递给线程的参数(这里为NULL,无参数)
// 参数3:线程属性(NULL表示使用RTOS默认属性)
osThreadNew(app_main, NULL, NULL);
// 判断内核状态是否为已就绪(osKernelReady)
// 只有内核初始化成功、线程创建成功后才会进入就绪态
if (osKernelGetState() == osKernelReady) {
// 启动RTOS内核调度器
// 开始线程调度,系统从此由RTOS接管,不再返回main函数
osKernelStart();
}
// 无限循环
// 正常情况下内核启动后不会执行到这里
// 若执行到此处,说明RTOS启动失败、系统出现异常
while(1);
}
- 2. 创建app_main.c
这是真正的进程入口,程序如下:
创建3个线程
#include "cmsis_os2.h"
void thread1(void *);
void thread2(void *);
void thread3(void *);
void app_main (void *argument) {
(void)argument; // 告诉编译器:我知道没用,别警告
osThreadNew(thread1, NULL, NULL); // Create thread1
osThreadNew(thread2, NULL, NULL); // Create thread2
osThreadNew(thread3, NULL, NULL); // Create thread3
}
- 3.创建threads.c
这是每个线程的入口函数
#include "cmsis_os2.h"
#include <stdio.h>
void __attribute__((noreturn)) thread1(void *argument){
(void)argument; // 告诉编译器:我知道没用,别警告
for(;;){
printf("hello from thread 1\n");
osDelay(1000);
}
}
void __attribute__((noreturn)) thread2(void *argument){
(void)argument;
for(;;){
printf("hello from thread 2\n");
osDelay(1000);
}
}
void __attribute__((noreturn)) thread3(void *argument){
(void)argument;
for(;;){
printf("hello from thread 3\n");
osDelay(1000);
}
}
创建完程序后,工程结构如下:
- 4.设置EventRecorder的来源
这个非常有趣,保证绝大多数用过Keil的人都不知道的隐藏功能,可以直接用下拉框选择宏定义参数。
5.编译
这时候就可以用Keil MDK的最新ARM编译器进行编译了,应该没有warning和error,可能编译的时候会出现找不到.h文件的问题,只要增加编译头文件路径即可
编译输出如下:
五、调试和运行程序
- 1.用EventRecorder查看系统事件
按ctrl+F5进入调试模式
选择EventRecorder窗口
不断按F5或者按下运行按钮
就会在Event Recorder窗口不断地看到有各种事件发生
- 2.用semihosting直接看printf的输出
打开debug-printf的输出窗口
不断按F5或者按下运行按钮
就会看到各个线程的printf输出信息
六、总结
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)