【裸机开发】定时器中断(EPIT)

news2024/11/17 7:52:07

EPIT 是周期性中断定时器,会定期调用指定的中断服务函数,其实可以看做是一种IRQ的外设中断,对应的中断ID是88(=56+32)或者 89(=57+32)。


目录

一、定时器计数流程

二、寄存器解析

1、EPIT1_CR

2、EPIT1_LR

3、EPIT1_CMPR 

4、EPIT1_CNR

5、EPT1_SR

三、其他初始化操作

1、全局中断初始化

2、GIC 的 EPIT 中断使能

3、注册中断服务函数

四、总结


一、定时器计数流程

定时器计数主要涉及到三个寄存器:

  • count register:计数器启动以后,每隔一个时钟周期,自减1
  • compare register:当 count register == compare register 时,触发中断,调用对应的中断服务函数
  • load register处理完中断服务函数以后,下一次开始自减的初始值是多少(有两种模式,分别对应着不同的初始值)

这里使用简单的 C 代码阐述一下这三个寄存器之间的关系

/*
 * mode: 表示计数模式
 * count register: 计数寄存器(每隔一个时钟周期,自减1)
 * compare register: 比较寄存器(保存每次停止自减的临界值)
 * load register: 加载寄存器。保存每次重新自减的初始值
 */

if(mode == 0)    // 每次从 0xffff ffff 开始自减
    count_register = 0xffffffff;
else            // mode = 1,每次从 load register 开始自减
    count_register = load_register;

// 假设每一次while循环都是一个时钟周期
while(1)
{
    if(count_register == compare_register)    // 停止计数
    {
        // 调用中断服务函数

        // 重新开始计数
        if(mode == 0)    // 每次从 0xffff ffff 开始自减
            count_register = 0xffffffff;
        else            // mode = 1,每次从 load register 开始自减
            count_register = load_register;
    }
    else
        count_register --;
}

二、寄存器解析

了解定时器的计数流程后,我们也大致知道了计数过程需要用到哪些寄存器,整个过程涉及到的寄存器如下:

  • EPIT1_CR        —— 配置 EPIT(选择时钟源、计数使能、比较使能等)
  • EPIT1_LR        —— 对应 load register
  • EPIT1_CMPR  —— 对应 compare register
  • EPIT1_CNR     —— 对应 count register
  • EPT1_SR         —— 记录 EPIT 的状态(每次处理完中断,都要置1)

1、EPIT1_CR

CR 是控制寄存器,用于配置EPIT的使能、分频、时钟源等。主要配置的字段:15~0 bit、25~24 bit

bit 0:EPIT使能。设为 1

bit 1:EPIT打开以后的最初计数值来源。0 表示从上一次关闭EPIT时的值开始,1 表示从 Load Register 或者 0xFFFF_FFFF 开始。设为 1 

bit 2:比较寄存器使能。设为 1

bit 3:计数加载控制,也就是模式选择。mode = 0 表示当计数器和比较寄存器相等时,下一次从0xFFFF_FFFF 开始;mode = 1 表示当计数器和比较寄存器相等时,下一次从Load Register 的值开始。设为 1 

bit 15-4:时钟源分频数。取值为0~4095

bit 25-24:选择时钟源。我们选择 01,即 ipg_clk(66MHz) 

寄存器: EPIT1_CR
基地址: 0x20D0000
初始化操作:
    // bit 3-0
    EPIT1_CR &= ~(0xF);       // bit 3-0 清零
    EPIT1_CR |= 0xF;
    
    // bit 15-4
    EPIT1_CR &= ~(0xFFF0);    // bit 15-4 清零
    EPIT1_CR |= (0x1 << 4);   // 2 分频

    // bit 25-24
    EPIT1_CR &= ~(0x3 << 24);    // bit 25-24 清零
    EPIT1_CR |= (0x1 << 24);     // 01

2、EPIT1_LR

