【裸机开发】定时器中断(EPIT)

EPIT 是周期性中断定时器,向下计数(即自减),会定期调用指定的中断服务函数,其实可以看做是一种IRQ的外设中断,对应的中断ID是88(=56+32)或者 89(=57+32)。


目录

一、定时器计数流程

二、寄存器解析

1、EPIT1_CR

2、EPIT1_LR

3、EPIT1_CMPR 

4、EPIT1_CNR

5、EPT1_SR

三、其他初始化操作

1、全局中断初始化

2、GIC 的 EPIT 中断使能

3、注册中断服务函数

四、总结


一、定时器计数流程

定时器计数主要涉及到三个寄存器:

  • count register:计数器启动以后,每隔一个时钟周期,自减1
  • compare register:当 count register == compare register 时,触发中断,调用对应的中断服务函数
  • load register处理完中断服务函数以后,下一次开始自减的初始值是多少(有两种模式,分别对应着不同的初始值)

这里使用简单的 C 代码阐述一下这三个寄存器之间的关系

/*
 * mode: 表示计数模式
 * count register: 计数寄存器(每隔一个时钟周期,自减1)
 * compare register: 比较寄存器(保存每次停止自减的临界值)
 * load register: 加载寄存器。保存每次重新自减的初始值
 */

if(mode == 0)    // 每次从 0xffff ffff 开始自减
    count_register = 0xffffffff;
else            // mode = 1,每次从 load register 开始自减
    count_register = load_register;

// 假设每一次while循环都是一个时钟周期
while(1)
{
    if(count_register == compare_register)    // 停止计数
    {
        // 调用中断服务函数

        // 重新开始计数
        if(mode == 0)    // 每次从 0xffff ffff 开始自减
            count_register = 0xffffffff;
        else            // mode = 1,每次从 load register 开始自减
            count_register = load_register;
    }
    else
        count_register --;
}

二、寄存器解析

了解定时器的计数流程后,我们也大致知道了计数过程需要用到哪些寄存器,整个过程涉及到的寄存器如下:

  • EPIT1_CR        —— 配置 EPIT(选择时钟源、计数使能、比较使能等)
  • EPIT1_LR        —— 对应 load register
  • EPIT1_CMPR  —— 对应 compare register
  • EPIT1_CNR     —— 对应 count register
  • EPT1_SR         —— 记录 EPIT 的状态(每次处理完中断,都要置1)

1、EPIT1_CR

CR 是控制寄存器,用于配置EPIT的使能、分频、时钟源等。主要配置的字段:15~0 bit、25~24 bit

bit 0:EPIT使能。设为 1

bit 1:EPIT打开以后的最初计数值来源。0 表示从上一次关闭EPIT时的值开始,1 表示从 Load Register 或者 0xFFFF_FFFF 开始。设为 1 

bit 2:比较寄存器使能。设为 1

bit 3:计数加载控制,也就是模式选择。mode = 0 表示当计数器和比较寄存器相等时,下一次从0xFFFF_FFFF 开始;mode = 1 表示当计数器和比较寄存器相等时,下一次从Load Register 的值开始。设为 1 

bit 15-4:时钟源分频数。取值为0~4095

bit 25-24:选择时钟源。我们选择 01,即 ipg_clk(66MHz) 

寄存器: EPIT1_CR
基地址: 0x20D0000
初始化操作:
    EPIT1_CR = 0;     // 所有位清零(顺带禁止EPIT1)
    EPIT1_CR |=(0xE | (3 << 4) | (0x1 << 24));

    // ... 其他初始化操作

    EPIT1_CR |= 1;            // EPIT1 使能

注意:一开始先不要对EPIT进行使能,一旦使能,可能就按照默认值 0xFFFF_FFFF 开始计数了,所以我们一开始要先禁用 EPIT,对其他位或者寄存器初始化完毕以后再使能。

2、EPIT1_LR

LR 是加载寄存器,保存每次触发中断以后,重新计数的起始值。默认起始值是 0xFFFF FFFF。假设定时器的时间间隔为 1 s,时钟频率是 66MHz / 2 = 33 MHz(这里的2表示2分频),即时钟周期是 1/33M s

因此,LR 寄存器的值应设为 33000000,对应十六进制为 0x1F7 8A40

寄存器: EPIT1_LR
基地址: 0x20D0008
初始化操作:
    EPIT1_LR = 0x1F78A40;

3、EPIT1_CMPR 

比较寄存器决定何时产生中断,因为当计数寄存器和比较寄存器相等时,就会触发中断,从而调用对应的中断服务函数。默认值是 0 (一般无需设置)

寄存器: EPIT1_CMPR 
基地址: 0x20D000C
初始化操作:
    EPIT1_CMPR  = 0;

4、EPIT1_CNR

计数寄存器保存着当前计数值。初始情况下可以和上面 LR 寄存器的值保持一致

寄存器: EPIT1_CNR
基地址: 0x20D0010
初始化操作:
    EPIT1_CNR = 0x1F78A40;

5、EPT1_SR

EPIT状态寄存器记录着EPIT中断是否发生。在中断服务函数执行完毕以后,要清除标志位,即改寄存器要置1。

寄存器: EPIT1_SR
基地址: 0x20D0004
清除标志位操作:
    EPIT1_SR = 1;

三、其他初始化操作

1、全局中断初始化

参考:IRQ 全局中断初始化

2、GIC 的 EPIT 中断使能

EPIT 的中断ID 在本文开始位置已经给出了,如果要用 EPIT1,中断ID = 88;如果要使用 EPIT2,中断ID = 89。

/* EPIT1 中断使能 */
GIC_EnableIRQ(88);

3、注册中断服务函数

当定时器中断触发时,我们反转 LED 灯的状态。不要忘记清除中断标志位!

static unsigned int status = OFF;

void epit_irqhandler(void* userParams)
{
    switch_led(status);
    status = !status;

    EPIT1_SR = 1;           // 清除中断标志位
}
void led_on()
{
    GPIO1_DR &= ~(1 << 3);
}

void led_off()
{
    GPIO1_DR |= (1 << 3);
}

void switch_led(uint8_t status)
{
    if (status == ON)
    {
        led_on();
    }
    else
    {
        led_off();
    }
}

四、总结

unsigned int epit_stat = ON;

/*
 * frac: 代表分频数
 * interval: 代表计数器的初始值
 */
void epit_init(unsigned int frac, unsigned int value)
{
    if (frac < 1 )
        frac = 1;
    else if(frac > 4096)
        frac = 4096;
    
    /* EPIT1 中断使能 */
    GIC_EnableIRQ(88);

    /* 注册中断服务函数 */
    register_irqhandler(88, epit_irqhandler);

    EPIT1_CR = 0;       // CR 寄存器清零
    /* EPIT1 使能、分频、时钟源初始化 */
    EPIT1_CR |=(0xE | ((frac - 1) << 4) | (0x1 << 24));

    /* 加载寄存器 */
    EPIT1_LR = value;

    /* 比较寄存器 */
    EPIT1_CMPR = 0;

    /* 计数寄存器 */
    EPIT1_CNR = value;

    EPIT1_CR |= 1;
}

void epit_irqhandler(void* userParams)
{
    switch_led(epit_stat);
    epit_stat = !epit_stat;

    EPIT1_SR = 1;           // 清除中断标志位
}

猜你喜欢

转载自blog.csdn.net/challenglistic/article/details/131366284