Hi
It's my first experience with nordic. I need to implement nfr 52833 with RFID-RC522 connected by SPI port. Does anyone have an example to start using the SPI port in SDK 2.4.2 ?
On the other hand, I have found in the devZone two libraries mfrc522.c and mfrc522.h used for SDK v17. Can I implement these libraries in the newest SDK 2.4.2 ?
#include "mfrc522.h" #define debug_info(...) NRF_LOG_INFO(__VA_ARGS__) #define SPI_INSTANCE 0 /**< SPI instance index. */ static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */ static volatile bool spi_xfer_done; /**< Flag used to indicate that SPI instance completed the transfer. */ static uint8_t m_tx_buf[2];// = TEST_STRING; /**< TX buffer. */ static uint8_t m_rx_buf[1]; /**< RX buffer. */ static uint8_t m_write_buf[1]; /**< RX buffer. */ static const uint8_t m_length = 1; /**< Transfer length. */ static const uint8_t m_tx_length = 2; /**< Transfer length. */ /** * @brief SPI user event handler. * @param event */ void spi_event_handler(nrf_drv_spi_evt_t const * p_event, void * p_context) { spi_xfer_done = true; // NRF_LOG_INFO("Transfer completed."); // if (m_rx_buf[0] != 0) // { // NRF_LOG_INFO(" Received:"); // NRF_LOG_HEXDUMP_INFO(m_rx_buf,1); // } } void PCD_WriteRegister(PCD_Register reg, byte value){ nrf_gpio_pin_write(SPI_SS_PIN,0); m_tx_buf[0] = reg &0x7E; m_tx_buf[1] = value; memset(m_rx_buf, 0, m_length); spi_xfer_done = false; nrf_drv_spi_transfer(&spi,&m_tx_buf[0], m_length, NULL, 0); while (!spi_xfer_done) { __WFE(); } NRF_LOG_FLUSH(); // m_tx_buf[1] = value; // memset(m_rx_buf, 0, m_length); // spi_xfer_done = false; // // nrf_drv_spi_transfer(&spi, &m_tx_buf[1], m_length, NULL, 0); // // while (!spi_xfer_done) // { // __WFE(); // } // NRF_LOG_FLUSH(); // byte cpm = PCD_ReadRegister(reg); // if(cpm!=value) debug_info("WTF %x: %x - %x",reg>>1,cpm,value); nrf_gpio_pin_write(SPI_SS_PIN,1); } void PCD_WriteRegister_long(PCD_Register reg, byte count, byte *values){ nrf_gpio_pin_write(SPI_SS_PIN,0); m_tx_buf[0] = reg & 0x7E; memset(m_rx_buf, 0, m_length); spi_xfer_done = false; nrf_drv_spi_transfer(&spi,&m_tx_buf[0], m_length, NULL, 0); while (!spi_xfer_done) { __WFE(); } NRF_LOG_FLUSH(); for (byte index = 0; index < count; index++) { memset(m_rx_buf, 0, m_length); spi_xfer_done = false; nrf_drv_spi_transfer(&spi, &values[index], m_length, NULL, 0); while (!spi_xfer_done) { __WFE(); } NRF_LOG_FLUSH(); } nrf_gpio_pin_write(SPI_SS_PIN,1); } byte PCD_ReadRegister(PCD_Register reg){ nrf_gpio_pin_write(SPI_SS_PIN,0); m_tx_buf[0] = (0x80 | (reg & 0x7E)); memset(m_rx_buf, 0, m_length); spi_xfer_done = false; nrf_drv_spi_transfer(&spi,&m_tx_buf[0], m_length, m_rx_buf, m_length); while (!spi_xfer_done) { __WFE(); } memset(m_rx_buf, 0, m_length); spi_xfer_done = false; uint8_t _reg; _reg = 0x00; nrf_drv_spi_transfer(&spi,&_reg, m_length, m_rx_buf, m_length); while (!spi_xfer_done) { __WFE(); } NRF_LOG_FLUSH(); nrf_gpio_pin_write(SPI_SS_PIN,1); return m_rx_buf[0]; } void PCD_ReadRegister_long(PCD_Register reg, byte count, byte *values, byte rxAlign){ nrf_gpio_pin_write(SPI_SS_PIN,0); if (count == 0) { return; } byte address = 0x80 | (reg& 0x7E); // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. byte index = 0; count--; memset(m_rx_buf, 0, m_length); spi_xfer_done = false; nrf_drv_spi_transfer(&spi,&address, m_length, m_rx_buf, m_length); while (!spi_xfer_done) { __WFE(); } NRF_LOG_FLUSH(); if (rxAlign) { // Only update bit positions rxAlign..7 in values[0] // Create bit mask for bit positions rxAlign..7 byte mask = (0xFF << rxAlign) & 0xFF; // Read value and tell that we want to read the same address again. memset(m_rx_buf, 0, m_length); spi_xfer_done = false; nrf_drv_spi_transfer(&spi,&address, m_length, m_rx_buf, m_length); while (!spi_xfer_done) { __WFE(); } byte value = m_rx_buf[0]; // Apply mask to both current value of values[0] and the new data in value. values[0] = (values[0] & ~mask) | (value & mask); index++; } while (index < count) { memset(m_rx_buf, 0, m_length); spi_xfer_done = false; nrf_drv_spi_transfer(&spi,&address, m_length, m_rx_buf, m_length); while (!spi_xfer_done) { __WFE(); } values[index] = m_rx_buf[0]; index++; } memset(m_rx_buf, 0, m_length); spi_xfer_done = false; uint8_t _reg = 0x00; nrf_drv_spi_transfer(&spi,&_reg, m_length, m_rx_buf, m_length); while (!spi_xfer_done) { __WFE(); } values[index] = m_rx_buf[0]; nrf_gpio_pin_write(SPI_SS_PIN,1); } void PCD_ClearRegisterBitMask( PCD_Register reg, ///< The register to update. One of the PCD_Register enums. byte mask ///< The bits to clear. ) { byte tmp; tmp = PCD_ReadRegister(reg); PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask } // End PCD_ClearRegisterBitMask() void PCD_SetRegisterBitMask( PCD_Register reg, ///< The register to update. One of the PCD_Register enums. byte mask ///< The bits to set. ) { byte tmp; tmp = PCD_ReadRegister(reg); PCD_WriteRegister(reg, tmp | mask); // set bit mask } // End PCD_SetRegisterBitMask() StatusCode PCD_CalculateCRC( byte *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. byte length, ///< In: The number of bytes to transfer. byte *result ///< Out: Pointer to result buffer. Result is written to result[0..1], low byte first. ) { PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit PCD_WriteRegister(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization PCD_WriteRegister_long(FIFODataReg, length, data); // Write data to the FIFO PCD_WriteRegister(CommandReg, PCD_CalcCRC); // Start the calculation // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73μs. // TODO check/modify for other architectures than Arduino Uno 16bit // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73us. for (uint16_t i = 5000; i > 0; i--) { // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved byte n = PCD_ReadRegister(DivIrqReg); if (n & 0x04) { // CRCIRq bit set - calculation done PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. // Transfer the result from the registers to the result buffer result[0] = PCD_ReadRegister(CRCResultRegL); result[1] = PCD_ReadRegister(CRCResultRegH); return STATUS_OK; } } // 89ms passed and nothing happend. Communication with the MFRC522 might be down. return STATUS_TIMEOUT; } // End PCD_CalculateCRC() void PCD_AntennaOn() { uint8_t value = PCD_ReadRegister(TxControlReg); if ((value & 0x03) != 0x03) { PCD_WriteRegister(TxControlReg, value | 0x03); value = PCD_ReadRegister(TxControlReg); } } // End PCD_AntennaOn() StatusCode PICC_RequestA(byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. ) { return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize); } // End PICC_RequestA() void printf_value(uint8_t count, uint8_t *values){ for (uint8_t index = 0; index < count; index++) { debug_info("%p - %x\n",&values[index],values[index]); } } StatusCode PCD_CommunicateWithPICC( byte command, ///< The command to execute. One of the PCD_Command enums. byte waitIRq, ///< The bits in the ComIrqReg register that signals successful completion of the command. byte *sendData, ///< Pointer to the data to transfer to the FIFO. byte sendLen, ///< Number of bytes to transfer to the FIFO. byte *backData, ///< nullptr or pointer to buffer if data should be read back after executing the command. byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. ) { // Prepare values for BitFramingReg byte txLastBits = validBits ? *validBits : 0; byte bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. byte mcmd = PCD_ReadRegister(CommandReg); PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits PCD_WriteRegister(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization PCD_WriteRegister_long(FIFODataReg, sendLen, sendData); // Write sendData to the FIFO PCD_WriteRegister(BitFramingReg, bitFraming); // Bit adjustments PCD_WriteRegister(CommandReg, command); // Execute the command if (command == PCD_Transceive) { PCD_SetRegisterBitMask(BitFramingReg, 0x80); // StartSend=1, transmission of data starts } // Wait for the command to complete. // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting. // Each iteration of the do-while-loop takes 17.86μs. // TODO check/modify for other architectures than Arduino Uno 16bit uint16_t i; for (i = 2000; i > 0; i--) { byte n = PCD_ReadRegister(ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq // debug_info("n:%x",n); if (n & waitIRq) { // One of the interrupts that signal success has been set. break; } if (n & 0x01) { // Timer interrupt - nothing received in 25ms return STATUS_TIMEOUT; } } // 35.7ms and nothing happend. Communication with the MFRC522 might be down. if (i == 0) { debug_info("STATUS_TIMEOUT2"); return STATUS_TIMEOUT; } // Stop now if any errors except collisions were detected. byte errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr if (errorRegValue & 0x13) { // BufferOvfl ParityErr ProtocolErr return STATUS_ERROR; } byte _validBits = 0; // If the caller wants data back, get it from the MFRC522. if (backData && backLen) { byte n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO if (n > *backLen) { return STATUS_NO_ROOM; } *backLen = n; // Number of bytes returned PCD_ReadRegister_long(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO _validBits = PCD_ReadRegister(ControlReg) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last received byte. If this value is 000b, the whole byte is valid. if (validBits) { *validBits = _validBits; } } // Tell about collisions if (errorRegValue & 0x08) { // CollErr return STATUS_COLLISION; } // Perform CRC_A validation if requested. if (backData && backLen && checkCRC) { // In this case a MIFARE Classic NAK is not OK. if (*backLen == 1 && _validBits == 4) { return STATUS_MIFARE_NACK; } // We need at least the CRC_A value and all 8 bits of the last byte must be received. if (*backLen < 2 || _validBits != 0) { return STATUS_CRC_WRONG; } // Verify CRC_A - do our own calculation and store the control in controlBuffer. byte controlBuffer[2]; StatusCode status = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]); if (status != STATUS_OK) { return status; } if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1])) { return STATUS_CRC_WRONG; } } return STATUS_OK; } // End PCD_CommunicateWithPICC() StatusCode PCD_TransceiveData( byte *sendData, ///< Pointer to the data to transfer to the FIFO. byte sendLen, ///< Number of bytes to transfer to the FIFO. byte *backData, ///< nullptr or pointer to buffer if data should be read back after executing the command. byte *backLen, ///< In: Max number of bytes to write to *backData. Out: The number of bytes returned. byte *validBits, ///< In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. Default nullptr. byte rxAlign, ///< In: Defines the bit position in backData[0] for the first bit received. Default 0. bool checkCRC ///< In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. ) { byte waitIRq = 0x30; // RxIRq and IdleIRq return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC); } // End PCD_TransceiveData() StatusCode PICC_REQA_or_WUPA( byte command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. ) { byte validBits; StatusCode status; if (bufferATQA == NULL || *bufferSize < 2) { // The ATQA response is 2 bytes long. return STATUS_NO_ROOM; } PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. validBits = 7; // For REQA and WUPA we need the short frame format - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0] status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits,0,false); if (status != STATUS_OK) { return status; } if (*bufferSize != 2 || validBits != 0) { // ATQA must be exactly 16 bits. return STATUS_ERROR; } return STATUS_OK; } // End PICC_REQA_or_WUPA() bool PICC_IsNewCardPresent() { byte bufferATQA[2]; byte bufferSize = sizeof(bufferATQA); // Reset baud rates PCD_WriteRegister(TxModeReg, 0x00); PCD_WriteRegister(RxModeReg, 0x00); // Reset ModWidthReg PCD_WriteRegister(ModWidthReg, 0x26); StatusCode result = PICC_RequestA(bufferATQA, &bufferSize); debug_info("result:%x",result); return (result == STATUS_OK || result == STATUS_COLLISION); } // End PICC_IsNewCardPresent() void PCD_Reset() { PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command. // The datasheet does not mention how long the SoftRest command takes to complete. // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms. uint8_t count = 0; do { // Wait for the PowerDown bit in CommandReg to be cleared (max 3x50ms) nrf_delay_ms(50); } while ((PCD_ReadRegister(CommandReg) & (1 << 4)) && (++count) < 3); } // End PCD_Reset() #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) bool PCD_PerformSelfTest() { // This follows directly the steps outlined in 16.1.1 // 1. Perform a soft reset. PCD_Reset(); // 2. Clear the internal buffer by writing 25 bytes of 00h byte ZEROES[25] = {0x00}; PCD_WriteRegister(FIFOLevelReg, 0x80); // flush the FIFO buffer PCD_WriteRegister_long(FIFODataReg, 25, ZEROES); // write 25 bytes of 00h to FIFO PCD_WriteRegister(CommandReg, PCD_Mem); // transfer to internal buffer // 3. Enable self-test PCD_WriteRegister(AutoTestReg, 0x09); // 4. Write 00h to FIFO buffer PCD_WriteRegister(FIFODataReg, 0x00); // 5. Start self-test by issuing the CalcCRC command PCD_WriteRegister(CommandReg, PCD_CalcCRC); // 6. Wait for self-test to complete byte n; for (uint8_t i = 0; i < 0xFF; i++) { // The datasheet does not specify exact completion condition except // that FIFO buffer should contain 64 bytes. // While selftest is initiated by CalcCRC command // it behaves differently from normal CRC computation, // so one can't reliably use DivIrqReg to check for completion. // It is reported that some devices does not trigger CRCIRq flag // during selftest. n = PCD_ReadRegister(FIFOLevelReg); if (n >= 64) { debug_info("nnn:%x",n); NRF_LOG_FLUSH(); break; } } PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. // 7. Read out resulting 64 bytes from the FIFO buffer. byte result[64]; PCD_ReadRegister_long(FIFODataReg, 64, result, 0); // Auto self-test done // Reset AutoTestReg register to be 0 again. Required for normal operation. PCD_WriteRegister(AutoTestReg, 0x00); // Determine firmware version (see section 9.3.4.8 in spec) byte version = PCD_ReadRegister(VersionReg); // Pick the appropriate reference values const byte *reference; debug_info("version:%x",version); // Verify that the results match up to our expectations for (uint8_t i = 0; i < 64; i++) { debug_info("result[%d]:%x",i,result[i]); NRF_LOG_FLUSH(); // if (result[i] != pgm_read_byte(&(reference[i]))) { // return false; // } } debug_info("Test passed; all is good"); // Test passed; all is good. return true; } // End PCD_PerformSelfTest() void mfrc522_init() { nrf_gpio_cfg_output(SPI_SS_PIN); nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; spi_config.ss_pin = SPI_SS_PIN; spi_config.miso_pin = SPI_MISO_PIN; spi_config.mosi_pin = SPI_MOSI_PIN; spi_config.sck_pin = SPI_SCK_PIN; APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL)); PCD_Reset(); uint8_t v = PCD_ReadRegister(VersionReg); NRF_LOG_INFO("version:%x",v); // Reset baud rates PCD_WriteRegister(TxModeReg, 0x00); PCD_WriteRegister(RxModeReg, 0x00); // Reset ModWidthReg PCD_WriteRegister(ModWidthReg, 0x26); // When communicating with a PICC we need a timeout if something goes wrong. // f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo]. // TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg. PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds v=PCD_ReadRegister(TModeReg); NRF_LOG_INFO("TModeReg:%x",v); PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25μs. v=PCD_ReadRegister(TPrescalerReg); NRF_LOG_INFO("TPrescalerReg:%x",v); PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25μs. v=PCD_ReadRegister(TPrescalerReg); NRF_LOG_INFO("TPrescalerReg:%x",v); PCD_WriteRegister(TReloadRegH, 0x04); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout. PCD_WriteRegister(TReloadRegL, 0xE8); PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the register setting PCD_WriteRegister(ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4) PCD_AntennaOn(); NRF_LOG_FLUSH();
#include "nrf_drv_spi.h" #include "app_error.h" #include <string.h> #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "nrf_delay.h" #include "nrf_gpio.h" typedef uint8_t byte; typedef uint8_t PCD_Register; typedef uint8_t PCD_Command; typedef uint8_t PCD_RxGain; typedef uint8_t PICC_Command; typedef uint8_t PICC_Type; typedef uint8_t StatusCode; typedef uint8_t MIFARE_Misc; // Page 0: Command and status // 0x00 // reserved for future use #define CommandReg (0x01 << 1)// starts and stops command execution #define ComIEnReg (0x02 << 1)// enable and disable interrupt request control bits #define DivIEnReg (0x03 << 1)// enable and disable interrupt request control bits #define ComIrqReg (0x04 << 1)// interrupt request bits #define DivIrqReg (0x05 << 1)// interrupt request bits #define ErrorReg (0x06 << 1)// error bits showing the error status of the last command executed #define Status1Reg (0x07 << 1)// communication status bits #define Status2Reg (0x08 << 1)// receiver and transmitter status bits #define FIFODataReg (0x09 << 1)// input and output of 64 byte FIFO buffer #define FIFOLevelReg (0x0A << 1)// number of bytes stored in the FIFO buffer #define WaterLevelReg (0x0B << 1)// level for FIFO underflow and overflow warning #define ControlReg (0x0C << 1)// miscellaneous control registers #define BitFramingReg (0x0D << 1)// adjustments for bit-oriented frames #define CollReg (0x0E << 1)// bit position of the first bit-collision detected on the RF interface // 0x0F // reserved for future use // Page 1: Command // 0x10 // reserved for future use #define ModeReg (0x11 << 1)// defines general modes for transmitting and receiving #define TxModeReg (0x12 << 1)// defines transmission data rate and framing #define RxModeReg (0x13 << 1)// defines reception data rate and framing #define TxControlReg (0x14 << 1)// controls the logical behavior of the antenna driver pins TX1 and TX2 #define TxASKReg (0x15 << 1)// controls the setting of the transmission modulation #define TxSelReg (0x16 << 1)// selects the internal sources for the antenna driver #define RxSelReg (0x17 << 1)// selects internal receiver settings #define RxThresholdReg (0x18 << 1)// selects thresholds for the bit decoder #define DemodReg (0x19 << 1)// defines demodulator settings // 0x1A // reserved for future use // 0x1B // reserved for future use #define MfTxReg (0x1C << 1)// controls some MIFARE communication transmit parameters #define MfRxReg (0x1D << 1)// controls some MIFARE communication receive parameters // 0x1E // reserved for future use #define SerialSpeedReg (0x1F << 1)// selects the speed of the serial UART interface // Page 2: Configuration // 0x20 // reserved for future use #define CRCResultRegH (0x21 << 1)// shows the MSB and LSB values of the CRC calculation #define CRCResultRegL (0x22 << 1) // 0x23 // reserved for future use #define ModWidthReg (0x24 << 1)// controls the ModWidth setting? // 0x25 // reserved for future use #define RFCfgReg (0x26 << 1)// configures the receiver gain #define GsNReg (0x27 << 1)// selects the conductance of the antenna driver pins TX1 and TX2 for modulation #define CWGsPReg (0x28 << 1)// defines the conductance of the p-driver output during periods of no modulation #define ModGsPReg (0x29 << 1)// defines the conductance of the p-driver output during periods of modulation #define TModeReg (0x2A << 1)// defines settings for the internal timer #define TPrescalerReg (0x2B << 1)// the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg. #define TReloadRegH (0x2C << 1)//1 defines the 16-bit timer reload value #define TReloadRegL (0x2D << 1)//2 #define TCounterValueRegH (0x2E << 1)// shows the 16-bit timer value #define TCounterValueRegL (0x2F << 1) // Page 3: Test Registers // 0x30 // reserved for future use #define TestSel1Reg (0x31 << 1)// general test signal configuration #define TestSel2Reg (0x32 << 1)// general test signal configuration #define TestPinEnReg (0x33 << 1)// enables pin output driver on pins D1 to D7 #define TestPinValueReg (0x34 << 1)// defines the values for D1 to D7 when it is used as an I/O bus #define TestBusReg (0x35 << 1)// shows the status of the internal test bus #define AutoTestReg (0x36 << 1)// controls the digital self-test #define VersionReg (0x37 << 1)// shows the software version #define AnalogTestReg (0x38 << 1)// controls the pins AUX1 and AUX2 #define TestDAC1Reg (0x39 << 1)// defines the test value for TestDAC1 #define TestDAC2Reg (0x3A << 1)// defines the test value for TestDAC2 #define TestADCReg (0x3B << 1 // shows the value of ADC I and Q channels // 0x3C // reserved for production tests // 0x3D // reserved for production tests // 0x3E // reserved for production tests // 0x3F // reserved for production tests #define PCD_Idle (0x00) // no action, cancels current command execution #define PCD_Mem (0x01) // stores 25 bytes into the internal buffer #define PCD_GenerateRandomID (0x02) // generates a 10-byte random ID number #define PCD_CalcCRC (0x03) // activates the CRC coprocessor or performs a self-test #define PCD_Transmit (0x04) // transmits data from the FIFO buffer #define PCD_NoCmdChange (0x07) // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit #define PCD_Receive (0x08) // activates the receiver circuits #define PCD_Transceive (0x0C) // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission #define PCD_MFAuthent (0x0E) // performs the MIFARE standard authentication as a reader #define PCD_SoftReset (0x0F) // resets the MFRC522 #define RxGain_18dB (0x00 << 4)// 000b - 18 dB, minimum #define RxGain_23dB (0x01 << 4)// 001b - 23 dB #define RxGain_18dB_2 (0x02 << 4)// 010b - 18 dB, it seems 010b is a duplicate for 000b #define RxGain_23dB_2 (0x03 << 4)// 011b - 23 dB, it seems 011b is a duplicate for 001b #define RxGain_33dB (0x04 << 4)// 100b - 33 dB, average, and typical default #define RxGain_38dB (0x05 << 4)// 101b - 38 dB #define RxGain_43dB (0x06 << 4)// 110b - 43 dB #define RxGain_48dB (0x07 << 4)// 111b - 48 dB, maximum #define RxGain_min (0x00 << 4)// 000b - 18 dB, minimum, convenience for RxGain_18dB #define RxGain_avg (0x04 << 4)// 100b - 33 dB, average, convenience for RxGain_33dB #define RxGain_max (0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB #define PICC_CMD_REQA (0x26) // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. #define PICC_CMD_WUPA (0x52) // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. #define PICC_CMD_CT (0x88) // Cascade Tag. Not really a command, but used during anti collision. #define PICC_CMD_SEL_CL1 (0x93) // Anti collision/Select, Cascade Level 1 #define PICC_CMD_SEL_CL2 (0x95) // Anti collision/Select, Cascade Level 2 #define PICC_CMD_SEL_CL3 (0x97) // Anti collision/Select, Cascade Level 3 #define PICC_CMD_HLTA (0x50) // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. #define PICC_CMD_RATS (0xE0, // Request command for Answer To Reset. // The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9) // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. // The read/write commands can also be used for MIFARE Ultralight. #define PICC_CMD_MF_AUTH_KEY_A (0x60) // Perform authentication with Key A #define PICC_CMD_MF_AUTH_KEY_B (0x61) // Perform authentication with Key B #define PICC_CMD_MF_READ (0x30) // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight. #define PICC_CMD_MF_WRITE (0xA0) // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. #define PICC_CMD_MF_DECREMENT (0xC0) // Decrements the contents of a block and stores the result in the internal data register. #define PICC_CMD_MF_INCREMENT (0xC1) // Increments the contents of a block and stores the result in the internal data register. #define PICC_CMD_MF_RESTORE (0xC2) // Reads the contents of a block into the internal data register. #define PICC_CMD_MF_TRANSFER (0xB0) // Writes the contents of the internal data register to a block. // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) // The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. #define PICC_CMD_UL_WRITE (0xA2 // Writes one 4 byte page to the PICC. #define PICC_TYPE_UNKNOWN (0x00) #define PICC_TYPE_ISO_14443_4 (0x01)// PICC compliant with ISO/IEC 14443-4 #define PICC_TYPE_ISO_18092 (0x02) // PICC compliant with ISO/IEC 18092 (NFC) #define PICC_TYPE_MIFARE_MINI (0x03)// MIFARE Classic protocol, 320 bytes #define PICC_TYPE_MIFARE_1K (0x04)// MIFARE Classic protocol, 1KB #define PICC_TYPE_MIFARE_4K (0x05)// MIFARE Classic protocol, 4KB #define PICC_TYPE_MIFARE_UL (0x06)// MIFARE Ultralight or Ultralight C #define PICC_TYPE_MIFARE_PLUS (0x07)// MIFARE Plus #define PICC_TYPE_MIFARE_DESFIRE (0x08)// MIFARE DESFire #define PICC_TYPE_TNP3XXX (0x09)// Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure #define PICC_TYPE_NOT_COMPLETE (0xff) // SAK indicates UID is not complete. #define STATUS_OK (0x00)// Success #define STATUS_ERROR (0x01)// Error in communication #define STATUS_COLLISION (0x02)// Collission detected #define STATUS_TIMEOUT (0x03)// Timeout in communication. #define STATUS_NO_ROOM (0x04)// A buffer is not big enough. #define STATUS_INTERNAL_ERROR (0x05)// Internal error in the code. Should not happen ;-) #define STATUS_INVALID (0x06)// Invalid argument. #define STATUS_CRC_WRONG (0x07)// The CRC_A does not match #define STATUS_MIFARE_NACK (0xff) // A MIFARE PICC responded with NAK. #define MF_ACK (0xA) // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK. #define MF_KEY_SIZE (6) // A Mifare Crypto1 key is 6 bytes. // A struct used for passing the UID of a PICC. typedef struct { byte size; // Number of bytes in the UID. 4, 7 or 10. byte uidByte[10]; byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection. } Uid; // A struct used for passing a MIFARE Crypto1 key typedef struct { byte keyByte[MF_KEY_SIZE]; } MIFARE_Key; ///////////////////////////////////////////////////////////////////////////////////// // Basic interface functions for communicating with the MFRC522 ///////////////////////////////////////////////////////////////////////////////////// void PCD_WriteRegister(PCD_Register reg, byte value); void PCD_WriteRegister_long(PCD_Register reg, byte count, byte *values); byte PCD_ReadRegister(PCD_Register reg); void PCD_ReadRegister_long(PCD_Register reg, byte count, byte *values, byte rxAlign); //TODO rxAlign = 0 void PCD_SetRegisterBitMask(PCD_Register reg, byte mask); void PCD_ClearRegisterBitMask(PCD_Register reg, byte mask); StatusCode PCD_CalculateCRC(byte *data, byte length, byte *result); ///////////////////////////////////////////////////////////////////////////////////// // Functions for manipulating the MFRC522 ///////////////////////////////////////////////////////////////////////////////////// void PCD_Init(); void PCD_Reset(); void PCD_AntennaOn(); void PCD_AntennaOff(); byte PCD_GetAntennaGain(); void PCD_SetAntennaGain(byte mask); bool PCD_PerformSelfTest(); ///////////////////////////////////////////////////////////////////////////////////// // Power control functions ///////////////////////////////////////////////////////////////////////////////////// void PCD_SoftPowerDown(); void PCD_SoftPowerUp(); ///////////////////////////////////////////////////////////////////////////////////// // Functions for communicating with PICCs ///////////////////////////////////////////////////////////////////////////////////// StatusCode PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits, byte rxAlign, bool checkCRC); // TODO eclip StatusCode PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits, byte rxAlign, bool checkCRC); //TODO eclip StatusCode PICC_RequestA(byte *bufferATQA, byte *bufferSize); StatusCode PICC_WakeupA(byte *bufferATQA, byte *bufferSize); StatusCode PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize); StatusCode PICC_Select(Uid *uid, byte validBits); //TODO eclip StatusCode PICC_HaltA(); ///////////////////////////////////////////////////////////////////////////////////// // Convenience functions - does not add extra functionality ///////////////////////////////////////////////////////////////////////////////////// bool PICC_IsNewCardPresent(); bool PICC_ReadCardSerial(); static void spi_event_handler(nrf_drv_spi_evt_t const * p_event,void *p_context); static uint8_t spi_transmit(uint8_t data); static void mfrc522_write(uint8_t reg, uint8_t data); static uint8_t mfrc522_read(uint8_t reg); void mfrc522_init(); void mfrc522_reset();