Independent finite UART and SPI DMA controllers

The existing typed faces, shared immutable operations tables and caller-owned request/state storage remain authoritative. A cold instance selects one exact reviewed register/IRQ/DMA tuple. There is no stream allocator, runtime registry, extra mutable route pointer or hidden copy pool. The mutable DMA state layout is unchanged; the additional routes consume only selected instances.

Provider

First route

Second route

STM32 UART

USART1, APB2 84 MHz, DMA2 stream7 channel4

USART2, APB1 42 MHz, DMA1 stream6 channel4

GD32 UART

USART0, APB2 100 MHz, literal DMA1 channel7 selector4

USART1, APB1 50 MHz, literal DMA0 channel6 selector4

STM32 SPI

SPI1, APB2 84 MHz, DMA2 RXstream0/TXstream3 channel3

SPI2, APB1 42 MHz, DMA1 RXstream3/TXstream4 channel0

GD32 SPI

SPI4, APB2 100 MHz, literal DMA1 RXchannel3/TXchannel4 selector2

SPI0, APB2 100 MHz, literal DMA1 RXchannel2/TXchannel5 selector3

Reviewed silicon AFs are USART2/USART1 PA2/PA3 AF7, SPI2 PB13/PB14/PB15 AF5, and SPI0 PA5/PA6/PA7 AF5. These facts do not supply external Board wiring, connectors, electrical pull-ups or qualification. Typed configuration remains the single assembly authority. The second UART TX conflicts with the first I2C TX engine and must be rejected in resource resolution. GD literal DMA0/1 is distinct from public opaque controller IDs 1/2.

STM UART initialization uses retained exact IRQ, DMA, stream and clock facts. STM SPI initialization validates the selected bus, clock and engine pointers; an idle bus whose DMA vectors remain enabled cannot be acquired by another cold object. GD cold _initialize_at methods select only the two maintained readonly controller descriptors. Existing primary initializers remain thin wrappers. Duplicate/live hardware, retained enabled DMA publishers and unsupported tuples reject before effects. A disabled engine still has an owner while its vector lease is enabled; cold acquisition preserves that owner’s flags/priority.

Finite DMA completion is independent from wire completion. Hot W1C clears only observed completion/half-completion bits; fresh error bits remain latched. The provider reads errors after actual engine withdrawal and again before settlement. It never reports success after a detected DMA error. Both engines, IRQ sources and SPI wire must drain before CS release and SETTLED; UART also requires true TC. Failed withdrawal retains QUARANTINED requests and buffers. Peer flags, clocks, vectors, CS and loans remain independent. Shared DMA clock ownership belongs to outer assembly and is never released by an individual stop.

Explicit SPI fixed-memory flags preserve caller-owned dummy/discard scalar storage, exact one-byte DMA domains and MINC identity. There is no implicit scratch fallback. STM SPI2 polling abort/recovery pulses APB1 SPI2 reset; it does not reset the neighboring APB2 SPI1 controller.

Only finite second-controller UART TX/SPI DMA is implemented here. Existing primary receive modes remain covered by their own suites; secondary continuous RX is not admitted through these new facts. Actual GoogleTest/GoogleMock MMIO regressions and strict ARM SDK object/layout reports are development evidence. Factory/selected whole-image validation is recorded separately. Physical DMA, IRQ latency, CS/wire timing and Board HIL remain not executed.