Can't get multiple SoftwareSerial to run on the Mega

I've been using hardware Serial1, Serial2, Serial3 on a Mega to communicate with other Arduinos. I have a need to talk to more than 3 (although only infrequently) so I'm trying to figure out how to use the SoftwareSerial library.

I am using Arduino 1.0.5 on Windows 7.

I started with the sketch "Two part receive" example in the softwareSerial library and have left most of the original comments intact:

const char sketch[] = "SoftwareSerialTest_2013aug20MasterE";  // August 2013 by Rick Rantilla

// rev E - keep it as simple as possible
/*
  Software serial multple serial test
 
 Receives from the two software serial ports, 
 sends to the hardware serial port. 
 
 In order to listen on a software port, you call port.listen(). 
 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
 
 The circuit: 
 Two devices which communicate serially are needed.
 * First serial device's TX attached to digital pin 2, RX to pin 3
 * Second serial device's TX attached to digital pin 4, RX to pin 5
 
 Note:
 Not all pins on the Mega and Mega 2560 support change interrupts, 
 so only the following can be used for RX: 
 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69
 
 Not all pins on the Leonardo support change interrupts, 
 so only the following can be used for RX: 
 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).
 
 created 18 Apr. 2011
 modified 25 May 2012
 by Tom Igoe
 based on Mikal Hart's twoPortRXExample
 
 This example code is in the public domain.
 
 */

#include <SoftwareSerial.h>
// software serial #1: TX = digital pin 10, RX = digital pin 11
//SoftwareSerial portOne(10,11);
SoftwareSerial portOne(12,2);

//Sample program is confusing on RX and TX
//From the arduino reference:
//A call to SoftwareSerial(rxPin, txPin) creates a new SoftwareSerial object

// software serial #2: TX = digital pin 8, RX = digital pin 9
// on the Mega, use other pins instead, since 8 and 9 don't work on the Mega
SoftwareSerial portTwo(13,3);

void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(57600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.println(sketch); // so I can always tell what is actually in the Arduino
  // Start each serial port
  portTwo.begin(9600);
  Serial1.begin(9600);  // On the Mega, Serial1 is TX pin 18, RX pin 19
  portOne.begin(9600);
  additionalSoftwarePort();  // x x x x x x x x x x x x x x x x x x x x x
}


void loop()
{
  hardwarePort();
  firstSoftwarePort();
  //additionalSoftwarePort();  // x x x x x x x x x x x x x x x x x x x x x
  delay(500); // just to slow the display down
  // blank line to separate a cycle
  Serial.println();
}  
  

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


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


void hardwarePort(void)
{
  // now for a hardware serial port
  Serial.println("hardware:");
  // while there is data coming in, read it
  // and send to the hardware serial port:
  while (Serial1.available() > 0) {
    char inByte = Serial1.read();
    Serial.write(inByte);
  }
}

I've added one hardware Serial1 port to keep it familiar, to see what stops working when and to keep myself sane. As shown here, I have 3 "slave" Arduinos connected from their pins 0 and 1 to appropriate pins on the Mega and have the slaves sending short messages every few seconds. The sketch always passes data from the slave connected to the Serial1 port (pins 18 and 19) to my computer monitor. As written above, the data from softwareSerial portOne also gets passed to my monitor. However, if I play with the two lines that have all the "x"s I get into trouble. If I comment out the call to additionalSoftwarePort() in the setup and place it inside of the main loop, then not only do I NOT get anything from softwareSerial portTwo, but I get nothing from portOne as well. Hardware Serial1 port keeps on humming.

