cancel
Showing results for 
Search instead for 
Did you mean: 

Timer runtime config issue

Lex
Associate III

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

7 REPLIES 7
Sarra.S
ST Employee

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.

Lex
Associate III

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

PGump.1
Senior

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

Lex
Associate III

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

PGump.1
Senior

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

Lex
Associate III

Thanks, Pedro! I'll try it out

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.