About the project

  1. about this documentation in HTML
  2. License

Development tools

  1. Linux
    1. Step-by-step tutorial development tools
      1. Tools to build the firmware
        1. stm8-binutils-gdb
      2. Tools to flash the firmware
        1. How to erase and unlock protected read memory
      3. Hardware tools to flash and debug the firmware
      4. (optional) Tools do flash and debug the firmware
      5. (optional) Tools to debug using serial port
      6. (optional) Tools to see diffs on the source code
  2. Windows
  3. C library
  4. Other tools
    1. Battery voltage boost step-up converter

Motor controllers

  1. BMSBattery S series
    1. BMSBattery S06S
      1. S06ST (torque sensor version)
      2. S06S-BL (Bluetooth version)
      3. PWM signals
        1. very low speed - 6 steps
        2. low speed up to max speed - sineware
      4. Phase B current signal
      5. Throttle
    2. BMSBattery S12S
      1. Programming header
      2. PWM signal at max speed - sineware
      3. Phase B and motor total current signals
    3. BMSBattery bottle battery controller
    4. LCD control panel
      1. LCD protocol
    5. Bluetooh
      1. DIY Bluetooth module
    6. How to open the controller and solder the programming header
    7. Hardware mods
  2. Other controllers
    1. BMSBattery S06P
      1. various info
        1. 01
        2. 02
    2. Kunteng 18 mosfets motor controller
    3. Lishui motor controllers
      1. LSW-675
        1. Datasheets
        2. PWM signals
    4. JinHui motor controllers
  3. GreenEBikeKit


  1. BMSBattery Q75
  2. BMSBattery Q85
  3. BMSBattery Q100
  4. BMSBattery Q100C

Torque sensors

  1. BMSBattery torque sensor

Datasheets and application notes

  1. STM8S105C6T6
    1. Interrupts

Motor control

  1. Torque speed
  2. Motor control scheme of S06S controller
  3. BLDC 6 steps
  4. PWM schemes
    1. So, Which PWM Technique is Best? (Part 1)
    2. So, Which PWM Technique is Best? (Part 2)
    3. So, Which PWM Technique is Best? (Part 3)
    4. So, Which PWM Technique is Best? (Part 4)
    5. So, Which PWM Technique is Best? (Part 5)
    6. So, Which PWM Technique is Best? (Part 6)
    7. So, Which PWM Technique is Best? (Part 7)
  5. PWM control and Dead Time Insertion
  6. Low inductance motors
  7. Throttle Control Modes
  8. Phase angle FOC
  9. PWM frequency VS motor eRPM
    1. Max motor speed using FOC
    2. Kelly controllers ultra high speed
  10. Sinusoidal Control of BLDCM with Hall Sensors Based
  11. Self-Learn Hall Sensor Calibration Mode
  12. STM8S105 Alternatives
  13. Regeneration
    1. Regen in SimonK firmware


  1. forum messages
    1. 2017.04.25 - Initial forum message
    2. 2017.05.08 - First flash and debug on a dev board
    3. 2017.05.18 - First code flashing and running
    4. 2017.05.20 - more new information
    5. 2017.08.23 - SxxP versus SxxS versus LSW-675
    6. 2017.09.01 - Trying to figure out an algorithm to automatically adjust ui8_position_correction_value
    7. 2017.09.02 - How to do FOC on the BMSBattery S06S/Kunteng STM8 motor controllers
    8. 2017.09.03 - more ideas about zero crossing for FOC
    9. 2017.09.05 - measuring IQ current and manually adjusting position_correction_value
    10. 2017.09.15 - our OpenSource firmware efficiency compared to Lishui 12 FET FOC
    11. 2017.09.19 - measuring motor current
    12. 2017.10.23 - FOC and no FOC comparison
  2. STM8S003 board
  3. 2017.12.01 - Regen ebrake like coast brakes


  1. 2017.05.22 - Hackaday Links: May 21, 2017

Smart BMS with bluetooth

Regen in SimonK firmware

The next article explains a bit how regen works.


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.
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.
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

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.
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.
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.
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.
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.
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.
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.
click meclick me
12345brew install avragit clone tgy/make kda_nfet_ni.hexavrdude -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.
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.
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)

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.
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.
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.
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.
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 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.
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.
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?
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. []