2

I have an Arduino Uno. It's role is to echo back what it receives.
But if I send it a stream of ascii characters it starts to error after the first one. Occasionally it gets the second character correct but often not.

If I delay each character then it works ok. I couldn't see this limitation mentioned in the SoftwareSerial library: https://www.arduino.cc/en/Reference/SoftwareSerial

The Arduino is running the following code:

#define BT_RX_PIN 16 // A2
#define BT_TX_PIN 17 // A3
#include <SoftwareSerial.h>
SoftwareSerial OtherSerial(BT_RX_PIN, BT_TX_PIN);

void setup()
{
  Serial.begin(9600);  // not used
  OtherSerial.begin(9600);
}

void loop()
{
  if (OtherSerial.available()) {
    char value = OtherSerial.read();
    String stri = "Received: ";
    stri += value;
    OtherSerial.println(stri);
  }
}

The limitations do say "If using multiple software serial ports, only one can receive data at a time.". I don't have multiple software serial ports though I do have an instance of the "normal" serial port but I'm not sending any data to it... but perhaps even just initialising it is enough to disrupt seamless communication with the SoftwareSerial port?

Using the following test code for serial communication from a Raspberry Pi (using logic level conversion to go from 5V -> 3.3V and visa versa):

import time

def write(msg, delay):
  for char in msg:
    with open("/dev/ttyAMA0", "w") as f:
      f.write(char)
      time.sleep(delay)

write("hello", 0.01) # repeated 10 times at each delay time

I got the following results:

Delay (ms)   |   Success rate
10           |   100 %
9            |   100 %
8            |     0 %
5            |     0 %
1            |     0 %

A delay of 9 ms between each character means the communication rate falls from ~ 960 characters per second (9600 baud / 10 bits per 7 bit character) to ~ 100 characters per second (1 / (1 / 960 characters per second + 9ms)). Is this right? Perhaps I'm doing something else wrong / set it up wrong in software / hardware?

  • Really, there is no "best delay" as it appears the delay needed depends on what the RPi sends the Arduino. The more the RPi sends, the longer the delay in order for the Arduino to not let any data go missing. – st2000 Jun 23 at 0:49
  • Are you opening the serial port for every single character? Why? Should you not put the with line before the for line? – Nick Gammon Jun 23 at 4:39
  • @NickGammon it was a quick hack to flush the characters to the file. – AJP Jun 23 at 9:38
  • 1
    Fairly obviously, you will get much better throughput if you don't send the word "Received:" for each character you receive. That's like putting 13 litres of water into a bucket every second and taking 1 litre out, and then wondering why it overflows. – Nick Gammon Jun 23 at 10:54
  • 1
    The documentation should indeed make it clear that SoftwareSerial cannot receive at the same time as it is transmitting, so it is not a good choice for attempting to do that. – Nick Gammon Jun 23 at 21:47
5

Simply put, a serial port implemented in software requires the program to sample the input pin fast enough to detect every transition. To satisfy the Nyquist frequency rate we need the program to sample the data twice as fast as we expect the data to change.

A serial port implemented in hardware might only need to be sampled at 1/16 this rate assuming the data size is 8 bits.

Your program implements a serial port in software which is admirably keeping up with the received data. However, when you tell the program to send the message "Received" plus the string that was received, the program stops looking at the serial input pin long enough for data to go missing.

By far the easiest solution would be to use a hardware implemented serial port. If this is not possible consider approaching the problem using interrupts. However, while a powerful programming tool, interrupts can be difficult to implement and hard to debug.

5

SoftwareSerial has a considerable overhead. It can often send at 115200 successfully but 9600 is about its limit for receiving, and you're trying both send and receive. In addition, for each character your code receives, it transmits considerably more than that 1 character (11 characters, by my count). It isn't too surprising that it would fall behind. You will need to either reduce the size of what you echo or reduce the rate at which you send characters to it (which is what you accomplished with your delay) so that the transmission (echo) rate can keep up.

Update:

The OP reports success with continuous reception by, and transmission from, the Arduino at 57600 baud (but not at the same time). The transmission rate would be consistent with my experience transmitting at 115200 baud (blindly and for short bursts, to reconfigure ESP8266-01s that were shipped with a preset 115200 rate.

  • 1
    13 characters because of the carriage-return/newline. This is right, you can't expect to send 13 characters for every one you receive, and keep up. Plus, when SoftwareSerial sends it turns interrupts off, so it can't receive at the same time. – Nick Gammon Jun 23 at 4:31
  • @JRobert I've managed to successfully transmit continuously at 57600 baud (but with no transmit from the Arduino until after the whole message has been sent to it). Could you edit your answer to reflect this and I'll mark it as the "correct" answer. Thanks. – AJP Jun 23 at 12:02
  • Sure - is that 57600 transmission to- or from the Arduino? Not having the direct experience, I feel I should quote yours in my update. – JRobert Jun 23 at 16:31
  • Yes 57600 transmission is to and from. I tried with 115200 but (and perhaps it's due to my longer electrical wires / lack of proper grounding / interference) but this didn't work and the echo was garbage. This could have just been the transmit from the Arduino to the Raspberry Pi but regardless in this case it didn't work at 115200 but did at 57600. – AJP Jun 23 at 22:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.