Parallax RFID Read/Write Module 28440

Looking through the forums here and on parallax it looks like several people have had trouble getting the Parallax RFID Read/Write Module 28440 to correctly interface with the Arduino. The read/write module is a vast improvement over the old, read only module. The old module has numerous examples of how to code it for an Arduino. The new module is 4 times as fast, backwards compatible with with old reader tags and also supports write functionality.

I finally got it working so I thought I'd share my code. Note that this is a very rough and ugly code, but it works. I will be refining it over the next few days, but figured I'd post it as soon as I got it working to relieve frustration and also let others play with the code.

Here is the code for reading new style (EM4x50) tags.

//Interface Arduino USB with Parallax 28440 125 Khz UART RFID Reader/Writer
//Program reads a EM4x50 tag and reports the ID on the serial monitor.
//Coded by Uberdude

#include "NewSoftSerial.h"
#define txPin 6
#define rxPin 8

//Reader/Writer Commands
#define RFID_READ 0x01
//#define RFID_WRITE 0x02
//#define RFID_LEGACY 0x0F

NewSoftSerial mySerial(rxPin, txPin);
int val = 0;
//char code[6]; //Note this is 11 for the extra null char?
//int bytesread = 0;
//int flag = 0;

//Tags
//char TAG1[11] = "0800E28C60";
//char TAG2[11] = "0800D9E43E";

void setup()
{
Serial.begin(9600);
mySerial.begin(9600);

// pinMode(2, OUTPUT);
// pinMode(4, OUTPUT);
pinMode(txPin, OUTPUT); //pin 6
pinMode(rxPin, INPUT); //pin 8

Serial.println("RFID Read/Write Test");
}

void loop()
{
mySerial.print("!RW");
mySerial.print(RFID_READ, BYTE);
mySerial.print(3, BYTE);

//0th read
if(mySerial.available() > 0) { // if data available from reader
val = mySerial.read();
if(val != 255){
Serial.print("Error Code:");
Serial.println(val, HEX);
}
}

//1st byte
if(mySerial.available() > 0) { // if data available from reader
val = mySerial.read();
if(val != 255){
Serial.print("1st:");
Serial.println(val, HEX);
}
}

//2nd byte
if(mySerial.available() > 0) { // if data available from reader
val = mySerial.read();
if(val != 255){
Serial.print("2nd:");
Serial.println(val, HEX);
}
}

//3rd byte
if(mySerial.available() > 0) { // if data available from reader
val = mySerial.read();
if(val != 255){
Serial.print("3rd:");
Serial.println(val, HEX);
}
}

//4th byte
if(mySerial.available() > 0) { // if data available from reader
val = mySerial.read();
if(val != 255){
Serial.print("4th:");
Serial.println(val, HEX);
}
}

delay(500); // wait for a 1/2 second
}

Note that if you have a rectangular read/write tag from parallax like I have, they come pre loaded with 0xFEEDBEEF in the first data address. If you didn't get your tags from there, or have a round tag, it should show up as 4 zeros. Alternately just change the the mySerial.print(3, BYTE); to mySerial.print(33, BYTE); which will read the unique serial ID. One thing that screwed me up for a long time is that the first byte of data in the ID could be a 1 which I was thinking was the error code. Hence why I went to this ugly code explicitly stating what the bytes I was getting.

Enjoy

Here is code to read the old (EM4100) tags

//Interface Arduino USB with Parallax 28440 125 Khz UART RFID Reader/Writer
//Current program reads a legacy tag and lights an LED based on which tag it is.
//Coded by Uberdude

#include "NewSoftSerial.h"
#define txPin 6
#define rxPin 8

//Reader/Writer Commands
//#define RFID_READ 0x01
//#define RFID_WRITE 0x02
#define RFID_LEGACY 0x0F

//Error Codes
//#define ERR_OK 0x01

NewSoftSerial mySerial(rxPin, txPin);
char statusCode;
int val = 0;
char code[11]; //Note this is 11 for the extra null char?
int bytesread = 0;

//Tags
char TAG1[11] = "0800E28C60";
char TAG2[11] = "0800D9E43E";

void setup()
{
Serial.begin(9600);
mySerial.begin(9600);

pinMode(2, OUTPUT);
pinMode(4, OUTPUT);
pinMode(txPin, OUTPUT); //pin 6
pinMode(rxPin, INPUT); //pin 8

Serial.println("RFID Read/Write Test");
}

void loop()
{
mySerial.print("!RW");
mySerial.print(RFID_LEGACY, BYTE);
//mySerial.print(32, BYTE);

if(mySerial.available() > 0) { // if data available from reader

if((val = mySerial.read()) == 10) { // check for header
bytesread = 0;
while(bytesread<10) { // read 10 digit code
if( mySerial.available() > 0) {
val = mySerial.read();
if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
break; // stop reading
}
code[bytesread] = val; // add the digit
bytesread++; // ready to read next digit
}
}

if(bytesread == 10) { // if 10 digit read is complete
Serial.print("TAG code is: "); // possibly a good TAG
Serial.println(code); // print the TAG code
}
bytesread = 0;

if (memcmp(code, TAG1, 10) == 0){
digitalWrite(2, HIGH); //light the Green LED
}

if (memcmp(code, TAG2, 10) == 0){
digitalWrite(4, HIGH); //light the Red LED
}
delay(500); // wait for a 1/2 second
digitalWrite(2, LOW);
digitalWrite(4, LOW); //reset LEDs to off
}
}
}

about the write part?
I'm designing a patch in max/msp to encode bytes on rfid tags.

do you have an example of code to write on rfid tags from arduino?

I haven't gotten around to sketching any code to write to RFID tags, but from the documentation provided for the 28440, it should be fairly easy. Just have to watch that the data you're writing is in byte.

I tried your code exactly and I can't get anything to happen, well the led on the rfid flashes from red to green(or yellow) when a tag gets close but it doesn't print out... a little help please. Maybe I connected it wrong

Arduino D8 = RFID VCC
Arduino D6 = RFID SN
Arduino 5v = RFID SOUT
Arduino GND = RFID GND

Arduino 5v = RFID VCC (Vcc means positive voltage)
Arduino D6 = RFID SIN (Serial In)
Arduino D8 = RFID SOUT (Serial Out)
Arduino GND = RFID GND (Ground)

Also, Here is the link to the tag writing code, I haven't reposted it cause I'm lazy.

http://forums.parallax.com/showthread.php?129430-Interface-Arduino-to-RFID-Read-Write

May I ask a stupid question?

In UberDude's code above (1st post), he shows the serial number of 2 of the tags he was using (they're commented out) 0800E28C60 and 0800D9E43E. Both of these serial numbers have 10 digits (5 Bytes) but he is only reading 4 bytes with the code, and the .PDF on the tag states that the tag's serial number is 32 bit (4 bytes). I'm lost...

In UberDude's code above (1st post), he shows the serial number of 2 of the tags he was using (they're commented out) 0800E28C60 and 0800D9E43E. Both of these serial numbers have 10 digits (5 Bytes) but he is only reading 4 bytes with the code, and the .PDF on the tag states that the tag's serial number is 32 bit (4 bytes).

Fair enough to say, a legacy read gets you the serial number of a legacy tag
header+10 bytes(40 bits)+footer

So if you were using legacy tags, you would need to code for it.

A read of a read/write tag gets you a the data from the specified address (1-33)
status + 4 bytes(32 bits)

Each of the 33 data locations has 4 bytes!
Of these locations, 3-31 are writable!

So you need to write to a tag, before you will see anything meaningful

the status codes all not explicitly mentioned anywhere in the datasheet, are in the stamp example code.
http://www.parallax.com/Portals/0/Downloads/docs/prod/rf/28440-RFIDReadWrite-v1.0.pdf
Page 10 at the top

ERR_OK 0x01 ' No errors
ERR_LIW 0x02 ' Did not find a listen window
ERR_NAK 0x03 ' Received a NAK, could be invalid command
ERR_NAK_OLDPW 0x04 ' Received a NAK sending old password (RFID_SetPass), could be incorrect password
ERR_NAK_NEWPW 0x05 ' Received a NAK sending new password (RFID_SetPass)
ERR_LIW_NEWPW 0x06 ' Did not find a listen window after sending old password (RFID_SetPass)
ERR_PARITY 0x07 ' Parity error when reading data

The two tags that are commented out are from an earlier program which reads the legacy tags. You can also see the hex code for reading a legacy code (0x0F) also commented out. You can pretty much just use the code from the old read only module:

http://www.arduino.cc/playground/Learning/PRFID

To get a read on a legacy tag, hence I didn't bother posting that since its pretty much a solved problem. But as far as I could tell, no one had written any code for the read/write module. Good luck

here is my slightly modified & (in my opinion) more elegant-looking version of uberdude's "read" code for the new (black) parallax RFID readers. I modified his code to suppress the "null reads" which occur when no card is present and quickly take up the whole monitor. I also suppressed the error codes, as I saw no real need for them.

#include <NewSoftSerial.h>
#define RFID_READ 0x01
#define txPin 6
#define rxPin 8

NewSoftSerial mySerial(rxPin, txPin);
int val;
int runs = 0;

void setup()
{
Serial.begin(9600);
Serial.println("RFID Read/Write Test");
mySerial.begin(9600);
pinMode(txPin, OUTPUT);
pinMode(rxPin, INPUT);
}

void suppressAll() //suppresses the "null result" from being printed if no RFID tag is present
{
if(mySerial.available() > 0)
{ mySerial.read();
suppressAll();
}
}

void loop()
{
int val;
mySerial.print("!RW");
mySerial.print(RFID_READ, BYTE);
mySerial.print(32, BYTE);

if(mySerial.available() > 0)
{
val = mySerial.read(); //The mySerial.read() procedure is called, but the result is not printed because I don't want the "error message: 1" cluttering up the serial monitor
if (val != 1) //If the error code is anything other than 1, then the RFID tag was not read correctly and any data collected is meaningless. In this case since we don't care about the resultant values they can be suppressed
{suppressAll();}
}

if(mySerial.available() > 0) {
val = mySerial.read();
Serial.print("1st:");
Serial.println(val, HEX);
}

if(mySerial.available() > 0) {
val = mySerial.read();
Serial.print("2nd:");
Serial.println(val, HEX);
}

if(mySerial.available() > 0) {
val = mySerial.read();
Serial.print("3rd:");
Serial.println(val, HEX);
}

if(mySerial.available() > 0) {
val = mySerial.read();
Serial.print("4th:");
Serial.println(val, HEX);
Serial.println("-----------------");
}

delay(750);
}

also, a huge thanks to uberdude for your original code. I am fairly new to programming and it would have taken me ages to figure out the basic functionality on my own...thanks!

after some more work, i was able to get the write operation working. Here is the code i used:

//Code to write data to Parallax RFID reader/writer 28440 from Arduino
//Program writes to one of the 29 user-defined addresses (3-31) as define by whichSpace
//The four bytes to be written are defined by first, second, third, and fourth
//Coded by vgrhcp

#include <NewSoftSerial.h>
#define RFID_WRITE 0x02
#define txPin 6
#define rxPin 8

#define whichSpace 4

#define first 1
#define second 26
#define third 3
#define fourth 27

NewSoftSerial mySerial(rxPin, txPin);

void setup()
{
Serial.begin(9600);
Serial.println("RFID Write Test");
mySerial.begin(9600);
pinMode(txPin, OUTPUT);
pinMode(rxPin, INPUT);
}

void suppressAll() //Keeps error code & the "write confirmation" codes from being printed in the serial monitor
{
if(mySerial.available() > 0)
{ mySerial.read();
suppressAll();
}
}

void loop()
{
int val;

mySerial.print("!RW");
mySerial.print(RFID_WRITE, BYTE);
mySerial.print(whichSpace, BYTE);
mySerial.print(first, BYTE);
mySerial.print(second, BYTE);
mySerial.print(third, BYTE);
mySerial.print(fourth, BYTE);

if(mySerial.available() > 0) {
val = mySerial.read();
if (val == 1) //If data was written successfully
{ Serial.println("Data written succesfully!");
suppressAll();
}
else suppressAll(); //If an error occured during writing, discard all data recieved from the RFID writer
}
delay(250);
}

I just have one problem now...my code writes data as bytes, as it must for the RFID writer to understand it (i tried writing as DEC and HEX, but it did not work). However, the read code that uberdude wrote and i modified prints the values it reads as HEX. So the issue is that if you write, say, 26 as one of the bytes onto a card and then read it, it will come up as 1A, which is the HEX value that corresponds to 26. To solve this, you must change the read procedure form printing HEX to DEC like so:

//Code to read data from Parallax RFID reader/writer 28440 via Arduino
//Program reads data from one of the 29 user-defined addresses (3-31) as define by whichSpace
//Writen by vgrhcp based on code by uberdude

#include <NewSoftSerial.h>
#define RFID_READ 0x01
#define txPin 6
#define rxPin 8

#define whichSpace 4

NewSoftSerial mySerial(rxPin, txPin);
int val;
int runs = 0;

void setup()
{
Serial.begin(9600);
Serial.println("RFID Read Test");
mySerial.begin(9600);
pinMode(txPin, OUTPUT);
pinMode(rxPin, INPUT);
}

void suppressAll() //suppresses the "null result" from being printed if no RFID tag is present
{
if(mySerial.available() > 0)
{ mySerial.read();
suppressAll();
}
}

void loop()
{
int val;
mySerial.print("!RW");
mySerial.print(RFID_READ, BYTE);
mySerial.print(whichSpace, BYTE);

if(mySerial.available() > 0)
{
val = mySerial.read(); //The mySerial.read() procedure is called, but the result is not printed because I don't want the "error message: 1" cluttering up the serial monitor
if (val != 1) //If the error code is not 1, then there has been an error and the RFID tag was not read correctly.In this case we don't really care about the resultant values, so they can be suppressed
{suppressAll();}
}

if(mySerial.available() > 0) {
val = mySerial.read();
Serial.print("1st:");
Serial.println(val, DEC);
}

if(mySerial.available() > 0) {
val = mySerial.read();
Serial.print("2nd:");
Serial.println(val, DEC);
}

if(mySerial.available() > 0) {
val = mySerial.read();
Serial.print("3rd:");
Serial.println(val, DEC);
}

if(mySerial.available() > 0) {
val = mySerial.read();
Serial.print("4th:");
Serial.println(val, DEC);
Serial.println("-----------------");
}

delay(750);
}

these two codes are now fully compatible with each other; so long as the whichSpace is set to the same value (3-31) in each program, the reader will read whatever was written by the writer. Enjoy!

Now all you have to learn is to use the # icon when posting code not the quote icon.

what do you mean?

When posting code, select the code and hit the # icon not the quote icon next to it. Then you get a nice scrolling box and the software doesn't mess up square brackets and interpreted them as formatting.

yes, but then it strips out the colors. I think that they are more beneficial than the scrolling box....

But your code is mangled, and the post is a pain to scroll through and the colours are not too important once you know how to program and we are doing the answering anyway

Thank you all for doing all of this work. I'm working on a Mega 2560 and cannot get this to work at all. I tried many examples, including the ones on this page. If it makes any difference, I'm using the "Blue Eye Key Fob Tag" from Parallax that uses the EM-4100 tech.

According to Arduino's SofwareSerial example, (http://arduino.cc/en/Tutorial/SoftwareSerialExample) "Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69"

So I naturally just changed the RX pin to any one of the above. I only want to read tags, not write them, so I suppose TX doesn't really matter, but I hook it up anyway. Still nothing.

Can anyone give me any pointers for a Mega 2560?

I'm trying to get this to work with an Arduino Mega 2560. I'm also working with the Blue Fob tags sold by Parallax (https://www.parallax.com/StoreSearchResults/tabid/768/List/0/SortField/4/ProductID/503/Default.aspx?txtSearch=blue+fob) which work on the EM-4100 tech, which I suppose we are referring to as 'legacy'.

I cannot for the life of me get a read. In addition, the LED on the RFID reader is always GREEN, not red as I believe it should be, correct? According to Arduino's SoftwareSerial example, though: "Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69" (http://arduino.cc/en/Tutorial/SoftwareSerialExample so I use 10 typically for RX and anything else for TX, but that really shouldn't matter since I only want to read.

Can anyone give me any pointers?

The blue tags you are using are the 'legacy' tags so you need to use the RFID_ReadLegacy command (0x0F) in order to get a valid read.

Per the datasheet, "A visual indication of the RFID Read/Write Module’s state is given with the on-board LED (Light Emitting Diode). When the module is successfully powered-up and is in an idle state, the LED will be GREEN; when the module is in an active state (for example, searching for a valid tag or performing an operation on the tag), the LED will be RED."

So the fact that it stays green is no surprise, it means that at least the module is powered up. Try sending a command and seeing if it flashes red, if so, then you know the Arduino and the tag are communicating. If not, check your comm set up, are Tx and Rx reversed? are you using softwareserial or the older NewSoftwareSerial (yes it is confusing). Try it out on another serial device or on an Uno which this was coded for.

Good Luck