This use case shows how to set up an interrupt for when a DMA transfer is completed.
In this use case, the DMA is configured for:
- Interrupt level: Low
- Burst length: 1 byte
- Transfer count: 1024
- Source: Buffer located in RAM
- Destination: Buffer located in RAM
- Source and destination address reload mode: End of transaction
- Source and destination address direction mode: Increment
In this use case data is copied from the source buffer to the destination buffer in 1-byte bursts, until all data in the block is transferred. This example is analogus to a memcpy(destination, source, sizeof(source))
operation performed in hardware asynchronously to the CPU.
Each time the DMA transfer completes, a user-specified callback function is run to notify the user application.
Setup steps
Prerequisites
For the setup code of this use case to work, the following must be added to the project:
- System Clock Manager Service (sysclk)
- Sleep Manager Service
- PMIC Driver
A callback function, called dma_transfer_done
, must also be provided by the user application:
Example code
Add to application C-file:
#define DMA_CHANNEL 0
#define DMA_BUFFER_SIZE 1024
static uint8_t source[DMA_BUFFER_SIZE];
static uint8_t destination[DMA_BUFFER_SIZE];
static void dma_init(void)
{
memset(&dmach_conf, 0, sizeof(dmach_conf));
DMA_CH_SRCRELOAD_TRANSACTION_gc);
DMA_CH_DESTRELOAD_TRANSACTION_gc);
(uint16_t)(uintptr_t)source);
(uint16_t)(uintptr_t)destination);
}
Add to main()
:
Workflow
- Define the DMA channel that will be used for the transfer for convenience:
- Define the array length that will be the used for the source and destination buffers located in RAM:
#define DMA_BUFFER_SIZE 1024
- Create a pair of global arrays that will hold the source and destination data copied by the DMA controller channel when it is triggered:
static uint8_t source[DMA_BUFFER_SIZE];
static uint8_t destination[DMA_BUFFER_SIZE];
- Create a function
dma_init()
to intialize the DMA:
static void dma_init(void)
{
}
- Create config struct for DMA channel:
- Make sure the configuration structure is zeroed out to ensure that all values are reset to their defaults before writing new values:
memset(&dmach_conf, 0, sizeof(dmach_conf));
- Configure the DMA channel for single byte bursts, with a transfer length equal to the size of the source and destination buffers:
- Configure the DMA channel to reset the source and destination addresses at the end of the complete transaction (i.e. after
DMA_BUFFER_SIZE
bytes copied):
- Configure the DMA channel to increment the source and destination addresses after each byte transferred:
- Configure the DMA channel source and destination addresses:
(uint16_t)(uintptr_t)destination);
- Enable the DMA module so that channels can be configured in it:
-
- Attention
- Calling dma_enable() will result in a soft-reset of the entire DMA module, clearing all channel configurations. If more than one DMA channel is to be configured, this function should be called only once in the application initialization procedure only.
- Set up the DMA channel interrupt to run at low interrupt priority, and link it to the user created
dma_transfer_done()
function:
- Write the DMA channel configuration to the DMA and enable it so that it can be triggered to start the transfer:
- Initialize the clock system, PMIC driver and Sleep Manager service:
- Call our DMA init function:
- Enable global processing of interrupts:
Usage steps
Example code
Add to, e.g., main loop in application C-file:
Workflow
- Start the DMA transfer:
- Sleep while waiting for the transfer to complete: