Serial Buffering Code

Hello All,

I am new to posting in this forum and I have what might seem like an old and beaten to death question but I cannot seem to find the answer I am looking for.

I have a need to support serial communication from one variable baud rate source, selected by the host device to a device of a fixed baud rate (9600). The source baud rates I want to support is pretty wide. 50,75,110,300,600,1200,2400,4800,9600,14400,19200,28800, 38400,56000,57600, and 115200.

I understand that both the normal Serial port and the SoftSerial port have a buffer size of 64 bytes. And I am using the following as a starting point. So mySerial is set up for 9600, and Serial will be set up as any of the above stated rates.

if (mySerial.available())
Serial.write(mySerial.read());

if (Serial.available())
mySerial.print(Serial.read());

I understand that I will need a bucket to place data in, I am not sure how to implement this? Can anyone help?

Please advise and thank you
Mike T.

I believe what you are looking for is an array for your "bucket".

But I don't understand why, do you not know the baud rate? If you do know the baud rate, then just do Serial.begin(baudRate);

Ok let me try to explain this better. Here is my proposed setup for a versatile speech chip interface.

I have a TTS256 Text to speech chip talking to a speakjet chip directly. (9600 baud into the TTS)

I also have a serial LCD screen (9600 baud into the LCD)

I will be hooking these two things up to an Arduino Pro Mini.

There will be a total of three serial ports being dealt with.

  1. Soft serial to the TTS at 9600
  2. Soft serial to the LCD at 9600
  3. Hardware serial that will be TTL level serial port for an FTDI or MAX232 hookup to varied devices.

What I hope to have is a system that I can hook various machines up to and use the TTS circuitry with status updated on the Serial LCD. There are many things I want to hook up to this setup. Everything from an old Commodore Vic 20 for TTS games to a PC using a FTDI at say 115200 baud.

