8pwm PULL request

I think i found a strategy for making the square wave.

By setting the LOW side gate output with reverse polarity, then setting those two complimentary outputs to the same duty-cycle should create a square-wave.

 // Configure TIM1 channels 1-6 for PWM output
      TIM_OC_InitTypeDef sConfigOC1 = {0};
      sConfigOC1.OCMode = TIM_OCMODE_PWM1;
      sConfigOC1.Pulse = 0;
      sConfigOC1.OCPolarity = TIM_OCPOLARITY_HIGH;
      sConfigOC1.OCFastMode = TIM_OCFAST_DISABLE;

      TIM_OC_InitTypeDef sConfigOC2 = {0};
      sConfigOC2.OCMode = TIM_OCMODE_PWM2;
      sConfigOC2.Pulse = 0;
      sConfigOC2.OCPolarity = TIM_OCPOLARITY_LOW;
      sConfigOC2.OCFastMode = TIM_OCFAST_DISABLE;

In this configuration, the polarity for PWM1 is set to high, meaning that the output will be active when the duty cycle is high (100%) and inactive when the duty cycle is low (0%). The polarity for PWM2 is set to low, meaning that the output will be active when the duty cycle is low (0%) and inactive when the duty cycle is high (100%). 

So these will not cross conduct if set to the same duty-cycle?

No, these will not cross conduct if set to the same duty cycle. 
And setting both to 30% will create a squarewave ?

Yes, setting both to 30% will create a square wave.

I guess next step is to verify if it work on two of the broken out pins. Ill try to set my Portenta up as a analyzer. Maybe someone already did that ? It does have super fast high resolution ADCs. Hmmā€¦ that would require a USB High Speed link. Maybe to fast for processing ?

I do have PA15(TIM8_CH1) and PB3(TIM8_CH1N) broken out. Basically I will have to measure the output on the 16bit ADC of the Portenta H7, and see how fast it will plot a time_frame.

@runger

Im back to square one, this is my output with 8pins:

TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM2-CH1 TIM2-CH2 score: 2
TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM2-CH1 TIM8-CH1N score: 3
TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH1 TIM2-CH2 score: 3
TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH1 TIM8-CH1N score: 2
STM32-DRV: best: TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM2-CH1 TIM2-CH2 score: 2
STM32-DRV: Restarting timer 1

The last two pins should be on TIM8 CH1,CH1N

Hmmmā€¦
This is unfortunate, but it doesnā€™t know which you prefer in this case - this would have to be reflected in the scoring function.

As a quick fix you could re-order the elements in the PinMap to move the lines involving TIM8 up, I think when equal the first entries will win.

more complex solution would be to reflect it in the scoring function. but this is a lot more complex than it seems since while you seem to want TIM8, the next user might prefer TIM2, for whatever reasonā€¦

Ah, I tried with the actual pins (PA14 and PB0) that worked. I wanted to measure PA15 and PB3.
Now it started bussing, in a not so good way?

The LOW side FET should have a high signal, when on?

TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH2 TIM1-CH2N score: -4
TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH2 TIM3-CH3 score: 3
TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH2 TIM8-CH2N score: 2
STM32-DRV: best: TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH2 TIM8-CH2N score: 2

Im thinking the dead-time is two low?

Maybe its bussing because the duty-cycle is not being set?

I printed out some more values:

Just wanted to see if it cleared the 4th pair. When its CH2 it fails. Probably due to the lack of Advanced Timer. With TIM8 it clears.

dead_time_ns:  400
Systemcore clock:  168000000
dead_time_ns:  400
Systemcore clock:  168000000
dead_time_ns:  400
Systemcore clock:  168000000
dead_time_ns:  400
Systemcore clock:  168000000
Init pair 4 GOOD!

@runger
Im thinking the setpwm for the 8PWM driver should do the same as the 4PWM only using the setPhase. Like its done for phases with the 6PWM driver.

// phase a
      _setSinglePhaseState(phase_state[0], ((STM32DriverParams*)params)->timers[0], ((STM32DriverParams*)params)->channels[0], ((STM32DriverParams*)params)->channels[1]);
      if(phase_state[0] == PhaseState::PHASE_OFF) dc_a = 0.0f;
      _setPwm(((STM32DriverParams*)params)->timers[0], ((STM32DriverParams*)params)->channels[0], _PWM_RANGE*dc_a, _PWM_RESOLUTION);

At times the grounding side of the single phase (stepper is 2phase) has to go low, So it would make sense to introduce the phase_state aswell?

@runger

Ok, so while the humming, there is voltage regulation on the outĀ“s.

A1: 1,87V
A2: 6,88V

B1: 6,04V
B2: 1,90V

The board is getting hot without current draw, and its still hizzing a bit.

Should I send the same value to the two complimentary pins?

At the moment Im just doing this:

