Implementing an optical UART Tx line via SoftwareSerial - Reading nonsense

Hi all,

I am working on a "Li-Fi" - themed project, where my current goal is to transmit a message string serially between two Arduino Nanos, with the physical data line being replaced by a simple LED driver and photodiode receiver circuitry.

I am trying to write a message string in ASCII to a SoftwareSerial defined serial port. The Tx pin for the SoftwareSerial port is used to drive the gate of a 2N7000 that sinks an LED load. The LED strobes are received by op amp circuitry and fed to the input of a comparator as a 1-bit ADC. The result looks something like this for a three character message with newline and carriage return appended:

NOTE: In the above image, the yellow signal trace is the voltage measured directly at the Tx pin of the dedicated transmitting Arduino. The green trace is the voltage measured after amplification and the digitization on the receive end (to be read by a different Arduino). The green trace is inverted via the oscilloscope, and I am using inverted logic in my SoftwareSerial object to (I believe) accomplish the same effect.

I'll also add this; the signal captures with the green trace not inverted (so the signal that the receive Arduino truly sees):


////////
CODE
\\\\\\\\
My code for the transmitted signal (ie the Arduino driving the LED; the yellow trace):

//This program takes a predefined input string and sends it via the software serial
//Tx pin upon the press of a push button input attached to D5 

#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3
#define buttonPin 5

String password;
String msg = "ffx\n\r";
int pbState = 0;

SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  // Define pin modes
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
    
  // Set the baud rate for the SoftwareSerial object
  mySerial.begin(115200);

}

void loop() {
  
  password = msg;
  
  //Write hex string to software serial tx pin
  
  if (digitalRead(buttonPin) == 1 & pbState == 0) {
    mySerial.print(password); 
    pbState = 1;  
    digitalWrite(LED_BUILTIN, HIGH);
  }
  
  if (digitalRead(buttonPin) == 0 & pbState == 1) {
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Message sent via software serial...");
    delay(10);
    pbState = 0;
  }
  
}

It seems for testing as of now this transmit code works fine, but on the receive end, I am seeing a bunch of question marks, despite the fact that the signals look nearly identical when measured (they have a delay between them on the order of a 0.5-2 µs). Here is my code for the reading the received (green trace) photodiode signal:

//This program reads an input string received on a software serial defined
//serial port. The HW serial port is used for debugging means.

#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3

String password;
String msg = "Waiting for msg... ";

SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin, true);

void setup() {
  //Init hardware serial for debugging means
  Serial.begin(115200);

  // Define pin modes for TX and RX
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
    
  // Set the baud rate for the SoftwareSerial object
  mySerial.begin(115200);

}

void loop() {
  //Print greeting message
  Serial.println(msg);
  
  //Wait for a string to be entered
  while (mySerial.available() == 0) {}
  
  //Store string
  password = mySerial.readString();
  
  //Write hex string to HW serial tx pin
  Serial.print(password);
  
}

And the funny results I was mentioning:

So you can see it looks like it sometimes gets it, sometimes not.

Here's where I'm at:

I don't think the logical inversion has anything to do with it since when chars are recognized, they are the correct ones ('f' and 'x'). This leads me to think its some issue with using readString() on a software serial object, but I also didn't notice a similar problem when the the Arduino's were wired directly together. And full-circle, the signals look so similar that I'm not sure how substituting the Tx line for the LED:Photodiode:amplifier equivalent would cause this. I am looking for guidance as to what could be my issue. Hopefully it is reconcilable without adjusting my hardware setup too much. For example adding a channel for duplexed communication would not be easy.

Thanks for your time.

Have you tried lower baud rates? Maybe start at 9600 and work your way up.

Have you tried printing the character values in binary? Perhaps you are getting single bit errors.

In UNO/Nano SoftwareSerial supports up to 57600 bps maximum.

Could you use one signal channel of your hantek to TX of the sending arduino and RX of the receiving arduino - and then space the traces apart so that it's clearly visible what signal is what - and how they relate?

I assume you meant && instead of &? Not only here...

I assume you meant && instead of &? Not only here...

Thanks for your input; indeed I was looking for logical AND. Made the change.

SoftwareSerial supports baud rates as slow as 300, I would start with that. No way would I expect 115200 to work using optical coupling, that is hard enough if not impossible to get working with a direct connection because of the intense cpu usage.

1 Like

In UNO/Nano SoftwareSerial supports up to 57600 bps maximum.

Ahhh... I misread that bullet point on the library documentation page. I changed to 57600 baud and it works without a hitch. Thanks for your help.

Have you tried lower baud rates? Maybe start at 9600 and work your way up.

Hi Paul, thanks for your input. It looks like slowing down the baud rate fixed the erroneous reads. I marked your reply as the solution since yours was earliest.

Could you use one signal channel of your hantek to TX of the sending arduino and RX of the receiving arduino - and then space the traces apart so that it's clearly visible what signal is what - and how they relate?

This is a recapture using 57600 baud. Again the yellow trace is the sent message and green is the message as it is received. The problem was addressed by lowering the baud rate for software serial.

No way would I expect 115200 to work using optical coupling, that is hard enough if not impossible to get working with a direct connection because of the intense cpu usage.

What about with an ESP8266 board at a much higher clock speed? Or would SoftwareSerial be limited still?

For what it's worth; switching the baud rate to 57600 for SS fixed the misreads.

With an ESP8266, I would use hardware serial and if needed an external inverter, although it looks like signal inversion may be supported https://github.com/esp8266/Arduino/issues/4896

Over what distance are you expecting to be using the optical link? The usable baud rate will generally drop with distance.

Why waste cycles on ANY processor trying to do something in software that's more appropriately done in hardware? Use a board that has an available hardware UART and make your life much easier.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.