Sensorless Brushless Can’t Even

Charles wrote a prac­ti­cal and less point­less­ly tech­ni­cal post about his SimonK exper­i­ments, com­plete with a 250 lb sys­tem pro­to­type. The­se are my hope­ful­ly in-phase sci­ence notes.

If you’ve spent any time on hob­by avion­ics and mobile robot­ics in the last few years, you’ve heard of the “SimonK reflash.” This refers to firmware writ­ten by the epony­mous Simon Kir­by based on the work of Bern­hard Konze for the hob­by-grade ATmega8-based sen­sor­less con­trollers for brush­less motors.


Quadro­tor folks use con­trollers flashed with SimonK firmware because it does almost no input fil­ter­ing, near­ly direct­ly con­vert­ing its input, a remote con­trol (R/C) style pulse sig­nals, into its out­put, a pulse-width mod­u­la­tion (PWM) duty cycle, scaled to to dri­ve a brush­less motor. Mobile robot­ics folks, includ­ing those in my com­bat cir­cles, use SimonK’s effec­tive sen­sor­less star­tup rou­ti­nes and reversible oper­a­tion to run trac­tion sys­tems. They speak rev­er­ent­ly of the Simon’s amaz­ing pow­ers over air­craft elec­tron­ic speed con­trollers (ESCs).

The most bizarre part of this is that the con­trollers the­se peo­ple are using and hack­ing are avail­able from the likes of Hong Kong-based Hob­byK­ing for $5.

HobbyKing store screenshot

Five frig­gin’ dol­lars.

I live down the street from $4 toast. So the idea that for 20% more than a slice of flame-kissed bran smeared with Fresh Mead­ows Farm mul­ber­ry com­pote, one can spin three-phase motors sound­ed seri­ous skep­tic alarms in my head.

McDonald's McDouble

By the way, a McDou­ble is $1. Not that it should be, but it is. Bul­lied farm­ers, count­less suf­fer­ing ani­mals, and under­paid ser­vice work­ers made it pos­si­ble.

I bought six units of the­se (ESCs, not McDou­bles) with the inten­tion of fig­ur­ing out what they’re real­ly worth. Ques­tions I want to answer start with,

  1. Can this con­troller spin a motor?
  2. Can I recon­fig­ure SimonK for this con­troller so that when reflashed, it still spins a motor?
  3. Do the cool SimonK fea­tures that com­bat robot folks use work with it?

For brevi­ty (lol.), I’m going to refer to this fam­i­ly of ATmega8A-based sen­sor­less brush­less con­trollers with vir­tu­al neu­tral (explained lat­er) as CCCs: cheap Chi­ne­se con­trollers.

To start, I’m not crit­i­cal­ly exam­in­ing CCCs’ or this par­tic­u­lar controller’s design and con­struc­tion. I first want to see it work as rumored. Not to men­tion that for $5, we know that I’ve bought shit­ty hard­ware. It doesn’t do me any good to point out the turd nuggets until lat­er, except as prep work and due dili­gence.

Can this controller spin a motor?


This on its own is aston­ish­ing. The glob­al man­u­fac­tur­ing econ­o­my has cut out enough mid­dle­men to offer unit quan­ti­ty com­put­er­ized pow­er elec­tron­ics through retail out­fits tak­ing cred­it card pay­ments in US Dol­lars, shipped to your door. Take a breath.

SimonK functional test

ESC heat shrink removal

OK, I said I wasn’t gonna delve into the details, but the reflash­ing requires access to the micro­con­troller, so I do at least need to take it apart.

Multistar 20A 6S Slim top

Multistar 20A 6S Slim bottom

Yup, that’s a motor con­troller.

Flashing the firmware

“Reflash­ing” refers to pro­gram­ming the device-inter­nal flash mem­o­ry in the Atmel ATmega8A micro­con­troller that runs the motor con­troller with dif­fer­ent firmware.

