BERGSONNE

Implementation status

The same core_* API and behavior DSL target every Core — this page is the honest map of how far each one is along, and where the platform is headed across architectures. One contract, many implementations.

Core.ST.H5: known issues, fix pending
A September 2026 audit found the H5’s foundation off: its HSI divider is left at ÷2, so it runs at half the documented clock and everything timed from SYSCLK_HZ is off by 2x; its interrupt table is shifted from IRQ 27; and SPI has no kernel clock. The rows this touches are marked partial with a note until the H5 fix session. See Clocks.

Overview

A peripheral feature is “done” on a Core when the layers beneath the core_* API are implemented for that MCU and the result is checked on hardware. Because the contract is shared, this is the only thing that varies between Cores — so a single matrix captures the whole platform.

Today the shipping Cores are STMicroelectronics Arm Cortex-M parts. WCH (RISC-V) and Nordic (nRF54) Cores are in development; when they arrive they populate the same matrix without changing a line of your firmware.

Status, not marketing
Statuses come straight from the SDK’s own status files, re-synced whenever they change in the SDK. This snapshot: 26 September 2026, from tiles@044f8f3. Verified means checked on real hardware; compiles means the code builds but hasn’t been hardware-verified yet. Hover a dot for its note: most name the bench test and date.

Cores by architecture

Cores are named by vendor and series — Core.ST.L4, Core.CH.*, Core.N.*. The vendor segment is the architecture seam: everything above the core_* line is shared, everything below is re-implemented per family.

STMicroelectronics

· Arm Cortex-MShipping

The Cores shipping today, from an ultra-low-power M0+ up to an M33 rated for 250 MHz. The full feature matrix below is measured against these.

Core.ST.L0
STM32L011
M0+ · rated 32 MHz
Core.ST.L4
STM32L422
M4 · rated 80 MHz
Core.ST.W5
STM32WBA55
M33 · rated 100 MHz
Core.ST.H5
STM32H523
M33 · rated 250 MHz

WCH

· RISC-VIn development

RISC-V Cores bringing a lower-cost architecture to the same tile platform. The core_* API and behavior DSL are unchanged — only the layers beneath are re-implemented.

In development — same core_* contract, drivers via the PAL.

Nordic

· Arm Cortex-M33In development

nRF54 Cores adding modern wireless (BLE / 802.15.4) alongside the Arm M33 line. Same contract, same drivers via the PAL.

In development — same core_* contract, drivers via the PAL.

Feature support matrix

Features by group, against the shipping Cores. Each entry carries the SDK layer it reaches (LL → HAL → TAL → Core); a layer implies everything beneath it.

