搜索
bottom↓
回复: 0

【正点原子Linux连载】第十八章EPIT定时器试验--摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南

[复制链接]

出0入234汤圆

发表于 2020-6-3 15:42:07 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2020-10-24 16:01 编辑


1)实验平台:正点原子阿尔法Linux开发板
2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
4)本章实例源码下载:
GPIO中断试验.rar (1.62 MB)

第十八章EPIT定时器试验

        
        定时器是最常用的外设,常常需要使用定时器来完成精准的定时功能,I.MX6U提供了多种硬件定时器,有些定时器功能非常强大。本章我们从最基本的EPIT定时器开始,学习如何配置EPIT定时器,使其按照给定的时间,周期性的产生定时器中断,在定时器中断里面我们可以做其它的处理,比如翻转LED灯。



18.1 EPIT定时器简介
        EPIT的全称是:Enhanced Periodic Interrupt Timer,直译过来就是增强的周期中断定时器,它主要是完成周期性中断定时的。学过STM32的话应该知道,STM32里面的定时器还有很多其它的功能,比如输入捕获、PWM输出等等。但是I.MX6U的EPIT定时器只是完成周期性中断定时的,仅此一项功能!至于输入捕获、PWM输出等这些功能,I.MX6U有其它的外设来完成。
        EPIT是一个32位定时器,在处理器几乎不用介入的情况下提供精准的定时中断,软件使能以后EPIT就会开始运行,EPIT定时器有如下特点:
、时钟源可选的32位向下计数器。
、12位的分频值。
、当计数值和比较值相等的时候产生中断。
EPIT定时器结构如图18.1.1所示:
image002.gif

图18.1.1 EPIT定时器框图

        图18.1.1中各部分的功能如下:
        、这是个多路选择器,用来选择EPIT定时器的时钟源,EPIT共有3个时钟源可选择,ipg_clk、ipg_clk_32k和ipg_clk_highfreq。
        、这是一个12位的分频器,负责对时钟源进行分频,12位对应的值是0~4095,对应着1~4096分频。
        、经过分频的时钟进入到EPIT内部,在EPIT内部有三个重要的寄存器:计数寄存器(EPIT_CNR)、加载寄存器(EPIT_LR)和比较寄存器(EPIT_CMPR),这三个寄存器都是32位的。EPIT是一个向下计数器,也就是说给它一个初值,它就会从这个给定的初值开始递减,直到减为0,计数寄存器里面保存的就是当前的计数值。如果EPIT工作在set-and-forget模式下,当计数寄存器里面的值减少到0,EPIT就会重新从加载寄存器读取数值到计数寄存器里面,重新开始向下计数。比较寄存器里面保存的数值用于和计数寄存器里面的计数值比较,如果相等的话就会产生一个比较事件。
        、EPIT可以设置引脚输出,如果设置了的话就会通过指定的引脚输出信号。
        、产生比较中断,也就是定时中断。
        EPIT定时器有两种工作模式:set-and-forget和free-running,这两个工作模式的区别如下:
        set-and-forget模式:EPITx_CR(x=1,2)寄存器的RLD位置1的时候EPIT工作在此模式下,在此模式下EPIT的计数器从加载寄存器EPITx_LR中获取初始值,不能直接向计数器寄存器写入数据。不管什么时候,只要计数器计数到0,那么就会从加载寄存器EPITx_LR中重新加载数据到计数器中,周而复始。
        free-running模式:EPITx_CR寄存器的RLD位清零的时候EPIT工作在此模式下,当计数器计数到0以后会重新从0XFFFFFFFF开始计数,并不是从加载寄存器EPITx_LR中获取数据。
        接下来看一下EPIT重要的几个寄存器,第一个就是EPIT的配置寄存器EPITx_CR,此寄存器的结构如图18.1.2所示:
image004.gif

图18.1.2 EPITx_CR寄存器结构图

        寄存器EPITx_CR我们用到的重要位如下:
        CLKSRC(bit25:24):EPIT时钟源选择位,为0的时候关闭时钟源,1的时候选择选择Peripheral时钟(ipg_clk),为2的时候选择High-frequency参考时钟(ipg_clk_highfreq),为3的时候选择Low-frequency参考时钟(ipg_clk_32k)。在本例程中,我们设置为1,也就是选择ipg_clk作为EPIT的时钟源,ipg_clk=66MHz。
        PRESCALAR(bit15:4):EPIT时钟源分频值,可设置范围0~4095,分别对应1~4096分频。
        RLD(bit3):EPIT工作模式,为0的时候工作在free-running模式,为1的时候工作在set-and-forget模式。本章例程设置为1,也就是工作在set-and-forget模式。
        OCIEN(bit2):比较中断使能位,为0的时候关闭比较中断,为1的时候使能比较中断,本章试验要使能比较中断。
        ENMOD(bit1):设置计数器初始值,为0时计数器初始值等于上次关闭EPIT定时器以后计数器里面的值,为1的时候来源于加载寄存器。
        EN(bit0):EPIT使能位,为0的时候关闭EPIT,为1的时候使能EPIT。
        寄存器EPITx_SR结构体如图18.1.3所示:
