Receiving large amount serial data, 209 bytes at 115K baud

27 Apr 2016

I'm trying to receive a large amount of serial data at 115200 baud rate into a LPC1768. My current code is showing that only 17 bytes are being read at a time. I downloaded BufferedSerial but I can't seem to understand how the data is pushed into the buffer "MyBuffer".

<code>

int main() {

MSserial.baud(115200);

MSserial.format(8, SerialBase::None, 1);

timer.attach(&DatOut, 1.0f);

while(1) {

MSserial.gets(lbuf,209);

out.puts(lbuf);

wait(0.5);

count = 0;

} }

</code>

28 Apr 2016

Generally it's a bad idea to have a wait in a loop for anything that needs to cope with lots of data, similarly using a timer to check for input data is a bad idea, it's far better to constantly check or use a data received interrupt.

The code below will buffer up serial data and then echo it to a second port in packets of 206 bytes. It's untested so there may be the odd syntax error or bug but the basic structure is sound.

The code implements a buffer that data is written into as it arrives from the serial port. The main code waits until the buffer contains at least 206 bytes and then makes a copy of the buffer and resets the byte counter so that the buffer can be re-used.

This leaves the main loop with a copy of the serial data that it can do whatever it want to with. The only timing requirement to avoid data loss is that the main loop has finished whatever it wants to do before the next packet finishes arriving.

This is in effect a simplified version of what BufferedSerial is doing in the background.

#include "mbed.h"
#define rxBufferSize 255

Serial dataIn(tx,rx);
Serial dataOut(tx,rx);

// sneaky trick for the lazy: make buffers 1 byte larger than we assume in the code.
// This means there will always be space to add a null terminator if we need to.
char dataRxBuffer[rxBufferSize+1]; 
volatile int rxBufferPtr; // must be volatile or the compiler may over-optimise.

char dataCopy[rxBufferSize+1];
int receivedDataCount = 0;

// called every time a byte is received.
void onDataRx() {
  while (dataIn.readable()) { // while there is data waiting
    dataRxBuffer[rxBufferPtr++] = dataIn.getc(); // put it in the buffer
    if (rxBufferPtr == rxBufferSize) {
      // BUFFER OVERFLOW. What goes here depends on how you want to cope with that situation.
      // For now just throw everything away.
      rxBufferPtr  = 0;
    }
  }
}

main() {
  dataIn.baud(115200); // set baud rates (8, none, 1 format is default so no need to set that)
  dataOut.baud(115200);

  dataIn.attach(&onDataRx); // set the rx interrupt function

  while (true) {
    if (rxBufferPtr  >= 206) { // got a full data packet
      __disable_irq();            // disable interrupts so data doesn't arrive while we are doing this
      memcpy(dataCopy,dataRxBuffer,rxBufferPtr);   // copy the packet to a new location
      receivedDataCount  = rxBufferPtr;
      rxBufferPtr = 0;                                                  // reset the counter
      __enable_irq();                                                 // re-enable interrupts

      // at this point dataCopy contains a copy of the packet you received. 
      // receivedDataCount contains the size of that packet (it should always be 206).

      // for now echo the data on a different port.
      dataCopy[receivedDataCount] = 0; // add a null just in case the received data didn't have one at the end
      dataOut.puts(dataCopy);
     } // end of if packet ready
  } // end of while(true)
}

You could improve upon this and eliminate the need for the memory copy by swapping the buffers rather than copying from one to the other but with such a low data rate it's probably not worth the added complexity.

You could also move the packet detection into the interrupt handler, it simplifies the main background loop but removes flexibility.