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. 初始化阶段

  1. 关闭 EPIT:写 CR 寄存器,先禁止定时器,防止配置过程中异常触发
  2. 选择时钟源:配置 CR 的 CLKSRC 位,一般选择 IPG 时钟(66MHz)
  3. 配置预分频:设置 CR 的 PRESCALER 位,对时钟分频,得到需要的计数频率
  4. 配置工作模式:开启自动重载模式 RLD,开启比较中断 OCIEN;配置 ENMOD 模式(计数器初始值来源)
  5. 设置加载寄存器 LR:写入定时初值,决定计数的起始值
  6. 设置比较寄存器 CMPR:一般设为 0,代表计数减到 0 触发中断
  7. 配置 GIC 中断控制器:开启 EPIT 中断、设置中断优先级,注册中断服务函数
  8. 清除中断标志位 SR,清除残留中断
  9. 使能 EPIT 定时器,启动计数

2. 运行与中断处理阶段

  1. 定时器启动后,CNR 从 LR 的值开始向下计数
  2. CNR == CMPR(0),触发中断,置位中断标志
  3. 进入中断服务函数:
    • 判断中断标志位
    • 执行用户任务(点灯、计数、采样等)
    • 软件写 SR 寄存器,清除中断标志(非常关键,不清除会重复进中断)
  4. 硬件自动把 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 位,向上计数,溢出后回 016 位为主,部分 32 位;支持向上、向下、中心对齐计数模式
自动重载无硬件自动重载机制;溢出后计数器归 0,需要软件处理周期定时ARR 自动重载寄存器,带影子缓冲,溢出硬件自动重载;支持预装载开关
功能2 路输入捕获、3 路输出比较;可引脚翻转、PWM 生成;溢出中断、捕获中断、比较中断输入捕获、输出比较、PWM、互补 PWM、死区、刹车、编码器接口、DMA 触发
预分频12 位,分频系数 1‑409616 位,分频系数 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;
        }
    }
}

两个分支逻辑

  1. 没有发生计数器溢出new > old new‑old 就是已经过去的 tick 数;差值≥n,时间到,退出。

  2. 发生计数器溢出(new < old):计数器从0xFFFFFFFF回卷到 0 继续计数 0xFFFFFFFFU‑old:old 到最大计数值还剩多少 tick; new:溢出之后,从 0 开始又跑了多少 tick; 两者相加就是总共走过的 tick 数,总和≥n 代表延时完成。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