3. FreeRTOS system source code porting

Table of contents

1. Obtain FreeRTOS source code

2. FreeRTOS system source code content

3. FreeRTOS system source code porting

1. Obtain FreeRTOS source code

Come to FreeRTOS official website: https://www.freertos.org/

What I mainly provide here is the V10.4.6 version of FreeRTOS

1. Enter the official website and click Download FreeRTOS

2. Click Download

2. FreeRTOS system source code content

 Closely related to us is the FreeRTOS kernel, we open the freeRTOS system kernel folder

 The contents of each folder are

name describe
Demo FreeRTOS Demo Routine
License Licensing related to FreeRTOS
Source FreeRTOS source code
Test Common and porting layer test code

Demo folder

        In the Demo folder is the demonstration routine of FreeRTOS, which supports a variety of chip architectures, including F1, F4, and F7. Demonstration works.

Source folder 

        The Source folder is the instance of the source code

 Next, let's take a look at the meaning of each file

name describe
include Contains header files for FreeRTOS
portable Contains porting files for FreeRTOS
croytin.c Coroutine related files
event_group.c Event related documents
list.c list related files
tail.c Queue related files
stream_buffer.c Stream buffer related files
tasks.c Software related documents
timers.c Software timer related documents

The bold red ones must be added, and others can be used or not, depending on your own needs.

portable folder

        In the final analysis, the FreeRTOS operating system is a software-level thing, so how does FreeRTOS work with hardware?

        The stuff in the portable folder is the bridge

Since we use MDK for development, here we focus on introducing some of the migration files.

name describe
Keil point to the RBDS folder
RVDS Migration files for different core chips
Meng Mang memory management file

3. FreeRTOS system source code porting

Preparation for transplantation:

1. FreeRTOS source code

2. Basic engineering

Migration steps:

1. Add FreeRTOS source code (add FreeRTOS) source code to the basic project, header file path, etc.

2. FreeRTOSConfig, add FreeRTOSconfig.h configuration file

3. Modify the SYSTEM file, modify sys.c, delay.c, usart.c in the SYSTEM file

4. Modify interrupt related files, modify Systick interrupt, SVC interrupt, PendSV interrupt.

5. Add application programs and check whether the porting is successful.

Start porting:

1. Add FreeRTOS source code

        Create a new FreeRTOS subfolder in the Middlewares folder of the basic project, as shown in the following figure:

         Then you need to add the source code of FreeRTOS to the newly created FreeRTOS subfile. Add all the files under the Source folder of the FreeRTOS kernel source code to the FreeRTOS folder of the project, as shown in the following figure:

          Among them, we introduced earlier, portable, only three files are actually used, and we can delete other unused files

         In MemMang, it is our memory management algorithm. In fact, we only use algorithm 4, that is, only use heap_4.c. RVDS is a bridge between software and hardware. Different kernels have different files.

2. Add the file to the project

        Open the project and create two new file groups, namely Middlewares/FreeRTOS_CORE and Middlewares/FreeRTOS_PORT, as shown in the figure below:

        We add the C source code of the kernel to Middlewares/FreeRTOS_CORE, and the Middlewares/FreeRTOS_PORT group is used to store the migration files of the FreeRTOS kernel. Two files need to be added to this group, namely heap_x.c and port.c. Different development boards have different port.c folders to port.

STM32 series development board type The folder where port.c is located
STM32F1 ARM_CM3
STM32F4 ARM_CM4F
STM32F7 ARM_CM7/r0p1
STM32H7 ARM_CM7/r0p1

        After adding, as shown in the figure below:

3. Add header file path

        We need to add two header files in total, one is the include header file of the FreeRTOS system, and the other is the header file of the hardware connection. The path after adding is shown in the figure below:

 4. Add the FreeRTOSConfig.h file

       FreeRTOSConfig.h is the configuration file of the FreeRTOS operating system. The FreeRTOS operating system can be tailored. Users can tailor FreeRTOS according to their needs, and cut out the functions that do not need FreeRTOS, so as to save memory resources in the MCU.

5. Modify the SYSTEM file

        We modify sys.h, delay.h, usart.h respectively

5.1、sys.h

        Change the 1 in #define SYS_SUPPORT_OS 1 to 0

/**
 * SYS_SUPPORT_OS用于定义系统文件夹是否支持OS
 * 0,不支持OS
 * 1,支持OS
 */
#define SYS_SUPPORT_OS         1