`
   void _writeDutyCycle8PWM(float dc_1a, float dc_1b, float dc_1c, float dc_1d, void* params) {

    // Scale duty cycles to the PWM period
    
      _setPwm(((STM32DriverParams*)params)->timers[0], ((STM32DriverParams*)params)->channels[0], _PWM_RANGE*dc_1a, _PWM_RESOLUTION);
      // phase b
      
      _setPwm(((STM32DriverParams*)params)->timers[2], ((STM32DriverParams*)params)->channels[2], _PWM_RANGE*dc_1b, _PWM_RESOLUTION);
      // phase c
     
      _setPwm(((STM32DriverParams*)params)->timers[4], ((STM32DriverParams*)params)->channels[4], _PWM_RANGE*dc_1c, _PWM_RESOLUTION);

      
      _setPwm(((STM32DriverParams*)params)->timers[6], ((STM32DriverParams*)params)->channels[6], _PWM_RANGE*dc_1d, _PWM_RESOLUTION);

}`
STM32-DRV: best: TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH2 TIM8-CH2N score: 2
dead_time_ns:  2000
Systemcore clock:  168000000
dead_time_ns:  2000
Systemcore clock:  168000000
dead_time_ns:  2000
Systemcore clock:  168000000
dead_time_ns:  2000
Systemcore clock:  168000000
Init pair 4 GOOD!STM32-DRV: Restarting timer 1

Ok, so I managed to get it to select TIM8_CH1 and TIM8_CH1N, on the right pins.

But both pins are set high. That means I have been shorting the 4th bridge, no wonder why it got hot.

Now I can probe the waveform. Luckily the internal driver has a protection feature against cross-conducting scenarios.

Maybe it cant configure pins on two different timers ?

No, normally it can do it

Well thats Strange! I need to understand something about STM32 complimentary outputs.

When they are set up. Is changing that channel, the channel 1 (CH1,CH1N), enough or should we change both outputs?

It kinda sounds self explanatory.

Ok,

I enabled the phase :smiley:

phase_state[3] = PhaseState::PHASE_ON;

By reading pin change and recording the time on my Portenta, I got this output:
The phase voltage set to dc_1d = 0.247;.

So its like when they are not set, or set to 0, they are both high. And when set to 25% they mess up.

@Juan-Antonio_Soren_E

Shouldnā€™t they all be center aligned? Those timings look a little sus.

How does it look on a regular oscilloscope?

Cheers,
Valentine

On a positive note, I can pull all the bridges to GND, so the hardware should be OK.

There is something wrong with the plotting, I think i need to comma separate the pins values. Not sure its being parsed correct.

This is the raw data.

As I see it. Each time a line is going high, both are low. So not what the processing app draws.

01:400
10:3
00:1604
01:1606
00:2556
10:2558
00:11127
01:11129
00:12079
10:12082

@runger @Valentine @VIPQualityPost @Antun_Skuric

Now I get it. The Deadtime value cant be higher then 255. When it is set to standard 0.02, the calculations give 244. Almost the limit.

If it is turned up, it returns 0.

This is with a deadtime set in driver to 0.05

STM32-DRV: best: TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH1 TIM8-CH1N score: 2
DeadTime :  0
DeadTime :  0
DeadTime :  0
DeadTime :  0
Init pair 4 GOOD!STM32-DRV: Restarting timer 1

Also, when I sat the freq. to 1Khz and using 0.02f, the dead_time returned 0. With 2Khz and 0.02f it returns:

STM32-DRV: best: TIM1-CH1 TIM1-CH1N TIM1-CH2 TIM1-CH2N TIM1-CH3 TIM1-CH3N TIM8-CH1 TIM8-CH1N score: 2
DeadTime :  244
DeadTime :  244
DeadTime :  244
DeadTime :  244
Init pair 4 GOOD!STM32-DRV: Restarting timer 1

I did make the Portenta grab the deadtime. Although it probably has much better capabilities compared to just digitalRead.

Now just printing to terminal with a set freq. and using PulseView (CSV import). 10% dutyā€¦

1 Like

The noise is gone, and the phase is regulated to 1,25 V, w. 12V supply and 10% duty. The other phases are floating though.

1 Like

Huh, Iā€™ll look into thatā€¦ thanks!!

It should definitely print the value and a warning in debug modeā€¦the real danger is if people start changing polarization like I did. I was lucky that the power supply is a standard router psu which canā€™t burn through the FETs, it did get hot that one timeā€¦

Hey, on a ā€œnormalā€ setup for a new board I would always recommend checking the PWM without the gates powered before driving the FETs and a motor. But on the STSPIN32G4 you canā€™t as the PWM happens internally on the chip. So here Iā€™d recommend using a current-limiting PSU and high ohm motor for safety during first tests.

To clarify the error youā€™ve found, what youā€™re saying is the macro __LL_TIM_CALC_DEADTIME() which we use to convert the ns to the dead-time value sometimes works out as >255? This would from my point of view be an error of the macro, but looking at it (its super-complex, ugh) it does seem to me the result is cast to uint8_t in all casesā€¦
Were you using the macro? Could you share the code you were running to set the dead-time?

[Edit]

no, wait, youā€™re saying the macro returns 0 if the dead-time is larger than the maximum? Thatā€™s even worse. I will add a check for that.

Iā€™ve pushed a fix for this the dev branch, if you want to try it outā€¦