FreeRTOS porting on STM32 V1.0

Publisher:MysticMoonLatest update time:2016-09-26 Source: eefocusKeywords:FreeRTOS Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

As an open source lightweight real-time operating system, FreeRTOS not only implements basic real-time scheduling, semaphores, queues, and storage management, but also does not require licensing fees for commercial applications.

        The implementation of FreeRTOS mainly consists of four files: list.c, queue.c, croutine.c and tasks.c. list.c is an implementation of a linked list, mainly used by the kernel scheduler; queue.c is an implementation of a queue, supporting interrupt environment and semaphore control; croutine.c and task.c are the organization implementations of two types of tasks. For croutine, each task shares the same stack, further reducing the need for RAM, but because of this, its use is relatively strictly restricted. Task is a traditional implementation, each task uses its own stack and supports full preemptive scheduling.

         The main functions of FreeRTOS can be summarized as follows:
                    1) Priority scheduling, round-robin scheduling of tasks of the same priority, and can be set to preemptive or non-preemptive kernels
                    2) Tasks can choose whether to share stacks (co-routines & tasks), and there is no limit on the number of tasks
                    3) Message queues, binary semaphores, counting semaphores, recursive mutexes
                    4) Time management
                    5) Memory management

         Like UC/OSII, the porting of FreeRTOS to STM32 is roughly implemented by three files: a .h file defines compiler-related data types and macro definitions for interrupt processing; a .c file implements task stack initialization, system heartbeat management, and task switching requests; and a .s file implements specific task switching.

        In this transplantation, the compiler software used is IAR EWARM 5.2.
1. Implementation of the key parts of each file:

 

1. PORTMACRO.H Macro definition part
1) Define various compiler-related data types
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE unsigned portLONG
#define portBASE_TYPE long

2) Architecture-related definitions
The stack growth direction of Cortex-M3 is from high address to low address
#define portSTACK_GROWTH (-1)
The number of heartbeats per millisecond
#define portTICK_RATE_MS ((portTickType) 1000/configTICK_RATE_HZ)
The byte alignment for accessing SRAM
#define portBYTE_ALIGNMENT 8

3) Define two functions that users actively use to cause kernel scheduling
Force context switching, call
#define portYIELD() vPortYieldFromISR() in the task environment Force context switching, call #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) vPortYieldFromISR()
in the interrupt processing environment

4) Define the management function of the critical area
Interrupt enable and disable
#define portDISABLE_INTERRUPTS() vPortSetInterruptMask()
#define portENABLE_INTERRUPTS() vPortClearInterruptMask()
Critical area entry and exit
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
Used to enable and disable interrupts in the interrupt environment
#define portSET_INTERRUPT_MASK_FROM_ISR() 0;vPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask();(void)x

2. PORT.C C interface part
1) Stack initialization
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
 *pxTopOfStack = portINITIAL_XPSR; /* Program status register*/
 pxTopOfStack--;
 *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* Task entry point*/
 pxTopOfStack--;
 *pxTopOfStack = 0; /* LR */
 pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
 *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* Task parameters*/
 pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack;
}

2) Start task scheduling
portBASE_TYPE xPortStartScheduler( void )
{
 Let the task switching interrupt and heartbeat interrupt be at the lowest priority, so that higher priority can preempt the MCU
 *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
 *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;

 Set and start the system's heartbeat clock
 prvSetupTimerInterrupt();
 
 Initialize the number of nested critical sections
 uxCriticalNesting = 0;

 Start the first task
 vPortStartFirstTask();

 Execute to vPortStartFirstTask function, the kernel has started normal scheduling
 return 0;
}

3) Actively release the right to use the MCU
void vPortYieldFromISR( void )
{
 trigger the PendSV system service interrupt, and the interrupt will be handled by the assembly function xPortPendSVHandler() when it arrives
 *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}
When entering the critical section, first turn off the interrupt; when exiting all nested critical sections, enable the interrupt
void vPortEnterCritical( void )
{
 portDISABLE_INTERRUPTS();
 uxCriticalNesting++;
}
void vPortExitCritical( void )
{
 uxCriticalNesting--;
if( uxCriticalNesting == 0 )
 {
  portENABLE_INTERRUPTS();
 }
}
4) Heartbeat clock processing function
void xPortSysTickHandler( void )
{
unsigned portLONG ulDummy;

 If it is preemptive scheduling, first check whether there are any tasks that need to be scheduled
 #if configUSE_PREEMPTION == 1
  *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; 
 #endif

 ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
 { Process the clock counting and delay tasks through the heartbeat processing function vTaskIncrementTick() of task.c
  vTaskIncrementTick();
 }
 portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
}

3. PORTASM.S assembly processing part
1) Request to switch tasks
xPortPendSVHandler:
 Save the context of the current task to its task control block
 mrs r0, psp  
 ldr r3, =pxCurrentTCB Get the task control block pointer of the current task
 ldr r2, [r3]      

 stmdb r0!, {r4-r11} saves R4-R11 to the task stack
 str r0, [r2] saves the last stack pointer to pxTopOfStack of the task control block

 stmdb sp!, {r3, r14}
disable interrupt
 mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY 
 msr basepri, r0
switch task context, pxCurrentTCB already points to the new task

bl vTaskSwitchContext 
 mov r0, #0
 msr basepri, r0
 ldmia sp!, {r3, r14}
 Restore the context of the new task to each register
 ldr r1, [r3]     
 ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */
 ldmia r0!, {r4-r11} /* Pop the registers. */
 msr psp, r0      
 bx r14 
The schematic diagram of task switching is as follows:

2.) To enable and disable interrupts, use BASEPRI to mask the interrupt source of the corresponding priority level
vPortSetInterruptMask:
 push { r0 }
 mov R0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
 msr BASEPRI, R0
 pop { R0 }

 bx r14
 