5.2、usart.c

        The modification of the usart.c file is also very simple. There are two places that need to be modified. The first is the interrupt service function of the serial port. When using µC/OS, OSIntEnter() and OSIntExit() need to be added to enter and exit the interrupt. function, which is the relevant processing mechanism of µC/OS for interrupts, but there is no such mechanism in FreeRTOS, so these two lines of code are deleted, and the interrupt service function of the modified serial port is as follows:

/**
 * @brief       串口1中断服务函数
 * @param       无
 * @retval      无
 */
void USART_UX_IRQHandler(void)
{ 
    uint32_t timeout = 0;
    uint32_t maxDelay = 0x1FFFF;
  
    HAL_UART_IRQHandler(&g_uart1_handle);       /* 调用HAL库中断处理公用函数 */

    timeout = 0;
    while (HAL_UART_GetState(&g_uart1_handle) != HAL_UART_STATE_READY) /* 等待就绪 */
    {
        timeout++;                              /* 超时处理 */
        if(timeout > maxDelay)
        {
            break;
        }
    }
     
    timeout=0;
    
    /* 一次处理完成之后,重新开启中断并设置RxXferCount为1 */
    while (HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK)
    {
        timeout++;                              /* 超时处理 */
        if (timeout > maxDelay)
        {
            break;
        }
    }

}

#endif

        Next, the second place to modify usart.c is the imported header file, because the related code of µC/OS has been deleted in the interrupt service function of the serial port, and the related code of FreeRTOS has not been used, so the usart. The header file about OS included in c is deleted, the code to be deleted is as follows:

/* 如果使用os,则包括下面的头文件即可 */
#if SYS_SUPPORT_OS
#include "os.h"                               /* os 使用 */
#endif

5.3、delay.c

        Next, modify the last file in the SYSTEM folder—delay.c, the delay.c file needs to be changed more, which can be roughly divided into three steps: delete the relevant code that is applicable to µC/OS but not applicable to FreeRTOS , Add the relevant code of FreeRTOS, and modify some content.

(1) Remove relevant code that works for µC/OS but not for FreeRTOS

        A total of 1 global variable, 6 macro definitions, and 3 functions need to be deleted. These codes to be deleted will be used when using µC/OS, but they do not need to be used when using FreeRTOS. The codes to be deleted are as follows:

static uint32_t g_fac_us = 0;       /* us延时倍乘数 */

/* 如果SYS_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS) */
#if SYS_SUPPORT_OS

/* 添加公共头文件 ( ucos需要用到) */
#include "os.h"

/* 定义g_fac_ms变量, 表示ms延时的倍乘数, 代表每个节拍的ms数, (仅在使能os的时候,需要用到) */
static uint16_t g_fac_ms = 0;

/*
 *  当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持
 *  首先是3个宏定义:
 *      delay_osrunning    :用于表示OS当前是否正在运行,以决定是否可以使用相关函数
 *      delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始化systick
 *      delay_osintnesting :用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行
 *  然后是3个函数:
 *      delay_osschedlock  :用于锁定OS任务调度,禁止调度
 *      delay_osschedunlock:用于解锁OS任务调度,重新开启调度
 *      delay_ostimedly    :用于OS延时,可以引起任务调度.
 *
 *  本例程仅作UCOSII的支持,其他OS,请自行参考着移植
 */

/* 支持UCOSII */
#define delay_osrunning     OSRunning           /* OS是否运行标记,0,不运行;1,在运行 */
#define delay_ostickspersec OS_TICKS_PER_SEC    /* OS时钟节拍,即每秒调度次数 */
#define delay_osintnesting  OSIntNesting        /* 中断嵌套级别,即中断嵌套次数 */


/**
 * @brief     us级延时时,关闭任务调度(防止打断us级延迟)
 * @param     无
 * @retval    无
 */
void delay_osschedlock(void)
{
    OSSchedLock();                      /* UCOSII的方式,禁止调度,防止打断us延时 */
}

/**
 * @brief     us级延时时,恢复任务调度
 * @param     无
 * @retval    无
 */
void delay_osschedunlock(void)
{
    OSSchedUnlock();                    /* UCOSII的方式,恢复调度 */
}

/**
 * @brief     us级延时时,恢复任务调度
 * @param     ticks: 延时的节拍数
 * @retval    无
 */
void delay_ostimedly(uint32_t ticks)
{
    OSTimeDly(ticks);                               /* UCOSII延时 */
}

/**
 * @brief     systick中断服务函数,使用OS时用到
 * @param     ticks : 延时的节拍数  
 * @retval    无
 */  
