Reputation: 5501
I'm attempting to setup and use the TIM2
peripheral in one pulse mode (OPM) on the STM32F303 Discovery
board.
The issue I'm encountering is that the timer instantly completes after enabling it.
I'm not using interrupt
's at this point and I'm just polling the TIM2_SR
(status register) UIF
bit to determine if the timer has completed.
This only happens the first time I enable the timer, if I use the timer again it works correctly (does not complete instantly).
I've tried resetting the TIM2_CNT
register prior to enabling the timer but the result is the same.
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 { }
}
The example above gets the LED to flicker on and off with little to no delay.
If I instead use an endless loop the timer works as intended after the initial call to 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 );
}
I've examined the registers while the application is running and everything appears to be set up correctly.
TIM2_CNT
register reads 0x0000_0000
prior to enabling the timerUIF
bit in the TIM2_SR
register is not set prior to enabling the timerTIM2_PSC
register reads the correct pre-scale 7999
TIM2_ARR
register contains the correct auto reload value 3999
OPM
bit in the TIM_CR1
register is set correctlyAfter reading a similar issue on a different forum it was suggested in that answer to enable the URS
bit in the TIM2_CR1
register, which causes an update interrupt/DMA request to only be issued on counter overflow/underflow. This of course did not work.
I get the sense that there is a bit
somewhere that I need to reset/set in order to get the timer to function as expected the first time I enable it.
Upvotes: 1
Views: 401
Reputation: 5501
OK, so after re-reading the section on timers in the manual I found the following:
The new prescaler ratio is taken into account at the next update event.
OK, so how can I generate an update event via software in order for the prescaler value to get updated prior to starting the timer. That's when I found this (emphsis mine):
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).
So after setting the prescaler
value I then set the UG
bit in the TIM2_EGR
register.
// 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( ) );
After forcing an update the timer started to work correctly every time (including the first time).
So, to sum up my issue RT*M
...
Upvotes: 0