Skip to main content
Associate
May 13, 2024
Solved

Dynamic phase shift

  • May 13, 2024
  • 5 replies
  • 3782 views

Hi,

My goal is to dynamically change the phase shift between two output signals. Ultimately I would like to do this by rotating an encoder knob, but for the sake of simplicity a software change will do to simplify things. I'm using a Blue pill (STM32F103C8T6).

TIMER 2 is set to Master:
Slave Mode: Disable
Channel1: PWM Generation CH1
Channel2: Output Compare No Output
Trigger Output (TRGO) Parameters:
- Trigger Event Selection: Output Compare (OC2REF)
Output Compare No Output Channel2:
- Mode: Active Level on match

TIMER 3 is set to Slave:
Salve Mode: Trigger Mode
Trigger Source: ITR1
Channel1: PWM Generation CH1
Channel2, 3, 4: Disabled

The code is simple:

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // 1st output signal
HAL_TIM_OC_Start(&htim2, TIM_CHANNEL_2); // phase shift value
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); // 2nd output signal

When hardcoded everything works great and I get a phase shift between signals. See the attached image.

But to change it I have to reflash the MCU as I can't get it changed dynamically.

I tried this in a while loop, but it didn't help:

1) TIM2->CCR2 = new_value;

2) stop all timers, set new value of phase shift and restart timers;

3) __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, new_value);

How to do this correctly?

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

This is what I managed to code. For thos of you who might be interested this will definitely be a help.
MCU is STM32F103C8T6 (Blue Pill) run at 72 MHz.

uint16_t desired_frequency = 50000; // Hz
float desired_duty_cycle = 8.5; // %
float desired_phase_shift = 0; // degrees (starting point)

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_OC_Start(&htim2, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

while (1){
 
 // For Blue pill (STM32F103C8T6 @ 72 MHz) values less than 1 degree make no difference. There will be 36 steps anyway (10 degree per each step)
 desired_phase_shift += 1;
 
 // Set new frequency (if needed)
 TIM2->ARR = 72000000 / desired_frequency - 1;
 
 // Set new duty cycle (if needed)
 TIM2->CCR1 = (uint16_t) ((TIM2->ARR + 1) * desired_duty_cycle / 100.0);
 
 // Set new phase shift between 2 signals (if needed)
 TIM2->CNT = (uint16_t) ((desired_phase_shift / 360.0) * (TIM2->ARR + 1));
 
 // Mandatory pause to rebuild timers to new settings
 // The higher the value, the more confident the performance. 10 is the minimum value 
 HAL_Delay(15); // 15 is safe enough 
}

The result is in attached file: roll from oscillator is just an example.

5 replies

llaabbssAuthor
Associate
May 13, 2024
AScha.3
Super User
May 13, 2024

Hi,

TIM2->CCR2 = new_value;

is ok, your loop just should have some waiting time (HalDelay()) , because CCR update is always at timer overflow/reload . And new_value is uint16_t - right ?

ed

I was thinking, you want only move the position of other TIM pulse...

If you feel a post has answered your question, please click on " Best Answer ".
llaabbssAuthor
Associate
May 13, 2024

No, TIM2->CCR2 = new_value doesn't work.

HAL_Delay(time) doesn't help either.

Tesla DeLorean
Guru
May 13, 2024

The challenge with the TIM is the singular counting element.

PWM Mode 1 has the signal go HIGH at ZERO/UPDATE, and LOW at CCRx

PWM Mode 2 has the signal go LOW at ZERO/UPDATE, and HIGH at CCRx

Multi-phase, square, out of a TIM can be accommodated via Toggle Mode, where the Channels can control the relative phases.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
llaabbssAuthorBest answer
Associate
May 13, 2024

This is what I managed to code. For thos of you who might be interested this will definitely be a help.
MCU is STM32F103C8T6 (Blue Pill) run at 72 MHz.

uint16_t desired_frequency = 50000; // Hz
float desired_duty_cycle = 8.5; // %
float desired_phase_shift = 0; // degrees (starting point)

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_OC_Start(&htim2, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

while (1){
 
 // For Blue pill (STM32F103C8T6 @ 72 MHz) values less than 1 degree make no difference. There will be 36 steps anyway (10 degree per each step)
 desired_phase_shift += 1;
 
 // Set new frequency (if needed)
 TIM2->ARR = 72000000 / desired_frequency - 1;
 
 // Set new duty cycle (if needed)
 TIM2->CCR1 = (uint16_t) ((TIM2->ARR + 1) * desired_duty_cycle / 100.0);
 
 // Set new phase shift between 2 signals (if needed)
 TIM2->CNT = (uint16_t) ((desired_phase_shift / 360.0) * (TIM2->ARR + 1));
 
 // Mandatory pause to rebuild timers to new settings
 // The higher the value, the more confident the performance. 10 is the minimum value 
 HAL_Delay(15); // 15 is safe enough 
}

The result is in attached file: roll from oscillator is just an example.