Grafito CANStepper

This is the full upload procedure for a CANStepper board. Pick one sketch per board. Do not mix GCSP and CANopen on the same CAN bus — the ID maps collide.

SketchVersionWhen to use
GrafitoCANStepper_C3GCSP 1.12Python (grafito-canstepper), G-code, Test Station
GrafitoCANStepper_C3_CANopenCANopen 2.1PLC that imports an EDS / DCF
CANStepper_WiFiPortaldemoPhone browser bench UI only — Wi‑Fi portal

Downloads: Firmware. Source: github.com/Grafito-Innovations/grafito-canstepper.

1. Power and USB (do this first)

USB-C on this board is data only. It does not power the ESP32 for programming.

  1. Apply Vin 5–24 V (typically 24 V) to the power / CAN connector.
  2. Then plug USB-C into the host.
  3. Keep Vin connected for the whole compile + upload. If Vin drops, the port disappears and the flash fails.

Do not hold a HOME switch closed at power-on. GPIO8 is a strapping pin: if it is held LOW at reset, the C3 can enter download boot and look “dead”. Leave HOME open (pin HIGH) until the board has booted. Details: Hardware → IO8.

2. Host tools (once per computer)

Option A — Arduino IDE 2 (GUI)

  1. Install Arduino IDE 2.

  2. File → Preferences → Additional boards manager URLs, add:

    https://espressif.github.io/arduino-esp32/package_esp32_index.json
  3. Boards Manager: install esp32 by Espressif Systems.

  4. Library Manager: install

    • FastAccelStepper (gin66)
    • TMC2209 (janelia-arduino / Peter Polidoro)

Option B — arduino-cli

# Linux / macOS example. Adjust the install path if needed.
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
export PATH="$HOME/bin:$PATH"

arduino-cli config init
arduino-cli config add board_manager.additional_urls \
  https://espressif.github.io/arduino-esp32/package_esp32_index.json
arduino-cli core update-index
arduino-cli core install esp32:esp32
arduino-cli lib install FastAccelStepper
arduino-cli lib install TMC2209

On Debian/Ubuntu, add your user to dialout (log out and back in once):

sudo usermod -aG dialout "$USER"

3. Board settings (both IDE and CLI)

SettingValue
BoardESP32C3 Dev Module
USB CDC On BootEnabled
Upload Speed921600 (drop to 115200 if uploads flake)
Flash Size4 MB (default)
PortLinux /dev/ttyACM0, macOS /dev/cu.usbmodem*, Windows COMx

Arduino IDE: Tools → Board → esp32 → ESP32C3 Dev Module, then Tools → USB CDC On Boot → Enabled, then Tools → Port.

FQBN used by arduino-cli:

esp32:esp32:esp32c3:CDCOnBoot=cdc

Find the port after Vin + USB are connected:

# Linux
ls /dev/ttyACM* /dev/ttyUSB*

# macOS
ls /dev/cu.usbmodem*

# Windows (PowerShell)
Get-CimInstance Win32_SerialPort | Select-Object DeviceID, Name

If two ACM devices appear, pick the CDC serial port (the one that shows the boot banner at 115200). Opening that port resets the ESP32-C3 — wait for the banner before talking to the board.

4. Flash GCSP 1.12 (Python / Test Station)

Arduino requires the folder name to match the .ino name:

GrafitoCANStepper_C3/
  GrafitoCANStepper_C3.ino

Download GrafitoCANStepper_C3.ino into that folder, or clone the repo and use firmware/GrafitoCANStepper_C3/.

Arduino IDE

  1. File → Open the .ino.
  2. Confirm board / CDC / port from the table above.
  3. Click Upload (right arrow). Wait until you see “Hard resetting via RTS pin…”.
  4. Tools → Serial Monitor, 115200 baud.

arduino-cli

From the repo root (or pass the sketch folder you downloaded):

arduino-cli compile --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc \
  firmware/GrafitoCANStepper_C3
arduino-cli compile --upload -p /dev/ttyACM0 \
  --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc \
  firmware/GrafitoCANStepper_C3

Windows: replace -p /dev/ttyACM0 with -p COM5 (your port).

Healthy GCSP banner

# GrafitoCANStepper fw 1.12 proto 1
# HOME pin GPIO8 INPUT_PULLUP raw=HIGH (strapping: keep HIGH at power-on)
# HOME: INPUT_PULLUP + endstop enable=1 active_high=1 action=stop (fw 1.12)
# POWER: enable_on_boot=0 hold<=5 run<=40 standstill=freewheel (fw 1.9)
# MT6701 SSI mode=3 encoder-loss-filter=25ms
# CAN started (1 Mbps)

