How to get MFRC522 transceive function working?

40 views Asked by At

I'm working on a PCB that uses an STM32 and MFRC522 to read and write to 13.56MHz RFID tags. I'm able to read and write to registers successfully but am unable to get the wireless communication working. Here's my MFRC.c driver file.

/* Write single byte MFRC register
 *
 * @param addr: register address
 *
 * @param data: value to write to register
 */

HAL_StatusTypeDef MFRC_REGW(uint8_t addr,uint8_t data){
    uint8_t value=data;
    if(HAL_I2C_Mem_Write(&hi2c1, MFRC_ADDR<<1, addr, 1, &value, 1, 100)!=HAL_OK){
        return(HAL_ERROR);
    }
    else{
        return(HAL_OK);
    }
    HAL_Delay(1);
}

/* Read single byte from MFRC register
 *
 * @param addr: register address
 *
 * @param data: pointer to store read value
 */

HAL_StatusTypeDef MFRC_REGR(uint8_t addr,uint8_t* data){
    if(HAL_I2C_Mem_Read(&hi2c1, MFRC_ADDR<<1, addr, 1, data, 1, 100)!=HAL_OK){
        return(HAL_ERROR);
    }
    else{
        return(HAL_OK);
    }
    HAL_Delay(1);
}

/* Write to MFRC FIFO buffer
 *
 * @param data: Array of data to write to FIFO
 *
 * @param size: Size of array (bytes)
 */

HAL_StatusTypeDef MFRC_FIFOW(uint8_t* data,uint8_t size){
    for(int i=0;i<size;i++){
        if(HAL_I2C_Mem_Write(&hi2c1, MFRC_ADDR<<1, 0x09, 1, &data[i], 1, 100)!=HAL_OK){
            return(HAL_ERROR);

        }
        HAL_Delay(1);

    }
    return(HAL_OK);
}

/* Read from MFRC FIFO buffer
 *
 * @param data: Array to store read values (Ensure array is large enough)
 *
 * @param size: Number of bytes to read from FIFO
 */

HAL_StatusTypeDef MFRC_FIFOR(uint8_t* data,uint8_t size){
    for(int i=0;i<size;i++){
        if(HAL_I2C_Mem_Read(&hi2c1, MFRC_ADDR<<1, 0x09, 1, &data[i], 1, 100)!=HAL_OK){
            return(HAL_ERROR);
        }
        HAL_Delay(1);

    }
    return(HAL_OK);
}

/*
 * Function to calculate CRC on whatever data is in FIFO
 * !!CRCIRQ bit in DivIrqReg register can be used to detect when CRC has been calculated!!
 *
 * @param result: Array to store the two bytes of CRC
 *
 * */

HAL_StatusTypeDef CALC_CRC(uint8_t* data,uint8_t size,uint8_t* result){
    uint8_t CRCIRQ;
    MFRC_REGW(CMD_REG,IDLE); //clear command register
    MFRC_REGW(DIVIRQ,0x04); //Clear interrupt bits so we can detect when CRCIRQ is set
    MFRC_REGW(FIFO_LEV,0x80);
    MFRC_FIFOW(data, size); //Write data to FIFO ready for CRC calculation
    MFRC_REGW(CMD_REG,CALCCRC); //Execute CRC calculation command
    HAL_Delay(100);
    MFRC_REGR(DIVIRQ,&CRCIRQ);
    if((CRCIRQ&0x04)!=0x04){
        return(HAL_ERROR);
    }
    MFRC_REGW(CMD_REG,IDLE);
    MFRC_REGR(CRCL, &result[0]);
    MFRC_REGR(CRCH,&result[1]);
    return(HAL_OK);

}

/* Initialise MFRC to begin transceiving
 *
 * Code is written to interface with MIFARE Ultralight PICC. Different PICCs will need different baud rate.
 */

