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).
Previous article:STM32f103-Example wakeup from sleep mode
Next article:Two ways to implement SysTick
Recommended ReadingLatest update time:2024-11-16 22:36
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- [RVB2601 Creative Application Development] User Experience 03 -- System Timer
- CH224 Preliminary Function Test
- [RVB2601 Creative Application Development] User Experience 07 -- Code Tracking Based on NTP
- [2022 Digi-Key Innovation Design Competition] - Intelligent Animal Identification System Based on Raspberry Pi
- CC2652RB SimpleLink Crystal-less BAW Multi-Protocol 2.4GHz Wireless MCU
- SIMCOM's low-cost GPRS module, experience in efficient data transmission in vehicle terminals
- EEWORLD University Hall----[High Precision Laboratory] Interface: 9 USB
- Switching Power Supply SPICE Simulation and Practical Design
- Analyzing the basic steps of FPGA power supply design
- [RVB2601 Creative Application Development] Audio Playback