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%):

输入捕获

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

 

posted on 2018-10-22 17:17  minnowbin  阅读(815)  评论(0编辑  收藏  举报

导航