cancel
Showing results for 
Search instead for 
Did you mean: 

Building a DMA driven serial handler: How can I drain FIFO

subscriptions
Associate II
Posted on July 16, 2014 at 10:45

I'm trying to understand how to build a buffered serial handler using DMA.

I currently have an interrupt driven handler, that adds characters received to a circular buffer, but due to the lack of a FIFO on the USARTs, I'm occasionally getting overruns when I can't service the interrupt.

As a result, I'd like to build a DMA based implementation instead.

I've seen the USART/DMA sample code, and am pretty confident I could build a solution using double buffering, but what I don't understand is how I can drain the FIFO when the line goes idle, for instance if I get a single byte, and then nothing more.

Any pointers to documentation for that?

#usart-dma-fifo #dma-stm32f217-usart
4 REPLIES 4
subscriptions
Associate II
Posted on July 16, 2014 at 10:57

I found this on page 315 of

Doc ID 018909 Rev 6.

I assume this works when using double buffer mode too?

If so, if I decide I've waited long enough, I assume I can disable the DMA stream, which will flush the buffers, and then once the DMA is completed, immediately set up the next transfer to a new set of memory locations.  I'm still worried I might lose bytes in that instant though.

 

FIFO flush

The FIFO can be flushed when the stream is disabled by resetting the EN bit in the

DMA_SxCR register and when the stream is configured to manage peripheral-to-memory or

memory-to-memory transfers: If some data are still present in the FIFO when the stream is

disabled, the DMA controller continues transferring the remaining data to the destination

(even though stream is effectively disabled). When this flush is completed, the transfer

complete status bit (TCIFx) in the DMA_LISR or DMA_HISR register is set.

yuvalk
Associate II
Posted on August 05, 2014 at 16:59

Hi,

I basically have the the same problem. I'm trying to use DMA when receiving unknown number of bytes. I tried to follow AN3109 but I see that the DMA will not fill the buffer I've assigned to DMA_Memory0BaseAddr when the USART interrupt is triggered. The buffer is filled ONLY when I sent more bytes then  DMA_BufferSize, which beat the purpose of the app note solution.

I was wandering if you found a solution to your problem you are willing to share.

 

Posted on August 05, 2014 at 17:43

Receiving is definitely more problematic. I don't think I'd use double buffer, but rather HT and TC interrupts, and periodic review. You can use 16-bit words from the USART, and you could mark/tag buffer entries as new or processed using unused bits.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
yuvalk
Associate II
Posted on August 06, 2014 at 12:18

Thanks Clive1 for the advice.

I'm trying to implement your suggestion and having trouble understanding with my DMA  configuration (see below) why the DMA transfer the data in word size bursts.

e.g. when I send 15 bytes on USART I get only 12 in my buffer. when I send 16, I'll get all 16 bytes in the buffer.

I thought the DataSize_Byte will take care of it (on the memory side and peripheral side).

Any ideas?

/* Configure DMA controller to manage USART RX ----------*/

DMA_DeInit(GPRS_COM_RX_DMA_STREAM);

COM_RS232_DMA_InitStructure.DMA_Channel = GPRS_COM_RX_DMA_CHANNEL;

COM_RS232_DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

COM_RS232_DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)COM_RS232_FIFOBuffer;

COM_RS232_DMA_InitStructure.DMA_BufferSize = (uint16_t)FIFO_SIZE;//FIFO_SIZE=16

COM_RS232_DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal

COM_RS232_DMA_InitStructure.DMA_PeripheralBaseAddr = GPRS_COM_DR_ADDRESS;

COM_RS232_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

COM_RS232_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

COM_RS232_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

COM_RS232_DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

COM_RS232_DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

COM_RS232_DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;

COM_RS232_DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;//DMA_FIFOThreshold_Full;//DMA_FIFOThreshold_HalfFull

COM_RS232_DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

COM_RS232_DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_Init(GPRS_COM_RX_DMA_STREAM, &COM_RS232_DMA_InitStructure);

DMA_ITConfig(GPRS_COM_RX_DMA_STREAM, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE | DMA_IT_DME | DMA_IT_FE, ENABLE);