IMX6ULL裸机开发——EPIT与GPT
EPIT增强型周期中断定时器:
i.MX6ULL 内置的专用周期定时器,共 2 路(EPIT1、EPIT2),32 位向下计数器,带 12 位预分频器。核心特点是硬件自动重装,计数器减到 0 触发中断后,硬件自动把加载寄存器的值重新载入计数器,不需要软件在中断服务函数里手动重写初值。功能精简,无输入捕获、无 PWM 输出,只用于产生稳定的周期性中断,适合操作系统系统节拍、定时采样、周期性任务。

EPIT 相当于阉割版、向下计数、32 位的 STM32 基本定时器,只保留周期中断;STM32 通用 / 高级定时器是多功能外设,EPIT 没有捕获、PWM、编码器等功能。i.MX6ULL 增强型周期中断定时器,专用极简周期定时器;STM32 的 TIM 分为基本定时器、通用定时器、高级定时器。
| 对比项 | EPIT(i.MX6ULL) | STM32 定时器(TIM) |
|---|---|---|
| 计数器 | 32 位,向下计数 | 基本定时器:16 位向上;通用 / 高级:16/32 位,支持向上、向下、中心对齐 |
| 自动重载 | 硬件自动重装,计数到 0,硬件自动把 LR 加载到 CNT,中断里不用软件写初值 | ARR 自动重载(影子寄存器),溢出后自动加载;但是有缓冲机制,修改 ARR 不一定立刻生效 |
| 功能范围 | 只有周期定时中断,无输入捕获、无 PWM 生成,仅可引脚翻转 | 功能丰富:定时中断、输入捕获、输出比较、PWM、正交编码器、DMA 触发;高级定时器还有互补 PWM、死区、刹车保护 |
| 寄存器 | CR 控制寄存器、LR 加载寄存器、CMPR 比较寄存器、SR 状态寄存器 | PSC 预分频、CNT 计数器、ARR 自动重载、CCR 捕获比较寄存器等,寄存器更多 |
| 预分频 | 12 位,1~4096 分频 | 16 位,1~65536 分频 |
| 定位 | 只做周期性中断(RTOS 系统节拍首选) | 多功能,一个定时器可同时做多件事(PWM + 捕获 + 定时) |
| 中断源 | 仅比较匹配中断(计数到 CMPR=0 即计数到 0) | 更新中断、捕获中断、比较中断、触发中断等多种中断源 |
EPIT 核心逻辑:计数器从 LR 值向下递减,一般都是设计比较值为0,所以减到 0 产生中断,硬件自动重载 LR 的值,循环往复。以下为配置EPIT的具体步骤
1. 初始化阶段
- 关闭 EPIT:写 CR 寄存器,先禁止定时器,防止配置过程中异常触发
- 选择时钟源:配置 CR 的 CLKSRC 位,一般选择 IPG 时钟(66MHz)
- 配置预分频:设置 CR 的 PRESCALER 位,对时钟分频,得到需要的计数频率
- 配置工作模式:开启自动重载模式 RLD,开启比较中断 OCIEN;配置 ENMOD 模式(计数器初始值来源)
- 设置加载寄存器 LR:写入定时初值,决定计数的起始值
- 设置比较寄存器 CMPR:一般设为 0,代表计数减到 0 触发中断
- 配置 GIC 中断控制器:开启 EPIT 中断、设置中断优先级,注册中断服务函数
- 清除中断标志位 SR,清除残留中断
- 使能 EPIT 定时器,启动计数
2. 运行与中断处理阶段
- 定时器启动后,CNR 从 LR 的值开始向下计数
- CNR == CMPR(0),触发中断,置位中断标志
- 进入中断服务函数:
- 判断中断标志位
- 执行用户任务(点灯、计数、采样等)
- 软件写 SR 寄存器,清除中断标志(非常关键,不清除会重复进中断)
- 硬件自动把 LR 重新载入 CNR,继续下一轮计数,中断服务函数中不需要手动重装初值
3. 定时周期计算公式
定时周期 = LR / (输入时钟 / (预分频 + 1))
示例:IPG=66MHz,预分频 65(66 分频),LR=1000000 计数频率 = 66M/(65+1)=1MHz,LR=1000000 → 定时 1s。
示例代码如下:
void epit1_init(void)
{
unsigned int temp = EPIT1->CR;
temp = 0;
temp &= ~(0x3 << 24);
temp |= (0x1 << 24); //设置定时器时钟源为外设时钟66MHz
temp &= ~(0xFFF << 4);
temp |= (65 << 4); //设置定时器预分频器的分频为66分频
temp |= (1 << 3); //设置定时器重装模式为从寄存器重装值
temp |= (1 << 1); //设置定时器的初始值来源为重装载寄存器
temp |= (1 << 2); //使能定时器输出比较中断
EPIT1->CR = temp;
EPIT1->CMPR = 0; //设置定时器比较值为0
EPIT1->LR = 1000000; //设置定时器重装载值为1000000
GIC_EnableIRQ(EPIT1_IRQn); //使能定时器的GIC中断
EPIT1->CR |= (1 << 0); //使能定时器开始计时
}
GPT通用定时器:
i.MX6ULL 的多功能通用定时器,共 2 路(GPT1、GPT2),32 位向上计数器,同样带 12 位预分频器与多时钟源选择。支持2 路输入捕获(测量外部脉冲宽度)、3 路输出比较(生成 PWM、翻转引脚),中断来源包含捕获中断、比较中断、溢出中断。既可自由运行做高精度微秒级延时,也可配置成周期中断,功能全面。适合脉冲测量、PWM 波形生成、信号检测、高精度延时等场景。

