Yes, exactly, the default behavior it to work exactly the same as we always have.
This change means libraries like ObjectFLED and OctoWS2811 which are sensitive to ~100ns latency can clear their DMA_DCHPRI_DPA bit.
Before this change, doing so had no effect, because all other DMA channels defaulted to their bit DMA_DCHPRI_ECP clear. But now that DMA_DCHPRI_ECP defaults to set on all DMA usage, DMA_DCHPRI_DPA can become useful on just some high priority channels. So now (or soon...) when you use Audio and a DMA-based display library and ObjectFLED/FastLED together in a project, code inside ObjectFLED would clear its DMA_DCHPRI_DPA bits, which will give it preemption over audio and display DMA because those less timing critical uses will default to allowing preemption. The assumption is most ordinary libraries that use DMA to feed peripherals with FIFO won't mess with these preemption bits.
The problem I (and others) are encountering is actually the reverse: audio needs priority (pre-emptive capability) over DMA being used to update displays. We can't "turn on" preemptive capability for channels used by the audio library because they aren't exposed outside their host objects.
Also important will the priorty settings. For the normal case of static instances used by nearly all hardware interface libraries, you would put the instances of high priority libraries first. The normal way of DMAChannel allocation will use the higher priority configured channels first.
I don't think this is correct? Currently channels are allocated starting with the lowest first, which also has the lowest priority.
So in the case of Audio and a DMA display library and ObjectFLED/FastLED, you would need to put the FastLED instances near the top of your code. Then put the audio and display instances later.
For global objects in different files (static or otherwise), there's no way to ensure the order of initialization. I've discussed this in the other thread; there really needs to be a bulletproof way to initialize a high or low priority channel without relying on indeterminate compiler behavior. At the least we need access to DMAChannels used in the audio library even just to know which channel numbers they have been assigned, so they can be manually prioritized with respect to other channels.
But if the absense of libraries specifically clearing their DMA_DCHPRI_ECP bit, the idea is this change keeps all DMA usage exactly the same as we've always had.
The changes I've done also maintain the existing behavior - by default channels will have preemptive capability but cannot be preempted, with an option that channels can be initialized as preemptible.
I also increased the available channel count up to 32 to match the hardware.
Might also be worth mentioning the hardware limitation that preemption happens at minor loop granularity. If a lower priority DMA channel configures a large amount of data to be moved on each minor loop, it will still hog the DMA controller because a higher priorty DMA channel can't preempt until the minor loop completes. This change is far from a magic bullet that will make latency sensitive DMA like ObjectFLED and OctoWS2811 work flawlessly with all other DMA-based libraries. It should help in many common cases with small minor loops, but it can't guarantee timing.
I don't believe this is the case. The reference manual strongly implies that preemption can interrupt the minor loop:
- page 91, "After eDMA activates a channel to execute, it runs until the minor loop completes,
unless preempted by a higher priority channel." This indicates a minor loop can be interrupted by preemption.
- page 99, "After the restored channel
completes one read/write sequence, it is again eligible for preemption. If any higher priority channel is requesting service, the restored channel is suspended and the higher priority channel is served." One read/write sequence refers to the larger of SSIZE or DSIZE, not a complete minor loop.
- page 101, "DMA arbitration can occur after each minor loop, and
one level of minor loop DMA preemption is allowed." There's a distinction made here between ordinary arbitration (performed based on channel priority) and preemption. If preemption could only happen at the end of a minor loop it would serve no purpose because arbitration already occurs at that time.