LR 是加载寄存器,保存每次触发中断以后,重新计数的起始值。默认起始值是 0xFFFF FFFF。假设定时器的时间间隔为 1 s,时钟频率是 66MHz / 2 = 33 MHz(这里的2表示2分频),即时钟周期是 1/33M s

因此,LR 寄存器的值应设为 33000000,对应十六进制为 0x1F7 8A40

寄存器: EPIT1_LR
基地址: 0x20D0008
初始化操作:
    EPIT1_LR = 0x1F78A40;

3、EPIT1_CMPR 

比较寄存器决定何时产生中断,因为当计数寄存器和比较寄存器相等时,就会触发中断,从而调用对应的中断服务函数。默认值是 0 (一般无需设置)

寄存器: EPIT1_CMPR 
基地址: 0x20D000C
初始化操作:
    EPIT1_CMPR  = 0;

4、EPIT1_CNR

计数寄存器保存着当前计数值。初始情况下可以和上面 LR 寄存器的值保持一致

寄存器: EPIT1_CNR
基地址: 0x20D0010
初始化操作:
    EPIT1_CNR = 0x1F78A40;

5、EPT1_SR

EPIT状态寄存器记录着EPIT中断是否发生。在中断服务函数执行完毕以后,要清除标志位,即改寄存器要置1。

寄存器: EPIT1_SR
基地址: 0x20D0004
清除标志位操作:
    EPIT1_SR = 1;

三、其他初始化操作

1、全局中断初始化

参考:IRQ 全局中断初始化

2、GIC 的 EPIT 中断使能

EPIT 的中断ID 在本文开始位置已经给出了,如果要用 EPIT1,中断ID = 88;如果要使用 EPIT2,中断ID = 89。

/* EPIT1 中断使能 */
GIC_EnableIRQ(88);

3、注册中断服务函数

当定时器中断触发时,我们反转 LED 灯的状态。不要忘记清除中断标志位!

static unsigned int status = OFF;

void epit_irqhandler(void* userParams)
{
    switch_led(status);
    status = !status;

    EPIT1_SR = 1;           // 清除中断标志位
}
void led_on()
{
    GPIO1_DR &= ~(1 << 3);
}

void led_off()
{
    GPIO1_DR |= (1 << 3);
}

void switch_led(uint8_t status)
{
    if (status == ON)
    {
        led_on();
    }
    else
    {
        led_off();
    }
}

四、总结

static unsigned int status = OFF;

/*
 * frac: 代表分频数
 * interval: 代表定时器的时间间隔
 */
void epit_init(unsigned int frac, unsigned int interval)
{
    /* EPIT1 中断使能 */
    GIC_EnableIRQ(88);

    /* 注册中断服务函数 */
    register_irqhandler(88, epit_irqhandler);

    /* EPIT1 使能、分频、时钟源初始化 */
    // bit 3-0
    EPIT1_CR &= ~(0xF);       // bit 3-0 清零
    EPIT1_CR |= 0xF;
    
    // bit 15-4
    EPIT1_CR &= ~(0xFFF0);    // bit 15-4 清零
    EPIT1_CR |= (0x1 << 4);   // 2 分频

    // bit 25-24
    EPIT1_CR &= ~(0x3 << 24);    // bit 25-24 清零
    EPIT1_CR |= (0x1 << 24);     // 01

    /* 加载寄存器 */
    EPIT1_LR = 0x1F78A40;

    /* 比较寄存器 */
    EPIT1_CMPR = 0;

    /* 计数寄存器 */
    EPIT1_CNR = 0x1F78A40;
}

