cancel
Showing results for 
Search instead for 
Did you mean: 

Generate a specific PWM signal

Stefan Stark
Associate III

Hi ST community,

For a project I would like to generate two interdependent PWM signals (Sa and Sw in the attached figure) with the STM32G0. The constraints/tasks are as follows:

  • tSw,off = constant for ~100ns
  • tSw,on = in a time range from ~100ns to 20us and is limited cycle by cycle by an active break (peak control application).
  • tSa,off = set every 300us in a time range from ~100ns to 30us.
  • tSa,on = is set every 300us in a time range from ~100ns to 5us.

The times for tSa,off and tSa,on are thus adjusted every 300us. The time tSw,on is limited cycle by cycle by the active break.

Following limitations I had to mention:

  • I'm allowed to interrupt the software all 300us for a few us (so polling could be difficult).
  • Focus on the STM32G0 microcontroller series.
  • The on time tSw,on is limited cycle by cycle with an comparator.

I will not present my previous approaches now, in order not to influence your ideas.

I look forward to your feedback.
Br, Stefan

1 ACCEPTED SOLUTION

Accepted Solutions
20 REPLIES 20
TDK
Guru
  • Use a single timer with CH1 and CH3 in combined PWM mode 2.
  • Set CCR1/CCR2 appropriately to get the first (blue) pulse on CH1
  • Set CCR3/CCR4 appropriately to get the second (black) pulse on CH3
  • When changing values, wait until the timer just rolls over, so it's in the tsw_off stage, and change all CCRx at once, quickly, with interrupts disabled.
If you feel a post has answered your question, please click "Accept as Solution".

Thx for your input TDK.

Some thoughts/Questions:

  • How is it possible with this concept to limit the on time of the Sw (tSw,on) with a comparator signal (active break)?
  • How can I make sure / find the time when the timer just rolls over? An Interrupt may be too slow and not possible in the final application.

Br, Stefan

TDK
Guru

> How is it possible with this concept to limit the on time of the Sw (tSw,on) with a comparator signal (active break)?

So when a comparator goes high, you want the pulse to be low? Not sure, but there's likely a way. Definitely a solution in hardware with an AND gate.

> How can I make sure / find the time when the timer just rolls over? An Interrupt may be too slow and not possible in the final application.

Assuming CCR1 is the timer value of the start of the first blue pulse:

  • Disable interrupts
  • Wait for CNT >= CCR1
  • Wait for CNT < CCR1
  • Change ARR and CCRx values. Probably won't matter, but do them in order.
  • Enable interrupts.

100us is plenty of time to change a few registers.

If you feel a post has answered your question, please click "Accept as Solution".

Hi TDK, thx again for your input.

  1. Do you have a reference where such a solution in hardware with an AND is illustrated? Till now we use this break function to disable all outputs of a TIM...
  2. I fully understand the logic of your propose, is there a function (callback function) which pops up when CNT < CCR1? Or what is your idea to monitor this?

Thx & Br

Stefan

Timer period starts at beginning of Tsa,off. Tsa,on generated using Combined PWM mode as TDK said above. Tsw,on normally generated using the plain PWM2 mode on one channel, as timer period ends with end of Tsw,on.

Premature end of Tsw,on accomplished through feeding COMP output to TIx or ETR (see TIMx_TISEL or TIMx_AF1 registers), setting that signal as Slave-mode controller's input (TIMx_SMCR.TS) and setting Slave-mode controller to Reset in TIMx_SMCR.SMS.

Update all required TIMx_CCRx together with TIMx_ARR in Update interrupt (or learn how to use Update-triggered "burst" DMA through the TIMx_DMAR/DCR mechanism). Enabling ARR/CCRx preset (TIMx_CR1.ARPE & TIMx_CCMRx.OCxPE) helps.

JW

> I fully understand the logic of your propose, is there a function (callback function) which pops up when CNT < CCR1? Or what is your idea to monitor this?

Literally read the register and wait for the condition. The update event happens when CNT=0. You could also use that, but it is subject to more delay.

__disable_irq();
while (TIM1->CNT < TIM1->CCR1);
while (TIM1->CNT >= TIM1->CCR1);
TIM1->CCR1 = x;
TIM1->CCR2 = x;
TIM1->CCR3 = x;
TIM1->CCR4 = x;
TIM1->ARR = x;
__enable_irq();

Or follow the idea from @waclawek.jan to us DMA to do the same on the update event, which will be even faster. Better solution, harder to program, though.

If you feel a post has answered your question, please click "Accept as Solution".

Ok now I got you. And I see that I miss to mention another critical limitiation. In the final application I'm not allowed to poll something in the while loop. All 300us I have some us time to do my magic (e.g., set the registers). I guess in this case the polling does not work, right? I also think it needs serval clk cycles to set the registers, by an clk of 48MHz also given at the moment it is car to set registers within some 100ns. So my thought's was that must be done within the periphery / hardware. What do you think?

Thx jan for your feedback. I have to think about that. We tried in a similar project the DMA-Burst mode function, do you have that in mind?

Br, Stefan

> DMA-Burst mode function

Yes, although I don't like the word "burst" as in DMA context that may mean several very different things. That's why I'm referring to the TIMx_DMAR/DCR register pair, that's unambiguous.

By using preloaded ARR and CCRx registers, the time window for update is one whole timer cycle, from Update to Update. Although, even with DMA, don't expect 5 registers (ARR..CCR3) to be updated within 400ns.

Tackle this one step at a time. For testing, you can modify the ARR/CCRx registers in Update interrupt, working with longer pulses/period; proceed to DMA later.

Final word, if you plan to use Cube/HAL for this, well, just don't.

JW