BERGSONNE

USB

Plug a Core into a computer and it shows up as a serial port — no drivers, no crystal. core_usb is a USB CDC device with printf and buffered RX, plus a vendor HID path for raw 64-byte reports. It sits on hal_usb_cdc. Use the Core / HAL / LL toggle at the top of the sidebar to switch.

Overview

USB device is available on the Cores with a USB peripheral — Core.ST.L4 and Core.ST.H5. It runs crystal-less: the HSI48 oscillator plus the Clock Recovery System (synced to USB SOF) keeps the clock USB-accurate, so no external part is needed.

CDC appears as a COM port
On the host it’s a virtual serial device (/dev/tty.usbmodem*, a COM port on Windows) — no driver install on modern OSes. The same port is what make flash-dfu touches at 1200 baud to enter the bootloader — and, on Core.ST.L4, what make flash-serial opens at 2400 baud to update the firmware without one (serial update).

CDC serial

Init once, then write like any serial port. core_usb_connected() tells you the host has actually opened the port (so you don’t spew into the void):

#include "core.h"   // Core.ST.L4 / H5

  core_usb_init();

  while (1) {
      if (core_usb_connected()) {
          core_usb_printf("adc=%u ticks=%lu\r\n", raw, core_millis());
      }
      core_delay_ms(500);
  }

Receiving

Two RX modes. Poll a background ring buffer, or register a callback that fires from the USB interrupt as bytes arrive (when set, data isn’t buffered for polling):

// Polling:
  while (core_usb_available()) {
      uint8_t b = core_usb_getc();
  }

  // Or callback-driven:
  static void on_rx(const uint8_t *data, uint16_t len, void *ctx) { /* ... */ }
  core_usb_on_receive(on_rx, NULL);

HID reports

Alongside CDC, the device exposes a vendor HID interface for raw 64-byte reports — handy for a custom host tool (via hidapi / pyusb) with no OS driver. It’s TX-only today:

uint8_t report[8] = { 0x01, 0x02, 0x03, 0x04 };
  core_usb_hid_send(report, sizeof(report));   // zero-padded to 64 bytes

Cross-architecture support

CDC serial is the verified path on the USB-capable Cores; HID rides the same stack. MSC and USB host are not implemented. (The ROM DFU bootloader is covered in bootloading.)

·L0M0+●L4M4·W5M33●H5M33WCH (RISC-V) · Nordic (nRF54) — in development
·L0M0+●L4M4·W5M33●H5M33WCH (RISC-V) · Nordic (nRF54) — in development

See the implementation status for the full matrix.

Known gaps

What the SDK itself lists as missing here, straight from the headers:

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.

From the @studio unsupported notes in core_usb.h, core_usb_hid.h — tiles@6af026f.

API reference

Default-instance · Tier 2
void core_usb_print(const char * s);
Print a string followed by a newline. Thin wrapper for DSL-style callers.
void core_usb_print_int(int v);
Print a signed integer followed by a newline.
void core_usb_print_float(double v);
Print a double with a newline. %g trims trailing zeros for readability.
void core_usb_print_bool(int v);
Print "true" / "false" followed by a newline.
Lower-level · Tier 1
void core_usb_init(void);
Initialize USB CDC. Device appears as /dev/tty.usbmodem* on the host.
int core_usb_connected(void);
Returns 1 if a host terminal is connected (DTR set).
int core_usb_wait_host(uint32_t timeout_ms);
Wait up to `timeout_ms` for a host terminal to open the port (DTR set). Feeds the watchdog while it waits. Not needed just to see early output: on Core.ST.L4 text printed before the port opens is kept (up to HAL_USB_CDC_TX_QUEUE_SIZE bytes) and sent when it does.
int core_usb_write(const uint8_t * buf, uint16_t len);
Transmit data: queued, never waits long (see hal_usb_cdc_write); returns bytes queued, -1 before init.
int core_usb_try_write(const uint8_t * buf, uint16_t len);
Transmit without waiting: queues the whole buffer or none of it. Returns len if queued, 0 if there is no room right now (offer it again later), -1 if no terminal is connected. Main loop only.
void core_usb_on_receive(hal_usb_cdc_rx_cb_t cb, void * ctx);
Set a callback for received data. Called from USB ISR. When set, data is NOT buffered for polling reads.
uint16_t core_usb_available(void);
Returns the number of bytes available to read (ring buffer mode).
uint8_t core_usb_getc(void);
Read a single byte (blocking — waits for data).
uint16_t core_usb_read(uint8_t * buf, uint16_t max);
Read available bytes into buf (non-blocking). Returns bytes read.
int core_usb_try_read(uint8_t * byte);
Non-blocking single byte read. Returns 1 if a byte was read, 0 if empty.
int core_usb_hid_send(const uint8_t * buf, uint16_t len);
Send a HID report (up to 64 bytes, zero-padded automatically). Blocking — waits for the previous report to be read by the host. Returns bytes of user data sent, or -1 if USB not configured.
void core_usb_hid_set_rx_callback(hal_usb_hid_rx_cb_t cb, void * ctx);
Register a callback for inbound HID reports (host -> device). Fires from the USB ISR with one report per call (up to 64 bytes), delivered via the EP3 OUT interrupt endpoint or HID SET_REPORT. Pass NULL to disable; unhandled reports are dropped.

Generated from core_usb.h, core_usb_hid.h — tiles@6af026f.