FreeRTOS的基础时钟

编程入门 行业动态 更新时间:2024-10-25 10:31:10

FreeRTOS的基础<a href=https://www.elefans.com/category/jswz/34/1769919.html style=时钟"/>

FreeRTOS的基础时钟

在STM32CubeMX启用FreeRTOS后,在导出代码时会出现一个如图4所示的对话框。提示在使用FreeRTOS时,强烈建议将HAL的基础时钟设置为非SysTick定时器。在前面的示例中,我们都是将HAL的基础时钟设置为定时器TIM6,但并未详细说明这么做的原因。

在前一节已经介绍了HAL基础时钟的作用,以及使用SysTick定时器或TIM6定时器作为HAL基础时钟时的工作原理。通过前面章节对FreeRTOS的介绍,也知道了FreeRTOS需要使用SysTick定时器作为其基础时钟,以产生FreeRTOS的嘀嗒信号,在SysTick的定时中断里进行任务状态检查,需要时发出任务调度申请。

图4 在使用FreeRTOS时提示需要使用非SysTick定时器作为HAL基础时钟源

那么,在使用FreeRTOS时,如果在图4的对话框中点击“Yes”,执意使用SysTick作为HAL的基础时钟,生成的代码编译后能否正常运行呢?如果使用了TIM6作为HAL的基础时钟,FreeRTOS是如何对SysTick进行初始化,如何对SysTick的中断进行处理的呢?

对于第一个问题,如果在图4的对话框中点击“Yes”,执意使用SysTick作为HAL的基础时钟,生成的代码编译后是无法正常运行的,即使FreeRTOS只有一个非常简单的任务。这种情况下FreeRTOS就没有基础时钟,无法产生嘀嗒信号,所以无法正常运行,其代码方面的原因在后面解释。

所以,在使用FreeRTOS时,必须为HAL设置一个非SysTick定时器作为HAL的基础时钟,SysTick将自动作为FreeRTOS的基础时钟。这是FreeRTOS的移植决定的,因为SysTick是Cortex-M内核的一个定时器,在整个STM32系列中都是存在的,使用SysTick作为滴答时钟进行移植显然适用性更强,针对不同系列的STM32处理器移植时需要的改动可以最小化。

1. SysTick定时器的初始化

在STM32CubeMX中基于STM32F407ZG创建一个项目,使用TIM6作为HAL的基础时钟,启用FreeRTOS后NVIC的自动设置结果如图5所示。定时器TIM6的抢占优先级为0,SysTick和PendSV中断的优先级都设置为15,而且这3个中断都不能被关闭,不能修改优先级。

图5 启用FreeRTOS,并使用TIM6作为HAL的基础时钟后的NVIC设置

在FreeRTOS中,系统嘀嗒信号的频率由参数configTICK_RATE_HZ决定,默认值是1000Hz。SysTick通过定时中断产生嘀嗒信号,SysTick默认定时周期是1ms。

在main()函数中,执行函数osKernelStart()启动内核时对SysTick定时器进行初始化设置。跟踪函数osKernelStart()的代码,发现最终设置SysTick定时器的是文件port.c中的函数xPortStartScheduler()和vPortSetupTimerInterrupt()。函数xPortStartScheduler()中设置SysTick和PendSV中断的中断优先级,函数vPortSetupTimerInterrupt()设置SysTick的定时周期,代码如下:

	// 设置systick 定时器,产生需要频率的嘀嗒中断__attribute__(( weak )) void vPortSetupTimerInterrupt( void ){/* 计算用于配置嘀嗒中断的需要的常数 */#if( configUSE_TICKLESS_IDLE == 1 )     //Tickless低功耗模式,正常情况下为0{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 *//*停止和清除SysTick的控制寄存器和计数值寄存器 */portNVIC_SYSTICK_CTRL_REG = 0UL;portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;/* 配置SysTick,使其以设定的频率产生中断*/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 );}