Con­fes­sion: I’ve nev­er actu­al­ly pro­grammed an AVR (the Atmel 8-bit micro­con­troller class of which the ATmega8A is a mem­ber) over its in-sys­tem pro­gram­ming (ISP) inter­face before. I’ve “upload­ed” a few Arduino “sketch­es,” but that’s send­ing the code over a seri­al link to the Arduino’s already-run­ning AVR, which pro­grams the code to itself.

Arduino upload sketch

In hob­by­ist argot, the pro­gram the micro­con­troller is run­ning to do this self-pro­gram­ming is called a boot­load­er, which con­fus­ing­ly is a def­i­n­i­tion con­trary to the use of the word out­side of inter­nal-flash sys­tem-on-chip (SoC) devices1.

AVR ISP connections

The alter­na­tive is to con­nect an ISP device that exter­nal­ly dri­ves the pro­gram­ming process. I want to pro­gram with an ISP pro­gram­mer because I don’t know if the ESCs have a boot­load­er that I could rely on. Exter­nal pro­gram­ming allows you to recov­er from mis­takes (boot­load­ers can and do erase them­selves) and is robust over dif­fer­ent micro­con­troller mod­els.

Inex­plic­a­bly, AVR ISP has two dif­fer­ent stan­dard con­nec­tors for its phys­i­cal inter­face, a 6- and a 10-pin. You could argue that the pinout on the 10-pin insu­la­tion-dis­place­ment con­tact (IDC) con­nec­tor puts a ground wire between every sig­nal-car­ry­ing con­duc­tor, improv­ing sig­nal integri­ty, but it’s a sev­er­al mega­hertz pro­to­col that doesn’t real­ly need that kind of con­sid­er­a­tion.

USBasp clone with socket programmer

In my pile of crap, I found a Bus Pirate, Spark­fun Edi­tion that has a 10-pin IDC head­er not for ISP pro­gram­ming and for some rea­son, a Pololu USB AVR pro­gram­mer that has a 6-pin head­er. I hacked up an adapter and prompt­ly ordered a pro­gram­mer with a 10-pin head­er.

The most notable thing about this setup is what the 10-pin head­er is attached to. It’s a sock­et pro­gram­ming fix­ture for the TQF­P32-pack­aged ATmega8A. It routes the pro­gram­ming sig­nals to spring-load­ed claw pins posi­tioned over the cor­rect gull wing leads. This lets you pro­gram a chip that’s sol­dered down, even if its board has no pro­gram­ming head­er exposed. I sus­pect it’s the tool used by Hob­byK­ing for pro­duc­tion on some its boards that lack test points, although the­se points are present as a row of sol­der blobs adja­cent to the micro­con­troller on the 20 A board.

AVRDUDE instal­la­tion and con­nec­tion test to see if it can read the tar­get ATmega8A’s fuse bits

Oth­er than that, it’s a straight­for­ward invo­ca­tion of AVRDUDE to flash each con­troller. On OS X, AVRDUDE is avail­able on Home­brew.

Building the code

Now the ques­tion is how to get and build the SimonK code for this con­troller. The eas­i­est way to do this is to have bought a con­troller on this Google spread­sheet to begin with: ESC specs for Simonk / BLHe­li FW flash. My con­troller (pro­duct ID 9351000061-0) isn’t on there, so I looked at the clos­est ones in the Hob­byK­ing Mul­ti­star sec­tion.

SimonK compatibility spreadsheet

That gives me the choic­es of kda.hex, kda_nfet.hex, kda_nfet_ni.hex, kda_8khz.hex, and dlu40a.hex, each a board tar­get for which the SimonK code can be con­fig­ured to build. There’s also a chance that the design is total­ly dif­fer­ent from those entire­ly, since the form fac­tor did change and thus Charles’s “Law of Chi­ne­se Pack­ag­ing Iner­tia (‘If the Chi­ne­se pro­duct looks the same, it prob­a­bly is the same’)” doesn’t quite apply.

