BERGSONNE

SPI

Full-duplex synchronous serial for fast peripherals — flash, displays, IMUs. core_spi is a blocking SPI master with software-managed chip-select; hal_spi and ll_spi sit underneath. Use the Core / HAL / LL toggle at the top of the sidebar to switch.

Overview

You pick an SPI instance (SPI1, …), a clock prescaler, and the clock polarity/phase (CPOL / CPHA — the four standard SPI modes). Chip-select is a regular GPIO you drive around each transaction, so one bus can address many devices.

Not on every Core
SPI master is available on the M4/M33 Cores, not the M0+ (Core.ST.L0 has no SPI). DMA is verified on L4; the newer SPI v2 IP on W5/H5 is still being brought up. The support matrix below has the specifics.

Transfers

Init, point chip-select at a tile pad, then transact. transfer is one full-duplex byte (send and receive at once); xfer wraps a multi-byte transfer in select/deselect for you:

#include "core.h"

hal_spi_t spi;
hal_spi_config_t cfg = { .prescaler = LL_SPI_PRESCALER_8, .cpol = 0, .cpha = 0 };
core_spi_init(&spi, SPI1, &cfg);
core_spi_set_cs(&spi, 8);            // chip-select on tile pad 8

core_spi_select(&spi);
uint8_t id = core_spi_transfer(&spi, 0x9F);   // e.g. flash JEDEC ID
core_spi_deselect(&spi);

uint8_t tx[4] = { 0x03, 0, 0, 0 }, rx[4];
core_spi_xfer(&spi, tx, rx, sizeof(tx));      // select + xfer + deselect

DMA transfers

For large transfers, hand the buffers to DMA and get a callback on completion — the CPU is free in the meantime. Both buffers must stay valid until the callback fires:

static void on_done(void *ctx) { /* transfer complete */ }

if (core_spi_xfer_dma(&spi, tx, rx, len, on_done, NULL) != HAL_OK) {
    // busy or unsupported on this Core
}
while (core_spi_busy(&spi)) { /* or go do other work */ }
DMA coverage
Full-duplex DMA is verified on Core.ST.L4; on the SPI v2 Cores it falls back or returns an error while the GPDMA path is finished.

Cross-architecture support

Polling master transfers are the baseline on the Cores that have SPI; DMA and the SPI v2 bring-up vary. The same core_spi contract holds where the peripheral exists:

·L0M0+L4M4W5M33H5M33WCH (RISC-V) · Nordic (nRF54) — in development

See the implementation status for the full matrix.

API reference

Default-instance · Tier 2
int core_spi_xfer_byte_bus(uint8_t bus, uint8_t cs_pad, uint8_t tx);
Single-byte full-duplex transfer over `bus`, with CS auto-managed around the call (asserted before, deasserted after). Returns the received byte (0..255) on success or -1 on any error (bus undeclared, cs_pad undefined). The signed return lets DSL programs branch on `< 0` without an out-pointer. Most chip protocols pair two of these (write a register address, then read or write the value). Multi-byte sequences that need CS held across them — display init streams, audio frame transfers — still need Tier 1 with manual select/deselect.
Lower-level · Tier 1
hal_status_t core_spi_init(hal_spi_t * h, SPI_TypeDef * instance, const hal_spi_config_t * cfg);
Initialize SPI in master mode. Same signature as hal_spi_init.
void core_spi_set_cs(hal_spi_t * h, uint8_t pad);
Assign a CS pin using a tile pad number. Resolves pad to port/pin via hal_pad_lookup, then calls hal_spi_set_cs to configure and deassert the pin.
void core_spi_select(hal_spi_t * h);
Assert CS (drive low).
void core_spi_deselect(hal_spi_t * h);
Deassert CS (drive high).
uint8_t core_spi_transfer(hal_spi_t * h, uint8_t tx);
Full-duplex single byte transfer. Returns received byte.
void core_spi_write(hal_spi_t * h, const uint8_t * data, uint32_t len);
Write-only (discard received data).
void core_spi_read(hal_spi_t * h, uint8_t * buf, uint32_t len);
Read-only (send zeros).
void core_spi_xfer(hal_spi_t * h, const uint8_t * tx, uint8_t * rx, uint32_t len);
Convenience: select + full-duplex transfer + deselect. tx and rx can be the same buffer. Either can be NULL.
hal_status_t core_spi_xfer_dma(hal_spi_t * h, const uint8_t * tx, uint8_t * rx, uint32_t len, hal_callback_t cb, void * ctx);
Start a DMA-based SPI transfer (non-blocking). Full-duplex: tx bytes are sent while rx bytes are received simultaneously. Either tx or rx can be NULL for write-only or read-only transfers. The callback fires from DMA ISR context when the transfer completes. Caller must manage CS: assert before calling, deassert in the callback. The command/address byte should be sent via polling (core_spi_transfer) before starting DMA.
int core_spi_busy(hal_spi_t * h);
Returns 1 if a DMA transfer is in progress.

Generated from core_spi.htiles@d3cff63.