PN532 spi通信
SPI communication detailsThe PN532 is slave. A Status byte (Bit 0 of Status byte) indicates if the PN532 is ready to give a response
or not. First byte sent on MOSI by the host controller indicates which operation will be performed:
xxxx xx10 : Read (by the host) Status byte
xxxx xx01 : Write data (transmission from the host to the PN532)
xxxx xx11 : Read data (transmission from the PN532 to the host)
After having sent a command, the host controller must wait for bit 0 of Status byte equals 1 before reading
the data from the PN532.
Bytes are transmitted LSB first.
NSS must be toggle as shown in the user manual (reference 1) or in the next figures.
看文档:http://www.adafruit.com/datashee ... ion%20Note_v1.2.pdf
严格按照:2.4.2.4 章来调试
波形如下:
C语言代码参考(记得要行读):
/**
File Name: pn532_spi.c
C Library for the PN532 written for the A Mega644.
Adapted from pn532.cpp written by Adafruit Industries
Author: Renato Amez
*/
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
#include "pn532_spi.h"
char pn532ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
char pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};
#define PN532_PACKBUFFSIZ 64
char pn532_packetbuffer;
// SET THE ACTUAL VALUE OF THE PINS BEFORE USING
#define PN532_CLK PINB7 // SPI clock pin
#define PN532_MISO PINB6 // SPI MISO pin
#define PN532_MOSI PINB5 // SPI MOSI pin
#define PN532_CS PINB4 // SPI chip select pin (CS/SSEL)
// CURRENT SETUP AT PORT A. SUBJECT TO CHANGE AT FINAL IMPLEMENTATION
#define DDRX DDRB
#define PORTX PORTB
#define PINX PINB
void setupPins(void) {
// Change desired port DDRx and set MISO to INPUT, others to OUTPUT
DDRX = (1 << PN532_MOSI) | (1 << PN532_CLK) | (1 << PN532_CS);
SPCR = (1 << MSTR) | (1 << SPR0) | (1 << SPE) | (1 << DORD);
}
void begin(void) {
PORTX &= ~(1 << PN532_CS);
_delay_ms(1000);
// send dummy command to get it synched up
pn532_packetbuffer = PN532_FIRMWAREVERSION;
uint8_t check = sendCommandCheckAck(pn532_packetbuffer, 1, 1000);
}
uint32_t getFirmwareVersion(void) {
uint32_t response;
pn532_packetbuffer = PN532_FIRMWAREVERSION;
if (0 == sendCommandCheckAck(pn532_packetbuffer, 1, 1000)) return 0;
// read data packet
readspidata(pn532_packetbuffer, 12);
// check some basic stuff
if (0 != strncmp((char*)pn532_packetbuffer,
(char*)pn532response_firmwarevers, 6))
return 0;
response = pn532_packetbuffer;
response << 8;
response |= pn532_packetbuffer;
response <<= 8;
response |= pn532_packetbuffer;
response <<= 8;
response |= pn532_packetbuffer;
return response;
}
// default timeout of one second
uint8_t sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout) {
uint16_t timer = 0;
// write the command
spiwritecommand(cmd, cmdlen);
// wait for the chip to say it's ready
while(readspistatus() != PN532_SPI_READY) {
if (timeout != 0) {
timer += 10;
if (timer > timeout) {
return 0;
}
}
_delay_ms(10);
}
// read acknowledgement
if (0 == spi_readack()) {
return 0;
}
timer = 0;
// wait for the chip to say it's ready
while(readspistatus() != PN532_SPI_READY) {
if (timeout != 0) {
timer += 10;
if (timer > timeout) {
return 0;
}
}
_delay_ms(10);
}
return 1;
}
uint8_t SAMConfig(void) {
pn532_packetbuffer = PN532_SAMCONFIGURATION;
pn532_packetbuffer = 0x01; // normal mode
pn532_packetbuffer = 0x14; // timeout 50ms * 20 = 1 second
pn532_packetbuffer = 0x01; // use IRQ pin!
if (0 == sendCommandCheckAck(pn532_packetbuffer, 4, 1000)) return 0;
// read data packet
readspidata(pn532_packetbuffer, 8);
return (pn532_packetbuffer == 0x15 ? 1 : 0);
}
uint8_t authenticateBlock(uint8_t cardnumber, uint32_t cid, uint8_t blockaddress,
uint8_t authtype, uint8_t* keys) {
pn532_packetbuffer = PN532_INDATAEXCHANGE;
pn532_packetbuffer = cardnumber;
if (authtype == KEY_A) {
pn532_packetbuffer = PN532_AUTH_WITH_KEYA;
} else {
pn532_packetbuffer = PN532_AUTH_WITH_KEYB;
}
pn532_packetbuffer = blockaddress; // Address can be 0-63 for MIFARE 1K card
pn532_packetbuffer = keys;
pn532_packetbuffer = keys;
pn532_packetbuffer = keys;
pn532_packetbuffer = keys;
pn532_packetbuffer = keys;
pn532_packetbuffer = keys;
pn532_packetbuffer = ((cid >> 24) & 0xFF);
pn532_packetbuffer = ((cid >> 16) & 0xFF);
pn532_packetbuffer = ((cid >> 8) & 0xFF);
pn532_packetbuffer = ((cid >> 0) & 0xFF);
if (0 == sendCommandCheckAck(pn532_packetbuffer, 14, 1000)) return 0;
// read data packet
readspidata(pn532_packetbuffer, 2+6);
if ((pn532_packetbuffer = 0x41) && (pn532_packetbuffer == 0x00)) {
return 1;
} else {
return 0;
}
}
uint8_t readMemoryBlock(uint8_t cardnumber, uint8_t blockaddress, uint8_t* block) {
pn532_packetbuffer = PN532_INDATAEXCHANGE;
pn532_packetbuffer = cardnumber;
pn532_packetbuffer = PN532_MIFARE_READ;
pn532_packetbuffer = blockaddress;
if (0 == sendCommandCheckAck(pn532_packetbuffer, 4, 1000)) return 0;
// read data packet
readspidata(pn532_packetbuffer, 18+6);
for (uint8_t i = 8; i < 18+6; i++) {
block = pn532_packetbuffer;
}
if ((pn532_packetbuffer == 0x41) && (pn532_packetbuffer == 0x00)) {
return 1; // read successful
} else {
return 0;
}
}
// Do not write to Sector Trailer Block unless you know what you are doing
uint8_t writeMemoryBlock(uint8_t cardnumber, uint8_t blockaddress, uint8_t* block) {
pn532_packetbuffer = PN532_INDATAEXCHANGE;
pn532_packetbuffer = cardnumber;
pn532_packetbuffer = PN532_MIFARE_WRITE;
pn532_packetbuffer = blockaddress;
for (uint8_t byte = 0; byte < 16; byte++) {
pn532_packetbuffer = block;
}
if (0 == sendCommandCheckAck(pn532_packetbuffer, 4+16, 1000)) return 0;
// read data packet
readspidata(pn532_packetbuffer, 2+6);
if ((pn532_packetbuffer == 0x41) && (pn532_packetbuffer == 0x00)) {
return 1; // write successful
} else {
return 0;
}
}
uint32_t readPassiveTargetID(uint8_t cardbaudrate) {
uint32_t cid;
pn532_packetbuffer = PN532_INLISTPASSIVETARGET;
pn532_packetbuffer = 1; // max 1 card at once
pn532_packetbuffer = cardbaudrate;
if (0 == sendCommandCheckAck(pn532_packetbuffer, 3, 1000)) return 0x00; // no cards read
// read data packet
readspidata(pn532_packetbuffer, 20);
if (pn532_packetbuffer != 1) return 0;
uint16_t sens_res = pn532_packetbuffer;
sens_res <<= 8;
sens_res |= pn532_packetbuffer;
cid = 0;
for (uint8_t i = 0; i < pn532_packetbuffer; i++) {
cid <<= 8;
cid |= pn532_packetbuffer;
}
return cid;
}
// high level SPI
uint8_t spi_readack(void) {
uint8_t ackbuff;
readspidata(ackbuff, 6);
return (0 == strncmp((char*) ackbuff, (char*) pn532ack, 6)) ? 1 : 0;
}
// mid level SPI
uint8_t readspistatus(void) {
PORTX &= ~(1 << PN532_CS); // write LOW to CS pin
_delay_us(2000);
spiwrite(PN532_SPI_STATREAD);
// read byte
uint8_t x = spiread();
PORTX |= (1 << PN532_CS); // write HIGH to CS pin
return x;
}
void readspidata(uint8_t* buff, uint8_t n) {
PORTX &= ~(1 << PN532_CS); // write LOW to CS pin
_delay_us(2000);
spiwrite(PN532_SPI_DATAREAD);
for (uint8_t i = 0; i < n; i++) {
_delay_us(1000);
buff = spiread();
}
PORTX |= (1 << PN532_CS); // write HIGH to CS pin
}
void spiwritecommand(uint8_t* cmd, uint8_t cmdlen) {
uint8_t checksum;
cmdlen++;
PORTX &= ~(1 << PN532_CS); // write LOW to CS pin
_delay_us(2000);
spiwrite(PN532_SPI_DATAWRITE);
checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2;
spiwrite(PN532_PREAMBLE);
spiwrite(PN532_PREAMBLE);
spiwrite(PN532_STARTCODE2);
spiwrite(cmdlen);
uint8_t cmdlen_1 = ~cmdlen + 1;
spiwrite(cmdlen_1);
spiwrite(PN532_HOSTTOPN532);
checksum += PN532_HOSTTOPN532;
for (uint8_t i=0; i<cmdlen-1; i++) {
spiwrite(cmd);
checksum += cmd;
}
uint8_t checksum_1 = ~checksum;
spiwrite(checksum_1);
spiwrite(PN532_POSTAMBLE);
PORTX |= (1 << PN532_CS); // write HIGH to CS pin
}
// low level SPI
void spiwrite(uint8_t c) {
SPDR = c;
//wait until SPIF is set (SPI done)
while (!(SPSR & (1<<SPIF))) ;
uint8_t junk = SPDR;
}
uint8_t spiread(void) {
SPDR = 0;
//wait until SPIF is set (SPI done)
while (!(SPSR & (1<<SPIF))) ;
return SPDR;
}记得先 调用getFirmwareVersion
页:
[1]