cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F303RE: PWMs utilizing Timers with Phase Shift

KMew
Senior III

Hello,

I am assisting with the firmware development of a dual-active bridge converter and I am trying to create a phase-shifted PWM signal that will control the switches. Creating the phase shift is proving challenging, but I had an idea that I believe, in theory, should work. However, I cannot seem to get the configuration correct to implement it.

 

I am using the STM32F303RE. Let me explain my strategy:

I am utilizing TIM1 and TIM3. Specifically:
TIM1-CH1 - PWM Signal that goes externally, used as reference (aka not phase shifted)

TIM1-CH2 - PWM Signal that goes externally, used as reference (aka not phase shifted)

TIM1-CH3 - PWM Signal that's internal

 

TIM8-CH1 - PWM Signal that goes externally, in slave mode

TIM8-CH2 - PWM Signal that goes externally, in slave mode

 

I would like to make both TIM8's a slave that starts its counter on the falling edge of TIM1-CH3. TIM1-CH3 will be synchorized with TIM1-CH1/2 (in other words, their rising edges will always be the same). I will then change the duty cycle of  TIM1-CH3. Since TIM8 is a slave of TIM1-CH3, TIM8 will start its counter and rise on the falling edge of TIM1-CH3. See the visual below to help understand.

KMew_0-1706889515705.png

I am trying to implement them in the STM32CubeMX/IDE, but it's not working. Here is my CubeMX configuration

 

TIM1:

KMew_1-1706889584526.pngKMew_2-1706889611420.pngKMew_3-1706889628508.png

 

TIM8:

KMew_4-1706889658934.pngKMew_5-1706889671820.pngKMew_6-1706889680915.png

 

 

In the CubeIDE, I also added the following lines after the initialization:

	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
	HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
	HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);


	HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);
	HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_2);
	HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_2);


  TIM1->CCR1 = 80;
  TIM1->CCR2 = 80;
  TIM1->CCR3 = 10;

  TIM8->CCR1 = 80;
  TIM8->CCR2 = 80;

 

Unfortunately, it is not working. TIM1-CH1/2 and TIM8-CH1/2 are in sync with no shaft shift, despite the TIM1->CCR3 = 10 that should shift it by 10 counts.

 

Can anyone help me figure out what I'm doing wrong?

 

12 REPLIES 12
Sarra.S
ST Employee

Hello @KMew 

For the master configuration: TIM1_CH3, configure it as "output compare with no output", select the trigger event selection as output compare CH3 (as you did in the screenshot) and in the output compare mode select it as "active on level match" as you want their rising edges to always be the same.

I don't see an issue with your slave configuration. 

You'll need to update the code to start the OC for TIM1_CH3 

For more explication, you can refer to Hands-On with STM32 Timers: Internal Triggering System

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.

Hello Sarra,

 

Thank you for the reply.

If I change it to output compare, can I change the "duty cycle" of TIM1-CH3 dynamically?

KMew
Senior III

@Sarra.S Hello, I just wished to bump this.
I need to dynamically change the "pulse" or "duty cycle" during operation of the code. Can that be done with your method? If not, can you please provide a method for that?

Trigger mode of Slave-mode controller (as set in TIMx_SMCR.SMS) upon arrival of TRGI sets TIMx_CR1.CEN.

It means, that you don't want to set TIMx_CR1.CEN in the slave timer "manually" in your code, you want it to be set through the TRGO-TRGI mechanism from the master timer.

It also means, that if you want to repeat this process automatically, you have to use the One-Pulse mode in slave timer (i.e. TIMx_CR1.OPM = 1), where TIMx_CR1.CEN  is cleared by hardware upon Update (i.e. after each period of timer).

In other words, you want the slave timer to generate only one pulse per trigger, and then trigger it repeatedly from the master timer.

JW

Hello @waclawek.jan,
Thank you for your reply! 

I believe I understand waht you're saying. If I want to change it dynamically, I need to have a single pulse. When I just define the PWM and "duty cycle," it locks the value in and no longer checks the falling edge of TIM1-CH3. 

So your proposal is to create only one pulse, but then re-enable each pulse at the falling edge of TIM1-CH3. 

 

So I would have an interrupt occur on the PWM falling edge which would do TIM8_CR1.CEN = 1, correct?

No interrupts.

I am talking about the master-slave connection between timers.

Just set TIM8_CR1.OPM = 1 and leave TIM8_CR1.CEN = 0.

If you've set properly TIM8_SMCR to be triggered from TIM1 and in Trigger mode, the trigger from TIM1 will start the TIM8 in hardware, it will generate one pulse, and as it's in one-pulse mode, it will stop itself.

JW

Hello @waclawek.jan 

Ahh okay, thank you for clarifying.

So if I want to link TIM8 to TIM1-CH3, how do I control it such that I can change the rising edge of TIM8 to create this phase shift?

 

Would I set the TGRO to OC3REF (Since it's CH3)? The part I'm still not seeing is how to sync the rising edge of TIM8 to the falling edge of TIM1-CH3 (or some other method that I can dynamically control the phase shift of TIM8)

> Would I set the TGRO to OC3REF (Since it's CH3)?

Yes.

> The part I'm still not seeing is how to sync the rising edge of TIM8 to the falling edge of TIM1-CH3 (or some other method that I can dynamically control the phase shift of TIM8)

Well... it's not that straighforward.

The way how PWM works is, that for TIMx_CNT values between 0..TIMx_CCRx-1 it is at one level (in following we assume PWM mode 2, so it's 0), and between TIMx_CCRx..TIMx_ARR it is at the other level (1). If in OPM mode the timer is "idle", i.e. not running, TIMx_CNT = 0, so output is at "idle" at 0. If you want to generate an edge as soon as possible after the trigger, the best way is to set TIMx_CCRx = 1, so the pulse starts one timer clock after the trigger; and set TIMx_ARR to the expected duration of the pulse + 1.

You can compensate that one timer clock delay by setting the master (i.e. TIM1_CH3) to one less. In fact, you may need to compensate more, as there may be some delay in the TRGO-TRGI process, too.

The best way to try all this is to set up roughly what you want, and then in debugger change directly the relevant registers content, while observing the output on the pins using oscilloscope/logic analyzer. It's fun.

JW

Michal Dudka
Senior III

Why don't use "Asymmetric PWM mode" which allows you to generate directly two phase shifted PWMs with controllable duty cycle and phase shift ? If you just start TIM1 and TIM8 synchronously (using TRGO-TRGI) then you have four "shiftable" outputs (+ four complementary if you need them).