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