ARM-07-i.MX6ULL-EPIT定时器和GPT

一,EPIT定时器

这张图是 i.MX6ULL 芯片中 EPIT 定时器模块的框图

(1)EPIT 定时器工作原理:

  1. 时钟源​ → 多路选择器选时钟(可选关闭、IPG 时钟、32K 时钟、高速时钟)

  2. 分频​ → 12 位预分频器(分频系数 1~4096)

  3. 计数​ → 32 位计数器(从加载寄存器值开始向下计数)

  4. 比较​ → 与比较寄存器值匹配时触发比较器

  5. 输出控制​ → 比较触发中断(ITIF/ITIE)和输出引脚(EPITn_OUT)

  6. 重载​ → 计数到 0 时自动从加载寄存器重载,继续计数

核心流程:时钟 → 分频 → 计数 → 比较 → 中断/输出 → 重载循环

应用:定时中断、PWM 生成、精确延时。

**Set-and-forget mode(设置即忘模式)**​

一次性配置加载值和比较值,定时器自动循环工作,无需软件反复干预。

**Free-running mode(自由运行模式)**​

计数器从初始值不断递减→归零→自动重载,持续循环计数,永不停止。

配置定时器

(2)EPITx_CR

(3)配置代码

cs 复制代码
void epit1_init(irq_handler_t handler)
{
    // 配置EPIT1控制寄存器(EPIT1->CR)
    unsigned int tmp = EPIT1->CR;
    // 清除时钟源选择位(CLCKSRC, bit25:24)
    tmp &= ~(0x3 << 24);
    // 设置时钟源为Peripheral时钟(ipg_clk, 66MHz),CLCKSRC=01
    tmp |= (0x1 << 24);
    // 使能比较中断(OIEN, bit17)
    tmp |= (1 << 17);
    // 清除分频值(PRESCALAR, bit15:4)
    tmp &= ~(0xfff << 4);
    // 设置分频值=65 → 66分频(65+1),时钟=66MHz/66=1MHz(1us计数)
    tmp |= (65 << 4);
    // 设置工作模式为set-and-forget(bit3=1)
    tmp |= (1 << 3);
    // 使能比较中断(bit2=1)
    tmp |= (1 << 2);
    // 设置计数器初始值来源为加载寄存器(ENMOD, bit1=1)
    tmp |= (1 << 1);
    // 写入配置到CR
    EPIT1->CR = tmp;

    // 设置加载寄存器(LR)=1000000 → 计数1秒(1MHz计数频率)
    EPIT1->LR = 1000000;
    // 设置当前计数值(CNR)=1000000 → 初始值与LR相同
    EPIT1->CNR = 1000000;
    // 设置比较值(CMPR)=0 → 计数到0时产生中断
    EPIT1->CMPR = 0;

    // 注册EPIT1中断处理函数
    request_irq(EPIT1_IRQn, handler);

    // 使能EPIT1(EN, bit0=1)
    EPIT1->CR |= (1 << 0);
}

二 ,GPT

延时函数是很常用的 API 函数,在前面的实验中我们使用循环来实现延时函数,但是使用循环
来实现的延时函数不准确,误差会很大。虽然使用到延时函数的地方精度要求都不会很严格(要求严格的 话就使用硬件定时器了),但是延时函数肯定是越精确越好,这样延时函数就可以使用在某些对时序要求 严格的场合。下面我们来学习一下如何使用硬件定时器来实现高精度延时。
GPT 是 i.MX6U 芯片内置的通用定时器模块,它是一个 32 位向上递增计数器,支持输入捕获、输出比较、中断生成等功能,可以工作在重新启动或自由运行两种模式,是精确延时的理想硬件基础。
我们将 GPT 的时钟源配置为 ipg_clk(66MHz) ,并通过 12 位分频器设置 66 分频 ,得到 1MHz 的计数频率,即计数器每计 1 个数对应 1 微秒,为高精度延时提供时间基准。
GPT也有两种工作模式:
重新启动(restart)模式:在此模式下,当计数值和比较寄存器中的值相等的话计数值就会清零,然后 重新从0X00000000 开始向上计数,只有比较通道 1 才有此模式!向比较通道 1 的比较寄存器写入任何数据都 会复位 GPT 计数器。对于其他两路比较通道(通道 2 和 3),当发生比较事件以后不会复位计数器。
自由运行(free-run)模式:当在此模式下,此模式适用于所有三个比较通道,当比较事件发生以后并 不会复位计数器,而是继续计数,直到计数值为 0XFFFFFFFF,然后重新回0X00000000。
我们的最终目标是利用 GPT 硬件定时器实现高精度的微秒和毫秒级延时函数,取代不准确的软件循环延时,使其能够用于 UART 波特率生成、传感器时序控制、通信协议超时处理等对时序敏感的场合,提升系统可靠性。

