Raspberry Pi Pico W and Rx Buffer Size

Hello everyone,

I am attempting to use a Raspberry Pi Pico W for a project, but can't store enough data from the serial input to do my calculations. I need about 70 bytes, but the buffer size seems to be 31 bytes - any idea how to increase this size?

The following code works with 'frameLength' of 31 and below, but fails to proceed past 'if (Serial1.available() > frameLength)' where 'frameLength is 32 or greater...

Thoughts? I've tried SoftwareSerial but it won't allow for 4 parameters (TxPin, RxPin, logic invert, buffer).

#define frameLength 32 // Number of bytes to be stored

//SoftwareSerial swSer(swSerRX, swSerTX, false, 256); // Set Serial port for data input - format (rxPin, txPin, inverse_logic, buffer size)

void setup()
{
delay(10000);
Serial.begin(115200);
Serial1.begin(9600);
}

void loop()
{
byte readData[frameLength];

// Get data frame
if (Serial1.available() > frameLength) // Need to ensure at least 30 characters in buffer
{
if (Serial1.peek() == 170) // Check to see if START character is there
{
Serial.println();
for (byte i = 0; i< frameLength; i++)
{
readData[i] = Serial1.read();
Serial.print(readData[i]);
Serial.print(".");
}
}
else Serial1.read(); // Character is not START character - go to the next character in buffer
}

delay (100);
}

Rather than keep everything in the RX buffer, read it into your own buffer until you read the end of the message and then process it. Read this tutorial: Serial Input Basics - updated

With a Arduino Mega 2560 ? then always use a hardware Serial port. I think the size is 64 bytes.

What can you tell about the frame of data ?
Is is ASCII data ? Is there something at the end, for example a Carriage Return or Line Feed ?
How do you know where the begin and end is of that data.

1 Like

As per the title, I am using a Raspberry Pi Pico.

My data is a proprietary format (Resol VBus, for a solar hot water system) - variable sized frames of numerical bytes, which includes a checksum and other elements that needs to be post-processed.

I made some poorly-written code for an ESP8266 and vowed to clean it up. When I saw the Raspberry Pi Pico I thought this was my opportunity, but I am discovering significant differences between Arduino/ESP8266 and the Pico.

Sorry, I misunderstood that. I thought the Raspberry Pi was sending data.

When you use the Arduino IDE and have installed the Raspberry Pi Pico as a board (and did not add a json file in the preferences), then you have a Arduino layer on top of Mbed. I don't know what the buffer size is for the Serial port.

The rule is: if there is a byte, read it.

char myOwnBigBuffer[100];
int index;

void loop()
{
  if (Serial.available() > 0)       // something ?
  {
    myOwnBigBuffer[index] = Serial.read();   // read it
    index++;
  }
}

If the start of the data is seen, then start filling the buffer at the begin. If the end of the data is seen, then the data in the buffer can be processed. If the buffer is full, then do nothing (when the start is seen, the buffer is filled from the begin).

Koepel,

thank you for that.

A major constraint is that the data frames are about 70 bytes long, so if a read commences with a full buffer then it's likely serial data has been dropped between the last element of the serial buffer and the time it starts to read new data in (there's no guarantee that element 32 of the data frame will line up with element 31 (the last element in the serial buffer).

This is my code to date (but the test data received doesn't match the test data being sent [which has been verified by a logic analyser]).

#define frameLength 100 // Number of bytes to be stored

byte frameData[frameLength];

//SoftwareSerial swSer(swSerRX, swSerTX, false, 256); // Set Serial port for data input - format (rxPin, txPin, inverse_logic, buffer size)

void setup() 
{
delay(10000);
Serial.begin(115200);
Serial1.begin(9600);
}



void loop()
{

while (Serial1.available()) // At the start, if there is something in the buffer...
{
  Serial1.read(); // ... completely empty the buffer.
}

while (Serial1.read() != 170 && Serial.peek() != 16) // Look for the start (170, 16) sequence
{
  Serial1.read();
}

for (int count = 0; count < frameLength; count++) 
{
  while (Serial1.available() < 5) // While the buffer is near empty...
  {
    ; // ... let the buffer fill with some data
  }

  frameData[count] = Serial1.read(); // Fill the next elemeent of the frameData array from the buffer.
}

Serial.println();
Serial.println("Starting");
for (int count = 0; count < frameLength; count++) 
{
  Serial.print(frameData[count]);
  Serial.print(".");
}
}

Seriously, the rule is: if there is a byte then read it. Put it in a buffer (an array) and process it when the full frame of data is received. Do not wait for something. Can you remove all the while-loops and for-loops and try again ?

The Arduino loop() runs over and over again. Let it run. The faster and more often the loop() runs, the more responsive the code is. Don't hang around to wait for data.
Always follow the KISS rule.

The baudrate is 9600 baud. The 70 bytes take 73 ms. That is slow. So take every byte (or a few bytes) and put it in a buffer. Don't empty the bytes that are available (in a buffer inside the Serial library), that could be data of a new frame.

Is (170, 16) the start sequence ?
What is at the end ?
What is the minimal time between the frames ?

Yes, 170, 16, is the start sequence.

Hang on - my code was based on my thought that the serial buffer is FIFO - is it?

If the buffer keeps the last 31 bytes, then the issue I was trying to prevent from occurring will never occur...

You are still thinking that you have to do something with that internal buffer of the Serial library.

The Serial library has a internal FIFO buffer in software which is filled from a interrupt as data comes in. You should read from that internal buffer as soon as there is something. It does not matter if that internal buffer is 10 bytes or 10000 bytes. It only gives you extra time to do something in the sketch.

Maybe you should think as if that internal buffer is 10 bytes.
As soon as you see something in that internal buffer with Serial.available() then you read that byte with Serial.read(). Don't let that internal buffer be filled. You need your own buffer in the sketch to fill with data.

I don't know how to explain it better. I see it visually with balloons and ropes, but that might make it more confusing. The interrupt routine is a balloon, the Arduino loop() is a balloon, and the data travels along ropes between the balloons. To avoid a traffic jam on a rope, the data should travel on that rope between the interrupt and the loop() as often as possible.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.