0

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?

Clifford
  • 88,407
  • 13
  • 85
  • 165
Shahab
  • 1
  • 2
  • 1
    A logic analyzer would save you a lot of guesswork. I'm suspicious that you should not be using HAL_SPI_Transmit() and HAL_SPI_Receive(), and instead you should be using HAL_SPI_TransmitReceive(). I don't think separate single-byte calls to HAL_SPI_Transmit/Receive() will satisfy the read/write requirements of the device. And be aware that SPI is full duplex. See [this answer](https://stackoverflow.com/a/67936545/1401213) for an example of how to use HAL_SPI_TransmitReceive(). – kkrambo Jul 26 '23 at 09:05
  • You might want to try different variations of clock phase and polarity. There are only 4 possible combinations, so if you're unsure, you could try them all. Also beware that the SPI peripheral on the STM32 often initialises with the clock in the wrong state. A dummy transaction (e.g. with CS de-asserted) fixes it. – pmacfarlane Jul 26 '23 at 10:51
  • @kkrambo Thanks for your response. The HAL_SPI_TransmitReceive() function was the once I initially tried but it did not work so I used these functions to simplify the code and I thought maybe HAL_SPI_TransmitReceive() was the problem. However, now I think that all of these functions can work, the actual problem is that SPI communication is not working at all. I've tried using the same modules with Arduino UNO with the same SPI configuration and they work perfectly. – Shahab Jul 26 '23 at 15:17
  • @pmacfarlane Thanks for responding. I've tried all possible variations of the clock polarity, phase and baud rate and nothing works. I've used the same SPI configuration that the Arduino library uses for these modules (4 MHz Baud rate, CPHA 0 and CPOL 0). My Arduino is using this same configuration and works with the modules perfectly. Drivers for the module for other STM boards also have the same configuration. Can there be a compatibility issue or something else which is specific to my board? – Shahab Jul 26 '23 at 15:46
  • @pmacfarlane Also, if the STM32 often initializes the clock in the wrong state, how come it's working fine when I connect the STM32 with my Arduino and both communicate over the same SPI peripheral? And by performing a dummy transaction do you mean I should send dummy data (0x0) to a random address (1 for example)? – Shahab Jul 26 '23 at 16:17
  • Yes, any transaction that causes the STM32 to drive the clock line would fix it. If you don't assert the chip-select signal, then it won't matter what you send. You really do need to get a logic analyser or an oscilloscope with at least three channels for this kind of problem. – pmacfarlane Jul 26 '23 at 18:13
  • 1
    Are you sure you're configuring the `MISO` pin correctly? You're using `GPIO_MODE_INPUT` but shouldn't it be `GPIO_MODE_AF_PP`? – pmacfarlane Jul 26 '23 at 18:20
  • Oh okay. Well the chip select for the MFRC522 works on active low, so for this application I should assert it first and then perform the dummy transaction? – Shahab Jul 26 '23 at 22:48
  • I'll try getting access to an oscilloscope, this is for a university project and I'll have to request access and it'll probably take too long. By the way, the MISO pin was initially configured to be GPIO_MODE_AF_PP, but I saw somewhere that it was configured as GPIO_MODE_INPUT, so I tried both. I doubt that's the problem – Shahab Jul 26 '23 at 22:50
  • You want the STM32 to drive the clock, but you want the MFRC522 to ignore the transaction. So don't assert chip-select. – pmacfarlane Jul 27 '23 at 10:07
  • Alright I'll try that and then update it here, thanks. – Shahab Jul 27 '23 at 12:28

0 Answers0