(1)GPT 控制寄存器 (GPTx_CR)

SWR(bit15):软件复位位。写 1 复位 GPT,复位完成后硬件自动清零。
FRR(bit9):运行模式选择。0=比较通道1工作在重启模式,1=所有通道工作在自由运行模式。
CLKSRC(bit8:6):时钟源选择。1=ipg_clk(我们的选择)。
ENMOD(bit1):使能模式。0=关闭时保留计数值,1=关闭时清零计数器。
EN(bit0):使能位。1=启动定时器,0=停止。

(2)GPT 预分频寄存器 (GPTx_PR)

  • PRESCALER(bit11:0):12 位分频值。范围 0~4095,对应 1~4096 分频。我们设 65 实现 66 ()分频(65+1)。

(3)配置代码如下

cs 复制代码
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "gpt.h"

// 软件复位GPT1,置位SWR(bit15)后等待其自动清零(复位完成)
static inline void gpt1_reset(void)
{
    GPT1->CR |= (1 << 15);        // SWR(bit15)=1,复位GPT
    while((GPT1->CR & (1 << 15))); // 等待SWR自动清零
}

// 初始化GPT1:复位→配置CR/PR→使能定时器
void gpt1_init(void)
{
    gpt1_reset();  // 复位GPT1
    unsigned int tmp = GPT1->CR;
    
    // 清除中断掩码位IMx(bit20~28)和输出模式位OMx(bit16~19)
    tmp &= ~(0x1ff << 20);
    tmp &= ~(0xf << 16);
    
    // 配置工作模式和时钟源
    tmp |= (1 << 9);     // FRR(bit9)=1:所有比较通道自由运行模式
    tmp &= ~(0x7 << 6);  // 清除CLKSRC(bit8:6)
    tmp |= (1 << 6);     // CLKSRC(bit8:6)=001,选择ipg_clk(66MHz)时钟源
    tmp &= ~(1 << 1);    // ENMOD(bit1)=0:关闭时保留计数值
    GPT1->CR = tmp;      // 写入配置
    
    // 配置预分频器
    tmp = GPT1->PR;      // 预分频寄存器
    tmp &= ~(0xfff << 0);// 清除PRESCALER(bit11:0)
    tmp |= (65 << 0);    // 分频值=65 → 66分频(65+1),时钟=66MHz/66=1MHz(1us计数)
    GPT1->PR = tmp;
    
    GPT1->CR |= (1 << 0); // EN(bit0)=1:使能GPT1定时器
}

// 微秒级延时:通过读取GPT1_CNT差值计算时间(处理32位溢出)
void inline delay_us(unsigned int num)
{
    unsigned int counter = 0;
    unsigned int cur_couter = 0;
    unsigned int old_couter = GPT1->CNT; // 记录初始计数值
    while(1)
    {
        cur_couter = GPT1->CNT;
        if(cur_couter == old_couter)
            continue;
        // 计算计数值增量(处理溢出:cur < old 时说明溢出,加0xffffffff)
        if(cur_couter > old_couter)
            counter += cur_couter - old_couter;
        else
            counter += cur_couter + 0xffffffff - old_couter;
        if(counter >= num)  // 达到目标延时则退出
            return;
        old_couter = cur_couter;
    }
}

// 毫秒级延时:循环调用delay_us(1000)
void delay_ms(unsigned int num)
{
    while(num--)
    {
        delay_us(1000);
    }
}
相关推荐
蓝凌y2 小时前
51单片机之数码管0~9显示
单片机·嵌入式硬件·51单片机
CODE_RabbitV2 小时前
STM32 开发中 C 语言结构体复习(精简版)
c语言·stm32·嵌入式硬件
皮皮哎哟2 小时前
ARM—点灯(基于正点原子的IMX6U-mini)
arm开发·单片机·嵌入式硬件·imx6ull·点灯·固件库
可乐鸡翅好好吃2 小时前
一次因 MPU6050 硬件异常导致的 nRF52840 启动卡顿问题总结
单片机·嵌入式硬件
爱喝纯牛奶的柠檬2 小时前
基于STM32和电阻分压模块的电压测量
stm32·单片机·嵌入式硬件
dashizhi20152 小时前
服务器共享禁止外部设备访问、共享文件禁止非单位内部电脑访问?
stm32·单片机·嵌入式硬件
坤坤藤椒牛肉面2 小时前
ARM——General Purpose Timer (GPT)
arm开发·gpt
电子科技圈3 小时前
芯科科技闪耀2026嵌入式世界展以Connected Intelligence赋能,构建边缘智能网联新生态
人工智能·嵌入式硬件·mcu·物联网·智慧城市·健康医疗·智能硬件
llilian_163 小时前
音频分析仪 专业音频分析仪破解行业测试痛点实战解析 音频测试仪 专业音频分析仪
大数据·功能测试·单片机·测试工具·音视频