In the Make­file, there’s a suf­fix rule for .inc to .hex, so I know each of those .hex tar­gets were built from the cor­re­spond­ing .inc (by sym­link­ing ¯\_(ツ)_/¯ the source base­name to that of its tar­get…).

Look­ing at the board, I know it’s all N-chan­nel pow­er tran­sis­tors (FETs) so kda.hex and kda_8khz.hex are out. men­tions opto-iso­la­tors and has the wrong resis­tor val­ues (O_POWER and O_GROUND) so its tar­get HEX can be elim­i­nat­ed as well.

That leaves kda_nfet.hex and kda_nfet_ni.hex. Their .inc’s dif­fer only on whether they invert the pulse width input sig­nal. I couldn’t trace any invert­ing tran­sis­tor from said input (the orange wire) to the micro­con­troller so I was lean­ing 80% towards kda_nfet_ni.hex. Get­ting that wrong doesn’t blow any­thing up, but get­ting the pow­er stage polar­i­ty or pinout wrong does, so I dou­ble checked the .inc dec­la­ra­tions again­st the board. The resis­tor divider val­ues were also wrong, but I had a hunch they didn’t mat­ter too much.

SimonK flash make target
Down­load, com­pil­ing, and flash­ing SimonK firmware

Down­load­ing the code is fair­ly straight­for­ward, since it’s on GitHub. I also need­ed to install avra, an AVR assem­bler.

brew install avra
git clone
cd tgy/
make kda_nfet_ni.hex
avrdude -c usbasp -p m8 -U flash:w:kda_nfet_ni.hex:i

After that, it was just a mat­ter of build­ing the .hex tar­get with make and flash­ing the file to the con­troller.

Lego Batman first try

And it worked. First try.

Now, this all seemed “easy” because I yolo’d my con­troller using an edu­cat­ed guess at a work­ing con­fig. How­ev­er, you should nev­er take the account of some­thing being easy from an embed­ded sys­tems engi­neer at face val­ue, because we’re about as cred­i­ble on easy things as is an email from Lagos promis­ing rewards for break­ing Bernie Mad­off out of pris­on, espe­cial­ly if firmware is involved.

Bikini Atoll nuclear test

More impor­tant­ly, you shouldn’t be yolo’ing non-$5 hard­ware. The remain­ing 20% out­come of my 80% con­fi­dence in kda_nfet_ni.hex was that the con­troller lit­er­al­ly catch­es fire. There’s a real dis­cov­ery process to finding—or writing—a board con­fig (the .inc file) appro­pri­ate to your con­troller before you flash it. It’s a com­bi­na­tion of trac­ing con­nec­tions on its print­ed cir­cuit board (PCB) for micro­con­troller pin assign­ments and ana­lyz­ing polar­i­ties used by the stock firmware with a mul­ti­me­ter or oscil­lo­scope. Charles’s write­up has an exam­ple of this and the SimonK README describes the full setup process.

Customizing options

Since the setup went so smooth­ly, I jumped direct­ly into con­fig­ur­ing SimonK for “robot dri­ve.” The­se are con­trol par­a­digms that set con­trollers used for mobile robot trac­tion oper­a­tion apart from say, R/C air­plane pro­peller dri­ve.

I deduced what the­se options mean through a com­bi­na­tion of read­ing the code (it’s 4000 lines of AVR assem­bler, by the way), guess­ing “how I’d imple­ment it,” and through empir­i­cal test­ing with a radio/servo tester and an oscil­lo­scope.

Regenerative braking (COMP_PWM)

Brushless inverter passive diode
Non-regen­er­a­tive default PWM with pas­sive diode free­wheel­ing2

