You are on page 1of 2

Correct way of implementing a uart receive buffer in a small ARM microcontroller? - ...

Page 1 of 2



Correct way of implementing a uart receive buffer in a small ARM microcontroller?

I am looking for ideas for a receive buffer for a small application dealing with 15 byte packets at 921.6Kbaud over rs485. I am thinking of using a circular buffer as the interface between the UART ISR and main. As it is a microprocessor I was wanting to put while(uartindex!=localindex){dostuff} in the while(;;){doforever} part of main but I have been told this is not acceptable. How do people deal with their uarts under similar circumstances?
arm uart circular-buffer

edited Sep 16 '13 at 6:08 icktoofay 53.8k 5 74 105

asked Jul 25 '11 at 21:23 Meter Code 16 3

Lol - I'm an ARM asm guy and this made me giggle out of my own ignorance. I'll watch this to enlighten myself going forward :) Michael Dorgan Jul 25 '11 at 21:28 I have done things like that and had no problems, so am curious to see what folks say about this and why it is wrong. dwelch Jul 26 '11 at 1:15 The only thing that can go wrong is not to get the concept of a memory barrier. artless noise Mar 10 '13 at 20:43

3 Answers
ISR should fill a FIFO. Main should consume it. Bellow a very simple fifo algorithm: #defineRINGFIFO_SIZE(1024)/*serialbufferinbytes(power2)*/ #defineRINGFIFO_MASK(RINGFIFO_SIZE1ul)/*buffersizemask*/ /*Bufferread/writemacros*/ #defineRINGFIFO_RESET(ringFifo){ringFifo.rdIdx=ringFifo.wrIdx=0;} #defineRINGFIFO_WR(ringFifo,dataIn){[RINGFIFO_MASK&ringFifo.wrIdx++]= #defineRINGFIFO_RD(ringFifo,dataOut){ringFifo.rdIdx++;[RINGFI #defineRINGFIFO_EMPTY(ringFifo)(ringFifo.rdIdx==ringFifo.wrIdx) #defineRINGFIFO_FULL(ringFifo)((RINGFIFO_MASK&ringFifo.rdIdx)==(RINGFIFO_MAS #defineRINGFIFO_COUNT(ringFifo)(RINGFIFO_MASK&(ringFifo.wrIdxringFifo.rdIdx /*buffertype*/ typedefstruct{ uint32_tsize; uint32_twrIdx; uint32_trdIdx; uint8_tdata[RINGFIFO_SIZE]; }RingFifo_t; RingFifo_tgUartFifo;

(Care must be taken with this FIFO algorithm, size MUST be power of 2) The ISR should behave like this: voidISR_Handler() { uint8_tc; while(UART_NotEmpty()){ c=UART_GetByte(); 10/02/2014

Correct way of implementing a uart receive buffer in a small ARM microcontroller? - ... Page 2 of 2

RINGFIFO_WR(gUartFifo,c); } } And the Main: while(1) { if(!RINGFIFO_EMPTY(gUartFifo)){ /*consumefifousingRINGFIFO_RD*/ } } This algorithm reads the FIFO directly from the main loop, you should use a intermediate layer that checks if there is a full packet in the buffer, and deals with it, in such a manner that main would be like this: uint8_tptrToPacket; uint32_tpacketSize; while(1) { if(!Uart_HasValidPacket()){ Uart_GetPacket(&ptrToPacket,&packetSize) /*ProcesspacketusingptrToPacketandpacketSize*/ } }
answered Mar 11 '13 at 19:35 fanl 467 1 9

The approach you suggest would probably be workable if the uartindex is never written in the main loop (except to initialize it while interrupts are disabled), and localindex is never touched by the interrupt routine. I would suggest that you make your buffer size be a power of 2, use unsigned integers for the two indices, and allow them to count freely over their full 32-bit size; use bit masking when indexing your buffer in both the "stuff" and "fetch" routines. If you do that, then (unsigned)(uartindexlocalindex) should indicate how many characters are in the buffer, even when it's completely full, without requiring special-case behavior in the buffer-full case and without limiting an N-byte buffer to holding N-1 items. Note that while the typecast in the aforementioned expression isn't strictly necessary, I would recommend including it since it makes obvious that the wrapping behavior when subtracting unsigned quantities is deliberate and expected.
answered Mar 11 '13 at 17:35 supercat 22.6k 26 44

See: Wikipedia's non-blocking algorithms. Specifically, single-reader single-writer ring buffer FIFO are listed as being implemented with out any special atomic primitives. I am also quite sure that Donald Knuth's The Art of Computer Programming has some paragraphs on this topic. The only real caveats are that you need memory barriers and atomic writes (don't write half a pointer/int). You can always use buffer indexes that are atomic; for instance a byte if that is all the CPU supports. For an ARM, there is no such restrictions. Also, Linux's kfifo.h has an implementation of such a ring buffer and it is used every where in the Linux kernel on multiple architectures in many similar circumstances.
answered Mar 10 '13 at 3:18 artless noise 5,955 2 13 40

Not the answer you're looking for? Browse other questions tagged arm uart
circular-buffer or ask your own question. 10/02/2014