OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3116|回复: 0

<新手向>第二期 裸机开发 P37-P38第16讲 EPIT定时器 随堂笔记

[复制链接]

5

主题

17

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2020-3-22
在线时间
35 小时
发表于 2020-6-7 15:53:18 | 显示全部楼层 |阅读模式
本帖最后由 YOKI 于 2020-6-7 15:55 编辑

好久没有发帖了,今天补充一下定时器的帖子。
/********************************************/
时间        :2020/04/10/
作者        :YOKI
导师        :正点原子 左忠凯
硬件        :正点原子 ALPHA I.MX LINUX 开发板
/*******************************************/
EPIT  周期中断定时器
既然讲定时器,那肯定和时钟有关 本节先回顾一下时钟相关的内容:
在 bsp_clk.c 中有一个总线时钟配置函数
/* AHB_CLK_ROOT 总线时钟频率设置 */
void AHB_CLK_ROOT_init(void)
{
int PERIPH_CLK_SEL_BUSY = ((CCM->CDHIPR >> 5) & 0X01);  //外设时钟    判忙标志位
int AHB_PODF_BUSY = ((CCM->CDHIPR >> 1) & 0X01);        //总线时钟分频 判忙标志位
int MMDC_CH0_MASK = 1;
CCM->CCDR |= (MMDC_CH0_MASK << 17);/* CCM_CCDR bit17 置1 不允许 PRE_PERIPH_CLK_SEL 握手*/
CCM->CBCMR |= (01<<18 );            /* CCM_CBCMR bit18-bit19  PRE_PERIPH_CLK_SEL=01 时钟源 PLL2 PFD2 不分频*/
while(PERIPH_CLK_SEL_BUSY);         /* 等待 PERIPH_CLK_SEL_BUSY 清零 */  
CCM->CBCDR &= ~(1<<25 );            /* CCM_CBCDR bit25  PERIPH_CLK_SEL=0 时钟源 PLL2 PFD2 */
while(AHB_PODF_BUSY);               /* 等待 AHB_PODF_BUSY 清零 */         
CCM->CBCDR |= (3<<10);              /* CCM_CBCDR bit10-bit12 AHB_PODF=011 时钟源 4 分频 */
CCM->CCDR &= ~(MMDC_CH0_MASK << 17);/* CCM_CCDR bit17 置0 允许 PRE_PERIPH_CLK_SEL 握手*/
/* 5、设置IPG_CLK_ROOT最小3Mhz,最大66Mhz (boot rom自动设置好了可以不用设置)*/
CCM->CBCDR &= ~(3 << 8); /* CBCDR的IPG_PODF清零 */
CCM->CBCDR |= (1 << 8);  /* IPG_PODF 2分频,IPG_CLK_ROOT=66MHz */

/* 6、设置PERCLK_CLK_ROOT时钟 */
CCM->CSCMR1 &= ~(1 << 6); /* PERCLK_CLK_ROOT时钟源为IPG */
CCM->CSCMR1 &= ~(7 << 0); /* PERCLK_PODF位清零,即1分频 */
}
其中 第5部分 是和EPIT有关的时钟设置(ipg_clk):
CCM->CBCDR &= ~(3 << 8); /* CBCDR的IPG_PODF清零 */
CCM->CBCDR |= (01 << 8);  /* IPG_PODF 2分频,IPG_CLK_ROOT=66MHz */

IPG_CLK_ROOT 由CCM_CBCDR来控制,
IPG_CLK 来自 总线时钟 AHB_CLK_ROOT 的 2分频(修改CBCDR寄存器 可设置不同值)
AHB_CLK_ROOT 来自 PLL2 的 4分频(修改CBCDR寄存器 可设置不同值)
即 PLL2 =528 MHz IPG_CLK = ((528MHz/2)/4)= 66MHz 也就是说,IPG_CLK会随 PLL2 的修改变动
EPIT  周期中断定时器的时钟源由3个:
1、 IPG_CLK
2、 IPG_CLK_32K
3、 IPG_CLK_highfreq
这里选用IPG_CLK 作为时钟源,EPIT是32位的向下(减1)周期性计时器,
EPIT  周期中断定时器的工作机制如下:
用户给定一个计数值(重装载值) 存到 EPITx—LR 寄存器,再给定一个值(比较值)到 EPITx—CMPR 寄存器,
当计数器每个时钟周期 减1 同时和EPITx—CMPR 寄存器的值比较 ,当减到 比较值 时产生一个中断信号再重新装载计数值。
EPIT 有2种工作模式(通过EPIT_CR 寄存器 的 RLD位(bit3) 设定):
1、set and forget (bit3 = 1) : 计数值由用户给定,自动重装
2、free runing (bit3 = 0) : 计数值 = 0xFFFF FFFF,自动重装;
当EPIT 减到比较值或者0x0000 0000 时会产生中断也可从指定引脚输出信号
中断号:(EPIT1_IRQn = 88;EPIT2_IRQn = 89 )

