我正试图在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
。。。