HAL_StatusTypeDef MFRC_INIT(void){
    HAL_GPIO_WritePin(GPIOB, NRST, 1); //Make sure MFRC is not reset
    HAL_GPIO_WritePin(GPIOB, NRST, 0);
    HAL_Delay(1);
    HAL_GPIO_WritePin(GPIOB, NRST, 1);
    HAL_Delay(50);
    MFRC_REGW(TX_REG,0x00);
    MFRC_REGW(RX_REG,0x00);
    SET_ANTGAIN();
    MFRC_REGW(MODWIDTH,0x26);
    //MFRC_REGW(TModeReg,0x80); //timer starts automatically after every transmission
    //MFRC_REGW(TPrescalerRegLO,0xA9); //Set prescaler to 169 => f_timer=40kHz, use this for timeouts
    //MFRC_REGW(TReloadHI,0x03); //Set reload counter to 4000 => 100ms timeout
    //MFRC_REGW(TReloadLO,0xE8);
    MFRC_REGW(TXASK,0x40); //Force 100% ASK modulation regardless of ModGsPrereg
    MFRC_REGW(MODE_REG,0x3D);
    MFRC_ANTON();
    return(HAL_OK);



}

/* Transceive data between MFRC and PICC
 *
 * @param sendData: Array of data to send
 *
 * @param sendsize: Number of bytes to send
 *
 * @param recdata: Array to store received data
 *
 * @param recsize: Number of bytes to receive
 *
 */

HAL_StatusTypeDef MFRC_TRANSCEIVE(uint8_t* sendData,uint8_t sendsize,uint8_t* recdata,uint8_t recsize){
    uint8_t IRQval=0;
    uint8_t BIT_val=0;
    uint8_t stat;
    uint8_t transaction[sendsize];

    memcpy(transaction,sendData,sendsize);

    MFRC_REGW(CMD_REG,IDLE); //Clear command register
    MFRC_REGW(IRQ_REG,0x7F);
    MFRC_REGW(BITFRAME,0x00);
    MFRC_REGW(FIFO_LEV,0x80); //Clear FIFO buffer
    MFRC_FIFOW(sendData,sendsize); //Write data to FIFO ready for transmission
    //MFRC_FIFOR(FIFO_State, sendsize);
    //CDC_Transmit_FS(FIFO_State, sendsize);
    MFRC_REGW(CMD_REG,TRANSCEIVE); //Send FIFO data and receive PICC response
    MFRC_REGR(BITFRAME,&BIT_val);
    MFRC_REGW(BITFRAME,(BIT_val|0x80)); //Start send bit
    HAL_Delay(100);
    MFRC_REGR(IRQ_REG,&IRQval);
    if((IRQval&0x30)!=0x30){ //Return error if RXIRQ and IDLEIRQ bits are not set
        return(HAL_ERROR);
    }

    MFRC_FIFOR(recdata,recsize); //Read and store received data
    return(HAL_OK);
}

And this is what I have in main.c.

  HAL_Delay(5000);
  MFRC_INIT();
  uint8_t value[18];
  uint8_t CRC_val[2];
  uint8_t FIFO;
  uint8_t transaction[4]={0x30,0x00}; //Read starting from 0x00 and we will receive first four pages (16 bytes) + CRC (2 bytes)
  char mess[]="Transceive Error";
  char messcrc[]="CRC error";
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      if(CALC_CRC(transaction, 2, CRC_val)!=HAL_OK){
          CDC_Transmit_FS(messcrc, strlen(messcrc));
      }
      memcpy(transaction+2,CRC_val,2);
      //CDC_Transmit_FS(transaction, 4);
      if(MFRC_TRANSCEIVE(transaction, 4, value, 18)!=HAL_OK){

      }
      else{
          CDC_Transmit_FS(value, 18);
      }
      HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

Essentially I'm just trying to read the first four pages of memory of the MIFARE Ultralight PICC. I'm pretty confident it is a firmware issue and not hardware as my hardware closely matches the typical arduino MFRC522 breakout board and my coil field strength is quite good.

I'm following the widely used MFRC522 arduino library as a guide but the MFRC_Transceive function is not working. The data is being transmitted as I can see that the FIFO_LEVEL register returns 4 before transmitting and 0 after issuing the TRANSCEIVE command to the command register. The one thing I haven't been able to check is the CRC. For my data 0x30,0x00 (read command for MIFARE Ultralight) the MFRC522 calculates the CRC to be 0xA802. I tried using online ISO CRC calculators but they didn't seem to agree with this value so I'm thinking an incorrect CRC may be the issue but I have no way of checking for certain.

Aside from the CRC I'm very puzzled on what else may be wrong. If anyone else has written their own driver for the MFRC522 and has any ideas to try that would be greatly appreciated. Thanks in advance.

0

There are 0 answers