FeatureLayerL0M0+L4M4W5M33H5M33
System
core initializationCore●●●●
LEDStudio●●●●
delay (ms / µs)Studio●●●●
SysTickLL●●●●
fault handlers●●●●
unique device IDCore●●●●
brick recoveryCore·●·●
SWO / ITM debug outputHAL·●●●
WAMR (Wasm) runtimeStudio··●●
Clocks
HSI (internal RC)LL●●●●
HSE (external crystal)LL··●·
MSI / MSIS (low-power)LL●●··
CSI (low-power internal)LL···●
PLL (high-speed)LL●●●●
GPIO
digital I/O (read / write)Studio●●●●
EXTI (external interrupts)Studio●●●●
alternate function configLL●●●●
open-drain / pull configCore●●●●
UART
TX / RX (polling)Core●●●●
interrupt-drivenCore●●●●
DMACore○○○○
hardware flow control○○○○
LPUART (low-power)Core●●·●
I2C
standard mode (100 kHz)Core●●●●
fast mode (400 kHz)Core●●●●
fast-mode plus (1 MHz)·●·●
interrupt-drivenCore○○○○
target / device modeCore●●●●
DMA○○○○
10-bit addressingCore○○○○
SMBus mode○○○○
SPI
master TX / RX (polling)Core·●●◐
interrupt-drivenCore·○○○
DMACore·●●○
slave mode·○○○
OctoSPI / QSPI···○
Timers
basic timebase / tickStudio●●●●
PWM outputStudio●●●●
STEP/DIR stepper pulsesCore●●●●
input captureCore●●○●
one-shot pulse○○○○
encoder mode○○○○
LPTIM (low-power timer)○○○○
IWDG (watchdog)Studio●●●●
ADC
single-shot raw readStudio●●●●
millivolt read (VREFINT)Studio◐●●●
temperature sensorStudio●●●●
resolution (8 / 10 / 12-bit)Core●●◐●
oversampling / burstCore●●●●
DMACore●●●◐
DMA results in millivoltsCore◐●●●
continuous / scan modeCore●●●●
external trigger (TIMx TRGO / EXTI)Core●◐◐◐
analog watchdog○○○○
Audio
PDM microphone captureCore··●·
NVM
true EEPROMCore●···
flash emulationCore·●●○
OTP identity slotsCore·○◐○
Project Generation (Coregen)
GPIO pad auto-initCore●●●●
I2C auto-initCore●●●●
analog pad initCore●●●●
SPI auto-initCore·●●●
UART auto-initCore●●●●
timer / PWM auto-initCore●●○●
Power Management
sleep modeCore●●●●
STOP modeCore●●●◐
standby / shutdownCore●●●●
RTC wakeupStudio●●●◐
EXTI wakeupCore●●●●
wakeup pin (Standby)Core○●○○
RTC Alarm AStudio●●●●
backup registersStudio●●●●
Security
hardware RNG·●●●
AES (hardware)·○◐·
PKA / ECC··○○
HASH (SHA-256)··○○
Connectivity
USB CDC serialStudio·●·●
Scope over USBCore·●·●
Scope over BluetoothCore··●·
USB HID·●·●
USB-reachable sleepCore·◐·○
USB MSC·○·○
ROM DFU bootloader·●·●
serial update (USB CDC)HAL·●·●
SWD flash from StudioStudio○○●○
BLE radio··●·
BLE advertising··●·
BLE GATT server··●·
FDCAN···○
Advanced
I3C controller···○
I3C target···○
COMP (analog comparator)●●○·
DACStudio···●
Bluetooth LE
advertisingCore··●·
GATT services + characteristicsCore··●·
notify / on-write callbacksCore··●·
pairing + bondingCore··◐·
central / scanner roleCore··○·

Legend

Status of each feature on each Core:

  • ●Verified on hardware
  • ●Compiles (not yet hardware-verified)
  • ◐Partial
  • ○Planned
  • ·Not applicable to this MCU

The Layer column uses the SDK’s stack vocabulary — see SDK layers & API tiers. A higher layer implies the ones beneath it are present too.

Known gaps

The matrix says how far each feature has got; these say what’s missing. Each SDK header lists its own gaps (@studio unsupported), and they are published here as written. High / medium / low is how much closing the gap is worth; C API / DSL / wire is where it sits (the C API, the Studio DSL, or the Scope wire format). The subsystem guides show their own.

ADC
lowDSLTwin VDD / die-temp are constants

read_pad / read_mv_pad use the per-pad slider on the chip view, but temp_decidegc and vdd_mv return fixed values (25.0 °C / 3300 mV). No UI affordance to vary them yet — DSL programs that branch on under-/over-temp or low-VDD logic always see nominal in the IDE.

mediumDSLNo DSL access to sampling speed / resolution

Tier 2 calls the default instance at its compile-time resolution (12-bit) and per-pad sampling speed set during init. SAMP_FAST / MED / SLOW / VERY_SLOW and ADC_6/8/10/12BIT aliases are reachable only via the explicit-handle Tier 1 API.

mediumDSLNo multi-instance ADC dispatch

Tier 2 wrappers always hit core_adc1. Cores with multiple ADCs (Core.ST.H5 has ADC1 + ADC2) need per-pad peripheral tagging in tile JSON before coregen can emit the dispatch. Until then DSL programs are limited to whichever pads coregen routed to ADC1.

