Serial Circular Buffer Woes!!!

03 Oct 2010

So I am starting a project and working on the serial buffer routines.  I am using a serial interrupt to read characters and buffer them to an array of characters.  Whenever I get a carriage return (=13) I set sFlag=1 so the main program can pick it up and print the string to the serial.  It works mostly but behaves weird depending on the amount of characters sent to the buffer.  Some letters get overwritten and some are just missing etc.  Can anyone help me get this sorted out please.

 

 

#include "mbed.h"
#include "MobileLCD.h"
#include "QEI.h"


QEI wheel (p29, p30, p28, 500);
MobileLCD lcd(p5, p6, p7, p8, p9);
Serial pc(USBTX,USBRX);
DigitalOut led(LED1);
DigitalOut led2(LED2);
char buff[100];
int sFlag=0;
int i=0;

void Serialint() {
    led=!led;
    buff[i]= pc.getc();
    if (buff[i]==13) {
        sFlag=1;
        //i=0;
    } else {
        i++;
    }

}

int main() {
    pc.baud(115200);
    pc.attach(&Serialint);
    lcd.locate(0,0);
    lcd.printf("Count is:");
    pc.printf("Matt's Serial!!\n\r");


    while (1) {

        //    wait(0.1);
        //    lcd.locate(0,1);
        //    lcd.printf("%10i", wheel.getPulses());

        if (sFlag==1) {
            sFlag=0;
            pc.printf("%s\n\r",buff);
            i=0;
            if (strcmp(buff,"tenletters")==0) {
                led2=1;
            } else {
                led2=0;
            }
        }

    }
}
03 Oct 2010

Hi Matt

There's a lot of threads about this subject on the forum, so hopefully you can find some good code examples. Have a look here, for example.

I think the essence of your problem is that you are trying to access the buffer from both the interrupt handler and also the main loop. With this type of code, you need to arrange mutually exclusive access eg. disable the interrupts whilst accessing the buffer in the main loop.

Regards
Daniel

03 Oct 2010 . Edited: 03 Oct 2010

Matt,

I just published this library which you may find useful either "as is" or as a starting point. The library extends Serial into a fully customisabnle circular InOut buffer system.

http://mbed.org/users/AjK/libraries/SerialBuffered

regards,

--Andy

03 Oct 2010

Oh, and further to what Daniel said, there are various schemes you can use. My library is based on a project I put together. My project doesn't actually use the library itself. The library is a "common set" of functions distilled into a generic re-useable library. But, for example, in my project I use all the Uarts. One Uart reads a GPS module. It uses two RX buffers. When the ISR "sees" a '\n' it switches buffers and raises a flag to say "the old buffer needs parsing" by the main system. While the old buffer is being parsed the ISR fills the other buffer and then switches again, back and forth. That's one simple way to sepeate the ISR from the main code. Just have to make sure you process the "old buffer" before the next '\n'. But with a GPS at 9600 and one stream per second, that was pretty easy.

Another example is I have a Uart talking to a GOTO telescope mount. That required a different approach using "packets". In that case the main system creates data packets and then queues them. The serial ISR then processes packets and controls their flow using a simple state machine maintained by each packets data structure. Again, just another method of handling a "pipe".

I won't bother what the other two Uarts are doing, you get the idea :)

regards,

--Andy

03 Oct 2010

I made the following changes to the code and now all works as expected. I also reduced the char buff[20].

 I did try two serial ports with the same problem as before (<-didnt fix it).  I looked at the thread about disabling the NVIC setting before printf statements but didnt get that far before I got it to work with my changes.  I also looked at the thread about adding a putc in the ISR but that didnt make any difference either.

Thanks everyone for the suggestions and hopefully I can now move on to the next issue.

 

  while (1) {

            wait(0.1);
            lcd.locate(0,1);
            lcd.printf("%10i", wheel.getPulses());

        if (sFlag==1) {
            sFlag=0;
            pc.printf("%s\n\r",buff);
            
            if (strcmp(buff,"tenletters")==0) {
                led2=1;
            } else {
                led2=0;
            }
            for (q=0;q<21;q++) {
                buff[q]='\0';
            }
        }

    }