Module RFID PN532 (I2C)
Schéma d’Ensemble
Documents
Projet Démonstration
Driver RFID PN532
pn532.h
/*
* pn532.h
*
* Created on: Oct 3, 2017
* Author: kerhoas
*/
#ifndef INC_PN532_H_
#define INC_PN532_H_
#include "main.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)
#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)
#define PN532_GPIO_VALIDATIONBIT (0x80)
#define PN532_GPIO_P30 (0)
#define PN532_GPIO_P31 (1)
#define PN532_GPIO_P32 (2)
#define PN532_GPIO_P33 (3)
#define PN532_GPIO_P34 (4)
#define PN532_GPIO_P35 (5)
//======================================================================
void pn532_reset();
uint8_t pn532_SAMConfig(void);
uint32_t pn532_getFirmwareVersion(void);
uint8_t pn532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength, uint16_t timeout);
uint8_t pn532_mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData);
uint8_t pn532_mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data);
uint8_t pn532_mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data);
#endif /* INC_PN532_H_ */
pn532.c
#include "pn532.h"
#define PN532_PACKBUFFSIZ 64
uint8_t pn532_packetbuffer[PN532_PACKBUFFSIZ];
uint8_t pn532ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
uint8_t pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};
uint8_t writeBuffer[60];
uint8_t _uid[7]; // ISO14443A uid
uint8_t _uidLen; // uid len
uint8_t _key[6]; // Mifare Classic key
uint8_t _inListedTag; // Tg number of inlisted tag.
uint8_t pn532_sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout);
uint8_t pn532_readack() ;
uint8_t pn532_waitready(uint16_t timeout) ;
void pn532_readdata(uint8_t* buff, uint8_t n);
void pn532_writecommand(uint8_t* cmd, uint8_t cmdlen);
uint8_t pn532_isready();
//===============================================================================================
void pn532_reset()
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, 0);
HAL_Delay(400);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, 1);
HAL_Delay(10);
}
//===============================================================================================
uint32_t pn532_getFirmwareVersion(void)
{
uint32_t response;
pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
if (pn532_sendCommandCheckAck(pn532_packetbuffer, 1,1000)==0)
{
return 0;
}
// read data packet
pn532_readdata(pn532_packetbuffer, 12);
// check some basic stuff
if (0 != strncmp((char *)pn532_packetbuffer, (char *)pn532response_firmwarevers, 6))
{
return 0;
}
int offset = 7; // Skip a response byte when using I2C to ignore extra data.
response = pn532_packetbuffer[offset++];
response <<= 8;
response |= pn532_packetbuffer[offset++];
response <<= 8;
response |= pn532_packetbuffer[offset++];
response <<= 8;
response |= pn532_packetbuffer[offset++];
return response;
}
//===============================================================================================
uint8_t pn532_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 (pn532_sendCommandCheckAck(pn532_packetbuffer, 4, 1000) == 0)
return 0;
// read data packet
pn532_readdata(pn532_packetbuffer, 8);
int offset = 6;
if (pn532_packetbuffer[offset] == 0x15)
{ return 1; }
else
{return 0;}
}
//===============================================================================================
uint8_t pn532_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 (pn532_sendCommandCheckAck(pn532_packetbuffer, 3, 1000)==0)
{
return 0x0; // no cards read
}
// wait for a card to enter the field (only possible with I2C)
if (!pn532_waitready(timeout)) {
return 0x0;
}
pn532_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;
}
/**************************************************************************/
/*!
Tries to authenticate a block of memory on a MIFARE card using the
INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
for more information on sending MIFARE and other commands.
@param uid Pointer to a byte array containing the card UID
@param uidLen The length (in bytes) of the card's UID (Should
be 4 for MIFARE Classic)
@param blockNumber The block number to authenticate. (0..63 for
1KB cards, and 0..255 for 4KB cards).
@param keyNumber Which key type to use during authentication
(0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
@param keyData Pointer to a byte array containing the 6 bytes
key value
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t pn532_mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData)
{
uint8_t len;
uint8_t i;
// Hang on to the key and uid data
memcpy (_key, keyData, 6);
memcpy (_uid, uid, uidLen);
_uidLen = uidLen;
// Prepare the authentication command //
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
pn532_packetbuffer[1] = 1; /* Max card numbers */
pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
memcpy (pn532_packetbuffer+4, _key, 6);
for (i = 0; i < _uidLen; i++)
{
pn532_packetbuffer[10+i] = _uid[i]; /* 4 byte card ID */
}
if (pn532_sendCommandCheckAck(pn532_packetbuffer, 10+_uidLen,1000)==0)
return 0;
// Read the response packet
pn532_readdata(pn532_packetbuffer, 12);
// check if the response is valid and we are authenticated???
// for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
// Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good
if (pn532_packetbuffer[7] != 0x00)
{
return 0;
}
return 1;
}
/**************************************************************************/
/*!
Tries to read an entire 16-byte data block at the specified block
address.
@param blockNumber The block number to authenticate. (0..63 for
1KB cards, and 0..255 for 4KB cards).
@param data Pointer to the byte array that will hold the
retrieved data (if any)
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t pn532_mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data)
{
/* 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] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
/* Send the command */
if (pn532_sendCommandCheckAck(pn532_packetbuffer, 4,1000)==0)
{
return 0;
}
/* Read the response packet */
pn532_readdata(pn532_packetbuffer, 26);
/* If byte 8 isn't 0x00 we probably have an error */
if (pn532_packetbuffer[7] != 0x00)
{
return 0;
}
/* Copy the 16 data bytes to the output buffer */
/* Block content starts at byte 9 of a valid response */
memcpy (data, pn532_packetbuffer+8, 16);
return 1;
}
/**************************************************************************/
/*!
Tries to write an entire 16-byte data block at the specified block
address.
@param blockNumber The block number to authenticate. (0..63 for
1KB cards, and 0..255 for 4KB cards).
@param data The byte array that contains the data to write.
@returns 1 if everything executed properly, 0 for an error
*/
/**************************************************************************/
uint8_t pn532_mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
{
/* Prepare the first command */
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
pn532_packetbuffer[1] = 1; /* Card number */
pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
memcpy (pn532_packetbuffer+4, data, 16); /* Data Payload */
/* Send the command */
if ( pn532_sendCommandCheckAck(pn532_packetbuffer, 20,10000)==0)
{
return 0;
}
HAL_Delay(50);
/* Read the response packet */
pn532_readdata(pn532_packetbuffer, 26);
return 1;
}
//===============================================================================================
uint8_t pn532_sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout) {
// write the command
pn532_writecommand(cmd, cmdlen);
// Wait for chip to say its ready!
if (!pn532_waitready(timeout)) {
return 0;
}
// read acknowledgement
if (!pn532_readack()) {
return 0;
}
return 1; // ack'd command
}
//===============================================================================================
uint8_t pn532_readack() {
uint8_t ackbuff[6];
pn532_readdata(ackbuff, 6);
return (0 == strncmp((char *)ackbuff, (char *)pn532ack, 6));
}
//===============================================================================================
uint8_t pn532_waitready(uint16_t timeout) {
uint16_t timer = 0;
while(pn532_isready()==0) {
if (timeout != 0) {
timer += 10;
if (timer > timeout) {
//term_printf("TIME OUT \n\r");
return 0;
}
}
HAL_Delay(10);
}
return 1;
}
//===============================================================================================
uint8_t pn532_isready()
{
uint8_t x;
x = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_10);
if (x==0) {return 1;} else {return 0;}
}
//===============================================================================================
void pn532_readdata(uint8_t* buff, uint8_t n) {
// I2C write.
uint8_t i;
HAL_Delay(50);
i2c1_ReadBuffer(PN532_I2C_ADDRESS, buff, n+2);
// discard first byte
for (i=0; i<n-1; i++)
{
buff[i] = buff[i+1];
}
}
//===============================================================================================
void pn532_writecommand(uint8_t* cmd, uint8_t cmdlen) {
// I2C command write.
uint8_t checksum;
//uint8_t writeBuffer[60];
uint8_t i;
cmdlen++;
HAL_Delay(2); // or whatever the delay is for waking up the board
checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2;
writeBuffer[0]= PN532_PREAMBLE; // 0x00
writeBuffer[1]= PN532_PREAMBLE; // 0x00
writeBuffer[2]= PN532_STARTCODE2; // 0xFF
writeBuffer[3]= cmdlen;
writeBuffer[4]= ~cmdlen + 1;
writeBuffer[5]= PN532_HOSTTOPN532; // 0xD4
checksum += PN532_HOSTTOPN532;
i=0;
while(i<cmdlen-1)
{
writeBuffer[6+i]=cmd[i];
checksum += cmd[i];
i++;
}
i=i+6;
writeBuffer[i]=~checksum;
i=i+1;
writeBuffer[i]=PN532_POSTAMBLE;
i2c1_WriteBuffer(PN532_I2C_ADDRESS, writeBuffer, i+1);
}
//===============================================================================================
main.c
#include "main.h"
#include "pn532.h"
int writeToken=0;
char string_to_write[20];
int stringLength = 0;
//=========================================================
// >>>>>>>>>>>> MAIN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//=========================================================
int main(void)
{
uint32_t versiondata;
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[16];
int i;
HAL_Init();
SystemClock_Config();
uart2_Init();
i2c1_Init();
HAL_Delay(1000);
pn532_reset();
HAL_Delay(100);
versiondata = pn532_getFirmwareVersion();
HAL_Delay(200);
if (! versiondata)
{
term_printf("Didn't find PN53x board\n\r");
while (1); // halt
}
term_printf("Found chip PN5%x\n\r",(versiondata>>24) & 0xFF);
term_printf("Firmware version %d.%d\n\r",(versiondata>>16) & 0xFF, (versiondata>>8) & 0xFF);
pn532_SAMConfig(); // configure board to read RFID tags
HAL_Delay(200);
term_printf("Write ? (esc for no ) \n\r");
// wait for string
writeToken = term_scanf(string_to_write, &stringLength);
term_printf("Waiting for an ISO14443A Card ...");
while(1)
{
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
// 'uid' will be populated with the UID, and uidLength will indicate
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
success = pn532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000);
if (success)
{
term_printf("Found an ISO14443A card \n\r");
term_printf("UID Length: %d bytes \n\r", uidLength);
if (uidLength == 4)
{
// We probably have a Mifare Classic card ...
term_printf("Seems to be a Mifare Classic card (4 byte UID) \n\r");
term_printf("UID Value: 0x%x 0x%x 0x%x 0x%x\n\r", uid[0],uid[1],uid[2],uid[3] );
// Now we need to try to authenticate it for read/write access
// Try with the factory default KeyA: 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
term_printf("Trying to authenticate block 4 with default KEYA value \n\r");
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
// Start with block 4 (the first block of sector 1) since sector 0
// contains the manufacturer data and it's probably better just
// to leave it alone unless you know what you're doing
success = pn532_mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);
HAL_Delay(200);
if (success)
{
term_printf("Sector 1 (Blocks 4..7) has been authenticated \n\r");
// If you want to write something to block 4 to test with, uncomment
// the following line and this text should be read back in a minute
if(writeToken == 1)
{
term_printf("string to write : %s \n\r", string_to_write);
//memcpy(data, (const uint8_t[]){ 'K', 'E', 'R', 'H', 'O', 'A', 'S', ' ', 'V','i','n','c','e','n','t',0}, sizeof data);
memcpy(data, string_to_write, stringLength);
success = pn532_mifareclassic_WriteDataBlock (4, data);
if(success)
{
term_printf("Writing Block Finished");
writeToken = 0;
}
}
// Try to read the contents of block 4
success = pn532_mifareclassic_ReadDataBlock(4, data);
if (success)
{
// Data seems to have been read ... spit it out
term_printf("Reading Block 4 (HEX): \n\r");
for(i=0 ; i<16 ; i++)
{
term_printf("%x ",data[i]);
}
term_printf("| %s",data);
term_printf("\n\r");
// Wait a bit before reading the card again
HAL_Delay(1000);
}
else
{
term_printf("Ooops ... unable to read the requested block. Try another key? \n\r");
}
}
else
{
term_printf("Ooops ... authentication failed: Try another key? \n\r");
}
}
}
HAL_Delay(500);
} // END WHILE
return 0;
}