mediumC APINo oversampling / averaging helper

STM32 ADCs can hardware-oversample 2×–256× for extra effective resolution. The HAL exposes the registers but core_adc has no convenience wrapper — callers reach into tal_adc / hal_adc to set OVSR/OVSS bits manually.

lowC APINo injected channels

Regular-group external triggers ARE supported: core_adc_set_trigger() paces DMA conversions from a TIMx TRGO or EXTI line. Injected groups (a second, higher-priority conversion sequence that preempts the regular one) are not surfaced. Bring-your-own register writes if you need a preempting sample inside a control loop.

Backup
lowDSLTwin backup state wipes on Reset

read/write round-trip within a single run, but the per-slot store is cleared on every project reload — DSL programs that rely on backup state surviving a soft reset (e.g., boot counters across the user clicking Reset in the IDE) can't be exercised end-to-end.

lowC APINo tamper / anti-tamper integration

The TAMP block on WBA/H5 hosts the backup registers but also drives tamper detection (active edge, anti-tamper erase, time-stamping on tamper). None of that is wrapped — backup is read/write only.

BLE
mediumDSLNo Twin coverage for BLE

DSL coverage landed: a project declares a contract, gets palette blocks to publish and receive, and can bind a characteristic to a variable so coregen generates the publisher. What is still missing is the simulator side, so a DSL program that uses BLE cannot be exercised without flashing a board.

mediumDSLConnect / disconnect are not DSL events

core_ble_on_connect() and core_ble_on_disconnect() take a callback pointer rather than overriding a weak symbol, so coregen has no seam to emit a dispatcher against. Every other event in the DSL arrives through that weak-symbol pipeline. Until this is wired the only way to notice a connection from the DSL is to poll.

lowDSLByte-array characteristics have no DSL form

A `bytes` characteristic can be declared and published from C, but the DSL has no type that carries a buffer and a length, so it gets neither a publish block nor a write handler, and it cannot be bound to a variable. Scalars and strings both work.

mediumC APICentral / scanner mode

Peripheral-only today. No scanning, no central-role connections, no GATT-client reads/writes. Tracked as its own initiative — most Bergsonne use-cases are peripheral-role (sensor advertising to a phone). Apps that need central-role drop into the WBA BLE stack.

lowC APIPairing refinements (LE Secure Connections, directed reconnect)

core_ble_enable_pairing() does Just Works *legacy* pairing with bonding: characteristics require an encrypted link and the keys persist in flash NVM, so a bonded host reconnects without re-prompting. Not yet exposed: LE Secure Connections (numeric-comparison / passkey MITM protection) and directed advertising for fast reconnect to a known bonded central.

lowC APIArbitrary 128-bit UUIDs

Narrower than it used to be. A contract pins its own 16-bit ids, custom (placed in the Bergsonne base UUID) or SIG-adopted, and core_ble_add_service_id() / _sig() take them verbatim, so ids never shift and deployed clients keep working. What is still missing is a fully arbitrary 128-bit UUID, which is what interop with an existing app that expects some other vendor's base requires.

lowC APIAdvanced features (LE Audio, extended adv, multi-link)

The WBA radio supports LE Audio (LC3), extended advertising / 2M PHY / coded PHY, and multi-link (multiple simultaneous connections). None of that is exposed.

DAC
mediumC APINo waveform / DMA generation

Single-sample writes only. STM32H5's DAC supports DMA-fed sample buffers + the internal noise / triangle wave generators — none of which are wrapped. Audio + arbitrary-waveform tiles need this.

lowC APINo dual-channel synchronization

The DAC peripheral has two channels that can be triggered together for stereo / I-Q output. Only single-channel writes are exposed.

Debug
lowDSLNo DSL surface

Debug output is intentionally Tier 1 — the DSL doesn't have a notion of "debug print to a hardware probe." DSL programs use Core.USB.print for visible output; SWO is reserved for users who are already in C and have a probe attached.

lowC APINo ITM channel selection / timestamps

