Search code examples
timerstm32microcontroller

Changing the timer frequency dynamically


I'm trying to modify the frequency of a pwm timer at runtime but I don't know how exactly the counter overflow is triggered described in the reference manual.

The output should be a short pulse of constant width (constant TIMx_CCRx) with a variable frequency (TIMx_ARR) in upcounting, edge-aligned mode (p.354 and 372 in the reference manual). I want to be able to adjust the frequency faster than the minimum archivable output frequency should be.

Eg. the tick time (CK_CNT) is 1 ms, the maximum time is 1000 ms and I want to be able to update the ARR value every 100 ms. When the new ARR value is higher than the current counter register value the timer should continue counting up. When the new ARR value is smaller than the current counter register value the timer should create a counter overflow and restart from 0. To be able to update the auto-reload register every 100 ms I disabled ARR-preloading (ARPE=0).

What would happen when I write a value into the ARR register smaller than the current counter register value? There is only an example for when the new ARR value is bigger than the counter value on p.356.

Would a counter overflow trigger and the timer starts from 0? Do I have to create an update event (UEV) manually? Do I have to check the counter value and restart the timer manually if the new ARR value would be lower?


Solution

  • I didn't find anything in the reference manual but finally got to test the behaviour on actual hardware:

    • Setting the ARR to a value lower than the current counter value doesn't create an interrupt/update event/etc, the timer keeps counting up
    • Manually creating an update event automatically restarts the counter
    • Setting the ARR to the current counter value creates an update event

    I don't want to restart the counter when setting the ARR value to something higher than the counter value. The solution is to create a manual update event when the ARR value is lower than the counter value. There shouldn't be a problem with the counter reaching ARR while setting it because that automatically creates an update event.

    This seems to work as expected:

    void update_arr (TIM_HandleTypeDef* htim, uint16_t arr) {
        __HAL_TIM_SET_AUTORELOAD(htim, arr);
        if (__HAL_TIM_GET_COUNTER(htim) >= __HAL_TIM_GET_AUTORELOAD(htim)) {
            htim->Instance->EGR  |= TIM_EGR_UG;
        }
    }