With SimonK in its default con­fig­u­ra­tion, the action of the three-phase invert­er in the con­troller is alter­nat­ing between excit­ing the in-phase coils (one high-side leg on and one low-side on3) and diode free­wheel­ing (only one high side on). The frac­tion of the time spent excit­ing the coils is then the frac­tion of the bus volt­age that is applied to the motor; the motor will accel­er­ate until its induced back-EMF (BEMF) reach­es this frac­tion.

How­ev­er, nei­ther of those states allows the motor to return ener­gy to the bus, unless its BEMF (which is lin­ear to its speed) exceeds the bus volt­age plus the FETs’ body diode for­ward volt­age4. In the first video above, you can see that reduc­ing the throt­tle caus­es the motors to coast and slow­ly reduce its speed until it match­es the applied (frac­tion­al) volt­age.

Brushless inverter synchronous rectification
Regen­er­a­tive PWM with high-side syn­chro­nous rectification/active free­wheel­ing; note the V phase high-side switch turn­ing on syn­chro­nous­ly with the low-side switch turn­ing off2

Regen­er­a­tive brak­ing is a result of using dif­fer­ent pulse-width mod­u­la­tion (PWM) schemes that allow the motor to flow cur­rent back into the controller’s bus dur­ing at least part of the cycle. SimonK’s option­al PWM scheme alter­nates between excit­ing the in-phase coils (one high-side leg on and one low-side on) and “active” free­wheel­ing (two high-side legs on). The active free­wheel­ing both brakes the motor (applies torque in the oppo­site direc­tion of motion) and allows the dri­ven phase wind­ings act as a boost con­vert­er.

Now you can see that the motor’s speed close­ly tracks the applied throt­tle. This is because when the BEMF of the motor exceeds the PWM duty cycle × bus volt­age, the motor returns cur­rent to the bus. This is the reverse of excit­ing the motor, so cur­rent is allowed to flow in both direc­tions and will want to flow until the motor’s BEMF match­es its applied volt­age.

This is called COMP_PWM in the code because the phase that switch­es between high-side con­duct­ing and low-side con­duct­ing is tog­gling between its com­ple­men­tary FETs.

Brushless inverter locked antiphase
Regen­er­a­tive PWM with locked antiphase; not sup­port­ed by SimonK2

This is slight­ly mis­lead­ing because oth­er PWM schemes like locked antiphase or space vec­tor mod­u­la­tion (SVM) also use com­ple­men­tary PWM.

RLC series schematic
Series resis­tor-induc­tor-capac­i­tor cir­cuit

An elec­tri­cal engi­neer might con­sid­er that motor speed changes don’t hap­pen instan­ta­neous­ly, but instead acts anal­o­gous­ly to a series RLC cir­cuit. The motor speeds up or slows down (increas­ing and decreas­ing BEMF) like the charg­ing and dis­charg­ing of the capac­i­tor (C). The induc­tance (L) of the phase wind­ings offers “iner­tia” again­st cur­rent (I) changes. The stiff volt­age source is the bat­tery with bus capac­i­tance, and its volt­age (V) varies with PWM duty cycle. And to damp the cur­rent slosh­ing in and out of the capacitor/motor speed/induced BEMF is the resis­tance (R) pro­vid­ed by the motor wind­ings, invert­er rDS (on), and to some degree, the bus capac­i­tors’ equiv­a­lent series resis­tance (ESR).

You might also con­sid­er that this is very lit­tle damp­ing, so regen­er­a­tive brak­ing results in mas­sive cur­rent spikes, and you’d be right. With­out some lim­it to how quick­ly the PWM duty cycle slews or bet­ter yet, feed­back con­trol again­st sensed cur­rent, com­ple­men­tary PWM destroys motor con­trollers.

Reversible operation (RC_PULS_REVERSE)

SimonK has an option to inter­pret its throt­tle input as bidi­rec­tion­al, with com­mand­ed speeds in oppo­site direc­tions mir­rored across a neu­tral point between the extremes of the input range.

