关于FreeRTOS

获取FreeRTOS

可以通过GitHub仓库FreeRTOS/FreeRTOS下载源代码(此仓库中包含一些Demo,可以方便移植)

可以直接在FreeRTOS™ - FreeRTOS™直接点击下载按钮下载所需版本(此方法下载的为LTS,不包含Demo)

下载 FreeRTOS - FreeRTOS™文档中亦有讲述相关的获取FreeRTOS的方法

文档

官方提供如下在线文档可以了解学习FreeRTOS

FreeRTOS 文档 - FreeRTOS™

移植FreeRTOS到STM32H723ZGT6

移植所需文件

FreeRTOS的源代码组织见源组织 - FreeRTOS™有相关介绍。

如果是下载的是Github仓库:FreeRTOS/FreeRTOS的源代码, 那么应该有下述路径,提供了一些Demo例程,理论上是可以直接使用的(例如下图提供了CORTEX_STM32F103的IAR、KEIL、GCC的Demo例程),我目前不是使用的这种方法,暂不讨论。

在这里插入图片描述

见下图,是FreeRTOS kernel的目录组织结构,后文描述的所有的移植工作都是基于此LTS版本的源代码进行的。

在这里插入图片描述

移植文件详细步骤

  1. 在STM32H723ZGT6的项目下新建FreeRTOS目录,在FreeFTOS目录下新建source、include、portable目录

在这里插入图片描述

  1. 拷贝FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel目录下的所有.c文件到步骤1创建的FreeRTOS/source目录下,步骤1中的图中是我已完成这一步骤的结果。

  2. 拷贝FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\include目录下的所有.h文件到FreeRTOS/include目录下。

  3. 拷贝FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\portable目录下的所需文件到FreeRTOS/portable目录下。

    这一步,需要对FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\portable目录下的文件做一个简单的介绍

    在这里插入图片描述

    如上图所示,我们需要关注的主要有Common和MemMang这两个目录。

    在这里插入图片描述

    在Common目录中包含了MPU相关的代码,我目前没有使用,但我也移植过去了。

    MPU指的就是Memory Protect Unit即存储保护单元,很多Cortex-M系列的芯片都包含。

    在MemMang目录中包含了FreeRTOS堆内存管理的实现,分别由heap_1/heap_2/heap_3/heap_4/heap_5五种实现,在FreeRTOS 堆内存管理 - FreeRTOS™在线文档中有相关介绍。

    在这里插入图片描述

    在这一步我们还需要根据我们所使用的开发平台选择具体平台相关的代码,可以看到在FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\portable目录下包含很多的开发平台,例如常见的IAR、Keil、RVDS、GCC等等,我使用的是VSCode + GCC工具链去完成开发工作,所以我是用的是GCC目录下的代码。STM32H723是使用的ARM Cortex-M7的内核,所以我使用的是FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\portable\GCC\ARM_CM7\r0p1目录下的代码。

    在这里插入图片描述

    最终FreeRTOS/portable目录下的移植的文件组成如下:

    在这里插入图片描述

修改Makefile

修改Makefile文件把源代码以及头文件的目录加入到Makefile的编译逻辑中

在这里插入图片描述

FreeRTOS配置

新建FreeRTOSConfig.h文件配置FreeFTOS

FreeRTOS可通过名为FreeRTOSConfig.h的配置文件进行定制。所有FreeRTOS应用程序都必须在其预处理器的include路径中包含FreeRTOSConfig.h头文件。FreeRTOSConfig.h可根据正在构建的应用程序定制RTOS内核,因此该配置文件特定于应用程序,而不是RTOS,并且应位于应用程序目录中,而不是 RTOS 内核源代码目录中。

相关介绍详见在线文档:定制 - FreeRTOS™

Core\Inc目录下新建FreeRTOSConfig.h文件(也可以在其他目录下新建,只要编译的时候-I指定了头文件所在的目录即可),文件的内容可以复制FreeRTOSv202406.01-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\examples\coverity\FreeRTOSConfig.h文件中的内容,并根据实际情况做对应修改。

在这里插入图片描述

每个参数在定制 - FreeRTOS™在线文档中有相关的介绍,下面附上我所使用的FreeRTOSConfig.h文件,可作为参考。

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "stm32h723xx.h"
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  #include <stdint.h>
  extern uint32_t SystemCoreClock;
#endif
#define configENABLE_FPU                         0
#define configENABLE_MPU                         0

#define configUSE_PREEMPTION                     1
#define configSUPPORT_STATIC_ALLOCATION          0
#define configSUPPORT_DYNAMIC_ALLOCATION         1
#define configUSE_IDLE_HOOK                      0
#define configUSE_TICK_HOOK                      0
#define configCPU_CLOCK_HZ                       ( SystemCoreClock )
#define configTICK_RATE_HZ                       ((TickType_t)1000)
#define configMAX_PRIORITIES                     ( 7 )
#define configMINIMAL_STACK_SIZE                 ((uint16_t)128)
#define configTOTAL_HEAP_SIZE                    ((size_t)15360)
#define configMAX_TASK_NAME_LEN                  ( 16 )
#define configUSE_16_BIT_TICKS                   0
#define configUSE_MUTEXES                        1
#define configQUEUE_REGISTRY_SIZE                8
#define configUSE_PORT_OPTIMISED_TASK_SELECTION  1

