peter 发表于 2014-11-13 16:17:06

PN532 spi通信

SPI communication details
      The 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]
查看完整版本: PN532 spi通信