software serial limitations

i have an Arduino Mega application that uses 3 serial interfaces that works.

this is DCC model railroad application that translates commands from the PC thru one serial to an NCE (cabbus) command station thru another serial interface. Both are rs-485. The 3rd interface (USB) is used for debugging.

i rebuilt the application for an Uno using software serial. I used pins 8 (RX) and 9 for one interface and 10 (RX) and 12 for the 2nd.

i was unable to read serial data while other code was running. the other code checks for received data on corresponding interfaces and processes that data.

but when I simplified the code to simply check the one soft serial interface and echo it on the serial monitor it worked. It seems like the soft serial interface needs to be constantly queried to work

this is a big disappointment and I have to wonder how useful a soft serial interface can be if very little else can be done

The softwareSerial library can only read data from one instance at a time, i.e. only one can be active at any moment. It sounds like this was your issue.

There are several different Software Serial interfaces, each with its own limitations. You did not say which one you have, and you did not show your code.

The Software Serial that I am most familiar with will only listen on one port at a time, yet I have used this to link hundreds of Unos. Each Uno had one hardware serial port for debugging, and two software serial ports to link to adjacent Unos.

Were you attempting to exceed the limitations of your implementation?

This page explains how to use 2 software serial ports.

vaj4088:
There are several different Software Serial interfaces, each with its own limitations. You did not say which one you have, and you did not show your code.

i didn't know there were several different SoftwareSerial libraries. The one I have has the following

SoftwareSerial.cpp (formerly NewSoftSerial.cpp)

vaj4088:
The Software Serial that I am most familiar with will only listen on one port at a time, yet I have used this to link hundreds of Unos. Each Uno had one hardware serial port for debugging, and two software serial ports to link to adjacent Unos.

Here's a Two Port Receive example which I assume works, but does very little, and which I inferred implies that multiple ports can be used simultaneously[/quote]

vaj4088:
Were you attempting to exceed the limitations of your implementation?

i certainly wasn't attempt to exceed the limitations. My understanding is the limitation is 57600 bps and RX pins are restricted to RX: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).

simplified code that works inside #if/#else

// NCE USB Cab Interface

const char *version  = "CabUsb 200522b";

#include "CabUsb.h"
#include "cabbus.h"
#include "jmriIf.h"

#if defined __AVR_ATmega328P__      // Uno
SoftwareSerial Serial1 (RX1, TX1);
SoftwareSerial Serial3 (RX3, TX3);
#endif

extern void pcRead (void);

#if 0
unsigned int debug  = 0;
#elif 0
unsigned int debug  = DBG_BUS_RESP;
#else
unsigned int debug  = DBG_BUS_RESP| DBG_JMRI_MON;
#endif

// ---------------------------------------------------------
byte ioPins [] = {Hb, TxEn1, TxEn3 };
#define NumIoPins sizeof(ioPins)

// -----------------------------------------------------------------------------
void
loop (void)
{
#if defined __AVR_ATmega328P__      // Uno
    Serial1.listen ();
    if (Serial1.available()) {
        uint8_t c = Serial1.read ();
        Serial.println (c, HEX);
    }

#else
    jmriIf ();

    busProcess ();
    pcRead ();
#endif
}

// ---------------------------------------------------------
void
setup (void)
{
    char s [40];
    Serial.begin (115200);

    Serial1.begin(9600);
    if (! Serial1)
        Serial.println ("Serial1 begin failed");
    else {
        sprintf (s, "%s: RX1 %d, TX1 %d", __func__, RX1, TX1);
        Serial.println (s);
    }

    Serial3.begin(9600);
    if (! Serial3)
        Serial.println ("Serial3 begin failed");
    else {
        sprintf (s, "%s: RX3 %d, TX3 %d", __func__, RX3, TX3);
        Serial.println (s);
    }

    for (uint8_t i= 0; i < NumIoPins; i++)  {
        pinMode      (ioPins [i], OUTPUT);
        digitalWrite (ioPins [i], LOW);     // disable TX
    }

    Serial.println (version);

#if defined __AVR_ATmega328P__      // Uno
    Serial.println ("Uno");
#endif

#if defined __AVR_ATmega2560__
    Serial.println ("Mega");
#endif
}

