STM32 timer period too short the first time after reset - Page 1
Forum section: electronics / general

author: Karel
author_rank: Super Contributor
timestamp: May 27, 2022, 10:46:40 am
content: Hi,I can't find the cause of a strange behaviour of the timers of an STM32L452RET.This phenomena happens with all timers (TIM2, 3, 6, 15 and 16).The phenomena is: after a reset the first period of the timer is always too short. After that all next periods have the correct length.This happens both in "one pulse mode" and normal mode.The MCU is running at 80 MHz.The timer prescaler is set to 80 so the timer clock is 1 MHz (1 uSec. resolution).I'm not using "HAL". Here's my code:Code:void timer3_init(void){set_bit(RCC->APB1ENR1, 1); /* enable timer3 clock */RCC->APB1ENR1;_NOP();_NOP();_NOP();timer3_is_singleshot = 0;clear_bit(TIM3->CR1, 0); /* counter disable */TIM3->CR1;TIM3->PSC = (CPU_HZ / 1000000) - 1; /* set timer prescaler to 80 */TIM3->CNT = 0;TIM3->ARR = 0xffff;clear_bit(TIM3->CR1, 7); /* auto preload */set_bit(TIM3->CR1, 2); /* update request source set to counter overflow only */TIM3->SR = 0; /* clear interrupt flags */TIM3->SR;set_bit(TIM3->DIER, 0); /* enable update interrupts */NVIC_EnableIRQ(TIM3_IRQn);}void timer3_start_us(unsigned int us){#ifdef TIM3_DEBUG_GPIO_PINSGPIOC->BSRR = 1 << 1; /* set PC1 debug pin */#endifclear_bit(TIM3->CR1, 0); /* counter disable */TIM3->CR1;TIM3->CNT = 0;if(us > 0xffff){us = 0xffff;}else if(us < 10){us = 10;}TIM3->ARR = us;if(timer3_is_singleshot){set_bit(TIM3->CR1, 3); /* enable one pulse mode */}else{clear_bit(TIM3->CR1, 3); /* disable one pulse mode */}TIM3->SR = 0; /* clear interrupt flags */TIM3->SR;set_bit_pbb(&TIM3->CR1, 0); /* counter enable */#ifdef TIM3_DEBUG_GPIO_PINSGPIOC->BSRR = 1 << 17; /* reset PC1 debug pin */#endif}void TIM3_IRQHandler(void){#ifdef TIM3_DEBUG_GPIO_PINSGPIOC->BSRR = 1 << 0; /* set PC0 debug pin */#endifif(tim3_handler_pntr != NULL){tim3_handler_pntr();}#ifdef TIM3_DEBUG_GPIO_PINSGPIOC->BSRR = 1 << 16; /* reset PC0 debug pin */#endifTIM3->SR = 0; /* clear interrupt flags */TIM3->SR;}Any ideas?

author: ozcar
author_rank: Frequent Contributor
timestamp: May 27, 2022, 11:22:14 am
content: At a guess I'd say it might have something to do with writes to some of the timer registers being buffered, meaning that they only take effect at the next update event. This is optional for some registers, like ARR and CCRx, but maybe you can't turn that feature off for when you write to PSC (check the fine print in the ref manual). If necessary, you could try forcing an update event via UG in the EGR register after setting the values.

author: Karel
author_rank: Super Contributor
timestamp: May 27, 2022, 02:07:34 pm
content: Quote from: ozcar on May 27, 2022, 11:22:14 amThanks!You solved the problem. In the function that initializes the timer, I had to set the UG bit in the EGR register.From the manual:Bit 0UG: Update generationThis bit can be set by software, it is automatically cleared by hardware.0: No action1: Re-initialize the counter and generates an update of the registers. Note that the prescalercounter is cleared too (anyway the prescaler ratio is not affected). The counter is cleared ifthe center-aligned mode is selected or if DIR=0 (upcounting), else it takes the auto-reloadvalue (TIMx_ARR) if DIR=1 (downcounting).

author: rhodges
author_rank: Frequent Contributor
timestamp: May 30, 2022, 04:36:35 pm
content: I ran across this, too. In case other readers find it helpful, here is what I did:Code:RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;val = cpu_speed / (KHZ * 1000);#ifdef NOT_NEEDEDRCC->APB1RSTR |= (RCC_APB1RSTR_TIM4RST); /* Reset TIM4. */RCC->APB1RSTR &= ~(RCC_APB1RSTR_TIM4RST);#endifTIM4->PSC = val - 1;TIM4->EGR = TIM_EGR_UG; /* Force update for prescaler value. */TIM4->SR = 0; /* Clear update flag. */TIM4->DIER = TIM_DIER_UIE; /* Interrupt on update. */TIM4->CR1 = TIM_CR1_CEN; /* Enable timer. */

