找回密码
 立即注册
首页 业界区 安全 FreeRTOS 简单内核实现1 前言

FreeRTOS 简单内核实现1 前言

坠矜 昨天 09:36
0、写在前面

为深入理解 RTOS 内核工作机制,笔者制作了名为 “FreeRTOS 内核简单实现” 的项目专栏 ,目标为自己动手从 0 到 1 编程一个简单的 RTOS 内核,从而实现任务并行工作的效果,主要实现了以下功能

  • 静态创建任务
  • 临界段保护
  • 支持任务多优先级
  • 任务阻塞延时
  • 时间片轮询
注意:

  • 本项目不是仿真,而是基于 STM32F407 开发板从 0 到 1 编程实现的 RTOS 简单内核,目前只在 Cortex-M4 内核 MCU 上进行了验证,最终会使用 GPIO 输出作为各种效果的演示,支持 Keil 与 CLion 两种开发环境,两者项目流程几乎一致,只是在汇编程序与工程配置上存在区别,不同之处会在教程中做明确说明
  • 本项目实现的 RTOS 时间基准使用了 SysTick,但 STM32 HAL 库的时间基准也为 SysTick ,因此可能存在潜在的问题,如果出现问题可以按照 “6、补充 - 更换 RTOS 时基” 小节所述修改完成的 RTOS 内核
1、参考资料


  • FreeRTOS内核实现_忆昔z的博客-CSDN博客
  • GitHub - aeneag/FreeRTOS_kernel: 深入理解FreeRTOS内核,从零开始实现内核
  • FreeRTOS内核实现与应用开发实战指南
2、准备工作

2.1、STM32 空工程

参考 STM32CubeMX教程1 工程建立 文章创建一个 STM32F407VGT6 空工程
参考 STM32CubeMX教程2 GPIO输出 - 点亮LED灯 文章初始化 4 个 LED 灯用于对本项目实现的 RTOS 内核验证
注意:空工程中 NVIC 选择 4 位抢占优先级,并应将 SysTick 和 PendSV 中断设置为最低优先级
2.2、创建 RTOS 文件目录

工程根目录下创建一个 RTOS 目录,目录结构如下

  • RTOS

    • Inc

      • FreeRTOS.h,用来包含 RTOS 所有的头文件
      • FreeRTOSConfig.h,用来配置裁剪 RTOS 的功能
      • list.h,双向链表数据结构头文件
      • portMacro.h,用来统一 RTOS 中用到的类型和定义一些功能宏
      • task.h,任务管理头文件

    • Src

      • list.c,双向链表数据结构源文件
      • prot.c,用来定义与底层芯片架构有关的函数和中断服务函数
      • task.c,任务管理源文件


如果使用 Keil 则需要将上面创建的文件添加到 Keil 工程中,并在设置中增加头文件路径,具体步骤如下图所示
1.png

2.png

如果使用的 CLion 需要在 CMakeLists_template.txt 模板文件中添加 RTOS 目录下的源文件目录和头文件目录,具体如下所示
  1. // 增加头文件目录
  2. include_directories(${includes} RTOS/Inc)
  3. // 增加源文件目录
  4. file(GLOB_RECURSE SOURCES ${sources} "RTOS/*.*")
复制代码
FreeRTOS.h
  1. #ifndef INC_FREERTOS_H
  2. #define INC_FREERTOS_H
  3. #include "FreeRTOSConfig.h"
  4. #include "portMacro.h"
  5. #include "list.h"
  6. #include "task.h"
  7. // 如果后续编程提示找不到 __DSB() 等汇编,可添加该 MCU 头文件
  8. #include "stm32f4xx_hal.h"
  9. #endif //INC_FREERTOS_H
复制代码
FreeRTOSConfig.h、list.h、portMacro.h 和 task.h
  1. // XXX 替换为对应头文件名称
  2. #ifndef XXX_H
  3. #define XXX_H
  4. #include "FreeRTOS.h"
  5. #endif //XXX_H
复制代码
list.c、prot.c 和 task.c
  1. /*list.c*/
  2. #include "list.h"
  3. /*prot.c*/
  4. #include "FreeRTOS.h"
  5. /*task.c*/
  6. #include "task.h"
复制代码
按照上述列出的文件添加内容,添加完成后编译整个工程应该不会有错误发生,之后将在各个文件中添加程序逐步实现 RTOS 简单内核
3、约定

整个专栏文章做如下约定

  • 代码段开头会添加该代码段中函数 / 定义所处的文件位置,如下所示代码段表示变量 xTickCount 应该在 task.c 文件中定义
  1. /* task.c */
  2. // 滴答定时器计数值
  3. static volatile TickType_t xTickCount = (TickType_t)0U;
复制代码

  • 请自行安排本专栏文章中各个代码段在工程文件中的位置
4、专栏目录

如下所示为 "FreeRTOS 简单内核实现" 专栏所有文章链接

  • FreeRTOS 简单内核实现1 前言
  • FreeRTOS 简单内核实现2 双向链表
  • FreeRTOS 简单内核实现3 任务管理
  • FreeRTOS 简单内核实现4 临界段
  • FreeRTOS 简单内核实现5 阻塞延时
  • FreeRTOS 简单内核实现6 优先级
  • FreeRTOS 简单内核实现7 阻塞链表
  • FreeRTOS 简单内核实现8 时间片轮询
5、项目仓库

项目 github 工程代码链接如下 FreeRTOS 简单内核实现,标 Star 防丢失!
6、补充 - 更换 RTOS 时基

首先,在 CubeMX 中设置任意 Timer 为 1ms 的周期定时器(你可以随意更改 RTOS 的心跳周期),具体可以参考 STM32CubeMX教程5 TIM 定时器概述及基本定时器 文章内容,笔者以 STM32F4 的 TIM6 为例子,注意在 NVIC 中勾选 TIM6 全局中断,抢占优先级为最低优先级 15
然后,修改 portMacro.h 中的 xPortSysTickHandler 宏定义
  1. /* portMacro.h */
  2. #define xPortSysTickHandler         HAL_TIM_PeriodElapsedCallback
复制代码
其次,修改 port.c 中的 xPortSysTickHandler 函数
  1. /* port.c */
  2. // RTOS 时基中断处理
  3. void xPortSysTickHandler(TIM_HandleTypeDef *htim)
  4. {
  5.         if(htim == &htim6)
  6.         {
  7.                 // 关中断
  8.                 vPortRaiseBASEPRI();
  9.                 // 更新系统时基
  10.                 if(xTaskIncrementTick() != pdFALSE)
  11.                 {
  12.                         taskYIELD();
  13.                 }
  14.                 // 开中断
  15.                 vPortSetBASEPRI(0);
  16.         }
  17. }
复制代码
最后,在 port.c 文件中启动调度器函数中 xPortStartScheduler() 启动 RTOS 的时基
  1. /* port.c */
  2. extern TIM_HandleTypeDef htim6;
  3. // 启动调度器
  4. BaseType_t xPortStartScheduler(void)
  5. {
  6.         // 设置 PendSV 和 SysTick 中断优先级为最低
  7.         portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
  8.         portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
  9.        
  10.         // 初始化 RTOS 时基
  11.         HAL_TIM_Base_Start_IT(&htim6);
  12.        
  13.         // 启动第一个任务,不再返回
  14.         prvStartFirstTask();
  15.        
  16.         // 正常不会运行到这里
  17.         return 0;
  18. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册