SoftwareSerial comms stop working if Arduino not power-cycled

I’m trying to set-up serial communications between this SparkFun fingerprint sensor and an Arduino UNO using SoftwareSerial but am having trouble getting it properly working.

Background
The Arduino UNO has a single hardware serial port (RX = pin 0, TX = pin 1) but this is also used for USB comms which I currently need for debugging and uploading purposes.

I’m trying to use SoftwareSerial on pins A4 (18) and A5 (19), with the sensor’s TX (Arduino’s RX) being pin A5, and sensor’s RX (Arduino’s TX) on pin A4. I have a simple voltage divider on the sensor’s RX pin to bring the 5V signal from the Arduino down to ~3.2V (561ohm + 1kohm).

NOTE: One important detail is that I did not properly hook up the sensor initially. The sensor’s TX wire was on +5V power and the RX wire on GND, with the actual power and ground wires in two different digital pins. The Arduino was powered on with the sensor hooked up like this for a while before I caught the error, and it did get noticeably hot although there’s no damage I can visually make-out now. Even properly plugged in, however, the sensor does get fairly hot and I don’t know if that’s normal.

I plan on writing my own library to interface with the sensor, but at the moment I’m using this known good library just to make sure everything works before I start playing around with things. Currently I’m trying out the LED blink example provided with the library.

The problem
When the Arduino is initially plugged in, everything works perfectly fine. The sensor’s CMOS LED blinks as expected, it seems like communications are working properly. However, the moment I open the Serial terminal, try to upload code, or hit the hardware reset button, and the Arduino resets, nothing works anymore. The last code that runs is the Serial write, and then the program hangs while waiting on the response from the sensor. Since it hangs on the response, the LED on/off packets are not sent the and the LED stops blinking. This implies that when the Arduino is properly plugged in, just the fact that the LED is blinking on/off means that both TX and RX packets are being sent/received properly.

Code
All the library code is a straight copy-paste from the GitHub provided above.

My sketch is as follows:

#include "FPS_GT511C3.h"

FPS_GT511C3 fps(19, 18);

void setup() {
    Serial.begin(9600);
    fps.UseSerialDebug = true; // so you can see the messages in the serial debug screen
    fps.Open();
}

void loop() {
    fps.SetLED(true); // turn on the LED inside the fps
    delay(1000);
    fps.SetLED(false);// turn off the LED inside the fps
    delay(1000);
}

Wow, that’s the prettiest BAD library I’ve seen. Ever.

  • It uses SoftwareSerial, a real CPU killer
  • It uses heap, a LOT!
  • It blocks on responses
  • It doesn’t do any error checking
  • It doesn’t have a timeout on blocking operations (probably why it hangs)
  • It doesn’t use F macro for string constants
    Needless to say, I’m glad to hear you’re going to re-write it. It is begging for a finite-state machine implementation and proper memory usage. Gak.

That said, you could easily replace SoftwareSerial with NeoSWSerial in the H file. If you’d be willing to use pins 8 and 9 instead, you could also use AltSoftSerial (remove the listen calls).

For the one method you call, you could try this instead:

bool FPS_GT511C3::SetLED(bool on)
{
	Command_Packet cp;
	cp.Command = Command_Packet::Commands::CmosLed;
	if (on)
	{
		if (UseSerialDebug) Serial.println( F("FPS - LED on") );
		cp.Parameter[0] = 0x01;
	}
	else
	{
		if (UseSerialDebug) Serial.println( F("FPS - LED off") );
		cp.Parameter[0] = 0x00;
	}
	cp.Parameter[1] = 0x00;
	cp.Parameter[2] = 0x00;
	cp.Parameter[3] = 0x00;

	byte* packetbytes = cp.GetPacketBytes();
	SendCommand(packetbytes, 12);

	Response_Packet* rp = GetResponse();
	bool retval = rp->ACK;

	delete rp;
	delete packetbytes;

	return retval;
}

