硬件计时器在首次使用时立即完成.STM32F303VC



我正试图在STM32F303 Discovery板上以单脉冲模式(OPM(设置和使用TIM2外围设备。

我遇到的问题是计时器在启用后立即完成。

在这一点上,我没有使用interrupt,我只是轮询TIM2_SR(状态寄存器(UIF位,以确定计时器是否已完成。

这种情况只发生在我第一次启用计时器时,如果我再次使用计时器,它会正常工作(不会立即完成(。

在启用计时器之前,我尝试过重置TIM2_CNT寄存器,但结果是一样的。

use cortex_m_rt::entry;
use stm32f3xx_hal::pac;

#[entry]
fn main( ) -> ! {
let p = pac::Peripherals::take( ).unwrap( );
p.RCC.apb1enr.modify( | _, w | w.tim2en( ).set_bit( ) );
p.TIM2.cr1.write( | w | w
.urs( ).set_bit( )
.opm( ).set_bit( )
.cen( ).clear_bit( ) );
// I've tried resetting the CNT register at this point
// in the application but the result was the same. 

// Set the prescaler based on an 8MHz clock.
p.TIM2.psc.write( | w | w.psc( ).bits( 7999 ) );
// Here I initialize an LED (GPIOE). I've removed this code to 
// keep the example as clean as possible.
let delay = | duration | {         
p.TIM2.arr.write( | w | w.arr( ).bits( duration ) ); 
// I've also tried resetting the CNT register here 
// but the result was the same.       
p.TIM2.cr1.modify( | _, w | w.cen( ).set_bit( ) );
while p.TIM2.sr.read( ).uif( ).bit_is_clear( ) { }
p.TIM2.sr.write( | w | w.uif( ).clear_bit( ) );
};
// Enable LED.
// This call instantly returns.
delay( 3999 );
// Disable LED.
loop { }
}

上面的例子使LED在几乎没有延迟的情况下闪烁。如果我改为使用无休止循环,则计时器在对delay的初始调用后按预期工作。

loop {
// Enable LED.
// The first call in the first loop iteration
// returns instantly.
delay( 3999 );
// Disable LED.

// This call, and every call here after correctly
// returns after 4 seconds.
delay( 3999 );
}

我已经在应用程序运行时检查了寄存器,一切似乎都设置正确。

  • TIM2_CNT寄存器在启用计时器之前读取0x0000_0000
  • TIM2_SR寄存器中的UIF位在启用计时器之前未设置
  • TIM2_PSC寄存器读取正确的预缩放7999
  • TIM2_ARR寄存器包含正确的自动重新加载值3999
  • TIM_CR1寄存器中的OPM位设置正确

在另一个论坛上读到类似的问题后,该答案建议启用TIM2_CR1寄存器中的URS位,这将导致更新中断/DMA请求仅在计数器上溢/下溢时发出。这当然不起作用。

我感觉到某个地方有一个bit,我需要重置/设置它,以便在我第一次启用它时使计时器按预期工作。

好的,所以在重新阅读手册中关于计时器的章节后,我发现了以下内容:

在下一次更新事件中将考虑新的预分频器比率。

好的,那么我如何通过软件生成更新事件,以便在启动计时器之前更新预分频器值。就在那时我发现了这个(emphsis mine(:

在递增计数模式中,计数器从0计数到自动重新加载值(TIMx_ARR寄存器(,然后从0重新启动并生成计数器溢出事件。Update事件可在每次计数器溢出时生成,或通过设置TIMx_EGR寄存器中的UG位(通过软件或使用从属模式控制器(生成。

因此,在设置prescaler值之后,我在TIM2_EGR寄存器中设置UG位。

// Set the prescaler based on an 8MHz clock.
p.TIM2.psc.write( | w | w.psc( ).bits( 7999 ) );
// Generate an update event so that the new prescaler
// value gets loaded.
p.TIM2.egr.write( | w | w.ug( ).update( ) );

在强制更新后,计时器每次(包括第一次(都开始正常工作。

所以,总结一下我的问题RT*M。。。

最新更新