I.MX6U 裸机开发16.EPIT定时器
- 一、EPIT定时器的概念
- 1. 基本概念
- (1)时钟源
- (2)12位预分频器
- (3)计数器重装(Counter Reload)
- (4)32位计数器寄存器(Counter Register)
- (5)比较器寄存器
- 2. EPIT 2种工作模式
- (1) set-and-forget
- (2)free-running
- 3. 比较事件
- 二、IMX6ULL 的 EPIT 定时器
- 1. EPIT_CR
- 2. EPITx_SR
- 3. EPITx_LR
- 4. EPITx_CMPR
- 5. EPITx_CNR
- 三、实验程序
- 1. EPIT初始化
- 2. 主函数
一、EPIT定时器的概念
1. 基本概念
EPIT(Enhanced Periodic Interrupt Timer)是一种增强型周期性中断定时器,主要用于嵌入式系统中产生周期性的中断信号。
以汽车电子系统为例,车辆中的一些传感器数据需要按照固定的周期进行采集和处理。EPIT 定时器就可以设置一个合适的周期,每隔一段时间产生一个中断。当发生中断时,处理器就可以暂停当前的任务,转而去执行数据采集程序,比如采集车速传感器的数据。
IMX6U的 EPIT 是一个32位的向下计数器,有12位的分频值。
从《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81》 可以看到EPIT 定时器框图如下:
(1)时钟源
EPIT 的时钟源可以选择 ipg_clk (66MHz),经过后面的分频器。
(2)12位预分频器
分频器有12位,0 ~ 4095分别代表 1 ~ 4096分频。
预分频器的输出连接到Prescaled clock,即分频后的时钟信号。
(3)计数器重装(Counter Reload)
用于重新加截计数器值,当计数器减到 0 的时候,
(4)32位计数器寄存器(Counter Register)
这是一个 32 位的比较寄存器,用于存储比较值。
比较寄存器的值与计数器的值通过CMP(比较器)进行比较。
(5)比较器寄存器
- CMP(比较器)用于比较计数器寄存器和比较寄存器的值。
- 当计数器的值达到比较寄存器的值时,会产生一个中断信号。
- ITIF(中断标志)和ITIE(中断使能)用于控制和指示中断状态。
- EPITn_OUT是定时器的输出信号,用于外部设备的控制。
2. EPIT 2种工作模式
通过 EPIOTx_CR 可以设置EPIT的工作模式。通过手册查询该寄存器 RLD 位置作用:
(1) set-and-forget
当 RLD为1时,计时器工作在 set-and-forget 模式,该模式即 “ 设置后就不用管 ”。
在此模式下,计数器从加载寄存器(EPIT_LR)获取数据;它不能直接从块数据总线写入。
每当计数器达到零时,EPIT_LR 中的值就会被加载到计数器中。然后这个值会递减到零。若要直接初始化计数器而不是等待计数达到零,需设置 EPIT 计数器覆写使能位(EPIT_CR [IOVW]),并使用所需的初始化值写入 EPIT_LR。
(2)free-running
当RLD为0 时,计时器工作在“自由运行”模式。在这个模式下,计数器从 0000 0000h 翻转到 FFFFFFFFh,而不会从模式寄存器重新加截值,翻转之后,计数器会继续向下计数。
要直接初始化计数器,也需要设置 EPIT 计数器覆盖使能位(EPIO_EPITCL [IOVW] ),并将所需要的初始化值写入 EPIT_LR。
3. 比较事件
当 EPIT_EPITCMPR 值与 EPIT_EPITCNR 中的值相匹配时,会设置一个比较状态标志 , 如果控制寄存器中的OCIEN 位被置位,还会产生一个中断。
下图是比较事件和中断的时序:
在对设置值、产生中断时序要求非常严格的情况下,需要细致了解其时序。 一般的情况下,可能不需要了解如此清楚。
二、IMX6ULL 的 EPIT 定时器
IMX6ULL 共有两个 EPIT 定时器,主要包含以下寄存器。
1. EPIT_CR
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)。
2. EPITx_SR
EPIT_SR 是状态寄存器,主要用于记录和提供与定时器相关的状态信息,只有bit0(OCIF) 有效,表示中断状态。 写1时清零。
当OCIF 位值为1时,表示发生中断, 值为0的时候表示中断没有发生。
处理完定时器中断,需要清除该标志位。
3. EPITx_LR
加载寄存器,设置计数器的加载值。
4. EPITx_CMPR
比较计数器,当计数器值和CMPR一致时,产生中断。
5. EPITx_CNR
计数器寄存器,当前计数值。
三、实验程序
本实验实现 500ms 周期的定时器,在EPIT的中断服务函数中让LED闪烁。
1. EPIT初始化
/**
* @brief EPIT初始化, 工作在 set-and-forget 模式
*/
void epit_init(EPIT_Type *base, unsigned int frac, unsigned int value) {
if(frac > 4095){
frac = 4095;
}
// 配置EPIT设置寄存器,先清0
base->CR = 0;
// 设置初始值为加载值 | 使能EPIT模块 | 使能中断 | 分频值 | 使能时钟
base->CR = (1 << 1) | (1 << 2) | (1 << 3) | (frac << 4) | (1 << 24);
// 设置加载值
base->LR = value;
// 设置比较值
base->CMPR = 0;
// 使能GIC中断
if(base == EPIT1)
GIC_EnableIRQ(EPIT1_IRQn);
else
GIC_EnableIRQ(EPIT2_IRQn);
// 注册中断服务函数
sys_irq_handle_register(EPIT1_IRQn, (system_irq_handler_t)epit_irqhandler, NULL);
// 定时器使能
base->CR |= 1 << 0;
}
分频值计算:
其中 Tclk = 66Mhz
如果分频值是1,则1秒进中断 66M次。 如果要500ms进一次,分频值设置1,计数器值设置为 66M/2。
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;
}
本文代码开源地址:
https://gitee.com/xundh/learn_i.mx6u.git