cancel
Showing results for 
Search instead for 
Did you mean: 

USART RX interrupt driven ring buffer

e239955
Associate II
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);

}

}

}

}
5 REPLIES 5
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
Up vote any posts that you find helpful, it shows what's working..
e239955
Associate II
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;
}
}

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
Up vote any posts that you find helpful, it shows what's working..
e239955
Associate II
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);
}
}

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
Up vote any posts that you find helpful, it shows what's working..