1. RTOS介绍
FreeRTOS 是一款免费、开源、轻量级的实时操作系统(RTOS),专为微控制器(MCU)和小型嵌入式系统设计,使用相当广泛,同时易于使用。
官网:https://wap.freertos.org/
官网有详细的FreeRTOS介绍,包含移植教程。以下则基于官网的下图所示移植说明进行移植。


 

2. 硬件
APM32F103VB MINI板

3. 移植介绍
在开始移植前,需确保有一个完全能正确执行的裸机代码环境。

如下为本次移植的裸机代码环境:


 

官网提供最新版本的OS代码下载。部分.c源文件是必须使用的,可选的.c源文件则根据自己的情况酌情添加,实际代码位于FreeRTOS/FreeRTOS-Kernel目录内。


 


 

此处,我们将.c源文件拷贝工程的/lib/FreeRTOS/kernel目录内:


 

因为我们使用的是Keil编译环境,所以port.c应该从FreeRTOS/FreeRTOS-Kernel/portable/Keil中拷贝使用,但Keil目录内提示“See-also-the-RVDS-directory”,所以实际从目录:FreeRTOS/FreeRTOS-Kernel/portable/RVDS拷贝即可,且APM32F103为Cortex-M3内核,所以port最终拷贝的目录为:FreeRTOS/FreeRTOS-Kernel/portable/RVDS/ARM_CM3:


 

代码拷贝到工程的lib/FreeRTOS/portable目录中:


 

heap_x.c位于源码的FreeRTOS/FreeRTOS-Kernel/portable/MemMang目录内,此处拷贝到工程的lib/FreeRTOS/MemMang目录中:


 

.c源文件拷贝完成,还有部分头文件需要拷贝,将整个include文件夹拷贝到工程目录中:


 


 

其中配置文件FreeRTOSConfig.h位于目录:
FreeRTOS/FreeRTOS-Kernel/examples/template_configuration

同时,注意官网的提示:It is therefore specific to the application, not the RTOS, and should be located in an application directory, not in one of the RTOS kernel source code directories.
配置文件是应用特定的文件,不是RTOS的一部分,应该放到应用的文件夹内,所以我们放在工程的src/app文件夹内:

至此,文件的拷贝完成,添加到工程中,并添加对应的头文件路径(选择使用heap_4.c,其他版本可从官网查看差异并根据自己的情况选择):

因为是通用的配置文件,因此不可能一次性编译成功,还需要修改FreeRTOSConfig.h,首次编译后出现多个errors,都是配置文件的问题,配置文件各个宏定义不理解含义,则可以在官网点进去查看,里面有绝大部分宏定义的解析,另外也可以借助AI工具查找资料辅助理解:

具体FreeRTOSConfig.h如何修改,大家根据编译提示和官网的解析,做对应的更改即可,同时功能裁剪也是配置文件的工作。
最后,要注意到平台移植port.c文件内部:
复制

 
  1. /*
  2. * Exception handlers.
  3. */
  4. void xPortPendSVHandler( void );
  5. void xPortSysTickHandler( void );
  6. void vPortSVCHandler( void );
已经实现了三个中断服务函数,这三个中断服务函数非常重要,我们需要屏蔽apm32f10x_int.c文件中的对应版本,改为使用port.c内的代码:

复制

 
  1. /*!
  2. * @brief   This function handles SVCall exception
  3. *
  4. * @param   None
  5. *
  6. * @retval  None
  7. *
  8. */
  9. //void SVC_Handler(void)
  10. //{
  11. //}
  12. /*!
  13. * @brief   This function handles PendSV_Handler exception
  14. *
  15. * @param   None
  16. *
  17. * @retval  None
  18. *
  19. */
  20. //void PendSV_Handler(void)
  21. //{
  22. //}
  23. /*!
  24. * @brief   This function handles SysTick Handler
  25. *
  26. * @param   None
  27. *
  28. * @retval  None
  29. *
  30. */
  31. //void SysTick_Handler(void)
  32. //{
  33. //}

因为startup.s启动文件的中断服务函数名与apm32f10x_int.c中是一致的,所以为了改为使用port.c内的中断服务函数名,需要在FreeRTOSConfig.h文件添加如下宏定义:
复制

 
  1. /* 每次任务切换都执行, 保存 / 恢复上下文,完成任务切换 */
  2. #define xPortPendSVHandler                      PendSV_Handler
  3. /* 系统启动时仅执行一次, 启动第一个任务,切换到线程模式         */
  4. #define vPortSVCHandler                         SVC_Handler
  5. /* cmsis_os2.c 已经实现新的版本 */
  6. /* 提供OS运行的节拍 */
  7. #define xPortSysTickHandler                   SysTick_Handler

