I.MX6U 裸机开发18.GPT定时器实现高精度延时

devtools/2024/11/24 11:00:08/

I.MX6U 裸机开发18.GPT定时器实现高精度延时

  • 一、GPT定时器简介
    • 1. GPT 功能
    • 2. 时钟源
    • 3. 框图
    • 4. 运行模式
      • (1)Restart mode
      • (2)Free-Run Mode
    • 5. 中断类型
      • (1)溢出中断 Rollover Interrupt
      • (2)输入捕获中断 Input Capture Interrupt 1,2
      • (3)输出捕获中断 Output Compare Interrupt 1,2,3
    • 6. 寄存器
      • (1) GPTx_CR
        • bit 0
        • bit 1
        • bit 2
        • bit 3
        • bit 4
        • bit 5
        • bits 6-8
        • bit 9
        • bit 10
        • bit 11-14
        • bit 15
        • bit22-20 OM1, bit25-23 OM2, bit 28-26 OM3
        • bit 29 FO1, bit30 FO2, bit31 FO3
      • (2) GPTx_PR 分频寄存器
      • (3) GPTx_SR 状态寄存器
        • **bit 0**: Output Compare 1 Flag (OF1)
        • **bit 1**: Output Compare 2 Flag (OF2)
        • **bit 2**: Output Compare 3 Flag (OF3)
        • **bit 3**: Input Capture 1 Flag (IF1)
        • **bit 4**: Input Capture 2 Flag (IF2)
        • **bit 5**: Rollover Flag (ROV)
      • (4) GPTx_IR 中断寄存器
      • GPTx_IR 中断寄存器
  • 二、定时器中断实现500ms定时
    • 1. 初始化 GPT 定时器
    • 2. 中断函数里实现LED闪烁
  • 三、实现高精度延时
    • 1. 实现高精度延时的做法
    • 2. 实现us延时
    • 3. 实现 ms 延时

一、GPT定时器简介

1. GPT 功能

IMX6ULL 的GPT定时器(General Purpose Timer)是一种通用定时器,可以用于生成精确的时间延迟、测量时间间隔、产生周期性中断等,以下是它的几个特性:

  • GPT 有一个 32 位的向上计数器。定时器的计数值可以通过外部引脚上的事件被捕获到一个寄存器中。
  • 捕获触发可以被编程为上升沿和/或下降沿。
  • GPT 还可以在输出比较引脚上生成一个事件,并在定时器达到编程值时产生一个中断。
  • GPT 有一个 12 位的预分频器,它从多个时钟源中提供一个可编程的时钟频率。

相比较,EPIT:

  • 32位向下计数器
  • 没有捕获功能

2. 时钟源

在这里插入图片描述
本文使用 ipg_clk 作为时钟源,即66MHz。

3. 框图

在这里插入图片描述

  1. 从左上角开始,输入时钟
  2. 时钟进入 Prescaler 12位分频器(值0~4095)
  3. 分频后进入 Timer Counter,即32位计数器
  4. GET_CAPTURE1, GET_CAPTURE2 实现捕获功能
  5. TIMER Output Reg1~3, 是三路时钟输出,Timer Count要与这三路值进行比较,
  6. GET_COMPARE1~3,三路比较输出

4. 运行模式

(1)Restart mode

自由运行模式,计数器从零开始计数,并在达到最大值后回到零,继续计数。这个模式通常用于测量时间间隔或生成周期性中断。
比较的时候,是比较定时器的计数值和比较寄存器OCR。

特点:

  1. 计数器不断循环计数。
  2. 可以配置中断,在计数器溢出时触发中断。
  3. 只有比较通道1适用这种模式。

(2)Free-Run Mode

输入捕获模式,计数器在检测到外部事件(如信号边沿)时捕获当前计数值,并将其存储在捕获寄存器中。这个模式通常用于测量外部事件的时间间隔。

特点:

  1. 计数器在检测到外部事件时捕获当前计数值。
  2. 可以配置中断,在捕获事件发生时触发中断。
  3. 三个通道都适用, 从0开始一直加到 0xFFFFFFFF,然后重新从0开始。

5. 中断类型

(1)溢出中断 Rollover Interrupt

计数器达到其最大值并回到零时,会触发溢出中断。这个中断通常用于周期性任务或需要精确时间间隔的应用。

