Skip to main content
Explorer II
August 12, 2024
Solved

Changing the period values of all timers in high-resolution timer

  • August 12, 2024
  • 2 replies
  • 1512 views

I have a high-resolution timer configured at some frequency. This master timer has three other timers associated to it, where each timer also runs at the same frequency. But the trigger events of these timers are compare values from the master timer, that generate update event to trigger the reset of these timers.

This works and all and I am using LL APIs but I need now at some point to change the period of these timers to a lower frequency. I know I can change the period using LL APIs while running. But can I do so without causing any glitches?

I have 6 outputs (2 for each timer) set to 50% duty cycle.

My approach would be to use the functions as follows, but instead of doing a jump in the period, I do in a ramped fashion. Which means each run of the mainLoop I changed the period and then apply the code shown for all timers.

Then after 10 mainLoop runs, the change of frequency is completed

LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_MASTER, NEW_PERIOD);
LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_A, NEW_PERIOD);

uint32_t newCompareValue = __calculateCompareValue(NEW_PERIOD);

LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_MASTER, newCompareValue); // Compare value 1 used for timer A


 

    This topic has been closed for replies.
    Best answer by nouirakh

    Hello @BSale.1 ,

    It can be tricky to change the period of high-resolution timers without causing glitches, especially when you have multiple timers synchronised and generating outputs. Your approach of ramping the period change gradually over multiple iterations of the main loop is a great way to minimise glitches, by breaking the period change into smaller steps, you reduce the risk of glitches. Also, you need to ensure that the updates to the period and compare values are synchronized. For the Duty Cycle Calculation: Adjust the compare values based on the new period to maintain the desired duty cycle.
    Example of

    #define NUM_STEPS 10
    
    void updateTimerPeriods(uint32_t currentPeriod, uint32_t newPeriod) {
     uint32_t stepPeriod;
     uint32_t stepCompareValue;
     uint32_t periodIncrement = (newPeriod - currentPeriod) / NUM_STEPS;
    
     for (int i = 0; i < NUM_STEPS; i++) {
     stepPeriod = currentPeriod + (i * periodIncrement);
     stepCompareValue = __calculateCompareValue(stepPeriod);
    
     // Update the master timer period
     LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_MASTER, stepPeriod);
    
     // Update the associated timers' periods
     LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_A, stepPeriod);
     LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_B, stepPeriod);
     LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_C, stepPeriod);
    
     // Update the compare values
     LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_MASTER, stepCompareValue);
     LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_A, stepCompareValue);
     LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_B, stepCompareValue);
     LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_C, stepCompareValue);
    
     // Wait for the next main loop iteration
     // This could be a delay or a synchronization point in your main loop
     waitForNextIteration();
     }
    }
    
    uint32_t __calculateCompareValue(uint32_t period) {
     // Calculate the compare value based on the new period
     return period / 2; // Example for 50% duty cycle
    }
    
    void waitForNextIteration() {
     // Implement a delay or synchronization mechanism
     // This could be a simple delay or a more complex event-driven wait
     HAL_Delay(10); // Example delay of 10ms
    }

     

    2 replies

    ST Employee
    August 14, 2024

    Hello @BSale.1 ,

    Could you pls specify which STM32 product you are currently working with? 

    Regards,

     

    BSale.1Author
    Explorer II
    August 16, 2024

    stm32g474

    nouirakhAnswer
    ST Employee
    August 16, 2024

    Hello @BSale.1 ,

    It can be tricky to change the period of high-resolution timers without causing glitches, especially when you have multiple timers synchronised and generating outputs. Your approach of ramping the period change gradually over multiple iterations of the main loop is a great way to minimise glitches, by breaking the period change into smaller steps, you reduce the risk of glitches. Also, you need to ensure that the updates to the period and compare values are synchronized. For the Duty Cycle Calculation: Adjust the compare values based on the new period to maintain the desired duty cycle.
    Example of

    #define NUM_STEPS 10
    
    void updateTimerPeriods(uint32_t currentPeriod, uint32_t newPeriod) {
     uint32_t stepPeriod;
     uint32_t stepCompareValue;
     uint32_t periodIncrement = (newPeriod - currentPeriod) / NUM_STEPS;
    
     for (int i = 0; i < NUM_STEPS; i++) {
     stepPeriod = currentPeriod + (i * periodIncrement);
     stepCompareValue = __calculateCompareValue(stepPeriod);
    
     // Update the master timer period
     LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_MASTER, stepPeriod);
    
     // Update the associated timers' periods
     LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_A, stepPeriod);
     LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_B, stepPeriod);
     LL_HRTIM_TIM_SetPeriod(HRTIM1, LL_HRTIM_TIMER_C, stepPeriod);
    
     // Update the compare values
     LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_MASTER, stepCompareValue);
     LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_A, stepCompareValue);
     LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_B, stepCompareValue);
     LL_HRTIM_TIM_SetCompare1(HRTIM1, LL_HRTIM_TIMER_C, stepCompareValue);
    
     // Wait for the next main loop iteration
     // This could be a delay or a synchronization point in your main loop
     waitForNextIteration();
     }
    }
    
    uint32_t __calculateCompareValue(uint32_t period) {
     // Calculate the compare value based on the new period
     return period / 2; // Example for 50% duty cycle
    }
    
    void waitForNextIteration() {
     // Implement a delay or synchronization mechanism
     // This could be a simple delay or a more complex event-driven wait
     HAL_Delay(10); // Example delay of 10ms
    }

     

    BSale.1Author
    Explorer II
    August 16, 2024

    Thank you very much for your reply. 
    I tested the idea against the glitches, a glitch cannot be detected only a constant slow increase in the period until the desired new period is reached.

    This was only a dry test, the next step would be testing this with power.

    I am facing now a different problem, since my system consists of a lot timers (actually 6 + master) and a lot of compare values, the update function takes a lot to execute. This is messing with my frequency of the whole system and I can see that my main control frequency is affected due to the fact that HRTIMER runs at a 5 times higher frequency than the control frequency. I can work around the implementation and try to optimize it. But do you see any other idea this can be optimized?

    ST Employee
    August 16, 2024

    It's really important to make sure that your high-resolution timers are working as well as they can be, so you don't end up slowing down the whole system. Here are some ways to make updates more efficient:

    • Use interrupts and DMA to offload the update process from the CPU. This can help the update function run faster and the main control loop more efficiently.
    • Prioritize Critical Updates, If some timers or compare values are more important than others, make sure you update them first. This can help keep the most critical parts of your system running smoothly.
    • Optimize Calculation Functions, ensure that the functions used to calculate new periods and compare values are optimized for performance. Avoid unnecessary calculations and use efficient algorithms.