xESC Firmware (VESC based)

June 26, 2026 · View on GitHub

License: GPL v3

This is the firmware for the xESC2 family of motor controllers, based on the open-source VESC firmware by Benjamin Vedder.

xESC-specific features

Hardware variant auto-detection

All xESC2 boards use the same firmware binary (xesc_all_variants). The firmware reads an OTP (One-Time Programmable) identity record from flash at boot and configures itself for the detected hardware — gate driver, current sensing mode, pin assignments, and motor parameters are all selected at runtime.

HardwareHow it's detectedGate driverCurrent sensing
xESC2 mini v1.xNo OTP + no v2 pin strapTMC6200Phase shunts
xESC2 mini v2.xOTP identity recordTMC6200Phase shunts
xESC2 power v2.xOTP identity recordTMC6200Phase shunts
xESC2 liteOTP identity recordDRV8376Low-side shunts

v1.x boards have no OTP and no pin strap. The firmware detects this combination and loads the v1 hardware configuration automatically — no OTP branding required.

v2.x boards carry a pin strap that tells the firmware OTP is required. If OTP is missing or invalid, the firmware will not enable the motor and shows a static red LED.

OTP Branding (xESC2 v2.x series)

v2.x boards ship with a factory-written OTP identity record containing the board type, hardware variant, revision, and the STM32's unique chip ID. The record is cryptographically signed to prevent misconfiguration.

Builder Keys

Builder keys are BLS12-381 private keys — generated once per builder and stored securely (e.g. ~/.config/xesc/keys/builder1.key). Only needed during branding, not for normal operation.

Building the Branding Tool

cd cmd/otp_brand
go build -o otp_brand .

Or use Docker for a fully static binary:

docker build -f cmd/otp_brand/Dockerfile -o out .
# binary lands in out/otp_brand

Usage

# 1. Generate a builder key (once per builder)
./otp_brand --generate-key ~/.config/xesc/keys/builder1.key
# -> ~/.config/xesc/keys/builder1.key      (private key, 32 bytes)
# -> ~/.config/xesc/keys/builder1.key.pub  (public key, 96 bytes hex)

# 2. Sign and flash an OTP identity block (pair 0 by default)
./otp_brand --type mini --variant v2_pwr --hw 2.0.1 \
    --key ~/.config/xesc/keys/builder1.key --flash

# The STM32 UID is read automatically from the connected device.
# To specify it explicitly (e.g. for scripting or when auto-read fails):
./otp_brand --type mini --variant v2_pwr --hw 2.0.1 \
    --key ~/.config/xesc/keys/builder1.key \
    --stm32uid a1b2c3d4e5f6a7b8c9d0e1f2 --flash

# To write to a different pair (e.g. after a previous branding on pair 0):
./otp_brand ... --pair 1 --flash

# 3a. Verify signature directly from the device (ST-Link required)
./otp_brand --verify-device 0 --key ~/.config/xesc/keys/builder1.key.pub
# -> OTP pair 0 - Signature verification: VALID
# -> OTP data: {"type":0,"variant":2,"hw":"2.0.1","serial":1,...}

# 3b. Verify signature from a .bin file
./otp_brand --verify otp_blocks.bin --key ~/.config/xesc/keys/builder1.key
# or with public key only:
./otp_brand --verify-pub otp_blocks.bin --key ~/.config/xesc/keys/builder1.key.pub

# 3c. Read OTP pair and display decoded fields (no signature check)
./otp_brand --read 0

# 4. Dry-run: preview what would be written (including auto-read UID)
./otp_brand --type mini --variant v2_pwr --hw 2.0.1 \
    --key ~/.config/xesc/keys/builder1.key --dry-run

# 5. Offline: generate signed hex for on-device programming
./otp_brand --type mini --variant v2_pwr --hw 2.0.1 \
    --key ~/.config/xesc/keys/builder1.key \
    --stm32uid a1b2c3d4e5f6a7b8c9d0e1f2 --emit-hex \
    | vesc-tool-or-terminal otp_brand 0 <hex>

If --stm32uid is omitted, the tool attempts to read it from the device via ST-Link. This works for all operations that require a connected device (--flash, --read, --verify-device). For offline operations (--emit-hex, --output only) the UID must be passed explicitly. If auto-read fails (no ST-Link connected), the tool exits with a clear error message.

STM32CubeProgrammer discovery order: $ST_PROGRAMMER_PATH/usr/local/STMicroelectronics/.../opt/STMicroelectronics/...$PATH.