此时,FreeRTOS的移植就已经全部完成,我们可以直接按照OS的代码写法要求写代码测试即可。
下面介绍一个使用FreeRTOS更便利的方案:
如果了解FreeRTOS,会知道,同一个功能,在中断环境下和非中断环境下,调用的OS接口是不一样的,例如,获取信号量,中断环境下需要调用xSemaphoreTakeFromISR,而非中断环境下需要调用xSemaphoreTake。ARM为此提供了一个解决方案,屏蔽了这种差异,让中断和非中断环境下,都是调用同一个接口函数。
拷贝cmsis_os2的代码到OS目录中,只有3个文件:


 

打开cmsis_os2.c,查看获取信号量部分的代码,osSemaphoreAcquire函数内部会调用IS_IRQ检查当前是否处于中断环境,如果是则调用xSemaphoreTakeFromISR接口,否则调用xSemaphoreTake接口,而我们在编程时,不管是中断或非中断环境下,都是统一调用osSemaphoreAcquire接口即可,非常便利。
其他的功能也有一样的处理方式。


 

有cmsis_os加入后,编程需要使用到OS的功能,都统一从cmsis_os.h/cmsis_os2.h中取接口函数使用即可,不用再使用原生的FreeRTOS接口。
因为cmsis_os2.c中重新实现了SysTick_Handler中断服务函数,所以FreeRTOSConfig.h需要屏蔽掉xPortSysTickHandler宏定义,使用cmsis_os2.c中的版本即可。


 


 

4. 测试
测试创建两个任务,分别翻转1个LED进行测试:
复制

 
  1. /* LED_D2 */
  2. TaskHandle_t *led_d2_task_handle;
  3. const osThreadAttr_t led_d2_task_att = {
  4.         .name = "LED_D2",
  5.         .priority = (osPriority_t)10,
  6.         .stack_size = (1024),
  7. };
  8. /* LED_D3 */
  9. TaskHandle_t *led_d3_task_handle;
  10. const osThreadAttr_t led_d3_task_att = {
  11.         .name = "LED_D3",
  12.         .priority = (osPriority_t)11,
  13.         .stack_size = (1024),
  14. };
  15. /*
  16. * @brief       LED D2 任务
  17. *
  18. * @param       None
  19. *
  20. * @retval      None
  21. *
  22. */
  23. static void led_d2_task(void *argument)
  24. {
  25.     (void)argument;
  26.    
  27.     while (1) {
  28.         bsp_gpio_toggle(OUTPUT_LED2);
  29.         osDelay(100);
  30.     }
  31. }
  32. /*
  33. * @brief       LED D3 任务
  34. *
  35. * @param       None
  36. *
  37. * @retval      None
  38. *
  39. */
  40. static void led_d3_task(void *argument)
  41. {
  42.     (void)argument;
  43.    
  44.     while (1) {
  45.         bsp_gpio_toggle(OUTPUT_LED3);
  46.         osDelay(300);
  47.     }
  48. }
  49. /*
  50. * @brief       任务创建
  51. *
  52. * @param       None
  53. *
  54. * @retval      None
  55. *
  56. */
  57. void task_create(void)
  58. {
  59.     led_d2_task_handle = osThreadNew(led_d2_task, NULL, &led_d2_task_att);
  60.     led_d3_task_handle = osThreadNew(led_d3_task, NULL, &led_d3_task_att);
  61. }
复制

 
  1. // 外设初始化
  2. void bsp_init(void)
  3. {
  4.     NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);
  5.     bsp_gpio_init();
  6. }
复制

 
  1. // 应用初始化
  2. void app_init(void)
  3. {
  4.     osKernelInitialize();
  5.     task_create();
  6.         osKernelStart();
  7. }
  8. // 应用任务
  9. void app_task(void)
  10. {
  11. }

LED翻转的间隔时间与程序使用的osDelay延时一致。


 

另外,NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4)将优先级分组配置为4,则中断优先级全部为抢占,而没有子优先级,方便OS管理中断。


5.详细代码
 

 FreeRTOS.zip (5.94 MB, 下载次数: 0)


---------------------
作者:口天土立口
链接:https://bbs.21ic.com/icview-3509353-1-1.html?_dsign=7f5afd4e
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