系列视频教程
版本:https://www.rt-thread.org/document/site/#/
RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。适用于家电、消费电子、医疗设备、工控等领域大量使用的 32 位 ARM 入门级 MCU 的场合,入门文档传送门
支持架构:ARM:Cortex M0/ M3/ M4/ M7 等、RISC-V 及其他。功能:线程管理、线程间同步与通信、时钟管理、中断管理、内存管理。
相比较Nano版本,除了内核之外,还 由内核层、组件和服务层、IoT 框架层、文件系统、图形库、设备框架等组成。包含完整的中间件组件,具备低功耗、安全、通信协议支持和云端连接能力,是一个完整的 IoT OS,入门文档传送门
RT-Thread Smart 是基于 RT-Thread 操作系统上的混合操作系统,简称为 rt-smart,它把应用从内核中独立出来,形成独立的用户态应用程序,并具备独立的地址空间(32 位系统上是 4G 的独立地址空间)。rt-smart 软件包是 RT-Thread Smart 的用户体验软件包,可在 QEMU 模拟的 VExpress-A9 机器中或树莓派 4B 开发板上执行。本文档是针对 QEMU、树莓派 4B 开发板上快速上手 rt-smart,入门文档传送门
初级教程选择最基本的rt-thread nano版本,主要学习rt-thread内核和HAL库、cubems的使用。
HAL库与Cubemx系列|Systick-系统滴答定时器详解
之前拼夕夕上拼的开发板,价格相当可以,相信不少小伙伴都买了,小飞哥买来之后已经吃灰大半年了,这次也是重新拾起来,做教程学习使用,后续开发教程就在这块板子上进行啦
硬件介绍传送门:https://github.com/alibaba/AliOS-Things/wiki/AliOS-Things-Developer-Kit-Hardware-Guide
开发板是基于STM32L496VGTx芯片研发的一款物联网开发板,STM32L496VGTx这款芯片具有高性能、低功耗的特点。其内核为ARM 32位Cortex-M4 CPU,最高80MHZ的主频率,1MB的闪存320KB的SRAM,最多支持136个高速IO口,还支持SPI,CAN,I2C,I2S,USB,UART等常用的外设接口。
咱们使用cubemx移植,比较简单快速,官网教程传送门
移植目录结构
要获取 RT-Thread Nano 软件包,需要在 CubeMX 中添加 https://www.rt-thread.org/download/cube/RealThread.RT-Thread.pdsc
具体步骤:
选择开发板对应的芯片型号,新建工程即可
时钟配置,创建好工程后,可以采用默认的时钟配置,也可以自定义时钟,小飞哥采用的是外部时钟配置,首先需要选择时钟源
选择外部时钟源,由于硬件焊接的是8M晶体,这里选择8M,主频最大80MHZ,那就给他干到80MHZ,榨干他
调试模式配置,SWD模式
选中芯片型号之后,点击 Softwares Packages->Select Components,进入组件配置界面,选择 RealThread, 然后根据需求选择 RT-Thread 组件,然后点击 OK 按钮,如下图所示:
注意
RT-Thread Nano 软件包中包含 kernel, shell 和 device 三个部分,仅选择 kernel 表示只使用 RT-Thread 内核,工程中会添加内核代码;选择 kernel 与 shell 表示在使用 RT-Thread Nano 的基础上使用 FinSH Shell 组件,工程中会添加内核代码与 FinSH 组件的代码。再选择 device 表示使用 rt-thread 的 device 框架,用户基于此框架编写外设驱动并注册后,就可以使用 device 统一接口操作外设。
第一阶段教程主要是HAL库,所以暂时不添加device库
根据自己的都需要配置一些参数,基本都是默认不需要怎么调整
配置串口,用于FinSH控制台使用,结合开发板硬件连接,选择LPUART1,PB10,PB11,一定要这么选,不然会出问题,波特率115200
RT-Thread 操作系统重定义 HardFault_Handler、PendSV_Handler、SysTick_Handler 中断函数,为了避免重复定义的问题,在生成工程之前,需要在中断配置中,代码生成的选项中,取消选择三个中断函数(对应注释选项是 Hard fault interrupt, Pendable request, Time base :System tick timer),最后点击生成代码,具体操作如下图 所示:
到这里就可以进行代码生成了
直接生成的工程是有一些问题,需要处理一下的,首次编译会报一个错误,错误信息是说有个文件没有包含,定位过去看看,需要手动取消注释,在cubemx配置中没有看到这个选项,每次新生成工程,都要搞一下子...蓝瘦想哭
接下来需要在 board.c 中实现 系统时钟配置(为 MCU、外设提供工作时钟)与 OS Tick 的配置 (为操作系统提供心跳 / 节拍)。
如下代码所示, HAL_Init() 初始化 HAL 库, SystemClock_Config() 配置了系统时钟, SystemCoreClockUpdate() 对系统时钟进行更新,_SysTick_Config() 配置了 OS Tick。此处 OS Tick 使用滴答定时器 systick 实现,需要用户在 board.c 中实现 SysTick_Handler() 中断服务例程,调用 RT-Thread 提供的 rt_tick_increase() ,如下图所示。
void rt_hw_board_init(void)
{
extern void SystemClock_Config(void);
HAL_Init();
SystemClock_Config();
SystemCoreClockUpdate();
//板级外设初始化
MX_GPIO_Init();
//uart_init();
/*
* 1: OS Tick Configuration
* Enable the hardware timer and call the rt_os_tick_callback function
* periodically with the frequency RT_TICK_PER_SECOND.
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/RT_TICK_PER_SECOND);
/* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}
我们的外设初始化也统一放在这里
串口号也需要更改,rt-thread默认的串口号是USART2,改为我们需要的串口号
内存堆初始化
系统内存堆的初始化在 board.c 中的 rt_hw_board_init() 函数中完成,内存堆功能是否使用取决于宏 RT_USING_HEAP 是否开启,RT-Thread Nano 默认不开启内存堆功能,这样可以保持一个较小的体积,不用为内存堆开辟空间。
开启系统 heap 将可以使用动态内存功能,如使用 rt_malloc、rt_free 以及各种系统动态创建对象的 API。若需要使用系统内存堆功能,则打开 RT_USING_HEAP 宏定义即可,此时内存堆初始化函数 rt_system_heap_init() 将被调用,如下所示:
初始化内存堆需要堆的起始地址与结束地址这两个参数,系统中默认使用数组作为 heap,并获取了 heap 的起始地址与结束地址,该数组大小可手动更改,如下所示:
注意
开启 heap 动态内存功能后,heap 默认值较小,在使用的时候需要改大,否则可能会有申请内存失败或者创建线程失败的情况,修改方法有以下两种:
可以直接修改数组中定义的 RT_HEAP_SIZE 的大小,至少大于各个动态申请内存大小之和,但要小于芯片 RAM 总大小。
也可以参考《RT-Thread Nano 移植原理》——实现动态内存堆 章节进行修改,使用 RAM ZI 段结尾处作为 HEAP 的起始地址,使用 RAM 的结尾地址作为 HEAP 的结尾地址,这是 heap 能设置的最大值的方法。
为了避免每次代码生成之后重复调用初始化内容,我们把板级系统生成的初始化代码屏蔽掉,统一在board.c中调用,需要做一下处理
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
#if 0
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_LPUART1_UART_Init();
/* USER CODE BEGIN 2 */
#endif
//rt_user_thread_entry();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
rt_kprintf("\r\n----------start------\r-!\n");
rt_kprintf("欢迎关注小飞哥玩嵌入式\r\n");
rt_kprintf("HELLO RT-THREAD Nano!\r\n");
rt_kprintf("\r\n----------end------\r\n");
rt_thread_mdelay(1000);
}
/* USER CODE END 3 */
}
然后编译下载固件,OK,至此,移植工作就已经完成了,还是比较顺利的,后面就可以学习Nano的核心组件了