FalCAN gs_usb firmware

April 28, 2026 · View on GitHub

This is a fork of candleLight_fw with support for RS-485 and RS-422 with the FalCAN Probe board https://github.com/AndersBNielsen/FalCAN

See HW repo for instructions on how to switch between CAN and RS-485-mode.

TODO:

  • Transceiver control in software instead of hardware jumpers
  • RS-485 echo control in software
  • i2c/SPI/GPIO-USB-bridge mode

candleLight_gsusb

Build

This is firmware for certain STM32F042x/STM32F072xB-based USB-CAN adapters, notably:

Of important note is that the common STM32F103 will NOT work with this firmware because its hardware cannot use both USB and CAN simultaneously. Beware also the smaller packages in the F042 series which map a USB and CAN_TX signal on the same pin and are therefore unusable !

This implements the interface of the mainline linux gs_usb kernel module and works out-of-the-box with linux distros packaging this module, e.g. Ubuntu.

Limitations

STM32G0B1-based devices are not yet supported by the mainline firmware. Support for these devices is discussed in https://github.com/candle-usb/candleLight_fw/pull/139 and https://github.com/candle-usb/candleLight_fw/pull/176.

STM32G431-based devices (e.g. CANable-MKS 2.0) are not supported by this project yet.

Currently, the firmware sends back an echo frame to the host when the frame is written to the CAN peripheral, and not when the frame is actually sent successfully on the bus. This affects timestamps, one-shot mode, and other edge cases.

Known issues

Be aware that there is a bug in the gs_usb module in linux<4.5 that can crash the kernel on device removal.

Here is a fixed version that should also work for older kernels: https://github.com/HubertD/socketcan_gs_usb

The Firmware also implements WCID USB descriptors and thus can be used on recent Windows versions without installing a driver.

Building

Building requires arm-none-eabi-gcc toolchain.

macOS (Arm GNU Toolchain)

This repo includes a CMake toolchain file for Arm GNU Toolchain 15.2 rel1: cmake/arm-gnu-toolchain-15.2rel1.cmake.

Install the toolchain

Option A (Arm official installer, recommended for matching CI/toolchain versions):

  • Download and install Arm GNU Toolchain from Arm (the installer typically places it under /Applications/ArmGNUToolchain/<version>/arm-none-eabi/bin).
  • Verify:
/Applications/ArmGNUToolchain/15.2.rel1/arm-none-eabi/bin/arm-none-eabi-gcc --version

Option B (Homebrew):

  • Package names can change over time. The usual workflow is:
brew search arm-none-eabi
brew install arm-none-eabi-gcc

Also install build/flash tools:

brew install cmake dfu-util

The cleanest known-good path on macOS is to use the Arm installer toolchain and pass its bin directory explicitly during configure:

rm -rf build-falcan-armgnu-fresh

cmake -S . -B build-falcan-armgnu-fresh \
  -DCMAKE_TOOLCHAIN_FILE=cmake/arm-gnu-toolchain-15.2rel1.cmake \
  -DARM_GNU_TOOLCHAIN_BIN_DIR=/Applications/ArmGNUToolchain/15.2.rel1/arm-none-eabi/bin

cmake --build build-falcan-armgnu-fresh --target falcan_fw -- -j8

This produces:

  • build-falcan-armgnu-fresh/falcan_fw
  • build-falcan-armgnu-fresh/falcan_fw.bin
  • build-falcan-armgnu-fresh/falcan_fw.dfu

Fresh build (clean build directory)

From the repo root:

rm -rf build-falcan-armgnu-fresh

cmake -S . -B build-falcan-armgnu-fresh \
  -DCMAKE_TOOLCHAIN_FILE=cmake/arm-gnu-toolchain-15.2rel1.cmake \
  -DARM_GNU_TOOLCHAIN_BIN_DIR=/Applications/ArmGNUToolchain/15.2.rel1/arm-none-eabi/bin

# Build one target
cmake --build build-falcan-armgnu-fresh --target falcan_fw -- -j8

# Or build everything
# cmake --build build-falcan-armgnu-fresh -- -j8

If your Arm toolchain is not under /Applications/ArmGNUToolchain/..., pass the bin dir explicitly:

cmake -S . -B build-falcan-armgnu-fresh \
  -DCMAKE_TOOLCHAIN_FILE=cmake/arm-gnu-toolchain-15.2rel1.cmake \
  -DARM_GNU_TOOLCHAIN_BIN_DIR=/path/to/arm-none-eabi/bin

Notes:

  • LTO is intentionally opt-in in this fork: add -DENABLE_LTO=ON at configure time if you want it.
  • The build produces both .bin and .dfu artifacts (in the build directory).
  • If a Homebrew-provided toolchain fails with nano.specs errors, use the Arm installer path shown above.