Com­bined with COMP_PWM, this RC_PULS_REVERSE option allows “four-quad­rant” (4Q) con­trol of your brush­less motor. This means that either for­ward or reverse torque can be applied to a motor that is spin­ning for­ward or in reverse. As you can imag­ine, this is crit­i­cal to brush­less motors used for mobile robot trac­tion appli­ca­tions, where dif­fer­en­tial steer­ing like on skid-steer load­ers and tanks is the norm. In this dri­ve­train scheme, torques are com­mand­ed in either direc­tion while at any posi­tion or veloc­i­ty.

I’m pret­ty impressed by the firmware’s abil­i­ty to main­tain rotor track­ing dur­ing direc­tion­al changes5.

Neutral braking (MOTOR_BRAKE)

While it’s a bit hard to tell that the motor is revers­ing in the RC_PULS_REVERSE video, it’s eas­ier to tell that when the motor is com­mand to zero speed, it’ll coast until it comes to a stop.

Brushless inverter brake
Brake acti­va­tion using two high-side switch­es2

SimonK (and even most stock air­plane ESC firmwares) pro­vides an option to brake the motor by turn­ing on FETs along one side of the invert­er. This short cir­cuits the induced cur­rent through the invert­er. Due to Lenz’s law, the direc­tion of the induced cur­rent cre­ates a torque that brakes the motor. Like when dri­ving the motor, the brak­ing can also be PWM’d so it’s only active for some frac­tion of time (BRAKE_POWER set­ting).

The result is quick­er stop­ping when the motor is com­mand­ed to neu­tral or zero speed. This stop­ping torque would be more sig­nif­i­cant when mul­ti­plied by gear­ing as in a trac­tion sys­tem.

A lot of addi­tion­al set­tings cov­er brak­ing torque and ramp­ing.

Variable timing advance (MOTOR_ADVANCE, TIMING_OFFSET)

“Six-step” sen­sor­less con­trollers like CCCs are so named because they approx­i­mate three-phase AC out­put using six steps of PWM’d direct cur­rent (DC) out­put, with each step rep­re­sent­ing one-six­th or 60° of a rota­tion. DC dri­ve takes up only two motor phas­es, leav­ing the third undriven and mon­i­tored for the motor’s BEMF. The tran­si­tion between each step is called com­mu­ta­tion.

Six step brushless commutation
Six step sen­sor­less com­mu­ta­tion; with­out loss of gen­er­al­i­ty, zero-cross detec­tion tim­ing (in the high­light­ed step) is shown in detail in fol­low­ing dia­gram2

Notice that when a phase is left undriven, the BEMF it shows moves from its pre­vi­ous step’s DC state (+ or -) to its next step’s DC state (- or +). The con­troller mon­i­tors this tran­si­tion specif­i­cal­ly look­ing for a neg­a­tive-to-pos­i­tive or pos­i­tive-to-neg­a­tive sign change, or zero-cross, because it occurs at 30° of rota­tion past the pre­vi­ous com­mu­ta­tion.

By the way, the “zero” referred to isn’t the neg­a­tive bus volt­age (i.e. the inverter’s zero), but rather the volt­age at the motor’s star—or “neutral”—connection (i.e. the motor’s zero). For sim­plic­i­ty with PWM at 100% duty cycle as shown, the volt­age at the motor’s zero is rough­ly equal to (Vbus+ + Vbus-) ÷ 2, the aver­age of the inverter’s bus­es. So for the­se volt­age tim­ing dia­grams, you should pic­ture it from the motor’s per­spec­tive with zero volts float­ing at half bus volt­age.

Assum­ing the rotor is spin­ning at con­stant speed, the zero-cross occurs halfway in time through each step. Given the dura­tion (Tzero-cross in the tim­ing dia­gram) between the pre­vi­ous com­mu­ta­tion and the zero-cross, the firmware extrap­o­lates the time it takes to rotate to the step’s full 60°. It sched­ules the next com­mu­ta­tion for that time, which the­o­ret­i­cal­ly is Tzero-cross from when zero-cross hap­pened.

