【Bug】FreeRTOS滴答定时器初始化及中断服务函数卡死

Bug1

在导入FreeRTOS库下,滴答定时器初始化时钟源为**SysTick_CLKSource_HCLK_Div8(即HCLK的八分频)**时,任务延时时间不准确,任务中vTaskDelay(1000)了1s,但是实际PC上通过串口助手查看接收到的串口数据时间间隔了8s


Reason1

CTRL寄存器的Bit2用于控制SysTick定时器的时钟源,0=AHB/8,1=AHB

通过Debug查看发现程序运行后SysTick的控制及状态寄存器CTRL 的Bit2位被置一,而我本来是想要初始化为0的,然后发现在开启任务调度器函数中会重新对SysTick定时器进行初始化,具体代码如下:

c 复制代码
// 626行对CTRL进行了设置
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 */

		/* 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 );
	}

在port.c的626行处对SysTick控制寄存器重新进行了写入,并根据宏portNVIC_SYSTICK_CLK_BIT来设置SysTick的时钟源选择,而该宏又根据下面的宏判断来设置值,代码如下:

c 复制代码
// 89行确定宏的值
#ifndef configSYSTICK_CLOCK_HZ
	#define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
	/* Ensure the SysTick is clocked at the same frequency as the core. */
	#define portNVIC_SYSTICK_CLK_BIT	( 1UL << 2UL )
#else
	/* The way the SysTick is clocked is not modified in case it is not the same
	as the core. */
	#define portNVIC_SYSTICK_CLK_BIT	( 0 )
#endif

依然是在port.c的第89行,此处根据是否定义了宏configSYSTICK_CLOCK_HZ 来确定宏portNVIC_SYSTICK_CLK_BIT 的值,如果定义了第一个宏,则给宏portNVIC_SYSTICK_CLK_BIT 赋值为0 ,即0x00,Bit2的值为0,如果没有定义该宏,则赋值为**( 1UL << 2UL ),即0x04,Bit2的值为1,最后该宏赋值给了上面的CTRL寄存器,以此来设置滴答定时器时钟源的选择
如果想设置SysTick的时钟源为HCLK/8,则必须定义
宏configSYSTICK_CLOCK_HZ**,这样宏portNVIC_SYSTICK_CLK_BIT的值才为0x00,才不会在开启调度器后CTRL寄存器的Bit2的值设置为1


Resolution1

SysTick的时钟源设置为HCLK/8,则需要定义宏configSYSTICK_CLOCK_HZ,定义为HCLK则不要定义该宏


Bug2

初始化完SysTick后程序卡死在中断服务函数SysTick_Handler


Reason2

SysTick_Handler中断服务函数执行代码:

c 复制代码
void SysTick_Handler(void)
{
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    {
        xPortSysTickHandler();	
    }
}

我是直接在stm32f10x_it.c中直接在中断服务函数中调用FreeRTOS中的中断处理函数,在编译时有一个警告内容如下:

...\USER\stm32f10x_it.c(153): warning: #223-D: function "xPortSysTickHandler" declared implicitly

当时没怎么在意这个警告,就没有去管了,并且之前的创建动静态时也有这个警告,不过在重新编译了一下后面就没再提示了,而且之前的程序也能正常实现任务调度

在这次做中断管理实验时发现,我只要在该函数上面include函数所在的头文件,并且extern该函数,程序又能正常运行了,具体添加代码如下:

c 复制代码
#include "FreeRTOS.h"
#include "task.h"	
extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{
		if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
		{
				xPortSysTickHandler();	
		}
}

这样程序又不会卡死在里面了,但是一但注释掉前三行,程序又卡死了,在之前的程序中没有前三行程序也正常调度,但在这次的实验中又必须添加进去程序才不会卡死,这个具体的原因还未知,猜测可能是编译器问题把有的时候能找到该函数有的时候找不到


Resolution2

在SysTick的中断服务函数所在的文件中,一定要导入FreeRTOS相关的头文件,防止程序找不到该函数导致卡死,在SysTick_Handler前加入以下三行代码:

c 复制代码
#include "FreeRTOS.h"
#include "task.h"	
extern void xPortSysTickHandler(void);

或者直接在FreeRTOSConfig.h中宏定义一下:

c 复制代码
#define xPortSysTickHandler		SysTick_Handler

这样当程序调用中断服务函数时会直接跳到FreeRTOS为我们写好的中断服务函数中,更加方便,但需要注意注释掉stm32f10x_it.c中的函数,防止冲突


相关推荐
LittleSeedling20 小时前
【bug】使用transformers训练二分类任务时,训练损失异常大
bug
何遇mirror20 小时前
【话题】Bug 故事:跨时区的时间转换错误
bug
蜡笔羊驼20 小时前
pyfftw BUG
bug
Evand J20 小时前
写的bug与调试
bug
dr李四维20 小时前
应用商店双弹窗“APP在向用户申请权限时未同步告知用户申请此权限的理由”驳回uni-app应用上线的解决方法
前端·javascript·笔记·uni-app·产品运营·bug·产品经理
代码唐1 天前
uniapp奇怪bug汇总
uni-app·bug
乄bluefox2 天前
SpringBoot中使用Sharding-JDBC实战(实战+版本兼容+Bug解决)
java·数据库·spring boot·redis·后端·缓存·bug
安和昂2 天前
【iOS】bug调试技巧
ios·bug·cocoa
明月与玄武2 天前
测试人员--如何区分前端BUG和后端BUG
bug·如何区分前端bug和后台bug
清水白石0082 天前
从一个“支付状态不一致“的bug,看大型分布式系统的“隐藏杀机“
java·数据库·bug