PWM Deadtime compensation

Yes it should be as easy as that.
This other variant mentioned in this article


maps the deadtime compensation when it’s below a threshold current so that it’s not just on or off.

The value of the deadtime compensation should be less than the programmed deadtime. In my case I was increasing it until I was satisfied with the phase current waveform.
MESC firmware has an interesting method to measure the effective deadtime, by increasing the pwm until phase current is visible in the measurement.

And this is another interesting article about deadtime compensation I had in my bookmarks

1 Like

I am not yet working on it, but more pictures of how the dead time impacts the current waveform

And why:

That’s interesting, but it would depend on the implementation?

For example, our software 6-PWM dead-time applies the dead-time in equal proportions to the high and low side, and would not be subject to the phase shift shown in the diagram.

I’d have to look them up, but IIRC the hardware dead-time of at least some of the MCUs is also symmetrical.

So this would be a problem seen more in combination with external drivers applying dead-time in hardware?

If we’re diving into the details of PWM generation at this level, a concern I have is that our PWM output is not synchronised to the hardware - this means that when setting the PWM levels (typically once per main loop cycle) there is a random chance that we hit the PWM timer reset while changing the values. Normally the PWM peripheral registers used are buffered, so its not a problem writing the values per se, but what it means is that one or two phases could switch to new values one PWM cycle earlier than the other phases.
(This is assuming the user has taken care to use pins from the same timer. On many MCUs we allow using different timers, in which case the phases aren’t necessarily in sync).
The solution could be to use interrupt/DMA driven setting of the PWM values, to ensure they are all changed at a time that guarantees they are applied together in the next PWM cycle.

If I find time (lol, don’t hold your breath) I’ll set up a test to see if it makes any difference.

We need to differentiate the programmed deadtime and the effective deadtime.
The shift is due to the turn ON and turn OFF delay of the mosfet, and that depends on the direction of the current.
In figure c, when the current is positive, the ON time is smaller than the ideal pwm(a), so you add a conpensation factor to the duty cycle.
In figure d, when the current is negative, the ON time is higher than the ideal pwm(a), so you substract a conpensation factor from the duty cycle.

We are not touching the timer deadtime configuration, just compensating the waveform.
This could probably be implemented before setting the pwm here and could look like:

if (abs(Ua) > threshold) Ua += sign(current.a) * dtcomp;
if (abs(Ub) > threshold) Ub += sign(current.b) * dtcomp;
if (abs(Uc) > threshold) Uc += sign(current.c) * dtcomp;

This is possible only if the phase currents are available, so current sensing should be used, and with 2 shunts, the 3rd phase current should be derived as Ia + Ib + Ic = 0
Close to 0 current, the deadtime is not compensated.
Dtcomp depends on the range in the driver.

The diagram also shows that the real middle of the pwm is shifted, but that’s another topic.

1 Like

I started to play around with this.
Using the openloop mode is the best, as you can spin the motor slow enough and the current is high enough to see a proper waveform

One challenge is the quality of the phase current samples as it’s not filtered.

Hope I am not bothering you with this here.
I am struggling with getting this to work because the phase current is noisy, I need to think about it, maybe I can do a reverse clark and park of the already filtered d and q currents.
I wanted to show you how it looks like when it works but I cheated by using the duty cycles instead of the phase current, which should not be a problem without load.

I just added this:

center = driver->voltage_limit/2;
Ua += (Ua > center ? 1:-1) * dtcomp;
Ub += (Ub > center ? 1:-1) * dtcomp;
Uc += (Uc > center ? 1:-1) * dtcomp;

The compensation has to be surprisingly high for me (0.7v), but the phase current waveform becomes sinusoidal.
I recorded the waveform and the motor.

1 Like

The waveform link doesn’t work for me

Oups, can you try again ?

Anybody interested in giving this a try ?
It should already give good results in openloop at slow speed/low load.
I just want to make sure I am not fighting with a problem only I have with my setup.

I can summarize what I did so far.

I declared a global variable for deadtime compensation so I can update it and observe the waveform.

float dtcomp = 0;

Here I added the code for the deadtime compensation.

if (dtcomp > 0){
  center = driver->voltage_limit/2;
  Ua += (Ua > center ? 1:-1) * dtcomp;
  Ub += (Ub > center ? 1:-1) * dtcomp;
  Uc += (Uc > center ? 1:-1) * dtcomp;
}
// set the voltages in driver
driver->setPwm(Ua, Ub, Uc);