sudo apt-get install gcc-arm-none-eabi

mkdir build
cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/gcc-arm-none-eabi-8-2019-q3-update.cmake

# or,
# cmake-gui ..
# don't forget to specify the cmake toolchain file before configuring.
#
# compile all targets :

make

# OR, each board target is a cmake option and can be disabled before running 'make';
# OR, compile a single target , e.g.
make cantact_fw

#
# to list possible targets :
make help

macOS flashing quick commands (ROM DFU)

If the device is in STM32 ROM DFU mode (0483:df11):

dfu-util -l
dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D build-falcan-armgnu-fresh/falcan_fw.bin

Or use the generated flash target:

cmake --build build-falcan-armgnu-fresh --target flash-falcan_fw

Download Binaries

Prebuilt binaries can be downloaded by clicking CI. On the workflow overview page, select the latest workflow that ran on master branch. The firmware artifacts can downloaded by clicking them at the bottom of the page.

Flashing

Flashing candleLight on linux: (source: https://cantact.io/cantact/users-guide.html)

  • Flashing requires the dfu-util tool. On Ubuntu, this can be installed with sudo apt install dfu-util.
  • compile as above, or download the current binary release: gsusb_cantact_8b2b2b4.bin
  • If dfu-util fails due to permission issues on Linux, you may need additional udev rules. Consult your distro's documentation and see 70-candle-usb.rules provided here.
  • If compiling with cmake, make flash-<targetname_fw>, e.g. make flash-canable_fw, to invoke dfu-util.

method for reflashing a specific device by serial

  • when multiple devices are connected, dfu-util may be unable to choose which one to flash.
  • Obtain device's serial # by looking at dfu-util -l
  • adapt the following command accordingly : dfu-util -D CORRECT_FIRMWARE.bin -S "serial_number_here", -a 0 -s 0x08000000:leave
  • note, the :leave suffix above may not be supported by older builds of dfu-util and is simply a convenient way to reboot into the normal firmware.

fail-safe method (or if flashing a blank device)

  • Disconnect the USB connector from the CANtact, short the BOOT pins, then reconnect the USB connector. The device should enumerate as "STM32 BOOTLOADER".

  • invoke dfu-util manually with: sudo dfu-util --dfuse-address -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D CORRECT_FIRMWARE.bin where CORRECT_FIRMWARE is the name of the desired .bin.

  • Disconnect the USB connector, un-short the BOOT pins, and reconnect.

Associating persistent device names

With udev on linux, it is possible to assign a device name to a certain serial number (see udev manpages and systemd.link). This can be useful when multiple devices are connected at the same time.

An example configuration :

 $ cat /etc/systemd/network/60-persistent-candev.link
[Match]
Property=ID_MODEL=cannette_gs_usb ID_SERIAL_SHORT="003800254250431420363230"

[Link]
# from systemd.link manpage:
# Note that specifying a name that the kernel might use for another interface (for example "eth0") is dangerous because the name assignment done by udev will race with the assignment done by the kernel, and only one
#   interface may use the name. Depending on the order of operations, either udev or the kernel will win, making the naming unpredictable. It is best to use some different prefix

Name=cannette99

( The serial number can be found with the lsusb utility). After reloading systemd units and resetting this board :

 $ ip a
....
59: cannette99: <NOARP,ECHO> mtu 16 qdisc noop state DOWN group default qlen 10
    link/can
 $

Hacking

Submitting pull requests

  • Each commit must not contain unrelated changes (e.g. functional and whitespace changes)
  • Project must be compilable (with default options) and functional, at each commit.
  • Squash any "WIP" or other temporary commits.
  • Make sure your editor is not messing up whitespace or line-ends.
  • We include both a .editorconfig and uncrustify.cfg which should help with whitespace.

Typical command to run uncrustify on all source files (ignoring HAL and third-party libs): uncrustify -c ./uncrustify.cfg --replace --no-backup $(find include src -name "*.[ch]")

Profiling

Not great on cortex-M0 cores (F042, F072 targets etc) since they lack hardware support (ITM and SWO). However, it's possible to randomly sample the program counter and get some coarse profiling info.

For example, openocd has the profile command (see https://openocd.org/doc/html/General-Commands.html#Misc-Commands), e.g.

profile 5 test.out 0x8000000 0x8100000

(from inside gdb, the command needs to be prefixed with monitor to forward it to openocd, i.e. monitor profile 5 ......

The .out file can then be processed with gprof <firmware_name> -l test.out

  • Cangaroo open source can bus analyzer software
  • Candle.NET .NET wrapper for the candle API