Projects‎ > ‎

Scorpion XL Custom Firmware

This is just a placeholder for some ideas percolating in my brain.  In fact, it gets more and more disorganized as I go through this, so if you're looking for coherent information, it ain't here.  Once I get things figured out I'll re-organize into a tutorial.

For (so far) all of my 3-pound combat robots -- and most of those my students are building -- we're using the Scorpion XL speed controller.  They've served us well.

It turns out these use an ATmega168 microprocessor, meaning they're in the same architecture family as the Arduino microcontroller and should be programmable by the same tools.  So here's my thinking:
  1. Save the proprietary Scorpion XL firmware on my computer, in case something goes wrong.  The avrdude utility (which can be found in the \hardware\tools\avr\bin directory of an Arduino installation) can do this.
  2. Figure out how to upload custom firmware on it.  The Tx/Rx pins, as well as the ICSP pins, are exposed on the board, so this shouldn't be a huge problem.  It probably won't have an Arduino-style bootloader on it, however, so I'll likely need something like the Pololu USB AVR Programmer. (Apparently the UsbTiny programmer has issues with Windows 7.)
  3. Determine the mapping of solder points, header pins, and from-the-radio-receiver signal (yellow) wires to Arduino pins (or ATmega168 pins, which have a different name).
  4. Use the XL as both a speed controller and a robot brain for (semi-)autonomous tasks.  At the least, I should be able to 
    1. communicate with I2C devices or, alternately, 
    2. with analog sensors, since the I2c pins double as analog inputs,
    3.  and/or TTL serial devices (through the Tx/Rx pins)
    4. and/or "Arduino" pins 10, 11, 12, 13 (these are the ICSP pins)
    5. change the speed-response curve (XL only allows linear and exponential in stock firmware)
    6. monkey around with controlled braking vs. free-speed braking (?)
I'm curious if any of the Scorpion's jumper pins are just exposed digital I/O pins from the ATmega168.

Useful modifications

  • Connect an Xbee directly to the Scorpion for a custom Xbee-based radio control scheme (using the Tx/Rx pins).  This would save the weight and hassle of using an Arduino Nano or Mini on the 'bot just to run the Xbee.
  • If enough analog inputs are exposed, use them to monitor LiPo battery voltage through the balance connector.  (Requires one analog input per LiPo cell, as each input measures from 0V to +5V.)
  • Control an LED light show.  For bling.
  • A quick look at the on-board LEDs suggests they're probably programmable...and may affect current/voltage on other pins depending on how they're connected.  Be cautious!

Thoughts on pin-outs