(2)输入捕获中断 Input Capture Interrupt 1,2

可以捕获外部事件的时间戳。GPT有两个输入捕获通道,分别为输入捕获中断1(Input Capture Interrupt 1)和输入捕获中断2(Input Capture Interrupt 2)。

(3)输出捕获中断 Output Compare Interrupt 1,2,3

在计数器达到预设值时触发中断。GPT有三个输出比较通道,分别为输出比较中断1(Output Compare Interrupt 1)、输出比较中断2(Output Compare Interrupt 2)和输出比较中断3(Output Compare Interrupt 3)。

6. 寄存器

(1) GPTx_CR

GPTx_CR 是 GPT的控制寄存器,用于配置和控制 GPT 定时器的各种功能。以下是 GPTx_CR 寄存器的各个功能位的详细说明:

bit 0

GPT Enable: 使能GPT定时器,1使能

bit 1

GPT Enable Mode: 使能模式,0表示GPT定时器计数值默认为上次关闭的时候值,为1表示默认值为0

bit 2

GPT Debug Enable: 调试模式使能

bit 3

GPT Wait Mode Enable: 等待模式使能

bit 4

GPT Doze Mode Enable: 休眠模式使能

bit 5

GPT Stop Mode Enable: 停止模式使能

bits 6-8

GPT Clock Source: 时钟源选择

  • 000: 时钟源关闭
  • 001: 使用IPG时钟源
  • 010: 使用高频IPG时钟源
  • 011: 使用外部时钟源
  • 100: 使用外设时钟源
  • 101: 使用晶体振荡器作为参考时钟,频率为24 MHz
bit 9

GPT Free-Run or Restart Mode: 自由运行或重启模式,0为Restart 模式, 1为 Free-Run模式。

bit 10

EN_24M: 使能24 MHz晶体振荡器输入时钟。

  • 硬件复位会重置EN_24M位。
  • 软件复位不会影响EN_24M位。
bit 11-14

未使用

bit 15

SWR: 软件复位,这是GPT模块的软件复位位。它是一个自清除位。

  • 当模块处于复位状态时,SWR位被置位。
  • 当复位过程完成时,SWR位被清除。
  • 设置SWR位会将所有寄存器重置为默认复位值,除了GPT控制寄存器中的EN、ENMOD、STOPEN、WAITEN和DBGEN位。
    • 0: GPT不处于复位状态
    • 1: GPT处于复位状态
bit22-20 OM1, bit25-23 OM2, bit 28-26 OM3

设置比较输出功能,比较事件发生以后,相应的IO输出:

  • 000: 输出断开。引脚上无响应。
  • 001: 切换输出引脚,翻转输出;
  • 010: 清除输出引脚,清0。
  • 011: 设置输出引脚,置1。
    1xx: 在输出引脚上生成一个有效低脉冲(即一个输入时钟宽度)。在比较事件发生时,输出引脚立即设置为1,并在下一个输入时钟时生成一个低脉冲。
bit 29 FO1, bit30 FO2, bit31 FO3

强制输出比较通道3

  • 0: 写0无效。
  • 1: 在定时器输出比较通道3引脚上执行编程的引脚操作;OF3标志不设置。

本文实验使用 IPG时钟源, Restart Mode。

(2) GPTx_PR 分频寄存器

用来设置分频值。
bits 0-11: 分频值(Prescaler Value)
这些位用于设置预分频值。预分频值的范围通常为0到4095。
实际的分频因子为(分频值 + 1),即如果分频值为0,则分频因子为1;如果分频值为1,则分频因子为2,以此类推。

这个用来设置 Crystal Oscillator 24M 的分频。

(3) GPTx_SR 状态寄存器

GPTx_SR(Status Register)是GPT的状态寄存器,用于指示定时器的各种状态和事件。功能位的作用如下:

bit 0: Output Compare 1 Flag (OF1)
  • 当输出比较通道1发生比较事件时,该位被置位。
  • 0: 没有发生比较事件
  • 1: 发生了比较事件
bit 1: Output Compare 2 Flag (OF2)
  • 当输出比较通道2发生比较事件时,该位被置位。
  • 0: 没有发生比较事件
  • 1: 发生了比较事件
bit 2: Output Compare 3 Flag (OF3)
  • 当输出比较通道3发生比较事件时,该位被置位。
  • 0: 没有发生比较事件
  • 1: 发生了比较事件