cabbus.cpp (6.63 KB)

cabbus.h (226 Bytes)

CabUsb.h (605 Bytes)

jmriIf.cpp (4.29 KB)

jmriIf.h (215 Bytes)

keycodes.h (4.77 KB)

pcRead.cpp (4.33 KB)

gcjr:
i rebuilt the application for an Uno using software serial.

Stick with the Mega. Life will be a lot simpler.

...R

gcjr:
this is a big disappointment and I have to wonder how useful a soft serial interface can be if very little else can be done

Its not a disappointment at all, used correctly, and within its limitations, it allows Arduinos such as Unos and pro Minis to talk to serial devices, which is a good thing.

gcjr:
My understanding is the limitation is and RX pins are restricted to RX: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).

You implied in the first post you were using a UNO, in which case you can use all pins.

You appear to have posted the restrictions for a Mega.

srnet:
Its not a disappointment at all, used correctly, and within its limitations, it allows Arduinos such as Unos and pro Minis to talk to serial devices, which is a good thing.

how am I using it "incorrectly"?

how is it not a disappointment if it won't work at 9600 bps when presumably it's limitation is 57600 bps

I have actually tested the SoftwareSerial library and found that reliable communication is possible up to 38400 at most. I do not know if any of the other software serial libraries (NeoSWSerial, AltSoftSerial, ... ) are any faster.

The board listens on one virtual port (portOne) until it receives a "?" character. After that, it listens on the second virtual port (portTwo).

Also:

When using two software serial ports, you have to switch ports
by listen()ing on each one in turn. Pick a logical time to switch
ports, like the end of an expected transmission, or when the
buffer is empty. This example switches ports when there is nothing
more to read from a port

from Two Port Receive Example

so it seems that the software serial ports cannot be used as replacements for the hardware serial ports on the Mega.

in my case, one of the ports i'm trying to use as a software serial port has traffic at least every 4 ms.

Not with that library they're not. Maybe there's one that will do two software ports simultaneously, but I suspect not.

If you're switching boards for physical size reasons, take a look at the Teensy range, I see that the 3.1 has three serial ports.

gcjr:
how is it not a disappointment if it won't work at 9600 bps.

I have used it on a great may projects reading 9600baud GPSs on 8Mhz Arduino Pro Minis and no-doubt countless others have as well. This works.

What Software serial cannot do, as the documentation makes clear, is listen to two or more instances at the same time.

The Two Port Receive example you quoted, shows two Software serial ports defined, with each being read in turn using port.listen(). That you switch between the Software serial instances in this way should make clear that the two ports cannot be used simultaneously.

gcjr:
how am I using it "incorrectly"?

how is it not a disappointment if it won't work at 9600 bps when presumably it's limitation is 57600 bps

Its limitation is 38400. If it isn't working at 9600, you are doing something incorrectly. I think we can be quite sure that nobody is using it like you do with any success, and nobody else has bothered to look at your code, which is mostly junk as far as comms is concerned. You can start with this bit

SoftwareSerial Serial1 (RX1, TX1);
SoftwareSerial Serial3 (RX3, TX3);

And while you are at it, you might consider including the software serial library, any software serial library, as you won't get far without it. Now I don't have any software serial libraries, but the examples in yours will surely tell you how to do that. Further, if you can't work out whether you have a Uno or a Mega in your hand, swapping it all for a train set would be a good idea. So you as well get rid of all that that Uno<>Mega stuff, as it may just be adding to your problem, and a simple "hello world" test would be well in order.
Since you have a Mega, you would be well-advised to read reply#5 again, twice.