(As another glitch, if I keep both calls to additionalSoftwarePort() in the program it won't compile at all.)

I've made sure my RX and TX pins are correct. I've swapped out the mega's. I've checked I don't have a library of NewSoftSerial stuck in the mix. I've incorporated everything I've found in the forum and on Google to try to get two SoftwareSerial ports to run on the Mega but have run out of ideas.

Thanks in advance for any other leads.

SoftwareSerial requires pin change interrupts. Not all pins on the Mega support that. I don't have the reference right here, but I would check that out.

Thanks, Nick. The notes that came with Tom Igoe and Mikal Hart's example cover the Mega pin change interrupts, although they are a little inconsistant with the article the example is embedded it. The Software Serial Library article says: "Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69)." The example program says: "Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69" so I steered away from pins 14 and 15 which might not have change interrupts on some Mega models. Any other ideas?

14 & 15 are hardware serial?

Yes 14 and 15 are hardware Serial3. I don't know why the library authors suggested these pins for softwareserial and I haven't tried them.

I could also use pins 0 and 1 for Serial to get a 4th hardware serial connection but doing so is a pain because I can't use the USB monitor at the same time. So far I can get up to 4 hardware serial ports and at most one softwareserial port.

Here is a little more background on my project.

I have 6-12 modules in each system. Each module has to send/receive up to 5 different types of signals to the host Mega. I started multiplexing the the signals to try to get them down to 4-wires (in, out, power and ground). While debugging the breadboard on a module the other day I realized these breadboards were becoming micro-controllers in themselves. So I just replaced each breadboard with a UNO and did everything for the local module in software. Now I'm struggling with communicating between the UNOs and the Mega Master. If I can get only 4 hardware and one software serial from a Mega, I could make sub networks. But softwareSerial has to have been invented to avoid this. Help!

have you looked at using I2C or SPI instead?

I agree with aarondc. Connecting via I2C seems the obvious thing. Using two wires (plus power and ground) you can connect dozens of boards. Just give each one a different address. It's somewhat faster than serial, too.

Well, everything new seems easy before you start on it. Then little things begin to creep in. I thought I2C and SPI were limited to a few meters or less. I need about 10 meters between the farthest points in the network. Also my network has to be set up in a star configuration since users will be adding and removing nodes and the Master has to figure this out on the fly.

In any case, has anyone ever successfully used multiple serialsoftware connections?

Have you successfully used multiple I2c connections with Arduinos?

I did a little more checking, so unless someone knows better I2C and SPI seem too limited for my application.

The I2C protocol specification on Wikipedia says it is limited to a few meters and seems to be designed for very stable configurations.

The SPI protocol seems to require 4 wires plus power and ground (total 6 wires) and also seems to not work well with dynamically adding nodes.

I briefly looked at USB, especially since each UNO already has a USB connector, but I'm not familiar with USB protocols. I have a Mega ADK with a host USB port. Maybe I could hook a "squid" USB port expander to it and use a standard USB cable from each UNO. --- OOPs! The Arduino USB Host reference page says "USBHost does not support devices that are connected through USB hubs." So I guess it is only good for connecting 1 peripheral.

Looks like I'm back to trying to make softwareserial work or designing my own communications protocol from scratch. Actually I have a scratch protocol half developed before I switched from breadboards in each module to UNOs.

Well you are perhaps pushing async serial for 10 meters.

SoftwareSerial can be problematic, particularly if you have multiple instances of it. One approach would be to use a multiplexer to share 8 or 16 incoming lines with one instance of a serial port (preferably hardware serial).

However you can slow I2C right down, which should compensate for any capacitance over long runs.

Have you successfully used multiple I2c connections with Arduinos?

The sketch below, modified from my I2C page, shows sending to two Arduinos from a third one:

#include <Wire.h>

const byte SLAVE1 = 42;
const byte SLAVE2 = 43;
const byte LED = 13;

void setup () 
{
  Wire.begin ();
  pinMode (LED, OUTPUT);     
}  // end of setup

void loop () 
{
  for (byte slave = SLAVE1; slave <= SLAVE2; slave++)
  {
    for (byte x = 2; x <= 7; x++)
    {  
      Wire.beginTransmission (slave);
      Wire.write (x);
      if (Wire.endTransmission () == 0)
        digitalWrite (LED, HIGH); 
      else
        digitalWrite (LED, LOW); 
      delay (200);
    }  // end of for loop
  }  // end of for each slave
}  // end of loop

I need about 10 meters between the farthest points in the network. Also my network has to be set up in a star configuration ...

Despite the star configuration, the longest cable run is 10 m?

There are I2C driver chips, you know.

nrf2401+ has the range and you could set up the script to auto detect new nodes. a bit more work but it's been done as a mesh network and has a lot of posts, library or two.

Well the I2C/TWI was a good diversion... but no cigar!

My bad. I haven't described enough requirements. I was using the star network to simplify field replacement of modules, trying to make the slave modules as similar as possible. In my application, if something hooks up to the host/master on an available port, the Master should know how to talk to it. With an I2C/TWI network (as I understand it) a replacement slave that might be hooked up has to have the same address built into it as the previous old module before the Master could make sense of it. Or at least the replacement would have to have a unique address compared to any others already on the network. I can't expect users to be setting switches or keeping track of addresses loaded in software on replacement or reconfigured modules. Unless I'm missing something.

I found reference to the 1-wire protocol where every slave device would have a world-wide unique 48-bit address. These addresses are written into a chip at the factory. The master has a protocol for identifying the unique address of any new device added to the network. The only thing I'd have to add is a single 1-wire interface chip to each UNO and its module. Anyone have any experience with 1-wire?

If not, I'm back to hoping someone can show me how to do SoftwareSerial for real, or I'll make a multilayer Hardware Serial network.

Actually I have a plan B. I think I can reduce all the communication down to sending very few types of messages in either direction. If there are enough interrupt enabled pins on the mega then I can probably write a very simple toggle protocol. I think I can get by with just:

The messages slave to master: 1-I'm here, add me to the network, 2-I need your permission to continue, 3-Increment the master counter or 4-I acknowledge your command/request.
The messages master to slave: 1-acknowledge (so I know you exist), 2-Increment your display for the user or 3-Yes you have my permission to continue or 4-No you should not continue.

aarondc:

The nrf2401 is kind of neat, but I'd have to think through a couple of issues: 1) I still need to get power to the slave modules by running a cable. 2) The slave module would need some kind of address/identifier that is guaranteed to be unique from all the other modules on the network. It will take me some time to work through the mesh network/auto detect posts. 3) I'm a little reluctant to start adding chip count to the modules, again.

Incidently I have a future plan to use bluetooth or something from an Android phone to send parameters to the Master, so radio is "on my radar", just I hadn't planned on dealing with it yet. Putting a nrf2401 into each module may eliminate the Master entirely, except for power. I have servos and stuff on the modules so I do need more than just battery power.

In the meantime, I'll take a little look at multiplexors. If I only have to do one at the Master and essentially end up with a bunch of point to point serial lines that might be a good way to get above 4/5 lines out limit of the Mega.

PS. I'm still looking for help on SoftwareSerial or a clear indication that multiple SoftwareSerial doesn't work.

I'm making progress with my own simple protocol using the attachInterrupt function on pins 2,3 18,19,20 and 21. (Like the onRequest function in the wire library only using 6 separate wires.)

In the SoftwareSerial library it says " Note:
Not all pins on the Mega and Mega 2560 support change interrupts,
so only the following can be used for RX:
10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69"

This makes me think that these 16 pins do support change interrupts, whatever they are. If they can be accessed (like the attachInterrupt function can set up interrupts on pins 2,3,18, 19, 20 and 21) then I can hook up 16 communication lines with my own protocol. How does one access this "change interrupt" function on these 16 pins?

How many devices are you talking to?

I'm not trying to push a particular solution, but conceivably a new (I2C) device could ask for an address to be allocated. I believe the Lego Mindstorms uses I2C, and they have lots of pluggable devices. For that matter, how does DHCP work? I don't think the allocation of addresses is an insoluble problem.

If not, I'm back to hoping someone can show me how to do SoftwareSerial for real, or I'll make a multilayer Hardware Serial network.

Meh, is all I can say to that. With respect, SoftwareSerial uses pin changes interrupts and bit-banging. I'm not surprised it isn't scalable. I use it myself with one additional device. Not dozens.

In my application I have typically 6 modules each Master must talk to. However, I have to be prepared to talk to as many as 12 modules. I don't anticipate any modules ever being more than 10 meters from the Master. The modules have nothing to say to each other, they just talk to the Master. However, either the Master or the slaves can initiate a transaction. There SHOULD never be more than one transaction in any given second anywhere on each network (except for a request/acknowledgement pair).

There could be a "user error" condition where a user presses a module control button at the same time as the user is replacing a different module. A warning to not do this or to power down the master when adding/changing modules probably won't be sufficient to prevent it. I'm still thinking this through.

As I said in reply #10, a 16-port multiplexer (or two) could do it for you. Then just use one hardware serial port. However one issue would be knowing which port on the multiplexer to have selected. Some sort of wired-OR could solve that.

Discussion about that:

So you could have each serial input line wired to one multiplexer, and also via diodes as shown to an interrupt pin. When the state changes you immediately use the multiplexer to quickly poll the ports to find which one changed (eg. by having the slave send a dummy 0x00 byte which should give you time). Once you know which port, you switch the multiplexer to that, and also the second multiplexer for the (serial) output line. Do the transaction, and then go back into idle state. Total usage: 3 pins (Rx, Tx, interrupt) plus two multiplexer chips, and one diode per incoming line.

Use a weak pull-up on all outgoing Tx lines to hold them high (idle) when not selected.

Thanks, Nick. Although I don't understand multiplexers very well, I can almost understand your explanation of using the diodes to figure out which pin called.

I'm going to move on in this project as I have a lot of other issues to deal with. For now, I'm going to use the 6 hardware interrupts on the Mega to each communicate with one slave. I've written a simple protocol I understand and feel I have control of. Having 6 slaves hooked up will give me some good experience with timing, cable distances and strange user behavior.

Later I can use one or two of the lines to hook to other Megas in the Master box and get more slaves 5 at a time. But it is good to have options. If I have time, I'll come back to some of these ideas you and Aaron have helped me with.

I'll post back here when I've hit the next significant milestone if you are interested.