void epit_irqhandler(void* userParams)
{
    switch_led(status);
    status = !status;

    EPIT1_SR = 1;           // 清除中断标志位
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/682419.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

骨传导耳机、运动耳机推荐:南卡OE开放式TWS耳机值得买吗?南卡OE测评

目前&#xff0c;如果说到骨传导耳机、蓝牙耳机想必大家都很熟悉&#xff0c;那你了解TWS耳机么&#xff1f; 如果说iPhone“重新定义”了智能手机&#xff0c;那么AirPods就重新定义了耳机——它“断”了耳机与手机/播放器间的连线&#xff0c;还将左右耳彼此间的连线彻底摒弃…

SimpleDateFormat显示24小时和12小时时间格式

public static void main(String[] args) throws Exception {MainTest1 mainTest1 new MainTest1();mainTest1.dateFormat();} yyyy-MM-dd HH:mm:ss格式显示的时间为:2017-06-12 18:01:06 yyyy-MM-dd hh:mm:ss格式显示的时间为:2017-06-12 06:01:06

二章:VMvare虚拟机的安装+VMvare安装winServer2008

目录 一、Vmware软件安装 二、Vmware软件注册 三、Vmware配置虚拟机-1 四、Vmware配置虚拟机-2 五、Vmware配置虚拟机-3 六、Vmware安装windows server 2008 一、Vmware软件安装 第一步 双击安装程序&#xff0c;点击下一步。 第二、三步 勾选接受许可&#xff0c;点击下一步。…

SAM【1】:Segment Anything

文章目录 前言1. Abstraction & Introduction1.1. Abstraction1.2. Introduction 2. Segment Anything Model2.1. Segment Anything Task2.1.1. Task2.1.2. Pre-training2.1.3. Zero-shot transfer 2.2. Segment Anything Model Methods2.2.1. Image Encoder2.2.2. Prompt …

python:并发编程(二十三)

前言 本文将和大家一起探讨python并发编程的实际项目&#xff1a;win图形界面应用&#xff08;篇五&#xff0c;共八篇&#xff09;&#xff0c;系列文章将会从零开始构建项目&#xff0c;并逐渐完善项目&#xff0c;最终将项目打造成适用于高并发场景的应用。 本文为python并…

微信小程序快速入门【二】

微信小程序快速入门【二】 文章目录 微信小程序快速入门【二】&#x1f468;‍&#x1f3eb;内容1&#xff1a;背景&#x1f468;‍⚖️内容2&#xff1a;项目结构&#x1f468;‍&#x1f4bb;内容3&#xff1a;项目配置文件app.json&#x1f468;‍&#x1f680;内容4&#x…

SpringBoot使用入门和案例实现

目录 1. 在pom.xml中添加依赖2. 编辑resources/application.properties3. 编写springboot的主程序4. 编写Controller程序5. IDEA本地测试6. 打包上传到服务器运行 1. 在pom.xml中添加依赖 步骤如下&#xff1a; 添加springboot的parent依赖添加springboot的starter-web依赖。…

osip开源库在windows平台上编译

背景 之前写过一篇关于sip协议栈选型的文章&#xff0c;最终采用了osip 2.3.6版本&#xff0c;文章中说明了为什么采用osip协议栈&#xff0c;以及为什么采用2.3.6版本。现在Linux上的产品已经基本满足需求了&#xff0c;接下来我们打算开发一套客户端和服务端对接&#xff0c…

电子邮件机器人和聊天机器人如何使您的客户支持受益?

当我们谈论客户支持中的人工智能时&#xff0c;通常会想到基于Web的聊天机器人。然而&#xff0c;现代人工智能的进步使电子邮件机器人成为客户支持自动化的下一个风口&#xff0c;使组织能够满足人们对于快速便捷的全渠道体验的期望。 有些人认为&#xff0c;与Facebook Mess…

“兆易创新杯”第十八届中国研究生电子设计竞赛有感

今年的电赛给我的感觉是时间真的紧张&#xff0c;可能是因为去年有疫情原因影响所以能准备的时间到七月份&#xff0c;今年不到月底就要全部出成品。我们团队一直在自研一款增强现实眼镜&#xff0c;从硬件设计到软件实现全部由我和另外两个小伙伴一起完成&#xff0c;所以就把…

matlab实现声音录制与左右声道分离

基础知识 1.MATLAB识别的常用语音信号类型&#xff1a; WAV格式 TXT格式 2.读取wav格式语音用函数&#xff1a;wavread 常用格式&#xff1a; ywavread(‘语音文件名’) [y,fs]wavread (‘语音文件名’) 用于读取语音,采样值放在向量y中,fs表示采样频率。 3.读取wav格式语音用…

动态代理与Spring Aop

动态代理 JDK 动态代理 使用JAVA反射包中的类和接口实现动态代理的功能&#xff0c;JAVA.lang.reflect包&#xff1b;主要是三个类&#xff1a; InvocationHandler,Method,Proxy; CGLIB动态代理&#xff0c;第三方工具类库&#xff0c;创建代理对象&#xff0c;cglib的原理是继…

城市内涝监测需要什么设备

近年来&#xff0c;随着城市化进程的加快&#xff0c;城市内涝问题愈发突出。强降雨、缺乏排水设施和过度的人类活动等因素&#xff0c;导致城市内涝灾害频发。内涝不仅给居民生活和财产安全带来威胁&#xff0c;还对城市基础设施和经济发展造成严重影响。 为了应对城市内涝灾…

spring中事务失效的情况(常见的5种)

1.多线程调用 从上面的例子中&#xff0c;我们可以看到事务方法add中&#xff0c;调用了事务方法doOtherThing&#xff0c;但是事务方法doOtherThing是在另外一个线程中调用的。 这样会导致两个方法不在同一个线程中&#xff0c;获取到的数据库连接不一样&#xff0c;从而是两…

centos7宝塔项目配置步骤

0、 1、 2、前面两个空格去掉勾 3、window 配置虚拟机 对应的域名

Django高级扩展之celery使用

Celery是一个简单、灵活、可靠的分布式系统&#xff0c;用于处理大量消息&#xff0c;同时为操作提供维护此类系统所需的工具。是一个专注于实时处理的任务队列&#xff0c;同时还支持任务调度。 目录 应用场景 问题 解决 celery架构图 安装 配置celery Settings.py配置…

CVE-2022-25099

文章目录 CVE-2022-25099一、漏洞介绍二、渗透步骤1、打开网站2、登录后台3、文件上传4、查看flag值 CVE-2022-25099 一、漏洞介绍 WBCE CMS v1.5.2 RCE。 WBCE CMS v1.5.2 /language/install.php 文件存在漏洞&#xff0c;攻击者可精心构造文件上传造成RCE。 二、渗透步骤 1…

宝塔面板实用教程(1):10分钟部署在线客服系统

客服系统发布以来&#xff0c;一直有朋友询问如何在宝塔面板中安装部署&#xff0c;开始我一直认为参考 Linux 版的安装教程就可以了&#xff0c;一直没有专门写宝塔环境的教程。这段时间来咨询的朋友越来越多&#xff0c;经过了解&#xff0c;我才知道宝塔面板的普及率有多高&…

SSM流浪动物救助网站-计算机毕设 附源码82131

SSM流浪动物救助网站 摘 要 随着生活水平的持续提高和家庭规模的缩小&#xff0c;宠物已经成为越来越多都市人生活的一部分&#xff0c;随着宠物的增多&#xff0c;流浪的动物的日益增多&#xff0c;中国的流浪动物领养和救助也随之形成规模&#xff0c;同时展现巨大潜力。本次…

XML文件

xml文件 类似于html那种标签语言 但是用途却大不一样&#xff0c;xml一般用于小型数据传输&#xff08;存储数据&#xff09; xml文件作用 xml语法规则 一个简单的xml文件案例 xml解析 解析思想 所谓的xml解析 也就是从xml文件提取数据 解析思想&#xff1a;前端的文档对…