硬件定时器在第一次使用时立即完成。 STM32F303VC
Hardware timer instantly completes when first used. 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
位,这会导致更新 interrupt/DMA 请求仅在柜台 overflow/underflow 上发行。这当然不行。
我觉得我需要 reset/set 某个地方有一个 bit
以便让计时器在我第一次启用它时按预期运行。
好的,所以在重新阅读手册中有关计时器的部分后,我发现了以下内容:
The new prescaler ratio is taken into account at the next update event.
好的,那么我如何通过软件生成更新事件,以便在启动定时器之前更新预分频器值。就在那时我发现了这个(强调我的):
In upcounting mode, the counter counts from 0 to the auto-reload value (content of the
TIMx_ARR register), then restarts from 0 and generates a counter overflow event.
An Update event can be generated at each counter overflow or by setting the UG bit in the TIMx_EGR register (by software or by using the slave mode controller).
因此,在设置 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
...
我正在尝试在 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
位,这会导致更新 interrupt/DMA 请求仅在柜台 overflow/underflow 上发行。这当然不行。
我觉得我需要 reset/set 某个地方有一个 bit
以便让计时器在我第一次启用它时按预期运行。
好的,所以在重新阅读手册中有关计时器的部分后,我发现了以下内容:
The new prescaler ratio is taken into account at the next update event.
好的,那么我如何通过软件生成更新事件,以便在启动定时器之前更新预分频器值。就在那时我发现了这个(强调我的):
In upcounting mode, the counter counts from 0 to the auto-reload value (content of the TIMx_ARR register), then restarts from 0 and generates a counter overflow event. An Update event can be generated at each counter overflow or by setting the UG bit in the TIMx_EGR register (by software or by using the slave mode controller).
因此,在设置 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
...