Electronic – STM32 – ESC : Problem with the BEMF

brushless-dc-motormotor controllerstm32

I'm making a ESC for my BLDC motor. I used a STM32 (to generate my PWM), 3 IR2101 mosfet drivers (https://www.infineon.com/dgdl/ir2101.pdf?fileId=5546d462533600a4015355c7a755166c) and 6 mosfets to control the differents phases of the motor.

My schematic:

enter image description here
enter image description here

I generate my phase with a PWM on the High side and a GPO on le Low side.

HIGH side of my PWM (phase A,B and C)

enter image description here

PHASE A (going below 0V!)

enter image description here

The signal seems correct but when I connect my motor we can see that the BEMF is backward compared to a good BEMF.

PHASE A B C
enter image description here

BEMF A B C
enter image description here

I try to change the frequency of the PWM, change the duty cycle or the delay between each phase but nothing change (and sometime it's worse…). Do you have an idea why ?

My STM run at 8MHz.
PWM frequency : 900Hz with a duty cycle of 5%.
During this test my motor consumes 12V / 0.8 A.

EDIT

I don't know why my BEMF is reversed compared to a good one.
enter image description here

Below you can see my phase C (yellow), the virtual ground of my motor (light blue), the mathematical operation Phase C – Virtual ground (dark blue) and the output of my LM339 (pink).
enter image description here

I saw multiples subject about this problem on Stack exchange but each time the answer isn't clear. (enter link description here).

I guess that my PWM and BEMF aren't 'in phase'.. I need some explanations.

Best Answer

Welcome to StackExchange! Well done first post.

You are correct, your forcing voltage is out of phase with your motor.

Looks to me like you are sampling in the incorrect location during your PWM cycle. Ensure that your ADC sample occurs at the center of the PWM cycle when the PWM cycle is high. There may be a minimum duty cycle required in order to get a proper sample, but that may not be the case as 900Hz is a pretty low frequency.

It is difficult to surmise from your scope screenshots, but it appears that the phase is negative going on the low side of your PWM and positive-going on the up-side of your PWM... so your code is likely doing exactly what you are telling it to do, but in the wrong place in the cycle.

I like to check my interrupt timing (roughly) by setting up a pin to turn on when the ADC interrupt starts and turn off when the ADC interrupt ends. I can usually gather good information from that.

If you verify/fix your ADC sample time, and the problem persists, then post a screenshot of one phase as it is rising, full-scale Y-axis.

Stick with it! Problems are solved by putting your head down and working at it. But remember to walk away and get some sleep. Problems look very different in the morning!


edited to add

Based on your comments, I am getting the sense that there may be some basic misunderstandings (I may be wrong).

Calculating Neutral Voltage

First off, you don't need to measure a neutral voltage. This is a wasted ADC module. You can calculate your neutral voltage: neutral = (phaseA + phaseB + phaseC) / 3;. Recommend you convert that to a fixed-point notation for speed, but the math is correct. Now that is one less ADC that you require!

Your neutral looks pretty much correct. If you mentally do the math that I just described, you will see that the neutral voltage is indeed the average (or very nearly) of the phase voltages.

Configure Registers to do the Work

Next, if you configure your TIM1 and ADC12 registers in center-aligned and triggered at the peak of counter mode, then no calculation is necessary to sample correctly.

When to Commutate

In your comment, you wrote

if the floating phase - the virtual ground = 0. If it's true, then I theoretically know the duration to wait before commutating the next phase to high

This is true only half the time and I just want to word it with clarity. Note that the BEMF phase is alternating between rising on one phase and falling on another.

if(phaseIsRising){
    if(phaseVoltage > neutral)
        commutate();
}else{
    if(phaseVoltage < neutral)
        commutate();
}

If you correctly implement the above code, you will be able to operate the motor, but 30 degrees advanced. Believe me, it will look much better than it does in your screenshots.

Further Work

If you get this far, I will leave it to you to determine how to shift the commutation event by 30 degrees.