1
votes

I'm using a STM32F4 for receiving data from a FPGA (now it only relays data from a PC) using DMA UART. The DMA UART is working as it should, but it can only give an interrupt when the buffer for the UART it is half full or full. The problem is that I want to know if I got new data in the buffer without it being half or full.

In short I am looking for a register which point to where the next byte from the UART should go in the DMA buffer. Does anyone know of a register like that.

Thank you!

5
The STM32F4 datasheet should know...DigitalNinja
The number of transfers in the DMA registers shows if you had any transfers and using the simple arithmetic where the pointer in the buffer is. with the DMA interrupts it gives you all the information needed0___________
You wont be able to read byte-by-byte using DMA. Only wait for the data and parse data in buffer after timeout or full buffer. If you need read data by every byte, then use IT. That is much better.Bulkin

5 Answers

2
votes

The DMA has a CNDTR register (be aware that it counts down)

2
votes

Thanks for the help, I found what I was looking for.

uint32_t bytesRx DMA1_Stream1->NDTR;

and

UART_HandleTypeDef huart3;
uint32_t bytesRx = huart3.hdmarx->Instance->NDTR;

Both of them works for finding how many bytes that have been received, observe that NDTR counts down.

0
votes

Do you use HALs? We use this code to know how many bytes we've received:

UART_HandleTypeDef              *pHandleUart;
(...)
static uint8_t Uart_RxBufferPointerCheck(void)
{
    uint8_t returnValue = 0;

    rxUartBuffer.last = ( (uint16_t)UART_MAX_BUFFER_LENGTH - Uart_Dma_GetPeripheralNumberOfData() );

    if ( rxUartBuffer.last >= rxUartBuffer.first )
    {
        returnValue = 1;
    }

    return ( returnValue );
}

static uint16_t Uart_Dma_GetPeripheralNumberOfData(void)
{
    return (uint16_t) pHandleUart->hdmarx->Instance->NDTR;
}   

rxUartBuffer.first is modified when we read those bytes. This code is fo F7 uC, I hope it also works on F4.

0
votes

One way would be to poll and check the serial Rx buffer for data or check the value of hdmarx->Instance->CNDTR if changed from the default value of buffer size.

The second option would be to use an IDLE interrupt to know if data is received, this can be done by adding a few lines in HAL_UART_IRQHandler

if((__HAL_UART_GET_IT(huart, UART_IT_IDLE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_IDLE) != RESET))
{ 
    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_IDLEF);
}
-1
votes

I tried to look your part up, but only found marketing pages. To get what you want, disable the DMA. The purpose in the DMA is to lessen the interrupt load, and perhaps maintain a wire rate stream if your cpu can’t keep up with the interrupt rate. Since you want the interrupt for notification, the DMA is sorta pointless. Worse, it is keeping you from seeing the interrupt.

Often US?ARTs have an on-board fifo, which alleviates the interrupt rate somewhat, while letting you synchronize with the beginning of a burst or whatever your purpose is.