nxp pn532 NFC SPI initiator code, with all functions minimized and made as fast as possible (code for target is also there, you just need to change the functions in the main). Code advises are welcome, i am an electronist not a programmer
Revision 0:f07ca719c12e, committed 2013-11-15
- Comitter:
- marius90
- Date:
- Fri Nov 15 12:58:57 2013 +0000
- Commit message:
- working;
Changed in this revision
diff -r 000000000000 -r f07ca719c12e lib/PN532.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/PN532.cpp Fri Nov 15 12:58:57 2013 +0000 @@ -0,0 +1,279 @@ +#include "mbed.h" +#include "PN532.h" +#include "string.h" + +#define PN532_PACK_BUFF_SIZE 64 +uint8_t pn532_packetbuffer[PN532_PACK_BUFF_SIZE]; + +uint8_t pn532ack[] = { + 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00 +}; +uint8_t pn532response_firmwarevers[] = { + 0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03 +}; + +PN532::PN532(PinName mosi, PinName miso, PinName sclk, PinName ss) +{ + _spi = new SPI(mosi, miso, sclk); + _spi->frequency(5000000); + _spi->format(8, 0); + _ss = new DigitalOut(ss); + *_ss = 1; +} + +void PN532::begin(void) +{ + _spi->frequency(5000000); + _spi->format(8, 0); + pn532_packetbuffer[0] = PN532_FIRMWAREVERSION; + printf("begin"); + /*Ignore response!*/ + sendCommandCheckAck(pn532_packetbuffer, 1); +} + +uint32_t PN532::getFirmwareVersion(void) +{ + uint32_t response; + + pn532_packetbuffer[0] = PN532_FIRMWAREVERSION; + + if (!sendCommandCheckAck(pn532_packetbuffer, 1)) + return 0; + + //Read data packet + read(pn532_packetbuffer, 12); + //Check some basic stuff + if (0 != strncmp((char *)pn532_packetbuffer, (char *)pn532response_firmwarevers, 6)) { + return 0; + } + response = pn532_packetbuffer[6]; + response <<= 8; + response |= pn532_packetbuffer[7]; + response <<= 8; + response |= pn532_packetbuffer[8]; + response <<= 8; + response |= pn532_packetbuffer[9]; + return response; +} + +bool PN532::SAMConfig(void) +{ + pn532_packetbuffer[0] = PN532_SAMCONFIGURATION; + pn532_packetbuffer[1] = 0x01; // normal mode; + pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second + pn532_packetbuffer[3] = 0x01; // use IRQ pin! + + if (! sendCommandCheckAck(pn532_packetbuffer, 4)) + return false; + + // read data packet + read(pn532_packetbuffer, 8); + + return (pn532_packetbuffer[5] == 0x15); +} + + +uint32_t PN532::configurePeerAsInitiator(void) +{ + pn532_packetbuffer[0] = PN532_INJUMPFORDEP; + pn532_packetbuffer[1] = 0x01; //Active Mode + pn532_packetbuffer[2] = 2;// Use 1 or 2 424 kb/s. + pn532_packetbuffer[3] = 0x01; //Indicates Optional Payload is present + + //Polling request payload + pn532_packetbuffer[4] = 0x00; + pn532_packetbuffer[5] = 0xFF; + pn532_packetbuffer[6] = 0xFF; + pn532_packetbuffer[7] = 0x00; + pn532_packetbuffer[8] = 0x00; + + if (!sendCommandCheckAck(pn532_packetbuffer, 9)) { + return false; + } + // read data packet + read(pn532_packetbuffer, 19+6); + + // check the response + + return (pn532_packetbuffer[7] == 0x00); //No error + +} + +uint32_t PN532::configurePeerAsTarget() +{ + uint8_t pbuffer[38] = { + PN532_TGINITASTARGET, + 0x00, + 0x08, 0x00, //SENS_RES + 0x12, 0x34, 0x56, //NFCID1 + 0x40, //SEL_RES + 0x01, 0xFE, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, // POL_RES + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xFF, 0xFF, + 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, //NFCID3t: Change this to desired value + 0x00, 0x00 //Length of general and historical bytes + }; + for(uint8_t i = 0; i < 38; i ++) { + pn532_packetbuffer[i] = pbuffer[i]; + } + + if (! sendCommandCheckAck(pn532_packetbuffer, 38)) { + return false; + + } + // read data packet + read(pn532_packetbuffer, 18+6); + return (pn532_packetbuffer[23] == 0x00); //No error as it received all response +} + +bool PN532::initiatorTxRx(char* dataOut,char* dataIn) +{ + pn532_packetbuffer[0] = PN532_INDATAEXCHANGE; + pn532_packetbuffer[1] = 0x01; //Target 01 + + for(uint8_t iter=(2+0); iter<(2+16); iter++) { + pn532_packetbuffer[iter] = dataOut[iter-2]; //pack the data to send to target + } + + if (! sendCommandCheckAck(pn532_packetbuffer, 18)) + return false; + + // read data packet + read(pn532_packetbuffer, 18+6); + + for(uint8_t iter=8; iter<(8+16); iter++) { + dataIn[iter-8] = pn532_packetbuffer[iter]; //data received from target + } + + return (pn532_packetbuffer[7] == 0x00); //No error +} + +uint32_t PN532::targetTxRx(char* dataOut,char* dataIn) +{ + /* Receiving from Initiator */ + pn532_packetbuffer[0] = PN532_TGGETDATA; + if (! sendCommandCheckAck(pn532_packetbuffer, 1)) + return false; + + // read data packet + read(pn532_packetbuffer, 18+6); + + for(uint8_t iter=8; iter<(8+16); iter++) { + dataIn[iter-8] = pn532_packetbuffer[iter]; //data received from initiator + } + + /* Sending to Initiator */ + if(pn532_packetbuffer[7] == 0x00) { //If no errors in receiving, send data. + pn532_packetbuffer[0] = PN532_TGSETDATA; + for(uint8_t iter=(1+0); iter<(1+16); iter++) { + pn532_packetbuffer[iter] = dataOut[iter-1]; //pack the data to send to target + } + + if (! sendCommandCheckAck(pn532_packetbuffer, 17)) + return false; + + // read data packet + read(pn532_packetbuffer, 2+6); + + return (pn532_packetbuffer[7] == 0x00); //No error + } + return true; +} + +bool PN532::sendCommandCheckAck(uint8_t* cmd, uint8_t cmd_len, uint16_t timeout) +{ + uint16_t timer = 0; + // write the command + writeCommand(cmd, cmd_len); + // Wait for chip to say it's ready! + + + while (readSpiStatus() != PN532_SPI_READY) { + + if (timeout != 0) { + timer+=10; + if (timer > timeout) + return false; + } + wait_ms(10); + } + + + // read acknowledgement + if (!checkSpiAck()) { + return false; + } + + timer = 0; + // Wait for chip to say its ready! + while (readSpiStatus() != PN532_SPI_READY) { + + if (timeout != 0) { + timer+=10; + if (timer > timeout) + return false; + } + wait_ms(10); + } + return true; // ack'd command +} + +void PN532::writeCommand(uint8_t buf[], uint8_t len) +{ + uint8_t checksum; + len++; + checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2; + + *_ss=0; + + write(PN532_SPI_DATAWRITE); + write(PN532_PREAMBLE); + write(PN532_STARTCODE1); + write(PN532_STARTCODE2); + write(len); + uint8_t cmdlen_1=~len + 1; + write(cmdlen_1); + write(PN532_HOSTTOPN532); + checksum += PN532_HOSTTOPN532; + + for (uint8_t i=0; i<len-1; i++) { + write(buf[i]); + checksum += buf[i]; + } + uint8_t checksum_1=~checksum; + write(checksum_1); + write(PN532_POSTAMBLE); + *_ss = 1; +} + +uint8_t PN532::read(uint8_t buff[], uint8_t n) +{ + uint8_t response; + *_ss = 0; + write(PN532_SPI_DATAREAD); + for (uint8_t i=0; i < n; i ++) { + wait_ms(1); + buff[i] = read(); + } + *_ss= 1; + response = read(); + return response; +} + + +bool PN532::checkSpiAck(void) +{ + uint8_t ackbuff[6]; + read(ackbuff, 6); + return (0 == strncmp((char *)ackbuff, (char *)pn532ack, 6)); +} + +uint8_t PN532::readSpiStatus(void) +{ + *_ss = 0; + wait_ms(2); + write(PN532_SPI_STATREAD); + uint8_t status = read(); + *_ss=1; + return status; +}
diff -r 000000000000 -r f07ca719c12e lib/PN532.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/PN532.h Fri Nov 15 12:58:57 2013 +0000 @@ -0,0 +1,79 @@ +#ifndef __PN532_H__ +#define __PN532_H__ + +#define PN532_PREAMBLE 0x00 +#define PN532_STARTCODE1 0x00 +#define PN532_STARTCODE2 0xFF +#define PN532_POSTAMBLE 0x00 + +#define PN532_HOSTTOPN532 0xD4 + +#define PN532_FIRMWAREVERSION 0x02 +#define PN532_GETGENERALSTATUS 0x04 +#define PN532_SAMCONFIGURATION 0x14 +#define PN532_INLISTPASSIVETARGET 0x4A +#define PN532_INDATAEXCHANGE 0x40 +#define PN532_INJUMPFORDEP 0x56 +#define PN532_TGINITASTARGET 0x8C +#define PN532_TGGETDATA 0x86 +#define PN532_TGSETDATA 0x8E + + + +#define PN532_WAKEUP 0x55 +#define PN532_SPI_STATREAD 0x02 +#define PN532_SPI_DATAWRITE 0x01 +#define PN532_SPI_DATAREAD 0x03 +#define PN532_SPI_READY 0x01 + +#define PN532_MIFARE_ISO14443A 0x0 + +#define KEY_A 1 +#define KEY_B 2 + +#define mosi1 p5 +#define miso1 p6 +#define sclk1 p7 +#define ss1 p8 + +#define REVERSE_BITS_ORDER(b) b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; \ + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; \ + b = (b & 0xAA) >> 1 | (b & 0x55) << 1 + +class PN532 +{ +public: + + PN532(PinName mosi, PinName miso, PinName sclk, PinName ss); + void begin(void); + bool SAMConfig(void); + uint32_t getFirmwareVersion(void); + uint32_t configurePeerAsInitiator(void); + uint32_t configurePeerAsTarget(void); + bool initiatorTxRx(char* dataOut, char* dataIn); + uint32_t targetTxRx(char* dataOut, char* dataIn); + bool sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout = 1000); + +private: + DigitalOut *_ss; + SPI *_spi; + + uint8_t read(uint8_t buff[], uint8_t n); + uint8_t readSpiStatus(void); + bool checkSpiAck(void); + void writeCommand(uint8_t buf[], uint8_t len); + void wakeup (void); + inline void write(uint8_t data) { + REVERSE_BITS_ORDER(data); + _spi->write(data); + } + inline uint8_t read() { + uint8_t data = _spi->write(0); + REVERSE_BITS_ORDER(data); + return data; + } + + +}; + +#endif \ No newline at end of file
diff -r 000000000000 -r f07ca719c12e main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Nov 15 12:58:57 2013 +0000 @@ -0,0 +1,50 @@ +#include "mbed.h" +#include "PN532.h" +#include <string> + + +DigitalOut led1(LED1); +DigitalOut led2 (LED2); + + +PN532 nfc(mosi1, miso1, sclk1, ss1); + +int main() +{ + printf("\r INITIATOR STARTED\n"); + nfc.begin(); + + + uint32_t versiondata = nfc.getFirmwareVersion(); + if (! versiondata) { + printf("Didn't find PN532\r\n"); + + while (1) { + led1 = !led1; + wait(0.1); + } + } + + printf("Found chip PN5%2X\r\n", versiondata >> 24); + printf("Firmware V%d.%d\r\n", (versiondata >> 16) & 0xFF, (versiondata >> 8) & 0xFF); + + + nfc.SAMConfig(); + wait(1); + + char dataOut[] = "hello target"; + char dataIn[16]; + + while (1) { + if(nfc.configurePeerAsInitiator()==1) { + printf("found target"); + nfc.initiatorTxRx(dataOut, dataIn); + printf("\n\r%s", dataIn); + } else { + printf("no target"); + } + led1=!led1; + wait(1); + } +} +
diff -r 000000000000 -r f07ca719c12e mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Nov 15 12:58:57 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f \ No newline at end of file