查看: 20782|回复: 2

PN532 spi通信

[复制链接]

425

主题

251

回帖

2万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
20594
发表于 2014-11-13 16:17:06 | 显示全部楼层 |阅读模式
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语言代码参考(记得要行读):
  1. /**
  2.         File Name: pn532_spi.c

  3.         C Library for the PN532 written for the A Mega644.
  4.         Adapted from pn532.cpp written by Adafruit Industries

  5.         Author: Renato Amez

  6. */

  7. #include <avr/io.h>
  8. #include <avr/pgmspace.h>
  9. #include <stdio.h>
  10. #include <util/delay.h>
  11. #include <string.h>
  12. #include "pn532_spi.h"

  13. char pn532ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
  14. char pn532response_firmwarevers[] = {0x00, 0xFF, 0x06, 0xFA, 0xD5, 0x03};

  15. #define PN532_PACKBUFFSIZ        64
  16. char pn532_packetbuffer[PN532_PACKBUFFSIZ];

  17. // SET THE ACTUAL VALUE OF THE PINS BEFORE USING
  18. #define PN532_CLK                PINB7        // SPI clock pin
  19. #define PN532_MISO                PINB6        // SPI MISO pin
  20. #define PN532_MOSI                PINB5         // SPI MOSI pin
  21. #define PN532_CS                PINB4        // SPI chip select pin (CS/SSEL)

  22. // CURRENT SETUP AT PORT A. SUBJECT TO CHANGE AT FINAL IMPLEMENTATION
  23. #define DDRX                        DDRB
  24. #define PORTX                        PORTB
  25. #define PINX                        PINB

  26. void setupPins(void) {
  27.         // Change desired port DDRx and set MISO to INPUT, others to OUTPUT
  28.         DDRX = (1 << PN532_MOSI) | (1 << PN532_CLK) | (1 << PN532_CS);

  29.         SPCR = (1 << MSTR) | (1 << SPR0) | (1 << SPE) | (1 << DORD);
  30. }

  31. void begin(void) {
  32.         PORTX &= ~(1 << PN532_CS);
  33.         
  34.         _delay_ms(1000);
  35.         
  36.         // send dummy command to get it synched up
  37.         pn532_packetbuffer[0] = PN532_FIRMWAREVERSION;
  38.         uint8_t check = sendCommandCheckAck(pn532_packetbuffer, 1, 1000);
  39. }

  40. uint32_t getFirmwareVersion(void) {
  41.         uint32_t response;

  42.         pn532_packetbuffer[0] = PN532_FIRMWAREVERSION;

  43.         if (0 == sendCommandCheckAck(pn532_packetbuffer, 1, 1000)) return 0;

  44.         // read data packet
  45.         readspidata(pn532_packetbuffer, 12);

  46.         // check some basic stuff
  47.         if (0 != strncmp((char*)pn532_packetbuffer,
  48.                 (char*)pn532response_firmwarevers, 6))
  49.                         return 0;

  50.         response = pn532_packetbuffer[6];
  51.         response << 8;
  52.     response |= pn532_packetbuffer[7];
  53.     response <<= 8;
  54.     response |= pn532_packetbuffer[8];
  55.     response <<= 8;
  56.     response |= pn532_packetbuffer[9];

  57.     return response;

  58. }

  59. // default timeout of one second
  60. uint8_t sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen, uint16_t timeout) {
  61.         uint16_t timer = 0;
  62.         
  63.         // write the command
  64.         spiwritecommand(cmd, cmdlen);

  65.         // wait for the chip to say it's ready
  66.         while(readspistatus() != PN532_SPI_READY) {
  67.                 if (timeout != 0) {
  68.                         timer += 10;
  69.                         if (timer > timeout) {
  70.                                 return 0;
  71.                         }
  72.                 }
  73.                 _delay_ms(10);
  74.         }

  75.         // read acknowledgement
  76.         if (0 == spi_readack()) {
  77.                 return 0;
  78.         }

  79.         timer = 0;
  80.         // wait for the chip to say it's ready
  81.         while(readspistatus() != PN532_SPI_READY) {
  82.                 if (timeout != 0) {
  83.                         timer += 10;
  84.                         if (timer > timeout) {
  85.                                 return 0;
  86.                         }
  87.                 }
  88.                 _delay_ms(10);
  89.         }
  90.         
  91.         return 1;
  92. }

  93. uint8_t SAMConfig(void) {
  94.         pn532_packetbuffer[0] = PN532_SAMCONFIGURATION;
  95.         pn532_packetbuffer[1] = 0x01; // normal mode
  96.         pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
  97.         pn532_packetbuffer[3] = 0x01; // use IRQ pin!

  98.         if (0 == sendCommandCheckAck(pn532_packetbuffer, 4, 1000)) return 0;

  99.         // read data packet
  100.         readspidata(pn532_packetbuffer, 8);

  101.         return (pn532_packetbuffer[5] == 0x15 ? 1 : 0);
  102. }

  103. uint8_t authenticateBlock(uint8_t cardnumber, uint32_t cid, uint8_t blockaddress,
  104.                                         uint8_t authtype, uint8_t* keys) {
  105.         pn532_packetbuffer[0] = PN532_INDATAEXCHANGE;
  106.         pn532_packetbuffer[1] = cardnumber;

  107.         if (authtype == KEY_A) {
  108.                 pn532_packetbuffer[2] = PN532_AUTH_WITH_KEYA;
  109.         } else {
  110.                 pn532_packetbuffer[2] = PN532_AUTH_WITH_KEYB;
  111.         }
  112.         pn532_packetbuffer[3] = blockaddress; // Address can be 0-63 for MIFARE 1K card

  113.         pn532_packetbuffer[4] = keys[0];
  114.         pn532_packetbuffer[5] = keys[1];
  115.         pn532_packetbuffer[6] = keys[2];
  116.     pn532_packetbuffer[7] = keys[3];
  117.     pn532_packetbuffer[8] = keys[4];
  118.     pn532_packetbuffer[9] = keys[5];

  119.         pn532_packetbuffer[10] = ((cid >> 24) & 0xFF);
  120.         pn532_packetbuffer[11] = ((cid >> 16) & 0xFF);
  121.         pn532_packetbuffer[12] = ((cid >> 8) & 0xFF);
  122.         pn532_packetbuffer[13] = ((cid >> 0) & 0xFF);

  123.         if (0 == sendCommandCheckAck(pn532_packetbuffer, 14, 1000)) return 0;
  124.         
  125.         // read data packet
  126.         readspidata(pn532_packetbuffer, 2+6);

  127.         if ((pn532_packetbuffer[6] = 0x41) && (pn532_packetbuffer[7] == 0x00)) {
  128.                 return 1;
  129.         } else {
  130.                 return 0;
  131.         }
  132. }

  133. uint8_t readMemoryBlock(uint8_t cardnumber, uint8_t blockaddress, uint8_t* block) {
  134.         pn532_packetbuffer[0] = PN532_INDATAEXCHANGE;
  135.         pn532_packetbuffer[1] = cardnumber;
  136.         pn532_packetbuffer[2] = PN532_MIFARE_READ;
  137.         pn532_packetbuffer[3] = blockaddress;

  138.         if (0 == sendCommandCheckAck(pn532_packetbuffer, 4, 1000)) return 0;

  139.         // read data packet
  140.         readspidata(pn532_packetbuffer, 18+6);
  141.         for (uint8_t i = 8; i < 18+6; i++) {
  142.                 block[i-8] = pn532_packetbuffer[i];
  143.         }

  144.         if ((pn532_packetbuffer[6] == 0x41) && (pn532_packetbuffer[7] == 0x00)) {
  145.                 return 1; // read successful
  146.         } else {
  147.                 return 0;
  148.         }
  149. }

  150. // Do not write to Sector Trailer Block unless you know what you are doing
  151. uint8_t writeMemoryBlock(uint8_t cardnumber, uint8_t blockaddress, uint8_t* block) {
  152.         pn532_packetbuffer[0] = PN532_INDATAEXCHANGE;
  153.         pn532_packetbuffer[1] = cardnumber;
  154.         pn532_packetbuffer[2] = PN532_MIFARE_WRITE;
  155.         pn532_packetbuffer[3] = blockaddress;

  156.         for (uint8_t byte = 0; byte < 16; byte++) {
  157.                 pn532_packetbuffer[4+byte] = block[byte];
  158.         }

  159.         if (0 == sendCommandCheckAck(pn532_packetbuffer, 4+16, 1000)) return 0;

  160.         // read data packet
  161.         readspidata(pn532_packetbuffer, 2+6);

  162.         if ((pn532_packetbuffer[6] == 0x41) && (pn532_packetbuffer[7] == 0x00)) {
  163.                 return 1; // write successful
  164.         } else {
  165.                 return 0;
  166.         }
  167. }

  168. uint32_t readPassiveTargetID(uint8_t cardbaudrate) {
  169.         uint32_t cid;

  170.         pn532_packetbuffer[0] = PN532_INLISTPASSIVETARGET;
  171.         pn532_packetbuffer[1] = 1; // max 1 card at once
  172.         pn532_packetbuffer[2] = cardbaudrate;

  173.         if (0 == sendCommandCheckAck(pn532_packetbuffer, 3, 1000)) return 0x00; // no cards read

  174.         // read data packet
  175.         readspidata(pn532_packetbuffer, 20);

  176.         if (pn532_packetbuffer[7] != 1) return 0;

  177.         uint16_t sens_res = pn532_packetbuffer[9];
  178.         sens_res <<= 8;
  179.         sens_res |= pn532_packetbuffer[10];

  180.         cid = 0;
  181.          for (uint8_t i = 0; i < pn532_packetbuffer[12]; i++) {
  182.                 cid <<= 8;
  183.                 cid |= pn532_packetbuffer[13+i];
  184.         }

  185.         return cid;
  186. }

  187. // high level SPI
  188. uint8_t spi_readack(void) {
  189.         uint8_t ackbuff[6];
  190.         
  191.         readspidata(ackbuff, 6);

  192.         return (0 == strncmp((char*) ackbuff, (char*) pn532ack, 6)) ? 1 : 0;
  193. }

  194. // mid level SPI
  195. uint8_t readspistatus(void) {
  196.         PORTX &= ~(1 << PN532_CS); // write LOW to CS pin
  197.         _delay_us(2000);

  198.         spiwrite(PN532_SPI_STATREAD);
  199.         // read byte
  200.         uint8_t x = spiread();

  201.         PORTX |= (1 << PN532_CS); // write HIGH to CS pin
  202.         return x;
  203. }

  204. void readspidata(uint8_t* buff, uint8_t n) {
  205.         PORTX &= ~(1 << PN532_CS); // write LOW to CS pin
  206.         _delay_us(2000);
  207.         spiwrite(PN532_SPI_DATAREAD);

  208.         for (uint8_t i = 0; i < n; i++) {
  209.                 _delay_us(1000);
  210.                 buff[i] = spiread();
  211.         }

  212.         PORTX |= (1 << PN532_CS); // write HIGH to CS pin
  213. }

  214. void spiwritecommand(uint8_t* cmd, uint8_t cmdlen) {
  215.         uint8_t checksum;

  216.         cmdlen++;

  217.         PORTX &= ~(1 << PN532_CS); // write LOW to CS pin
  218.         _delay_us(2000);
  219.         spiwrite(PN532_SPI_DATAWRITE);

  220.         checksum = PN532_PREAMBLE + PN532_PREAMBLE + PN532_STARTCODE2;
  221.         spiwrite(PN532_PREAMBLE);
  222.         spiwrite(PN532_PREAMBLE);
  223.         spiwrite(PN532_STARTCODE2);

  224.         spiwrite(cmdlen);
  225.         uint8_t cmdlen_1 = ~cmdlen + 1;
  226.         spiwrite(cmdlen_1);

  227.         spiwrite(PN532_HOSTTOPN532);
  228.         checksum += PN532_HOSTTOPN532;

  229.         for (uint8_t i=0; i<cmdlen-1; i++) {
  230.                 spiwrite(cmd[i]);
  231.                 checksum += cmd[i];
  232.         }

  233.         uint8_t checksum_1 = ~checksum;
  234.         spiwrite(checksum_1);
  235.         spiwrite(PN532_POSTAMBLE);
  236.         PORTX |= (1 << PN532_CS); // write HIGH to CS pin
  237. }

  238. // low level SPI
  239. void spiwrite(uint8_t c) {
  240.         SPDR = c;        
  241.         //wait until SPIF is set (SPI done)
  242.     while (!(SPSR & (1<<SPIF))) ;
  243.         uint8_t junk = SPDR;
  244. }

  245. uint8_t spiread(void) {
  246.         SPDR = 0;        
  247.         //wait until SPIF is set (SPI done)
  248.     while (!(SPSR & (1<<SPIF))) ;

  249.         return SPDR;
  250. }
复制代码
记得先 调用getFirmwareVersion

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|风火轮WIKI|手机版|小黑屋|深圳风火轮团队 ( 粤ICP备17095099号 )

GMT+8, 2024-10-30 11:29 , Processed in 0.064723 second(s), 23 queries .

快速回复 返回顶部 返回列表
 
【客服1】 商务合作 15289193
【客服2】 业务洽谈 13257599
【客服3】 售前咨询 510313198
【邮箱】
smartfire@smartfire.cn