2024-04-05 01:24 PM
Our project is run on the STM32F411E-DISCO board running under Segger Embedded Studio. All Timers TIM2/TIM5/TIM9/TIM10/TIM11 are being used. Under a debug session everything runs correctly. If we leave the board programmed with the debug code and power it up without the J-Link connection attached everything runs correctly. However, if we run a release build then the 32-bit timers run correctly but the 16-bit timers do not. From what we can see the 16-bit timers are running too fast as if the check we do for the rollover TIMx->SR & TIM_SR_UIF is always returning true. We looked at the RCC register settings in a debug session and none of the RCC or APB1/2ENR registers appear to have any bits enabled that weren't set by our code.
This issue was actually solved while this post was being written, so this is being posted anyway in case someone else runs into the same issue. Our initialization code runs generically for all timers and the final two lines are:
t->SR = (uint16_t)0x00;
t->CR1 |= TIM_CR1_CEN;
If the lines are swapped then the code runs as expected for both debug and release settings. This behavior has been seen on other ST processors where enabling the timer immediately caused UIF to assert, whether anything to do with the timer interrupts are enabled or not. For the F411 this appears to only be affecting the 16-bit timers with the 32-bit timers being fine, but why the debug build of the code is blocking this behavior is a mystery.
Solved! Go to Solution.
2024-04-05 04:33 PM - edited 2024-04-05 04:35 PM
Is not just these two lines, but also what's just before them - and my guess is, setting TIMx_EGR.UG. It takes time until this generated event propagates into TIMx_SR, so if the TIMx_SR clear happens too soon, the UIF bit gets set after that clear.
Reoedering increases that delay and gives chance for UIF to be set before the clear. Similarly the low optimization during debug.
Aren't the 32bit timers on a slower bus?
JW
2024-04-05 01:42 PM
Look at the code generated by the debug and release builds and see what is different. Different optimization levels can cause unexpected behavior depending on how your timer structures are defined.
Generally, the memory space occupied by the timers (and all peripherals) is flagged as "strongly ordered" so writing to SR must complete before the read/modify/write to CR1 happens if executed in the order you show above. I would be surprised if the compiler re-ordered those two lines, but you never know.
Does the definition of your timer structure declare the registers as "volatile"?
2024-04-05 04:33 PM - edited 2024-04-05 04:35 PM
Is not just these two lines, but also what's just before them - and my guess is, setting TIMx_EGR.UG. It takes time until this generated event propagates into TIMx_SR, so if the TIMx_SR clear happens too soon, the UIF bit gets set after that clear.
Reoedering increases that delay and gives chance for UIF to be set before the clear. Similarly the low optimization during debug.
Aren't the 32bit timers on a slower bus?
JW
2024-04-06 05:45 PM
Thank you for the additional feedback. It seems certain the UG bit is the root issue, since as waclawek.jan predicted, the line right before the initial two listed is...
t->EGR |= TIM_EGR_UG;
t->CR1 |= TIM_CR1_CEN;
t->SR = (uint16_t)0x00;
For readers that don't know the significance of the UG bit, it is this:
"This bit can be set by software, it is automatically cleared by hardware.
0: No action
1: Re-initializes the counter and generates an update of the registers. The prescaler counter is also cleared and the prescaler ratio is not affected. The counter is cleared."
The behavior of UG asserting also causing UIF to assert can actually be blocked by using the URS bit in CR1 (this bit is off by default, which is why were were getting this behavior):
"This bit is set and cleared by software to select the UEV event sources.
0: Any of the following events generates an update interrupt if enabled:
– Counter overflow
– Setting the UG bit
1: Only counter overflow generates an update interrupt if enabled."
Regarding Bob S' comment, we're using the TIM_TypeDef provided by ST, which does declare the registers volatile. Regarding "Aren't the 32bit timers on a slower bus?" On the F411, no, the 32- and 16- bit timers collectively are on separate APBs but all of them get the same clock source.
2024-04-07 01:53 AM
> all of them get the same clock source
That diagram is misleading. There are two APB buses, and timers on each of them have their separate clock setting, depending on the given APB prescaler.
Even if the resulting timer clock is equal for both buses (thanks to the "if divider > 1, timer clock is 2x" mechanism), the exact timing between several accesses to TIM registers from processor depends on the APB bus speed/divider. With non-1 divider, the access may be slower than 2 cycles, given that inter-bus synchronization gets activated (with undocumented timing). At the typical 100MHz setting, APB1 bus where the 32-bit TIM2/TIM5 sit is max. 50MHz so its clock gets divided and accesses to TIM2/TIM5 may be slow enough to cover up the above effect; as opposed to APB2 which is max. 100MHz and there's no division, and where the 16-bit TIM9/10/11 sit.
JW