srnet:
The Two Port Receive example you quoted, shows two Software serial ports defined, with each being read in turn using port.listen(). That you switch between the Software serial instances in this way should make clear that the two ports cannot be used simultaneously.

which version of SoftwareSerial do you use?

isn't that what the example code (posted below from TwoPortReceive) is doing? it executes listen() on one port and checks available() then does the same for the the other port.

of course this a do nothing example. the limited delay in listening between each port is when processing a byte from the other port.

it's not clear to me how often and when specifically listen() needs to run.

void loop() {
  // By default, the last intialized port is listening.
  // when you want to listen on a port, explicitly select it:
  portOne.listen();
  Serial.println("Data from port one:");
  // while there is data coming in, read it
  // and send to the hardware serial port:
  while (portOne.available() > 0) {
    char inByte = portOne.read();
    Serial.write(inByte);
  }

  // blank line to separate data from the two ports:
  Serial.println();

  // Now listen on the second port
  portTwo.listen();
  // while there is data coming in, read it
  // and send to the hardware serial port:
  Serial.println("Data from port two:");
  while (portTwo.available() > 0) {
    char inByte = portTwo.read();
    Serial.write(inByte);
  }

  // blank line to separate data from the two ports:
  Serial.println();
}

Nick_Pyner:
I think we can be quite sure that nobody is using it like you do with any success,

is that because SoftwareSerial is too limited for such an application?

Nick_Pyner:
and nobody else has bothered to look at your code, which is mostly junk as far as comms is concerned.

got the interface working in a couple hours using a Mega

Nick_Pyner:
And while you are at it, you might consider including the software serial library,

which version of the library do you use?

Nick_Pyner:
Further, if you can't work out whether you have a Uno or a Mega in your hand,

i want to use the same code on either an Uno or Mega. The code determines the hardware using a defined macro.

#if defined __AVR_ATmega328P__      // Uno

gcjr:
is that because SoftwareSerial is too limited for such an application?

In your case, no. I'm afraid it is because you don't know what you are doing.

got the interface working in a couple hours using a Mega

Good. I guess you now see the advantage of the Mega

which version of the library do you use?

I don't use software serial ever. Mostly I use a Mega, but I don't use it on a Uno or my Pro Mini either. There is no need. There certainly are cases where you have no option but to use software serial, but it is more rare than you would think, and when you do it is under sufferance. Quite often software serial is just a refuge for the lazy and incompetent.

i want to use the same code on either an Uno or Mega. The code determines the hardware using a defined macro.

#if defined __AVR_ATmega328P__      // Uno

That sounds like a particularly dumb idea. God only knows what the motivation for that is and, if it means you are obliged to use software serial on a Mega, that would be code you should definitely not show your mother. Most code that will run on a Uno will run essentially verbatim on a Mega, but one of the major differences, thereby requiring different code, is serial communication.

Nick_Pyner:
I don't use software serial ever.

wow! ??

Nick_Pyner:
God only knows what the motivation for that is and, if it means you are obliged to use software serial on a Mega, that would be code you should definitely not show your mother.

the purpose is not to use SoftwareSerial unnecessarily on a Mega but be able switch back to the Mega to verify that any changes don't break the code.

it's pretty common in industry. i guess you've never had to write code professionally that needs to operate on different types of hardware. I've had to work on RF code that supports different RF hardware that operates on different bands with various restrictions

gcjr:
wow! ??

No wow, just no need. My serial peripheral adventures involve just one Bluetooth connected at 115200. In that situation, there is never ever a need to use software serial, and it wouldn't work at that speed anyway.

the purpose is not to use SoftwareSerial unnecessarily on a Mega but be able switch back to the Mega to verify that any changes don't break the code.

Whatever floats your boat.... Don't bother explaining why you wouldn't use another Uno to do that. I assume no RTC or SD card is involved in your exercise, and you confine software serial to pins that work on a Mega.