- Portal: Blog summary post
Note content reference (FreeRTOS Development Manual of punctual atom, authoritative guide of Cortex-M3, authoritative guide of Cortex-M3 and Cortex-M4, etc.) and network notes
Code environment: FreeRTOS generated by CubeMX (STM32F407)
outline
FreeRTOS time management part mainly involves system beat and task delay management.
- System beat: the operation of embedded real-time operating system must have clock beat, just like human heart. The clock beat of FreeRTOS is usually provided by SysTick,
- Task delay management: it mainly includes two delay functions (relative delay function vTaskDelay and absolute delay function vTaskDelayUntil)
1,SysTick
SysTick is directly related to the Coretx-M kernel. It is not exclusive to STM32. As long as it is the MCU of Cortex-M kernel, SysTick is available. SysTick timer is a 24 bit down counter whose mission is to provide services for the system. The operating system needs a system clock. Each system clock cycle will trigger the OS kernel to execute some system calls, such as task management, task switching, etc. SysTick can complete this function, enable SysTick interrupt, set the timing cycle, SysTikc will trigger the interrupt periodically, and the operations related to the system can be completed in SysTick's interrupt service function. If the system is not used, SysTick can also be used as an ordinary timer to complete a simple timing function. SysTick timer is bundled in NVIC to generate SysTick exception (exception No.: 15).
In the file core_ Systick structure used in CM4. H_ Type to describe the four registers, and the structure SysTick_Type is defined as follows:
#define SCS_BASE (0xE000E000UL) #define SysTick_BASE (SCS_BASE + 0x0010UL) typedef struct { __IOM uint32_t CTRL; //Control and status register __IOM uint32_t LOAD; //Automatic reload value register __IOM uint32_t VAL; //Current count value register __IM uint32_t CALIB; //Calibration value register } SysTick_Type; #define SysTick ((SysTick_Type *) SysTick_BASE)
CTRL, LOAD and VAL registers are the most operated registers in actual use, and CALIB register will not be used basically. The description of each bit of Ctrl, LOAD and VAL registers is shown in the table:
- The second bit of the CTRL register sets the SysTick clock source. 1 is the kernel clock. Generally, 1 is used, that is, the main frequency of the system (as shown in the figure below)
About SysTick settings [main. C -- > oskernelstart() -- > vtastartscheduler() -- > xportstartscheduler() -- > vportsetuptimerinthrupt()]
/* * Setup the SysTick timer to generate the tick interrupts at the required * frequency. */ #if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 ) __weak void vPortSetupTimerInterrupt( void ) { /* Calculate the constants required to configure the tick interrupt. */ #if( configUSE_TICKLESS_IDLE == 1 ) { ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ ); } #endif /* configUSE_TICKLESS_IDLE */ /* Stop and clear the SysTick. */ portNVIC_SYSTICK_CTRL_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; /* Configure SysTick to interrupt at the requested rate. */ portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT ); }
#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) )
- portNVIC_SYSTICK_CTRL_REG set SysTick parameters:
- portNVIC_SYSTICK_CLK_BIT: 168MHz using kernel clock
- portNVIC_SYSTICK_INT_BIT: open SysTick interrupt
- portNVIC_SYSTICK_ENABLE_BIT: enable SysTick
- portNVIC_SYSTICK_LOAD_REG set SysTick reload value:
- configSYSTICK_CLOCK_HZ: the final definition of this value is uint32_t SystemCoreClock = 16000000; 16 million here is the initial value, not the final value, because we have selected the kernel clock as the RTC clock source (168M), which will be modified during system initialization. As shown in the following code
- configTICK_ RATE_ If Hz is 100, the system beat clock cycle is 10ms, and the macro configtick is set_ RATE_ If Hz is 1000, the system beat clock cycle is 1ms. Too frequent Tick interrupt will lead to too frequent context switching and increase the system burden. Too long context switching will lead to untimely task response;
Systemclock is referenced in the main function_ Config(); Then through HAL_RCC_ClockConfig, updated systemcorelock value
//Other codes have been deleted /* Configure the system clock */ SystemClock_Config(); /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) } HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency) { /* Update the SystemCoreClock global variable */ SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR & RCC_CFGR_HPRE)>> RCC_CFGR_HPRE_Pos]; }
2. Time correlation function
The time delay function in FreeRTOS mainly has the following two functions:
- Provide delay for periodically executed tasks.
- For preemptive scheduler, high priority tasks can release CPU usage through time delay function, so that low priority tasks can be executed.
function | describe |
---|---|
Relative delay function | vTaskDelay() |
Absolute delay function | vTaskDelayUntil() |
GET system beat | xTaskGetTickCount() |
GET system beat (used in interrupt) | xTaskGetTickCountFromISR() |
2.1,xTaskGetTickCount
Function prototype | describe |
---|---|
TickType_t xTaskGetTickCount( void ) | Gets the number of clock ticks currently running in the system. |
TickType_t xTaskGetTickCount( void ) { TickType_t xTicks; /* Critical section required if running on a 16 bit processor. */ portTICK_TYPE_ENTER_CRITICAL(); { xTicks = xTickCount; } portTICK_TYPE_EXIT_CRITICAL(); return xTicks; }
2.2,xTaskGetTickCountFromISR
Function prototype | describe |
---|---|
TickType_t xTaskGetTickCountFromISR( void ) | Gets the number of clock ticks currently running in the system. (used to interrupt the service program) |
TickType_t xTaskGetTickCountFromISR( void ) { TickType_t xReturn; UBaseType_t uxSavedInterruptStatus; /* RTOS ports that support interrupt nesting have the concept of a maximum system call (or maximum API call) interrupt priority. Interrupts that are above the maximum system call priority are kept permanently enabled, even when the RTOS kernel is in a critical section, but cannot make any calls to FreeRTOS API functions. If configASSERT() is defined in FreeRTOSConfig.h then portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion failure if a FreeRTOS API function is called from an interrupt that has been assigned a priority above the configured maximum system call priority. Only FreeRTOS functions that end in FromISR can be called from interrupts that have been assigned a priority at or (logically) below the maximum system call interrupt priority. FreeRTOS maintains a separate interrupt safe API to ensure interrupt entry is as fast and as simple as possible. More information (albeit Cortex-M specific) is provided on the following link: https://www.freertos.org/RTOS-Cortex-M3-M4.html */ portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR(); { xReturn = xTickCount; } portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); return xReturn; }
2.3 vtask delay and vtask delayuntil
- Relative delay means that each delay starts from the task execution function vtask delay() and ends at the specified time
- Absolute delay means that the task calling vTaskDelayUntil() runs every x time. That is, the task cycle runs.
vTaskDelayUntil uses:
static void vTaskLED(void *pvParameters) { TickType_t xLastWakeTime; const TickType_t xFrequency = 200; /* Gets the current system time */ xLastWakeTime = xTaskGetTickCount(); while(1) { bsp_LedToggle(2); /* vTaskDelayUntil Is the absolute delay and vtask delay is the relative delay.*/ vTaskDelayUntil(&xLastWakeTime, xFrequency); } }