Using two instances with SoftwareSerial fails [RESOLVED]

Hi all
I am having trouble getting my little project working properly. What I want to acheve is to extract positioning data from a Fastrax UP501 GPS module, and parse them to a Wavecom Fastrack M1306B GSM module for sending them by SMS. Both modules use serial communication at 9600 baud. I use the latest Arduino 1.0 environment with the build-in SoftwareSerial.
Now - I am having trouble getting the SoftwareSerial working properly with two instances. When I uncomment the GSM routines, the GPS part works properly, and when I uncomment
the GPS routines, the GSM part works properly. But when I combine the two routines, the communication fails. If I am lucky, I get some data randomly, but it is mostly rubbish.

For the purpose, I have provided this small sample code. This “to the bone” code generates the problem just fine. Can someone see from the code if I am doing something wrong - or maby provide a workaround!?

Best regards
Flemming

#include <SoftwareSerial.h>
SoftwareSerial gps(6, 7);
SoftwareSerial gsm(3,2);

void setup()
{
  Serial.begin(9600);
  gps.begin(9600);
  gsm.begin(9600);
}

void check_gsm()
{
  while (gsm.available() > 0) {
    char inByte = gsm.read();
    Serial.write(inByte);
    }
}

void check_gps()
{
  while (gps.available() > 0) {
    char inByte = gps.read();
    Serial.write(inByte);
    }
    Serial.println();
}

void loop()
{
  gsm.listen();
  check_gsm();
  
  delay(500);
  
  gps.listen();
  check_gps();
}

You can have multiple instances of software serial, but there is a restriction in that you can only receive data from one instance at a time.

There are details here: http://arduiniana.org/libraries/newsoftserial/ - check the "Using Multiple Instances" section.

So basically you need to call gsm.listen() when you want to receive data from the gsm module, and gps.listen() when you want to receive data from the gps module. Note that the softserial being() method calls listen() also.

If the device you are not listening to sends any serial data you will not receive it.

I saw this the other day and thought it might help. http://www.adafruit.com/blog/2012/02/13/altsoftserial-library-for-an-extra-serial-port/

They add extra hardware to buffer the 2nd serial port so data isn't lost.

Thanks - I did read the link you provided, and thought that I was using the gsm.listen() and gps.listen() correctely. When I see the sample code there, they first call the "listen" method to activate it, and then they call the actual code getting the data. When I look at my code, it seems to me that I do the same. Should I re-arrange something i the code?

However - I now think that the problem is that data is not getting in simultaneously. The GPS transmits every second, and the GSM modem only transmits when a SMS is recieved. Instead I need to read if any SMS has arrived, and not polling the modem for any activity.

void loop()
{
  ...
  // collect data from the GPS unit for a few seconds
  gps.listen();
  read_gps_data();  // use gps as active device
  // collect temperature data from thermometer
  therm.listen();
  read_thermometer_data(); // now use therm
  // LCD becomes the active device here
  LCD.listen();
  LCD.print("Data gathered...");
  ...
}

dhunt: You can have multiple instances of software serial, but there is a restriction in that you can only receive data from one instance at a time.

There are details here: http://arduiniana.org/libraries/newsoftserial/ - check the "Using Multiple Instances" section.

So basically you need to call gsm.listen() when you want to receive data from the gsm module, and gps.listen() when you want to receive data from the gps module. Note that the softserial being() method calls listen() also.

If the device you are not listening to sends any serial data you will not receive it.

I think a HW solution could be a good idea if my solution with reading the SMS status does not work. I would prefer a solution that uses a buffer and interrupt, that way I could use polling and still use SoftwareSerial.

hellonearthis:
I saw this the other day and thought it might help.
http://www.adafruit.com/blog/2012/02/13/altsoftserial-library-for-an-extra-serial-port/

They add extra hardware to buffer the 2nd serial port so data isn’t lost.

Lemme:
Thanks - I did read the link you provided, and thought that I was using the gsm.listen() and gps.listen() correctely. When I see the sample code there, they first call the “listen” method to activate it, and then they call the actual code getting the data. When I look at my code, it seems to me that I do the same. Should I re-arrange something i the code?

However - I now think that the problem is that data is not getting in simultaneously. The GPS transmits every second, and the GSM modem only transmits when a SMS is recieved. Instead I need to read if any SMS has arrived, and not polling the modem for any activity.

Ah yes, I didn’t pay attention to your main loop.

So multiple instances of software serial only seems useful when you can control when the peripheral sends its data, for example if the peripheral waits for a command from the arduino and then responds. I don’t think you will be able to use multiple instances when the peripherals are sending asynchronous messages to the arduino.

I’m not sure if you can use Paul Stoffregen’s AltSoftSerial interface and an instance of software serial together, but that might be an option. Another option would be to use the hardware serial port for one device and software serial for the second.

If you need to use the hardware serial interface for PC communication then I think you really need dedicated hardware serial interfaces for the other devices - maybe consider a Mega board that provides four hardware serial interfaces?

Instead I need to read if any SMS has arrived, and not polling the modem for any activity.

You really need different hardware. You can effectively use multiple software serial ports only for sending. NOT for receiving.

If you are listening to the gsm port, nothing that happens on the gps port will be noticed. If you are listening to the gps port, nothing that happens on the gsm port will be noticed.

Software serial is like having one telephone and two jacks. You can plug the phone into one jack or the other. When it is plugged into the gps jack, a call to the gsm jack will not make your phone won't ring. If the phone is plugged into the gsm jack, a call to the gps jack will not make your phone ring. Moving the phone from one jack to the other will not tell you about missed calls.

You really need another phone.

Thanks for the answer. I now realise the limitations of SoftwareSerial. Fortunally I can make the code wait for the GPS data to arrive, and then move on to the other task where I actively ask the modem and get the result right away. This way I keep to the sequence. And i now works!

Thanks
Flemming

hellonearthis: They add extra hardware to buffer the 2nd serial port so data isn't lost.

Not really. There is no hardware involved, this is simply a variation of the Software Serial that has better performance.

The "extra" hardware shown in the posting is for the RS232/TTL serial conversion.

Brad (KF7FER)