Usually you want to use sequences with DMA.
Using this pattern (note, I have not used Atmel SAM devices, but works on STM32, and the idea should work on any decent modern micro):
typedef struct __attribute__((packed))
{
uint16_t voltage;
int16_t current;
} adc_datapoint_t;
#define BUFLEN 1
volatile adc_datapoint_t adc_buf[BUFLEN];
void init_adc()
{
DMA.memory_address = adc_buf;
DMA.transfer_length = sizeof adc_buf / sizeof adc_buf[0]; // also known as number of elements
DMA.transfer_size = 16 bits (in this case, because of 16-bit ADC)
DMA.mode = continuous / wrap around / whatever it is called.
Start DMA
Configure ADC channel sequence to match that struct
Configure ADC in DMA mode
Etc.
Start ADC
}
If you do this, you can just access the struct directly, getting latest measurements, whenever and wherever you want! No need to manage anything, except when you need to know that all values within the struct are from the same "round", converted in the same order, then you can use DMA completion interrupt, for example.
But in my projects, I have noticed that just having the latest value is often exactly what is needed.