3-Phase Inverter & BLDC Basics
Embedded → Motor Control (FOC, BLDC)
Six switches is all it takes to spin three phases
A brushless DC motor has three stator windings (phases A, B, C) arranged 120° apart. To spin the rotor, you don't need three independent voltage sources — you need one DC bus and six switches (usually MOSFETs) arranged as three half-bridges, one per phase. Each half-bridge has a high-side switch (connects the phase to +V) and a low-side switch (connects the phase to ground). Turn on the right pair at the right time and current flows through two windings while the third sits idle — that's the entire power stage every FOC drive is built on top of.
One phase always floats
At any instant in six-step (trapezoidal) commutation, exactly two phases are energized — one pulled high (PWM-switched to the bus), one pulled low (tied to ground) — and the third phase is left floating(both its switches open). That floating phase isn't wasted: its terminal voltage is exactly what a sensorless drive reads to estimate rotor position from back-EMF, since nothing is actively driving it.
Stepping through all six combinations of (high phase, low phase) advances the stator's magnetic field in 60° increments — one full mechanical rotation of the field takes six sectors, hence "six-step". The commutation table below is the standard sequence:
| Sector | High-side ON | Low-side ON | Phase A | Phase B | Phase C |
|---|---|---|---|---|---|
| 1 | AH | BL | PWM | GND | float |
| 2 | AH | CL | PWM | float | GND |
| 3 | BH | CL | float | PWM | GND |
| 4 | BH | AL | GND | PWM | float |
| 5 | CH | AL | GND | float | PWM |
| 6 | CH | BL | float | GND | PWM |
Firmware: a lookup table, not a calculation
The commutation decision itself is deliberately cheap — a lookup, not real-time trig — because it has to run inside a fast interrupt (typically driven by Hall-sensor edges or a commutation timer):
// One entry per sector: which GPIO/PWM channel drives high,
// which drives low, all others forced off.
typedef struct { uint8_t high_phase; uint8_t low_phase; } commutation_step_t;
static const commutation_step_t COMMUTATION_TABLE[6] = {
{ .high_phase = PHASE_A, .low_phase = PHASE_B }, // sector 1
{ .high_phase = PHASE_A, .low_phase = PHASE_C }, // sector 2
{ .high_phase = PHASE_B, .low_phase = PHASE_C }, // sector 3
{ .high_phase = PHASE_B, .low_phase = PHASE_A }, // sector 4
{ .high_phase = PHASE_C, .low_phase = PHASE_A }, // sector 5
{ .high_phase = PHASE_C, .low_phase = PHASE_B }, // sector 6
};
void apply_commutation_step(uint8_t sector, uint16_t pwm_duty) {
disable_all_phase_outputs(); // safety: never leave two
// high-sides fighting each other
const commutation_step_t *s = &COMMUTATION_TABLE[sector];
set_high_side_pwm(s->high_phase, pwm_duty); // switched (speed control)
set_low_side_on(s->low_phase); // held on (current return path)
// the third phase's driver stays disabled -> floats -> readable as back-EMF
}Step through the sequence yourself
Advance the sector manually, or hit auto-play — watch which phase floats each step, and notice it's always the phase that was just energized two steps ago:
| Sector | High | Low | A | B | C |
|---|---|---|---|---|---|
| 1 | AH | BL | PWM | GND | float |
| 2 | AH | CL | PWM | float | GND |
| 3 | BH | CL | float | PWM | GND |
| 4 | BH | AL | GND | PWM | float |
| 5 | CH | AL | GND | float | PWM |
| 6 | CH | BL | float | GND | PWM |
Practice
Completion saves automatically after you read through to the end.
Next lesson →