3
\$\begingroup\$

I have strange behavior of timers. I'm using a Blue Pill with a STM32F103 chip with the HAL lib.

My case: I set up TIM2 to input capture mode to count impulses, then I store it in a global structure and after some impulses I try to change TIM3 (setup as one pulse, PWM 2 mode, no output) ARR and CCR1 (in my case):

void TIM2_IRQHandler(void)
  if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC1)) {
    if (myStruct.pulse_count == 10) {
      __HAL_TIM_SET_AUTORELOAD(&htim3, myStruct.calc_tim3_arr);
      __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, myStruct.calc_tim3_ccr);
      TIM3->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN;
    }
  }
}

myStruct is declared in main.c and looks like this:

typedef struct {
  uint16_t pulse_count;
  uint16_t calc_tim3_arr;
  uint16_t calc_tim3_ccr;
} myStruct_t;

and imported into stm32f1xx_it.h (and init in main.c) as:

extern myStruct_t myStruct;

My problem is in setting up new ARR and CCR1 via macros to dynamically changed values of the calc_tim3_arr and calc_tim3_ccr values. Nothing happens after change. I'm waiting for an interrupt event from TIM3, but I never get it, and in the debugger I see updated values in each register. And what's interesting, if I change the code to:

void TIM2_IRQHandler(void)
  if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC1)) {
    if (myStruct.pulse_count == 10) {
     __HAL_TIM_SET_AUTORELOAD(&htim3, 1000);
     __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 100);
     TIM3->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN;
    }
  }
}

(replacing variables calc_tim3_arr and calc_tim3_ccr with some static values) all works fine.
I try to use the CMSIS register directly - not working.

So I can't understand why it's happening and what I need to do. Any ideas?

UPD. TIM3 ARPE enabled

\$\endgroup\$
1
  • 3
    \$\begingroup\$ You need to declare your myStruct_t myStruct as volatile. So volatile myStruct_t myStruct; in main.c and extern volatile myStruct_t myStruct; everywhere else. This tells the compiler that values in the struct could change "unexpectedly", and that it's not allowed to optimize reads & writes to the struct by keeping values in registers instead of the struct. \$\endgroup\$
    – brhans
    Dec 24, 2022 at 0:46

2 Answers 2

3
\$\begingroup\$

The compiler is optimising by keeping values in processor registers instead of the struct, because it doesn't know the values can be changed unexpectedly from elsewhere.

You can prevent this behaviour by declaring the struct as volatile, so by declaring volatile myStruct_t myStruct in main.c and extern volatile myStruct_t myStruct everywhere else.

This tells the compiler to use the values in the struct, and read/write from/to the struct, and not keep the values in registers as an optimisation.

\$\endgroup\$
0
\$\begingroup\$

Thanks to @brhans! Adding volatile to the struct declaration and extern volatile makes my code work.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.