zoukankan      html  css  js  c++  java
  • SiliconLabs EFR32BG 定时器输入捕获和脉宽调制

    输入捕获

    在输入捕获模式下,定时器的计数值(TIMERn_CNT)可以被比较/捕获寄存器(TIMERn_CCx_CCV)获得。

    在TIMERn_STATUS寄存器中CCPOL位指示了触发TIMERn_CCx_CCV寄存器(比较/捕获寄存器)捕获动作的边沿的极性。

    上图中,TIMERn_CNT表示了定时器的计数,其中m和y分别记录了input脉冲的头两个上升沿的时间。

    TIMERn_CCx_CCVB表示了TIMERn_CCx_CCV寄存器中的Buffer缓冲寄存器。

    TIMERn_CCx_CCV表示捕获/比较寄存器。

    由于缓冲寄存器的存在,可以在读出前记录两次捕获事件。

    第一次捕获的时间总是可以从TIMERn_CCx_CCV中读出。读过该地址之后,该寄存器将从TIMERn_CCx_CCVB寄存器中载入下一个捕获时间值(如果缓冲寄存器中存在有效计数值)。

    捕获计数值可以通过读TIMERn_CCx_CCVP寄存器获得,而不改变FIFO的内容。TIMERn_CCx_CCVB也可以不改变FIFO内容的情况下读出数值。

    TIMERn_STATUS中ICV_flag指示了TIMERn_CCx_CCV中是否存在有效但是没有读出的捕获计数。

    在输入捕获模式下,TIMERn_CCx_CCV是只读的。

    如果在TIMERn_CCx_CCV和TIMER_CCx_CCVB都含有没有读出的捕获值时,一个新的捕获被触发,那么缓存溢出标志(位于TIMERn_IF中ICBOF)将被置位。

    发生溢出后,新的捕获值将被写入TIMERn_CCx_CCVB,并覆盖原值。而TIMERn_CCx_CCV中的值将保持不变。

    因此,TIMERn_CCx_CCV中总是保存了最早产生的一个未读出值,而TIMERn_CCx_CCVB中总是保存了最新读到的值。

    注意:在输入捕获模式,定时器将在它运行时只触发中断。

    周期/脉宽 捕获

    周期和脉宽的捕获只能在通道0中使用,因为只有该通道能够开始和停止定时器。

    开始和停止定时器通过设置TIMERn_CTRL寄存器中RISEA为Clear&Start

    对于周期捕获,比较/捕获通道应该被设置为捕获相同输入信号的上升沿。

    为了捕获高脉冲的宽度,比较/捕获通道应该被设置为捕获输入信号的下降沿。(这里为什么呢?如何理解高脉冲?

    为了测量信号的脉宽,应该选择对立的极性。

    脉宽调制

    PWM模式,TIMERn_CCx_CCV被缓冲,以避免输出中的小故障。

    比较输出动作配置位在PWM模式下被忽略。

    PWM输出只支持向上计数和向上/向下计数两种模式。

    向上计数(单斜坡)PWM

    如果计数器被设置为向上计数并且比较/捕获通道处于PWM模式,那么可以产生单斜坡的PWM输出。

    向上计数模式里,PWM周期是TOP+1次循环。PWM输出为高的次数等于TIMERn_CCx_CCV中的值。这意味着一个连续的高输出通过设置TIMERn_CCx_CCV为TOP+1或者更大来实现。(其实就是定时器计数和CCV中值做比较,大于CCV输出低,小于CCV输出高)

    PWM分辨率如下计算:

    Rpwm_up = log(TOP + 1) / log(2)

    PWM频率如下计算:

    fpwm_up = fHFPERCLK / (2 ^ PRESC * (TOP + 1))

    高状态占空比如下计算:

    DSup = CCVx / (TOP +1)

    上下计数(双斜坡)PWM

    如果设置为上下计数,比较/捕获通道以PWM方式输出,将产生双斜坡的PWM波形。

    PWM分辨率如下计算:

    Rpwm_up_down = log(TOP + 1) / log(2)

    PWM频率如下计算:

    fpwm_up_down = fHFPERCLK / (2 ^ PRESC * TOP)

    高状态占空比如下计算:

    DSup_down = CCVx / (TOP)

    关键代码:

    参考代码来自 https://github.com/SiliconLabs/peripheral_examples

    PWM输出

    对于PWM功能的实现,有以下几个关键点:

    设置TOP寄存器:

    TIMER_TopSet(TIMER0, CMU_ClockFreqGet(cmuClock_TIMER0) / PWM_FREQ);

     这里在设置TOP寄存器是,用到了定时器自身的频率。这里的关系应该怎么理解呢?

    设置CCV寄存器:

    TIMER_CompareSet(TIMER0, 0, (TIMER_TopGet(TIMER0) * duty_cycle_percent) / 100);

    对于Silabs的EFRBG还需要设置IO管脚的路由位置。这里原理还没有搞清楚,但不像早期接触的ST的芯片,每个IO有固定的功能复用。在silabs上对于同一个功能,可以通过IO路由映射到不同的管脚上。

    上图中TIM0_CC0功能,可以分表route到不同的线上,同时对应了不同的管脚。测试代码里面选择了IO_PC10,所以需要路由到15号线。

      TIMER0->ROUTELOC0 |=  TIMER_ROUTELOC0_CC0LOC_LOC15;
      TIMER0->ROUTEPEN |= TIMER_ROUTEPEN_CC0PEN;

    在中断处理函数中,重新修改CCV寄存器的值,即可输出特定占空比的波形。手册上没有明确写,个人上图理解中断事件是由于TOP的溢出产生的。TIMER_IF_CC0是中断标识寄存器。

    void TIMER0_IRQHandler(void)
    {
      // Get pending flags and clear
      TIMER_IntClear(TIMER0, TIMER_IF_CC0);
    
      // Update CCVB to alter duty cycle starting next period
      TIMER_CompareBufSet(TIMER0, 0, (TIMER_TopGet(TIMER0) * duty_cycle_percent) / 100);
    }

    PWM一般用于电机的控制和呼吸灯的实现。我这里只是需要一个简单的脉冲输出,然后再通过输入捕获功能将其频率捕获回来即可。

    下图是例程中输出的脉冲波形(频率1000,即周期1ms,占空比50%):

    输入捕获

    下面还需要通过输入捕获,采集到上面生成的波形的频率。

  • 相关阅读:
    Single Number II
    Pascal's Triangle
    Remove Duplicates from Sorted Array
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Unique Paths
    Sort Colors
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Climbing Stairs
  • 原文地址:https://www.cnblogs.com/minnowbin/p/9829117.html
Copyright © 2011-2022 走看看