void SysTick_Handler(void)
{
    /* OS 开始跑了,才执行正常的调度处理 */
    if (delay_osrunning == OS_TRUE)
    {
        /* 调用 uC/OS-II 的 SysTick 中断服务函数 */
        OS_CPU_SysTickHandler();
    }
    HAL_IncTick();
}
#endif

(2) Add the relevant code of FreeRTOS

        Just use the extern keyword to import a FreeRTOS function —— xPortSysTickHandler() in the delay.c file. This function is used to process the FreeRTOS system clock beat. This tutorial uses SysTick as the heartbeat of the FreeRTOS operating system, so it needs Call this function in the SysTick interrupt service function, so add the code before the SysTick interrupt service function, and modify the code as follows:

void SysTick_Handler(void)
{
   代码省略
}
#endif

(3) Modify part of the content

        The last thing to modify includes two, including the header file and 4 functions. First look at the four functions that need to be modified, namely SysTick_Handler(), delay_init(), delay_us() and delay_ms().

(a) SysTick_Handler()

        This function is the interrupt service function of SysTick. In this function, the function xPortSysTickHandler() imported in the previous step needs to be called repeatedly. The modified code is as follows:

/**
 * @brief     systick中断服务函数,使用OS时用到
 * @param     ticks: 延时的节拍数
 * @retval    无
 */  
void SysTick_Handler(void)
{
    HAL_IncTick();
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) /* OS开始跑了,才执行正常的调度处理 */
    {
        xPortSysTickHandler();
    }
}

 (b) delay_init()

         The function delay_init() is mainly used to initialize SysTick. What should be explained here is that when the function vTaskStartScheduler() is subsequently called (this function will be analyzed in detail when explaining the FreeRTOS task scheduler below), FreeRTOS will initialize SysTick according to the configuration of the FreeRTOSConfig.h file, so delay_init( ) function initialized SysTick is mainly used before FreeRTOS starts task scheduling. The part to be modified in the function delay_init() is mainly the reload value of SysTick and the deletion of unused codes. The code modification is as follows:

void delay_init(uint16_t sysclk)
{
#if SYS_SUPPORT_OS                                      /* 如果需要支持OS */
    uint32_t reload;
#endif
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);/* SYSTICK使用内核时钟源,同CPU同频率 */
    g_fac_us = sysclk;                                  /* 不论是否使用OS,g_fac_us都需要使用 */
#if SYS_SUPPORT_OS                                      /* 如果需要支持OS. */
    reload = sysclk;                                    /* 每秒钟的计数次数 单位为M */
    reload *= 1000000 / configTICK_RATE_HZ;             /* 根据delay_ostickspersec设定溢出时间,reload为24位
                                                           寄存器,最大值:16777216,在168M下,约合0.099s左右 */
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;          /* 开启SYSTICK中断 */
    SysTick->LOAD = reload;                             /* 每1/delay_ostickspersec秒中断一次 */
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;           /* 开启SYSTICK */
#endif 
}

(c) delay_us()

        The function delay_us() is used for microsecond-level CPU busy delay. The original function delay_us() has added custom functions delay_osschedlock() and delay_osschedunlock() before and after the delay to lock and unlock the µC/OS task scheduler. This makes the delay more accurate. It is not necessary to add these two functions in FreeRTOS, but it should be noted that this will reduce the precision of the microsecond-level delay of the function delay_us(). The modified code of the function delay_us() is as follows:

void delay_us(uint32_t nus)
{
    uint32_t ticks;
    uint32_t told, tnow, tcnt = 0;
    uint32_t reload = SysTick->LOAD;        /* LOAD的值 */
    
    ticks = nus * g_fac_us;                 /* 需要的节拍数 */
    told = SysTick->VAL;                    /* 刚进入时的计数器值 */
    while (1)
    {
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            if (tnow < told)
            {
                tcnt += told - tnow;        /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */
            }
            else
            {
                tcnt += reload - tnow + told;
            }
            told = tnow;
            if (tcnt >= ticks) 
            {
                break;                      /* 时间超过/等于要延迟的时间,则退出 */
            }
        }
    }
} 

 (d) delay_ms()

        The function delay_ms() is used for millisecond-level CPU busy delay. The original function delay_ms() will judge whether µC/OS is running. If µC/OS is running, use µC/OS OS delay to perform millisecond-level delay. , otherwise call the function delay_us() to perform a millisecond-level CPU busy delay. In FreeRTOS, the function delay_ms() can be defined as only CPU busy delay. When OS delay is required, call the OS delay function vTaskDelay() provided by FreeRTOS (this will be explained later in the explanation of FreeRTOS time management. function analysis) to perform system tick-level delay, the modified code of the function delay_ms() is as follows:

