2014-07-16 01:45 AM
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-usart2014-07-16 01:57 AM
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.
2014-08-05 07:59 AM
2014-08-05 08:43 AM
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.
2014-08-06 03:18 AM
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=16COM_RS232_DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_NormalCOM_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_HalfFullCOM_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);