当前位置: 首页 > news >正文

Cortex-M3的SysTick 定时器

目录

概述

1 SysTick 定时器

1.1 SysTick 定时器功能介绍

1.2 SysTick 定时器功能实现

1.3 SysTick在系统中的作用

2 SysTick应用的实例

2.1 建立异常服务例程

2.2 使能异常

2.3 闹钟功能

2.4  重定位向量表

2.5 消灭二次触发

3 SysTick在FreeRTOS中的应用

3.1 STM32Cube配置SysTick

3.2 STM32HAL中sysTick接口


概述

本文主要介绍Cortex-M3的SysTick 定时器的相关知识,还介绍了一个使用汇编语言编写的Cortex-M3的SysTick的应用实例。还介绍基于Cortex-M3内核的经典MCU STM32F103中SysTick在实际项目应用的方法。

1 SysTick 定时器

1.1 SysTick 定时器功能介绍

SysTick 是一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时初值。只要SysTick 控制及状态寄存器中的使能位被置位, 就永不停息。下图是SysTick的相关寄存器:

CM3 允许为 SysTick 提供两个时钟源以供选择:

1)是内核的“自由运行时钟” FCLK。“自由” 表现在它不来自系统时钟 HCLK, 因此在系统时钟停止时 FCLK 也继续运行。

2)一个外部的参考时钟。但是使用外部时钟时,因为它在内部是通过 FCLK 来采样的,因此其周期必须至少是 FCLK 的两倍(采样定理)。

很多情况下芯片厂商都会忽略此外部参考时钟,因此通常不可用。通过检查校准寄存器的位[31](NOREF), 可以判定是否有可用的外部时钟源,而芯片厂商则必须把该引线连接至正确的电平。

1.2 SysTick 定时器功能实现

当 SysTick 定时器从 1 计到 0 时,它将把 COUNTFLAG 位置位;

下述方法可以清零之:
1)读取 SysTick 控制及状态寄存器(STCSR)
2)往 SysTick 当前值寄存器(STCVR)中写任何数据

1.3 SysTick在系统中的作用

1)SysTick 的最大使命,就是定期地产生异常请求,作为系统的时基。 OS 都需要这种“滴答” 来推动任务和时间的管理。

2)如欲使能 SysTick 异常, 则把 STCSR.TICKINT 置位。 另外, 如果向量表被重定位到 SRAM 中,还需要为 SysTick 异常建立向量,提供其服务例程的入口地址。

2 SysTick应用的实例

2.1 建立异常服务例程

建立SysTick异常服务例程