A lot of things to be fixed, though. Using the F macro everywhere (as above) could decrease the RAM usage enough that maybe all the new/delete calls have a little more room to work.

Putting a timeout in ::GetResponse would also help the sketch get back “in sync” with the packet boundaries and avoid the hangs:

const uint16_t FPS_TIMEOUT = 250; // ms

Response_Packet* FPS_GT511C3::GetResponse()
{
  _serial.listen();

  uint16_t startTime = millis();
  uint8_t  i = 0;
  byte     resp[12];
  
  do {
    if (_serial.available()) {
      resp[i] = (byte) _serial.read();
      if ((i > 0) || (resp[0] == Response_Packet::COMMAND_START_CODE_1))
        i++;
    }
  } while ( (i < sizeof(resp)) && ((uint16_t) millis() - startTime < FPS_TIMEOUT) );

  // No error checking!  What if no response?!?
  
  Response_Packet* rp = new Response_Packet( *resp, UseSerialDebug );

  if (UseSerialDebug) 
  {
    Serial.print( F("FPS - RECV: ") );
    SendToSerial(rp->RawBytes, 12);
    Serial.println();
    Serial.println();
  }

  return rp;
}

I didn’t try compiling any of my suggestions, so there might be some typos. I gotta go get my brain bleach.

Plehhhh,
/devv

Haha yea it's definitely not the best, and it's the only lib for that device as far as I can tell. Once I get this issue figured out I plan on re-writing it and putting it up as an alternative.

Lots of good ideas here for the library, but the thing that's got me really confused is that the problem remains with the library completely removed. To see if that was the issue, I just took it out entirely and tried bit-banging my way to success, but the same exact issue happens: works when initially powered-on, fails to work when reset.

The code at this point couldn't be any simpler, just initialize a NeoSWSerial object, start the serial interface, and then send out each byte of the open packet one by one. Then in loop, each byte of the LED on/LED off commands is sent with a 100ms delay. LED blinks as expected when powered on, does not blink when reset.

This actually further implies that the issue lies somewhere other than just waiting for the response, because this new code doesn't wait for a response at all. It continuously sends the LED on/off commands but the sensor does not react to them (after the Arduino is reset).

#include "NeoSWSerial.h"

NeoSWSerial _serial(19, 18);

void setup() {
//  Serial.begin(9600);  // Took out the hardware serial just to see if that was the issue
  _serial.begin(9600);

  // Open
  _serial.write((byte)0x55);
  _serial.write((byte)0xAA);
  _serial.write((byte)0x01);
  _serial.write((byte)0x00);
  _serial.write((byte)0x01);
  _serial.write((byte)0x00);
  _serial.write((byte)0x00);
  _serial.write((byte)0x00);
  _serial.write((byte)0x01);
  _serial.write((byte)0x00);
  _serial.write((byte)0x02);    // pre-calculated checksum
  _serial.write((byte)0x01);
}

void loop() {
  // Turn LED on
  _serial.write((byte)0x55);
  _serial.write((byte)0xAA);
  _serial.write((byte)0x01);
  _serial.write((byte)0x00);
  _serial.write((byte)0x01);
  _serial.write((byte)0x00);
  _serial.write((byte)0x00);
  _serial.write((byte)0x00);
  _serial.write((byte)0x12);
  _serial.write((byte)0x00);
  _serial.write((byte)0x13);    // pre-calculated checksum
  _serial.write((byte)0x01);

  delay(100);

  // Turn LED off
  _serial.write((byte)0x55);
  _serial.write((byte)0xAA);
  _serial.write((byte)0x01);
  _serial.write((byte)0x00);
  _serial.write((byte)0x00);
  _serial.write((byte)0x00);
  _serial.write((byte)0x00);
  _serial.write((byte)0x00);
  _serial.write((byte)0x12);
  _serial.write((byte)0x00);
  _serial.write((byte)0x12);    // pre-calculated checksum
  _serial.write((byte)0x01);
   
  delay(100);
}

