Skip to main content
e239955
Associate
October 14, 2015
Question

USART RX interrupt driven ring buffer

  • October 14, 2015
  • 5 replies
  • 1871 views
Posted on October 14, 2015 at 08:51

Hey guys. First of all im new to this kind of stuff, so dont judge me please. 

I've been working for days on USART. I learned to transmit and receive strings via usart in normal mode, but as i try to do it with interrupts everything fall apart.

First I have tried to init usart interupts, and use it with single characters - it worked nicely, but now im trying to do it with multiple chars using ring buffer as a storage. After all i will try to parse the string that i got. I searched every thread but it seems that i cant find the right answer to this.

Maybe anyone have some examples of this? (ring buffer struct functions and implementation of it into usart interrupt receiver?)

struct bufer {

char buf[buffsize];

int start;

int end;

int count;

};

struct bufer buf = {0};

void UartBufferInit(void) {

buf.start = 0;

buf.end = 0;

}

bool UartBufferEmpty(void) {

return (buf.start == buf.end) ? TRUE : FALSE;

}

bool UartBufferFull(uint8_t c) {

return (((buf.end + 1) % buffsize) == buf.start) ? TRUE : FALSE;

}

bool PutIntoBuffer(uint8_t c) {

if(!UartBufferFull()){

buf.buf[buf.end] = c;

buf.end = (buf.end +1) % buffsize;

return TRUE;

} else {

return FALSE;

}

}

void USART1_IRQHandler(void) {

static char CopyOfBuf[buffsize];

static int rx_index = 0;

if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {

char rx = USART_ReceiveData(USART1);

if ((rx == '\r') || (rx == '\n')) {

if(rx_index != 0) {

memcpy(CopyOfBuf, buf.buf, sizeof(buf.buf)+1);

PutIntoBuffer(CopyOfBuf);

}

}

}

}
    This topic has been closed for replies.

    5 replies

    Tesla DeLorean
    Guru
    October 14, 2015
    Posted on October 14, 2015 at 09:15

    Well there's definitely some confusing on your part between characters, and strings, at a C level.

    The routine doesn't use rx_index, or advance it, and the memcpy() exceeds the length of the buffer. For strlen() you might need a +1 to account for the NUL, but the sizeof() gives the length of the buffer allocation, which is buffsize. Not sure I can get my head around what you need/want to achieve here, as you're better of parsing the data out of the FIFO/ring, and just stuffing the characters in one by one, as they arrive. The interrupt code looks to be a poor hack of some line buffering code example, which you don't cite.

    void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
    char rx = USART_ReceiveData(USART1);
    PutIntoBuffer(rx); 
    }
    }

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    e239955
    e239955Author
    Associate
    October 14, 2015
    Posted on October 14, 2015 at 10:05

    I made some changes in the code. Now Interrupt handler looks like:

    void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
    PutIntoBuffer(USART_ReceiveData(USART1));
    }
    }

    For the check i use RTOS task to blink leds.

    __task void packetread (void) {
    for(;;) {
    static char CopyOfBuf[buffsize];
    strcpy(CopyOfBuf, buf.buf);
    if (strncmp(CopyOfBuf, ''set'', 3)) {
    os_tsk_create(STSblink, 1);
    } else if(strncmp(CopyOfBuf, ''gps'', 3)) {
    os_tsk_create(GPS_blink, 1);
    } else {
    snd(''wrong command
    '');
    }
    os_dly_wait(50);
    }
    }

    and as far as i can see it just doesnt compares the string. Instead of it it jumps to STSblink task. Maybe do you know why? In my opinion i made some mistakes in ring buffer write routine, please check it and give your opinion.

    struct bufer {
    char buf[buffsize];
    int head;
    int tail;
    int count;
    };
    struct bufer buf = {0};
    void UartBufferInit(void) {
    buf.head = 0;
    buf.tail = 0;
    }
    bool UartBufferEmpty(void) {
    return (buf.head == buf.tail) ? TRUE : FALSE;
    }
    bool UartBufferFull(void) {
    return (((buf.tail + 1) % buffsize) == buf.head) ? TRUE : FALSE;
    }
    bool PutIntoBuffer(uint8_t c) {
    if(!UartBufferFull()){
    buf.buf[buf.tail] = c;
    buf.tail = (buf.tail +1) % buffsize;
    return TRUE;
    } else {
    return FALSE;
    }
    }

    Tesla DeLorean
    Guru
    October 14, 2015
    Posted on October 14, 2015 at 10:51

    I think a key part of your problem is that string functions expect NUL termination, you don't provide for, or handle that.

    When pulling data out, you want to do it a character at a time, forming a string, and when you encounter a CR or LF character, you replace that with a NUL (ZERO), and then process that string.
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    e239955
    e239955Author
    Associate
    October 14, 2015
    Posted on October 14, 2015 at 13:40

    And what is the best way to search in a buffer for end symbols. I cant do something like if (buf.buf == ' ') thing, cuz of the size of the buffer.

    Im trying it with strncmp, but seems that is not quite good idea too.

    __task void packetread (void) {
    for(;;) {
    static char CopyOfBuf[buffsize];
    if (strncmp(buf.buf, ''
    
    '', 2) == 0){
    strcpy(CopyOfBuf, buf.buf);
    if (strncmp(CopyOfBuf, ''set'', 3 ) == 0) {
    os_tsk_create(STSblink, 1);
    } else if(strncmp(CopyOfBuf, ''gps'', 3) == 0) {
    os_tsk_create(GPS_blink, 1);
    } else {
    snd(''wrong command
    '');
    }
    }
    os_dly_wait(50);
    }
    }

    Tesla DeLorean
    Guru
    October 14, 2015
    Posted on October 14, 2015 at 17:04

    Well you can't take it out of the ring buffer assuming it's going to be a linear run of characters that doesn't wrap, because at some point it will wrap, and the data won't always start at the beginning.I did post some explicit examples of using a LINE buffer, that are better suited to GPS NMEA streams which have specific start characters, and termination characters.

    https://community.st.com/0D50X00009Xkh8gSAB

     

    https://community.st.com/0D50X00009Xkh8gSAB#comment-69622

     If you're going to pursue the FIFO/ring buffer, you going to need to extract a character at a time, placing them in a linear buffer. Once you've closed the string out with a NUL, *THEN* you can use string functions. You can't strcpy() out of the buffer because it's unbounded.

    Edit: Fixed DEADLINK

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..