All output goes to ITM stimulus port 0 with no timestamp packets. Multi-channel routing (e.g., separate streams for log vs. data) and ETM/CYCCNT correlation aren't wrapped.

Fault
mediumC APINo structured fault report capture

The default handler dumps to USB CDC at runtime on the L4 only (the W5, H5 and L0 lose the cause), and there's no crash log that survives reset for post-mortem analysis. A small ring buffer in backup or NVM (with the captured PC / LR / xPSR / fault status registers) would make field debugging tractable.

I2C
mediumDSLTier 2 is byte-level only — no bulk / scan

The current Tier 2 surface is write_byte_bus / read_byte_bus / probe_bus. DSL programs that need to push a multi-byte payload (display init sequences, IMU FIFO drains) or discover what's on a bus (`scan -> int[]`) drop back to Tier 1 with a hal_i2c_t handle. Adds need the array-IN / array-OUT host-call ABI prototyped on the tile-driver side — track with the DSL Capability Coverage close.

highC APIInterrupt-driven / non-blocking I/O

All current operations are polled. A non-blocking variant (with completion callback or status poll) would let DSL programs interleave bus traffic without stalling the main loop. Tracked on the SDK roadmap as 'I2C interrupt-driven'.

highC APIDMA transfers

No DMA path for bulk reads/writes. Long FIFO drains (e.g., IMU water-level batch reads) currently block on polled byte loops.

mediumDSLTarget mode is C-only

Target (device) mode landed at Tier 1: core_i2c_target_init() lets a Core answer as an I2C device on a host bus, using a register-file model with an optional ISR callback. There is no Tier 2 / DSL surface, because a register buffer and a callback have no representation in the DSL host-call ABI. A Studio-level version would need a declarative "expose these variables as registers" binding, close to what the BLE characteristic binding does.

lowC APITarget mode on H5 I2C2 / I2C3

startup_stm32h523xx.s carries vectors for I2C1_EV, I2C1_ER and I2C2_EV only. There is no I2C2_ER or I2C3 entry, and slot 58 is labelled as I2C2 Error shared with USART1, so target mode is restricted to I2C1 on Core.ST.H5. I2C1 + I2C3 both work on Core.ST.L4 and Core.ST.W5; Core.ST.L0 has only I2C1.

mediumC API10-bit addressing

API takes uint8_t addr — 7-bit only. No path for 10-bit-addressed peripherals (rare in practice but in spec).

lowC APISMBus / PMBus extensions

No PEC, no Alert Response, no block read/write protocol framing. Not requested by any current tile.

LED
lowDSLNo DSL access to SOS

core_led_sos is `__attribute__((noreturn))` so it can't be exposed safely — DSL programs that "call SOS" would deadlock the worker. Reserved for fault-handler escape-to-C use.

lowC APINo PWM brightness / color

The onboard LED is hard-wired as a digital push-pull output. No PWM dimming wrapper, no RGB/RGBW support (tiles with addressable LEDs use Disp.RGBW or similar, not core_led).

NVM
mediumDSLNo bulk read / write Tier 2 yet

Tier 2 covers the byte-level pair (read_byte, write_byte) — enough for boot counters, single flags, small struct fields. Multi-byte read_buf / write_buf still need the array-IN / array-OUT host-call ABI prototyped on the tile-driver side. Tracked with the DSL Capability Coverage close.

lowDSLTwin NVM state wipes on Reset

read_byte / write_byte round-trip within a single run, but the per-slot store is cleared on every project reload — DSL programs that rely on NVM state surviving a soft reset (boot counters, crash flags) can't be exercised end-to-end in the IDE. Same issue the Backup register gap calls out; closing both needs persistent per-slot state across worker resets.

mediumC APINo NVM on Core.ST.H5 yet

core_nvm_write returns -1 on Core.ST.H5 (CORE_NVM_SIZE is 0). The flash emulation behind Core.ST.L4 and Core.ST.W5 has not been ported to the H523's 8 KB sectors yet. Until it is, H5 programs that need persistent state are limited to backup registers.

lowC APINo wear-tracking API

