I.MX6U 裸机开发16.EPIT定时器

摘要:EPIT(Enhanced Periodic Interrupt Timer)是一种增强型周期性中断定时器,主要用于嵌入式系统中产生周期性的中断信号。以汽车电子系统为例,车辆中的一些传感器数据需要按照固定的周期进行采集和处理。EPIT 定时器就可以设置一个合适

EPIT(Enhanced Periodic Interrupt Timer)是一种增强型周期性中断定时器,主要用于嵌入式系统中产生周期性的中断信号。
以汽车电子系统为例,车辆中的一些传感器数据需要按照固定的周期进行采集和处理。EPIT 定时器就可以设置一个合适的周期,每隔一段时间产生一个中断。当发生中断时,处理器就可以暂停当前的任务,转而去执行数据采集程序,比如采集车速传感器的数据。

IMX6U的 EPIT 是一个32位的向下计数器,有12位的分频值。
从《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81》 可以看到EPIT 定时器框图如下:

EPIT 的时钟源可以选择 ipg_clk (66MHz),经过后面的分频器。

分频器有12位,0 ~ 4095分别代表 1 ~ 4096分频。
预分频器的输出连接到Prescaled clock,即分频后的时钟信号。

这是一个 32 位的比较寄存器,用于存储比较值。
比较寄存器的值与计数器的值通过CMP(比较器)进行比较。

通过 EPIOTx_CR 可以设置EPIT的工作模式。通过手册查询该寄存器 RLD 位置作用:

当 RLD为1时,计时器工作在 set-and-forget 模式,该模式即 “ 设置后就不用管 ”。
在此模式下,计数器从加载寄存器(EPIT_LR)获取数据;它不能直接从块数据总线写入。

每当计数器达到零时,EPIT_LR 中的值就会被加载到计数器中。然后这个值会递减到零。若要直接初始化计数器而不是等待计数达到零,需设置 EPIT 计数器覆写使能位(EPIT_CR [IOVW]),并使用所需的初始化值写入 EPIT_LR。

当RLD为0 时,计时器工作在“自由运行”模式。在这个模式下,计数器从 0000 0000h 翻转到 FFFFFFFFh,而不会从模式寄存器重新加截值,翻转之后,计数器会继续向下计数。

要直接初始化计数器,也需要设置 EPIT 计数器覆盖使能位(EPIO_EPITCL [IOVW] ),并将所需要的初始化值写入 EPIT_LR。

当 EPIT_EPITCMPR 值与 EPIT_EPITCNR 中的值相匹配时,会设置一个比较状态标志 , 如果控制寄存器中的OCIEN 位被置位,还会产生一个中断。

下图是比较事件和中断的时序:


在对设置值、产生中断时序要求非常严格的情况下,需要细致了解其时序。 一般的情况下,可能不需要了解如此清楚。

IMX6ULL 共有两个 EPIT 定时器,主要包含以下寄存器。

EPIT_CR 是EPIT的控制寄存器,主要用于配置和控制EPIT 工作模式、时钟源、分频值、中断使能等。


其主要有以下位域:

bit0:EN:EPIT 使能位,0 表示关闭 EPIT,1 表示使能 EPIT。bit1:ENMOD:设置计数器初始值来源,0 时计数器初始值等于上次关闭 EPIT 定时器以后计数器里面的值,1 时来源于加载寄存器。bit2:OCIEN:比较中断使能位,0 关闭比较中断,1 使能比较中断,当计数器的值与比较寄存器中的值相等时,如果该位为 1,则会触发中断。bit3:RLD:EPIT 工作模式选择位,0 时工作在 free-running 模式,1 时工作在 set-and-forget 模式.bit4-15:PRESCALAR:EPIT 时钟源分频值,可设置范围 0-4095,分别对应 1-4096 分频,用于对选定的时钟源进行分频,以得到合适的计数时钟频率。bit25-24:CLKSRC:EPIT 时钟源选择位,00 时关闭时钟源,01 选择 Peripheral 时钟(ipg_clk),10 选择 High-frequency 参考时钟(ipg_clk_highfreq),11 选择 Low-frequency 参考时钟(ipg_clk_32k)。

EPIT_SR 是状态寄存器,主要用于记录和提供与定时器相关的状态信息,只有bit0(OCIF) 有效,表示中断状态。 写1时清零。
当OCIF 位值为1时,表示发生中断, 值为0的时候表示中断没有发生。
处理完定时器中断,需要清除该标志位。

本实验实现 500ms 周期的定时器,在EPIT的中断服务函数中让LED闪烁。

/*** @brief EPIT初始化, 工作在 set-and-forget 模式*/void epit_init(EPIT_Type *base, unsigned int frac, unsigned int value) {if(frac > 4095){frac = 4095;}// 配置EPIT设置寄存器,先清0base->CR = 0;// 设置初始值为加载值 | 使能EPIT模块 | 使能中断 | 分频值 | 使能时钟base->CR = (1 LR = value;// 设置比较值base->CMPR = 0;// 使能GIC中断if(base == EPIT1)GIC_EnableIRQ(EPIT1_IRQn);elseGIC_EnableIRQ(EPIT2_IRQn);// 注册中断服务函数sys_irq_handle_register(EPIT1_IRQn, (system_irq_handler_t)epit_irqhandler, NULL);// 定时器使能base->CR |= 1

分频值计算:
Tout=((frac+1)∗value)/Tclk
其中 Tclk = 66Mhz
如果分频值是1,则1秒进中断 66M次。 如果要500ms进一次,分频值设置1,计数器值设置为 66M/2。

#include "inc/main.h"#include "bsp_clk.h"#include "bsp_delay.h"#include "led.h"#include "beep.h"#include "key.h"#include "bsp_int.h"//#include "bsp_exti.h"#include "bsp_epit.h"int main(void){bsp_int_init; /* 初始化中断 */imx6u_clkinit; /* 初始化系统时钟 */clk_enable; /* 使能外设时钟 */led_init; /* 初始化LED */beep_init; /* 初始化蜂鸣器 */// exti_init; /* 初始化外部中断 */epit_init(EPIT1, 0, 66000000 / 2); /* 初始化EPIT1, 1分频, 500ms中断一次 */while(1) {}return 0;}

本文代码开源地址:

来源:编程圈子

相关推荐