1、CMSIS-RTOS2是什么?
关于CMSIS-RTOS2的官方描述如下:
CMSIS-RTOS v2 (CMSIS-RTOS2) 为基于 Arm® Cortex® 处理器的设备提供通用 RTOS 接口。它为需要RTOS功能的软件组件提供了一个标准化的API,因此为用户和软件行业带来了巨大的好处:
- CMSIS-RTOS2 提供了许多应用所需的基本功能。
- CMSIS-RTOS2 的统一功能集减少了学习工作,并简化了软件组件的共享。
- 使用 CMSIS-RTOS2 的中间件组件与 RTOS 无关,并且更易于调整。
- CMSIS-RTOS2 的标准项目模板可以附带免费提供的 CMSIS-RTOS2 实现。
CMSIS-RTOS2 是一个通用 API,与底层 RTOS 内核无关。应用程序程序员在用户代码中调用 CMSIS-RTOS2 API 函数,以确保从一个 RTOS 到另一个 RTOS 的最大可移植性。使用 CMSIS-RTOS2 API 的中间件通过避免不必要的移植工作来利用这种方法。
2、RTX5是什么?
全称Keil RTX5,是一个开源的、确定性的实时操作系统,实现了 CMSIS-RTOS v2 API,这是一个用于基于 Cortex-M处理器的设备的通用 RTOS 接口。
支持抢占、轮询、协作调度;已通过 PSA 认证;Apache 2.0许可证下发布的,并在GitHub上完全开放。
3、CMSIS-RTOS2 RTX5移植要点
(1)准备一个工程模板
(2)点击“Manage Rub-Time Environment”
(3)依次选择CMSIS,RTOS2,Keil RTX5 (这里用Library)
(4)相关代码添加到工程中
(5)编译报错,
可以看到void SVC_Handler(void)
、void PendSV_Handler(void)
、void SysTick_Handler(void)
三个函数重复定义,这三个中断已经在RTOS中实现了,在gd32l23x_it文件中屏蔽掉即可。
(6)RTX5系统配置
通过RTX_Config.h文件配置,可以使用代码配置也可以使用配置向导配置
System Configuration:系统配置
Thread Configuration:线程配置
Timer Configuration:定时器配置
Event Flags Configuration:事件标志配置
Mutex Configuration:互斥量配置
Semaphore Configuration:信号量配置
Memory Pool Configuration:内存池配置
Message Queue Configuration:消息队列配置
Event Recorder Configuration:事件记录配置
(7)关于系统配置(System Configuration)
配置RTX5使用的动态内存为20480字节;
内核时钟为1000hz,默认使用的是systick;
使能RTX5轮询功能。
(8)关于线程配置(Thread Configuration)
默认的线程栈为512字节;
空闲线程栈为512字节;
使能栈溢出检测。
(9)CMSIS-RTOS2 API
所有的API都可以在cmsis_os2.h文件中找到。
相关文档可查看https://www.keil.com/pack/doc/CMSIS/RTOS2/html/genRTOS2IF.html。
4、CMSIS-RTOS2多任务
建立三个任务,在主任务中创建LED闪烁任务和 adc采样任务,之后主任务永久延时。
(1)主线程
uint8_t os_main_thread_stack_mem[512];
const osThreadAttr_t os_main_thread_attr={
.name="main",
.priority=osPriorityLow,
.stack_size=sizeof(os_main_thread_stack_mem),
.stack_mem=os_main_thread_stack_mem,
};//线程参数
osThreadNew(MainThreadFunc, NULL, &os_main_thread_attr); // 创建主
//线程体
void MainThreadFunc(void *argument)
{
LedThreadInit();
AdcThreadInit();
osDelay(osWaitForever);
}
(2)led线程
void LedThreadInit(void) //自定义的线程初始化函数
{
LedInit();//led初始化函数
osThreadNew(LedThreadFunc, NULL, NULL); // 创建线程
}
//线程体
void LedThreadFunc(void *argument)
{
while(1)
{
printf("\r\nLED %s\r\n",gpio_output_bit_get(GPIOA,GPIO_PIN_7 | GPIO_PIN_8)?"on":"off");
gpio_bit_toggle(GPIOA, GPIO_PIN_7 | GPIO_PIN_8);
osDelay(500);
}
}
(3)adc采样线程
const osThreadAttr_t os_adc_thread_attr={
.name="adc",
.priority=osPriorityNormal2,
};//adc线程参数
void AdcThreadInit(void) //自定义的线程初始化函数
{
AdcInit();//adc初始化函数
osThreadNew(AdcThreadFunc,NULL,&os_adc_thread_attr); //创建线程
}
//线程体
void AdcThreadFunc(void *argument)
{
float temperature=0;
uint16_t ref=0;
float Vdd=0;
while(1)
{
ref=AdcSample(ADC_CHANNEL_17);
Vdd=1.2/(float)ref*4095;
printf("\r\nVdd=%.3f V\r\n",Vdd);
printf("Channel 1=%.3fV\r\n",AdcSample(ADC_CHANNEL_1)*Vdd / 4095);
temperature = ((float)((int16_t)AdcSample(ADC_CHANNEL_16) - (*(int16_t *)(0x1FFFF7F8)))* Vdd / 4095 * 1000 / Vdd) + 30;
printf("Temp=%.3f\r\n\r\n",temperature);
osDelay(2000);
}
}
(4)主函数
int main(void)
{
SerialInit();
printf("GD32L233:%s,%s\r\n\r\n",__DATE__,__TIME__);
osVersion_t ver;
char id[20];
osKernelGetInfo(&ver,id,sizeof(id));//获取版本并打印
printf("\r\nVersion api:%d,kernel:%d, %s\r\n",ver.api,ver.kernel,id);
osKernelInitialize(); // 初始化 CMSIS-RTOS
osThreadNew(MainThreadFunc, NULL, &os_main_thread_attr); // Create application main thread
if (osKernelGetState() == osKernelReady)
{
osKernelStart(); // 启动内核
}
while(1);
}
5、实验现象
可以看出CMSIS-RTOS2API版本为2.1.3,RTX5内核版本为5.5.2;
LED 500ms闪烁一次,adc2000ms采样一次。