MFRC522 with STM32L072CZ MCU (SPI Failure)

153 Views Asked by At

I am trying to configure the MFRC522 module and connect it with the STM32L072CZ MCU to read a RFID card. Studying different github projects, the arduino MFRC522 library and the RC522 datasheet, I've written a basic driver that should work with my STM32 to implement all the functionalities of the MFRC522 module to read and write an RFID card or tag. The problem I have is whenever I try to read or write a register on the module, it fails. I suspect there is a problem with the SPI communication between the module and the STM32.

I reached this conclusion after debugging my code, and when I reach the init function for the MFRC522 module, it fails to write any registers, I can see that because when I try to read those registers again they just return 0x0. I then tried to simplify my code by just initializing the module and using the read register function to read the version register of the module, which according to the module datasheet should return 90h or 91h. After initializing the module, I read this register and it just returns 0. I have also tried to read DivIrqReg and TestBusReg registers but they all return 0, so I am sure there is a problem with the SPI communication and the module isn't initialized properly because of this, and I am not reading any value.

I've been looking at this problem for 2 days now and since I am new to STM32 or firmware development and communication protocols, I am lost and can't diagnose the problem. I don't have access to a logic analyzer either so if someone could look at my code and see what's wrong that would be great.

The register write function is:

void Write_MFRC522(uint8_t addr, uint8_t val)
{
    uint8_t addr_bits = (((addr<<1) & 0x7E));

    /* CS LOW */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

    //The address is located:0XXXXXX0
    HAL_SPI_Transmit(&hspi1, &addr_bits, 1, 500);
    HAL_SPI_Transmit(&hspi1, &val, 1, 500);

    /* CS HIGH */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}

The register read function is:

uint8_t Read_MFRC522(uint8_t addr)
{
    uint8_t rx_bits;
    uint8_t addr_bits = (((addr<<1) & 0x7E) | 0x80);

    /* CS LOW */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

    //The address is located:1XXXXXX0
    HAL_SPI_Transmit(&hspi1, &addr_bits, 1, 500);
    HAL_SPI_Receive(&hspi1, &rx_bits, 1, 500);

    /* CS HIGH */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);

    return rx_bits;
}

The init function is:

void MFRC522_Init(void)
{

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);         // Set RST pin high for normal operation
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);           // Set NSS for SPI

    MFRC522_Reset();

    Write_MFRC522(MifareREG_T_MODE, 0x80); //0x8D);
    Write_MFRC522(MifareREG_T_PRESCALER, 0xA9);
    Write_MFRC522(MifareREG_T_RELOAD_L, 0x03);
    Write_MFRC522(MifareREG_T_RELOAD_H, 0xE8);
    Write_MFRC522(MifareREG_TX_AUTO, 0x40);
    Write_MFRC522(MifareREG_MODE, 0x3D);    

    AntennaOn();
}

The SPI configuration is as follows:

void MX_SPI1_Init(void)
{
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI1)
  {
    /* SPI1 clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PA4     ------> SPI1_NSS (Software Managed)
    PA5     ------> SPI1_SCK
    PA11     ------> SPI1_MISO
    PA12     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    // GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI1_MspInit 1 */

    // Configure the NSS pin (PA4) as a GPIO output.
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // Configure MISO to be input
    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

And my main looks as follows:

#include "main.h"
#include "gpio.h"

#include "mfrc_522.h"
#include <stdio.h>
#include <string.h>

char str1[17]={'\0'};
char str2[17]={'\0'};

int main(void)
{
    unsigned char status;

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();

  /* USER CODE BEGIN 2 */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);      // RST pin
  HAL_Delay(100);
  MFRC522_Init();
  //HAL_Delay(1000);

  status = Read_MFRC522(MifareREG_DIV_IRQ);
  status = Read_MFRC522(MifareREG_TEST_BUS);
  status = Read_MFRC522(MifareREG_VERSION);

  while (1)
  {

  }
}

I think the configuration for clock phase and clock polarity are correct, and if I understand from the datasheet properly, the SPI clock should be less than 10MHz, hence I have set a prescaler for 8. I don't understand why it's not working. Also, I have doubled checked all hardware connections and also tried another module but nothing works so there is probably a problem with the SPI connection. Can someone help me diagnose the problem?

1

There are 1 best solutions below

0
On

The problem you are having is that you are receiving only one byte from the RC522 after telling it you wish to read from a certain address. After a write, the first read will be null (or unknown data) while the register is fetched. The next read will contain the actual data from the register specified.

//The address is located:1XXXXXX0
HAL_SPI_Transmit(&hspi1, &addr_bits, 1, 500);
HAL_SPI_Receive(&hspi1, &rx_bits, 1, 500);

Here's a snippet I reproduced for you from the data sheet that explains this via a table:

8.1.2.1 SPI read data

Reading data using SPI requires the byte order shown in Table 6 to be used. >It is possible to read out up to n-data bytes. The first byte sent defines both the mode and the address.

Line Byte 0 Byte 1 Byte 2 To Byte n Byte n + 1
MOSI address 0 address 1 address 2 ... address n 00
MISO XXXX data 0 data 1 ... data n - 1 data n

Following this logic, your read function needs to transmit an extra 00 after the address, and then return the second byte read as the register containing the data at the selected address. Something like this should work:

uint8_t Read_MFRC522(uint8_t addr)
{
    uint8_t rx_bits[2];
    uint8_t addr_bits[] = { (((addr<<1) & 0x7E) | 0x80) , 0 };

    /* CS LOW */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

    //The address is located:1XXXXXX0
    HAL_SPI_Transmit(&hspi1, addr_bits, 2, 500);
    HAL_SPI_Receive(&hspi1, rx_bits, 2, 500);

    /* CS HIGH */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);

    return rx_bits[1];
}