本文参考资料《ARM Cortex™-M4F技术参考手册》-4.5章节SysTick Timer(STK),和4.48章节SHPRx,其中STK这个章节有SysTick的简介和寄存器的详细描述。因为SysTick是属于CM4内核的外设,有关寄存器的定义和部分库函数都在core_cm4.h这个头
文件中实现。所以学习SysTick的时候可以参考这两个资料,一个是文档,一个是源码。
SysTick简介
SysTick——系统定时器是属于CM4内核中的一个外设,内嵌在NVIC中。系统定时器是一个24bit的向下递减的计数器,计数器每计数一次的时间为1/SYSCLK,一般我们设置系统时钟SYSCLK等于168M。当重装载数值寄存器的值递减到0的时候,系统定时器就产生一次中断,以此循环往复。
因为SysTick是属于CM4内核的外设,所以所有基于CM4内核的单片机都具有这个系统定时器,使得软件在CM4单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。
SysTick寄存器介绍
SysTick——系统定时有4个寄存器,简要介绍如下。在使用SysTick产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用。
表1.SysTick寄存器汇总
寄存器名称 | 寄存器描述 |
CTRL | SysTick控制及状态寄存器 |
LOAD | SysTick重装载数值寄存器 |
VAL | SysTick当前数值寄存器 |
CALIB | SysTick校准数值寄存器 |
表2. SysTick控制及状态寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
16 | COUNTFLAG | R/W | 0 | 如果在上次读取本寄存器后,SysTick已经计到了0,则该位为1 |
2 | CLKSOURCE | R/W | 0 | 时钟源选择位,0:AHB/8,1:处理器时钟AHB |
1 | TICKINT | R/W | 0 | 1:SysTick倒数计数到0时产生SysTick异常请求;0:数到0时无动作。也可以通过读取COUNTFLAG标志位来确定计数器是否递减到0 |
0 | ENABLE | R/W | 0 | SysTick定时器的使能位 |
表3. SysTick重装载数值寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
23:00 | CURRENT | R/W | 0 | 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG标志 |
SysTick属于内核的外设,有关的寄存器定义和库函数都在内核相关的库文件core_cm4.h中。
SysTick配置库函数
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
// 不可能的重装载值,超出范围
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL);
}
/* 设置重装载寄存器 */
SysTick->LOAD = (uint32_t)(ticks - 1UL);
/* 设置中断优先级0x0F */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
/* 设置当前数值寄存器的值为0 */
SysTick->VAL = 0UL;
/* 设置系统定时器的时钟源为AHB_CLK=168MHz
* 使能系统定时器中断
* 使能定时器
*/
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
/* 正常情况返回0 */
return (0UL);
}
用固件库编程的时候我们只需要调用库函数SysTick_Config()即可,形参ticks用来设置重装载寄存器的值,最大不能超过重装载寄存器的值,当重装载寄存器的值递减到0的时候产生中断,然后重装载寄存器的值又重新装载往下递减计数,以此循环往复。紧随其后设置好中断优先级,最后配置系统定时器的时钟为168M,使能定时器和定时器中断,这样系统定时器就配置好了,一个库函数搞定。
SysTick_Config()库函数主要配置了SysTick中的三个寄存器:LOAD、VAL和CTRL,有关具体的部分看代码注释即可。其中还调用了固件库函数NVIC_SetPriority()来配置系统定时器的中断优先级,该库函数也在core_m4.h中定义,原型如下:
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if ((int32_t)IRQn < 0)
{
SCB->SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}else
{
NVIC->IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}
}
因为SysTick属于内核外设,跟普通外设的中断优先级有些区别,并没有抢占优先级和子优先级的说法。在STM32F407中,内核外设的中断优先级由内核SCB这个外设的寄存器:SHPRx(x=1.2.3)来配置。有关SHPRx寄存器的详细描述可参考《Cortex-M4内核编程手册》4.4.8章节。
本文完结!