What I can see:

  • 6 pins: ICSP header ("Arduino" pins 10-13, plus a power (+5?) and ground).  For purposes of orienting the AVR programmer cable, VDD is upper-left, GND is upper-right.  Red conductor should be to the left when connected to Scorpion)
  • 8 7 pins: Jumper header (note: the upper-left jumper header pin is connected to the upper-left ICSP header pin).  3 of these are probably either ground or power as they are 1/2 of a 2-pin jumper pair (my guess is power -- that way the ATmega168's internal pull-up resistors are used, eliminating the need for on-board resistors).
  • 2 pins: Tx/Rx pins ("Arduino" pins 1 and 0, respectively)
  • 3 pins: signal wires of the FLIP channel servo-connectors
    • the solder point to the immediate left of Tx *seems* to be connected to the FLIP channel signal wire
  • 1 pin: additional solder point immediately beside Rx
  • Many break-out holes for ground and/or power
From the above, I count 14 available pins.


  • motor LEDs are tied to the PWM pins used as enables for the motors (i.e., they don't have a dedicated pin)
  • the overall status LED has its own pin
  • I'm guessing it's using four of these as half-bridges, so 4 pins reserved for the IN inputs and 2 pins to supply PWM to the INH inputs.
At most, I should have 13 pins available, and no more than 4 of them PWM-ready.  So, off-by-one from the visible pin count.  I bet that beside-Rx-solder-point is just a break-out for something else (judging from the traces, I suspect it's a +5v tap).  And we know at least 2 of the available pins (the I2C pins) are analog.

Arduino IDE Modifications

Using a Scorpion XL with Pololu AVR programmer, add the sections below to the boards.txt and programmers.txt files.

In boards.txt: XL (ATmega168, 5v) AVR

# scorpion xl does not have an external clock like Arduino, so
# fuse bits must reflect using the internal 8 MHz oscillator!

# using internal atmega168 oscillator @ 8 MHz

In programmers.txt:


# Orginal from b.cook ... USB AVR Programmer



Commands (Assuming Pololu AVR Programmer)

  • Backup the stock firmware: avrdude -C ../etc/avrdude.conf -p m168 -P COM5 -c avrispv2 -U flash:r:"e:/User Files/Lewis/project ideas/scorpion xl reprogram/factorycode.bin":r
    • -C ../etc/avrdude.conf (I'm running this from the Arduino-installed AVR tools directory and it needs to know the location of the conf file)
    • -p m168 (specifies ATmega168)
    • -P COM5 (the COM port my AVR programmer is using)
    • -c avrispv2 (this is the programmer-id for the Pololu AVR Programmer)
    • -U "...stuff here..." says read from the target device's flash memory and save to a local file
  • Restore the stock firmware: avrdude -C ../etc/avrdude.conf -p m168 -P COM3 -c avrispv2 -U flash:w:file.bin:r
[My "good" scorpion and the "broken" one from work have identical firmwares.]

Verbose output (stock firmware)
  • D:\arduino-1.0\hardware\tools\avr\bin>avrdude -C ../etc/avrdude.conf -p m168 -P COM5 -c avrispv2 -v

avrdude: Version 5.11, compiled on Sep  2 2011 at 19:38:36
         Copyright (c) 2000-2005 Brian Dean,
         Copyright (c) 2007-2009 Joerg Wunsch

         System wide configuration file is "../etc/avrdude.conf"

         Using Port                    : COM5
         Using Programmer              : avrispv2
         AVR Part                      : ATMEGA168
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no        512    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     16384  128    128  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : STK500V2
         Description     : Atmel AVR ISP V2
         Programmer Model: STK500
         Hardware Version: 15
         Firmware Version Master : 2.10
         Topcard         : Unknown
         Vtarget         : 4.6 V
         SCK period      : 3.3 us
         Varef           : 0.0 V
         Oscillator      : 3.686 MHz

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e9406
avrdude: safemode: lfuse reads as E2
avrdude: safemode: hfuse reads as DD
avrdude: safemode: efuse reads as 7

avrdude: safemode: lfuse reads as E2
avrdude: safemode: hfuse reads as DD
avrdude: safemode: efuse reads as 7
avrdude: safemode: Fuses OK

avrdude done.  Thank you.

Fuse Setting, deconstructed

Note that a "1" means "not programmed" and a "0" means "programmed"
  • From the low fuse
    • CDIV9=1
    • CKOUT=1
    • SUT1=1, SUT0=0
    • CKSEL3=0, CKSEL2=0, CKSEL1=1, CKSEL0=0 (8 MHz internal clock used)
  • From the high fuse
    • RSTDISBL=1 (reset on PINC6 is enabled)
    • DWEN=1
    • SPIEN=0 (SPI pins are enabled  -- we know these are exposed on the board because we can connect an AVR programmer)
    • WTON=1
    • EESAVE=1
    • BODLEVEL2=1, BODLEVEL1=0, BODLEVEL0=1 (brownout detection at Vcc=2.7 V) 
  • Extended fuse
    • BOOTSZ1=1, BOTTSZ0=1
    • BOOTRST=1


  • (Convert .bin to .atmel_generic format using the srec_cat command): srec_cat scorpionxl-flash-factory.bin -binary -Output scorpionxl-flash-factory.atmel_generic
  • (*Potential* disassembly -- this is a "forced" disassembly from the .bin file, meaning some data was probably mis-interpreted as asm): avr-objdump -D --target=binary --architecture=avr scorpionxl-flash-factory.bin > flash-factory.avr.asm
    • First instruction is a jumpt to 0x68, which appears to be a valid instruction.  All instructions between 0x0 and 0x68 are alternating pairs of RETI and NOP; according to the datasheet, the first 0x32 of these are supposed to be interrupt vectors, so all seems well (with just some extra space for good measure?)

Digging Through ASM to Find Pin References

ATmega168 pins are organized into 8-bit registers called ports such that one port can store the I/O bits for up to 8 pins (one pin per bit).  For example, Port B (PB7:0) contains eight general-purpose I/O pins.  I'm searching through the ASM to find references to the memory addresses which map to ports (hacked up a Ruby script to do the job):

 PortDDR AddressDDR values written PORT addressPORT values written Analysis (corresponding Arduino pins shown in parentheses) Notes
 A      Not relevant?
 B 0x04 (0x24)*  41 = 00101001b

 0x05 (0x25) 17 = 00010001b
 64 = 01000000b
 16 = 00010000b
 32 = 00100000b
  1 = 00000001b
  2 = 00000010b
128 = 10000000b

  • PORTB5 (13/SCK)
  • PORTB3 (11/PWM/MOSI)
  • PORTB0 (8)
Pullup-enabled inputs:
  • PORTB7 (crystal oscillator)
  • PORTB6 (crystall oscillator)
  • PORTB4 (12/MISO)
  • PORTB1 (9/PWM)
Potential inputs:
  • PORTB2 (10/PWM/SS)
 PORTB7 and PORTB6 might be usable as I/O pins since the Scorpion XL does not use an external clock.  Evidence is mounting that yes, PB7 and PB6 are available as I/O pins:
1) we're using the internal oscillator
2) as best I can tell, ASSR is 0x00, which means these pins likely are not configured for TOSCx.
 C 0x07 (0x27)  12 = 00001100b 0x08 (0x28)  0 = 00000000b
  8 = 00001000b
  4 = 00000100b
  • PORTC3 (A3)
  • PORTC2 (A2)
Pullup-enabled inputs:
  • PORTC5 (A5/SCL)
  • PORTC4 (A4/SDA)
  • PORTC1 (A1)
  • PORTC0 (A0)
 High bit (PINC7) is unused (maybe?).  PINC6 will be a RESET pin if the RSTDISBL fuse is unset, which it is, according to avrdude.
 D 0x0A
 104 = 01101000b 0x0B
 22 = 00010110b
  2 = 00000010b
  • PORTD6 (6/PWM)
  • PORTD5 (5/PWM)
  • PORTD3 (3/PWM)
Pullup-enabled inputs:
  • PORTD4 (4)
  • PORTD2 (2)
  • PORTD1 (1/Tx)
Potential inputs:
  • PORTD7 (7)
  • PORTD0 (0/Rx)
*The first value is used when accessing the register directly (IN, OUT, SBI, CBI instructions); the parenthetical value is if accessed as a direct SRAM memory location (ST, LD instructions).

On an I/O pin port, the following rules apply:
  • DDR bit for that pin = 1 implies the pin is output; input otherwise
  • PORT bit is the logic state of the pin; writing a 1 to it when it is an input, however, will set the pull-up resistor (see the messiness that was pre-Arduino 1.0 and setting the pullups)
In interpreting the above table, if I found a 1 in a DDR register, I call that an output.  If I find a 1 in a PORT register that is not already and output, I call that an input with the pullup resistor enabled.  Anything else is marked as a potential input, i.e., it is definitely not an output but could simply be an unconnected input.

Scanning through the code I found writes to the following PWM-configuration registers:
 Register Relevant Pin(s) Found valuesNotes
 0x24 [port address] (TCCR0A)OC0A/PORTD6 (Arduino 6)
OC0B/PORTD5 (Arduino 5)
 241 = 11110001b 
 0x25 [port address] (TCCR0B) see above 0 both 0x24 and 0x25 required to configure this PWM
 0xB0 [sram address] (TCCR2A)OC2A/PORTB3 (Arduino 11)
OC2B/PORTD3 (Arduino 3)
 0xB1 [sram address] (TCCR2B) see above2 = 00000010b both 0xB0 and 0xB1 required to configure this PWM

I'm going to make a guess that either of OC0A or OC0B is one motor-enable output and either of OC2A or OC2B is the other.  Reasoning: Take the 0x24 register as an example.  What we know is that one or both of the PWM outputs was maybe configured, but we don't know if it's both or either specific one.  The same goes for the 0xB0 register.  Since we only have two motors, best guess is each register is only configuring one of its associated PWM pins.

Now, try to resolve that with what we know about outputs (two tables back)...and OUCH:  all four of the PWM pins in question are configured as outputs.  Some of them act as ICSP pins -- will the presence of an ICSP signal automatically override the PWM functions or is software required to differentiate?

After adding more support for arithmetic instructions, I got 241 written to 0x24 and 0 to 0x25.  According to the chip specs, this says Arduino pins 5 and 6 are definitely set for PWM.  Gonna make a big guess those are the motor enable outputs. Revised guess: 6 may be a PWM enable, but I'm thinking 5 may be an INH for the right motor. Updated Revised Guess: But what if all four INH inputs are PWM (which would allow LED brightness based on speed) and the IN inputs are binary????!?!?!?  Yet another update: yes, the motor LEDs have brightness based on speed; I checked on my functional 'bot.

 Board Feature    ATmega168 pin
 Arduino pin Tested Reasoning Notes
 Left Motor INH (shared by both half-bridges, receives PWM)  5, 6, 3
 tentative; needs motor tests Based on constant-propagation analysis of stock binary

motors_probe.ino suggests 3 (so far the motor LEDs respond to this pin)
 Probably 3, since it is a PWM and caused a motor LED to shine.
 Left Motor Forward NH  11 see above motors_probe.ino suggests 11 (so far the motor LEDs respond to this pin)
 Left Motor Reverse NH 11 see above see above
 Left Motor LED  3 yes tested with status_led_probe.ino HIGH on 3 produced red; LOW turned it off but did not produce green.  Could be a separate pin or connected to any of the Left Motor signal pins.
 Right Motor INH (shared by both half-bridges, receives PWM)  5, 6, 3
  tentative; needs motor tests Based on constant-propagation analysis of stock binary.

motors_probe.ino suggests 5 (so far the motor LEDs respond to this pin)
 Probably 5, since it is a PWM and caused a motor LED to shine.

 Right Motor Forward IN  6see above motors_probe.ino suggests 6 (so far the motor LEDs respond to this pin)
 Right Motor Reverse IN 36 see abovesee above
 Right Motor LED  5 yes tested with status_led_probe.ino HIGH on 5 produced red; LOW turned it off but did not produce green.  Could be a separate pin or connected to any of the Right Motor signal pins.
 Status LED  8 yes tested with status_led_probe.ino logic LOW turns status LED on
 Tx Solder Point/left 1/Tx
 yes PCB label, product info, tested with a terminalNote that BOTH microcontroller pins are connected to this same physical pin.  Meaning one must be set to INPUT (high-Z) to use the other.
 Tx Solder Point/right +5v +5v yes tested w/ multimeter 
 Rx Solder Point/left  Is NOT pin 0  tested with pin0_probe.ino Needs testing to ensure it is the hardware Rx
 Rx Solder Point/right A4/18/SDA
 yestested pin 18 with exposed_pins_probe.ino
tested pin 0 i/o with pin0_probe.ino
tested Rx with tx_rx_probe.ino
registered as a pullup-enabled input in the suspected list.  Discovered somewhat by accident; I tested it on a whim.

Dude, two chip-pins on the same PCB pins! Meaning one must be set to INPUT (high-Z) to use the other.
 RIGHT Channel Signal Wire  2yes tested with exposed_pins_probe.ino  registered as a pullup-enabled input in the suspected list.
 LEFT Channel Signal Wire  4 yestested with exposed_pins_probe.ino  registered as a pullup-enabled input in the suspected list.
 FLIP Channel Yellow Wire  1/Tx
 yes  Connected to Tx Solder Point/left (multimeter)May also be tied to A5/SCL??!?! (per trace examination)
 FLIP Channel Red Wire  is NOT pin 0  Connected to Rx Solder Point/right (multimeter)I learned on a previous 'bot build that the FLIP channel can not supply BEC -- I'm betting that's because the red wire is tied to one of the serial pins instead of power.
 ENC/00 pin*  +5v yes tested on multimeter.  Has continuity with output leg of voltage regulator.
 ENC/01 pin*     Not on suspected inputs list.
 ENC/02 pin*     Not on suspected inputs list.
 ENC/03 pin*     Not on suspected inputs list.
 ENC/10 pin*  +5vyes tested on multimeter.  Has continuity with output leg of voltage regulator. 
 ENC/11 pin*  9 yes tested with exposed_pins_probe.ino registered as a pullup-enabled input in the suspected list
 ENC/12 pin*     Not on suspected inputs list.
 ENC/13 pin*     Not on suspected inputs list.
 ISP/00 pin**+5v+5vyestested w/ multimeter All ISP pins tested by virtue of successful communication over an AVR programming cable.
 ISP/01 pin** 11/MOSIyesbased on ISP header orientation 
 ISP/02 pin**GNDGND yes tested w/ multimeter  
 ISP/10 pin** 12/MISOyesbased on ISP header orientation 
 ISP/11 pin** 13/SCKyesbased on ISP header orientation 
 ISP/12 pin** RSTyesbased on ISP header orientation This is an ISP header, so do not assume the RST is connected to Arduino 10/SS.
 Current sensing     per product info; could be multiple pins
 Analog voltage feedback input     multiple inputs, per product info, but unknown how many at this time
* ENC/rc refers to the 4-column-by-2-row pin header labeled "ENC", where r is the row and c is the column (zero-based)
**ISP/rc refers to the 3-column-by-2-row pin header labeled "ISP", where r is the row and c is the column (zero-based)

Half-Bridge Pin Mapping

The ESC has four half-bridges (two per channel), probably from this family of devices.  (Reasoning: he lists the BTN7960B half-bridge on the downloads page as a "key component", though he is not specific as to which device (Scorpion XL, XXL, or OSMC) to which it applies.  Visual inspection of the chips on the board, and tests of certain pins, support that the XL uses this component.

The key pins for the half-bridge are shown below:

Pin descriptions:
  • INH (inhibit): When zero, the half-bridge is "off", regardless of the state of IN.  When one, the half-bridge's state is determined by IN.  This would be connected to a PWM input on the Arduino -- paralleled to the companion half-bridge's INH.  (On the physical device, this is pin 2, second from the left if the small pins are facing down.)
  • IN (input): the input signal for the half-bridge.  When 1, the high-side switch (HSS) is active, otherwise the low-side switch (LSS) is used. In combination with the IN pin on the companion half-bridge, this is used to set the direction of the motor, as well as select between powered braking and free-spin braking.  (pin 3 on the physical device)
  • IS (current sense): TODO (pin 6 on the physical device)
  • OUT: the powered output of the half-bridge, connected directly to the drive motors.  Speed of the motors is controlled by the duty-cycle of the powered output (effectively, OUT is a power-amplified version of the logic-level PWM on the INH pin).  (pins 4 and 8 on the physical device, the latter being the huge tab at the top of the device.)
I'm guessing that the motor LED's are in parallel with the motor power tabs with green oriented one way and red the other...and not driven directly by their own I/O pins.

It is possible to handle the forward, reverse, left turn, and right turn maneuvers with just two bits: one for the left IN's and one for the right IN's, assuming the dual IN's on each motor are the complement of each other.  Since I seem to be running out of output-configured Arduino pins, I'm going to guess that A2 and A3 (or whichever of 3, 5, and 6 is not a PWM channel) is being used for this.

Useful Links

Subpages (1): random