raidersnake's ADC multiplexing

Source: SAMD51 ADC0 and ADC1 Multiplexing with DMA - Hardware / Arduino Zero - Arduino Forum

This one's interesting because raidersnake not only had a very similar objective, but also solved the issue of programming the DMAC and using SPI/SD card in the same sketch without locking up the board. However, it came with some errors that stop ADC1 from functioning continuously without some tweaks. Even then, ADC1 does not seem to be giving real results.

As of writing this, a modified version exists in the sandbox_DMA branch as dma_ADC_linked_descriptors - commit 8d065dcaa65aab43ac917459d1054ec46d87ec81

High Level Overview

TODO

Globals and Fluff

Code starts with SD setup. Each ADC gets its own buffer to store results. The buffer is then split between each pin.

Then, a 4 element array is initialized with the pins for the ADC multiplexor. These are the input pins to be read from.

Next, a simple descriptor struct (dmacdescriptor) is declared.

Array pointers are made for the writeback section and descriptor section to reside in SRAM. There's also a declaration for descriptor, which will be used to make copying descriptors over to the descriptor section easier. There's also a 2 element array of dmacdescriptors made in preparation to link the two active ones together.

setup()

The SD/SPI stuff is initialized with the parameters from above. Since the SPI library has its own DMAC setup, the following lines are used to realign the descriptor section and writeback section addresses to those set by the SPI library:

descriptor_section =  reinterpret_cast<dmacdescriptor(*)[DMAC_CH_NUM]>(DMAC->BASEADDR.reg); //point array pointer to BASEADDR defined by SD.begin

    wrb =  reinterpret_cast<dmacdescriptor(*)[DMAC_CH_NUM]>(DMAC->WRBADDR.reg);                 //point array pointer to WRBADDR defined by SD.begin

The DMAC is then enabled. At the same time, all priority levels are enabled via:

    DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);

Referencing the datasheet and the definition for DMAC_CTRL_LVLEN, the latter term in the bitwise or operator sets the priority-level-enable bits all to 1.

ADC DMA Sequencing Setup

DMAC Channel 2's priority is set to 3 (highest). It's trigger source is set to ADC0's DSEQ trigger. The conditions for this trigger are shown in Section 45.6.3.4 of the SAMD51 datasheet. When this trigger request comes, it triggers a burst transfer.

Next, the empty descriptor is configured. The next descriptor address is set to itself, creating a circular descriptor., and dstaddr is . The descriptor is configured according to datasheet Section 45.6.3.4 for DMA Sequencing. The descriptor is then set to be valid.

descriptor is modified in order to make copying easier:

DMAC ADC0 Setup

DMAC Channel 3 is set to priority level 3. It's trigger source is set to ADC0's RESRDY interrupt, which triggers when a ADC0 result is ready. Channel 3 is configured to do burst transfers.

descriptor is modified again in order to make copying easier:

descriptor is modified again in order to make copying easier:

DMAC ADC1 Setup

DMAC Channel 4 is set to priority level 3. It's trigger source is set to ADC0's RESRDY interrupt, which triggers when a ADC1 result is ready. Channel 4 is configured to do burst transfers.

descriptor is modified again in order to make copying easier:

descriptor is modified again in order to make copying easier: