GPT
-介绍
GPT有一个32位向上计数器,定时计数器值可以使用外部引脚上的事件捕获到寄存器中,捕获触发器可以被编程为上升沿和下降沿。GPT还可以在输出比较引脚上生成事件,并在定时器达到编程值时产生中断。GPT有一个12位预分频器,它提供从多个时钟源获得的可编程时钟频率
-特征
1.一个带时钟源选择的32位向上计数器,包括外部时钟
2.俩个具有可编程触发边缘的输入捕获通道
3.三个具有可编程输出模式的输出比较通道(还提供强制比较功能)
4.可编程为在低功耗和调试模式下处于活动状态
5.在捕获、比较和翻转事件时中断生成
6.为计数器操作重新启动或自由运行模式
-GPT的工作原理
选择时钟信号
IMX6ULL有4个时钟源可供GPT选择输入到预分频器,分别为:
1.高频参考时钟(ipg_clk_highfreq)
2.低频参考时钟(ipg_clk_32k)
3.外围时钟(ipg_clk)
4.外部时钟(GPT_CLK)或者晶体振荡器时钟(ipg_clk_24M)
(外部时钟或晶体振荡器只能选择一个)
这里选择ipg_clk=66MHZ作为GPT定时器的输入时钟源,芯片在启动的时候,芯片内部的程序已经做了系统时钟的初始化
预分频设置寄存器(GPT_PR)
时钟频率与预分频数的关系:最终输入频率=时钟频率/(预分频数+1)
GPT计数器工作模式
GPT计数器可以编程为以俩种模式之一工作:重新启动模式或自由运行模式
在重新启动模式下(可通过GPT控制寄存器GPT_CR选择),当计数器达到比较值时,计数器复位并从0x000000000再次启动(重新启动功能仅与比较通道1相关联)
在自由运行模式下,当所有3个通道发生比较事件时,计数器不会重置;相反,计数器会继续计数,直到0xffffffffff,然后归零
GPT操作
通用计时器(GPT)有一个计数器(GPT_CNT),它是一个32位自由运行的向上计数器,它在软件启用后开始计数(EN=1)
tips:
1.如果禁用GPT计时器(EN=0),则主计数器和预分频计数器将冻结其当前计数值。ENMOD位确定设置EN位并再次启用计数器时GPT计数器的值
2.如果设置了ENMOD位(=1),则启用GPT时,主计数器和预分频器计数器值将重置为0(EN=1)
3.如果ENMOD位被编程为0,则当GPT再次启用时(EN=1),主计数器和预分频器计数器从其冻结值重新开始计数
软件复位(GPT_CR控制寄存器中的SWR位)复位除EN,ENMOD,STOPEN,WAITEN和DBGEN位之外的所有寄存器位。这些位的状态不受软件复位的影响(禁用GPT时,可以进行软件复位)
-GPT的输入捕获
使用场景
在嵌入式开发中,经常需要捕获传感器的高电平(或低电平)信号的持续时间,如红外解码信号,编码器输入信号等
直观的理解,就是要不断的检测这个信号,当信号从0变成1时,记录一个时间time1,再从1变成0时,记录另一个时间time2,俩个时间差就是高电平的持续时间(time2-time1)
工作原理
1.启动定时器,让CNT计数器在不停的计数
2.首先配置定时器的输入通道为上升沿捕获,这样当检测到从0到1的跳变时,ICR(捕获寄存器)就会先保存当前的CNT值
3.然后将定时器的输入通道为下降沿捕获,当检测到从1到0的跳变时,ICR就会保存当前的CNT值
4.最终根据俩次捕获的值,就可以计算出高电平持续时间
tips:
IMX6ull芯片有俩个GPT定时器
-GPT的输出比较
工作原理
有三个输出比较通道,它们使用相同的计数器(GPT_CNT)作为输入捕获通道。当输出比较寄存器的编程内容与GPT_CNT中的值匹配时,设置输出比较状态标志并生成中断
(还有一个“强制比较”(forced-compare)功能,一但设置,就会马上产生比较事件,不管当前计数器的值是否等于比较值,强制比较的产生的事件,跟正常的输出事件相同,只是它不会设置状态标记位并且不会产生中断,一旦设置force-compare位,该事件就会即刻产生,这个位是自动清除的)
-高精度延时实现
实现思路
1.软件复位GPT定时器
2.确定GPT定时器的时钟源
3.预分频器的设置
4.确定比较寄存器的值(根据延时时间来确定)
5.开启GPT定时器
6.等待输出比较事件的产生
7.关闭GPT定时器
代码实现
gpt.c
#include "gpt.h"
//初始化
void gpt_int(){
//停止gpt
GPT1->CR &= ~(0x1<<0);
//软件复位gpt
GPT1->CR |= (0x1<<15);
//等待复位状态
while(GPT1->CR & (0x1<<15));
//时钟源选择
GPT1->CR &= ~(0x7<<6);
GPT1->CR |=(0X1<<6);
}
//预分频器设置
void gpt_divide(){
GPT1->PR &= ~(0xfff<<0);
GPT1->PR |= (0x41<<0);
}
//开始GPT
void gpt_start(){
//设置ENMOD
GPT1->CR |= (0x1<<1);
//设置工作模式FRR
GPT1->CR |=(0x1<<9);
//使能gpt
GPT1->CR |= (0x1<<0);
}
//关闭GPT
void gpt_stop(){
GPT1->CR &= ~(0x1<<0);
}
//设置比较寄存器的值
void gpt_compare(int value){
GPT1->OCR3 = value;
}
//等待比较事件的发生
void gpt_wait_compare(){
while(!(GPT1->SR & (0x1<<2)));
}
void gpt_delay_useconds(int value){
gpt_int();
gpt_divide();
gpt_compare(value);
gpt_start();
gpt_wait_compare();
gpt_stop();
}
void gpt_delay_mseconds(int value){
gpt_int();
gpt_divide();
gpt_compare(value*1000);
gpt_start();
gpt_wait_compare();
gpt_stop();
}
void gpt_delay_seconds(int value){
gpt_int();
gpt_divide();
gpt_compare(value*1000*1000);
gpt_start();
gpt_wait_compare();
gpt_stop();
}
gpt.h
#ifndef __GPT_HEAD__
#define __GPT_HEAD__
#include "../../include/imx6ull.h"
#include <stdio.h>
extern void gpt_delay_seconds(int value);
extern void gpt_delay_mseconds(int value);
extern void gpt_delay_useconds(int value);
#endif