1. 前言
滴答定时器是cortex内核中的内置定时器,是一个24bit的向下计数定时器。本篇将会介绍滴答定时器的相关寄存器及其配置,实现一个ms级别的延时,通过LED的闪烁来验证,所以需要将LED的驱动移植到本次的工程中。
2. Cortex-M3的滴答定时器
本章节主要介绍cortex-m3内核的滴答定时器的相关寄存器,参考手册《Cortex-M3 Devices Generic User Guide》。
2.1 控制和状态寄存器SYST_CSR
Bits | 名词 | 描述 |
---|---|---|
[31:17] | \ | 保留位 |
[16] | COUNTFLAG | 如果滴答定时器的计数值计数到0,那么读取这一位的话就会返回1 |
[15:3] | \ | 保留位 |
[2] | CLKSOURCE | 滴答定时器的时钟源:0=外部时钟;1=处理器时钟 |
[1] | TICKINT | 使能滴答定时器的异常请求:0=计数到0时不产生SysTick异常请求;1=计数到0会产生异常请求; |
[0] | ENABLE | 使能计数器:0=关闭计数器;1=开启计数器 |
这个寄存器可以设置滴答定时器的时钟源、中断使能及其本身的使能或者关闭,还可以从这个寄存器读取到其是否计数到0。我们需要首先选择这个定时器的时钟源,然后再来使能中断和开启计数器。
- 滴答定时器的时钟源
从寄存器的描述可以看到,滴答定时器有两种时钟源:处理器的时钟或者外部时钟。处理器的时钟没啥好说的,我们将处理器的时钟设置为多少,滴答定时器的时钟就是多少,而外部时钟是什么呢?
滴答定时器的外部时钟是芯片设计厂商,我们来看一下灵动微的MM32F3270给滴答定时器设计的外部时钟是怎样的。在MM32F3270的用户手册时钟树那里前面可以看到:
在MM32F3270处理器中,内核的滴答定时器时钟的外部时钟源还可以是AHB总线时钟8分频后的时钟。
通常我们会将这个寄存器的值初始化的时候设置为0x7,时钟是处理器的时钟,且使能中断,开启计数器。
2.2 预装载值寄存器SYST_RVR
Bits | 名称 | 作用 |
---|---|---|
[31:24] | \ | 保留位 |
[23:0] | RELOAD | 预装载值,滴答定时器从这个值开始向下计数,计数到0后在下一个周期重新从这个值开始计数 |
滴答定时器是一个24bit的向下计数器,所以其预装载寄存器可以设置的位数也只有低24bits,最大可以设置的值是0xFFFFFF=16777215。
假设我们期望滴答定时器每隔1ms进入一次中断,也就是让滴答定时器在其时钟频率下开始向下计数RELOAD这么多次需要耗费的时间是1ms,设滴答定时器的时钟=xMHz,那么reload的值就应该是xMHz/1kHz =xK。比如MM32F3270处理器的AHB总线时钟是120MHz,那么只需要将reload的值设置为120k就可以让滴答定时器每隔1ms进入一次中断,而120k是小于16777215的,是合法的值。
2.3 当前计数值寄存器SYST_CVR
Bits | 名称 | 描述 |
---|---|---|
[31:24] | Reserved | 保留位 |
[23:0] | CURRENT | 当前计数值 |
这个寄存器很简单,就是表明滴答定时器当前的计数值是多少,可读可写。
2.4 校准值寄存器SYST_CALIB
Bits | 名称 | 作用 |
---|---|---|
[31] | NOREF | 表明设备是否给处理器提供了支持的时钟信号,0=提供了;1=未提供;如果没有提供支持的时钟,那么滴答定时器的时钟源默认选择系统时钟且对CLKSOURCE那一位的写操作将会被忽略; |
[30] | SKEW | 表明TENMS值是否是正确的:0=正确;1=异常 |
[29:24] | - | 保留位 |
[23:0] | TENMS | 复位重载值是100ms,用作系统时钟的偏差。如果这个值读出来是0,那么表明校准值就是一个未知值 |
3. 如何配置滴答定时器
3.1 直接调用core_m3.h内联函数
在core_m3.h文件中有一个配置滴答定时器的内联函数:
1 | __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) |
它的参数就是设置的预装载值,选择的时钟源默认就是系统时钟,并且也使能了中断,所以我们可以在自己的应用程序中据此做一次封装:
1 | int Driver_SysTick_Config(void) |
我们默认将其预装载值设置为系统时钟除以1000,即每隔1ms进入一次滴答定时器的中断。
3.2 根据寄存器地址映射直接操控寄存器
根据前面介绍的滴答定时器的寄存器,按照自己所需设置寄存器的值即可。滴答定时器在内存中映射的基地址是:
各寄存器的地址:
那么我们的程序就可以这样操作:
1 |
|
3.3 滴答定时器的中断服务函数
1 | static volatile uint32_t uwTick = 0; |
4. 验证
要验证也很简单,我们利用刚才中断服务函数中的那个全局递增变量,仿照ST的HAL库写一个延时函数:
1 | unsigned int HAL_GetTick(void) |
然后操控一个GPIO延时改变电平,即闪烁一个LED:
1 | Driver_LED_Write(RedLED, LED_ON); |
根据灯的闪烁现象来粗布判断延时是否准确,更精准的测试可以用逻辑分析仪或者示波器来测试引脚的电平翻转时间。
- 本文作者: 摘星星的小朋友
- 本文链接: http://slhking.github.io/2022/05/10/MM32-4-TickClock/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!