bit 3: Input Capture 1 Flag (IF1)
  • 当输入捕获通道1发生捕获事件时,该位被置位。
  • 0: 没有发生捕获事件
  • 1: 发生了捕获事件
bit 4: Input Capture 2 Flag (IF2)
  • 当输入捕获通道2发生捕获事件时,该位被置位。
  • 0: 没有发生捕获事件
  • 1: 发生了捕获事件
bit 5: Rollover Flag (ROV)
  • 当计数器发生溢出时,该位被置位。
  • 0: 没有发生溢出
  • 1: 发生了溢出

(4) GPTx_IR 中断寄存器

GPTx_IR 中断寄存器

GPTx_IR(Interrupt Register)是GPT的中断寄存器,用于配置和控制定时器的中断功能,各位作用如下:

  • bit 0: Output Compare 1 Interrupt Enable (OF1IE)

    • 0: 禁用输出比较通道1中断
    • 1: 使能输出比较通道1中断
  • bit 1: Output Compare 2 Interrupt Enable (OF2IE)

    • 0: 禁用输出比较通道2中断
    • 1: 使能输出比较通道2中断
  • bit 2: Output Compare 3 Interrupt Enable (OF3IE)

    • 0: 禁用输出比较通道3中断
    • 1: 使能输出比较通道3中断
  • bit 3: Input Capture 1 Interrupt Enable (IF1IE)

    • 0: 禁用输入捕获通道1中断
    • 1: 使能输入捕获通道1中断
  • bit 4: Input Capture 2 Interrupt Enable (IF2IE)

    • 0: 禁用输入捕获通道2中断
    • 1: 使能输入捕获通道2中断
  • bit 5: Rollover Interrupt Enable (ROVIE)

    • 0: 禁用溢出中断
    • 1: 使能溢出中断

二、定时器中断实现500ms定时

在 bsp_delay.c 里实现下面功能。

1. 初始化 GPT 定时器


/*** @brief 初始化GPT定时器*/
void gpt1_timer_init(void)
{// bit0 软复位GPT1->CR = 0;GPT1->CR = 1 << 15;while(GPT1->SR & (1 << 15));// bit1, GPT 定时器计数器的初始值,为1表示默认值为0,0表示为上次关闭时候的值GPT1->CR |= (1 << 1);// bit6~8 时钟源,001表示ipg_clkGPT1->CR |= (1 << 6);// bit9 运行模式,设置为Restart模式(默认就是0,也可以不设置)GPT1->CR &= ~(1 << 9);// 设置分频值,使用PR寄存器,设置为66分频,这样进入GPT1的时钟为66MHz/66=1MHzGPT1->PR = 65;// 设置输出比较寄存器1的值,设置为1000000,即500msGPT1->OCR[0] = TIMER_DURATION;// bit0 使能输出比较中断GPT1->IR = (1 << 0);// 设置GIC中断GIC_EnableIRQ(GPT1_IRQn);// 注册中断服务函数sys_irq_handle_register(GPT1_IRQn, (system_irq_handler_t)gpt1_timer_irqhandler, NULL);// 使能GPT1定时器GPT1->CR |= (1 << 0);
}

2. 中断函数里实现LED闪烁


/*** @brief GPT中断服务函数*/
void gpt1_timer_irqhandler(unsigned int gicciar, void *param)
{static unsigned char state = 0;if(GPT1->SR & (1 << 0)) {state = !state;led_switch(LED0, state);}// 清除中断标志位GPT1->SR |= (1 << 0);
}

三、实现高精度延时

1. 实现高精度延时的做法

上面代码段里,

    // bit0 软复位GPT1->CR = 0;GPT1->CR = 1 << 15;while(GPT1->SR & (1 << 15));// bit1, GPT 定时器计数器的初始值,为1表示默认值为0,0表示为上次关闭时候的值GPT1->CR |= (1 << 1);// bit6~8 时钟源,001表示ipg_clkGPT1->CR |= (1 << 6);// bit9 运行模式,设置为Restart模式(默认就是0,也可以不设置)GPT1->CR &= ~(1 << 9);// 设置分频值,使用PR寄存器,设置为66分频,这样进入GPT1的时钟为66MHz/66=1MHzGPT1->PR = 65;