author: boB
author_rank: Frequent Contributor
timestamp: May 30, 2022, 05:09:37 pm
content: Little details that can be really important.I had a similar (but different) problem when using a timer toggle output mode where UG had to be done immediately after setting up the timer(s) otherwise the output pins would be WAY off in time and hurting hardware due to high current surges.Seems these types of things are left to the user to figure out.boB

author: wek
author_rank: Frequent Contributor
timestamp: May 30, 2022, 06:19:50 pm
content: Quote from: rhodges on May 30, 2022, 04:36:35 pmNote, that this does not guarantee that the interrupt won't fire immediately after being enabled.https://community.st.com/s/question/0D50X0000Avg2LBSQY/correct-way-to-clear-timsruif-after-setting-timegrughttps://community.st.com/s/question/0D50X00009XkaBtSAJ/tim-delay-needed-between-setting-event-through-egr-and-clearing-srJW

author: rhodges
author_rank: Frequent Contributor
timestamp: May 30, 2022, 08:28:10 pm
content: Those posts are years old... I checked errata for 32F103 and there is no mention of this.

author: wek
author_rank: Frequent Contributor
timestamp: May 31, 2022, 10:25:07 pm
content: Quote from: rhodges on May 30, 2022, 08:28:10 pmAnd that's good or bad?Quote from: rhodges on May 30, 2022, 08:28:10 pmThat's why you have to read my writings. ;-)JW

author: rhodges
author_rank: Frequent Contributor
timestamp: May 31, 2022, 11:41:14 pm
content: Quote from: wek on May 31, 2022, 10:25:07 pmI mean that this issue was posted in an ST forum years ago, and ST has apparently refused to acknowledge and document it.Do you think it is an acceptable workaround?Code:TIM4->EGR = TIM_EGR_UG; /* Force update for prescaler value. */while (TIM4->SR & TIM_SR_UIF)TIM4->SR = 0; /* Clear update flag. */

author: wek
author_rank: Frequent Contributor
timestamp: June 01, 2022, 12:59:58 pm
content: It's a user-driven forum, with only casual ST presence, i.e. ST staff does not follow it regularly/closely, see e.g.this.Things you see in errata usually come from ST's support, which primarily serves the $M customers, they don't have time/resources to investigate every pet problem on the forum.And I generally agree with this - after all, any extra support is paid by the customers through price of the chips.In am not sure about the workaround. Those often work simply because they waste enough time. I would definitively use a do-while cycle, though, so that SR is cleared at least once, no matter what. It may quite well be that UIF won't be set soon enough for the first read to see it being 1.JW

author: rhodges
author_rank: Frequent Contributor
timestamp: June 01, 2022, 08:23:31 pm
content: The funny thing is, I only noticed the delay in updating TIMx->PSC recently, when using the timer for FreeRTOS task statistics.My TIM4 update (rollover) interrupt routine incremented a "high 16 bit" counter, so there would be 32 bits for FreeRTOS. The first interrupt happened MUCH sooner that it should have, adding 65536 to the count almost immediately. Then the count was stable. As we know, this was because TIMx->PSC did not get the correct prescaler until the first overflow event.The code I posted solved this for me. But now I am thinking about the second issue, where clearing TIMx->SR might not clear the interrupt. My code should not work correctly. But it did.One more clue. I just remembered that when using the OpenOCD target of stm32f0x.cfg, it complained that the ID was wrong (0x2ba01477). So I used the target script I made for the "fake" stm32f103 (where I changed 0x1ba01477 to 0x2ba01477). So... Maybe my "fake" chip does not have the TIMx->SR problem?Just posting for the sake of discussion.

author: Dan N
author_rank: Contributor
timestamp: January 03, 2024, 03:17:16 pm
content: I wanted to add a couple of things to this old thread since this is such a common issue for STM32 beginners (including me on my first STM32 project last year).The timer prescaler register (PSC) always uses shadow/preload model with no other option (ARPE bit has no effect). I have only seen this explicitly stated in one place: AN4776 General-purpose timer cookbookTo expand on the solution in previous posts, I set the URS bit to prevent UG from possibly triggering an unwanted interrupt or dma transfer:Code:[...]TIM4->PSC = val - 1;TIM4->CR1 |= TIM_CR1_URS; /* no interrupt for UG */TIM4->EGR = TIM_EGR_UG; /* Force update for prescaler value. */[...]<edited EGR assign as wek suggested>

author: wek
author_rank: Frequent Contributor
timestamp: January 03, 2024, 07:02:27 pm
content: You don't need to RMW to TIMx_EGR, it's a write-only register (reads always as 0).JW