FlagValues / Description
--typemini, lite
--variantv1_std, v2_std, v2_pwr
--hw"2.0.1" (MAJOR.MINOR.PATCH)
--keyPrivate key path (32 bytes), or public key for verification
--stm32uidSTM32 UID (24 hex chars); auto-read from device if omitted
--outputOutput .bin path (default: otp_blocks.bin)
--pairOTP block pair to write or read (0–7, default: 0)
--flashFlash signed blocks to device after generation
--dry-runShow what would be done without writing anything
--emit-hexPrint signed block as hex for on-device programming
--verifyVerify BLS signature in a .bin using private key --key
--verify-pubVerify BLS signature in a .bin using public key --key
--verify-deviceVerify BLS signature of OTP pair N directly from device
--readRead OTP pair N from device and display decoded fields
--dump-cOutput C arrays for firmware test_otp_block[]
--dump-pubkeyPrint public key for a private key file
--generate-keyCreate new BLS12-381 key pair at PATH
--serialOverride auto-increment serial number
--forceSkip OTP occupation check

On-device terminal commands

Once firmware is running, two terminal commands are available:

  • otp_info — dump all OTP pairs with CRC validation and show the active block
  • otp_brand <pair> <128-hex-chars> — program a signed block directly (use --emit-hex output from the host tool)

VESC Firmware (upstream)

The sections below are from the upstream VESC firmware README. Build instructions, IDE setup, and flashing methods apply to xESC targets as well — use xesc_all_variants as the target name instead of the VESC examples shown.


Travis CI Status Codacy Badge Contributors Watchers Stars Forks

An open source motor controller firmware.

This is the source code for the VESC DC/BLDC/FOC controller. Read more at https://vesc-project.com/

Supported boards

All of them!

Check the supported boards by typing make

[Firmware]
     fw   - Build firmware for default target
                            supported boards are: 100_250 100_250_no_limits 100_500...

There are also many other options that can be changed in conf_general.h.

Prerequisites

On Ubuntu (Linux)/macOS

  • Tools: git, wget, and make
  • Additional Linux requirements: libgl-dev and libxcb-xinerama0
  • Helpful Ubuntu commands:
sudo apt install git build-essential libgl-dev libxcb-xinerama0 wget git-gui
  • Helpful macOS tools:
brew install stlink
brew install openocd

On Windows

Install Dev environment and build

On Ubuntu (Linux)/MacOS

Open up a terminal

  1. git clone http://github.com/vedderb/bldc.git
  2. cd bldc
  3. Continue with On all platforms

On Windows

  1. Open up a Windows Powershell terminal (Resist the urge to run Powershell as administrator, that will break things)
  2. Type choco install make
  3. git clone http://github.com/vedderb/bldc
  4. cd bldc
  5. Continue with On all platforms

On all platforms

  1. git checkout origin/master
  2. make arm_sdk_install
  3. make <-- Pick out the name of your target device from the supported boards list. For instance, I have a Trampa VESC 100/250, so my target is 100_250
  4. make 100_250 <-- This will build the VESC 100/250 firmware and place it into the bldc/builds/100_250/ directory

Other tools

Linux Optional - Add udev rules to use the stlink v2 programmer without being root

wget vedder.se/Temp/49-stlinkv2.rules
sudo mv 49-stlinkv2.rules /etc/udev/rules.d/
sudo udevadm trigger

IDE

Prerequisites

On macOS/Linux

  • python3, and pip

On Windows

All platforms

  1. pip install aqtinstall
  2. make qt_install
  3. Open Qt Creator IDE installed in tools/Qt/Tools/QtCreator/bin/qtcreator
  4. With Qt Creator, open the vesc firmware Qt Creator project, named vesc.pro. You will find it in Project/Qt Creator/vesc.pro
  5. The IDE is configured by default to build 100_250 firmware, this can be changed in the bottom of the left panel, there you will find all hardware variants supported by VESC

Upload to VESC

  1. Build and flash the bootloader first
  2. Then _flash to the target of your choice. So for instance, for the VESC 100/250:
make 100_250_flash

Method 2 - Upload Firmware via VESC tool through USB

  1. Clone and build the firmware in .bin format as in the above Build instructions

In VESC tool

  1. Connect to the VESC
  2. Navigate to the Firmware tab on the left side menu
  3. Click on Custom file tab
  4. Click on the folder icon to select the built firmware in .bin format (e.g. build/100_250/100_250.bin)
[ Reminder : It is normal to see VESC disconnects during the firmware upload process ]
[ Warning : DO NOT DISCONNECT POWER/USB to VESC during the upload process, or you will risk bricking your VESC ]
[ Warning : ONLY DISCONNECT your VESC 10s after the upload loading bar completed and "FW Upload DONE" ]
  1. Press the upload firmware button (downward arrow) on the bottom right to start upload the selected firmware.
  2. Wait for 10s after the loading bar completed (Warning: unplug sooner will risk bricking your VESC)
  3. The VESC will disconnect itself after new firmware is uploaded.

In case you bricked your VESC

you will need to upload a new working firmware to the VESC.
However, to upload a firmware to a bricked VESC, you have to use a SWD Debugger.

Contribute

Head to the forums to get involved and improve this project. Join the Discord for real-time support and chat

Tags

Every firmware release has a tag. They are created as follows:

git tag -a [version] [commit] -m "VESC Firmware Version [version]"
git push --tags

License

The software is released under the GNU General Public License version 3.0