void delay_ms(uint16_t nms)
{
    uint32_t i;

    for (i=0; i<nms; i++)
    {
        delay_us(1000);
    }
}

(e) Include the header

        According to the modification of the above steps, the related functions of FreeRTOS are used in the delay.c file, so it is necessary to include the related header files of FreeRTOS in the delay.c file, and remove the existing µC/OS related header files. First look at the µC/OS-related header files included in the delay.c file before modification:

/* 添加公共头文件 (FreeRTOS 需要用到) */
#include "FreeRTOS.h"
#include "task.h"

5.5. Modify the interrupt timer function

        During the transplantation of FreeRTOS, there will be these few to three important interrupts, namely the FreeRTOS system time base timer interrupt (SysTick interrupt), SVC interrupt, PendSV interrupt (SVC interrupt and PendSV interrupt are explained below. FreeRTOS interrupt and FreeRTOS task It will be analyzed in detail when switching), the interrupt service functions of these three interrupts are defined in the files provided by the HAL library, for the STM32 development boards with different punctual atoms, they correspond to different files, and the specific correspondence is shown in the following table:

STM32 series development board type of punctual atom The file where the interrupt service function is located
STM32F1 stm32f1xx_it.c
STM32F4 stm32f4xx_it.c
STM32F7 stm32f7xx_it.c
STM32H7 stm32h7xx_it.c

        Among them, the interrupt service function of SysTick has been defined in the delay.c file, and FreeRTOS also provides the interrupt service function of SVC and PendSV, so the three interrupt service functions provided by the HAL library need to be commented out, and the macro switch is used here In this way, the three interrupt service functions in the HAL library are not included in the compilation. The macros used are defined in sys.h, so it is also necessary to import the sys.h header file. Refer to the above table to find the corresponding file and modify it. After modification The code looks like this:

/*导入sys.h头文件*/
#include "./SYSTEM/SYS/sys.h"

#if(!SYS_SUPPORT_OS)
void SVC_Handler(void)
{
}
#endif


#if(!SYS_SUPPORT_OS)
void PendSV_Handler(void)
{
}
#endif

#if(!SYS_SUPPORT_OS)
void SysTick_Handler(void)
{
  HAL_IncTick();
}
#endif

        Finally, it is also the last place to be modified for porting FreeRTOS. The FreeRTOSConfig.h file has the following definition: #define configPRIO_BITS __NVIC_PRIO_BITS

        we need to

#define __NVIC_PRIO_BITS 4U

        changed to

#define __NVIC_PRIO_BITS 4

5.6. Optional steps

        This step is optional, but the author strongly recommends that readers complete it, because it will be used in subsequent experiments and standardize the project. This section can be divided into 3 small parts, which are respectively modifying the project target name, removing the USMART debugging component, and adding the timer driver.

1. Modify the project target name

        Change the previous basic project name to FreeRTOS

 2. Remove the USMART debugging component

 

 3. Add timer driver

        Since the basic timer peripherals of STM32 need to be used in subsequent experiments, it is necessary to add timer-related driver files to the project.

5.7. Add application

        After transplanting FreeRTOS, of course, it is necessary to test whether the transplantation is successful. In this step, a total of 1 file needs to be modified and 2 files added, the modified 1 file is main.c, and the added 2 files are freertos_demo.c and freertos_demo.h. For main.c, it mainly completes some hardware initialization in the main() function, and finally calls the freertos_demo() function in the freertos_demo.c file. And freertos_demo.c is used to write FreeRTOS related application code.

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SRAM/sram.h"
#include "./MALLOC/malloc.h"
#include "freertos_demo.h"
int main(void)
{
 HAL_Init(); /* 初始化 HAL 库 */
 sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
 delay_init(72); /* 延时初始化 */
 usart_init(115200); /* 串口初始化为 115200 */
 led_init(); /* 初始化 LED */
 lcd_init(); /* 初始化 LCD */
 key_init(); /* 初始化按键 */
 sram_init(); /* SRAM 初始化 */
 my_mem_init(SRAMIN); /* 初始化内部 SRAM 内存池 */
 my_mem_init(SRAMEX); /* 初始化外部 SRAM 内存池 */
 
 freertos_demo(); /* 运行 FreeRTOS 例程 */
}

Guess you like

Origin blog.csdn.net/zywcxz/article/details/131499260