周期中断定时器
关于EPIT定时器的内容位于《IMX6UL参考手册》的1013页。
Enhanced Periodic Interrupt Timer (EPIT):增强型周期中断定时器,这个定时器的计数方式是向下计数。即计数一次就减一。并且这个定时器主要工作是完成周期性中断定时。
EPIT的组成
EPIT由五个部分组成:时钟源,12位分频器,三个32位的寄存器,中断,输出引脚。
时钟源可以来自:ipg_clk、ipg_clk_32、ipg_clk_highfreq。
12位预分频器的分频系数为:1~4096。以下是由4分频转为2分频的时钟变化图。
3个32位寄存器:计数寄存器(EPIT_CNR)、加载寄存器(EPIT_LR)和比较寄存器(EPIT_CMPR),计数寄存器保存当前的计数值,比较寄存器也会存放一个值,当这个值和计数寄存器相等时就会产生一个比较事件。加载寄存器用于当计数寄存器计数归0时,重新加载计数值。
中断:计数寄存器和比较寄存器经过CMP比较器,当两者数值相等时,就会产生一个比较中断,也就是定时中断。
输出引脚:EPIT可以配置引脚输出,通过对应的引脚(EPITn_OUT)输出信号。对应的输出引脚如下图
EPIT框图如下:
计数值、比较值、输出信号、中断等之间的关系
如图所示:
- 计数器设定的值为4、比较值为2
一个时钟脉冲计数一次,并且向下计数,当计数到2时,会产生一个中断,并且Output Signal发生电平翻转,当计数到0时,重新加载计数值开始新的一轮计数。
定时器相关寄存器MAP
从该表可以发现,IMX6U有两个EPIT,并且每个EPIT对应一组寄存器组,每组寄存器组包含:
- 控制寄存器(EPITn_CR):配置定时器用的
- 状态寄存器(EPITn_SR):读取定时器状态用的
- 载入寄存器(EPITn_LR)
- 比较寄存器(EPITn_CMPR)
- 计数寄存器(EPITn_CNR):只有这货权限是只读
CR寄存器详细说明
EPITn_CR->CLKSRC:用于选择时钟源;
EPITn_CR->OM:用于配置输出引脚的输出模式;
EPITn_CR->STOPEN:使能停止模式(由硬件自己复位);
EPITn_CR->WAITEN:使能等待模式(由硬件自己复位);
EPITn_CR->DBGEN:使能debug模式(由硬件自己复位);
EPITn_CR->IOVW:配置EPIT计数器覆盖写,使能后所有写入加载寄存器的操作将覆盖计数器的内容;
EPITn_CR->SWR:软件复位(置1复位,并且自清除);
EPITn_CR->PRESCALAR:配置计数器时钟预分频值,0~4095;
EPITn_CR->RLD:计数器重加载模式,为 0 是 free-running 模式,为 1是 set-and-forget 模式;
EPITn_CR->OCIEN:使能输出比较中断事件;
EPITn_CR->ENMOD:定时器使能的模式;
EPITn_CR->EN:使能定时器。为 0 的时候关闭 EPIT,为 1 的时候使能 EPIT。
SR寄存器
OCIF:输出比较中断标志。 当计数器值和此寄存器值相等就会产生中断。 写1清除中断标志位。
定时器配置步骤
- 设置时钟源、分频系数、计数器重加载模式、计数器初值来源
- 使能比较中断,设置加载值和比较值(即配置定时器中断周期)
- 使能EPITn中断,注册中断服务函数
- 在主函数中添加初始化函数并使能定时器
示例代码
.c文件
#include "bsp_epittimer.h"
#include "bsp_int.h"
#include "bsp_led.h"
/*
* @description : 初始化EPIT定时器.EPIT定时器是32位向下计数器,时钟源使用ipg=66Mhz
* @param - frac : 分频值,范围为0~4095,分别对应1~4096分频。
* @param - value : 倒计数值。
* @return : 无
*/
void epit1_init(unsigned int frac, unsigned int value)
{
/*限制预分频系数不能超过4095*/
if(frac > 0XFFF)
frac = 0XFFF;
EPIT1->CR = 0; // 先清零CR寄存器
EPIT1->CR = 1<<24; // 配置时钟源Peripheral clock=66MHz
EPIT1->CR = frac << 4; // 配置预分频系数
EPIT1->CR = 1 << 3; // 配置计数模式:计数到0则重新加载计数值
EPIT1->CR = 1 << 2; // 使能比较中断
EPIT1->CR = 1 << 1; // 配置计数初值来自LR寄存器
EPIT1->LR = value; // 倒计数值
EPIT1->CMPR = 0; // 比较寄存器,当计数器值和此寄存器值相等就会产生中断
/* 使能GIC中对应的中断 */
GIC_EnableIRQ(EPIT1_IRQn);
/* 注册中断服务函数 */
system_register_irqhandler(EPIT1_IRQn, (system_irq_handler_t)epit1_irqhandler, NULL);
EPIT1->CR |= 1<<0; /* 使能EPIT1 */
}
/*
* @description : EPIT中断处理函数
* @param : 无
* @return : 无
*/
void epit1_irqhandler(void)
{
static unsigned char state = 0;
state = !state;
if(EPIT1->SR & (1<<0)) /* 判断比较事件发生 */
{
led_switch(LED0, state); /* 定时器周期到,反转LED */
}
EPIT1->SR |= 1<<0; /* 清除中断标志位 */
}
.h文件
#ifndef _BSP_EPITTIMER_H
#define _BSP_EPITTIMER_H
#include "imx6ul.h"
void epit1_init(unsigned int frac, unsigned int value);
void epit1_irqhandler(void);
#endif