author: peter-h
author_rank: Super Contributor
timestamp: January 08, 2024, 03:42:12 pm
content: I am trying to understand this.I am using a timer to measure the time between pulses, and load the value into a register which is then read by some foreground code.It works perfectly and I wonder whether it is because the issue occurs only once after power-up and thus doesn't get noticed, or whether the mode I am running doesn't show it, or whether it doesn't appear for some other spurious reason.This is my codeCode:/*** Set up TIM1 for ~21Hz+ waveform period measurement, via PE9* This produces a continuously updated value in TIM1->CCR1. This example code displays it:*while (1){float freq;uint32_t pclk2 = HAL_RCC_GetPCLK2Freq();uint16_t ccr1 = TIM1->CCR1;if ((ccr1>0)&&(pclk2>0))// prevent division by zero{freq = 1.0/(ccr1/((pclk2*2)/64.0));// 64=prescaler in config_TIM1_period_measure}else{freq=0;}debug_thread_printf("===== TIM1 = %5u %6.1f", ccr1, freq);osDelay(1000);}* TIM1 is clocked at 2xPCLK2 i.e. 84MHz here. The /64 prescaler drops this to 1.3125MHz* counter speed which is good for <30Hz and delivers a value 2625 at 500Hz.* Actual minimum input is 20.1Hz and below that it bombs due to int16 counter overflow.* The TIM1 config is very subtle and is based on hints here* https://community.st.com/s/question/0D53W00001DKBpGSAX/simple-32f417-tim1-usage-to-measure-tim1ch1-pulse-duration** TIM1 is used because it has the most features and because it is accessible on PE9. Not many other* spare pins for the others!* The input filter value is the biggest which still gives a negligible error for the application.* PA0 can be used for TIM5 CH1 and this is a 32 bit timer.* PE11 can also be used for TIM1 CH2, if we wanted the #2 compare channel.* Note that TIM1->CNT can also be read at any time, which will return the number of timer clocks* since the last input zero crossing, and if this is put inside a "critical" section then you can* accurately establish the phase of the input waveform.**/void config_TIM1_period_measure(void){GPIO_InitTypeDef GPIO_InitStruct;__GPIOE_CLK_ENABLE();// already enabled in switch init but never mindGPIO_InitStruct.Pin = GPIO_PIN_9;GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;// PE9 = TIM1_CH1GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;// PE9 = AF, and is an input because CH1=input in TIM1 cfgGPIO_InitStruct.Pull = GPIO_PULLUP;// PE9 = pullup because comparator driving it is open drain o/pGPIO_InitStruct.Speed = GPIO_SPEED_LOW;// This probably does nothing, being an inputHAL_GPIO_Init(GPIOE, &GPIO_InitStruct);// Set up TIM1 to count up and on PE9 +ve edge transfer the count to CCR and reload with 0__HAL_RCC_TIM1_CLK_ENABLE();// TIM1EN=1 in RCC2ENR and does a short delayTIM1->CR1 = 0;// TIM1 upcounter, counter disabled for now with CEN=0TIM1->ARR = 0xffff;// auto reload valueTIM1->PSC = 63;// prescaler=64TIM1->CCMR1 = (1 << 4)// IC1F: input filter = 2 Fck-int|(0 << 2)// IC1PSC: input prescaler off|(1 << 0);// CC1S: 01 = channel is input, from TI1TIM1->CCER = (0 << 3)// CC1NP: CC1 rising edge capture|(0 << 2)// CC1NE: oc1n not active|(0 << 1)// CC1P: rising edge capture|(1 << 0);// CC1E: enable CC1 captureTIM1->EGR = 0;// CC1G=0TIM1->CNT = 0;TIM1->CR2 = 0;// TI1S=0 - TIM1_CH1 pin is connected to TI1 inputTIM1->RCR = 0;TIM1->SMCR = (1 << 2)// internal clock source, SMS=100 (reset mode)|(1 << 6)// TS=101 (TI1FP1)|(1 << 4);TIM1->SR = 0;// Clear any "pending" flagTIM1->DIER = (1 << 1)// CC1IE=1 - enable interrupt on update|(1 << 0);// UIE=1TIM1->CR1 = (1 << 0);// CEN=1 - enable TIM1HAL_NVIC_SetPriority(TIM1_CC_IRQn,1,0);// Set highest priority for this oneHAL_NVIC_EnableIRQ(TIM1_CC_IRQn);// Enable the TIM1 global Interrupt}and at the end of the ISR I haveCode:// Reset TIM4 prescaler+counter chain, to avoid 1-sample-width jitter on output// This also forces a TRGO event which does a DAC updateTIM4->EGR=1;}edge_count++;// mark "getting edges"TIM1->SR = 0;// Clear CC1IF & UIF - clear pending interrupt}

