Skip to main content
Visitor II
February 2, 2024
Question

STM32F303RE: PWMs utilizing Timers with Phase Shift

  • February 2, 2024
  • 7 replies
  • 5394 views

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?

 

    This topic has been closed for replies.

    7 replies

    ST Employee
    February 2, 2024

    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!

    KMewAuthor
    Visitor II
    February 2, 2024

    Hello Sarra,

     

    Thank you for the reply.

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

    KMewAuthor
    Visitor II
    February 5, 2024

    @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?

    Super User
    February 5, 2024

    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

    KMewAuthor
    Visitor II
    February 5, 2024

    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?

    Super User
    February 5, 2024

    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

    KMewAuthor
    Visitor II
    February 5, 2024

    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)

    Super User
    February 5, 2024

    > 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

    Graduate II
    February 5, 2024

    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).

    KMewAuthor
    Visitor II
    February 6, 2024

    Hello @Michal Dudka 


    Thank you for the reply!

    So if I set things up as I have, what do I need to adjust to make it work?

    What will the TGRO need to be in this case?

    What registers do I have to use/change to create the phase shift? 

    Graduate II
    February 6, 2024

    How to set up and manage this mode is described in Reference manual ( 20.3.12 Asymmetric PWM mode ). If i read manual correctly, then you control rising and falling edges positions on one channel by registers CCR1 and CCR2 and on second channel by CCR3 and CCR4. Just follow reference manual.
    If you need both TIMers (more then two outputs), then choose one as Master (for example TIM1) and second as slave (TIM8). Configure TRGO signal to "Enable (event)" in TIM1 (MMS bits in TIM1_CR2). Configure TRGI in TIM8 to ITR0 (TS bits in TIM8_SMCR)  and select slave mode to "Trigger" (SMS bits in TIM8_SMCR). 
    Then when you enable TIM1, it sends signal on its TRGO on which is connected TRGI input of TIM8. TIM8 recieve that signal and start counting. All that should happen in one clock tick and both timers should run synchronized.

    Super User
    February 6, 2024

    @Michal Dudka, good point. I did not realize the 'F3xx already have Asymmetric PWM in timers; I thought it only came in newer STM32.

    JW