13.IMX6ULL裸机开发之GPT定时器

476 阅读2分钟

一、GPT定时器

以前的延时,通过空指令进行延时,不准确。当修改时钟频率后,才用延时就会有很大的变动。而6ULL的GPT是一个高精度定时器装置。

GPT是一个32bit的向上计数器,有两个输入捕获通道,三个输出比较通道。有一个12分频器。

GPT有两种模式restart和free-run模式。restart模式:定时器的值与寄存器的某个值比较相等就会重新开始计时。它是捕获专有的。free-run模式适用于比较输出的模式。

17_GPT.png

二、寄存器

CR寄存:

bit[0]:模块使能

bit[1]:当模块不使能时是否保存上次的值

bit[8-6]:时钟源选择

bit[9]:运行模式选择

bit[19-18]:输入捕获上升沿、下降沿或者双边沿

bit[28-26]:输出比较通道

PR寄存器:分频设置

SR寄存器:

bit[5]:产生溢出

bit[4-3]:输入捕获中断

bit[2-0]:输出比较中断

IR寄存器:中断使能

OCR,ICR:输出比较寄存器,输入捕获寄存器。

CNT寄存器:读计数器值寄存器

三、GPT的定时器使用

1.GPT进行软件复位。

2.配置GPT时钟源,进行时钟分频,设置定时时间。

3.设置输出比较模式中断使能

4.GPT中断设置,并使能模块。

四、精准定时器的编程

void Delay_Iinit(void)
{
    GPT1->CR = 0;
​
    GPT1->CR = 1<<15;
    while((GPT1->CR >>15) & 0x1);
    
    GPT1->CR |= (1<<1) | (1<<6) ;
    /*prescale*/
    GPT1->PR = 65;              //66divide , f=66000000/(65+1)=1000000
    /*Output Compare*/
    GPT1->OCR[0] = 1000000/2;   //Setup Interrupt round 500ms
    /*Open up GPT1 Output Compare channel*/
    GPT1->IR = (1 << 0);
​
    GIC_EnableIRQ(GPT1_IRQn);
    system_register_irqhandler(GPT1_IRQn , (system_irq_handler_t)GPT1_IRQ_Handler , NULL);
​
    GPT1->CR |= (1<<0);
}
​
void GPT1_IRQ_Handler(unsigned int gicciar,void *param){
    static unsigned char state = 0;
    if(GPT1->SR & (1<<0) ){
        state =! state;1
        led_switch(LED_RED , state);
    }
    GPT1->SR |= (1<<0);
}

五、精确延迟函数

开头我们说了,如果使用空指令NOP进行延时,如果我们对时钟频率进行修改,就会延迟不准的出现问题。为了解决上述问题,通常会使用精准延迟。

我们需要输入捕获开全马力,将CNT寄存器的值占满进行比较输出value。

void Delay(void){
    GPT1->CR = 0;
    GPT1->CR |= (1<<15);
    while( (GPT1->CR >>15)  & 0x1);
    
    GPT1->CR |= (1<<1) | (1<<6);
    GPT1->PR |= 65;     //1M
    
    GPT1->OCR[0] = 0xffffffff;
    
    GPT1->CR |= (1<<0);
}
//精确定时us
void delay_us(uint32_t usdelay){
    uint32_t oldcnt , newcnt;
    uint32_t tcntvalue;
    
    oldcnt = GPT1->CNT;
    while(1){
        newcnt = GPT1->NCT;
        if(newcnt |= oldcnt){
            if(newcnt > oldcnt)
                tcntvalue = newcnt - oldcnt;
            else
                tcntvalue = 0xffffffff-oldcnt + newcnt;
            oldcnt = newcnt;
            if(tcntvalue >= usdelay)
                break;
        }
    }
}
//精确ms定时
void delay_ms(uint16_t msdelay){
    uint16_t i = 0;
    for( i ; i < msdelay ; i++)
        delay_us(1000);
}
​

\