函数vPortSetupTimerInterrupt()的功能是配置SysTick定时器相关的寄存器,使其以设定的频率产生中断。当参数configUSE_TICKLESS_IDLE的值等于1的时候,也就是使用了Tickless低功耗模式的时候会计算几个常数,这几个常数会在Tickless低功耗模式的时候用于嘀嗒计数值的补偿。

函数中用到的portNVIC_SYSTICK_CTRL_REG、portNVIC_SYSTICK_LOAD_REG等宏是SysTick相关寄存器的移植定义,在文件port.c中的定义时:

	#define portNVIC_SYSTICK_CTRL_REG			( * ( ( volatile uint32_t * ) 0xe000e010 ) )#define portNVIC_SYSTICK_LOAD_REG			( * ( ( volatile uint32_t * ) 0xe000e014 ) )#define portNVIC_SYSTICK_CURRENT_VALUE_REG	( * ( ( volatile uint32_t * ) 0xe000e018 ) )

查阅Cortex-M4内核技术手册会发现,这3个宏对应的就是SysTick的控制和状态寄存器SYST_CSR、重载值寄存器SYST_RVR和当前值寄存器SYST_CVR。

2. SysTick定时器的中断处理

在使用TIM6作为HAL基础时钟,启用了FreeRTOS的项目中,会发现在文件stm32f4xx_it.c中没有SysTick中断ISR函数SysTick_Handler()的代码框架。而FreeRTOS要使用SysTick的定时中断产生嘀嗒信号,必然是要定义ISR函数的。搜索关键字SysTick_Handler,发现在文件FreeRTOSConfig.h中有如下的宏定义:

	/*  将FreeRTOS 移植的中断处理函数映射到CMSIS 的标准ISR函数名  */#define vPortSVCHandler     SVC_Handler#define xPortPendSVHandler  PendSV_Handler/* 重要提示: 在使用STM32Cube时,如果HAL的基础时钟被设置为SysTick,下面的定义会被注释,以免覆盖HAL定义的ISR函数SysTick_Handler  */#define xPortSysTickHandler SysTick_Handler

通过这3个宏定义,FreeRTOS将自己移植的3个中断的处理函数与CMSIS的标准ISR函数名关联起来。例如,SysTick中断的标准ISR函数名是SysTick_Handler,FreeRTOS移植的函数名就是xPortSysTickHandler。

源代码中有英文注释特别强调,如果将HAL的基础时钟设置为SysTick,那么第3个宏定义是会被注释掉的,以免覆盖HAL定义的ISR函数SysTick_Handler。但是,这种情况下FreeRTOS就没有基础时钟了,不会产生嘀嗒信号,所以FreeRTOS就无法正常运行了。

FreeRTOS移植的SysTick中断的处理函数xPortSysTickHandler()是在文件port.c中定义的,其功能是调用函数xTaskIncrementTick()使嘀嗒信号计数值递增,并且检查是否需要进行上下文切换。如果需要进行上下文切换,就将PendSV中断挂起,实际的上下文切换是在PendSV的中断处理程序里执行的。函数xTaskIncrementTick()的代码如下。

	void xPortSysTickHandler( void ){portDISABLE_INTERRUPTS();{/* 将RTOS嘀嗒计数值递增,并检查是否需要进行上下文切换 */if( xTaskIncrementTick() != pdFALSE ){/*使PendSV中断挂起,请求上下文切换,上下文切换在PendSV中断里执行 */portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;}}portENABLE_INTERRUPTS();}

其中调用的函数xTaskIncrementTick()是在文件task.c中实现的,文件task.c中定义了一个表示嘀嗒信号当前计数值的全局变量xTickCount,函数xTaskIncrementTick()的一个功能就是每次使xTickCount的值加1,在计算延时的时候就会用到全局变量xTickCount。

前一篇 使用SysTick作为HAL的基础时钟

主题   HAL和FreeRTOS的基础时钟

更多推荐

FreeRTOS的基础时钟

本文发布于:2024-02-12 08:32:42,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1686980.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:时钟   基础   FreeRTOS

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!