image006.jpg

图18.1.3 EPITx_SR寄存器结构图

        寄存器EPITx_SR只有一个位有效,那就是OCIF(bit0),这个位是比较中断标志位,为0的时候表示没有比较事件发生,为1的时候表示有比较事件发生。当比较中断发生以后需要手动清除此位,此位是写1        清零的。
        寄存器EPITx_LR、EPITx_CMPR和EPITx_CNR分别为加载寄存器、比较寄存器和计数寄存器,这三个寄存器都是用来存放数据的,很简单。
        关于EPIT的寄存器就介绍到这里,关于这些寄存器详细的描述,请参考《I.MX6ULL参考手册》第1174页的24.6小节。本章我们使用EPIT产生定时中断,然后在中断服务函数里面翻转LED0,接下来以EPIT1为例,讲解需要哪些步骤来实现这个功能。EPIT的配置步骤如下:
        1、设置EPIT1的时钟源
        设置寄存器EPIT1_CR寄存器的CLKSRC(bit25:24)位,选择EPIT1的时钟源。
        2、设置分频值
        设置寄存器EPIT1_CR寄存器的PRESCALAR(bit15:4)位,设置分频值。
        3、设置工作模式
        设置寄存器EPIT1_CR的RLD(bit3)位,设置EPTI1的工作模式。
        4、设置计数器的初始值来源
        设置寄存器EPIT1_CR的ENMOD(bit1)位,设置计数器的初始值来源。
        5、使能比较中断
        我们要使用到比较中断,因此需要设置寄存器EPIT1_CR的OCIEN(bit2)位,使能比较中断。
        6、设置加载值和比较值
        设置寄存器EPIT1_LR中的加载值和寄存器EPIT1_CMPR中的比较值,通过这两个寄存器就可以决定定时器的中断周期。
        7、EPIT1中断设置和中断服务函数编写
        使能GIC中对应的EPIT1中断,注册中断服务函数,如果需要的话还可以设置中断优先级。最后编写中断服务函数。
        8、使能EPIT1定时器
        配置好EPIT1以后就可以使能EPIT1了,通过寄存器EPIT1_CR的EN(bit0)位来设置。
        通过以上几步我们就配置好EPIT了,通过EPIT的比较中断来实现LED0的翻转。
18.2硬件原理分析
本试验用到的资源如下:
        ①、LED0。
        ②、定时器EPTI1。
        本实验通过EPTI1的中断来控制LED0的亮灭,LED0的硬件原理前面已经介绍过了。
18.3实验程序编写
        本实验对应的例程路径为:开发板光盘-> 1、裸机例程->10_epit_timer。
        本章实验在上一章例程的基础上完成,更改工程名字为“epit_timer”,然后在bsp文件夹下创建名为“epittimer”的文件夹,然后在bsp/epittimer中新建bsp_epittimer.c和bsp_epittimer.h这两个文件。在bsp_epittimer.h中输入如下内容:
  1. 示例代码18.3.1 bsp_epittimer.h文件代码
  2. 1  #ifndef _BSP_EPITTIMER_H
  3. 2  #define _BSP_EPITTIMER_H
  4. 3/***************************************************************
  5. 4  Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
  6. 5文件名    : bsp_epittimer.h
  7. 6作者      : 左忠凯
  8. 7版本      : V1.0
  9. 8描述      : EPIT定时器驱动头文件。
  10. 9其他      : 无
  11. 10论坛      : www.openedv.com
  12. 11日志      : 初版V1.0 2019/1/5 左忠凯创建
  13. 12 ***************************************************************/
  14. 13 #include "imx6ul.h"
  15. 14
  16. 15/* 函数声明 */
  17. 16void epit1_init(unsignedint frac,unsignedint value);
  18. 17void epit1_irqhandler(void);
  19. 18
  20. 19 #endif