I have already done a bit of programming in regards to this and I have listed a p[ortion of this below. It compiles just fine and I believe once I get everything wired up that I can get it to work if everything is set to 9600 baud, but I feel I might need extra buffering seeing as how 115200 max baud is is more than 2300 times the minimum baud of 50.

#include <SoftwareSerial.h>

// Define pins for serial ports
// SoftwareSerial object(rx,tx);
SoftwareSerial TTSSerial(10,11);  //Pin 10 goes to Pin 5(TX) on TTS256 chip Pin 11 goes to Pin 18(RX) on TTS256 chip
SoftwareSerial LCDSerial(12,13);  //Pin 12 not used Pin 13 goes to RX on LCD

//Define Pins for other function

int SJRst      = 2;       //Speakjet Reset Pin 11 active LOW
int TTSRst     = 3;       //Text to Speech reset pin 1 active HIGH
int SJBuf      = 4;       //Speakjet Buffer Hald Full Pin 15
int SJSpeak    = 5;       //Speakjet Speaking Pin 16
int SJReady    = 6;       //Speakjet Read Pin 17
int Mode       = 7;       //Pin for button to toggle Pass Through Mode
int Debug      = 8;       //Pin for button to toggle DEBUG Mode
int LCDLum     = 9;       //Pin to control LCD Illumination
int BaudPin1   = 14;      //Pin to add value of 1 to Val for baud rate setting
int BaudPin2   = 15;      //Pin to add value of 2 to Val for baud rate setting
int BaudPin3   = 16;      //Pin to add value of 4 to Val for baud rate setting
int BaudPin4   = 17;      //Pin to add value of 8 to Val for baud rate setting

//Define Variables

long debounce = 100;      //Debounce time 100 mSec
int UpdDis;               //Update Display Flag when status changes
int byteReceived;

// Define Mode Button Variables
int ModeFlg     = HIGH;
int ModRead;
int pModeFlg    = LOW;
long ModeTime   = 0;

//Define Debug Button Variables
int DBFlg       = HIGH;
int DBRead;
int pDBFlg      = LOW;
long DBTime     = 0;

//Define Speakjet Ready Variables
int SJRFlg      = HIGH;
int SJRRead;
int pSJRFlg     = LOW;

//Define Speakjet Speaking Variables
int SJSFlg      = HIGH;
int SJSRead;
int pSJSFlg     = LOW;

//Define Speakjet Buffer Variables
int SJBFlg      = HIGH;
int SJBRead;
int pSJBFlg     = LOW;

//Define LCD Illumination Variable
int IlumRead;
int pIlumFlg    = LOW;
long IlumTime   = 0;

//Valid baud rates to select from
long BaudRate[16] = {50,75,110,300,600,1200,2400,4800,9600,14400,19200,28800,
                     38400,56000,57600,115200} ;
//Value of which array will be used for BaudRate
int bVal = 0;      
//String used to display baud rate
String BaudStr;

//Valid screen illumination values
int IlumValue[4] = {128,140,150,157};

//Value of which array with be used for Illumination
int iVal = 0;

void setup() {

  //Define Pin direction

  pinMode(SJRst, OUTPUT);                                          
  pinMode(TTSRst, OUTPUT); 
  pinMode(SJBuf, INPUT);
  pinMode(SJSpeak, INPUT);
  pinMode(SJReady, INPUT);  
  pinMode(Mode, INPUT);
  pinMode(Debug, INPUT);  
  pinMode(LCDLum, INPUT);
  pinMode(BaudPin1, INPUT);
  pinMode(BaudPin2, INPUT);
  pinMode(BaudPin3, INPUT);
  pinMode(BaudPin4, INPUT);

  //Reset TTS and Speakjet 
  digitalWrite(SJRst, LOW);                                        //Hold Speakjet reset low
  digitalWrite(TTSRst, HIGH);                                      //Hold TTS reset high
  delay(300);
  digitalWrite(SJRst, HIGH);                                      //Activate SJ
  delay(300);
  digitalWrite(TTSRst, LOW);                                      //Activate TTS
  delay(300);
  
  //Open communication ports
  LCDSerial.begin(9600); // set up LCD serial port for 9600 baud
  delay(500); // wait for display to boot up

  TTSSerial.begin(9600); // set up TTS serial port for 9600 baud

  //Determine baud rate to host processor and open
 
  if ( digitalRead(BaudPin4) == HIGH) {bVal = bVal + 8;}
  if ( digitalRead(BaudPin3) == HIGH) {bVal = bVal + 4;}
  if ( digitalRead(BaudPin2) == HIGH) {bVal = bVal + 2;}
  if ( digitalRead(BaudPin1) == HIGH) {bVal = bVal + 1;}

  Serial.begin(BaudRate[bVal]);
  BaudStr = "Baud Rate: " + BaudRate[bVal];
   
  //Initialize LCD
  LCDSerial.write(254); // clear screen
  LCDSerial.write(1);
  LCDSerial.write(254); // move cursor to beginning of first line
  LCDSerial.write(128);
  LCDSerial.print(BaudStr); 
  LCDSerial.write(254); // move cursor to beginning of second line
  LCDSerial.write(192);
  LCDSerial.print("Mode:");
  LCDSerial.write(254); // move cursor to beginning of third line
  LCDSerial.write(148);
  LCDSerial.print("Debug:");
  LCDSerial.write(254); // move cursor to beginning of forth line
  LCDSerial.write(212);
  LCDSerial.print("Status:"); 
  
  updateDisplay( 0, 0, 0, 0, 0);

}

void loop() {
  
  UpdDis = LOW;
  ModRead = digitalRead(Mode);
  DBRead = digitalRead(Debug);
  SJRRead = digitalRead(SJReady);
  SJSRead = digitalRead(SJSpeak);
  SJBRead = digitalRead(SJBuf);
  IlumRead = digitalRead(LCDLum);
  
  //Check if Mode button was pressed
  if (ModRead == HIGH && pModeFlg == LOW && millis() - ModeTime > debounce) {
    if (ModeFlg == HIGH) {
     ModeFlg = LOW;
     TTSSerial.println("X");
    }
    else {
      ModeFlg = HIGH;
      TTSSerial.println("passthruon");
    }
    ModeTime = millis();  
    UpdDis = HIGH;  
  }
  
  //Check if Debug button was pressed
  if (DBRead == HIGH && pDBFlg == LOW && millis() - DBTime > debounce) {
    if (DBFlg == HIGH) {
      DBFlg = LOW;
      TTSSerial.println("debugoff");
      }
    else {
      DBFlg = HIGH;
      TTSSerial.println("debugon");      
      }
    DBTime = millis();
    UpdDis = HIGH;     
  }  
  
  //Check if Illumination Button was pressed
  if (IlumRead == HIGH && pIlumFlg == LOW && millis() - IlumTime > debounce) {
    //Send command to LCD to change value of illumination
    LCDSerial.write(124);
    LCDSerial.write(IlumValue[iVal]);
    iVal = iVal + 1;          //Bump iVal to use next Illumination Value
    if (iVal > 3) iVal = 0;   //If iVal is greater than 3 then set back to Zero to turn off Illumination 
    IlumTime = millis();
  }    
  
  //Check if Speakjet Ready Pin is HIGH
  if (SJRRead == HIGH && pSJRFlg == LOW) {
    if (SJRFlg == HIGH)
     SJRFlg = LOW;
    else
      SJRFlg = HIGH;
    UpdDis = HIGH; 
  }  
  
  //Check if Speakjet Speaking Pin is HIGH
  if (SJSRead == HIGH && pSJSFlg == LOW) {
    if (SJSFlg == HIGH)
     SJSFlg = LOW;
    else
      SJSFlg = HIGH;
    UpdDis = HIGH; 
  }    
  
  //Check if Buffer Half Full Pin is HIGH
  if (SJBRead == HIGH && pSJBFlg == LOW) {
    if (SJBFlg == HIGH)
     SJBFlg = LOW;
    else
      SJBFlg = HIGH;
    UpdDis = HIGH; 
  }      
 
  if (UpdDis == HIGH) {
    updateDisplay(ModeFlg, DBFlg, SJRFlg, SJSFlg, SJBFlg);}
  
  //route serial data from serial to TTS
  //
  //Route serial data from TTS to serial
  
  pModeFlg = ModRead;
  pDBFlg = DBRead;
  pSJRFlg = SJRRead;
  pSJSFlg = SJSRead;
  pSJBFlg = SJBRead;
  
  //Check for data coming from Host serial port and route to TTS chip
  if (Serial.available())
    TTSSerial.write(Serial.read());  
  
  //Check for data coming from the TTS chip and route to Host serial port
  if (TTSSerial.available())
    byteReceived = TTSSerial.read();
    if (byteReceived > 127) {
      if (byteReceived < 31) {
        Serial.write(byteReceived);
      }
      else if (byteReceived == 13) {  
        Serial.write(byteReceived);
      }
    }

}

OKAY, now I see your issue, you are worried that while transferring at a low baud rate will cause an incoming higher baud rate to overflow the buffer?

However, if I am not mistaken, serial events work off of interrupts and thus you will not have to worry about Serial.print("A lot of characters at a slow baud rate"); taking too long and overflowing your buffer from another incoming signal. Although, I am not sure about software serial, does it work off of interrupts as well?

Side notes: variables starting with uppercase usually refer to objects. Also, I recommend using #define instead of declaring your "constant" variables, this will save some cpu cycles and ram space. Also also, you should declare your variable types as byte instead of int when appropriate to save ram and cpu cycles.

What is the baud rate of speech? Maybe you can talk at 40 words per minute and each word has an average of 6 characters (including the space) and those characters require 9 bits of serial data each, then you're about 34 baud.

If you want to save up more than 64 characters from the incoming serial so that it can cue up a minute's worth of talking then you will need a buffer. Look for tutorials on "ring buffer" or "circular buffer" as you want incoming characters to be interleaved with (at the same time as) outgoing characters.

If you are worried that incoming data at (say) 57600 baud will overrun output data at 9600 baud - you are correct to be worried.

Normally the Arduino does not operate flow-control on incoming data which is what would be needed to tell the transmitting device to stop sending.

If you know that the maximum amount of data that will be received can be accommodated within the Arduino's limited SRAM memory you could arrange to save the data temporarily. The code in serial input basics can do that - you can easily increase the size of the array in which data is saved.

For more comprehensive advice you need to tell us all about the data that is being sent to the Arduino and what opportunities exist for controlling it from the Arduino.

...R

@Robin2, I don't think that is his concern, my guess is that he thinks that the slower baud rate will take too much time to receive and a higher baud rate signal will overflow the buffer.

For example, if a baud rate of 50 is used, then receiving 50 bits will take 1 second. But, if he is also receiving (let's say) 128 bytes on the hardware serial using a baud rate of 115200, then that 128 bytes will fill up and overflow the buffer before he finishes receiving the 50 baud signal.

However, I'm pretty sure serial does not wait around to send something, but uses interrupts, and thus, with correct programming will not have an issue. BUT, I am not sure if software serial uses interrupts, if it does NOT, then there is an overflow possibility.

Ps991:
@Robin2, I don't think that is his concern, my guess is that he thinks that the slower baud rate will take too much time to receive and a higher baud rate signal will overflow the buffer.

That sounds like receiving data on two different serial inputs at the same time. If that is what the OP want to do and if both serial streams use the concept in serial input basics there should not be a problem.

However, I thought (and still think) the OP is talking about receiving data at a fast baud rate and re-transmitting it at a lower baud rate.

...R

There will be a total of three serial ports being dealt with.

  1. Soft serial to the TTS at 9600
  2. Soft serial to the LCD at 9600
  3. Hardware serial that will be TTL level serial port for an FTDI or MAX232 hookup to varied devices.

What I hope to have is a system that I can hook various machines up to and use the TTS circuitry with status updated on the Serial LCD. There are many things I want to hook up to this setup. Everything from an old Commodore Vic 20 for TTS games to a PC using a FTDI at say 115200 baud.

more than 1 serial port, nothing stated about using 1 to re-transmit, however, he also says

but I feel I might need extra buffering seeing as how 115200 max baud is is more than 2300 times the minimum baud of 50.

which is what makes it seems like he is worried for an overflow due to long transmission times from a slow baud.

Ps991:
it seems like he is worried for an overflow due to long transmission times from a slow baud.

Maybe we are trying to say the same thing. In my mind it is the fast baud rate that will overflow (ie more data will come in than can go out).

..R

Then yes, we are trying to say the same thing. I re-read your 2nd earlier post and it now makes sense that we were and now are on the same page, but I havent heard from OP recently :confused:

Hello Again All,

First let me say to Ps991, I will take your coding suggestions and implement them, I can use ever CPU clock cycle I can get. Thanks.

Next I put together a visio diagram of the set up I am playing with and the set up I wish to use.

With the current setup you can see I have bi-directional communication with the TTS256 chip from the Host PC. there is one way communication flowing from the TTS256 to the Speakjet. The Speakjet's buffer half full pin is used as hardware flow control telling the TTS256 to pause on sending data. I also wired this up to the CTS pin on the Host PC's serial port to halt the PC from sending data.

In the proposed setup with the Arduino mini acting as a serial converter I am using this same hardware flow control logic. Sending data to the Arduino and other chips should not be a problem since everything will halt when the buffer half full pin goes high. The Arduino mini is just monitoring this pin to update status on an LCD screen.

The problem I imagine I will have is when the TTS256 chip wants to send data back to the Host via the Arduino Mini. If the baud rate of the host is slower than 9600 bps, I can potentially lose data. I believe someone mentioned loading the data coming back from the TTS256 into an array and just sending that array to the host when a limit has been reached.

Do any of you think this approach will work? I would test the code but at the moment I am working on the final amplifier I will be using, and getting optocouplers in the communication line with the Host..

Also to give you all a rough idea of the slower devices I am speaking off, there is a video os a Vic-20 text adventure game I managed to get working with the speakjet.

Vic-Jet

Thoughts?

Z0rb:
Hello Again All,

I don't get the impression that you have carefully considered all of the Replies that you have already beein given.

Can you explain how each of them is not relevant, if that is the case. Then we will have a better understanding of the problem.

...R