嵌入式硬件——I.MX6ULL EPIT(增强型周期中断定时器)
完整流程整理
EPIT(Enhanced Periodic Interrupt Timer)是I.MX6ULL的核心定时器外设,核心功能是周期性产生中断,支持精准定时控制,广泛用于LED翻转、按键消抖、定时任务调度等场景。以下从原理说明、完整流程(初始化+中断处理)、代码实现三部分展开整理。
一、EPIT核心概念与原理
核心功能与特点
- 32位向下计数器:从加载值(LR寄存器)开始递减,计数到0或与比较值(CMPR)相等时触发事件。
- 时钟源可选:支持3种时钟源(
ipg_clk
、ipg_clk_32k
、ipg_clk_highfreq
),默认选用ipg_clk
(66MHz,需提前通过CCM配置)。 - 12位分频:分频范围1~4096(PRESCALAR寄存器,0~4095对应1~4096分频)。
- 两种工作模式:
set-and-forget
模式(常用):计数器计数到0后,自动从LR寄存器重新加载初始值,循环计数。free-running
模式:计数器计数到0后,从0xFFFFFFFF重新开始计数,不依赖LR寄存器。
- 比较中断:当计数器值(CNR)与比较值(CMPR)相等时,触发中断(需使能OCIEN位)。
关键寄存器说明
寄存器 | 核心作用 |
---|---|
EPITx_CR | 控制寄存器:配置时钟源(CLKSRC)、分频(PRESCALAR)、工作模式(RLD)、中断使能(OCIEN)等。 |
EPITx_LR | 加载寄存器:存储计数器初始值(set-and-forget模式下的循环初始值)。 |
EPITx_CMPR | 比较寄存器:存储比较值,计数器值等于该值时触发中断。 |
EPITx_CNR | 计数寄存器:实时存储当前计数值(只读,向下计数)。 |
EPITx_SR | 状态寄存器:仅bit0(OCIF)有效,为1表示触发比较中断,需写1清零。 |
二、EPIT完整流程(初始化+中断处理)
阶段1:EPIT初始化流程(核心步骤)
初始化的目标是配置时钟源、分频、工作模式、中断,并启动定时器。
步骤 | 操作内容 |
---|---|
1 | 清零控制寄存器,确保初始状态干净 |
2 | 配置时钟源 |
3 | 配置分频值 |
4 | 选择工作模式 |
5 | 使能比较中断 |
6 | 配置计数器初始值来源 |
7 | 设置加载值(LR)和比较值(CMPR) |
8 | 注册中断服务函数 |
9 | 配置GIC中断(优先级+使能) |
10 | 启动EPIT定时器 |
阶段2:EPIT中断处理流程
当计数器值(CNR)等于比较值(CMPR)时,触发中断,进入中断服务函数。
步骤 | 操作内容 |
---|---|
1 | 检查中断标志(OCIF) |
2 | 执行中断任务 |
3 | 清除中断标志 |
定时周期计算(示例)
以初始化参数为例,计算定时周期(单位:秒):
- 时钟源频率:
ipg_clk = 66MHz
(66,000,000 Hz) - 分频值:
65
(对应66分频,实际分频系数=PRESCALAR+1) - 加载值(LR):
1000000
(计数器从1000000递减到0)
周期公式:
周期 = (LR值 × 分频系数) / 时钟源频率
代入示例:
周期 = (1000000 × 66) / 66000000 = 1秒
三、EPIT代码实现(完整代码+说明)
头文件(epit.h):声明函数接口
#ifndef __EPIT_H__
#define __EPIT_H__// 声明EPIT初始化函数,无参数(示例中固定配置1秒周期)
extern void init_epit1(void);#endif
源文件(epit.c):初始化与中断处理
#include "epit.h" // 自身头文件
#include "MCIMX6Y2.h" // 寄存器定义
#include "led.h" // LED控制函数(示例任务)
#include "interrupt.h" // 中断注册函数
#include "core_ca7.h" // GIC中断控制函数// 1. EPIT中断服务函数:定时触发时执行
void epit1_interrupt_handler(void)
{// 步骤1:检查中断标志(确认是EPIT比较中断)if ((EPIT1->SR & (1 << 0)) != 0){// 步骤2:执行定时任务(示例:翻转LED)led_nor();// 步骤3:清除中断标志(写1清零OCIF位)EPIT1->SR |= (1 << 0);}
}// 2. EPIT初始化函数:配置定时器与中断
void init_epit1(void)
{// 步骤1:清零控制寄存器,复位初始状态EPIT1->CR = 0;
}
主函数实现与初始化流程
主函数中需按顺序调用初始化函数,确保硬件模块正确配置。以下是关键实现步骤:
#include "led.h"
#include "beep.h"
#include "MCIMX6Y2.h"
#include "key.h"
#include "core_ca7.h"
#include "interrupt.h"
#include "clock.h"
#include "epit.h"int main(void)
{init_clock(); // 配置系统时钟,包括EPIT时钟源ipg_clk=66MHzsystem_interrupt_init(); // 初始化GIC中断控制器,使能中断处理init_beep(); // 可选:蜂鸣器初始化(若需声学反馈)init_led(); // LED初始化,为中断任务提供视觉输出init_key(); // 可选:按键初始化(若需外部触发)init_epit1(); // 配置EPIT定时器为1秒周期中断模式while(1) {} // 主循环保持空转,依赖中断驱动任务return 0;
}
四、关键注意事项
中断标志清除方式
EPIT的SR寄存器必须通过写1清除中断标志,写0将导致中断重复触发。典型中断服务函数实现如下:
void EPIT1_IRQHandler(void)
{EPIT1->SR |= 1; // 写1清除中断标志led_toggle(); // 执行定时任务(如LED翻转)
}
工作模式选择
- 周期性定时(如1秒LED翻转):配置为
set-and-forget
模式(RLD=1),计数器自动重载初始值。 - 自由计数模式:配置为
free-running
(RLD=0),计数器递减至0后停止。
定时周期调整方法
- 缩短周期:减小加载寄存器(LR)值或降低分频系数(PRESCALAR)。
- 延长周期:增大LR值(上限32位数值4294967295)或提高分频系数(上限4095)。
时钟源依赖
EPIT的时钟源(如ipg_clk
)需通过CCM模块提前配置,确保时钟频率稳定。在clock.c
中需正确设置分频参数。
五、EPIT工作流程总结
配置阶段
通过寄存器设置时钟源、分频比、重载值及中断使能,调用init_epit1()
启动定时器。触发阶段
计数器从LR值开始递减,达到比较值时触发中断,硬件自动跳转至中断服务函数。处理阶段
在中断服务函数中执行任务(如LED控制),清除中断标志后等待下一次触发。
典型应用场景
- 按键消抖:配置10ms定时中断检测按键状态。
- PWM模拟:高频定时翻转GPIO生成占空比信号。
- 系统任务调度:1秒周期刷新外设(如LCD显示)。