赞
踩
笔记内容参考(正点原子的FreeRTOS开发手册、cortex-m3权威指南、Cortex-M3和Cortex-M4权威指南等)以及网络笔记
代码环境:CubeMX生成的FreeRTOS
FreeRTOS时间管理部分,主要是涉及系统节拍以及任务延时管理。
SysTick直属与 Coretx-M 内核,它不是 STM32 专属的,只要是 Cortex-M 内核的 MCU 就都有 SysTick。SysTick 定时器是个 24 位的向下计数器,这个计数器的使命就是为系统提供服务的。操作系统都需要一个系统时钟,每个系统时钟周期都会触发 OS 内核执行一些系统调用,比如进行任务管理、任务切换等。SysTick 就可以完成此功能,使能 SysTick 中断,设置好定时周期,SysTikc 就会周期性的触发中断,跟系统有关的操作就可以在 SysTick 的中断服务函数中完成。如果不使用系统的话 SysTick 也可以当作普通的定时器使用,完成简单的计时功能。SysTick 定时器被捆绑在 NVIC 中,用于产生 SysTick 异常(异常号:15)。
在文件 core_cm4.h 中用结构体 SysTick_Type 来描述这四个寄存器,结构体 SysTick_Type的定义如下:
#define SCS_BASE (0xE000E000UL)
#define SysTick_BASE (SCS_BASE + 0x0010UL)
typedef struct
{
__IOM uint32_t CTRL; //控制与状态寄存器
__IOM uint32_t LOAD; //自动重装载值寄存器
__IOM uint32_t VAL; //当前计数值寄存器
__IM uint32_t CALIB; //校准值寄存器
} SysTick_Type;
#define SysTick ((SysTick_Type *) SysTick_BASE)
实际使用中操作最多的是 CTRL、LOAD 和 VAL 这三个寄存器,CALIB 寄存器基本不会使用了。CTRL、LOAD 和 VAL 这三个寄存器各 bit 的描述如表 所示:
关于SysTick的设置[main.c --> osKernelStart() --> vTaskStartScheduler() --> xPortStartScheduler() --> vPortSetupTimerInterrupt() ]
/* * 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 ) )
在main函数里面引用了 SystemClock_Config(); 然后通过HAL_RCC_ClockConfig,更新了SystemCoreClock值
//代码其他都是删过得 /* 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]; }
FreeRTOS 中的时间延迟函数主要有以下两个作用:
函数 | 描述 |
---|---|
相对延时函数 | vTaskDelay() |
绝对延时函数 | vTaskDelayUntil() |
GET系统节拍 | xTaskGetTickCount() |
GET系统节拍(中断里面使用) | xTaskGetTickCountFromISR() |
函数原型 | 描述 |
---|---|
TickType_t xTaskGetTickCount( void ) | 获取系统当前运行的时钟节拍数。 |
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;
}
函数原型 | 描述 |
---|---|
TickType_t xTaskGetTickCountFromISR( void ) | 获取系统当前运行的时钟节拍数。(用于在中断服务程序) |
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; }
vTaskDelayUntil使用:
static void vTaskLED(void *pvParameters) { TickType_t xLastWakeTime; const TickType_t xFrequency = 200; /* 获取当前的系统时间 */ xLastWakeTime = xTaskGetTickCount(); while(1) { bsp_LedToggle(2); /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/ vTaskDelayUntil(&xLastWakeTime, xFrequency); } }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。