复制代码

        bsp_epittimer.h文件很简单,就是一些函数声明。然后在bsp_epittimer.c中输入如下内容:
  1. 示例代码18.3.2 bsp_epittimer.c文件代码
  2. /***************************************************************
  3. Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
  4. 文件名   : bsp_epittimer.c
  5. 作者     : 左忠凯
  6. 版本     : V1.0
  7. 描述     : EPIT定时器驱动文件。
  8. 其他     : 配置EPIT定时器,实现EPIT定时器中断处理函数
  9. 论坛     : www.openedv.com
  10. 日志     : 初版V1.0 2019/1/5 左忠凯创建
  11. ***************************************************************/
  12. 1  #include "bsp_epittimer.h"
  13. 2  #include "bsp_int.h"
  14. 3  #include "bsp_led.h"
  15. 4
  16. 5/*
  17. 6   * @description           : 初始化EPIT定时器.
  18. 7   *                      EPIT定时器是32位向下计数器,时钟源使用ipg=66Mhz      
  19. 8   * @param – frac        : 分频值,范围为0~4095,分别对应1~4096分频。
  20. 9   * @param - value         : 倒计数值。
  21. 10  * @return                 : 无
  22. 11  */
  23. 12void epit1_init(unsignedint frac,unsignedint value)
  24. 13{
  25. 14        if(frac >0XFFF)
  26. 15        frac =0XFFF;
  27. 16        EPIT1->CR =0;/* 先清零CR寄存器 */
  28. 17
  29. 18        /*
  30. 19                 * CR寄存器:
  31. 20       * bit25:24 01 时钟源选择Peripheral clock=66MHz
  32. 21       * bit15:4  frac 分频值
  33. 22       * bit3: 1  当计数器到0的话从LR重新加载数值
  34. 23       * bit2: 1  比较中断使能
  35. 24       * bit1:    1  初始计数值来源于LR寄存器值
  36. 25       * bit0:    0  先关闭EPIT1
  37. 26       */
  38. 27        EPIT1->CR =(1<<24| frac <<4|1<<3|1<<2|1<<1);
  39. 28        EPIT1->LR = value;        /* 加载寄存器值        */
  40. 29        EPIT1->CMPR =0;        /* 比较寄存器值        */
  41. 30
  42. 31        /* 使能GIC中对应的中断        */
  43. 32        GIC_EnableIRQ(EPIT1_IRQn);
  44. 33
  45. 34        /* 注册中断服务函数                */
  46. 35        system_register_irqhandler(EPIT1_IRQn,
  47. (system_irq_handler_t)epit1_irqhandler,
  48. NULL);
  49. 36        EPIT1->CR |=1<<0;/* 使能EPIT1 */
  50. 37}
  51. 38
  52. 39/*
  53. 40  * @description          : EPIT中断处理函数
  54. 41  * @param                  : 无
  55. 42  * @return                 : 无
  56. 43  */
  57. 44void epit1_irqhandler(void)
  58. 45{
  59. 46        staticunsignedchar state =0;
  60. 47        state =!state;
  61. 48        if(EPIT1->SR &(1<<0))        /* 判断比较事件发生                        */
  62. 49        {
  63. 50        led_switch(LED0, state);        /* 定时器周期到,反转LED         */
  64. 51        }
  65. 52        EPIT1->SR |=1<<0;        /* 清除中断标志位                        */
  66. 53}
复制代码

        bsp_epittimer.c里面有两个函数epit1_init和epit1_irqhandler,分别是EPIT1初始化函数和EPIT1中断处理函数。epit1_init有两个参数frac和value,其中frac是分频值,value是加载值。在第29行设置比较寄存器为0,也就是当计数器倒计数到0以后就会触发比较中断,因此分频值frac和value就可以决定中断频率,计算公式如下:
Tout = ((frac +1)* value) / Tclk;
其中:
Tclk:EPIT1的输入时钟频率(单位Hz)。
Tout:EPIT1的溢出时间(单位S)。
第38行设置了EPIT1工作模式为set-and-forget,并且时钟源为ipg_clk=66MHz。假如我们现在要设置EPIT1中断周期为500ms,可以设置分频值为0,也就是1分频,这样进入EPIT1的时钟就是66MHz。如果要实现500ms的中断周期,EPIT1的加载寄存器就应该为66000000/2=33000000。
        函数epit1_irqhandler是EPIT1的中断处理函数,此函数先读取EPIT1_SR寄存器,判断当前的中断是否为比较事件,如果是的话就翻转LED灯。最后在退出中断处理函数的时候需要清除中断标志位。
