How does DMA channel priority and arbitration work?
When multiple DMA channels have pending transfer requests simultaneously, the DMA controller's internal arbiter decides which channel gets bus access. On STM32, this uses a two-level priority scheme:
Software priority (configurable): Each DMA channel/stream is assigned a priority level — Low, Medium, High, or Very High — via the PL bits in the configuration register. The arbiter services the highest-priority pending request first. This lets you ensure time-critical peripherals (audio DAC output that must not underrun, or ADC sampling that must not overrun) preempt less urgent transfers (UART logging, memory-to-memory copies). Assigning priorities incorrectly can cause subtle bugs: a high-priority bulk memory copy can starve the UART DMA channel long enough to cause receive overrun errors.
Hardware priority (tie-breaking): When two channels have the same software priority level, the lower-numbered channel always wins. Channel 1 beats channel 2; stream 0 beats stream 3. This is fixed in silicon and cannot be changed. It means the physical channel assignment matters — map your most time-critical peripheral to the lowest-numbered compatible channel.
Between individual data transfers (not mid-transfer), the arbiter re-evaluates priorities. This means a high-priority channel can preempt an ongoing low-priority transfer at the next data-unit boundary. The maximum latency a high-priority channel experiences is one transfer unit of the low-priority channel — typically 1-4 bus cycles. For systems with multiple DMA controllers (DMA1 and DMA2 on many STM32 families), each controller has its own independent arbiter. Contention between the two controllers is resolved by the bus matrix, which has its own arbitration rules and can cause additional latency if both controllers access the same bus slave simultaneously.
Source: DMA Q&A