Commutation timing advance diagram
Six-step sen­sor­less zero-cross detec­tion tim­ing26

How­ev­er, “com­mu­ta­tion” from the point of view of the motor con­troller is sim­ply the volt­age applied to the motor. It doesn’t reflect the cur­rent run­ning through the motor, which can be delayed sig­nif­i­cant­ly by the phase wind­ings’ induc­tance. So like most sen­sor­less firmwares, SimonK pro­vides a tim­ing advance option. It sched­ules com­mu­ta­tion events to occur ahead of reach­ing the 60° rota­tion mark, all the way up to advanc­ing to the next step imme­di­ate­ly after detect­ing zero-cross at the 30° rota­tion mark7. The MOTOR_ADVANCE option express­es the num­ber of degrees by which to advance (i.e. to sub­tract from the ide­al 60° step dura­tion), cor­re­spond­ing to the θadvance para­me­ter in the tim­ing dia­gram.

More­over, there’s yet anoth­er option, TIMING_OFFSET, that express­es the microsec­onds by which to advance the next com­mu­ta­tion. As you might imag­ine, a fixed amount of advance time rep­re­sents a greater frac­tion of a cycle as speed increas­es (and cycle times go down), cre­at­ing a greater effec­tive phase advance. This set­ting cor­re­sponds to the Toff­set para­me­ter in the tim­ing dia­gram.

Commutation advance

So, this option in effect cre­ates vari­able tim­ing that com­mands a more aggres­sive tim­ing with increas­ing speed. There’s even a fan-made cal­cu­la­tor to com­pute how much tim­ing advance you get at dif­fer­ent speeds. In my videos, I was run­ning 2° of MOTOR_ADVANCE and 37 µs of TIMING_OFFSET that I found to hit a hap­py local min­i­ma for low-throt­tle cur­rent draw.

Other tweaks

SimonK has a huge num­ber of con­fig­u­ra­tion options, with­out much orga­ni­za­tion between board con­fig­u­ra­tion, con­troller func­tion­al­i­ty, and user pref­er­ence cus­tomiza­tion.

  • Input range: STOP_RC_PULS and FULL_RC_PULS rep­re­sent the range of pulse widths to use as throt­tle input. With RC_PULS_REVERSE, they are actu­al­ly max speeds at oppo­site polar­i­ties, with a zero speed input at their aver­age. SimonK firmware can also be “cal­i­brat­ed” to store the­se end­points in non-volatile mem­o­ry (the AVR’s EEPROM). Also of note are lim­its for too-short and too-long puls­es that should be reject­ed: MIN_RC_PULS and MAX_RC_PULS. Pulse widths that fall out­side of the [STOP_RC_PULS, FULL_RC_PULS] range but fall with­in [MIN_RC_PULS, MAX_RC_PULS] are clamped to valid pow­er val­ues. For the tests above, I set my lim­its to [1100 µs, 1900 µs].
  • Dead­band: with RC_PULS_REVERSE, the con­troller needs a region in the cen­ter of the input range that rep­re­sents a “zero speed” com­mand. Due to tim­ing vari­a­tions in R/C sys­tems (whose trans­mit­ters also have non-neg­li­gi­ble slop in their con­trol sticks) and even micro­con­trollers, it’s dif­fi­cult send a pulse that is guar­an­teed to be received as a cer­tain width by the ESC. I set my RCP_DEADBAND to be 20 µs on either side of the cen­ter of my input range (1500 µs).
  • PWM fre­quen­cy: the PWM gen­er­a­tion in the SimonK code is done by load­ing the dura­tion of on and off inter­vals into a timer and wait­ing for its over­flow inter­rupt, so the result­ing fre­quen­cy isn’t exact (and prob­a­bly has some jit­ter). How­ev­er, it’s rough­ly a touch less than F_CPU / POWER_RANGE. My 16 MHz board with a POWER_RANGE of 856 was then run­ning at some­thing like 18 kHz, which is cor­rob­o­rat­ed by oscil­lo­scope shots.
  • Min­i­mum duty cycle: once the motor is run­ning, MIN_DUTY is the min­i­mum time in each PWM cycle that the invert­er is excit­ing the active phas­es. This is lim­it­ed by how quick­ly the low-side FETs can turn on then off (i.e. apply torque) and by how lit­tle aver­age volt­age will spin the motor quick­ly enough to gen­er­ate a usable BEMF sig­nal. With the aggres­sive default tim­ing advance of 18° and a default min­i­mum duty cycle of 6.5%, the min­i­mum no-load speed of this ESC/motor com­bi­na­tion was unrea­son­ably high. More­over, for human con­trol it’s kind of unex­pect­ed that the effec­tive com­mand­ed throt­tle should jump from 0 to 6.5% at a few per­cent stick posi­tion.

There are more options relat­ed to motor start behav­ior (on its own a broad top­ic) and I want to explore them in greater depth before offer­ing remarks.

What’s with the assembly code?

The­se days it’s pret­ty rare that a wide­ly used open source project is writ­ten in some computer’s assem­bly lan­guage. The code is basi­cal­ly unread­able to even most electrical/software engi­neers. Writ­ing assem­bly requires a lot of tedious busy work like reg­is­ter man­age­ment and call vari­able pass­ing, so a lot of func­tion­al­i­ty is hid­den behind ver­bose “boil­er­plate” code for say, sub­tract­ing 24-bit num­bers.

On the oth­er hand, given that the code is whol­ly opti­mized for a sin­gle (very lim­it­ed) micro­con­troller run­ning on a nar­row fam­i­ly of ESC boards, assem­bly makes sense. Real­ly, the tiny code space avail­able on the micro­con­troller and the ver­bosi­ty of AVR’s RISC instruc­tion set assem­bly puts a soft lim­it on how com­plex the code can get. To me, that’s a bless­ing. As a result, the com­plex­i­ty of func­tion­al­i­ty in the firmware is fair­ly man­age­able, even if writ­ing and debug­ging new fea­tures might be dif­fi­cult with­out a lot of under­damped head-desk inter­ac­tion.

Next: How does this even work?

Now that I’ve looked whether the firmware/controller com­bi­na­tion works, I want­ed to dig into how it works.

The most press­ing ques­tion for me is, how do CCCs spin motors with such min­i­mal micro­con­troller hard­ware? How does it, run­ning SimonK or not, per­form all the sen­sor­less motor con­trol tasks like detect BEMF zero-cross­ing and switch shoot-through unpro­tect­ed invert­ers with­out explod­ing them?

CCC phases with virtual


  1. Every­where else, it means a pro­gram that reads and loads the code to boot, not a pro­gram that writes soft­ware to stor­age. []
  2. Base image from Atmel Appli­ca­tion Note AVR444. [] [] [] [] [] []
  3. Remem­ber, one phase is left undriven, with its high- and low-side legs both off. Also, the oppos­ing high- and low-side legs in each phase can’t both be on or the bus would short through them. []
  4. This only occurs when the motor spins faster than the bus volt­age can dri­ve it, so it is not a par­tic­u­lar­ly use­ful mode of oper­a­tion. []
  5. i.e. When speed is close to zero and BEMF is low in ampli­tude to being unde­tectable. []
  6. Dia­gram is intend­ed to be gener­ic to all six-step sen­sor­less con­trollers, so it gloss­es over some SimonK imple­men­ta­tion details like when the timer real­ly resets its coun­ter. []
  7. You might note that since “com­mu­ta­tion tim­ing” is a delay from the 30° point, zero-cross detec­tion-based con­trollers can’t advance tim­ing more aggres­sive­ly than (60° – 30°) = 30° ahead of nor­mal. This lim­i­ta­tion is not usu­al­ly a prob­lem. []