A running log of project work in chronological order (newest entries at the bottom). Release-facing changes are summarised separately in CHANGELOG.md.
- Chose the project name Nux (the "war boy" from Mad Max: Fury Road), matching the Devilboy — Born to race body livery.
- Hardware direction: STM32F103C8T6, MOSFET H-bridge drive (target DRV8251A), SG90 servo steering, SX1276 GFSK link at 868 MHz, split 2S traction / 1S logic 18650 power, on/off scale lighting.
- Software architecture: bare-metal C11 (no HAL), cooperative AcroSched scheduler linked as a frozen pre-built library, shared radio protocol compiled into both firmwares.
- Monorepo layout:
common/(protocol + scheduler libs + adapter),vehicle/andtransmitter/firmwares.
- Recorded the initial project requirements in requirements.md.
- Created the initial documentation set (README, requirements, history, changelog, wiki).
- Drafted the shared radio contract
common/protocol/nux_protocol.h(little- endian packed frames, CRC-16/CCITT-FALSE):SNuxCommand_t(10 B) andSNuxTelemetry_t(9 B), light/status flag enums,_Static_assertsize guards.
- Protocol draft resolved: axis resolution stays
int16(±1000); telemetry keeps bothbattery_mvandbattery_pct; the software in-payload CRC-16 is kept (end-to-end, independent of the SX1276 hardware CRC); the frameseqis wideneduint8→uint16; the checksum moves into its ownnux_crcmodule. - AcroSched build configuration agreed: cooperative kernel,
ACROSCHED_MAX_TASKS = 8, 32-bit tick (uint32_t) at 1 kHz; watchdog hook on (IWDG), idle / low-power__WFIhook on, software timers off (periodic task modes cover turn-signal blink, fail-safe and telemetry cadence). Radio RX uses IPC event flags (RX_DONEset by the DIO0 ISR), not the mailbox. Both firmwares link the same library configuration.
- Clarified REQ-NUX-074 (radio RX via IPC event flags). Added REQ-NUX-076 (AcroSched build configuration), REQ-NUX-077 (hardware watchdog) and REQ-NUX-078 (idle / low-power hook).
- Widened the frame
seqtouint16; command frame is now 11 B, telemetry 10 B (_Static_assertsize guards updated). - Extracted
nuxCrc16(CRC-16/CCITT-FALSE) intocommon/protocol/nux_crc.{h,c}. - Implemented the frame API in
common/protocol/nux_protocol.c:nuxCommandFinalize/nuxCommandValid,nuxTelemetryFinalize/nuxTelemetryValid.
- Vendored the frozen AcroSched 2.1.0 library into
common/lib/: public headers ininc/plus the pre-built archivesac6/acrosched.libandgcc/libacrosched.a. Confirmed the vendoredacrosched_config.hmatches the agreed configuration (cooperative,MAX_TASKS = 8, watchdog on, IPC on, timers off, idle hook on). - Added the Cortex-M3 port header
common/lib/inc/acrosched_port.h(32-bit tick, PRIMASK critical sections,__WFIwait-for-event); it is required becauseacrosched_config.hincludes it and it is not part of the frozen library. - Wrote the thin scheduler adapter
common/sched/nux_sched.{h,c}(REQ-NUX-072): a self-containedNux*interface that hides theacro*API, owns the 1 kHz tick counter (nuxSchedTick/nuxSchedNow, bound to the scheduler innuxSchedInit), forwards task management, and re-exports the IPC event flags asSNuxEventGroup_t/nuxEventSet/nuxEventGet/nuxEventClear._Static_assertguards keep the mode/status encodings and the tick width in lock-step with the pre-built library ABI.
- Cleaned the imported BSP skeletons for both firmwares
(
vehicle/bsp/,transmitter/bsp/) down to a shared, board-agnostic base; the two copies are kept identical for now (per-peripheral split comes later). - Retargeted from the STM32VLDISCOVERY template (STM32F100 Value Line, 24 MHz)
to STM32F103C8: 72 MHz SYSCLK from the 8 MHz HSE crystal (PLL ×9), Flash
2 wait states + prefetch, APB1 /2 (36 MHz), APB2 72 MHz; debug USART1 on
PA9/PA10 re-tuned to
BRR = 625for 115200 baud. - Bound SysTick to the scheduler adapter:
SysTick_Handlernow callsnuxSchedTick(); dropped the BSP-ownedsys_tick, theacrosched.hinclude and the pre-emption tick (cooperative kernel only). - Kept the fault handlers (
handlers.c) as a naked MSP/PSP trampoline into a common C handler that captures the stacked frame and fault-status registers.
- Set up the CMSIS-Toolbox solution
nux.csolution.ymlwith a single target (STM32F103C8),Debug/Releasebuild types and both toolchains (AC6 6.20.1, GCC 15.2.1). - Following the intended workflow, projects pull in only
ARM::CMSIS:CORE(noDevice:Startup); the device header andSTM32F10X_MDdefine come from the DFP via the selected device, and startup/SystemInitare project-owned. - Added a shared layer
common/nux_common.clayer.yml(CMSIS core, protocol, scheduler adapter and the pre-built AcroSched library —.libfor AC6,.afor GCC) plus the two firmware projectsvehicle/transmitter, each with its BSP group and a minimalsrc/main.cskeleton. - Vendored the STM32F103C8 memory map and linker templates into each project's
RTE/Device/STM32F103C8/(regions_*.h,ac6_linker_script.sct.src,gcc_linker_script.ld.src); cbuild wires thelinker:node automatically. - GCC C runtime resolved with
--specs=nano.specs --specs=nosys.specs. - Verified: all four contexts build clean on both toolchains; the AcroSched library links in each case (ROM ~2 KB, RAM ~0.8 KB for the skeleton).
- Silenced the GCC-only newlib link warnings (
_close/_lseek/_read/_write"is not implemented and will always fail") by adding minimal no-op syscall stubsbsp/src/syscalls.cto both firmwares, compiled for GCC only (for-compiler: GCC); AC6 retargets through the ARM C Library and never sees the file. Re-verified: GCC 4/4 and AC6 4/4 contexts still build clean. - Aligned the README repository-layout tree with the actual structure
(
nux.csolution.yml,common/nux_common.clayer.yml,lib/{inc,ac6,gcc}, per-project*.cproject.yml,bsp/{inc,src},src/,RTE/Device/).
- Fixed the control strategy for the first prototype: the steering servo is driven from a 50 Hz pulse train with direct angle-to-pulse conversion; there is no MCU-side PID loop for the servo.
- Fixed the traction control law for the v0.1 prototype: no speed sensor is available, so there is no speed PID loop; PWM duty is mapped to throttle and current feedback is used as the active control signal.
- Chosen regulation model: open-loop throttle mapping with a PI current loop (driver IPROPI or shunt) for load limiting and coarse torque management, with current limiting, battery undervoltage checks and fail-safe active braking.
- This decision is now reflected in the project requirements so the architecture remains stable while the hardware and firmware are implemented.