【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中的函数,防止冲突


相关推荐
腾飞的信仰2 天前
如何快速解决程序中的BUG
bug
Everglowwwwww2 天前
【bug】通过lora方式微调sdxl inpainting踩坑
学习·计算机视觉·ai作画·stable diffusion·bug
数据最前线2 天前
创建索引遇到这个Bug,19c中还没有修复
oracle·bug
CV金科2 天前
蓝桥杯-STM32G431RBT6(UART解析字符串sscanf和解决串口BUG)
c语言·stm32·单片机·嵌入式硬件·mcu·算法·bug
DisonTangor2 天前
网传阿里云盘出现bug,可看到其他用户云盘图片
阿里云·bug
后端小张2 天前
System.out源码解读——err 和 out 一起用导致的顺序异常Bug
java·开发语言·jdk·bug
我又来搬代码了3 天前
【Android】【Bug】Activity全屏(保留底部按钮)被打断变成非全屏了
android·bug
__water3 天前
『功能项目』调整Boss技能bug【51】
c#·bug·unity引擎
johnny2333 天前
《Effective Debugging:软件和系统调试的66个有效方法》读书笔记-Part2
bug
曲大家4 天前
Java和西门子S7-1200通讯调试记录
bug