Why does this code compile properly, but make my Core flash red?

This code, direct from the RFID_UART library, causes my Spark Core to flash red. I can put it back with a full reset, but I can’t figure out why code that compiles would break my Core.

// RFID_UART.ino

#if defined (SPARK)
#include "SeeedRFID/SeeedRFID.h"
#else
#include <SoftwareSerial.h>
#include <SeeedRFID.h>
#endif

#define RFID_RX_PIN 10
#define RFID_TX_PIN 11

// #define DEBUG
#define TEST

SeeedRFID RFID(RFID_RX_PIN, RFID_TX_PIN);
RFIDdata tag;

void setup() {
	Serial.begin(57600);
	Serial.println("Hello, double bk!");
}

void loop() { 
	if(RFID.isAvailable()){
		tag = RFID.data();
		Serial.print("RFID card number: ");
		Serial.println(RFID.cardNumber());
#ifdef TEST
	Serial.print("RFID raw data: ");
	for(int i=0; i<tag.dataLen; i++){
	    Serial.print(tag.raw[i], HEX);
	    Serial.print('\t');
		}
#endif

If the data length is not correct, this code has the potential to walk off the end of memory and cause a hard fault.

How many red flashes are you getting–there is a code SOS followed by a number of flashes and then it repeats?

1 Like

I am getting an SOS code, followed by a single red flash. I found a reference saying that’s a hard fault?

I’ve tried setting “tag.dataLen” to 24 and re-flashing, but that didn’t make a difference.

Hi @raiderj

I was just reading the library code and it is written in a slightly funny way. I think you should test the return values in the tag for rational values, like is the dataLen == 0 or is tag.raw == NULL.

Does it print the card number but not the raw hex values?

Or does it print nothing before failing?

It fails right after flashing, and right now I don’t even have a reader connected. Is it possible for the .h or .cpp file themselves to cause the crash?

The example code assumes you have a reader connected. When you don’t have one connected, I am not sure what it does.

Can you change the code to test tag.dataLen for zero? I think you will find that it is zero. You should not look at tag.raw when the length is zero.

If I comment out all the lines of code and add them back in one at a time, this is the line that causes the hard fault:

SeeedRFID RFID(RFID_RX_PIN, RFID_TX_PIN);

So, it’s something in the library’s constructor that causes it to fail. Any ideas what that might be? It looks like others have used this library, but even so, maybe there’s a bug in the code for it?

And just to be certain, I’ve changed the RX & TX PIN to those on the Spark - 6 & 7

Please see the earlier posting

As per this post, Serial1.begin() before calling setup() caused issues… Please see the specific link:

If you move the initialization that happens in the constructor

SeeedRFID RFID(RFID_RX_PIN, RFID_TX_PIN);

to the setup(), this may work.The constructor function may need to be duplicated as an init() method and called in setup()

2 Likes

That was it! I don’t have anything actually connected yet… need to work out connecting 12V logic to the Core (thinking a voltage divider to start).

I’ll dig into those links - thank you very much for your help!

EDIT: In case anyone else needs this library, I’ve put in a modification request.

I wasn’t able to get the code to compile with the constuctor in setup(), but it does compile and flash without error if I move it to loop().

Can you go into a bit more detail about the init() function? How does that differ from setup()?

@raiderji

I examined the seeedrfid library. It needs the following to address problem faced above

  1. Empty constructor
    SeeedRFID::SeeedRFID()
    {
    }

  2. init function. Does what the constructor SeeedRFID::SeeedRFID(int rxPin, int txPin) does

These should be added to SeeedRFID.cpp

  1. Add declarations in the SeeedRFID.h class for the empty constructor and the init function

  2. use empty constructor for the RFID variable

  3. use the init function inside set up for RFID.

I have added these as examples which you may consider using. Hopeg this helps. I haven’t tested it on my system, so I cannot guarantee it works!

SeeedRFID.h

class SeeedRFID
{
private:
 #if (PLATFORM_ID == 0) || (PLATFORM_ID == 6)	//Core or Photon
	USARTSerial * _rfidIO; // software serial
 #else
	SoftwareSerial * _rfidIO; // software serial
 #endif
	RFIDdata _data;
	boolean _isAvailable;
	RFIDType _type;
	boolean checkBitValidationUART();
	boolean read();
public:
	SeeedRFID(int rxPin, int txPin);
	SeeedRFID();   // Empty constructor
	~SeeedRFID();
        init(int rxPin, int txPin);

	boolean isAvailable();
	RFIDdata data();
	unsigned long cardNumber();
};

SeeedRFID.c

SeeedRFID::init(int rxPin, int txPin)
{
 #if (PLATFORM_ID == 0) || (PLATFORM_ID == 6)	//Core or Photon
    _rfidIO = &Serial1;		// Select Serial1 or Serial2
 #else
    _rfidIO = new SoftwareSerial(rxPin, txPin);
    _rfidIO->begin(9600);
 #endif
	// init RFID data
	_data.dataLen = 0;
	_data.chk = 0;
	_data.valid = false;

	_isAvailable = false;
	_type = RFID_UART;
}

SeeedRFID::SeeedRFID()
{
}

RFID_UART.ino

SeeedRFID RFID;
RFIDdata tag;

void setup() {
        RFID.init(RFID_RX_PIN, RFID_TX_PIN);
	Serial1.begin(9600);	//Done here to prevent SeeedRFID constructor system crash
	
	Serial.begin(57600);
	Serial.println("Hello, double bk!");
}
1 Like

@raiderj and @TheVelozGroup, moving the Serial1.begin() to setup() was done to prevent the constructor from crashing the firmware. You still need the constructor as before (outside setup) as in the example that comes with the library. @TheVelozGroup’s suggestions are good but not necessary. :grinning: