【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定时器进行初始化,具体代码如下:

// 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的时钟源选择,而该宏又根据下面的宏判断来设置值,代码如下:

// 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中断服务函数执行代码:

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该函数,程序又能正常运行了,具体添加代码如下:

#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前加入以下三行代码:

#include "FreeRTOS.h"
#include "task.h"	
extern void xPortSysTickHandler(void);

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

#define xPortSysTickHandler		SysTick_Handler

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值