vPortClearInterruptMask:
 PUSH { r0 }
 MOV R0, #0
 MSR BASEPRI, R0
 POP { R0 }

 bxr14

3) Directly switch tasks, used to initialize the stack and registers when vPortStartFirstTask starts the task for the first time
vPortSVCHandler;
 ldr r3, =pxCurrentTCB
 ldr r1, [r3]
 ldr r0, [r1]
 ldmia r0!, {r4-r11}
 msr psp, r0
 mov r0, #0
 msr basepri, r0
 orr r14, r14, #13
 bx r14

4) Start the assembly implementation of the first task
vPortStartFirstTask
 through the interrupt vector table to locate the stack address
 ldr r0, =0xE000ED08 vector table offset register (VTOR)
 ldr r0, [r0]
 ldr r0, [r0]
 msr msp, r0 save the stack address to the main stack pointer msp
 trigger SVC soft interrupt, vPortSVCHandler () to complete the specific switching work of the first task
 svc 0

The process of starting the FreeRTOS kernel scheduler is as follows:

The above three files implement the underlying interface required for FreeRTOS kernel scheduling, and the relevant code is very concise.

2. Create a test task:
Now create the first test task, LED test
int main( void )
{
 Set the system clock, interrupt vector table and GPIO used by LED
 using the initialization function provided by the stm32 firmware package. For details, see the relevant manual
 prvSetupHardware();
 
 Create 4 LED tasks vLEDFlashTask() through xTaskCreate().
Each task flashes according to its own frequency, corresponding to the 4 LEDs on the development board
     vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );

• After creating an IDLE task, start the scheduler through xPortStartScheduler
 vTaskStartScheduler();  return 0
 
 if the scheduler does not work properly ; }

portTASK_FUNCTION() is a function declaration defined by FreeRTOS, and has no special function
static portTASK_FUNCTION( vLEDFlashTask, pvParameters )
{
... omitted ..., specifically to calculate the flashing frequency of each LED
 for(;;)
 {
  vTaskDelayUntil( &xLastFlashTime, xFlashRate );
  vParTestToggleLED( uxLED );

  The delay time xFlashRate of vTaskDelayUntil() is calculated from the last delay time xLastFlashTime,
  which is more accurate than the direct delay of vTaskDelay().
  vTaskDelayUntil( &xLastFlashTime, xFlashRate );
  vParTestToggleLED( uxLED );
 }
}

The task creation of FreeRTOS is not much different from that of UC/OSII. The main parameters are task function, stack size and task priority. For example:
xTaskCreate( vLEDFlashTask, ( signed portCHAR * ) "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );

Next, create another LCD display task and run it at the lowest priority:
xTaskCreate( vLCDTask, ( signed portCHAR * ) "LCD", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );

void vLCDTask( void *pvParameters )
{
 ... omitted...
 for( ;; )
 {
  vTaskDelay(1000);
  printf("%c ", usDisplayChar);
 }
}
This task is very simple. It refreshes a number on the LCD every 1000 ticks (that is, 1000ms).

Keywords:FreeRTOS Reference address:FreeRTOS porting on STM32 V1.0

Previous article:STM32f103-Example wakeup from sleep mode
Next article:Two ways to implement SysTick

Recommended ReadingLatest update time:2024-11-16 22:36

STM32 I2C initialization function, not using STM32 library
STM32 I2C initialization function, not using the STM32 library method.     //================================================ ========================= // ADC_Configuration(void) //================== ================================================== ====== void STM32_I2C_Configuration(void) {    //GPIO_Ini
[Microcontroller]
IAR first downloads and unlocks the flash for the STM32 microcontroller
After the new board was soldered, I encountered this problem for the first time when compiling and downloading: Warning: Stack pointer is setup to incorrect alignment. Stack addr = 0xAAAAAAAA At first I thought it was a problem with the debugger. I used the SWD interface mode of Jlink. I changed to STLink but the prob
[Microcontroller]
IAR first downloads and unlocks the flash for the STM32 microcontroller
STM32 GPIO mode summary
8 working modes of GPIO 4 input modes Floating Input Pull-up input Pull-down input Analog Input 4 output modes Open-drain output Multiplexed open-drain output Push-pull output Multiplexed push-pull output 3 maximum output speeds 2MHz 10MHz 50MHz Floating input mode   1) External inpu
[Microcontroller]
Design and implementation of LED dot matrix screen based on STM32
In recent years, with the rapid development of the information industry, dot matrix LED display screens have been widely used in various advertising and information display systems such as the financial industry, postal and telecommunications industry, stadiums, and advertising industry, becoming an important means of
[Microcontroller]
Design and implementation of LED dot matrix screen based on STM32
STM32 TIM1 F1 four-channel fully remapped PWM configuration
void TIM1_PWM_Init(u16 arr,u16 psc) {   GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; TIM_OCInitTypeDef  TIM_OCInitStructure;   RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE);   RCC_APB2PeriphClockCmd(RCC_APB2P
[Microcontroller]
Understanding of STM32 NVIC
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);          NVIC_InitStructure.NVIC_IRQChannel = WAKEUP_BUTTON_EXTI_IRQn;    NVIC_InitStructure.NVIC_IRQChannelPreemptionPrio rity = PreemptionPriorityValue;    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
[Microcontroller]
STM32 Systick system tick timer
Systick: System heartbeat timer, providing system beat              Can be used as an independent delay timer in bare metal programs use: 1. Generate the clock beat of the operating system 2. Facilitate program porting between different processors The SysTick timer is tied to the NVIC, exception number 15 3. As an ala
[Microcontroller]
STM32 Systick system tick timer
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号