2022-03-08 08:44 AM
I'm trying to use DMA to handle my incoming Rx data and, ideally, I'd like to just increment the index to keep track of the incoming data, essentially like this:
#define uartsize 2000
#define dma_buffer_interrupt_size 1
uint8_t UART_in_Buffer[uartsize];
HAL_UART_Receive_DMA(&huart3, &UART_in_Buffer[head_index], dma_buffer_interrupt_size);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
head_index = (head_index + dma_buffer_interrupt_size) % uartsize;
}
The problem I'm having is that when I setup a circular buffer, once it enters HAL_UART_RxCpltCallback(), it resets the index to 0. So if I have the dma_buffer_interrupt_size set to 3, for instance, it will enter that interrupt routine every 3 bytes, increment the count, and then if I send another 3 bytes, it will write over the first 3 bytes of the array.
I can get around that by doing the following:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
head_index = (head_index + dma_buffer_interrupt_size) % uartsize;
HAL_UART_DMAStop(&huart3);
HAL_UART_Receive_DMA(&huart3, &UART_in_Buffer[head_index], dma_buffer_interrupt_size);
}
This will change the starting point to the head location, but it uses a lot of code to do this and rules out any advtantages of doing this over a normal buffer (in fact, it might essentially just have recreated the functionality of a normal buffer over a circular buffer).
Is there a way to setup a circular buffer so it's incrementing "head_index" after every byte but not resetting the index back to 0 every time it enters the interrupt? There's not really a way to manage the buffer at this point otherwise.
Currently, I can either count how many bytes I've received (but write over the previous ones) or I can write the data to the DMA buffer but not be able to track how many bytes have come in.
Solved! Go to Solution.
2022-03-08 09:55 AM
That's actually pretty perfect and seems to greatly simplify the code. I ended up moving to this:
#define uartsize 2000
uint8_t UART_in_Buffer[uartsize];
HAL_UART_Receive_DMA(&pc_uart, UART_in_Buffer, uartsize);
while (1)
{
head_index = (uartsize - DMA1_Stream0->NDTR) % uartsize;
}
Seems to work pretty well. Thanks for the help!
2022-03-08 09:15 AM
Set up circular DMA which is always running and use the NDTR register to track the head index. You will still get half- and full-complete callbacks if you want them, but you could also just poll NDTR for new bytes.
Edit: there is also HAL_UARTEx_ReceiveToIdle_DMA which you can use in circular mode and will generate a callback at idle conditions as well as half- and full-complete flags.
2022-03-08 09:55 AM
That's actually pretty perfect and seems to greatly simplify the code. I ended up moving to this:
#define uartsize 2000
uint8_t UART_in_Buffer[uartsize];
HAL_UART_Receive_DMA(&pc_uart, UART_in_Buffer, uartsize);
while (1)
{
head_index = (uartsize - DMA1_Stream0->NDTR) % uartsize;
}
Seems to work pretty well. Thanks for the help!