开发者

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

开发者 https://www.devze.com 2023-03-22 16:29 出处:网络
I am looking for ideas for a receive buffer for a small application dealing with 15 byte packets at 921.6Kbaud over rs485. I开发者_如何学JAVA am thinking of using a circular buffer as the interface be

I am looking for ideas for a receive buffer for a small application dealing with 15 byte packets at 921.6Kbaud over rs485. I开发者_如何学JAVA 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) { do stuff } 

in the

while (;;) {do forever} 

part of main but I have been told this is not acceptable.

How do people deal with their uarts under similar circumstances?


ISR should fill a FIFO. Main should consume it.

Bellow a very simple fifo algorithm:

#define RINGFIFO_SIZE (1024)              /* serial buffer in bytes (power 2)   */
#define RINGFIFO_MASK (RINGFIFO_SIZE-1ul) /* buffer size mask                   */

/* Buffer read / write macros                                                 */
#define RINGFIFO_RESET(ringFifo)      {ringFifo.rdIdx = ringFifo.wrIdx = 0;}
#define RINGFIFO_WR(ringFifo, dataIn) {ringFifo.data[RINGFIFO_MASK & ringFifo.wrIdx++] = (dataIn);}
#define RINGFIFO_RD(ringFifo, dataOut){ringFifo.rdIdx++; dataOut = ringFifo.data[RINGFIFO_MASK & (ringFifo.rdIdx-1)];}
#define RINGFIFO_EMPTY(ringFifo)      (ringFifo.rdIdx == ringFifo.wrIdx)
#define RINGFIFO_FULL(ringFifo)       ((RINGFIFO_MASK & ringFifo.rdIdx) == (RINGFIFO_MASK & (ringFifo.wrIdx+1)))
#define RINGFIFO_COUNT(ringFifo)      (RINGFIFO_MASK & (ringFifo.wrIdx - ringFifo.rdIdx))

/* buffer type                                                                */
typedef struct{
    uint32_t size;
    uint32_t wrIdx;
    uint32_t rdIdx;
    uint8_t data[RINGFIFO_SIZE];
} RingFifo_t;
RingFifo_t gUartFifo;

(Care must be taken with this FIFO algorithm, size MUST be power of 2)

The ISR should behave like this:

void ISR_Handler()
{
    uint8_t c;
    while(UART_NotEmpty()) {
        c = UART_GetByte();
        RINGFIFO_WR(gUartFifo, c);
    }
}

And the Main:

while(1)
{
    if (!RINGFIFO_EMPTY(gUartFifo)) {
        /* consume fifo using RINGFIFO_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_t ptrToPacket;
uint32_t packetSize;
while(1)
{
    if (!Uart_HasValidPacket()) {
        Uart_GetPacket(&ptrToPacket, &packetSize)
        /* Process packet using ptrToPacket and packetSize */
    }    
}


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)(uartindex-localindex) 

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消