Motors stay off until the host calls enable() (fw ≥1.9). Next step: Quickstart or the Test Station.

GCSP node ID is stored in NVS and survives a reflash. Default is 1. Change it from Python (node.set_node_id(n) then save_config()), then power-cycle. Do this before putting two boards on one CAN bus.

5. Flash CANopen 2.1 (PLC)

You must flash the folder, not a lone .ino. The sketch includes canopen_stack.h.

GrafitoCANStepper_C3_CANopen/
  GrafitoCANStepper_C3_CANopen.ino
  canopen_stack.h
  GrafitoCANStepper.eds          # PLC import (not compiled)
  GrafitoCANStepper_Node1.dcf
  GrafitoCANStepper_Node2.dcf

Download both the .ino and canopen_stack.h into the same folder. EDS / DCF: CANopen page.

Same board settings as GCSP (ESP32C3 Dev Module, USB CDC On Boot Enabled, same two libraries).

Factory node 1 (default)

arduino-cli compile --upload -p /dev/ttyACM0 \
  --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc \
  firmware/GrafitoCANStepper_C3_CANopen

Heartbeat COB-ID is 0x701. Import GrafitoCANStepper.eds, then GrafitoCANStepper_Node1.dcf if the PLC wants a commissioned instance.

Factory node 2 (customer PLC pack)

If the PLC imports GrafitoCANStepper_Node2.dcf, the board must be node 2. Heartbeat 0x702, SDO 0x602 / 0x582, RPDO1 0x202, TPDO1 0x182.

arduino-cli:

arduino-cli compile --upload -p /dev/ttyACM0 \
  --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc \
  --build-property "compiler.cpp.extra_flags=-DCO_FACTORY_NODE_ID=2" \
  firmware/GrafitoCANStepper_C3_CANopen

Arduino IDE: at the top of GrafitoCANStepper_C3_CANopen.ino (before the #ifndef CO_FACTORY_NODE_ID block), add:

#define CO_FACTORY_NODE_ID 2

Then Upload. Revert that line before flashing a node-1 board.

Healthy CANopen banner (node 2)

# GrafitoCANStepper CANopen fw 2.1 CiA402
702 0 00
# CAN started (1000000 bit/s) node 2
702 0 7F

Opening the USB serial monitor resets the C3. Wait for 7F (pre-operational heartbeat) before the PLC starts SDOs.

CANopen NVS namespace is co402. It does not inherit a GCSP node ID. After a first flash, if NVS already stored a different ID, write object 0x2000 = desired ID, 0x2008 = 1 (save), then reset.

PLC import: delete any older 2.0 EDS (revision 0x00020000), then import the 2.1 GrafitoCANStepper.eds (FileRevision 2, revision 0x00020100) and the matching Node DCF. Full sequence: CANopen / CiA 402.

6. Confirm the flash

You flashedSerial (115200)Host check
GCSP 1.12fw 1.12 proto 1pip install -U grafito-canstepper then bus.discover() → {1: '1.12'}
CANopen 2.1 node 1CANopen fw 2.1 and node 1Heartbeat 701 0 7F. Python discover() is empty (wrong protocol)
CANopen 2.1 node 2node 2Heartbeat 702 0 7F

Empty discover() after a CANopen flash is expected. Re-flash GCSP if you need Python again.

7. If upload fails

SymptomFix
Port missing / board not foundVin first, then USB. Close Serial Monitor, Test Station, and other scripts.
Failed to connect to ESP32: No serial dataCDC On Boot was Disabled on the last flash, or GPIO8 held LOW at reset. Release HOME, hold BOOT, tap RESET, retry upload, then release BOOT.
Upload starts then stallsDrop upload speed to 115200. Use a short USB data cable (not charge-only).
Linux Permission deniedsudo usermod -aG dialout $USER and re-login.
Banner is CANopen but you wanted PythonYou flashed the PLC sketch. Flash GrafitoCANStepper_C3.
Two boards, CAN silent / collisionsBoth still node 1. Set unique IDs before joining the bus.
PLC talks, motor never enablesEnable 6 → 7 → 15. If HOME is already active, set 0x200C = 0.

More symptoms: Troubleshooting.

On this page