#define configMESSAGE_BUFFER_LENGTH_TYPE         size_t

#define configUSE_CO_ROUTINES                    0
#define configMAX_CO_ROUTINE_PRIORITIES          ( 2 )

#define INCLUDE_vTaskPrioritySet             1
#define INCLUDE_uxTaskPriorityGet            1
#define INCLUDE_vTaskDelete                  1
#define INCLUDE_vTaskCleanUpResources        0
#define INCLUDE_vTaskSuspend                 1
#define INCLUDE_vTaskDelayUntil              0
#define INCLUDE_vTaskDelay                   1
#define INCLUDE_xTaskGetSchedulerState       1

#ifdef __NVIC_PRIO_BITS
 #define configPRIO_BITS         __NVIC_PRIO_BITS
#else
 #define configPRIO_BITS         4
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

#define configKERNEL_INTERRUPT_PRIORITY 		\
              ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	\
              ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}

#endif /* FREERTOS_CONFIG_H */
修改STM32H723ZGT6中部分exception handler接口

在port.c中提供了如下三个接口,我们需要使用这三个接口去替换到STM32H723ZGT6的异常处理函数

在这里插入图片描述

一般异常处理函数在.s启动文件中,我的在STM32H723ZGT6\startup_stm32h723xx.s文件中,我所作的修改如下,替换处理函数,同时去除了weak属性。

在这里插入图片描述

也可以通过其他方法去修改这一部分代码逻辑,需要注意的是在移植的port.c中有如下判断,如果使用其他函数名,记得修改相关代码。

在这里插入图片描述

使用FreeRTOS

基于前文的步骤,完成了FreeRTOS的移植工作之后,我们可以在main.c新建Task来验证以下前面移植的FreeRTOS是否可以正常工作。

包含头文件

#include "FreeRTOS.h"
#include "task.h"

新建Task相关函数

app1 Task 每隔1000个vTaskDelay打印app1 running日志

app2 Task 每隔1000个vTaskDelay打印app1 running日志

start Task用于新建app1和app2 Task,在完成新建工作后,删除掉start Task

#define START_TASK_PRIO 1
#define START_STK_SIZE 256
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);

#define app1_TASK_PRIO 2
#define app1_STK_SIZE 128
TaskHandle_t app1Task_Handler;
void app1_task(void *p_arg);

#define app2_TASK_PRIO 3
#define app2_STK_SIZE 128
TaskHandle_t app2Task_Handler;
void app2_task(void *p_arg);

void app1_task(void* p_arg)
{
  printf("app1 begin \r\n");
  while (1)
  {
    vTaskDelay(1000);
    printf("app1 running\r\n");
  }
}

void app2_task(void* p_arg)
{
  printf("app2 begin\r\n");
  while (1)
  {
    vTaskDelay(500);
    printf("app2 running\r\n");
  }
}

void start_task(void *pvParameters)
{
  taskENTER_CRITICAL();

  printf("begin to create app1 task\r\n");
  xTaskCreate((TaskFunction_t)app1_task,
              (const char*)"app1_task",
              (uint16_t)app1_STK_SIZE,
              (void*)NULL,
              (UBaseType_t)app1_TASK_PRIO,
              (TaskHandle_t*)&app1Task_Handler);


   printf("begin to create app2 task\r\n");
   xTaskCreate((TaskFunction_t)app2_task,
               (const char*)"app2",
               (uint16_t)app2_STK_SIZE,
               (void*)NULL,
               (UBaseType_t)app2_TASK_PRIO,
               (TaskHandle_t*)&app2Task_Handler);

  vTaskDelete(StartTask_Handler);
  taskEXIT_CRITICAL();
}

运行Task

在main函数中合适位置假如如下代码,验证FreeRTOS是否可以正常的进行任务的调度。

 /**************launch freeRTOS tasks ******/
  BaseType_t xReturn = pdPASS;
  xReturn = xTaskCreate((TaskFunction_t )start_task,
                        (const char*    )"start_task",
                        (uint16_t       )START_STK_SIZE,
                        (void*          )NULL,
                        (UBaseType_t    )START_TASK_PRIO,
                        (TaskHandle_t*  )&StartTask_Handler);

  if(pdPASS == xReturn)
    vTaskStartScheduler();
  else
    return -1;

理论上可以在串口日志上看到如下日志:

begin to create app1 task
begin to create app2 task
app2 begin
app1 begin 
app2 running
app2 running
app1 running
app2 running
app2 running
app1 running
app2 running
app2 running
app1 running
app2 running
app2 running
app1 running
......
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