MOV R0, #0xF                ; 异常号: 15
LDR R1, =systick_handler    ; 加载服务例程的入口地址
LDR R2, =0xE000ED08         ; 加载向量表偏移量寄存器的地址
LDR R2, [R2]                ; 读取向量表的首地址
STR R1, [R2, R0, LSL #2]    ; 写入向量

2.2 使能异常

LDR R0, =0xE000E010       ; 加载STCSR的地址
MOV R1, #0
STR R1, [R0]              ; 先停止SysTick,以防意外产生异常请求
LDR R1, =0x3FF            ; 让SysTick每1024周期计完一次。因为是从1023数到; 0,总共数了1024个周期,所以加载值为0x3FF
STR R1, [R0,#4]           ; 写入重装载的值
STR R1, [R0,#8]           ; 往STCVR中写任意的数,以确保清除COUNTFLAG标志
MOV R1, #0x7              ; 选择FCLK作为时钟源,并使能SysTick及其异常请求
STR R1, [R0]              ; 写入数值,开启定时器

除此之外, SysTick 定时器还提供了走完 10ms 所需要的格数(TENMS 位段),作为时间校准的参考信息。在 CM3 处理器的顶层有一个 24 位的输入,芯片厂商可以写入一个 10ms 的加载值,写程序时就可以读取 STCR 寄存器中的 TENMS 位段来获取此信息。不一定每个芯片都实现了此功能,因此在使用时还需查阅芯片的数据手册。

2.3 闹钟功能

SysTick 定时器还可以用作闹钟,作为启动一个特定任务的时间依据。例如,如果需要在 300 周期后执行一段代码,就可以在 SysTick 异常服务例程中设置执行那段代码的软件标志。使用 SysTick 时,清零 CURRENT 再编程 RELOAD 寄存器,以使它在 300 周期后产生异常,如下述代码所演示:

    LDR r0, =15LDR r1, =SysTickAlarm  ; SysTick异常服务例程为SetupExcpHanlerBL SetupExcpHandler    ; 调用前面章节讲到的子程来建立向量LDR R0, =0xE000E010    ; SysTick寄存器组的基地址MOV R1, #0             ; 编程前先除能SysTickSTR R1, [R0]STR R1, [R0,#0x8]      ; 清零CURRENTLDR R1, =(300-12)      ; 设置装载值。减去12是为了补偿中延迟STR R1, [R0,#0x4]      ; 写入RELOADLDR R4, =SysTickFired  ; 在RAM中的一个变量,指示是计时到期MOV R5, #0             ; 初始为0STR R5, [R4]MOV R1, #0x7           ; 使用FCLK,使能SysTick,使能SysTick异常STR R1, [R0]           ; 启动计时LDR R4, =SysTickFired
WaitLoopLDR R5, [R4]           ; 循环查询软件标志CMP R5, #0BEQ WaitLoop...                    ; SysTickFired在服务例程中被置位,主程序可以继续执行

2.4  重定位向量表

因为计数器是从 0 开始计数的,所以它会立即把 300‐12 加载入 CURRENT。 12 是中断响应的最短延时,因此减去它用以补偿。但是如果有更高优先级的异常抢占或者阻塞了它,则中断延迟还是会有的。

SetupExcpHandler 来建立向量表,但注意:必须重定位向量表到RAM 中才行。

SetupExcpHandler; 入口条件: R0 = 异常号; 入口条件: R1 = 异常服务例程PUSH {R0, R2, LR}LDR R2, =NVIC_VECTTBLLDR R2, [R2]                ; 读取向量表的地址STR.W R1, [R2, R0, LSL #2]  ; 表中[R2+R0<<2]的位置就是为该向量的POP {R0, R2, PC}            ; 快速返回

2.5 消灭二次触发

2.4节 重定位向量表时,减去12 只适用于一次性(one shot)的闹钟操作,必须在 SysTick 服务例程中按停这个 SysTick。进一步地,如果其它异常把它延迟得太久,就有可能会使 SysTick异常被悬起两次。因此,对于单次处理时,还需要其它一些步骤来消灭二次触发:

SysTickAlarm                ; SYSTICK exception handlerPUSH {LR}LDR R0, =0xE000E010     ; SYSTICK寄存器组的基地址MOV R1, #0STR R1, [R0]            ; 除能SysTick,因为只使用一次LDR R0, =0xE000ED04LDR R1, =0x02000000     ; 手工清除NVIC中的SysTick悬起位STR R1, [R0]...                     ; 执行所需的处理工作LDR R2, = SysTickFiredLDR R1, [R2]ORR R1, #1STR R1, [R2]            ; 设置软件标志,与主程序同步,以执行任务POP {PC}                ; 异常返回

在服务例程的末尾处,通过设置 SysTickFired 标志,通知主程序定时已经到期,可以结束循环等待了。
 

3 SysTick在FreeRTOS中的应用

3.1 STM32Cube配置SysTick

笔者以STM32103RTB芯片作为平台配置SysTick和FreeRTOS

1) 配置FreeRTOS的系统时钟为SysTick

2)使能FreeRTOS

3.2 STM32HAL中sysTick接口

在STM32HAL库中定义在core_cm3.h中,这部分代码在实际项目应用中,不建议修改,用户可以重新stm32f1xx_hal.c中和sysTick相关的应用接口。在这个文件中,和sysTick相关的应用接口被定义为__weak类型,意味着其可以被重写。

相关文章:

  • linux文件权限常用知识点,基于Linux(openEuler、CentOS8)
  • 基于Rsoft的Fullwave仿真模块进行双芯波导能量耦合与波分复用
  • Java 18 新特性详解
  • 后量子密码解决方案
  • 5.Redis之常用数据结构单线程模型
  • Java整合ELK实现日志收集 之 Elasticsearch、Logstash、Kibana
  • 为 AWS 子账户添加安全组修改权限
  • 深入探索SQL注入:盲注技术及其防御策略
  • 程序员做副业要知道重点在哪里
  • 区间预测 | Matlab实现DNN-KDE深度神经网络结合核密度估计多置信区间多变量回归区间预测
  • 永久代你不知道的东西
  • 哈希表---闭散列
  • colmap在windows上编译好的程序直接可以运行支持cuda
  • Spring是怎么处理循环依赖的
  • 【车载以太网测试从入门到精通】——SOME/IP协议测试
  • 2017 年终总结 —— 在路上
  • Asm.js的简单介绍
  • httpie使用详解
  • JavaScript 基础知识 - 入门篇(一)
  • Linux链接文件
  • mongodb--安装和初步使用教程
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • React+TypeScript入门
  • Selenium实战教程系列(二)---元素定位
  • Swift 中的尾递归和蹦床
  • 从0实现一个tiny react(三)生命周期
  • 浮动相关
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 与 ConTeXt MkIV 官方文档的接驳
  • 原生Ajax
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • 积累各种好的链接
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ​14:00面试,14:06就出来了,问的问题有点变态。。。
  • # 计算机视觉入门
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • $ git push -u origin master 推送到远程库出错
  • (1)虚拟机的安装与使用,linux系统安装
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
  • (php伪随机数生成)[GWCTF 2019]枯燥的抽奖
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (不用互三)AI绘画工具应该如何选择
  • (第二周)效能测试
  • (二)c52学习之旅-简单了解单片机
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (篇九)MySQL常用内置函数
  • (四)opengl函数加载和错误处理
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .NET Micro Framework初体验(二)
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • @Autowired 和 @Resource 区别的补充说明与示例
  • @synthesize和@dynamic分别有什么作用?