Software guy says... "It must be the hardware."

Power is always a good thing to check. How are you powering the unit? The Arduino 3.3V pin has a lower current limit than the 5V pins, and it can take up to 6V. I can't see the power requirement for this device, though.

I wonder if you're getting latch up somehow? Maybe you should put resistors on the TX line as well, to pull it up a little for the Arduino.

Cheers,
/dev

The sensor's TX wire was on +5V power and the RX wire on GND, with the actual power and ground wires in two different digital pins.

There is a pretty good chance that the device is at least partially, if not totally fried.

@/dev
Good point, I'm actually powering it entirely off of USB power right now. I don't currently have access to the board's power cord but will tomorrow afternoon, I'll try powering it off that and seeing if it changes anything.

The device's datasheet can be found here. The input is stated to be anything between 3.3V-5V, and I'm powering it off of the Arduino's 5V pin (that pin is actually plugged into a breadboard's power-rail, and is feeding the fingerprint sensor, an Adafruit BLE module, and a standard 16x2 LCD, but I don't think that should have much of an impact).

I was considering that the Arduino may not be registering the state changes sent by the sensor since it's outputting 3.3V on its TX pin and the Arduino digital input is 5V, but from searching around 3.3V should be plenty to register a HIGH on the Arduino's pin (cutoff ~2.5V).

I'll have access to a lab tomorrow and will check the RX/TX lines on an oscilloscope to see if there's any oddness there.

@jremington
Yea, that's what I'm inching closer and closer towards. I'm a couple hours away from just ordering a new module in case it's fried. The only thing that's really kept me from doing it so far is that the thing works perfectly when initially plugged in, so there's still a chance I'm doing something wrong but I've eliminated most everything at this point. The only thing I haven't tried yet is to see if the hardware serial port solves the issue. I think if that doesn't fix it, it's 99% the sensor hardware at fault.

If anybody ends up stumbling onto this topic with a similar issue, I ended up biting the bullet and purchasing a a teensy 3.2 (sorry Arduino :() since it has 3 hardware UARTs on top of the USB serial. The same sensor that was previously not working seems to be working fine now, so I don't think I fried it.

Surprisingly, it seems SoftwareSerial was at fault here, so be wary using it in future projects!

...will check the RX/TX lines on an oscilloscope to see if there's any oddness there.

Did they look ok? I'm a little skeptical that your simplified transmit-only sketch wouldn't work if the hardware was ok.

I wonder if the UNO crystal is marginal, which could lead to an out-of-spec 9600 baud? Or perhaps the sensor's timing is marginal, or was affected? The Teensy probably has slightly different timings and electrical characteristics.

Curiously,
/dev

@splnkr did you try the alternative software serial libraries? I have the same problem at the moment and probably can't move to a teensy since all the other devices on the project are good with the arduino!

do you have any other solutions to make this work on the current set up and library?

-dev:
Wow, that’s the prettiest BAD library I’ve seen. Ever.

  • It uses SoftwareSerial, a real CPU killer
  • It uses heap, a LOT!
  • It blocks on responses
  • It doesn’t do any error checking
  • It doesn’t have a timeout on blocking operations (probably why it hangs)
  • It doesn’t use F macro for string constants

Needless to say, I’m glad to hear you’re going to re-write it. It is begging for a finite-state machine implementation and proper memory usage. Gak.

That said, you could easily replace SoftwareSerial with NeoSWSerial in the H file. If you’d be willing to use pins 8 and 9 instead, you could also use AltSoftSerial (remove the listen calls).

Hey -dev, :slight_smile:
I want to make the library “FPS_GT511C3.h” use NeoSWSerial instead of SoftwareSerial. Do I really just need to replace “#include <SoftwareSerial.h>” with “#include <NeoSWSerial.h>” in the header file? And what about the “.cpp” file which is also part of the FPS library. Any changes to be made there?