Hardware serial ports with two different sets of buffers

Post here all questions related to STM32 core if you can't find a relevant section!
Post Reply
Tazzi
Posts: 20
Joined: Wed Jan 08, 2020 12:45 am

Hardware serial ports with two different sets of buffers

Post by Tazzi »

I honestly feel like I am always asking about weird requests :lol:

Is it possible to have serial ports with two different RX/TX buffers?

In the HardwareSerial.h file, we have the following two lines:
unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE];

Both SERIAL_RX_BUFFR_SIZE are set to 64bytes by default.

How can I achieve the following using Serial1 and Serial2, can I get the following setup:
Serial1 with SERIAL_RX_BUFFER_SIZE = 64bytes and SERIAL_TX_BUFFER_SIZE = 64bytes
Serial2 with SERIAL_RX_BUFFER_SIZE = 512ytes and SERIAL_TX_BUFFER_SIZE = 512bytes

The default hardware file means only one size can be defined which applies to all serial ports. But I am limited on ram, and only 1 serial port requires a larger buffer then the others.
The larger buffer serial port runs at a higher baud rate, this is causing the serials interrupt to fire off faster then the main app can pull our the data from the serial ports internal buffer. The reading of the serial port is a tight FOR loop, there is no way to read it out faster hence the buffer size is increased to prevent loss of data.

Is there a simple #ifdefined that I can use at the buffer initialization to customize the size based on the UART port being used?
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Hardware serial ports with two different sets of buffers

Post by ag123 »

you can try editing your local copy of the codes, so that you can possibly pass parameters in the class constructor.
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: Hardware serial ports with two different sets of buffers

Post by mrburnette »

Tazzi wrote: Mon Oct 25, 2021 1:20 am ...
Is it possible to have serial ports with two different RX/TX buffers?
...
It is considered (by me) to be bad form to modify core code (sorry ag123).

It is better IMO to simply double-buffer the serial stream where you require a larger buffer.

Code: Select all

Serial1 with SERIAL_RX_BUFFER_SIZE = 64bytes and SERIAL_TX_BUFFER_SIZE = 64bytes
Serial2 with SERIAL_RX_BUFFER_SIZE = 512ytes and SERIAL_TX_BUFFER_SIZE = 512bytes
So, in your case, you have a few options to implement, but you can sub-class serial #2 and add a secondary buffer. Or, since you are not servicing Serial2 frequently, you could use SoftwareSerial for the second serial port. Lady Ada has a nice example of subclassing the serial Rx here.

Adafruit has rewritten most of their libs ... can be a bit difficult to analyze. The "old" code looked like this:

Code: Select all

/***********************************
This is the Adafruit GPS library - the ultimate GPS library
for the ultimate GPS module!

Tested and works great with the Adafruit Ultimate GPS module
using MTK33x9 chipset
    ------> http://www.adafruit.com/products/746
Pick one up today at the Adafruit electronics shop 
and help support open source hardware & software! -ada

Adafruit invests time and resources providing this open source code, 
please support Adafruit and open-source hardware by purchasing 
products from Adafruit!

Written by Limor Fried/Ladyada  for Adafruit Industries.  
BSD license, check license.txt for more information
All text above must be included in any redistribution

****************************************/
#include <Arduino.h>
#ifndef _ADAFRUIT_GPS_H
  #define _ADAFRUIT_GPS_H

  #include <SoftwareSerial.h>

  // how long to wait when we're looking for a response
  #define MAXWAITSENTENCE 5

  class Adafruit_GPS {
   public:
    void begin(uint16_t baud); 

    Adafruit_GPS(SoftwareSerial *ser); // Constructor when using SoftwareSerial
    // Adafruit_GPS(HardwareSerial *ser); // Constructor when using HardwareSerial
    char *lastNMEA(void);
    boolean newNMEAreceived();
    void common_init(void);
    void sendCommand(char *);
    void pause(boolean b);
    boolean parseNMEA(char *response);
    uint8_t parseHex(char c);
    char read(void);
    boolean parse(char *);
    void interruptReads(boolean r);
    boolean wakeup(void);
    boolean standby(void);
    uint8_t hour, minute, seconds, year, month, day;
    uint16_t milliseconds;
    char lat, lon, mag;
    boolean fix;
    uint8_t fixquality, satellites;
    boolean waitForSentence(char *wait, uint8_t max = MAXWAITSENTENCE);

    private:
      boolean paused;
      uint8_t parseResponse(char *response);

    SoftwareSerial *gpsSwSerial;
    //HardwareSerial *gpsHwSerial;
  };
#endif

Code: Select all

/***********************************
This version of the Adafruit Adafruit_GPS.cpp file has been modified from
the original by M. Ray Burnette

Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above must be included in any redistribution
****************************************/
#include "Adafruit_GPS.h"

// how long are max NMEA lines to parse?
#define MAXLINELENGTH 120

// we double buffer: read one line in and leave one for the main program
volatile char line1[MAXLINELENGTH];
volatile char line2[MAXLINELENGTH];
// our index into filling the current line
volatile uint8_t lineidx=0;
// pointers to the double buffers
volatile char *currentline;
volatile char *lastline;
volatile boolean recvdflag;
volatile boolean inStandbyMode;


boolean Adafruit_GPS::parse(char *nmea) {
  // do checksum check
  // first look if we even have one
  if (nmea[strlen(nmea)-4] == '*') {
    uint16_t sum = parseHex(nmea[strlen(nmea)-3]) * 16;
    sum += parseHex(nmea[strlen(nmea)-2]);
    
    // check checksum 
    for (uint8_t i=1; i < (strlen(nmea)-4); i++) {
      sum ^= nmea[i];
    }
    
    if (sum != 0) {
      // bad checksum :(
      //return false;
    }
  }

/*
  // look for a few common sentences
  if (strstr(nmea, "$GPGGA")) {
    // found GGA
    char *p = nmea;
    // get time
    p = strchr(p, ',')+1;
    float timef = atof(p);
    uint32_t time = timef;
    hour = time / 10000;
    minute = (time % 10000) / 100;
    seconds = (time % 100);

    milliseconds = fmod(timef, 1.0) * 1000;
    return true;
  }
*/

  if (strstr(nmea, "$GPRMC")) {
   // found RMC
    char *p = nmea;

    // get time
    p = strchr(p, ',')+1;
    float timef = atof(p);
    uint32_t time = timef;
    hour = time / 10000;
    minute = (time % 10000) / 100;
    seconds = (time % 100);

    milliseconds = fmod(timef, 1.0) * 1000;
    p = strchr(p, ',')+1;  // A/V?
    p = strchr(p, ',')+1;  // lat
    p = strchr(p, ',')+1;  // N/S?
    p = strchr(p, ',')+1;  // lon
    p = strchr(p, ',')+1;  // E/W?
    p = strchr(p, ',')+1;  // speed
    p = strchr(p, ',')+1;  // angle

    p = strchr(p, ',')+1;
    uint32_t fulldate = atof(p);
    day = fulldate / 10000;
    month = (fulldate % 10000) / 100;
    year = (fulldate % 100);
    // we dont parse the remaining, yet!
    return true;
  }

  return false;
}

char Adafruit_GPS::read(void) {
  char c = 0;
  
  if (paused) return c;

    if(!gpsSwSerial->available()) return c;
    c = gpsSwSerial->read();

  //Serial.print(c);

  if (c == '$') {
    currentline[lineidx] = 0;
    lineidx = 0;
  }

  if (c == '\n') {
    currentline[lineidx] = 0;

    if (currentline == line1) {
      currentline = line2;
      lastline = line1;
    } else {
      currentline = line1;
      lastline = line2;
    }

    //Serial.println("----");
    //Serial.println((char *)lastline);
    //Serial.println("----");
    lineidx = 0;
    recvdflag = true;
  }

  currentline[lineidx++] = c;
  if (lineidx >= MAXLINELENGTH)
    lineidx = MAXLINELENGTH-1;

  return c;
}

Adafruit_GPS::Adafruit_GPS(SoftwareSerial *ser)
{
  common_init();     // Set everything to common state, then...
  gpsSwSerial = ser; // ...override gpsSwSerial with value passed.
}

// Initialization code used by all constructor types
void Adafruit_GPS::common_init(void) {
  gpsSwSerial = NULL; // Set both to NULL, then override correct
  recvdflag   = false;
  paused      = false;
  lineidx     = 0;
  currentline = line1;
  lastline    = line2;
  hour = minute = seconds = year = month = day = fixquality = satellites = 0; // uint8_t
  milliseconds = 0; // uint16_t
}

void Adafruit_GPS::begin(uint16_t baud) {
  if(gpsSwSerial) gpsSwSerial->begin(baud);
  delay(10);
}

boolean Adafruit_GPS::newNMEAreceived(void) {
  return recvdflag;
}

void Adafruit_GPS::pause(boolean p) {
  paused = p;
}

char *Adafruit_GPS::lastNMEA(void) {
  recvdflag = false;
  return (char *)lastline;
}

// read a Hex value and return the decimal equivalent
uint8_t Adafruit_GPS::parseHex(char c) {
    if (c < '0')
      return 0;
    if (c <= '9')
      return c - '0';
    if (c < 'A')
       return 0;
    if (c <= 'F')
       return (c - 'A')+10;
}

boolean Adafruit_GPS::waitForSentence(char *wait4me, uint8_t max) {
  char str[20];
  uint8_t i=0;
  while (i < max) {
    if (newNMEAreceived()) { 
      char *nmea = lastNMEA();
      strncpy(str, nmea, 20);
      str[19] = 0;
      i++;

      if (strstr(str, wait4me))
	return true;
    }
  }

  return false;
}

Tazzi
Posts: 20
Joined: Wed Jan 08, 2020 12:45 am

Re: Hardware serial ports with two different sets of buffers

Post by Tazzi »

Ah ok I see, software serial could be an option, but it is preferred to use hardware serial since best using the inbuilt options.

Plan of attack is to then create a custom hardwareserial class, that way I can have two sets of buffers :)
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: Hardware serial ports with two different sets of buffers

Post by mrburnette »

Tazzi wrote: Tue Oct 26, 2021 1:39 am Ah ok I see, software serial could be an option, but it is preferred to use hardware serial since best using the inbuilt options.

Plan of attack is to then create a custom hardwareserial class, that way I can have two sets of buffers :)

Read up on C++ techniques: https://www.w3schools.com/cpp/cpp_oop.asp


Added:


https://forum.arduino.cc/t/extending-th ... -que/41775
Post Reply

Return to “General discussion”