Hai,
i try to MFRC522 rfid reader interface the nrf52833.
1. I try the read version from reader but it's only show the 0xFF
2.I try to read the card id . it is not work.
I need solution for this. I attached the code below.
mfrc522.c file
#include <stdio.h> #include "../src/mfrc522.h" #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/sys/printk.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/spi.h> #define PICC_TIMEOUT_5MS 0x09 #define PICC_TIMEOUT_10MS 0x13 #define PICC_TIMEOUT_15MS 0X1E #define GPIO_CS 9 #define SPI1_NODE DT_NODELABEL(spi1) const struct device *spi1_dev = DEVICE_DT_GET(SPI1_NODE); #define GPIO1_NODE DT_NODELABEL(gpio0) const struct device *gpio1_dev = DEVICE_DT_GET(GPIO1_NODE); const struct spi_config spi_cfg = { .frequency =4000000U, .operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_OP_MODE_GET(0), .slave = 0, }; int SPI_Init(void) { if (!spi1_dev) { printk("Failed to get SPI device...\n"); return -1; } if (!gpio1_dev) { printk("Failed to get GPIO device\n"); return -1; } // Configure CS pin (Active Low) //gpio_pin_configure(gpio1_dev, GPIO_CS, GPIO_OUTPUT); gpio_pin_set(gpio1_dev, GPIO_CS, GPIO_OUTPUT_INACTIVE); // Ensure CS is inactive at first gpio_pin_configure(gpio1_dev, GPIO_CS,1); printk("SPI Initialized.\n"); return 0; } uint8_t TM_MFRC522_RdReg(uint8_t ucAddress) { uint8_t command = ((ucAddress << 1) & 0x7E) | 0x80; // Read command uint8_t tx_data[1] = {command}; // Send read command uint8_t rx_data[1] = {0}; // Receive buffer struct spi_buf tx_buf = { .buf = tx_data, .len = 1, }; struct spi_buf rx_buf = { .buf = rx_data, .len = 1, }; struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1, }; struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1, }; gpio_pin_set(gpio1_dev, GPIO_CS, 0); // Assert CS if (spi_transceive(spi1_dev, &spi_cfg, &tx, &rx) != 0) { printk("Error reading MFRC522 register\n"); gpio_pin_set(gpio1_dev, GPIO_CS, 1); // Deassert CS return 0; } gpio_pin_set(gpio1_dev, GPIO_CS,1); // Deassert CS return rx_data[0]; // Return received byte } void TM_MFRC522_WrReg(uint8_t ucAddress, uint8_t ucValue) { uint8_t command = (ucAddress << 1) & 0x7E; // Write command struct spi_buf tx_bufs[2] = { { .buf = &command, .len = 1 }, { .buf = &ucValue, .len = 1 } }; struct spi_buf_set tx_set = { .buffers = tx_bufs, .count = 2 }; gpio_pin_set(gpio1_dev, GPIO_CS, 0); // Assert CS if (spi_write(spi1_dev, &spi_cfg, &tx_set) != 0) { printk("SPI transfer failed with error.\n"); } gpio_pin_set(gpio1_dev, GPIO_CS, 1); // Deassert CS } int TM_MFRC522_Init(void) { TM_MFRC522_Reset(); // Initialize MFRC522 registers TM_MFRC522_WrReg(MFRC522_REG_T_MODE, 0x8D); TM_MFRC522_WrReg(MFRC522_REG_T_PRESCALER, 0x3E); TM_MFRC522_WrReg(MFRC522_REG_T_RELOAD_L, 0x09); TM_MFRC522_WrReg(MFRC522_REG_T_RELOAD_H, 0); TM_MFRC522_WrReg(MFRC522_REG_TX_AUTO, 0x40); TM_MFRC522_WrReg(MFRC522_REG_MODE, 0x3D); TM_MFRC522_WrReg(MFRC522_REG_RF_CFG, 0x70); TM_MFRC522_SetBitMask(MFRC522_REG_DIV1_EN, 0x80); // Enable automatic handshaking TM_MFRC522_AntennaOn(); // Enable antenna printk("MFRC522 Initialized.\n"); return 0; } void TM_MFRC522_SetBitMask(uint8_t reg, uint8_t mask) { TM_MFRC522_WrReg(reg, TM_MFRC522_RdReg(reg) | mask); } void TM_MFRC522_ClearBitMask(uint8_t reg, uint8_t mask) { TM_MFRC522_WrReg(reg, TM_MFRC522_RdReg(reg) & (~mask)); } void TM_MFRC522_AntennaOn(void) { uint8_t temp; temp = TM_MFRC522_RdReg(MFRC522_REG_TX_CONTROL); if (!(temp & 0x03)) TM_MFRC522_SetBitMask(MFRC522_REG_TX_CONTROL, 0x03); } void TM_MFRC522_AntennaOff(void) { TM_MFRC522_ClearBitMask(MFRC522_REG_TX_CONTROL, 0x03); } void TM_MFRC522_Reset(void) { uint8_t temp; TM_MFRC522_WrReg(MFRC522_REG_COMMAND, PCD_RESETPHASE); do { temp = TM_MFRC522_RdReg(MFRC522_REG_COMMAND); temp &= 0x10; } while (temp); } uint8_t MFRC522_ToCard(uint8_t command, uint8_t *sendData, uint8_t sendLen, uint8_t *backData, unsigned *backLen) { uint8_t _status = MI_ERR; uint8_t irqEn = 0x00; uint8_t waitIRq = 0x00; uint8_t lastBits; uint8_t n; unsigned i; // Set up irqEn and waitIRq depending on the command switch (command) { case PCD_AUTHENT: irqEn = 0x12; // Enable IRQ for authentication waitIRq = 0x10; // Wait for authentication complete IRQ break; case PCD_TRANSCEIVE: irqEn = 0x77; // Enable IRQ for transceive waitIRq = 0x30; // Wait for TX and RX complete IRQ break; default: break; } // Write irqEn and enable IRQ TM_MFRC522_WrReg(MFRC522_REG_COMM_IE_N, irqEn | 0x80); // Enable interrupts TM_MFRC522_ClearBitMask(MFRC522_REG_COMM_IRQ, 0x80); // Clear the interrupt flags TM_MFRC522_SetBitMask(MFRC522_REG_FIFO_LEVEL, 0x80); // Clear FIFO TM_MFRC522_WrReg(MFRC522_REG_COMMAND, PCD_IDLE); // Set the command register to idle // Write sendData into FIFO for (i = 0; i < sendLen; i++) { TM_MFRC522_WrReg(MFRC522_REG_FIFO_DATA, sendData[i]); } // Issue the command TM_MFRC522_WrReg(MFRC522_REG_COMMAND, command); // If PCD_TRANSCEIVE command, set framing bit if (command == PCD_TRANSCEIVE) { TM_MFRC522_SetBitMask(MFRC522_REG_BIT_FRAMING, 0x80); // Set the framing bit } // Wait for interrupt or timeout i = 0xFFFF; // Timeout counter do { n = TM_MFRC522_RdReg(MFRC522_REG_COMM_IRQ); // Read IRQ status i--; } while (i && !(n & 0x01) && !(n & waitIRq)); // Wait for interrupt or timeout TM_MFRC522_ClearBitMask(MFRC522_REG_BIT_FRAMING, 0x80); // Clear framing bit if (i != 0) // If no timeout occurred { // Check for errors in the process if (!(TM_MFRC522_RdReg(MFRC522_REG_ERROR) & 0x1B)) { _status = MI_OK; // No error occurred // If no tag found, return MI_NOTAGERR if (n & irqEn & 0x01) { _status = MI_NOTAGERR; } // Handle PCD_TRANSCEIVE command response if (command == PCD_TRANSCEIVE) { n = TM_MFRC522_RdReg(MFRC522_REG_FIFO_LEVEL); // Get number of bytes in FIFO lastBits = TM_MFRC522_RdReg(MFRC522_REG_CONTROL) & 0x07; // Get the remaining bits // Calculate back data length if (lastBits) { *backLen = (n - 1) * 8 + lastBits; } else { *backLen = n * 8; } if (n == 0) { n = 1; } // Limit the number of bytes to read if (n > 16) { n = 16; } // Read the data from FIFO into backData for (i = 0; i < n; i++) { backData[i] = TM_MFRC522_RdReg(MFRC522_REG_FIFO_DATA); } // Null-terminate the backData for safety backData[i] = 0; } } else { // If an error occurred, set the status to MI_ERR _status = MI_ERR; } } return _status; } uint8_t MFRC522_Request(uint8_t reqMode, uint8_t *TagType) { uint8_t _status; unsigned backBits; printk("Sending request...\n"); TM_MFRC522_WrReg(MFRC522_REG_BIT_FRAMING, 0x07); TagType[0] = reqMode; _status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits); if (_status != MI_OK) { printk("Request failed!\n"); } else { printk("Request succeeded. Back bits: %u\n", backBits); } if ((_status != MI_OK) || (backBits != 0x10)) { printk("MI_ERR\n"); _status = MI_ERR; } return _status; } uint8_t MFRC522_isCard(uint8_t *TagType) { if (MFRC522_Request(PICC_REQA, TagType) == MI_OK) { printk("Card detected!\n"); return 1; } else { printk("No card detected.\n"); return 0; } } TM_MFRC522_STS_T TM_MFRC522_Anticoll(uint8_t *serNum) { TM_MFRC522_STS_T status; uint8_t i; uint8_t serNumCheck = 0; uint16_t unLen; TM_MFRC522_ClearBitMask(MFRC522_REG_STATUS2, 0x08); TM_MFRC522_WrReg(MFRC522_REG_BIT_FRAMING, 0x00); TM_MFRC522_SetBitMask(MFRC522_REG_COLL, 0x80); serNum[0] = PICC_ANTICOLL; serNum[1] = 0x20; // NVB status = TM_MFRC522_ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen); if (status == MI_OK) { for (i = 0; i < 4; i++) { serNumCheck ^= serNum[i]; } if (serNumCheck != serNum[i]) { status = MI_ERR; } } TM_MFRC522_SetBitMask(MFRC522_REG_COLL, 0x80); return status; } TM_MFRC522_STS_T TM_MFRC522_ToCard(uint8_t command, uint8_t* sendData, uint8_t sendLen, uint8_t* backData, uint16_t* backLen) { TM_MFRC522_STS_T status = MI_ERR; uint8_t irqEn = 0x00; uint8_t waitFor = 0x00; uint8_t lastBits; uint8_t regValue; uint16_t i; switch (command) { case PCD_AUTHENT: irqEn = 0x13; waitFor = 0x10; // irqEn = 0x12; (original setting) break; case PCD_TRANSCEIVE: /* TxIRq(b6), RxIRq(b5), IdleIRq(b4), HiAlerIRq(b3), LoAlertIRq(b2), ErrIRq(b1), TimerIRq(b0) */ /* wait response from PICC or 5 ms timeout */ irqEn = 0x21; waitFor = 0x30; break; default: break; } /* IRQ pin is inverted with respect to the Status1Reg register’s IRq bit */ TM_MFRC522_WrReg(MFRC522_REG_COMM_IE_N, irqEn | 0x80); /* Clear marked bits in ComIrqReg register */ TM_MFRC522_ClearBitMask(MFRC522_REG_COMM_IRQ, 0x80); TM_MFRC522_WrReg(MFRC522_REG_COMMAND,PCD_IDLE); /* Flush FIFO contents */ TM_MFRC522_SetBitMask(MFRC522_REG_FIFO_LEVEL, 0x80); /* Cancel current comand execution */ TM_MFRC522_WrReg(MFRC522_REG_COMMAND, PCD_IDLE); /* Write data to FIFO */ for (i = 0; i < sendLen; i++) { TM_MFRC522_WrReg(MFRC522_REG_FIFO_DATA, sendData[i]); } /* Execute PCD_TRANSCEIVE command */ TM_MFRC522_WrReg(MFRC522_REG_COMMAND, command); if (command == PCD_TRANSCEIVE) { /* Start frame transmission */ TM_MFRC522_SetBitMask(MFRC522_REG_BIT_FRAMING, 0x80); } i = 1000; /* Wait response from PICC or internal timer 5 ms timeout happened */ do { regValue = TM_MFRC522_RdReg(MFRC522_REG_COMM_IRQ); i--; }while ((i!=0) && !(regValue&0x01) && !(regValue&waitFor)); /* Set StartSend=0 */ TM_MFRC522_ClearBitMask(MFRC522_REG_BIT_FRAMING, 0x80); /* Check if internal timer timeout */ if (!(regValue &0x01)) { if(i!=0) { if (!(TM_MFRC522_RdReg(MFRC522_REG_ERROR) & 0x1B)) { status = MI_OK; if (command == PCD_TRANSCEIVE) { /* Check the number of bytes stored in FIFO */ regValue = TM_MFRC522_RdReg(MFRC522_REG_FIFO_LEVEL); /* Check valid bit number of last byte */ lastBits = TM_MFRC522_RdReg(MFRC522_REG_CONTROL) & 0x07; if (lastBits) *backLen = (regValue - 1) * 8 + lastBits; else *backLen = regValue * 8; if (regValue == 0) regValue = 1; if (regValue > MFRC522_MAX_LEN) regValue = MFRC522_MAX_LEN; /* Read received data in FIFO */ for (i = 0; i < regValue; i++) backData[i] = TM_MFRC522_RdReg(MFRC522_REG_FIFO_DATA); } } else {status = MI_ERR;} } } TM_MFRC522_SetBitMask(MFRC522_REG_CONTROL,0x80); TM_MFRC522_WrReg(MFRC522_REG_COMMAND,PCD_IDLE); return status; } void TM_MFRC522_CalculateCRC(uint8_t *pIndata, uint8_t len, uint8_t *pOutData) { uint8_t i, n; TM_MFRC522_ClearBitMask(MFRC522_REG_DIV_IRQ, 0x04); TM_MFRC522_SetBitMask(MFRC522_REG_FIFO_LEVEL, 0x80); for (i = 0; i < len; i++) { TM_MFRC522_WrReg(MFRC522_REG_FIFO_DATA, *(pIndata + i)); } TM_MFRC522_WrReg(MFRC522_REG_COMMAND, PCD_CALCCRC); i = 0xFF; do { n = TM_MFRC522_RdReg(MFRC522_REG_DIV_IRQ); i--; } while ((i != 0) && !(n & 0x04)); pOutData[0] = TM_MFRC522_RdReg(MFRC522_REG_CRC_RESULT_L); pOutData[1] = TM_MFRC522_RdReg(MFRC522_REG_CRC_RESULT_M); } void TM_MFRC522_Halt(void) { unsigned unLen; uint8_t buff[4]; buff[0] = PICC_HALT; buff[1] = 0; TM_MFRC522_CalculateCRC(buff, 2, &buff[2]); if (MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &unLen) != MI_NOTAGERR) { printf("Halt command error. \n"); } } uint8_t TM_MFRC522_Check(uint8_t *id) { uint8_t status; uint8_t cardtype[3]; status = MFRC522_Request(PICC_REQA, cardtype); if (status == MI_OK) { printk("success..!\n"); status = TM_MFRC522_Anticoll(id); } else { printk("not success..!\n"); status = MI_ERR; } return status; }
mfrc522.h
#include <zephyr/device.h> #include <zephyr/sys/printk.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/spi.h> /* MFRC522 status */ typedef enum { MI_OK = 0, MI_NOTAGERR, MI_ERR } TM_MFRC522_STS_T; /* MFRC522 commands */ #define PCD_IDLE 0x00 // No action; Cancel the current command #define PCD_AUTHENT 0x0E // Authentication Key #define PCD_RECEIVE 0x08 // Receive Data #define PCD_TRANSMIT 0x04 // Transmit data #define PCD_TRANSCEIVE 0x0C // Transmit and receive data, #define PCD_RESETPHASE 0x0F // Reset #define PCD_CALCCRC 0x03 // CRC Calculate /* Mifare One card command word */ #define PICC_REQA 0x26 // find the antenna area does not enter hibernation #define PICC_WAKEUP 0x52 // find all the cards antenna area #define PICC_ANTICOLL 0x93 // anti-collision #define PICC_SElECTTAG 0x93 // election card #define PICC_AUTHENT1A 0x60 // authentication key A #define PICC_AUTHENT1B 0x61 // authentication key B #define PICC_READ 0x30 // Read Block #define PICC_WRITE 0xA0 // write block #define PICC_DECREMENT 0xC0 // debit #define PICC_INCREMENT 0xC1 // recharge #define PICC_RESTORE 0xC2 // transfer block data to the buffer #define PICC_TRANSFER 0xB0 // save the data in the buffer #define PICC_HALT 0x50 // Sleep /* MFRC522 Registers */ /* Page 0: Command and Status */ #define MFRC522_REG_RESERVED00 0x00 #define MFRC522_REG_COMMAND 0x01 #define MFRC522_REG_COMM_IE_N 0x02 #define MFRC522_REG_DIV1_EN 0x03 #define MFRC522_REG_COMM_IRQ 0x04 #define MFRC522_REG_DIV_IRQ 0x05 #define MFRC522_REG_ERROR 0x06 #define MFRC522_REG_STATUS1 0x07 #define MFRC522_REG_STATUS2 0x08 #define MFRC522_REG_FIFO_DATA 0x09 #define MFRC522_REG_FIFO_LEVEL 0x0A #define MFRC522_REG_WATER_LEVEL 0x0B #define MFRC522_REG_CONTROL 0x0C #define MFRC522_REG_BIT_FRAMING 0x0D #define MFRC522_REG_COLL 0x0E #define MFRC522_REG_RESERVED01 0x0F /* Page 1: Command */ #define MFRC522_REG_RESERVED10 0x10 #define MFRC522_REG_MODE 0x11 #define MFRC522_REG_TX_MODE 0x12 #define MFRC522_REG_RX_MODE 0x13 #define MFRC522_REG_TX_CONTROL 0x14 #define MFRC522_REG_TX_AUTO 0x15 #define MFRC522_REG_TX_SELL 0x16 #define MFRC522_REG_RX_SELL 0x17 #define MFRC522_REG_RX_THRESHOLD 0x18 #define MFRC522_REG_DEMOD 0x19 #define MFRC522_REG_RESERVED11 0x1A #define MFRC522_REG_RESERVED12 0x1B #define MFRC522_REG_MIFARE 0x1C #define MFRC522_REG_RESERVED13 0x1D #define MFRC522_REG_RESERVED14 0x1E #define MFRC522_REG_SERIALSPEED 0x1F /* Page 2: Configuration */ #define MFRC522_REG_RESERVED20 0x20 #define MFRC522_REG_CRC_RESULT_M 0x21 #define MFRC522_REG_CRC_RESULT_L 0x22 #define MFRC522_REG_RESERVED21 0x23 #define MFRC522_REG_MOD_WIDTH 0x24 #define MFRC522_REG_RESERVED22 0x25 #define MFRC522_REG_RF_CFG 0x26 #define MFRC522_REG_GS_N 0x27 #define MFRC522_REG_CWGS_PREG 0x28 #define MFRC522_REG__MODGS_PREG 0x29 #define MFRC522_REG_T_MODE 0x2A #define MFRC522_REG_T_PRESCALER 0x2B #define MFRC522_REG_T_RELOAD_H 0x2C #define MFRC522_REG_T_RELOAD_L 0x2D #define MFRC522_REG_T_COUNTER_VALUE_H 0x2E #define MFRC522_REG_T_COUNTER_VALUE_L 0x2F /* Page 3:TestRegister */ #define MFRC522_REG_RESERVED30 0x30 #define MFRC522_REG_TEST_SEL1 0x31 #define MFRC522_REG_TEST_SEL2 0x32 #define MFRC522_REG_TEST_PIN_EN 0x33 #define MFRC522_REG_TEST_PIN_VALUE 0x34 #define MFRC522_REG_TEST_BUS 0x35 #define MFRC522_REG_AUTO_TEST 0x36 #define MFRC522_REG_VERSION 0x37 #define MFRC522_REG_ANALOG_TEST 0x38 #define MFRC522_REG_TEST_ADC1 0x39 #define MFRC522_REG_TEST_ADC2 0x3A #define MFRC522_REG_TEST_ADC0 0x3B #define MFRC522_REG_RESERVED31 0x3C #define MFRC522_REG_RESERVED32 0x3D #define MFRC522_REG_RESERVED33 0x3E #define MFRC522_REG_RESERVED34 0x3F #define MFRC522_DUMMY 0x00 #define MFRC522_MAX_LEN 16 void TM_MFRC522_Halt(void); int SPI_Init(void); int TM_MFRC522_Init(void); uint8_t TM_MFRC522_RdReg(uint8_t ucAddress); void TM_MFRC522_WrReg(uint8_t ucAddress, uint8_t ucValue); void TM_MFRC522_SetBitMask(uint8_t reg, uint8_t mask); void TM_MFRC522_ClearBitMask(uint8_t reg, uint8_t mask); void TM_MFRC522_AntennaOn(void); void TM_MFRC522_AntennaOff(void); void TM_MFRC522_Reset(void); uint8_t MFRC522_ToCard(uint8_t command, uint8_t *sendData, uint8_t sendLen, uint8_t *backData,unsigned *backLen); uint8_t MFRC522_isCard(uint8_t *TagType ) ; TM_MFRC522_STS_T TM_MFRC522_ToCard(uint8_t command, uint8_t* sendData, uint8_t sendLen, uint8_t* backData, uint16_t* backLen); TM_MFRC522_STS_T TM_MFRC522_Anticoll(uint8_t* serNum); void TM_MFRC522_CalculateCRC(uint8_t* pIndata, uint8_t len, uint8_t* pOutData); void TM_MFRC522_Halt(void); uint8_t TM_MFRC522_Check(uint8_t *id); uint8_t MFRC522_Request(uint8_t reqMode, uint8_t *TagType);
main.c file
#include <zephyr/drivers/gpio.h> #include <zephyr/drivers/SPi.h> #include "../src/mfrc522.h" /* The devicetree node identifier for the "led0" alias. */ #define LED0_NODE DT_ALIAS(led0) uint8_t ID[5]; /* * A build error on this line means your board is unsupported. * See the sample documentation for information on how to fix this. */ static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); int main(void) { int ret; SPI_Init(); TM_MFRC522_Init(); if (!gpio_is_ready_dt(&led)) { return 0; } ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); if (ret < 0) { return 0; } uint8_t version = TM_MFRC522_RdReg(0x37); // Version register printk("MFRC522 Version: 0x%02X\n", version); if ((TM_MFRC522_Check(ID) == MI_OK)) { gpio_pin_toggle_dt(&led); printk(" [%02x%02x%02x%02x%02x]\n\r\n", ID[0], ID[1], ID[2], ID[3], ID[4]); } return 0; }
Output :
*** Booting nRF Connect SDK v2.7.0-5cb85570ca43 ***
*** Using Zephyr OS v3.6.99-100befc70c74 ***
SPI Initialized.
MFRC522 Initialized.
MFRC522 Version: 0xFF
Sending request...
Request failed!
MI_ERR
not success..!