2024-04-22 02:07 AM
Hi guys,
I have a simple timer config, which I want to change based on some conditions. I set GPIO high and when OPM timer INT happens, GPIO is set low. Default timer setup 50ms, which is changed to 500ms in the while() loop.
Problem: the first pulse duration after change is incorrect (old setup), then all works fine. Could some point out what is wrong in my setup?
A short code sample is here:
int main(void)
{
....
MX_TIM7_Init();
if (HAL_TIM_Base_Start_IT(&htim7) != HAL_OK) {
/* Starting Error */
Error_Handler();
}
while (1)
{
HAL_Delay(1000);
GPIOA->BSRR = (uint32_t)GPIO_PIN_0;
TIM7->CNT = 0;
TIM7->PSC = 800-1;
TIM7->ARR = 50000-1;
TIM7->CR1 |= TIM_CR1_CEN | TIM_CR1_OPM;
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM7) {
GPIOA->BRR = (uint32_t)GPIO_PIN_0;
}
}
static void MX_TIM7_Init(void)
{
...
htim7.Instance = TIM7;
htim7.Init.Prescaler = 80-1;
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
htim7.Init.Period = 50000-1;
htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
...
}
Thanks in advance
2024-04-22 10:00 AM
Hello @Lex,
This is likely because you're changing the timer configuration while the timer is still running.
When you modify the timer's prescaler and auto-reload register values within the while loop, the timer may not immediately apply these new settings because the timer's update event has not occurred yet!
Try adding this line to generate a UEV to load the new settings after updating them:
TIM7->EGR = TIM_EGR_UG;
I hope that helps!
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2024-04-22 02:44 PM
Hi Sarra,
Thank you for the response.
I'm trying to use TIM7 in one pulse mode and reusing it with different pulse duration. With 80MHz clock, pulse duration is 50 ms, so sleep time is much longer than pulse and UEV event happened before I do next changes.
I need to trigger a pulse with different duration right after the first one and do it in HAL_TIM_PeriodElapsedCallback().
If I change ARR, it works fine even without addressing EGR. However I have problems changing PSC.... If I set TIM_EGR_UG, UEV event happens instantly and pulse duration is almost zero (not 50 ms I need).
I wonder if:
1. Does TIM7->EGR = TIM_EGR_UG; leads to INT (call of HAL_TIM_PeriodElapsedCallback()) even before next line of code after changing EGR?
2. Can I change PSC so next pulse (after current ongoing INT handling is done) would have new parameters?
i.e. could I do it in HAL_TIM_PeriodElapsedCallback()?
3. Is there any difference of timer behavior by setting PSC as below?
htim7.Init.Prescaler = 80-1;
or
htim7.Instance->PSC = 80-1;
Of course, I could potentially use TIM6, but I wonder if I can do it with one timer by changing config after one pulse if generated.
/Lex
2024-04-22 05:30 PM
Hi,
I had this problem sometime ago. I found a bug in either the OPM initialisation, or start code in HAL I can't remember off hand. I initialise/ start the timer manually for OPM now - it's not hard.
If you are still having problems, let me know, and I'll look it up...
I hope that helps.
Kind regards
Pedro
2024-04-23 12:15 AM
Hi,
I have initial setup done and one pulse is working in STM32L4. I could change ARR between pulses without a problem as well.
I can't get it to work if I change PSC. Please, share your findings if they are relevant.
Regards,
Lex
2024-04-23 01:08 AM
Hi Lex,
As I said, HAL had some bugs with OPM. This code bypasses HAL, and is just 'deadwait' timer... The clock frequency was 80MHz. On a STM32F072.
#define Wait100nSTim TIM11
HAL_Init();
/* USER CODE BEGIN Init */
RCC->APB2RSTR |= RCC_APB2RSTR_TIM11RST;
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
RCC->APB2ENR |= RCC_APB2ENR_TIM11EN;
RCC->APB2RSTR &= ~RCC_APB2ENR_TIM11EN;
...
// use Wait100nSTim (TIM11) as a general purpose 100*nS timer
MODIFY_REG(Wait100nSTim->CR1, TIM_CR1_URS | TIM_CR1_UDIS | TIM_CR1_CEN, TIM_CR1_ARPE | TIM_CR1_OPM);
Wait100nSTim->CR2 &= ~(TIM_CR2_MMS_2 | TIM_CR2_MMS_1 | TIM_CR2_MMS_0);
Wait100nSTim->PSC = 8; //~100nS
Wait100nSTim->ARR = 999;
Wait100nSTim->EGR |= TIM_EGR_UG; //preset counter
...
void wait100Ns(uint16_t wait) {
Wait100nSTim->CR1 &= ~TIM_CR1_CEN; //stop counter
Wait100nSTim->PSC = 8; //prescaler = 100nS
Wait100nSTim->ARR = wait; //preset counter
Wait100nSTim->EGR |= TIM_EGR_UG; //reset counter
Wait100nSTim->CR1 |= TIM_CR1_CEN; //start counter
while (Wait100nSTim->CR1 & TIM_CR1_CEN) {}
}
It doesn't use interrupts, nor callback.
I hope this helps.
Kind regards
Pedro
2024-04-23 02:45 AM
Thanks, Pedro! I'll try it out
2024-04-23 03:31 AM
Hello @Lex,
2. you have to make sure that the timer is not running when you change PSC to avoid any unpredictable behavior! so, stop it, change the PSC, generate an update event, and then restart the timer in OPM.
This is what @PGump.1' s code is doing
3. yes there is a "functional" difference, the "htim7.Init.Prescaler" is used during the initialization process, so it will only take effect when HAL_TIM_Base_Init() or similar initialization functions are called.
Writing to htim7.Instance.Prescaler will change the PSC immediately, the change will take effect after UEV (by setting TIM_EGR_UG).
I really hope that clarifies things a bit!
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.