TackleBox is a production-grade dual-mode control stack positioned between Marlin and Klipper.
It must support both operating models at the same time:
- standalone, board-resident control like Marlin
- optional coprocessor-assisted orchestration like Klipper
- a build-once, flash-once board image with post-flash software evolution through stable abstractions
The current SKR 2 STM32F429 work is the first proving ground, not the product boundary. The permanent direction is a portable stack whose board-specific flash image stays thin while higher-level behavior, orchestration, and configuration can evolve independently.
Key reference documents:
CONTRIBUTING.mddocs/ARCHITECTURE.mddocs/REPOSITORY_LAYOUT.mddocs/PORTABILITY.mddocs/QUALITY.mddocs/RELEASE_READINESS.mddocs/FIRST_PUBLIC_PUSH_CHECKLIST.mddocs/STLINK_HOOKUP.mdkeelware/contracts/skr2-f429.mdproducts/skr2-f429/README.mdproducts/skr2-f429/manifest.jsonboatswain/PACKAGE_FORMAT_V1.mdplan/architecture-tacklebox-foundation-1.md
TackleBox is composed of five named layers.
BootAnchorsOptional board bootloaders and recovery environments that add CDC or other field-safe flashing, diagnostics, and recovery flows to boards that do not ship with a sufficient upgrade path.KeelWareThe hardware abstraction and board package layer. This is the board-specific flash image that owns clocks, buses, flash layout, pin roles, boot offsets, and transport wiring.BoatswainThe on-device supervisor/runtime layer. This is the board-resident control plane that executes commands, safety policy, macros, state machines, and updateable logic shipped through the common abstraction layer.SemaphorioThe host and coprocessor API/orchestration layer that talks to TackleBox devices over serial or future transports on Windows, Linux, and macOS.SpyGlassThe operator and observational layer, including dashboards, diagnostics, telemetry capture, and the future off-device or web-served control portal.
This repository currently contains the first operational slice of TackleBox on the BigTreeTech SKR 2 STM32F429VGT6 board.
What exists today:
- a working resident CDC bootloader path for a board that is otherwise awkward to update over USB
- a board-resident firmware shell with runtime configuration, microSD config loading, TMC controls, and safe motion primitives
- host-side flashing, validation, and operator tooling
- host tests, CI, and hardware-validation workflows
What this repository is evolving toward:
BootAnchorsas reusable optional bootloader packagesKeelWareas a stable board package/HAL boundaryBoatswainas an independently updateable device supervisor/runtime contractSemaphorioandSpyGlassas first-class host products rather than ad hoc scripts
The target package skeleton now exists at the repo root in bootanchors/, keelware/, boatswain/, semaphorio/, spyglass/, and products/. Those directories are currently ownership anchors and migration landing zones; the validated implementation still lives in the existing src/, lib/keyswitch_core/, and tools/ paths until compatibility moves are completed.
For host tooling, stable wrapper entrypoints now exist under semaphorio/ and spyglass/, while the currently validated implementations remain in tools/.
- USB CDC telemetry with heartbeat and status reporting
- USB CDC command parsing
- multi-source homing/safety domain model
- backoff and stop control
- runtime remapping and persisted configuration for active board roles
- boot-time configuration source precedence across USB, microSD, flash, and defaults
- CDC bootloader flashing and app handoff for the SKR 2 bring-up target
- host-runnable unit and integration tests for the domain/protocol layer
- host-assisted flash, mode-switch, and validation workflows
- graph-ready safety telemetry fields for force and stop-source reporting
The current Boatswain command surface accepts both plain-text and a few trimmed-down G-code style aliases:
STATUSM114M119CONFIG [key]CFG [key]SET <key> <value>SAVESAVECFGRESETCFGREBOOTHOMEG28SAFETYM122DRIVERTMCIRUN <0-31>IHOLD <0-31>IHOLDDELAY <0-15>SGTHRS <0-255>ENABLEM17DISABLEM18M84HOLD <on|off>MOVEABS <steps>G0 X<mm>G1 X<mm>MOVEREL <steps>JOG <steps>SETPOS <steps>PRESSPOS <steps>CYCLE <count>SIMLOAD <raw>SIMTHRESH <raw>SIMMECH <on|off>SIMSTALL <on|off>SIMCLEARSTOPM112BACKOFFHELP?
STATUS and SAFETY currently share the same structured telemetry payload so host scripts can consume one stable line format while the physical sensor stack is still being wired.
The simulation commands are the current way to validate the load-cell and StallGuard code paths before the load cell is physically attached. They let you drive the safety model over USB and verify state transitions, stop-source selection, and telemetry formatting on the real board.
Current telemetry fields:
diag0: raw DIAG0 input level for the currently configuredpin.diag0rolexstop: raw mechanical stop input level for the currently configuredpin.x_stoprolediag2: raw DIAG2 input level for the currently configuredpin.diag2rolepressed: debounced logical stop state derived from the configuredx_stoppathconf: confirmed/debounced mechanical stop stateload: load-cell trigger flagmech: mechanical fallback trigger flagstall: StallGuard fallback trigger flagsource: last stop source enum (0 none,1 load cell,2 mechanical,3 stall,4 seek-limit fault)force: placeholder raw load-cell reading, currently0until the frontend is wiredhomed: whether the arm has a trusted home/position referencehold: whether the firmware should keep the driver enabled while idlepos: current tracked position in steps relative to hometarget: current move target in stepspress: configured press target used by theCYCLEroutinecycles: remaining routine cyclesdone: completed routine cycles
Driver telemetry:
driver uart=<0|1> irun=<0-31> ihold=<0-31> iholddelay=<0-15> tpowerdown=<0-255> sgthrs=<0-255>
Configuration telemetry:
config loaded=<0|1> dirty=<0|1> reboot=<0|1>config pin.x_step=<Pn> ...config logic.stop_active_high=<0|1> logic.dir_inverted=<0|1> logic.home_towards_positive=<0|1> ...config tmc.irun=<n> ...boot: wait_usb ms=<n>boot: source=<defaults|flash|usb|microsd>
The SAFETY command also emits a simulation line in this format:
sim raw=<n> thresh=<n> load=<0|1> mech=<0|1> stall=<0|1>
That line reports the active simulation state used by the pre-hardware safety workflow.
The current KeelWare plus Boatswain image includes a persisted runtime configuration block stored in a reserved internal flash sector, so the board can be retuned and remapped without rebuilding or reflashing the board image.
What is configurable now:
- all GPIO roles currently used by this firmware:
x_uart,x_dir,x_step,x_enable,x_stop,diag0,diag2,ps_on,safe_power, andled - motion timing values like
step_pulse_us,home_feedrate_mm_per_min,move_feedrate_mm_per_min, and the compatibilitystep_interval_ussetter - indexed channel metadata like labels, enable flags, transport kind, bus index, and transport address
- axis mechanics values like
steps_per_rotation,travel_um_per_rotation,travel_min_um,travel_max_um,travel_limit_um, anddefault_press_umfor the active channel - logic/polarity flags like stop active-high, direction inversion, and whether homing seeks toward the positive or negative coordinate direction
- TMC runtime knobs like
irun,ihold,iholddelay,tpowerdown,sgthrs, anduart_bit_us - persisted simulated load threshold
What still is not firmware-configurable:
- actual supply voltage rails or analog hardware that is not already under software control
- arbitrary alternate peripheral routing beyond simple GPIO role remapping supported by this firmware shell
Workflow:
- Inspect the current desired config with
CONFIG. - Change values with
SET <key> <value>. - Persist them with
SAVE. - Reboot with
REBOOTor power-cycle the board when you changed pins or polarity.
Boot-time source order is now:
- wait for a USB host config session for
BOOT.HOST_WAIT_MS - try microSD config loading
- fall back to saved internal flash config
- fall back to safe built-in defaults
The firmware now includes an SDIO + FatFs microSD path and will read 0:device.cfg when a card is present. Use CONFIG SOURCES to see which source was selected for the current boot and whether USB, microSD card/config, flash, and defaults were available.
Examples:
CONFIG
CONFIG SOURCES
CONFIG CHANNELS
CONFIG CH1.LABEL
SET CHANNEL.ACTIVE 0
SET CHANNEL.LABEL X1
SET CH1.LABEL Y1
SET CH1.TRANSPORT LOCAL_GPIO
SET CHANNEL.TRANSPORT LOCAL_GPIO
SET TMC.IRUN 5
SET TMC.IHOLD 0
SET MOTION.STEP_INTERVAL_US 300
SET MOTION.HOME_FEEDRATE_MM_PER_MIN 600
SET MOTION.MOVE_FEEDRATE_MM_PER_MIN 1200
SET MOTION.SEEK_LIMIT_STEPS 8000
SET AXIS.TRAVEL_MIN_UM 0
SET AXIS.TRAVEL_MAX_UM 17500
SET AXIS.TRAVEL_UM_PER_ROTATION 8000
SET AXIS.TRAVEL_LIMIT_UM 17500
SET LOGIC.ENABLE_ACTIVE_LOW 1
SET LOGIC.HOME_TOWARDS_POSITIVE 1
SET TELEMETRY.HEARTBEAT_INTERVAL_MS 500
SET PIN.X_STEP PE2
SAVE
REBOOT
Supported SET keys:
CHANNEL.COUNT,CHANNEL.ACTIVE,CHANNEL.ENABLED,CHANNEL.LABELCHANNEL.TRANSPORT,CHANNEL.BUS_INDEX,CHANNEL.ADDRESSPIN.X_UART,PIN.X_DIR,PIN.X_STEP,PIN.X_ENABLE,PIN.X_STOPPIN.DIAG0,PIN.DIAG2,PIN.PS_ON,PIN.SAFE_POWER,PIN.LEDLOGIC.STOP_ACTIVE_HIGH,LOGIC.DIR_INVERTED,LOGIC.ENABLE_ACTIVE_LOW,LOGIC.HOME_TOWARDS_POSITIVEBOOT.HOST_WAIT_MSMOTION.STEP_INTERVAL_US,MOTION.HOME_FEEDRATE_MM_PER_MIN,MOTION.MOVE_FEEDRATE_MM_PER_MIN,MOTION.STEP_PULSE_US,MOTION.SEEK_LIMIT_STEPSMOTION.STOP_DEBOUNCE_COUNT,MOTION.BACKOFF_STEPSAXIS.STEPS_PER_ROTATION,AXIS.TRAVEL_UM_PER_ROTATIONAXIS.TRAVEL_MIN_UM,AXIS.TRAVEL_MAX_UM,AXIS.TRAVEL_LIMIT_UM,AXIS.DEFAULT_PRESS_UMTELEMETRY.STATUS_INTERVAL_MS,TELEMETRY.HEARTBEAT_INTERVAL_MSSIM.LOAD_THRESHOLDTMC.ALLOW_UNVERIFIED_MOTIONTMC.IRUN,TMC.IHOLD,TMC.IHOLDDELAY,TMC.TPOWERDOWN,TMC.SGTHRS,TMC.UART_BIT_US
Pin values use the P<port><pin> form, for example PE2 or PC13.
The base firmware now stores an indexed channel array. CHANNEL.ACTIVE selects which channel the current single-axis runtime binds to, and the channel-scoped PIN.*, LOGIC.*, AXIS.*, and TMC.* keys apply to that active channel.
For direct indexed access, CONFIG CHANNELS lists the current channel inventory, CONFIG CH<n>.* inspects channel n without rebinding the runtime, and SET CH<n>.* <value> applies channel-scoped metadata or mechanics changes directly to channel n.
AXIS.TRAVEL_MIN_UM sets the low edge of the current workspace, AXIS.TRAVEL_MAX_UM sets the high edge, and AXIS.TRAVEL_LIMIT_UM remains the total workspace span. MOTION.SEEK_LIMIT_STEPS is kept as a compatibility key, but it now derives and updates that workspace span through the axis mechanics configuration. For new tuning flows, prefer the AXIS.* keys.
CHANNEL.TRANSPORT currently accepts LOCAL_GPIO, REMOTE_BUS, and VIRTUAL. The current runtime can only execute a LOCAL_GPIO active channel; the other transport types exist so the software layer can model future remote MCU and virtual channels without redesigning the config schema again.
For the current LOCAL_GPIO runtime, CHANNEL.ADDRESS also feeds the active channel's TMC UART slave address. That makes it possible to probe TMC2209 addresses 0..3 live over USB without rebuilding the firmware.
A small host-side companion script is available in tools/boot-config-service/. It is an early Semaphorio slice that can watch for the STM32 CDC port, push a device.cfg file over USB immediately after boot, and then send BOOT so the board starts with the host-provided session config.
That lets you keep everyday tuning off the internal flash and only persist settings when you intentionally send SAVE. If no USB host session claims the boot window, the board next checks the onboard microSD card for device.cfg before falling back to flash or defaults.
The current repository layout is transitional. It contains the future TackleBox slices, but some code still carries the original bring-up naming.
src/main.cpp: firmware entrypoint and hardware adaptersrc/app_board.cpp: board GPIO and low-level pin helperssrc/app_runtime_config.cpp: persisted config, boot-source selection, and config telemetrysrc/app_tmc_link.cpp: board-side TMC transport and verificationsrc/bootloader_cdc_main.cpp: currentBootAnchorsCDC recovery shell for the SKR 2src/bootloader_flash.*: bootloader-side flash layout and application handoff helperssrc/boot_mode.*: reset-persistent boot-mode coordination shared between app and bootloadersrc/usb_cdc_bridge.*: USB CDC transport bridgesrc/usbd_cdc_if.*: STM32 USB CDC interface gluelib/keyswitch_core/include/keyswitch_domain.h: currentBoatswaindomain API for homing and motionlib/keyswitch_core/src/keyswitch_domain.cpp: currentBoatswaindomain state machine implementationlib/keyswitch_core/include/keyswitch_protocol.h: current device command parsing APIlib/keyswitch_core/src/keyswitch_protocol.cpp: current device command parsing implementationtools/board-usb.ps1: operator CLI for discovery, mode switching, and direct command executiontools/flash-over-cdc.ps1: SKR 2 bootloader uploader over CDCtools/usb_serial_common.ps1: shared host-side serial helpers used by scripts and teststools/arm-dashboard/: browser-based Web Serial operator UItest/run_host_tests.ps1: host test runnertest/run_ci_checks.ps1: local CI-equivalent validation bundletest/run_bootloader_serial_tests.ps1: live board validation for app and bootloader USB transitionstest/test_domain/: unit tests for homing and motion statetest/test_protocol/: unit tests for command parsingtest/test_integration/: higher-level command-to-domain integration tests
The repo is being prepared in four product phases:
- stabilize the current SKR 2 reference implementation and board workflows
- separate
BootAnchors,KeelWare,Boatswain,Semaphorio, andSpyGlassinto explicit package and repo boundaries - add multi-board descriptors and make board support additive instead of copy-driven
- package releases, docs, and validation artifacts so outside users can consume the project safely
GitHub Actions now runs the same validation spine intended for local use:
- host tests via
test/run_host_tests.ps1 - firmware builds for all declared PlatformIO environments via
test/run_ci_checks.ps1
The workflow lives in .github/workflows/ci.yml.
Embedded firmware build:
Set-Location "c:\git\BTT SKR2 Testing"
& "C:\Users\jd\.platformio\penv\Scripts\platformio.exe" run -e skr2_f429_usbFlash path:
- Build the firmware.
- Copy
.pio\build\skr2_f429_usb\firmware.binto the SKR2 microSD card asfirmware.bin. - Power-cycle the board.
The SKR2 board definitions already support stlink, so an ST-Link V2 can be used for direct SWD flashing and debugger-assisted bring-up.
Before replacing any resident bootloader image, back up the first 32 KiB boot region:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\backup_bootloader.ps1"Restore a captured bootloader image:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\restore_bootloader.ps1" -InputPath ".\artifacts\bootloader-backups\<your-backup>.bin"On Windows, these OpenOCD-based scripts require the ST-Link probe to use a libusb-compatible driver such as WinUSB or libusbK. If the backup script reports ProblemCode: 28, install the driver for STM32 STLink first and then re-run the script.
Typical SWD connections:
- ST-Link
SWDIO-> targetSWDIO - ST-Link
SWCLK-> targetSWCLK - ST-Link
GND-> targetGND - ST-Link
3V3-> target3V3sense or target reference voltage - optional
NRST-> targetNRSTfor cleaner reset control
For the board-relative hookup guide and signal map, see docs/STLINK_HOOKUP.md.
Direct upload with PlatformIO:
Set-Location "c:\git\BTT SKR2 Testing"
& "C:\Users\jd\.platformio\penv\Scripts\platformio.exe" run -e skr2_f429_usb -t uploadEnd-to-end hardware validation over ST-Link plus USB CDC:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_stlink_validation.ps1"Optional variants:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_stlink_validation.ps1" -IncludeMotion
& ".\test\run_stlink_validation.ps1" -IncludePersistence
& ".\test\run_stlink_validation.ps1" -Environment skr2_f429_usb_0This path is useful when:
- the SD-card flash path is inconvenient
- USB boot behavior is unstable and you still need to reflash safely
- you want repeatable hardware-in-the-loop validation before manual console testing
- you want to move toward breakpoint-driven TMC or SDIO bring-up later
Once the resident CDC bootloader is installed, normal application reflashing can happen directly over the board USB link without ST-Link:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\tools\flash-over-cdc.ps1" -EnterBootloader -FirmwarePath ".\.pio\build\skr2_f429_usb\firmware.bin"The uploader can now auto-discover the resident bootloader port. If the board is currently running the app, add -EnterBootloader and it will issue the mode switch first.
Mode transitions over USB:
- from the app console,
BOOTLOADERorRECOVERYresets into the resident bootloader shell - from the app console,
REBOOTrequests a clean reset back into the application - from the bootloader shell,
BOOTtransfers into the installed application RESETrestarts the board and leaves it in the default bootloader entry path
Bootloader shell commands:
HELP: print the supported bootloader command setINFO: report the application flash base and whether a valid app image is presentSTATUSorDIAG: report bootloader mode, uptime, USB state, and app-presence statusFLASHorMAP: report bootloader/app flash layout boundariesREAD <offset> <size>: bounded hex dump from the application slot for recovery inspectionERASE <size>/WRITE <offset> <hex>/CRC <size>: application update primitives used by the CDC uploaderBOOT: request a clean handoff into the applicationRESET: restart the MCU
The bounded READ command is intended for recovery and diagnostics, not bulk transfer. Keep it for spot checks, header inspection, and validating what the uploader actually wrote.
Live transition validation:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_bootloader_serial_tests.ps1"Operator USB control surface:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\tools\board-usb.ps1" -Action discover
& ".\tools\board-usb.ps1" -Action enter-bootloader
& ".\tools\board-usb.ps1" -Action bootloader-command -Command 'status'
& ".\tools\board-usb.ps1" -Action enter-app
& ".\tools\board-usb.ps1" -Action app-command -Command 'help'This gives the repo one shared USB control layer instead of script-local COM-port logic. That is the expected direction if the bootloader shell keeps growing into a broader recovery and maintenance surface.
Host tests:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_host_tests.ps1"Full local CI bundle:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_ci_checks.ps1"Local GitHub Actions validation with act:
Set-Location "c:\git\BTT SKR2 Testing"
act -j validate-linuxThe repository now uses a Linux CI job for cross-platform host/build validation, which makes act practical locally, and a separate Windows self-hosted hardware workflow for board-connected USB and ST-Link checks.
ST-Link-driven hardware validation:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_stlink_validation.ps1"GitHub Actions hardware validation is defined in .github/workflows/hardware-validation.yml and expects a self-hosted runner labeled windows and keyswitch-hil with the SKR2 board, ST-Link, and USB CDC path connected.
The host test runner compiles and executes:
- bootloader protocol unit tests
- protocol unit tests
- domain unit tests
- integration tests covering parser-to-domain end-to-end behavior for homing, move aliases, stop handling, hold/enable semantics, cycle routines, and motion fault paths
Live-board serial integration tests:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_live_serial_tests.ps1"Optional motion-command coverage:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_live_serial_tests.ps1" -IncludeMotionOptional persistence-command coverage:
Set-Location "c:\git\BTT SKR2 Testing"
& ".\test\run_live_serial_tests.ps1" -IncludePersistenceThe live serial runner now adapts to both runtime safety modes:
- if TMC verification succeeds, it expects enable, hold, and motion commands to execute normally
- if TMC verification fails, it expects the firmware to block energizing and motion commands with
reason=tmc_unverified
The live suite also exercises command aliases, config-source reporting, driver verification telemetry, simulation toggles, stop commands, and post-command heartbeat continuity.
A static browser operator console is available under tools/arm-dashboard/.
Run the local server:
Set-Location "c:\git\BTT SKR2 Testing\tools\arm-dashboard"
& .\serve.ps1Then open http://localhost:8765/ in Chrome or Edge and connect with Web Serial.
The dashboard provides:
- live state and driver telemetry
- force/position charting
- motion and cycle controls
- driver current tuning controls
- simulation controls for pre-load-cell workflows
- a raw command console and macro runner
Hardware E2E validation is now split between scripted serial checks and manual motion observation:
- Run
test\run_live_serial_tests.ps1to verify heartbeat plus safe command/response behavior. - Run
test\run_live_serial_tests.ps1 -IncludeMotionwhen the axis is safe to move. - Run
test\run_bench_readiness.ps1to summarize the current TMC verification state and, when requested, replay the calibrated away-and-back motion check. - Observe that
HOMEorG28triggers seek, switch hit, backoff, and stop. - Observe that
HOMEseeks in the configured home direction, and thatG0 X<n>moves in millimeters whileJOG <n>andCYCLE <n>behave as expected after homing. - Observe that
BACKOFFruns reverse motion as expected.
Example calibrated bench check on the current reference setup:
& ".\test\run_bench_readiness.ps1" -IncludeMotion -AllowUnverifiedMotion -TravelTargetSteps -20126 -TravelUmPerRotation 15900 -TravelMinUm -100000 -TravelMaxUm 100000 -HomeFeedrateMmPerMin 600 -MoveFeedrateMmPerMin 1500 -HoldAtTargetMs 15000Use -HoldAtTargetMs when you need a stable pause at the outbound position for ruler or caliper checks before the automatic return move. The script now also accepts -HomeFeedrateMmPerMin and -MoveFeedrateMmPerMin so the reference bench profile can be replayed explicitly. On shutdown it explicitly sends HOLD OFF and DISABLE, so a completed bench pass should not leave the driver energized at idle.
Pre-load-cell validation flow:
- Send
SIMTHRESH 1000to define the simulated load threshold. - Send
SIMLOAD 1200and confirmSAFETYreportsload=1,sourceremains unchanged until motion uses it, andforce=1200. - Send
SIMMECH ONorSIMSTALL ONto validate the fallback telemetry paths. - Send
SIMCLEARto return the simulated inputs to a neutral state.
The firmware now maintains a tracked arm position once homed, and it can be orchestrated through scripts or direct commands without immediately dropping motor state:
HOMEestablishes the zero reference.HOLD ONkeeps the driver enabled at idle so the tracked position stays physically meaningful.G0 X<n>moves to an absolute millimeter position derived from the configured axis mechanics, whileMOVEABS <n>remains the explicit absolute step-position command.JOG <n>orMOVEREL <n>performs a relative move in steps.PRESSPOS <n>sets the press depth used byCYCLE <count>.CYCLE <count>performs repeated press-and-return routines from the current home reference.
The runtime motion model is still step-native internally, but the trimmed G-code surface now maps G0/G1 X... millimeter positions through the configured axis mechanics. The explicit bring-up commands MOVEABS, MOVEREL, JOG, SETPOS, and PRESSPOS remain step-native so scripts and low-level diagnostics can still work directly in step units.
The runtime scheduler and domain model are still single-axis today, but the base firmware now carries a generalized indexed channel array with labels and transport metadata. That keeps the keyswitch tester as one application profile over a broader motion/control stack that can grow toward printer, CNC, robotics, multi-MCU, and bus-backed workloads without rewriting the software-layer channel model.
The firmware targets the SKR2 X-slot TMC UART pin on PE0, and the command/config surface for TMC2209 current and stall-threshold tuning is in place. On the current reference bench, live verification still reports driver verify=0 / ifcnt_valid=0, so driver-backed motion remains a constrained bring-up path and still depends on TMC.ALLOW_UNVERIFIED_MOTION=1 for physical travel testing.
Current default startup tuning is intentionally conservative to keep the driver cool during bench work:
IRUN 5IHOLD 0IHOLDDELAY 4TPOWERDOWN 4
That target was chosen after observing roughly 0.8 A at a hotter configuration; these defaults are meant to land much closer to a light-duty ~0.2 A starting point. Increase them only as needed for reliable motion under load.
Useful first-pass driver commands:
DRIVERorTMCreports the currently applied UART config.IRUN <0-31>sets the TMC run-current scale.IHOLD <0-31>sets the TMC hold-current scale.IHOLDDELAY <0-15>sets the hold-current transition delay.SGTHRS <0-255>sets the TMC2209 StallGuard threshold register.
Current bench notes:
- On the present mechanics setup, home is on the positive side, so travel away from home is the negative coordinate direction.
- That home-side convention is now configurable per channel through
LOGIC.HOME_TOWARDS_POSITIVE, so other machines can home toward either coordinate direction without changing the electrical dir inversion setting. - The observed rotation-distance calibration was approximately
2xhigh atAXIS.TRAVEL_UM_PER_ROTATION=8000; the current temporary bench fit isAXIS.TRAVEL_UM_PER_ROTATION=15900, which putMOVEABS -20126within about2 mmof a100 mmreference marker on this setup. - The current nicest motion tradeoff on this reference bench was
MOTION.HOME_FEEDRATE_MM_PER_MIN=600andMOTION.MOVE_FEEDRATE_MM_PER_MIN=1500; the axis remained smooth, stable, and nearly silent there. MOTION.MOVE_FEEDRATE_MM_PER_MIN=2400completed repeated away-and-back passes without fault, but it was noticeably noisier and more vibration-prone, so treat that range as exploratory until the TMC chopping and quiet-step behavior are tuned properly.- Do not treat the load-cell phase as ready until the TMC UART path verifies cleanly without the unverified-motion override.
The current command layer is intentionally small, but it is structured to evolve toward a trimmed-down G-code style surface. The preferred path is:
- keep plain macro commands for bring-up simplicity
- add a narrow, documented G-code alias set for motion and diagnostics
- avoid importing a large printer-oriented G-code stack until the tester domain actually needs it
Near-term cleanup targets:
- smooth motion timing further by separating stepping cadence from telemetry cadence
- finish timer-driven stepping so motion is smooth under heavier telemetry load
- wire in the load-cell frontend and calibration flow behind the existing placeholder hooks
- wire in TMC2209 DIAG/UART handling behind the existing stall fallback hook
- split hardware pin maps and board config from firmware startup
Keyswitch tester targets:
- load cell acquisition and calibration flow
- actuator force / travel sampling
- buttons / joystick / local UI controls
- richer serial protocol for scripted test sessions
- structured test results export
The firmware shell now has explicit placeholders for the next two hardware integrations:
read_load_cell_triggered()/read_load_cell_raw()insrc/main.cppfor HX711 or ADC-based force acquisition.read_stallguard_triggered()insrc/main.cppfor TMC2209 DIAG or UART-driven stall reporting.read_mechanical_fallback_triggered()insrc/main.cppfor combining the configuredx_stopsignal with simulated or future alternate fallback sources.
The next driver-facing expansion is explicit TMC2209 current configuration so HOLD ON can eventually map to a real reduced hold current instead of only keeping the driver enabled.
Once those are connected, the domain already prioritizes stops in this order during seek:
- load-cell threshold hit
- StallGuard stall detection
- mechanical fallback stop
On the SKR2 reference configuration, the default x_stop mapping still points at PC1, but the runtime now treats that as a configurable role instead of a fixed architectural assumption.