core_nvm_erase_all clears the region, but nothing reports the page erase count or the remaining write budget. Long-running data loggers budget their write rate from the figures in core_nvm.h.

OTP
highC APIOTP only on Core.ST.W5

CORE_OTP_* is backed only on Core.ST.W5 (STM32WBA55, 512 B @ 0x0BF90000). L0 / L4 / H5 report size 0 and every read/program returns an error until their OTP geometry is added. WBA55 is the only Core that currently ships a product using OTP identity.

mediumDSLprogram_slot is escape-to-C (destructive)

Reads (size, slot_count, slot_is_blank, read) are safe to surface, but the burn (core_otp_program_slot) is irreversible and write-once, so it is intentionally NOT exposed to the DSL — a stray palette call could permanently consume a slot. Provisioning burns happen from C / the production programmer, not from a Studio program.

GPIO
mediumDSLNo DSL access to slew-rate / pull / drive-strength

Tier 2 exposes write/read/toggle only. core_pad_speed, core_pad_output_od pull-config, and the analog-mode setter are reachable only by escaping to C. A Tier 2 wrapper (or @studio expose annotation) for slew-rate would let DSL programs tune SPI/UART rise times without leaving the IDE.

lowDSLBulk / fast pad write is C-only

The single-pad DSL ops do a pad→port/pin lookup each call. A C fast path now exists — core_pad_resolve() + core_pad_fast_* (resolved {port,mask} handle, direct BSRR/IDR) and core_pad_bulk_write() (one atomic BSRR for many pins) — used by bitbang inner loops like the CMSIS-DAP probe. Still no DSL surface (pointer/struct ABI), so synchronized-bus / LED-matrix updates from the IDE remain a gap.

Power
mediumDSLStandby family stays Tier 1 (noreturn)

core_standby_for / core_standby reset on wake — they never return on success and can't be safely exposed to the DSL, since the simulator would deadlock on a call that never returns. Recoverable variants (sleep, stop_for) are Tier 2; reaching Standby from a DSL program needs an "escape-to-C" fallthrough or a separate "would have entered Standby" event the simulator can model.

mediumDSLNo wake-on-pad Tier 2

core_stop_until_on_change blocks until a configured pad edge wakes the chip. The DSL surface is straightforward in spirit but needs the EXTI handler bridge to express "block until" cleanly across the host-call boundary. Tracked alongside the broader DSL event- model story.

highC APIStop / Standby not bench-verified on Core.ST.L0; Standby not on Core.ST.W5

The register maps behind stop_for / standby_for / RTC / backup were corrected against RM0377 and RM0493 on 2026-09-25 (the L0 enabled the LSE instead of the LSI and hung; the WBA wrote CCIPR instead of BDCR1, had no RTC bus clock and a reserved Standby LPMS). The W5's Stop passed tests/hw-sleep-cycle on 2026-09-25; its Standby and all of the L0 are compile-only until they do. Core.ST.L4 passed the same test; Core.ST.H5 keeps its older sleep code until its own fix session.

mediumC APIStandby can't outlast the watchdog

The IWDG keeps counting in Standby (always on the L0, by option byte on the L4/WBA) and nothing feeds it until main() runs again, so with the watchdog on (the Studio default, 5 s) core_standby_for refuses anything longer than half the timeout and returns HAL_ERROR, and core_standby_until_on_change returns without sleeping. Long sleeps use core_stop_for, which wakes to feed. Changing the IWDG_STDBY option byte would lift this on the L4/WBA; the SDK doesn't touch option bytes.

mediumC APIWKUP-pin Standby is L4-only

core_standby_until_on_change is implemented for STM32L422 only — Core.ST.L4.2's PA0/PA2 WKUP pins. Other Cores hit the (void) fallback and return without entering Standby.

mediumC APINo LPTIM (low-power timer) wakeup

The SDK roadmap flags LPTIM as Tier 1 high-impact: it runs in Stop without the RTC and gives finer wakeup granularity than seconds. Not wrapped here yet.