Here, I compensate the voltage command so that the amplitude is same with or without the deadtime compensation.

if (dtcomp > 0 && abs(dtcomp) > abs(Uq)) Uq -= _sign(Uq) * dtcomp; 

I ended up compensating for 0.70V, which in my case is almost the power supply voltage * Deadtime% * 2.
I am not sure if it’s a coincidence, based on this paper I am compensating both for the deadtime and the stiction.

A supplementary test using a current
sensor and the torque sensor on motor M4 found that, while
current production starts at d = 0.071, external torque is not
felt until d = 0.083. This indicates that the deadtime ddt =
0.071 is the deadtime duty cycle for this motor driver and the
stiction is dst = 0.012 or Vst = 60 mV at the tested location

I want to experiment by checking at what minimum pwm duty cycle the current starts flowing, and at what minimum pwm duty cycle movement is visible. I think this could even be measured by software.

This method is not taking all the ripple/cogging sources as does the anticogging map mentioned in the paper, but can probably already give good results with little tuning without an encoder.

@runger I believe this thread was created because of the deadtime compensation discussions, but please feel free to move my posts to a new thread if you think it doesn’t belong here, because I have more bla bla and screenshots coming :rofl: Thanks in advance

I’m interested in the stiction-compensation part, because a windturbine likes no_load conditions to start. But I’m not planning to use this ESC1 board.
I guess the code is universal for other powerstages as well? At least, when they use the same current sensing method?

[OT]
I’m surprised to see everyone playing with this evaluation board. To me it seems, it has major issues with excessive heat under load?
Currently I’m looking for the most mature mid-power range controller available…and the list of candidates is pretty short :frowning:

I think the effect of deadtime is relevant for any board.
The stiction might depend on the motor.

Bring them on!! :smiley:

From my point of view this is all fine, but if you want me to split the thread or something, let me know.

No wonder given the price of this (subsidized) hardware!
I think people underestimate the difficulty of interfacing with its minuscule solder pads, and don’t check the integration options (eg no SPI) in advance, because it’s actually quite complex to do so…

I believe Valentine has produced an updated design, renamed to Quadrans, there’s a forum post about it…
I’ve done an updated version based on the STM32G431, which I’ll test and then share as soon as I can.

@Anthony_Douglas what do you say? It’s your thread

Uh oh, IDK, take the discussion however you like, it will not undo what has been done, people can still read the stuff above, which mostly answers the question of how to change dead time on the board. I think we are mostly done with that subject, I would just make a new post for organizational reasons of the forum if the subject is changed but all good to me.

Moved to new thread by popular demand :smiley:

Thanks @runger, and sorry for creating that mess.

Here is another illustration of the problem with the deadtime.
This is the pwm waveform when running in openloop. The vertical lines are when the hall sensors change state, it should happen at the pwm waveform zero crossing (red arrows), with possibly a slight shift if the hall sensors are missaligned. But here it’s completely off, it means the magnetic angle generated by the windings is shifted.

Now this is with deadtime compensation. It’s much cleaner and the hall sensor signal can be used to identify the start and end electrical angle of each sector(autodetect)

That is an impressive difference, I’m really surprised!

is this with SimpleFOC code? Are the settings otherwise the same except for the deadtime compensation?

What do you mean by PWM waveform? The phase to GND voltage? Or the phase current?

Yes this is simplefoc with the changes mentioned here, I am just making the compensation 0(OFF) or 0.7V.
By PWM waveform, I mean the output duty cycles of the SVPWM sorry. I assume it’s in sync with the BEMF with low speed and load.

Now I tried something else, I halved the timers deadtime (60 to 30 cycles, it was too high anyway), and I still had to compensate by 0.5V instead of 0.7V to have a nice sinusoidal phase current waveform.
So that means I am not only compensating for the deadtime but probably also the stiction, otherwise I would have to halve the compensation as well.
If I still remember my middle school math, the deadtime compensation is 0.40V and stiction compensation is 0.30V. And by halving the deadtime, I get 0.20V deadtime compensation and still 0.30V stiction or black energy compensation.

This makes sense…

Ah, so we’re looking at the computed value for the PWM duty cycle, rather than the PWM itself or a measured voltage/current. This also makes more sense to me now.

The position of the HallSensor interrupts is an indirect feedback confirming it is probably working as intended? But to really see the effect we’d have to look at a phase current measurement?

Yes it is visible here, the phase current waveform improves as I increase the compensation.