author: Dan N
author_rank: Contributor
timestamp: January 08, 2024, 03:59:28 pm
content: Quote from: peter-h on January 08, 2024, 03:42:12 pmYour timer runs at the old frequency (previous PSC,ARR values) until it overflows and then loads your new PSC,ARR values. Because your timer runs all the time, it overflows and loads the new values before anything else happens. This will happen anytime you change PSC or ARR unless you force an immediate update using UG as shown in my post above.BTW, I have a project that does the same thing in almost the same way. But I use reset+trigger mode so the timer doesn't run until the first edge occurs on the capture input. It won't work at all on the first pass unless the PSC,ARR registers were forced to update at initialization.

author: peter-h
author_rank: Super Contributor
timestamp: January 08, 2024, 08:28:49 pm
content: QuoteThe timer is not enabled until after PSC and ARR are loaded.Or do you mean those load values are delayed until after the counter overflows? And in the meantime it runs at the power-up defaults for the chip?The value TIM_EGR_UG is 1 and that is what I am loading at the end of the ISR, above.It sounds like I should be loading EGR=1 after loading PSC and ARR during init, too:Code:TIM4->PSC = tim_pre;// prescaler for aboveTIM4->ARR = tim_tc;// time constant// This is needed because the last two above (PSC,ARR) are not loaded until the counter has overflowed// https://www.eevblog.com/forum/microcontrollers/stm32-timer-period-too-short-the-first-time-after-reset/TIM4->EGR = TIM_EGR_UG;// Force update for prescaler value (TIM_EGR_UG=1)do{TIM4->SR = 0;// Clear update flag.}while (TIM4->SR & TIM_SR_UIF);I am wondering if the above do/while is needed afteranyEGR load? Especially if you might be loading it near the point where it overflows.Also is there any scenario - defective silicon aside - which could make this hang? I use loops like this in places where a hang is not possible e.g. waiting for some DMA termination status bit.

author: Dan N
author_rank: Contributor
timestamp: January 08, 2024, 10:31:05 pm
content: Quote from: peter-h on January 08, 2024, 08:28:49 pmLoading PSC and ARR doesn't have any effect until a timer update event happens (overflow, UG, etc.). Until then your timer will run 64 times too fast.Quote from: peter-h on January 08, 2024, 08:28:49 pmThe UG bit isn't persistent. Writing 1 causes an immediate timer update event. It will always read 0.Quote from: peter-h on January 08, 2024, 08:28:49 pmThe do-while is totally unecessary and likely to cause problems. I posted the much better way to just set the URS bit before writing 1 to UG to prevent the interrupt from happening. You can clear URS afterward if you want UG somewhere else to cause an interrupt.

author: peter-h
author_rank: Super Contributor
timestamp: January 08, 2024, 11:24:42 pm
content: OK I now have justCode:// This is needed because the last two above (PSC,ARR) are not loaded until the counter has overflowed// https://www.eevblog.com/forum/microcontrollers/stm32-timer-period-too-short-the-first-time-after-reset/TIM4->CR1 |= TIM_CR1_URS;// Prevent spurious interruptsTIM4->EGR = TIM_EGR_UG;// Force update for prescaler value (TIM_EGR_UG=1)I think I understand it but not 100% sure about the URS bit. Basically it prevents a spurious interrupt via this hack (from the RM)Bit 2 URS: Update request sourceThis bit is set and cleared by software to select the UEV event sources.0: Any of the following events generate an update interrupt or DMA request if enabled.These events can be:– Counter overflow/underflow– Setting the UG bit– Update generation through the slave mode controller1: Only counter overflow/underflow generates an update interrupt or DMA request ifenabled.I have also put some dummy register reads (ARR) to waste time, although I don't understand enough about the issue (I have read wek's ST post and looked at his .c file in the zipfile he posted there) to know if two will be enough.Code:// Reset TIM4 prescaler+counter chain, to avoid 1-sample-width jitter on output// This also forces a TRGO event which does a DAC updateTIM4->EGR = TIM_EGR_UG;}edge_count++;// mark "getting edges"// the SR write needs a wait after the above EGR write - see// https://community.st.com/t5/stm32-mcus-products/tim-delay-needed-between-setting-event-through-egr-and-clearing/m-p/344272TIM4->ARR;// Some dummy readsTIM4->ARR;TIM1->SR = 0;// Clear CC1IF & UIF - clear pending interrupt}The code did run before but I found weird issues. I am taking in a 400Hz square wave whose period is measured with TIM1 and then a value is loaded into TIM4 to drive two DACs from a RAM table with DMA. The RAM table contains a sinewave and this is phase locked to the input 400Hz, based on zero crossings. I was getting weird artefacts around the zero.

author: bson
author_rank: Unknown
timestamp: January 17, 2024, 07:10:54 pm
content: I forget how the STM counters work, but it's pretty normal to stop a counter before configuring it, then starting it again afterwards. Otherwise you risk generating all kinds of crap timing and spurious pulses during configuration. Not a problem after power-on since timers are stopped, but this way you can use the same code to reconfigure as needed later.