lowC APINo autonomous-mode peripherals (Core.ST.W5)

The WBA's Stop2 autonomous mode (ADC / SPI / I2C / UART operating while the CPU sleeps) is on the roadmap as Tier 3 — none of it is surfaced through core_power yet.

PWM
mediumDSLNo DSL access to PWM frequency

Tier 2 only exposes duty. Frequency is fixed at coregen time from config.json's timer.freq_hz. DSL programs that want to sweep frequency (e.g., a buzzer playing notes) need set_freq exposed per-pad — the underlying tal_pwm has the path, but the wrapper + default-instance dispatch don't.

mediumDSLNo DSL access to periodic 'every' callbacks

core_every_us is Tier 1 only — it takes a C function pointer for the ISR callback. The DSL surface is `Core.Timer.tick` (in core_timer.h) which fires at config.json's timer.tick_ms; finer custom periods aren't reachable.

mediumC APINo complementary PWM / dead-time (TIM1 advanced)

SDK roadmap Tier 2 item: TIM1's complementary outputs + dead-time insertion + break input are needed for half-bridge / motor / power-converter tiles. The PWM wrapper is single-channel only.

lowC APINo phase / center-aligned modes

Edge-aligned PWM only. STM32 timers can do center-aligned (Mode 1 / 2 / 3) and per-channel phase offsets — useful for low-EMI switching. Not surfaced.

RNG
lowC APINo bias correction / health tests

The hardware exposes a CED (clock error) and SEIS (seed error) bit which core_rng_error checks, but there's no NIST SP 800-90B continuous-health-test wrapper. Crypto-grade users should consume the raw words through a vetted DRBG (mbedTLS, etc.).

RTC
mediumDSLNo DSL get_time / get_date

The C surface has core_rtc_get_time / get_date taking out-pointers; they're not exposed because the host-call ABI doesn't map cleanly to multi-out values. The newer multi-scalar-out ABI (see DSL Capability Coverage close, 2026-05-03) could land them.

mediumC APILSE / external crystal not exposed

