简述
ARM Cortex-A7的一个定时器,用来完成周期性中断定时
特点:
- 时钟源可选的32位向下计数器
- 12位的分频值
- 当计数值和比较值相等的时候产生中断
- 可以即使编程的计数器值
- 在低功耗和调试模式下能够编程为活跃状态
原理分析
结构分析
- 多路选择器,共有三个时钟源可选择:
- ipg_clk:由时钟控制模块CCM提供的Peripheral clock;
- ipg_clk_32k:低频率参考时钟,32kHz的参考时钟,来自外部的32kHz晶振;
- ipg_clk_highfreq:由时钟控制模块CCM提供的高频率参考时钟。
- 12bit的预分频器,对时钟源进行分频,12bit对应的值为04095,也就是可以设置为14096分频。
- EPIT内部,三个重要的寄存器(32位):
- Counter Register,计数寄存器,EPIT是一个向下计数的定时器,给予它一个初值,便会从这个初始值开始递减,直到为0,Counter Register就保存了当前的计数值。
- Load Register为装载寄存器,当EPIT被设置为set-and-forget模式,当计数器递减到0后,EPIT就会读取Load Register保存的值到Counter Register,并且重新开始计数。
- Compare Register为比较寄存器,用于和Counter Register中的值进行比较,如果相等的话能产生一个比较事件。
- 比较器,比较Compare Register和Counter Register中的值,相等即产生比较事件
- 设置外设引脚输出,指定引脚输出信号。
- 定时中断。
工作模式
两种工作模式: set-and-forget 和 free-running ,通过EPIT_CR[RLD]能设置
- 当EPIT_CR寄存器的RLD被置1的时候,EPIT工作在set-and-forget模式,在该模式下,EPIT定时器的计数值从LoadRegister中获取初始值,此时不能直接向CounterRegister中写入数据,当计数器的值递减为0后,将会从LoadRegister中加载数据到计数器,周而复始运行。
- 当EPIT_CR寄存器的RLD被清0的时候,EPIT工作在free-running模式,当计数器的值到0后,计数器的值会进行翻转变为0xFFFF_FFFF,并重新开始计数,而不是从Load Register中获取数据;
寄存器(部分)
寄存器EPITx_CR,用来配置EPIT
CLKSRC(bit[25:24]):用来设置EPIT的时钟源
- CLKSRC | 时钟源 |
---|---|
00 | 关闭时钟源 |
01 | Peripheral 时钟 |
10 | High-frequency |
11 | Low-frequency |
-
PRESCALAR(bit[15:4]):EPIT时钟源的预分频值,12bit,能设置的值为0x0000xFFF,对应分频的值为14096。
-
RLD(bit3):用于设置EPIT的工作模式,该bit为0的时候工作在free-running模式,为1的时候工作在set-and-forget模式。
-
OCIEN(bit2):比较中断使能位,设置为0的时候将禁止比较中断,设置为1的时候将使能比较中断。
-
ENMOD(bit1):用来设置计数器的初始值,设置为0时,计数器的初始值等于上次关闭EPIT定时器中计数器的值,设置为1时,初始值取决于RLD的配置,如果RLD=1时,计数器的值来源于Load Register,如果RLD=0,则计数器的值为0xFFFF_FFFF。
-
EN(bit0):EPIT定时器使能位。0闭,1使能
寄存器EPITx_SR,只有最低位(OCIF(bit0))有效,比较中断标识位,0的时候无比较事件发生,1的时候有比较时间发生。需手动清零。
溢出时间计算
溢出时间 = ((分频值+1)*装载值)/时钟频率
配置流程
- 设置时钟来源,通过EPIT_CR寄存器的CLKSRC位选择
- 设置定时器的预分频值,通过设置EPITx_CR寄存器中的PRESCALAR,配置EPIT定时器时钟分频值
- 设置工作方式,置EPITx_CR寄存器中的RLD
- 设置定时器中计数器的初始值来源,通过设置EPITx_CR的ENMOD(bit1),配置计数器的初值来源
- 使能比较中断,设置EPITx_CR的OCIEN位,置1
- 设置加载值(装载值)和比较值,设置EPITx_LR和EPITx_CMPR寄存器
- 中断服务函数
- 使能EPIT
实现过程
功能描述
通过EPTI1控制LED的亮灭。
代码编写(部分)
/***************************
File name: bsp_epit
Author: ori
Version: v1.0
Description: EPIT驱动文件
Others: 无
log: 2021/2/2
***************************/
#include "bsp_epit.h"
#include "bsp_int.h"
#include "bsp_led.h"
/*
* @description :EPIT1初始化
* @param - frac :分频
* @param - value :装载值
* @return :0
*/
void epit1_init(unsigned int frac, unsigned int value)
{
if(frac > 0XFFF)
frac = 0XFFF; /* 这里先设置为最大分频 */
EPIT1->CR = 0; /* 清零CR寄存器,为了方便后续配置 */
/* 66MHz,分频值为4,set-and-forget工作模式,值来源load register */
EPIT1->CR = (1<<24 | frac << 4 | 1 << 3 | 1 << 2 | 1 << 1);
EPIT1->LR = value; /* 加载寄存器值 */
EPIT1->CMPR = 0; /* 比较寄存器值 */
/* 使能中断 */
GIC_EnableIRQ(EPIT1_IRQn);
/* 注册中断服务函数 */
system_register_irqhandler(EPIT1_IRQn, (system_irq_handler_t)epit1_irqhandler, NULL);
/* 使能EPIT1 */
EPIT1->CR |= 1<<0;
}
/*
* @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; /* 清除中断标志位 */
}
/***************************
File name: bsp_epit
Author: ori
Version: v1.0
Description: EPIT驱动头文件
Others: 无
log: 2021/2/2
***************************/
#ifndef _BSP_EPIT_H
#define _BSP_EPIT_H
#include"imx6ul.h"
void epit1_init(unsigned int frac, unsigned int value);
void epit1_irqhandler(void);
#endif // !1
/***************************
File name: bsp_epit
Author: ori
Version: v1.0
Description: EPIT练习
Others: 无
log: 2021/2/2
***************************/
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_exit.h"
#include "bsp_epit.h"
/*
* @description : main函数
* @param : 无
* @return : 无
*/
int main(void)
{
int_init(); /* 初始化中断(一定要最先调用!) */
imx6u_clkinit(); /* 初始化系统时钟 */
clk_enable(); /* 使能所有的时钟 */
led_init(); /* 初始化led */
beep_init(); /* 初始化beep */
key_init(); /* 初始化key */
exit_init(); /* 初始化按键中断 */
/* 初始化EPIT定时器,1分频,计数值33000000,500ms */
epit1_init(0,33000000);
while(1)
{
delay(500);
}
return 0;
}
编译烧录
最后
本文多处参考正点原子的课程和资料(特表感谢),并在此基础上进了扩展和自己的理解,最后自己动手复原例程。