Until now I never used a microcontroller with an embedded DMA controller, so I always use the CPU to move data from memory to memory, from memory to peripheral, from peripheral to memory.
The micro usually have only a two-byte hardware FIFO (the byte currently shifting in and the previous completely received byte). So I often implement a sw FIFO buffer for receiving data from UART. In the ISR of receiving character, I move data from peripheral (UART) to memory (FIFO buffer). I implement a uart_getchar() function that checks if a new byte is present in the FIFO an returns that byte or EOF. This function is called from the application (background) not in the foreground.
#define ROLLOVER(x, max) (((x) + 1) >= (max) ? 0 : (x + 1))
uint8_t rx_buff[32]; size_t rx_size; volatile size_t rx_in; size_t rx_out;
/* ISR of a new received character */ void isr_rx(void) { size_t i = ROLLOVER(rx_in, rx_size); if(i == rx_out) return; // Rx FIFO full, discard character rx_buff[rx_in] = c; rx_in = i; }
/* uart_getchar() function */ int uart_getchar(void) { if (rx_out == rx_in) return EOF; // FIFO empty unsigned char data; data = rx_buff[rx_out]; rx_out = ROLLOVER(rx_out, rx_size); return data; }
Now I'm starting using new microcontrollers that embed a DMA engine, for example SAM C21 Cortex-M0+ from Atmel (I think many Cortex-M0+ micros out there integrate a DMA engine).
So I'm asking if it is possible to avoid completely the ISR and use the DMA to move received character in the FIFO buffer.
I read the datasheet, but I couldn't found a solution to my problem.
First of all, the destination memory address could be fixed or auto-incrementing, but there isn't a mechanism to wrap-around (FIFO buffer is a *circular* array, so after pushing N bytes, the address should start again from the beginning). Maybe I have to configure the DMA for a transaction with a byte count equals to the size of the FIFO buffer. When the last byte is received, the transaction ends and an interrupt could be raises (if correctly configured). In the relevant ISR, a new DMA transaction could be started (with the destination memory address equals to the beginning of the FIFO buffer).
Another issue is how the application (background) could know how many bytes are present in the FIFO buffer so it can pop and process them as it wants.