SoFunction
Updated on 2025-04-14

FreeRTOS real-time operating system porting process on Cortex-M3

1. File structure of FreeRTOS download package

You can download the latest version of FreeRTOS package from the official FreeRTOS website. I am using V8.2.3 here.

The total number of files in the download package is daunting, but the file structure is simple."FreeRTOS Getting Started Guide"Section 3 of the article describes the download package file structure in detail, and we will just briefly mention it here.

The root directory of the download package contains two subdirectories: FreeRTOS and FreeRTOS-Plus. Among them, the FreeRTOS-Plus folder contains some FreeRTOS+ components and sample programs (most components are charged). We do not understand more about the contents under this folder, and focus on the FreeRTOS folder.

The FreeRTOS folder contains two subdirectories: Demo and Source. Among them, the Demo contains the project files for the sample program, and the Source contains the real-time operating system source code files.

The FreeRTOS real-time operating system kernel contains only three necessary files, and there are three optional files. The RTOS core code is located in three source files, namely, and. These three files are located in the FreeRTOS/Source directory. There are 3 optional files in the same directory, called event_groups.c and, which are used for software timers, event groups and coroutines respectively.

For supported processor architectures, RTOS requires some code related to the processor architecture. It can be called the RTOS hardware interface layer, which is located in the FreeRTOS/Source/Portable/[Relevant Compiler]/[Relevant Processor Architecture] folder. This time we are going to port to Cortex-M3 microcontroller and use the Keil MDK compiler, so the required RTOS hardware interface code is located in the FreeRTOS\Source\portable\RVDS\ARM_CM3 folder.

Stack allocation also belongs to the hardware interface layer (porting layer), and has various types of stack allocation schemes under the FreeRTOS/Source/portable/MemMang folder. Here we use the stack allocation scheme provided by heap_1.c. About FreeRTOS's memory management, follow-upFreeRTOS memory management analysisThe article will introduce the characteristics and usage of FreeRTOS memory management in detail.FreeRTOS Advanced Memory Management Example Completely AnalyzedThis article will analyze the specific implementation of FreeRTOS memory management from the source code level. There is no need to worry about it here. You can also quickly browse these two articles. There may be many things you don’t understand in it, but don’t worry, let them go first.

The Demo folder under the FreeRTOS folder also includes various performance example programs, involving processors of multiple architectures and multiple compilers. Most of the sample program codes under the FreeRTOS/Demo/Common/Minimal folder are applicable to all ported hardware interfaces. The code under the FreeRTOS/Demo/Common/Full folder is a historical code and is only used in the PC porting layer.

2. Some preparations before transplantation

A hardware board with a Cortex-M3 microprocessor and ensures that the board can operate normally. Download the FreeRTOS package ("FreeRTOS version history update historyThere is a download address in the article "》, which is a mirror file I made on the download channel. You can download it at the official website. Download CMSIS-M3, in fact, you mainly need the core_cm3.h file inside (you can go to ARM official download. If you install keil 5 or a newer Keil 4 MDK compiler, you can also find it in the directory: Keil\ARM\CMSIS folder)

3. Transplantation process

3.1 Adding RTOS core code

Add these three kernel codes to the project, and add the two processor-related codes to the project, and add the two processor-related codes to the project. Located in the FreeRTOS\Source\portable\RVDS\ARM_CM3 folder, heap_1.c is located in the FreeRTOS/Source/portable/MemMang folder.

3.2 Add header file path

 ...\FreeRTOS\Source\portable\RVDS\ARM_CM3 

…\FreeRTOS\Source\include

3.3 Writing a file

For users who are new to FreeRTOS, the easiest way is to find a similar demo project, copy the files under the project, and modify them based on this. Detailed configuration instructions will be followedFreeRTOS kernel configuration instructionsAs given in the article, there is still no need to worry about it.

3.4 Write some hook functions

If you set configUSE_TICK_HOOK=1 in it, you must write the voidvApplicationTickHook( void ) function. This function uses time slice interrupts to easily implement a timer function. For details, please refer to the subsequent article FreeRTOS kernel configuration instructions. The section on the macro configUSE_TICK_HOOK.

If you set configCHECK_FOR_STACK_OVERFLOW=1 or =2 in it, you must write the voidvApplication*Hook(xTaskHandle pxTask, signed char *pcTaskName) function, which is used to detect stack overflow. For details, please refer to the subsequent article FreeRTOS kernel configuration instructions for the macro configCHECK_FOR_STACK_OVERFLOW section.

3.5 Check the hardware

In order to verify whether your hardware board works reliably, first write a small program slice, such as flashing an LED light or sending a character, etc. We use UART to send a character. The code looks like this (assuming you have configured the startup code and configured the UART correctly):

       #include""
       #include""
       #include""
       #include""   
       #include""
       int main(void)
       {
           init_rtos_debug();           //Initialize the debug serial port           MAP_UARTCharPut('A');        //Send a character           while(1);
       }

If the hardware can send characters normally, the hardware and the startup code are OK, you can proceed to the next step.

3.6 Mounting interrupt

Under Cortex-M3 hardware, FreeRTOS uses SysTick as the system beat clock and uses SVC and PendSVC for context switching. The exception interrupt service code is located in the file. The author of FreeRTOS has written these codes for CPUs of various architectures and can be used directly. What the user needs to do is simply attach these exception interrupt entry addresses to the startup code.

In, use the IMPORT keyword to declare the name of the exception interrupt service function to be attached, and then:

         DCD     SVC_Handler            Change to:   DCD     vPortSVCHandler
         DCD     PendSV_Handler         Change to:   DCD     xPortPendSVHandler
         DCD     SysTick_Handler        Change to:   DCD     xPortSysTickHandler

3.7 Create the first task

In step 3.5, in order to test whether the hardware can work, we wrote a small function that sends characters. Here we will use this small function as the main code for our first task to execute: send a character every 1 second. The code looks like this:

   void vTask(void *pvParameters)
   {
        while(1)
        {
            MAP_UARTCharPut(0x31);
            vTaskDelay(1000/portTICK_RATE_MS);
        }
   }

FreeRTOS tasks and writing formats will be in subsequent articlesFreeRTOS Task OverviewAs mentioned in detail in the article, this is just a very simple task, and you will have a general impression first. There is an API function vTaskDelay() in it. This function is used for delay. The specific usage will be in subsequent articlesFreeRTOS task controlIn detail, the code-level analysis of delay function will be in the tenth chapterFreeRTOSSystem beat clock analysisSystem beat clock analysis. There is no need to pay attention to too many unknown situations here, because these unknown spaces will be explored bit by bit later.

3.8 Set the beat clock

Here we use the SysTick timer as the system's beat clock, setting a beat interrupt every 10ms. Since FreeRTOS has done a lot of work on porting, we only need to configure the following two macro definitions in it:

configCPU_CLOCK_HZ&& (/*Your hardware platform CPU system clock, Fcclk*/)

configTICK_RATE_HZ&&& ((portTickType)100) &

The first macro defines the CPU system clock, which is the frequency at which the CPU executes. The second macro defines the time slice frequency of FreeRTOS, which is defined here as 100, indicating that RTOS can switch 100 tasks in one second, that is, each time slice is 10ms.

In the function vPortSetupTimerInterrupt() sets the beat clock. This function calculates the reload value register of the SysTick timer based on the parameters defined by the two macros above, and then sets the control and status registers of the SysTick timer, and sets the following: Use the kernel clock source, enable interrupts, and enable SysTick timer. In addition, the function vPortSetupTimerInterrupt() is called by the function vTaskStartScheduler(), which is used to start the scheduler.

3.9 Set interrupt priority related macros

This is particularly important because interrupt priority and interrupt nesting are involved. Here is a configuration example based on Cortex-M3 hardware (lpc177x_8x series microcontrollers), in which:

Follow-up articlesFreeRTOS kernel configurationThe instructions will introduce the meaning of these macros in detail. For the Cortex-M kernel, follow-up articlesNotes on using the FreeRTOS Cortex-M kernelIn this article, you will talk about the connection between these macros and hardware. At that time, you will definitely know what impact the numbers defined by these macros will have on your hardware. Now, we just need to know that they are important enough that no one can become fat in one bite.

3.10 Setting other macros

You also need to set up some necessary macros, which are as follows:

#define configUSE_PREEMPTION 1 //Configure as 1 to use preemptive kernel, configure as 0 to use time slices#define configUSE_IDLE_HOOK 0 //Set 1 to use an idle hook; set to 0 to not use an idle hook#define configMAX_PRIORITIES ( 5 ) //The number of priority levels available in the application task#define configUSE_TICK_HOOK 0 //Set to 1 to use the time slice hook, set to 0 not to use#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 80 ) // Minimum free stack#define configTOTAL_HEAP_SIZE         ( ( size_t ) ( 5 * 1024 ) )   //The kernel is available in totalRAM

3.11 Create a task

Call the API function provided by FreeRTOS to create a task, the code is as follows:

xTaskCreate(vTask,"Task1",50,NULL,1,NULL);

About the detailed task creation API function, it will be found in subsequent articlesFreeRTOS task creation and deletionIntroduced in the article.

3.12 Turn on the scheduler

Call the API function provided by FreeRTOS to start the scheduler, the code is as follows:

vTaskStartScheduler();

Regarding the detailed opening scheduler API function, it will be in the 13th chapter of the subsequent articleFreeRTOS kernel controlIntroduced in the article.

The main function code at this time is as follows:

     int main(void)
     {
         init_rtos_debug();                             //Initialize the debug serial port          xTaskCreate(vTask,"Task1",50,NULL,1,NULL);
          vTaskStartScheduler();
          while(1);   
       }

4. Summary

At this point, a most basic FreeRTOS application has already started running, connecting the hardware board to the PC's RS232 serial port, and it can be observed that every second, the board will send a specified character to the PC.

Looking back at the porting process, how easy it is to port FreeRTOS to Cortex-M3 hardware. This is thanks to the designers of FreeRTOS that have done a lot of work for porting. At the same time, the new generation of Cortex-M3 hardware has also added some convenience features to the operating system, such as SysTick timer and brand new interrupts and exceptions.

However, the success of transplantation is only the first step in the Long March, because this is just the simplest application. We are not clear about the mechanism behind FreeRTOS, the appearance of the scheduling algorithm, and even the semaphore. Judging from the transplant process of this article, we have also deliberately ignored many details, such as what is the significance of the macros in the file? What impact will the changes have on RTOS? For example, the details of the FreeRTOS task API, the details of the scheduling API, and how to allocate the memory of FreeRTOS? How to do stack overflow checks and more.

So, don’t be complacent first, the tortuous road is far from here.

Many of the following articles will give detailed explanations around this simplest transplant routine, and we must take out the details deliberately hidden in this article one by one. This will continue until we introduce communication mechanisms such as queues, semaphores, and mutexes.

I hope everyone will support me in the future!