本文介绍如何在NUCLEO-U5A5ZJ-Q上移植TobudOS内核,并创建多个任务实现对板卡上RGB灯的控制。
TobudOS 简介
TobudOS 是面向物联网领域开发的实时操作系统,基于腾讯自研的物联网操作系统TencentOS Tiny开源项目,2020年由腾讯捐赠到开放原子开源基金会进行孵化,2023年正式更名为TobudOS,TobudOS具有低功耗,低资源占用,模块化,安全可靠等特点,可有效提升物联网终端产品开发效率,提供精简的 RTOS 内核,内核组件可裁剪可配置,可快速移植到多种主流 MCU (如 STM32 全系列) 及模组芯片上。而且,基于 RTOS 内核提供了丰富的物联网组件,内部集成主流物联网协议栈(如 CoAP/MQTT/TLS/DTLS/LoRaWAN/NB-IoT 等),可助力物联网终端设备及业务快速接入物联网云平台。
NUCLEO-U5A5ZJ-Q 硬件
NUCLEO-U5A5ZJ-Q是基于ST的STM32U5A5ZJT6Q设计的评估板。
板载了通用的外设,比如按键、LED灯、串口等。本次实验使用的RGB灯在板上的位置如图所示。通过产看原理图可知,LED对应的管脚如下表。
模板工程创建
ST为开发者提供了很多开发工具的支持,比如Keil、IAR、STM32CubeIDE、Makefile等。本文选择STM32CubeIDE作为开发环境。
在STM32Cube IDE的创建工程菜单中选择创建STM32 project类型的工程。
在选择目标板卡的界面中选择目标板卡。
输入工程名和工程选项,完成工程的创建。
在完成工程的创建,工程的目录树如图所示。
TobudOS 内核移植
TobudOS内核移植涉及到的文件有。
在工程的顶层文件夹创建tiny文件夹用于存放操作系统相关的代码。
arch文件夹中包含了多种内核架构的代码,本文使用的NUCLEO_U5A5ZJ-Q的芯片内核为cortexm33,所以只保留如下的文件夹中的代码即可。
kernel文件夹中的代码是操作系统的源码,全部复制过来即可。
osal文件夹中包含了cmsisos和POSIX接口,本文中保留的文件如下。
到此,从TobudOS仓库中添加代码的工作就结束了,在工程的菜单栏中更行文件的索引。
在工程的属性对话框中,添加头文件路径和源代码路径
由于TobudOS的代码编译是条件编译,需要在工程中添加配置文件来开启相应的功能。
在Core/Inc文件中添加tos_config.h
文件的具体内容如下。
#ifndef _TOS_CONFIG_H_
#define _TOS_CONFIG_H_
#include "stm32u5xx.h" // 目标芯片头文件,视特定芯片而定
#define TOS_CFG_TASK_PRIO_MAX 10u // 配置TobudOS默认支持的最大优先级数量
#define TOS_CFG_ROUND_ROBIN_EN 0u // 配置TobudOS的内核是否开启时间片轮转
#define TOS_CFG_OBJECT_VERIFY_EN 1u // 配置TobudOS是否校验指针合法
#define TOS_CFG_OBJ_DYNAMIC_CREATE_EN 1u //开启TobudOS动态对象创建
#define TOS_CFG_TASK_DYNAMIC_CREATE_EN 1u // TobudOS 动态任务创建功能宏
#define TOS_CFG_EVENT_EN 1u // TobudOS 事件模块功能宏
#define TOS_CFG_MMBLK_EN 1u //配置TobudOS是否开启内存块管理模块
#define TOS_CFG_MMHEAP_EN 1u //配置TobudOS是否开启动态内存模块
#define TOS_CFG_MMHEAP_DEFAULT_POOL_EN 1u // TobudOS 默认动态内存池功能宏
#define TOS_CFG_MMHEAP_DEFAULT_POOL_SIZE 0x100 // 配置TobudOS默认动态内存池大小
#define TOS_CFG_MUTEX_EN 1u // 配置TobudOS是否开启互斥锁模块
#define TOS_CFG_MESSAGE_QUEUE_EN 1u // 配置TobudOS是否开启消息队列模块
#define TOS_CFG_MAIL_QUEUE_EN 1u // 配置TobudOS是否开启消息邮箱模块
#define TOS_CFG_PRIORITY_MESSAGE_QUEUE_EN 1u // 配置TobudOS是否开启优先级消息队列模块
#define TOS_CFG_PRIORITY_MAIL_QUEUE_EN 1u // 配置TobudOS是否开启优先级消息邮箱模块
#define TOS_CFG_TIMER_EN 1u // 配置TobudOS是否开启软件定时器模块
#define TOS_CFG_PWR_MGR_EN 0u // 配置TobudOS是否开启外设电源管理模块
#define TOS_CFG_TICKLESS_EN 0u // 配置Tickless 低功耗模块开关
#define TOS_CFG_SEM_EN 1u // 配置TobudOS是否开启信号量模块
#define TOS_CFG_TASK_STACK_DRAUGHT_DEPTH_DETACT_EN 1u // 配置TobudOS是否开启任务栈深度检测
#define TOS_CFG_FAULT_BACKTRACE_EN 0u // 配置TobudOS是否开启异常栈回溯功能
#define TOS_CFG_IDLE_TASK_STK_SIZE 128u // 配置TobudOS空闲任务栈大小
#define TOS_CFG_CPU_TICK_PER_SECOND 1000u // 配置TobudOS的tick频率
#define TOS_CFG_CPU_CLOCK (SystemCoreClock) // 配置TobudOS CPU频率
#define TOS_CFG_TIMER_AS_PROC 1u // 配置是否将TIMER配置成函数模式
#endif
在stm32u5xx_it.c
中为PendSV_Handler添加__weak修饰符,在SysTick_Handller中添加如下调用。
#include "tos_k.h "
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
if(tos_knl_is_running()) {
tos_knl_irq_enter();
tos_tick_handler();
tos_knl_irq_leave();
}
/* USER CODE END SysTick_IRQn 1 */
}
/**
* @brief This function handles Pendable request for system service.
*/
__weak void PendSV_Handler(void)
{
/* USER CODE BEGIN PendSV_IRQn 0 */
/* USER CODE END PendSV_IRQn 0 */
/* USER CODE BEGIN PendSV_IRQn 1 */
/* USER CODE END PendSV_IRQn 1 */
}
到此,就可以在main.c中添加调用TobudOS接口函数的应用代码了。添加以下代码创建三个任务以不同的频率控制板卡上的LED灯的闪烁。
#include "cmsis_os.h"
//task1
#define TASK1_STK_SIZE 512
void task1(void *pdata);
osThreadDef(task1, osPriorityNormal, 1, TASK1_STK_SIZE);
//task2
#define TASK2_STK_SIZE 512
void task2(void *pdata);
osThreadDef(task2, osPriorityNormal, 1, TASK2_STK_SIZE);
//task3
#define TASK3_STK_SIZE 512
void task3(void *pdata);
osThreadDef(task3, osPriorityNormal, 1, TASK3_STK_SIZE);
void task1(void *pdata)
{
while(1)
{
HAL_GPIO_TogglePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin);
osDelay(200);
}
}
void task2(void *pdata) {
while(1) {
HAL_GPIO_TogglePin(LED_RED_GPIO_Port, LED_RED_Pin);
osDelay(1000);
}
}
void task3(void *pdata) {
while(1) {
HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
osDelay(500);
}
}
在main.c中添加以下代码实现任务的创建和启动任务调度。
osKernelInitialize(); //TOS Tiny kernel initialize
osThreadCreate(osThread(task1), NULL); // Create task1
osThreadCreate(osThread(task2), NULL); // Create task2
osThreadCreate(osThread(task3), NULL); // Create task3
osKernelStart(); //Start TOS Tiny
完成上述操作后,编译工程并下载到开发板上,可以看到开发板上的LED以不同的频率闪烁,符合程序的设计。
心得
虽然第一次接触TobudOS,但是移植的时候只遇到一些小困难,跟着文档的指导移植,很快就可以完成。
工程代码仓库