EPITx_CR 寄存器(EPIT控制寄存器)个位含义
bit0:           EN          写 1    EPIT使能
bit1:           ENMOD       写 1    EPIT从装载值开始计数;写 0 从上一次计数停止的值开始计数
bit2:           OCIEN       写 1    比较中断使能
bit3:           RLD         写 1    set and forget模式;写 0 free runing模式
bit15-bit4:     PRESCALAR   时钟分频 0x000 -0xFFF  1分频 - 4096分频
bit16:          SWR         写 1    EPIT 复位
bit25-bit24:    CLKSRC      时钟选择 01 PREPERIPH_CLK 即 IPG_CLK
其它位请看参考手册。
EPITx_LR    重装载值寄存器
EPITx_CMPR  比较值寄存器
EPITx_SR    EPITx状态寄存器 发生中断(计时满一个周期)时值为1,写 1 清零。

其它寄存器请看参考手册根据以上原理编写 EPIT 初始化函数 和中断处理函数如下:

/******************** 初始化EPIT1 ****************/
/* 参数1: frac 分频值   分频值 0~4096             */
/* 参数2: reload_value 重装载值                  */
/***********************************************/
void EPIT1_init(unsigned int frac,unsigned int reload_value)
{   
    frac = frac-1;
    if(frac > 4095)
        {
         frac=4095;
        }
    EPIT1->CR = 0;  /* 先清零CR寄存器 */
    EPIT1->CR |= (1 << 1) |         //写 1    EPIT1从装载值开始计数
                 (1 << 2) |         //写 1    比较中断使能
                 (1 << 3) |         //写 1    set and forget模式
                 (frac << 4) |      //写分频值
                 (01 << 24);        //写 01   时钟选择 IPG_CLK
    EPIT1->LR = reload_value;       //写重装载值
    EPIT1->CMPR = 0x00000000;       //比较值为0 即倒计数到 0 发生中断

    GIC_EnableIRQ(EPIT1_IRQn);      //EPIT1_IRQn 中断ID 使能 中断ID=88
    Systerm_register_IRQ_Handler(EPIT1_IRQn,EPIT1_IRQ_Handel,NULL); //注册中断
    EPIT1->CR |= (1 << 0);          //EPIT1 使能
}

/* EPIT1中断处理函数 */
void EPIT1_IRQ_Handel(unsigned int gicc_IAR, void *param)
{   static unsigned char state = 0;

  if(EPIT1->SR & (1<<0))      /* 判断比较事件发生 */
        {
          /* 添加用户代码段 */          LED(state);          state = ~state;
        }
   EPIT1->SR |= (1<<0);                //写EPIT1_SR 写1清零 清除中断标志位  
  // GIC_DeactivateIRQ(EPIT1_IRQn);      //向 GICC_EOIR 写入发送中断的中断号来释放中断   
  // EPIT1->CR &= ~(1 << 0);             //EPIT1 关闭
}


在中断函数中可以通过添加其他代码 或 调用其他函数来实现蜂鸣器及LED 灯的响应;

/**********************************************************************************************/
以上注释和代码都是在学习 《正点原子 linux 第二期 裸机开发视频 P30-P36 第15讲 中断系统 》 过程中
跟着 左萌主 学习并加入了一点点自己的思考写成的,作为一个小菜鸡,我大着胆子发出来跟大家一起记录学习
如果有帮助请大家自行参考、下载,如果 转载 请注明出处,并在论坛和我联系。如果有错误请大神指正!左萌主赛高!
作者        :YOKI
导师        :正点原子 左忠凯 (请允许我叫你一声导师吧)
硬件        :正点原子 ALPHA I.MX LINUX 开发板
/*********************************************************************************************/




正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 13:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表