SAMD51 - DMA for USB

Hi!

I am having issues understanding how DMA works in the SAMD51 processor. I am converting a SAMD21 library to run with D51 chips. From my understanding after reading both the data sheets is that the whole DMA register layout changed significantly.

The D51 seems to have many individual controllers now instead of a register to set which one you want to use.

I am trying to remove the below errors from a project that I am working on (apologies in advanced for the mass text copy - I'll leave the code at the end).

I know that trying to compile for a SAMD51 is not going to work at all. I guess the questions I have to help get past this are:

Questions:
1/ Is there a specific DMA controller for the USB and SPI?
2/ What is the best way to try and convert the SAMD21 DMA to SAMD51?

Any assistance or pointers would be greatly appreciated :slight_smile:

Code File

Error Log Output

./bsp/bsp_dma.h:16:37: error: 'DMAC_CHCTRLB_TRIGACT_BLOCK_Val' was not declared in this scope
     DMA_TRIGGER_ACTON_BLOCK       = DMAC_CHCTRLB_TRIGACT_BLOCK_Val,
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./bsp/bsp_dma.h:16:37: note: suggested alternative: 'DMAC_CHCTRLA_TRIGACT_BLOCK_Val'
     DMA_TRIGGER_ACTON_BLOCK       = DMAC_CHCTRLB_TRIGACT_BLOCK_Val,
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                     DMAC_CHCTRLA_TRIGACT_BLOCK_Val
./bsp/bsp_dma.h:17:37: error: 'DMAC_CHCTRLB_TRIGACT_BEAT_Val' was not declared in this scope
     DMA_TRIGGER_ACTON_BEAT        = DMAC_CHCTRLB_TRIGACT_BEAT_Val,
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./bsp/bsp_dma.h:17:37: note: suggested alternative: 'DMAC_CHCTRLA_TRIGACT_BURST_Val'
     DMA_TRIGGER_ACTON_BEAT        = DMAC_CHCTRLB_TRIGACT_BEAT_Val,
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                     DMAC_CHCTRLA_TRIGACT_BURST_Val
./bsp/bsp_dma.h:18:37: error: 'DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val' was not declared in this scope
     DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val,
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./bsp/bsp_dma.h:18:37: note: suggested alternative: 'DMAC_CHCTRLA_TRIGACT_TRANSACTION_Val'
     DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val,
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                     DMAC_CHCTRLA_TRIGACT_TRANSACTION_Val
./bsp/bsp_dma.h: In function 'void dmac_set_action(uint8_t, uint8_t)':
./bsp/bsp_dma.h:97:11: error: 'struct Dmac' has no member named 'CHID'
     DMAC->CHID.bit.ID         = channel;
           ^~~~
./bsp/bsp_dma.h:98:11: error: 'struct Dmac' has no member named 'CHCTRLB'; did you mean 'CTRL'?
     DMAC->CHCTRLB.bit.TRIGACT = action;
           ^~~~~~~
           CTRL
./bsp/bsp_dma.h: In function 'void dmac_set_trigger(uint8_t, uint8_t)':
./bsp/bsp_dma.h:103:11: error: 'struct Dmac' has no member named 'CHID'
     DMAC->CHID.bit.ID         = channel;
           ^~~~
./bsp/bsp_dma.h:104:11: error: 'struct Dmac' has no member named 'CHCTRLB'; did you mean 'CTRL'?
     DMAC->CHCTRLB.bit.TRIGSRC = trigger;
           ^~~~~~~
           CTRL
./bsp/bsp_dma.h: In function 'void dmac_start(uint8_t)':
./bsp/bsp_dma.h:109:11: error: 'struct Dmac' has no member named 'CHID'
     DMAC->CHID.bit.ID    = channel;
           ^~~~
./bsp/bsp_dma.h:110:11: error: 'struct Dmac' has no member named 'CHCTRLA'; did you mean 'CTRL'?
     DMAC->CHCTRLA.bit.ENABLE = 1; // Enable the transfer channel
           ^~~~~~~
           CTRL
./bsp/bsp_dma.h:112:18: error: 'struct Dmac' has no member named 'CHCTRLA'; did you mean 'CTRL'?
     while(!DMAC->CHCTRLA.bit.ENABLE);
                  ^~~~~~~
                  CTRL
./bsp/bsp_dma.h: In function 'void dmac_abort(uint8_t)':
./bsp/bsp_dma.h:117:11: error: 'struct Dmac' has no member named 'CHID'
     DMAC->CHID.bit.ID = channel; // Select channel
           ^~~~
./bsp/bsp_dma.h:118:11: error: 'struct Dmac' has no member named 'CHCTRLA'; did you mean 'CTRL'?
     DMAC->CHCTRLA.reg = 0;       // Disable
           ^~~~~~~
           CTRL
./bsp/bsp_dma.h:120:17: error: 'struct Dmac' has no member named 'CHCTRLA'; did you mean 'CTRL'?
     while(DMAC->CHCTRLA.bit.ENABLE);
                 ^~~~~~~
                 CTRL
Makefile:205: recipe for target 'build/robohatmm1/source/AOSERCOM.o' failed

Hi wallarug,

1/ Is there a specific DMA controller for the USB and SPI?

Yes, the SAMD51's USB has a built-in DMA that's separate from it's generic Direct Memory Access Controller (DMAC). The DMAC can be used for memory-to-memory, peripheral-to-memory and memory-to-peripheral operations.

2/ What is the best way to try and convert the SAMD21 DMA to SAMD51?

The DMAC for the SAMD21 and SAMD51 are similar, but there are some register differences, for example:

During intialisation:

#ifdef __SAMD51__
 // Set the DMAC level, trigger source and trigger action to burst (trigger for every byte transmitted)
 DMAC->Channel[0].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(SERCOM0_DMAC_ID_TX) | DMAC_CHCTRLA_TRIGACT_BURST; 
 DMAC->Channel[0].CHPRILVL.reg = DMAC_CHPRILVL_PRILVL(0); // Set the channel priority level
#else 
 DMAC->CHID.reg = DMAC_CHID_ID(0);                        // Activate specified DMAC channel 
 // Set the DMAC level, trigger source and trigger action to beat (trigger for every byte transmitted)
 DMAC->CHCTRLB.reg = DMAC_CHCTRLB_LVL(0) | DMAC_CHCTRLB_TRIGSRC(SERCOM0_DMAC_ID_TX) | DMAC_CHCTRLB_TRIGACT_BEAT; 
#endif

Enabling the DMAC channel:

#ifdef __SAMD51__
 DMAC->Channel[0].CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; // Enable the DMAC channel
#else
 DMAC->CHID.reg = DMAC_CHID_ID(0);            // Activate the DMAC channel
 DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE;    // Enable the DMAC channel
#endif

The SAMD21 has 12 DMAC channels, while the SAMD51 has 32. The DMAC descriptors for both microcontrollers operate in a similar manner.