GPT (i.MX6ULL) 与 STM32 定时器对比
| 对比项 | GPT(i.MX6ULL) | STM32 TIM(通用 / 高级定时器) |
|---|---|---|
| 计数器 | 32 位,向上计数,溢出后回 0 | 16 位为主,部分 32 位;支持向上、向下、中心对齐计数模式 |
| 自动重载 | 无硬件自动重载机制;溢出后计数器归 0,需要软件处理周期定时 | ARR 自动重载寄存器,带影子缓冲,溢出硬件自动重载;支持预装载开关 |
| 功能 | 2 路输入捕获、3 路输出比较;可引脚翻转、PWM 生成;溢出中断、捕获中断、比较中断 | 输入捕获、输出比较、PWM、互补 PWM、死区、刹车、编码器接口、DMA 触发 |
| 预分频 | 12 位,分频系数 1‑4096 | 16 位,分频系数 1‑65536 |
| 时钟源 | 内部 IPG 时钟、外部参考时钟等多选择 | 内部时钟、外部 TI 引脚时钟、ETR 外部触发时钟 |
| 中断源 | 溢出中断、捕获中断、输出比较中断 | 更新中断、捕获 / 比较中断、触发中断、刹车中断等 |
| 周期定时 | 做周期中断需要在溢出中断里软件重设比较值,无自动重装 | 配置 ARR 即可硬件完成周期,无需软件重装 |
| 定位 | 通用定时器,兼顾定时、捕获、PWM,无编码器、死区刹车保护 | 功能极强,电机控制可直接用高级定时器 |
GPT 寄存器简要
- GPT_CR:控制寄存器,使能、时钟源、模式选择
- GPT_PR:预分频寄存器
- GPT_OCR1/OCR2/OCR3:输出比较寄存器
- GPT_ICR1/ICR2:输入捕获寄存器
- GPT_SR:状态寄存器(中断标志)
- GPT_IR:中断使能寄存器
一般我们需要精确定时会借助GPT来实现,具体原理如下:

具体配置流程如下:
1、设置 GPT1 定时器 先设置 GPT1_CR 寄存器的 SWR (bit15) 位,软件复位 GPT1 外设;复位完成后配置 GPT1_CR 的 CLKSRC (bit8:6) 位,选择时钟源为 ipg_clk,配置 GPT1 工作模式。
2、设置 GPT1 的分频值 配置 GPT1_PR 寄存器的 PRESCALAR (bit11:0) 位,写入分频系数,完成时钟分频。
3、设置 GPT1 的比较值 本实验不使用输出比较中断,将输出比较寄存器 GPT1_OCR1 设置为最大值0XFFFFFFFF。
4、使能 GPT1 定时器 全部参数配置完毕,将 GPT1_CR 寄存器 EN (bit0) 位置 1,使能 GPT1 定时器,定时器开始计数。
5、编写延时函数 GPT1 正常运行,读取 GPT1 计数器 CNT 值,基于计数值差值原理,分别编写 us、ms 高精度阻塞延时函数。
具体示例代码如下;
GPT初始化
void gpt_init(void)
{
GPT1->CR |= (0x01 << 15); //复位定时器的状态和寄存器
while(GPT1->CR & (0x01 << 15));
unsigned int temp = GPT1->CR;
temp &= ~(0x07 << 6); //设置定时器的时钟来源为外设时钟
temp |= (1 << 6);
temp &= ~(1 << 9); //设置定时器的工作模式为从零向上计数到顶
temp |= (1 << 9);
GPT1->CR = temp;
GPT1->PR &= ~(0xFFF << 0); //设置定时器预分频器为66分频
GPT1->PR |= (65 << 0);
GPT1->CR &= ~(1 << 1); //设置定时器失能后保存当前计数值
GPT1->CR |= (1 << 0); //使能定时器开始计数
}
延时函数编写:
void delay_us(unsigned int n)
{
unsigned int new = 0;
unsigned int old = GPT1->CNT;
while(1)
{
new = GPT1->CNT;
if(new - old >= n)
{
break;
}else if((new + (0xFFFFFFFFU - old) )>= n)
{
break;
}
}
}
两个分支逻辑
-
没有发生计数器溢出:
new > oldnew‑old就是已经过去的 tick 数;差值≥n,时间到,退出。 -
发生计数器溢出(new < old):计数器从
0xFFFFFFFF回卷到 0 继续计数0xFFFFFFFFU‑old:old 到最大计数值还剩多少 tick;new:溢出之后,从 0 开始又跑了多少 tick; 两者相加就是总共走过的 tick 数,总和≥n 代表延时完成。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)