Правильный способ реализации приемного буфера uart в маленьком микроконтроллере ARM? - PullRequest
6 голосов
/ 26 июля 2011

Я ищу идеи для буфера приема для небольшого приложения, работающего с 15-байтовыми пакетами со скоростью 921,6 Кбод вместо RS485. Я имею в виду использование кругового буфера в качестве интерфейса между ISR UART и основной. Поскольку это микропроцессор, я хотел поставить

while (uartindex!=localindex) { do stuff } 

в

while (;;) {do forever} 

часть основного, но мне сказали, что это неприемлемо.

Как люди справляются со своими уартами при сходных обстоятельствах?

Ответы [ 2 ]

5 голосов
/ 11 марта 2013

ISR должен заполнить FIFO.Main должен его потреблять.

Ниже приведен очень простой алгоритм fifo:

#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;

(этот алгоритм FIFO должен быть осторожен, размер ДОЛЖЕН быть степенью 2)

ISR должен вести себя так:

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

И Main:

while(1)
{
    if (!RINGFIFO_EMPTY(gUartFifo)) {
        /* consume fifo using RINGFIFO_RD */
    }    
}

Этот алгоритм считывает FIFO непосредственно из основного цикла, вы должны использовать промежуточный уровень, который проверяет, есть лиявляется полным пакетом в буфере и обрабатывает его таким образом, что main будет выглядеть так:

uint8_t ptrToPacket;
uint32_t packetSize;
while(1)
{
    if (!Uart_HasValidPacket()) {
        Uart_GetPacket(&ptrToPacket, &packetSize)
        /* Process packet using ptrToPacket and packetSize */
    }    
}
2 голосов
/ 11 марта 2013

Подход, который вы предлагаете, вероятно, будет работать, если uartindex никогда не записывается в главном цикле (кроме как для его инициализации, когда прерывания отключены), и localindex никогда не затрагивается подпрограммой прерывания.

Я бы посоветовал вам сделать размер буфера степенью 2, использовать целые числа без знака для двух индексов и позволить им свободно считать по своему полному 32-битному размеру;используйте битовую маскировку при индексации буфера в подпрограммах «stuff» и «fetch».Если вы это сделаете, то

(unsigned)(uartindex-localindex) 

должно указывать, сколько символов находится в буфере, даже если он полностью заполнен, не требуя особого поведения в случае заполнения буфера и не ограничивая N-байтбуфер для хранения N-1 предметов.

Обратите внимание, что хотя приведение типа в вышеупомянутом выражении не является строго необходимым, я бы рекомендовал включить его, поскольку становится очевидным, что при вычитании неподписанных величин поведение переноса равно преднамеренное и ожидается .

...