1 /**************************************************************************/
5 /**************************************************************************/
6 #include "pn532_drvr.h"
11 #include "core/systick/systick.h"
12 #include "core/gpio/gpio.h"
13 #include "core/ssp/ssp.h"
15 #define PN532_SELECT gpioSetValue(PN532_SPI_CSPORT, PN532_SPI_CSPIN, 0);
16 #define PN532_DESELECT gpioSetValue(PN532_SPI_CSPORT, PN532_SPI_CSPIN, 1);
18 #define PN532_SPI_STATREAD 0x02
19 #define PN532_SPI_DATAWRITE 0x01
20 #define PN532_SPI_DATAREAD 0x03
21 #define PN532_SPI_READY 0x01
23 // The number of attempts to make while waiting for the status ready bit
24 // Each attempt is 1ms
25 #define PN532_SPI_TIMEOUT 100
27 /**************************************************************************/
29 @brief Writes a single byte via SPI
31 /**************************************************************************/
32 uint8_t pn532SPIWrite(unsigned char data
)
34 // Note: bits have to be reversed since SPI is LSB on the PN532
35 // Thankfully the M3 has a quick HW reverse command (RBIT)
36 while ((SSP_SSP0SR
& SSP_SSP0SR_TNF_NOTFULL
) == 0);
37 SSP_SSP0DR
= ((unsigned char)(RBIT(data
)>>24)); // Write
38 while ((SSP_SSP0SR
& SSP_SSP0SR_RNE_NOTEMPTY
) == 0);
39 data
= ((unsigned char)(RBIT(SSP_SSP0DR
)>>24)); // Read
43 /**************************************************************************/
45 @brief Writes a byte array via SPI
47 /**************************************************************************/
48 void pn532SPIWriteArray(byte_t
* pbtData
, size_t len
)
52 pn532SPIWrite(*pbtData
);
58 /**************************************************************************/
60 @brief Reads a single byte via SPI
62 /**************************************************************************/
63 uint8_t pn532SPIRead(void)
65 return pn532SPIWrite(0x00);
68 /**************************************************************************/
70 @brief Reads a byte array via SPI
72 /**************************************************************************/
73 void pn532SPIReadArray(uint8_t* buff
, size_t len
)
78 buff
[i
] = pn532SPIRead();
83 /**************************************************************************/
85 @brief Sends a status request (SPI only)
87 /**************************************************************************/
88 uint8_t pn532GetStatus()
92 // Send SPI status request
94 pn532SPIWrite(PN532_SPI_STATREAD
);
101 /**************************************************************************/
103 @brief Initialises SPI and configures the PN532
105 /**************************************************************************/
106 void pn532HWInit(void)
108 PN532_DEBUG("Initialising SPI %s", CFG_PRINTF_NEWLINE
);
109 sspInit(0, sspClockPolarity_Low
, sspClockPhase_RisingEdge
);
112 gpioSetDir(PN532_SPI_CSPORT
, PN532_SPI_CSPIN
, gpioDirection_Output
);
115 // Reset PN532 and wait for it to finish booting
116 gpioSetDir(PN532_RSTPD_PORT
, PN532_RSTPD_PIN
, gpioDirection_Output
);
117 PN532_DEBUG("Resetting the PN532...\r\n");
118 gpioSetValue(PN532_RSTPD_PORT
, PN532_RSTPD_PIN
, 0);
120 gpioSetValue(PN532_RSTPD_PORT
, PN532_RSTPD_PIN
, 1);
124 /**************************************************************************/
126 @brief Builds a standard PN532 frame using the supplied data
128 @param pbtFrame Pointer to the field that will hold the frame data
129 @param pszFrame Pointer to the field that will hold the frame length
130 @param pbtData Pointer to the data to insert in a frame
131 @param swData Length of the data to insert in bytes
133 @note Possible error messages are:
135 - PN532_ERROR_EXTENDEDFRAME
137 /**************************************************************************/
138 pn532_error_t
pn532BuildFrame(byte_t
* pbtFrame
, size_t * pszFrame
, const byte_t
* pbtData
, const size_t szData
)
140 if (szData
> PN532_NORMAL_FRAME__DATA_MAX_LEN
)
142 // Extended frames currently unsupported
143 return PN532_ERROR_EXTENDEDFRAME
;
146 // LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
147 pbtFrame
[3] = szData
+ 1;
148 // LCS - Packet length checksum
149 pbtFrame
[4] = 256 - (szData
+ 1);
152 // DATA - Copy the PN53X command into the packet buffer
153 memcpy (pbtFrame
+ 6, pbtData
, szData
);
155 // DCS - Calculate data payload checksum
156 byte_t btDCS
= (256 - 0xD4);
158 for (szPos
= 0; szPos
< szData
; szPos
++)
160 btDCS
-= pbtData
[szPos
];
162 pbtFrame
[6 + szData
] = btDCS
;
164 // 0x00 - End of stream marker
165 pbtFrame
[szData
+ 7] = 0x00;
167 (*pszFrame
) = szData
+ PN532_NORMAL_FRAME__OVERHEAD
;
169 return PN532_ERROR_NONE
;
172 /**************************************************************************/
174 @brief Sends the specified command to the PN532, automatically
175 creating an appropriate frame for it
177 @param pdbData Pointer to the byte data to send
178 @param szData Length in bytes of the data to send
180 @note Possible error messages are:
184 - PN532_ERROR_INVALIDACK
185 - PN532_ERROR_SPIREADYSTATUSTIMEOUT
187 /**************************************************************************/
188 pn532_error_t
pn532SendCommand(const byte_t
* pbtData
, const size_t szData
)
190 pn532_pcb_t
*pn532
= pn532GetPCB();
193 if (pn532
->state
== PN532_STATE_BUSY
)
195 return PN532_ERROR_BUSY
;
197 pn532
->state
= PN532_STATE_BUSY
;
199 // Every packet must start with "00 00 ff"
200 byte_t abtFrame
[PN532_BUFFER_LEN
] = { 0x00, 0x00, 0xff };
204 pn532BuildFrame (abtFrame
, &szFrame
, pbtData
, szData
);
206 // Register the last command that was sent
207 pn532
->lastCommand
= pbtData
[0];
209 // Output the frame data for debugging if requested
210 PN532_DEBUG("Sending (%02d): ", szFrame
);
211 pn532PrintHex(abtFrame
, szFrame
);
216 // Send data to the PN532
217 pn532SPIWrite(PN532_SPI_DATAWRITE
);
218 pn532SPIWriteArray(abtFrame
, szFrame
);
220 // Wait for READY status
222 while (pn532GetStatus() != PN532_SPI_READY
)
224 if(t
++>PN532_SPI_TIMEOUT
)
226 PN532_DEBUG("Timeout waiting for READY status%s", CFG_PRINTF_NEWLINE
);
227 pn532
->state
= PN532_STATE_READY
;
228 return PN532_ERROR_SPIREADYSTATUSTIMEOUT
;
235 pn532SPIWrite(PN532_SPI_DATAREAD
);
236 const byte_t abtAck
[6] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
238 pn532SPIReadArray(abtRxBuf
, 6);
241 // Make sure the received ACK matches the prototype
242 if (0 != (memcmp (abtRxBuf
, abtAck
, 6)))
244 PN532_DEBUG ("Invalid ACK: ");
245 pn532PrintHex(abtRxBuf
, 6);
246 PN532_DEBUG("%s", CFG_PRINTF_NEWLINE
);
247 pn532
->state
= PN532_STATE_READY
;
248 return PN532_ERROR_INVALIDACK
;
251 pn532
->state
= PN532_STATE_READY
;
252 return PN532_ERROR_NONE
;
255 /**************************************************************************/
257 @brief Reads a response from the PN532
259 @note Possible error message are:
262 - PN532_ERROR_RESPONSEBUFFEREMPTY
263 - PN532_ERROR_PREAMBLEMISMATCH
264 - PN532_ERROR_APPLEVELERROR
265 - PN532_ERROR_EXTENDEDFRAME
266 - PN532_ERROR_LENCHECKSUMMISMATCH
267 - PN532_ERROR_SPIREADYSTATUSTIMEOUT
269 /**************************************************************************/
270 pn532_error_t
pn532ReadResponse(byte_t
* pbtResponse
, size_t * pszRxLen
)
273 pn532_pcb_t
*pn532
= pn532GetPCB();
275 // Check if we're busy
276 if (pn532
->state
== PN532_STATE_BUSY
)
278 return PN532_ERROR_BUSY
;
280 pn532
->state
= PN532_STATE_BUSY
;
281 pn532
->appError
= PN532_APPERROR_NONE
;
283 // Wait for the response ready signal
285 while (pn532GetStatus() != PN532_SPI_READY
)
287 if(t
++>PN532_SPI_TIMEOUT
)
289 PN532_DEBUG("Timeout waiting for READY status%s", CFG_PRINTF_NEWLINE
);
290 pn532
->state
= PN532_STATE_READY
;
291 return PN532_ERROR_SPIREADYSTATUSTIMEOUT
;
299 pn532SPIWrite(PN532_SPI_DATAREAD
);
302 pbtResponse
[0] = pn532SPIRead();
303 pbtResponse
[1] = pn532SPIRead();
304 pbtResponse
[2] = pn532SPIRead();
305 const byte_t pn53x_preamble
[3] = { 0x00, 0x00, 0xff };
306 if (0 != (memcmp (pbtResponse
, pn53x_preamble
, 3)))
308 PN532_DEBUG("Frame preamble + start code mismatch%s", CFG_PRINTF_NEWLINE
);
309 pn532
->state
= PN532_STATE_READY
;
310 return PN532_ERROR_PREAMBLEMISMATCH
;
313 // Check the frame type
314 pbtResponse
[3] = pn532SPIRead();
315 pbtResponse
[4] = pn532SPIRead();
316 pbtResponse
[5] = pn532SPIRead();
317 if ((0x01 == pbtResponse
[3]) && (0xff == pbtResponse
[4]))
320 PN532_DEBUG("Application level error (%02d)%s", pbtResponse
[5], CFG_PRINTF_NEWLINE
);
321 // Set application error message ID
322 pn532
->appError
= pbtResponse
[5];
323 pn532
->state
= PN532_STATE_READY
;
324 return PN532_ERROR_APPLEVELERROR
;
326 else if ((0xff == pbtResponse
[3]) && (0xff == pbtResponse
[4]))
329 PN532_DEBUG("Extended frames currently unsupported%s", CFG_PRINTF_NEWLINE
);
330 pn532
->state
= PN532_STATE_READY
;
331 return PN532_ERROR_EXTENDEDFRAME
;
335 // Check checksum, unless this is a response to the wakeup command
336 if (pn532
->lastCommand
= PN532_COMMAND_SAMCONFIGURATION
)
343 if (256 != (pbtResponse
[3] + pbtResponse
[4]))
346 PN532_DEBUG("Length checksum mismatch%s", CFG_PRINTF_NEWLINE
);
347 pn532PrintHex(pbtResponse
, 6);
348 pn532
->state
= PN532_STATE_READY
;
349 return PN532_ERROR_LENCHECKSUMMISMATCH
;
352 size_t szPayloadLen
= pbtResponse
[3] - 2;
353 for (i
=0; i
<szPayloadLen
; i
++)
355 pbtResponse
[i
+6] = pn532SPIRead();
357 // Get checksum and postamble
358 pbtResponse
[i
+7] = pn532SPIRead();
359 pbtResponse
[i
+8] = pn532SPIRead();
360 pbtResponse
[i
+9] = pn532SPIRead();
366 // Display the raw response data for debugging if requested
367 PN532_DEBUG("Received (%02d): ", *pszRxLen
);
368 pn532PrintHex(pbtResponse
, *pszRxLen
);
370 pn532
->state
= PN532_STATE_READY
;
371 return PN532_ERROR_NONE
;
374 /**************************************************************************/
376 @brief Sends the wakeup sequence to the PN532.
378 /**************************************************************************/
379 pn532_error_t
pn532Wakeup(void)
382 byte_t abtWakeUp
[] = { 0x01,0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00,0x00,0xff,0x03,0xfd,0xd4,0x14,0x01,0x17,0x00 };
383 // byte_t abtWakeUp[] = { 0x01,0x00,0x00,0xff,0x03,0xfd,0xd4,PN532_COMMAND_SAMCONFIGURATION,0x01,0x17,0x00 };
385 pn532_pcb_t
*pn532
= pn532GetPCB();
387 PN532_DEBUG("Sending Wakeup Sequence%s", CFG_PRINTF_NEWLINE
);
392 // Transmit wakeup sequence
393 pn532SPIWriteArray(abtWakeUp
, sizeof(abtWakeUp
));
396 // Register the last command that was sent
397 pn532
->lastCommand
= PN532_COMMAND_SAMCONFIGURATION
;
400 pn532ReadResponse(response
, &szLen
);
403 // Todo: Check for error ... currently throws a checksum error
404 // that isn't really an error
406 pn532
->state
= PN532_STATE_READY
;
407 return PN532_ERROR_NONE
;
410 #endif // #ifdef PN532_SPI