core_rtc_init always selects LSI (~32 kHz RC, ±5% typical drift on the L4/WBA; the L0's is 26-56 kHz part to part and is not calibrated against HSI16, so its RTC second can be off by tens of percent). Cores with an LSE crystal need ll_rtc_init(1) — no Tier 2 wrapper that takes a clock-source argument.

lowC APINo subsecond / millisecond accuracy

The wrapper exposes whole-second resolution. STM32 RTCs have a subsecond register (1/PREDIV_S) that's reachable from ll_rtc but not from this header — wall-clock timestamps round to the second.

Scope
mediumDSLNo host-to-device control channel

The stream is one-way. A host cannot start, stop or re-rate it, or pick channels; core_scope_enable() is firmware-side only. USB has an RX path and BLE would need a write characteristic beside Studio Scope.

mediumDSLNo units or scaling in the stream

The SDK is integer-only by convention (milli-units), so a channel in mdeg plots in mdeg. A per-channel unit + scale frame is planned (docs/scope-protocol.md, reserved frame types).

lowwireBLE packet size is assumed, not negotiated

core_ble does not report the ATT MTU, so the BLE link sends 180-byte notifications. A central that stayed at the 23-byte default would see nothing but CRC failures. Driver-deferred: needs core_ble_mtu().

lowwireNo 64-bit or double channels

The wire has no 8-byte type. Watching one is a compile error by design.

Serial
mediumDSLNo Tier 2 read surface

Tier 2 wraps the write side (print_bus, putc_bus) only. getc_bus, read_bus, available_bus need a Twin input affordance to be meaningful — without one the read functions would just return -1/0 always, defeating the point. Adding a "serial input" pane (analog of the GPIO toggle / ADC slider) closes both ends.

mediumDSLNo coregen auto-init for serial

Tier 2 wrappers assume the user has called core_serial_init on the matching handle before any send. Coregen doesn't yet read a `serial: { 1: { baud: 115200 } }` block out of config.json and emit the init in core_init(). Until it does, the bus has to be primed by hand even when using Tier 2.

highC APINo interrupt / DMA driven path

All calls block. SDK roadmap Tier 1 item: "UART IRQ + coregen" for non-blocking serial (GPS, RS-485). Long reads currently stall the main loop until the buffer fills or times out.

mediumC APINo flow control / parity / 9-bit modes

The thin wrappers expose only the basics — RTS/CTS, parity, stop bits, 9-bit data, and inversion are reachable only via the hal_uart_config_t struct passed to init.

mediumC APINo LPUART (low-power UART)

SDK roadmap Tier 2: LPUART works in Stop mode for wake-on-serial. Compile-only on every Core today; not surfaced through this header.

SPI
mediumDSLTier 2 is single-byte xfer only — no bulk / persistent CS

The Tier 2 surface is core_spi_xfer_byte_bus: one byte, CS auto- managed around the call. DSL programs that need to push a multi-byte payload with CS held (display init streams, SD-card sectors, audio frame transfers) drop back to Tier 1 (core_spi_xfer, core_spi_write_read, core_spi_exchange_dma). Bulk variants need the array-IN / array-OUT host-call ABI prototyped on the tile- driver side — track with the DSL Capability Coverage close.

mediumC APICore.ST.W5 SPI not yet bench-verified; Core.ST.H5 SPI still stalls

Core.ST.L4 passes tests/hw-spi-loopback (polled + DMA, modes 0-3, 1-4096 bytes, timeouts). Core.ST.W5 builds the same code (TSIZE sessions, GPDMA) but has not run it on hardware yet; the camera tile's LL half-duplex path is the only W5 SPI use proven on silicon. Core.ST.H5: the kernel clock is now per_ck (the HSI), but on the bench SPI1 still never clocks a frame and a transfer returns HAL_TIMEOUT (2026-09-26, only tried on a board started by the ROM bootloader).

lowC APISPI DMA not on Core.ST.H5

core_spi_exchange_dma / core_spi_xfer_dma run on Core.ST.L4 (DMA1) and Core.ST.W5 (GPDMA1 CH6/CH7) and return HAL_ERROR on Core.ST.H5, where polled transfers are the only path.

lowC API8-bit Motorola frames only

Frames are 8 bits. No 16-bit frames, hardware CRC, TI frame format or hardware NSS at the core level; the LL layer has the Core.ST.W5 half-duplex (1-line) mode.

mediumC APISlave mode missing

Master-only. No path for a Core to act as a SPI peripheral on another host's bus.

lowC APIQuad / Octo SPI / OctoSPI

SDK roadmap Tier 2: QUADSPI / OctoSPI (memory-mapped external flash for NOR / PSRAM tiles) is wired only on Core.ST.L4 + Core.ST.H5 silicon and isn't wrapped here.

Stepper
mediumDSLNo default-instance / DSL surface

Everything takes a core_stepper_t*. Coregen does not yet read a `stepper` block from config.json, so there is no `core_stepper_move(pad, steps)`-style wrapper and nothing in the Studio palette. The natural Tier 2 shape is one axis per config.json entry with STEP/DIR pads, initialised in core_init().

lowC APISTEP must be a timer output pad

The pulse is made by a compare channel, so STEP is restricted to pads carrying a TIMx.y function. There is no GPIO-bitbang fallback for arbitrary pads; DIR and ENABLE can be any pad.

lowC APILinear ramps only

The profile is trapezoidal (constant acceleration). No S-curve, no per-move acceleration override, no synchronised multi-axis moves.

lowC APINo stall, fault or limit-switch inputs

Drivers' nFAULT / ALM outputs and end-stop switches are left to the application (core_pad_on_change + core_stepper_halt).

Tiles
mediumC APIHard cap of 4 cached PALs per bus type

The internal slot table is sized to 4. Designs with >4 simultaneous I2C buses (or >4 SPI buses) will silently route extras to slot 0, which corrupts the cached function pointers if the bus types differ. No current Core has that many buses but the cap is undocumented for future-proofing.

lowC APINo bus / address discovery

Tile drivers receive a bare tiles_pal_t* and a tile JSON; there's no wrapper here that walks coregen's tile_handles.h to enumerate "what tiles are on what bus." Each test builds the wiring by hand.

Timer
mediumDSLTick event period is set in config.json, not from DSL

The DSL's `Core.Timer.tick` event fires at the period baked into coregen from config.json's timer.tick_ms. There's no `Core.Timer.set_tick_ms()` host call to retune at runtime — the period is fixed for the life of the program.

mediumDSLNo DSL access to per-channel capture / PWM

core_timer_capture_init / capture_read / pwm_set are Tier 1 — they take a core_timer_t* the DSL can't construct. PWM has its own default-instance helper (Core.PWM.duty); capture / measurement has no DSL surface.

mediumC APINo encoder / quadrature mode

The hardware supports incremental encoder mode (CH1+CH2 quadrature counting). The wrapper exposes neither encoder init nor read. Motion / rotary-encoder tiles can't use it without dropping into ll_tim.

lowC APINo one-pulse mode (OPM)

STM32 timers can fire a single pulse of programmable width and then auto-disable — useful for camera trigger / strobe / ultrasound ranging. Not wrapped.

Timing
lowC APINo monotonic 64-bit clock

millis wraps at ~49.7 days. Long-running systems (industrial / datalogger) need either a 64-bit upcounter or a wrap-aware helper for diff-since-start.

USB
mediumDSLNo DSL surface for receive (byte read / available)

The Core.USB.receive event handles inbound bytes one at a time, but DSL programs can't poll core_usb_available() / core_usb_read(). That makes message-framed protocols (read N bytes after a header) awkward — the workaround is to accumulate bytes in a DSL array inside the receive handler.

lowDSLNo DSL printf-with-formatting

print_int / float / bool emit one value per call, each on its own line. For multi-field log lines DSL programs concatenate with string ops (or call print multiple times). A `print_fmt(template, ...args)` host call would be the next step.

mediumC APIUSB MSC (mass storage)

SDK roadmap Tier 3: drag-and-drop firmware / datalog volume needs SCSI + FAT. A feature gap, not a workflow blocker — projects that need persistent storage today reach for NVM or SD via SPI.

mediumC APIUSB Host mode

Core.ST.H5 has DRD silicon but the wrapper is device-only. Most projects don't need host mode; the few that do (USB-keyboard / thumb-drive readers) drop into the lower-layer USB stack.

mediumC APINo CDC line-coding callback

Host-side baud changes (1200-touch bootloader trigger included) land in the lower stack. The header doesn't expose a hook for programs that want to react to baud / DTR changes.

USB HID
mediumDSLNo DSL surface for HID

Sending a HID report needs a buffer pointer + length. The DSL's array-host ABI (used for tile reads) could carry it, but no default-instance wrapper is wired up.

lowC APIVendor descriptor only

The HID descriptor is hard-coded as a 64-byte vendor report with usage page 0xFF00. No way to register custom reports (keyboard, mouse, gamepad) — that needs the full HID descriptor tooling.

Watchdog
lowDSLNo DSL access to caused_reset / clear_flags

These return / clear hardware flags that only matter on the very first boot iteration. Exposing them needs a story for "before studio_start runs" — Studio doesn't currently model that phase.

lowC APINo window watchdog (WWDG)

STM32 also has a windowed watchdog (must feed within a window, not just before the deadline). Useful for catching feed-too-fast bugs. Not wrapped here.

From the @studio unsupported notes in core_adc.h, core_backup.h, core_ble.h, core_dac.h, core_debug.h, core_fault.h, core_i2c.h, core_led.h, core_nvm.h, core_otp.h, core_pad.h, core_power.h, core_pwm.h, core_rng.h, core_rtc.h, core_scope.h, core_serial.h, core_spi.h, core_stepper.h, core_tiles.h, core_timer.h, core_timing.h, core_usb.h, core_usb_hid.h, core_watchdog.h — tiles@6af026f.