IMX6U裸机配置通用定时器
GPT介绍
先来看看GPT(General Purpose Timer)即通用定时器的概述图:
绿色方框部分是时钟源,它有一个12位的分频器,分频系数范围为 1 ~ 4096;
蓝色高亮处是一个32位的计数器,并且是向上计数的;
红色方框是两个输入捕获通道;
橙色方框是三个输出比较通道;
其中输出比较通道比较的是 Timer Output Regx 寄存器和 Timer Counter 寄存器的值,输出口则是三个GPT_COMPAREx;
无论输入输出,都有对应的中断事件,这些事件挂载在 Processor Interrupt Bus 上。
GPT的特性
(《来自IMX6UL参考手册》第28章,P1219)
① 一个可选时钟源的 32 位向上计数器。
② 两个输入捕获通道,可以设置触发方式。
③ 三个输出比较通道,可以设置输出模式。
④ 可以生成捕获中断、比较中断和溢出中断。
⑤ 计数器可以运行在重新启动(restart)或(自由运行)free-run 模式。
时钟源选择
时钟有5种选择,选择时钟后再进行分频。
- 直接用24M晶振
- 外部时钟GPT_CLK
- 外围时钟
- 低频基准时钟
- 高频基准时钟
时钟、输入、输出引脚图
这个图详细说明了每个GPT对应的时钟引脚、输入捕获引脚、比较输出引脚的分布和需要配置的模式。其中的GPTn_CLK是可以接入外部时钟来给定时器提供时钟源。按照手册要求,为保证GPT正常工作,外部时钟输入频率应小于外围时钟频率的1/4。
例如:GPT1的输入捕获通道1,对应的IO口为 GPIO1_IO00 和 UART1_RX_DATA ,要配置的模式分别为ALT1 和 ALT4,IO口方向为输入方向。
时钟分频
这是一个时钟分频的时序图,由4分频转2分频。
定时器的两种模式
Restart Mode:在该模式下,计数值达到用户定义的数值时就会自动清零。
Free-Run Mode:在该模式下,计数器一直在计数,直到计数至0xFFFFFFFF(2的32次方)时才会翻转归0。
GPT相关的寄存器组
IMX6U有两个GPT,每个GPT对应的寄存器有:
GPT控制寄存器:用于配置定时器等;
GPT分频寄存器:分频;
GPT状态寄存器:用于判断定时器状态;
GPT中断寄存器:中断相关;
GPT输出比较寄存器:3个输出比较相关;
GPT输入捕获寄存器:2个输入捕获相关;
GPT计数寄存器:计数的,读这个寄存器可以知道当前定时器的计数值。
GPTx_CR寄存器介绍
FO1-FO3 和 OM3-OM1 :与输出比较通道配置有关的段;
IM2-IM1:与输入捕获配置有关的段;
SWR:软件复位,向此位写 1 就可以复位 GPT 定时器,当 GPT 复位完成以后此为会自动清零。
EN_24M:使能24M晶振,0:失能,1:使能;
FRR:Free-Run模式和 Restart模式配置;
CLKSRC:配置时钟源;
ENMOD(bit1):GPT 使能模式,此位为 0 的时候如果关闭 GPT 定时器,计数器寄存器保存定时器关闭时候的计数值。此位为 1 的时候如果关闭 GPT 定时器,计数器寄存器就会清零;
EN(bit):GPT 使能位,为 1 的时候使能 GPT 定时器,为 0 的时候关闭 GPT 定时器。
GPTx_PR寄存器介绍
GPTx_SR寄存器介绍
GPTx_IR寄存器介绍
该寄存器用于对回滚中断、输入捕获中断、输出比较中断进行使能和失能的配置。(详见参考手册P1236)。
GPTx_OCRx寄存器介绍
用来配置输出比较寄存器的值,大小为0~2^32-1。
GPTx_ICRx寄存器介绍
用来存放输入捕获到的值,该寄存器的只有可读权限。
GPTx_CNT寄存器介绍
主计数器的寄存器。GPT_CNT是一个只读寄存器,可以读取而不影响GPT的计数过程。
利用GPT1配置一个高精度延时函数
步骤
- 配置GPT1定时器
- 使能GPT1定时器
- 编写延时函数
代码如下:
#include "bsp_delay.h"
void delay_init(void)
{
GPT1->CR = 0; /* 清零,bit0也为0,即停止GPT */
GPT1->CR = 1 << 15; /* bit15置1进入软复位 */
while((GPT1->CR >> 15) & 0x01); /* 等待复位完成 */
GPT1->CR = (1<<6); /* GPT时钟源选择ipg_clk=66Mhz */
GPT1->PR = 65; /* 设置为65,即66分频,因此GPT1时钟为66M/(65+1)=1MHz */
/*
* GPT的OCR1寄存器,GPT的输出比较1比较计数值,
* GPT的时钟为1Mz,那么计数器每计一个值就是就是1us。
* 为了实现较大的计数,我们将比较值设置为最大的0XFFFFFFFF,
* 这样一次计满就是:0XFFFFFFFFus = 4294967296us = 4295s = 71.5min
* 也就是说一次计满最多71.5分钟,存在溢出
*/
GPT1->OCR[0] = 0XFFFFFFFF;
GPT1->CR |= 1<<0; //使能GPT1
}
/*
* @description : 微秒(us)级延时
* @param - value : 需要延时的us数,最大延时0XFFFFFFFFus
* @return : 无
*/
void delayus(unsigned int usdelay)
{
unsigned long oldcnt,newcnt;
unsigned long tcntvalue = 0; /* 走过的总时间 */
oldcnt = GPT1->CNT; /* 先记录下计数器中原本存放的计数值 */
while(1)
{
newcnt = GPT1->CNT; /* 再次记录计数器中的值 */
if(newcnt != oldcnt) /* 如果计数器正常工作在计数 */
{
if(newcnt > oldcnt) /* GPT是向上计数器,并且没有溢出 */
/*新的减去原来的再加上自身累积的就等于总的计数值*/
tcntvalue += newcnt - oldcnt;
else /* 发生溢出 */
tcntvalue += 0XFFFFFFFF-oldcnt + newcnt;
oldcnt = newcnt; /* 更新一下oldcnt */
if(tcntvalue >= usdelay)/* 延时时间到了 */
break; /* 跳出 */
}
}
}
/*
* @description : 毫秒(ms)级延时
* @param - msdelay : 需要延时的ms数
* @return : 无
*/
void delayms(unsigned int msdelay)
{
int i = 0;
for(i=0; i<msdelay; i++)
{
delayus(1000);
}
}