最后就是mian.c文件了,在mian.c里面输入如下内容:
  1. 示例代码18.3.3 main.c文件代码
  2. /**************************************************************
  3. Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
  4. 文件名   : mian.c
  5. 作者     : 左忠凯
  6. 版本     : V1.0
  7. 描述     : I.MX6U开发板裸机实验10 EPIT定时器实验
  8. 其他     : 本实验主要学习使用I.MX6UL自带的EPIT定时器,学习如何使用
  9.             EPIT定时器来实现定时功能,巩固Cortex-A的中断知识。
  10. 论坛     : www.openedv.com
  11. 日志     : 初版V1.0 2019/1/4 左忠凯创建
  12. **************************************************************/
  13. 1  #include "bsp_clk.h"
  14. 2  #include "bsp_delay.h"
  15. 3  #include "bsp_led.h"
  16. 4  #include "bsp_beep.h"
  17. 5  #include "bsp_key.h"
  18. 6  #include "bsp_int.h"
  19. 7  #include "bsp_epittimer.h"
  20. 8
  21. 9/*
  22. 10  * @description  : main函数
  23. 11  * @param        : 无
  24. 12  * @return       : 无
  25. 13  */
  26. 14int main(void)
  27. 15{
  28. 16        int_init();        /* 初始化中断(一定要最先调用!)         */
  29. 17        imx6u_clkinit();        /* 初始化系统时钟        */
  30. 18        clk_enable();        /* 使能所有的时钟        */
  31. 19        led_init();        /* 初始化led                             */
  32. 20        beep_init();        /* 初始化beep                            */
  33. 21        key_init();        /* 初始化key                             */
  34. 22        epit1_init(0,66000000/2);        /* 初始化EPIT1定时器,1分频
  35. 23                         * 计数值为:66000000/2,也就是
  36. 24                         * 定时周期为500ms。
  37. 25                         */
  38. 26        while(1)
  39. 27        {
  40. 28        delay(500);
  41. 29        }
  42. 30
  43. 31                return0;
  44. 32}
复制代码

        main.c里面就一个main函数,第22行调用函数epit1_init来初始化EPIT1,分频值为0,也就是1分频,加载寄存器值为66000000/2=33000000,EPTI1定时器中断周期为500ms。第26~29行的while循环里面就只有一个延时函数,没有做其他处理,延时函数都可以取掉。
18.4编译下载验证
18.4.1编写Makefile和链接脚本
        修改Makfile中的TARGET为epit,在INCDIRS和SRCDIRS中加入“bsp/epittimer”,修改后的Makefile如下:
  1. 示例代码18.4.1.1  Makefile文件代码
  2. 1  CROSS_COMPILE          ?= arm-linux-gnueabihf-
  3. 2  TARGET                  ?=epit
  4. 3
  5. 4/* 省略掉其它代码...... */
  6. 5
  7. 6  INCDIRS        :=        imx6ul \
  8. 7                bsp/clk \
  9. 8                bsp/led \
  10. 9                bsp/delay  \
  11. 10                 bsp/beep \
  12. 11                bsp/gpio \
  13. 12                bsp/key \
  14. 13                bsp/exit \
  15. 14                 bsp/int \
  16. 15                 bsp/epittimer
  17. 16
  18. 17 SRCDIRS:=        project \
  19. 18                bsp/clk \
  20. 19                 bsp/led \
  21. 20                bsp/delay \
  22. 21                bsp/beep \
  23. 22                bsp/gpio \
  24. 23                 bsp/key \
  25. 24                bsp/exit \
  26. 25                bsp/int \
  27. 26                bsp/epittimer
  28. 27
  29. 28 /* 省略掉其他代码...... */
  30. 29
  31. 30 clean:
  32. 31  rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS)$(SOBJS)
复制代码

第2行修改变量TARGET为“epit”,也就是目标名称为“epit”。
        第15行在变量INCDIRS中添加EPIT1驱动头文件(.h)路径。
        第26行在变量SRCDIRS中添加EPIT1驱动文件(.c)路径。
        链接脚本保持不变。
18.4.2编译下载
        使用Make命令编译代码,编译成功以后使用软件imxdownload将编译完成的epit.bin文件下载到SD卡中,命令如下:
  1. chmod 777 imxdownload                        //给予imxdownload可执行权限,一次即可
  2. ./imxdownload epit.bin /dev/sdd                //烧写到SD卡中
复制代码

        烧写成功以后将SD卡插到开发板的SD卡槽中,然后复位开发板。程序运行正常的话LED0会以500ms为周期不断的亮、灭闪烁。



阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 02:25

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表