这里实现了1MHz的时钟设置,即每个计数是1uS,只要计算 GPT1->CNT 数值即可。

2. 实现us延时

/**
* @brief 延时us
*/
void delay_us(unsigned int us){unsigned long old_cnt;unsigned long tcntvalue = 0;old_cnt = GPT1->CNT;while(1){unsigned long new_cnt = GPT1->CNT;if(new_cnt != old_cnt){if(new_cnt > old_cnt){tcntvalue += new_cnt - old_cnt;}else{tcntvalue += 0xffffffff - old_cnt + new_cnt;}}if(tcntvalue >= us){break;}}
}

3. 实现 ms 延时

/**
* @brief 延时ms
*/
void delay_ms(unsigned int ms){while(ms--){delay_us(1000);}
}

main 函数:

#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"
#include "bsp_keyfilter.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中断一次 */
//    keyfilter_init();   /* 初始化按键 */
//    gpt1_timer_init();  /* 初始化GPT1定时器 */gpt1_delay_init();  /* 初始化GPT1高精度延时 */while(1) {delay_ms(500);led_switch(LED0, 0);delay_ms(500);led_switch(LED0, 1);}return 0;
}

本文代码开源地址;
https://gitee.com/xundh/learn_i.mx6u.git


http://www.ppmy.cn/devtools/136532.html

相关文章

websocket消息的实现

1. 创建 WebSocket 连接 WebSocket 是通过 WebSocket 对象建立的。连接成功后&#xff0c;前端可以与服务器双向通信。 const socket new WebSocket(ws://your-server-url);// 监听连接建立 socket.onopen () > {console.log(WebSocket connection established);// 可以…

SELinux知识点

SELinux 软件安全性 《关于UNIX的安全》中Dennis Ritchie提到&#xff1a;“首先要面对的事实是&#xff0c;UNIX的开发者并没有考虑安全问题&#xff0c;单这一点就单会引发大量的漏洞”。主要是因为防火墙通常不具备查杀病毒的能力&#xff0c;只能对数据包过滤&#xff0c…

Mac设置java环境变量

Mac电脑中存在多个jdk版本,如何配置java环境变量为指定版本jdk? 一、查看所有已安装的 JDK 版本 /usr/libexec/java_home -V二、临时设置 export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)三、永久设置 如果需要永久使用指定版

计算机网络的初步认识

文章目录 一、初识计算机网络1.1、基本概念和特点1.1.1、基本概念1.1.2、特点1.2、分类1.3、性能指标1.4、体系结构1.4.1、体系结构的基本认识1.4.2、TCP/IP的深入认识二、初始互联网2.1、互联网概念和特点2.1.1、概念2.1.2、特点2.2、互联网组成2.2.1、边缘部分2.2.2、核心部分…

微网能量管理研究

微网能量管理研究的重点 微网系统的建模 建立分布式能源单元模型以及微网系统的整体运行、协调控制和优化配置等方面的模型 分布式电源控制策略 微网内分布式电源及储能系统运行依赖于电力电子接口技术&#xff0c;需要相应的充放电控制策略 再生能源发电预测 准确预测太阳能…

Redis分布式锁的原理与Redisson实现

Redis分布式锁的原理与Redisson实现 目录 引言Redis分布式锁的基本原理Redisson实现Redis分布式锁Redisson分布式锁的使用示例小结 引言 在分布式系统中&#xff0c;多个服务实例同时访问共享资源时&#xff0c;可能会导致数据不一致或竞争条件。为了解决这些问题&#xff…

CANDENCE: 原理图中如何批量修改元件封装

原理图中如何批量修改元件封装 一、选中一部分元件更换封装 更换下图中的几个电阻的封装 选中这几个电阻&#xff0c;点击 “edit properties” 弹出以下对话框 点击“pivot”, 找到封装一栏 可以单个修改 也可以多个一起修改 修改完成 二、选中一页原理图中的元件更换封装…

从繁琐到优雅:用 PyTorch Lightning 简化深度学习项目开发

从繁琐到优雅&#xff1a;用 PyTorch Lightning 简化深度学习项目开发 在深度学习开发中&#xff0c;尤其是使用 PyTorch 时&#xff0c;我们常常需要编写大量样板代码来管理训练循环、验证流程和模型保存等任务。PyTorch Lightning 作为 PyTorch 的高级封装库&#xff0c;帮助…