Skip to content

feat(hal): opt-in DMA for ESP32 hardware SPI (Phase 1) - #142

Merged
lexus2k merged 2 commits into
masterfrom
feature/esp32-spi-dma
Aug 4, 2026
Merged

lexus2k merged 2 commits into
masterfrom
feature/esp32-spi-dma

Conversation

@lexus2k

@lexus2k lexus2k commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Draft — do not merge until validated on ESP32 hardware.

Roadmap "DMA-accelerated SPI", Phase 1 (Tier A: hardware DMA under the existing blocking API). ESP32 only.

What

Opt-in DMA transport for the ESP32 SPI HAL, guarded by CONFIG_ESP32_SPI_DMA_ENABLE (undefined by default).

  • With the macro off: SPI path is byte-for-byte the current code (internal 64-byte buffer, max_transfer_sz=32, no DMA channel).
  • With the macro on: begin() allocates a DMA-capable, word-aligned flush buffer (heap_caps_malloc(MALLOC_CAP_DMA), size CONFIG_ESP32_SPI_DMA_BUFFER_SIZE, default 512) and inits the bus with a DMA channel (SPI_DMA_CH_AUTO, fallback ch 1 on pre-4.3 IDF). Bulk pixel writes flush as large DMA transactions. Alloc failure → falls back to the internal buffer with DMA off.

Drivers are untouched — all logic lives in the SPI HAL behind the template interface.

Why it's safe

  • Default build provably unchanged (m_txbuf≡m_buffer, m_capacity≡64, DMA blocks compiled out).
  • Transfers stay blocking (spi_device_transmit), so the existing flush-before-DC-toggle ordering (setDataMode()/OnDcChange, which runs in task context) is preserved — the data/command line can never flip mid-transfer.

Verification

  • Full SDL unit suite passes (484 tests) — shared build unaffected.
  • New CI step builds the ESP32 example with CONFIG_ESP32_SPI_DMA_ENABLE defined (compile/link check), reusing the cached ESP-IDF.
  • Still required: functional test + throughput benchmark on real ESP32 hardware (e.g. ST7735/ILI9341 full-frame push). This is why the PR is a draft.

Commits

  • feat(hal): opt-in DMA for ESP32 hardware SPI
  • ci(esp32): verify build with SPI DMA enabled

Follow-ups (later phases)

  • Phase 2: same pattern for RP2040, then STM32.
  • Phase 3: async/overlapped DMA (double-buffered NanoCanvas flush) — DC transition becomes an explicit await barrier; adopt per-transaction DC callbacks rather than the GPIO-event hook.
  • Roadmap SSD1327 128x128 ESP32 #5: publish benchmarks.

lexus2k added 2 commits August 2, 2026 23:08
Add an opt-in DMA transport for the ESP32 SPI HAL, guarded by
CONFIG_ESP32_SPI_DMA_ENABLE (undefined by default). With the macro off the
SPI path is byte-for-byte identical to before: internal 64-byte buffer,
max_transfer_sz=32, no DMA channel.

When enabled, begin() allocates a DMA-capable, word-aligned flush buffer
(heap_caps_malloc(MALLOC_CAP_DMA), size CONFIG_ESP32_SPI_DMA_BUFFER_SIZE,
default 512) and initializes the bus with a DMA channel (SPI_DMA_CH_AUTO,
falling back to channel 1 on pre-4.3 IDF). Bulk pixel writes are then
buffered up to the larger capacity and flushed as large DMA transactions,
which is where the throughput win comes from. Allocation failure falls back
to the internal buffer with DMA disabled.

Transfers remain blocking (spi_device_transmit), so the existing
flush-before-DC-toggle ordering in setDataMode()/OnDcChange is preserved and
the data/command line can never flip mid-transfer. Drivers are untouched -
the change lives entirely in the SPI HAL behind the template interface.

Note: the DMA path requires validation on ESP32 hardware; the default
(non-DMA) build is unaffected and the full SDL test suite (484 tests) passes.
Add a CI step that rebuilds the ESP32 example with
CONFIG_ESP32_SPI_DMA_ENABLE defined, so the opt-in DMA SPI path is
compile/link-checked on every push. It runs in the existing job and reuses
the already-cached ESP-IDF toolchain (no re-install).

The macro is injected without touching tracked source via a new optional
EXTRA_DEFS parameter in examples/Makefile.esp32, which emits a global
add_compile_definitions(...) into the generated project CMakeLists. With
EXTRA_DEFS unset the generated project is byte-identical to before.
@lexus2k
lexus2k marked this pull request as ready for review August 4, 2026 17:55
@lexus2k
lexus2k merged commit 1f8407d into master Aug 4, 2026
3 checks passed
@lexus2k
lexus2k deleted the feature/esp32-spi-dma branch August 4, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant