mohammad3d
Joined: 28 Mar 2009 Posts: 17
|
PN532 RFID / NFC tag reader driver |
Posted: Wed Oct 17, 2018 1:56 am |
|
|
Hi every one,
I try to convert ARDUNIO PN532 ntag2xx reader example and library to
CCS C version on PIC16f877 device.
You can find original source code by "Adafruit Industries" in following address:
https://github.com/adafruit/Adafruit-PN532
The following is my code and it work like ardunio version on my PIC device.
The program send all data and messages on serial port.
you can monitor program output with a serial monitor software.
This program tested and fully worked...
main.c (main program file):
Code: |
//main.c File
#include <16F887.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage programing, B3(PIC16) or B5(PIC18) used for I/O
#FUSES HS
#use delay(crystal=4000000)//Set frequency at 4Mhz
#use rs232( baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, ERRORS)
//Note:Connect PN532 module to 5v PIC without any Level converter .It'll work fine.
//Note:PN532 work in SPI slave mode(PIC is MASTER)
//PN532 connection PIN
#define _SS PIN_C2//PN532 chip select pin(SS) to PIC pin17
#define _clk PIN_C3//PIC pin17
#define _mosi PIN_C5//PIC pin24
#define _miso PIN_C4//PIC pin23
//PN532 module MOSI pin to PIC16f877 pin 24(RC5/SDO)
//PN532 module MISO pin to PIC16f877 pin 23(RC4/SDI)
//PN532 module SCK pin to PIC16f877 pin 18(RC3/SCK)
//pre define for compiler compatibility
#define bool int1
#define uint8_t unsigned int8
#define uint16_t unsigned int16
#define uint32_t unsigned int32
#define LOW 0
#define HIGH 1
#define digitalWrite output_bit
#define digitalRead input
#define _BV(bit) (1<<(bit))
#define delay delay_us
#define PN532_PACKBUFFSIZ 64
byte pn532ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
byte pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};
byte pn532_packetbuffer[PN532_PACKBUFFSIZ];
//#define PN532DEBUG //uncomment to see debug messages
#include <string.h>
#include <PN532.h>
#include <PN532.c>
void main(void) {
uint8_t success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
uint8_t data[32];
uint32_t versiondata;
printf("\n\r Hello\n\r");
begin();
versiondata = getFirmwareVersion();
if (! versiondata) {
printf("\n\rDidn't find PN53x board\n\r");
while (true); // halt
}
// Got ok data, print it out!
printf("\n\rFound chip PN5%x\n\r",((versiondata>>24) & 0xFF));
printf("Firmware ver. %lu.%lu\n\r",((versiondata>>16) & 0xFF),((versiondata>>8) & 0xFF));
// configure board to read RFID tags
SAMConfig();
while(true)
{
printf("Waiting for an ISO14443A Card ...\n\r");
// Wait for an NTAG203 card. When one is found 'uid' will be populated with
// the UID, and uidLength will indicate the size of the UUID (normally 7)
success = readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength,0);
if (success) {
// Display some basic information about the card
printf("Found an ISO14443A card\n\r");
printf(" UID Length:%u bytes\n\r",uidLength);
printf(" UID Value: ");
PrintHex(uid, uidLength);
printf("\n\r");
if (uidLength == 7)
{
// We probably have an NTAG2xx card (though it could be Ultralight as well)
printf("Seems to be an NTAG2xx tag (7 byte UID)\n\r");
printf("\n\r");
// NTAG2x3 cards have 39*4 bytes of user pages (156 user bytes),
// starting at page 4 ... larger cards just add pages to the end of
// this range:
// See: http://www.nxp.com/documents/short_data_sheet/NTAG203_SDS.pdf
// TAG Type PAGES USER START USER STOP
// -------- ----- ---------- ---------
// NTAG 203 42 4 39
// NTAG 213 45 4 39
// NTAG 215 135 4 129
// NTAG 216 231 4 225
for (uint8_t i = 0; i < 42; i++)
{
success = ntag2xx_ReadPage(i, data);
// Display the current page number
printf("PAGE ");
if (i < 10) printf("0%u",i);
else printf("%u",i);
printf(": ");
// Display the results, depending on 'success'
// Dump the page data
if (success) PrintHexChar(data, 4);
else printf("Unable to read the requested page!\n\r");
}
}
else printf("This doesn't seem to be an NTAG203 tag (UUID length != 7 bytes)!\n\r");
// Wait a bit before trying again
printf("\n\n\rSend a character to scan another tag!\n\r");
while(!kbhit());
getch();
}
}
}
|
PN532.H (PN532 commands file)
Code: |
//PN532.h
#define PN532_PREAMBLE 0x00
#define PN532_STARTCODE1 0x00
#define PN532_STARTCODE2 0xFF
#define PN532_POSTAMBLE 0x00
#define PN532_HOSTTOPN532 0xD4
#define PN532_PN532TOHOST 0xD5
// PN532 Commands
#define PN532_COMMAND_DIAGNOSE 0x00
#define PN532_COMMAND_GETFIRMWAREVERSION 0x02
#define PN532_COMMAND_GETGENERALSTATUS 0x04
#define PN532_COMMAND_READREGISTER 0x06
#define PN532_COMMAND_WRITEREGISTER 0x08
#define PN532_COMMAND_READGPIO 0x0C
#define PN532_COMMAND_WRITEGPIO 0x0E
#define PN532_COMMAND_SETSERIALBAUDRATE 0x10
#define PN532_COMMAND_SETPARAMETERS 0x12
#define PN532_COMMAND_SAMCONFIGURATION 0x14
#define PN532_COMMAND_POWERDOWN 0x16
#define PN532_COMMAND_RFCONFIGURATION 0x32
#define PN532_COMMAND_RFREGULATIONTEST 0x58
#define PN532_COMMAND_INJUMPFORDEP 0x56
#define PN532_COMMAND_INJUMPFORPSL 0x46
#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A
#define PN532_COMMAND_INATR 0x50
#define PN532_COMMAND_INPSL 0x4E
#define PN532_COMMAND_INDATAEXCHANGE 0x40
#define PN532_COMMAND_INCOMMUNICATETHRU 0x42
#define PN532_COMMAND_INDESELECT 0x44
#define PN532_COMMAND_INRELEASE 0x52
#define PN532_COMMAND_INSELECT 0x54
#define PN532_COMMAND_INAUTOPOLL 0x60
#define PN532_COMMAND_TGINITASTARGET 0x8C
#define PN532_COMMAND_TGSETGENERALBYTES 0x92
#define PN532_COMMAND_TGGETDATA 0x86
#define PN532_COMMAND_TGSETDATA 0x8E
#define PN532_COMMAND_TGSETMETADATA 0x94
#define PN532_COMMAND_TGGETINITIATORCOMMAND 0x88
#define PN532_COMMAND_TGRESPONSETOINITIATOR 0x90
#define PN532_COMMAND_TGGETTARGETSTATUS 0x8A
#define PN532_RESPONSE_INDATAEXCHANGE 0x41
#define PN532_RESPONSE_INLISTPASSIVETARGET 0x4B
#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_I2C_ADDRESS 0x48 >> 1
#define PN532_I2C_READBIT 0x01
#define PN532_I2C_BUSY 0x00
#define PN532_I2C_READY 0x01
#define PN532_I2C_READYTIMEOUT 20
#define PN532_MIFARE_ISO14443A 0x00
// Mifare Commands
#define MIFARE_CMD_AUTH_A 0x60
#define MIFARE_CMD_AUTH_B 0x61
#define MIFARE_CMD_READ 0x30
#define MIFARE_CMD_WRITE 0xA0
#define MIFARE_CMD_TRANSFER 0xB0
#define MIFARE_CMD_DECREMENT 0xC0
#define MIFARE_CMD_INCREMENT 0xC1
#define MIFARE_CMD_STORE 0xC2
#define MIFARE_ULTRALIGHT_CMD_WRITE 0xA2
// Prefixes for NDEF Records (to identify record type)
#define NDEF_URIPREFIX_NONE 0x00
#define NDEF_URIPREFIX_HTTP_WWWDOT 0x01
#define NDEF_URIPREFIX_HTTPS_WWWDOT 0x02
#define NDEF_URIPREFIX_HTTP 0x03
#define NDEF_URIPREFIX_HTTPS 0x04
#define NDEF_URIPREFIX_TEL 0x05
#define NDEF_URIPREFIX_MAILTO 0x06
#define NDEF_URIPREFIX_FTP_ANONAT 0x07
#define NDEF_URIPREFIX_FTP_FTPDOT 0x08
#define NDEF_URIPREFIX_FTPS 0x09
#define NDEF_URIPREFIX_SFTP 0x0A
#define NDEF_URIPREFIX_SMB 0x0B
#define NDEF_URIPREFIX_NFS 0x0C
#define NDEF_URIPREFIX_FTP 0x0D
#define NDEF_URIPREFIX_DAV 0x0E
#define NDEF_URIPREFIX_NEWS 0x0F
#define NDEF_URIPREFIX_TELNET 0x10
#define NDEF_URIPREFIX_IMAP 0x11
#define NDEF_URIPREFIX_RTSP 0x12
#define NDEF_URIPREFIX_URN 0x13
#define NDEF_URIPREFIX_POP 0x14
#define NDEF_URIPREFIX_SIP 0x15
#define NDEF_URIPREFIX_SIPS 0x16
#define NDEF_URIPREFIX_TFTP 0x17
#define NDEF_URIPREFIX_BTSPP 0x18
#define NDEF_URIPREFIX_BTL2CAP 0x19
#define NDEF_URIPREFIX_BTGOEP 0x1A
#define NDEF_URIPREFIX_TCPOBEX 0x1B
#define NDEF_URIPREFIX_IRDAOBEX 0x1C
#define NDEF_URIPREFIX_FILE 0x1D
#define NDEF_URIPREFIX_URN_EPC_ID 0x1E
#define NDEF_URIPREFIX_URN_EPC_TAG 0x1F
#define NDEF_URIPREFIX_URN_EPC_PAT 0x20
#define NDEF_URIPREFIX_URN_EPC_RAW 0x21
#define NDEF_URIPREFIX_URN_EPC 0x22
#define NDEF_URIPREFIX_URN_NFC 0x23
|
PN532.C (PN532 driver file)
Code: |
//PN532.c
/**************************************************************************/
void spi_write_s(uint8_t c)
{
uint8_t i;
// Software SPI write.
digitalWrite(_clk, HIGH);
for (i=0; i<8; i++) {
digitalWrite(_clk, LOW);
if (bit_test(c,i)==1)
{
digitalWrite(_mosi, HIGH);
}
else
{
digitalWrite(_mosi, LOW);
}
delay(100);
digitalWrite(_clk, HIGH);
delay(100);
}
}
/**************************************************************************/
uint8_t spi_read_s(void)
{
uint8_t i, x;
x = 0;
// Software SPI read.
digitalWrite(_clk, HIGH);
for (i=0; i<8; i++)
{
digitalWrite(_clk, HIGH);
if (digitalRead(_miso)==1)
{
bit_set(x,i);
}
else
{
bit_clear(x,i);
}
digitalWrite(_clk, LOW);
delay(100);
digitalWrite(_clk, HIGH);
delay(100);
}
// digitalWrite(_clk, LOW);
return x;
}
/**************************************************************************/
void readdata(uint8_t* buff, uint8_t n)
{
digitalWrite(_ss, LOW);
delay(100);
spi_write_s(PN532_SPI_DATAREAD);
#ifdef PN532DEBUG
printf("Reading: ");
#endif
for (uint8_t i=0; i<n; i++) {
delay(20);
buff[i] = spi_read_s();
//buff[i] = spi_xfer(0);
#ifdef PN532DEBUG
printf("0x%x ",buff[i]);
#endif
}
#ifdef PN532DEBUG
printf("\r\n");
#endif
digitalWrite(_ss, HIGH);
delay(100);
}
/**************************************************************************/
void writecommand(uint8_t* cmd, uint8_t cmdlen) {
// SPI command write.
uint8_t checksum;
uint8_t i=0;
cmdlen++;
digitalWrite(_ss, LOW);
delay(100);
checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2;
delay(2000); // or whatever the delay is for waking up the board
spi_write_s(PN532_SPI_DATAWRITE);
spi_write_s(PN532_PREAMBLE);
spi_write_s(PN532_PREAMBLE);
spi_write_s(PN532_STARTCODE2);
spi_write_s(cmdlen);
spi_write_s(((~cmdlen) + 1));
spi_write_s(PN532_HOSTTOPN532);
checksum += PN532_HOSTTOPN532;
#ifdef PN532DEBUG
printf("PN532_SPI_DATAWRITE: 0x%x\n\r",PN532_SPI_DATAWRITE);
printf("PN532_PREAMBLE: 0x%x\n\r",PN532_PREAMBLE);
printf("PN532_PREAMBLE: 0x%x\n\r",PN532_PREAMBLE);
printf("PN532_STARTCODE2: 0x%x\n\r",PN532_STARTCODE2);
printf("cmdlen: 0x%x\n\r",cmdlen);
printf("~cmdlen + 1: 0x%x\n\r",~cmdlen + 1);
printf("PN532_HOSTTOPN532: 0x%x\n\r",PN532_HOSTTOPN532);
printf("checksum += PN532_HOSTTOPN532: 0x%x\n\r", checksum);
#endif
for (i=0; i<cmdlen-1; i++)
{
spi_write_s(cmd[i]);
checksum += cmd[i];
#ifdef PN532DEBUG
printf("cmd[%u]: 0x%x\n\r",i,cmd[i]);
#endif
}
spi_write_s(~checksum);
spi_write_s(PN532_POSTAMBLE);
digitalWrite(_ss, HIGH);
delay(100);
#ifdef PN532DEBUG
printf("~checksum: 0x%x\n\r",~checksum);
printf("PN532_POSTAMBLE 0x%x\n\r",PN532_POSTAMBLE);
printf("\r\n");
#endif
}
/**************************************************************************/
bool isready() {
uint8_t x;
// SPI read status and check if ready.
digitalWrite(_ss, LOW);
delay(100);
spi_write_s(PN532_SPI_STATREAD);
delay(100);
x = spi_read_s();
digitalWrite(_ss, HIGH);
delay(100);
// Check if status is ready.
if(x == PN532_SPI_READY) return 1;
else return 0;
}
/**************************************************************************/
bool waitready(uint16_t timeout) {
uint16_t timer = 0;
while(!isready()) {
if (timeout != 0) {
timer += 10;
if (timer > timeout) {
printf("waitready TIMEOUT!\n\r");
return false;
}
}
delay(100);
}
return true;
}
/**************************************************************************/
bool readack() {
uint8_t ackbuff[6];
readdata(ackbuff, 6);
return (0 == memcmp((char *)ackbuff, (char *)pn532ack, 6));
}
/**************************************************************************/
bool sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout) {
// write the command
writecommand(cmd, cmdlen);
// Wait for chip to say its ready!
if (!waitready(timeout)) {
return false;
}
// read acknowledgement
if (!readack()) {
#ifdef PN532DEBUG
printf("No ACK frame received!\n\r");
#endif
return false;
}
// For SPI only wait for the chip to be ready again.
// This is unnecessary with I2C.
if (!waitready(timeout)) {
return false;
}
return true; // ack'd command
}
/**************************************************************************/
uint32_t getFirmwareVersion(void) {
uint32_t response;
pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
if (! sendCommandCheckAck(pn532_packetbuffer, 1,1000)) {
return 0;
}
// read data packet
readdata(pn532_packetbuffer, 12);
// check some basic stuff
if (0 != memcmp((char *)pn532_packetbuffer, (char *)pn532response_firmwarevers, 6)) {
return 0;
}
int offset = 6 ;
response = pn532_packetbuffer[offset++];
response <<= 8;
response |= pn532_packetbuffer[offset++];
response <<= 8;
response |= pn532_packetbuffer[offset++];
response <<= 8;
response |= pn532_packetbuffer[offset++];
return response;
}
/**************************************************************************/
void PrintHex( byte* data,uint32_t numBytes)
{
uint32_t szPos;
for (szPos=0; szPos < numBytes; szPos++)
{
printf("0x");
printf("%2x",(data[szPos]&0xff));
if ((numBytes > 1) && (szPos != numBytes - 1))
{
printf(" ");
}
}
printf("\r\n");
}
/**************************************************************************/
void PrintHexChar(byte* data,uint32_t numBytes)
{
uint32_t szPos;
for (szPos=0; szPos < numBytes; szPos++)
{
printf("%2x",data[szPos]);
if ((numBytes > 1) && (szPos != numBytes - 1))
{
printf(" ");
}
}
printf(" ");
for (szPos=0; szPos < numBytes; szPos++)
{
if (data[szPos] <= 0x1F)
printf(".");
else
printf("%c",data[szPos]);
}
printf("\r\n");
}
/**************************************************************************/
bool SAMConfig(void) {
pn532_packetbuffer[0] = PN532_COMMAND_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,1000))
return false;
// read data packet
readdata(pn532_packetbuffer, 8);
int offset = 5;
return (pn532_packetbuffer[offset] == 0x15);
}
/**************************************************************************/
void begin() {
// SPI initialization
// setup_spi(SPI_MASTER|SPI_MODE_0|SPI_CLK_DIV_64);
digitalWrite(_ss, LOW);
delay(100);
// not exactly sure why but we have to send a dummy command to get synced up
pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
sendCommandCheckAck(pn532_packetbuffer, 1,1000);
// ignore response!
digitalWrite(_ss, HIGH);
delay(100);
}
/**************************************************************************/
bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength, uint16_t timeout) {
pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
pn532_packetbuffer[2] = cardbaudrate;
if (!sendCommandCheckAck(pn532_packetbuffer, 3, timeout))
{
#ifdef PN532DEBUG
printf("No card(s) read\n\r");
#endif
return 0x0; // no cards read
}
// read data packet
readdata(pn532_packetbuffer, 20);
// check some basic stuff
/* ISO14443A card response should be in the following format:
byte Description
------------- ------------------------------------------
b0..6 Frame header and preamble
b7 Tags Found
b8 Tag Number (only one used in this example)
b9..10 SENS_RES
b11 SEL_RES
b12 NFCID Length
b13..NFCIDLen NFCID */
if (pn532_packetbuffer[7] != 1)
return 0;
uint16_t sens_res = pn532_packetbuffer[9];
sens_res <<= 8;
sens_res |= pn532_packetbuffer[10];
/* Card appears to be Mifare Classic */
*uidLength = pn532_packetbuffer[12];
for (uint8_t i=0; i < pn532_packetbuffer[12]; i++)
{
uid[i] = pn532_packetbuffer[13+i];
}
return 1;
}
/**************************************************************************/
uint8_t ntag2xx_ReadPage (uint8_t page, uint8_t * buffer)
{
// TAG Type PAGES USER START USER STOP
// -------- ----- ---------- ---------
// NTAG 203 42 4 39
// NTAG 213 45 4 39
// NTAG 215 135 4 129
// NTAG 216 231 4 225
if (page >= 231)
{
return 0;
}
/* Prepare the command */
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
pn532_packetbuffer[1] = 1; /* Card number */
pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */
/* Send the command */
if (! sendCommandCheckAck(pn532_packetbuffer, 4,1000))
{
return 0;
}
/* Read the response packet */
readdata(pn532_packetbuffer, 26);
/* If byte 8 isn't 0x00 we probably have an error */
if (pn532_packetbuffer[7] == 0x00)
{
/* Copy the 4 data bytes to the output buffer */
/* Block content starts at byte 9 of a valid response */
/* Note that the command actually reads 16 byte or 4 */
/* pages at a time ... we simply discard the last 12 */
/* bytes */
memcpy (buffer, pn532_packetbuffer+8, 4);
}
else
{
return 0;
}
// Return OK signal
return 1;
}
|
Try and Enjoy... |
|