abobija / esp-idf-rc522

Library for communication with RFID / NFC cards using MFRC522 module
https://components.espressif.com/components/abobija/rc522
Apache License 2.0
139 stars 40 forks source link

Read write test failing causes `Failed to write data (err: ESP_ERR_INVALID_STATE)` #37

Closed ProPablo closed 2 weeks ago

ProPablo commented 4 months ago

I am using an esp32s2 mini, and I bought my card readers from both amazon and aliexpress and it seems both work with the arduino library for rfid.

I used the following arduino code:

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN 3 // Configurable, see typical pin layout above
#define SS_PIN 5  // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
void setup()
{
  Serial.begin(115200); // Initialize serial communications with the PC
  while (!Serial)
    ; // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
  Serial.println("Testing out connecting to SPI ");

  SPI.begin(7, 11, 9, 5); // Init SPI bus
  // SPI.begin(); // Init SPI bus
  Serial.println("Testing out connecting to mfrc");
  mfrc522.PCD_Init();                // Init MFRC522
  delay(4);                          // Optional delay. Some board do need more time after init to be ready, see Readme
  mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card Reader details
  Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
}

void loop()
{
  if (!mfrc522.PICC_IsNewCardPresent())
  {
    return;
  }
  if (!mfrc522.PICC_ReadCardSerial())
  {
    return;
  }
  MFRC522::Uid *uid = &mfrc522.uid;

  for (byte i = 0; i < uid->size; i++)
  {
    // After F hex wraps around to 10 so print space and 0 to go to new
    if (uid->uidByte[i] < 0x10)
      Serial.print(F(" 0"));
    else
      Serial.print(F(" "));
    Serial.print(uid->uidByte[i], HEX);
  }
  Serial.print("\n");
}

However when using this library, I seem to be getting the log: Read/write test failed followed by repeating messages of:

E (2220) rc522: write: Unknown transport
E (2220) rc522: Failed to write data (err: ESP_ERR_INVALID_STATE)

Code:

#include <esp_log.h>
#include <inttypes.h>
#include "rc522.h"

static const char *TAG = "rc522-demo";
static rc522_handle_t scanner;

static void rc522_handler(void *arg, esp_event_base_t base, int32_t event_id, void *event_data)
{
    rc522_event_data_t *data = (rc522_event_data_t *)event_data;

    switch (event_id)
    {
    case RC522_EVENT_TAG_SCANNED:
    {
        rc522_tag_t *tag = (rc522_tag_t *)data->ptr;
        ESP_LOGI(TAG, "Tag scanned (sn: %" PRIu64 ")", tag->serial_number);
    }
    break;
    }
}

void app_main()
{
    vTaskDelay(pdMS_TO_TICKS(2000));
    ESP_LOGI(TAG, "Starting up");
    rc522_config_t config = {
        .spi.host = SPI3_HOST,
        .spi.miso_gpio = GPIO_NUM_11,
        .spi.mosi_gpio = GPIO_NUM_9,
        .spi.sck_gpio = GPIO_NUM_7,
        .spi.sda_gpio = GPIO_NUM_5,
    };
    rc522_create(&config, &scanner);
    rc522_register_events(scanner, RC522_EVENT_ANY, rc522_handler, NULL);
    rc522_start(scanner);

    // while (1)
    // {
    //  ESP_LOGI(TAG, "Done 1 tick");
    //  vTaskDelay(pdMS_TO_TICKS(2000));
    // }
}

Having a deeper look at the source code, it turns out the invalid state error is there because in rc522_start if the test fails, rc522_destroy is called causing the SPI device to be destroyed but the task still remains for some reason.

I had a further look and changed the source of the read write test to:

        const uint8_t test_addr = RC522_MOD_WIDTH_REG, test_val = 0x25;
        uint8_t pass = 0;

        for (uint8_t i = test_val; i < test_val + 2; i++)
        {
            err = rc522_write(rc522, test_addr, i);

            if (err == ESP_OK)
            {
                err = rc522_read(rc522, test_addr, &tmp);
                if (err != ESP_OK)
                {
                    ESP_LOGE(TAG, "Read test failed (err: %s)", esp_err_to_name(err));
                }

                if (err == ESP_OK && tmp == i)
                {
                    pass = 1;
                }
                else
                {
                    ESP_LOGE(TAG, "Invalid return %d, expected %d", tmp, i);
                }
            }
            else
            {
                ESP_LOGE(TAG, "Write test failed (err: %s)", esp_err_to_name(err));
            }

            if (pass != 1)
            {
                ESP_LOGE(TAG, "Read/write test failed");
                // For some reason the task still goes on in the background, giving ESP_ERR_INVALID_STATE when trying to write
                rc522_destroy(rc522);

                return err;
            }
        }

I get the output: Invalid return 0, expected 37. So im guessing either the read or the write couldve failed here. I might try testing a known readable value, on the datasheet it says the address 37h is the VersionReg but im not sure how to use the SPI interface especially with rc522_read sorry :smiling_face_with_tear:.
I can't use pin 19 for sck as recommended by the library and the video as it isnt exposed through the dev board im using.
For now im throwing more hardware at the problem and using the pn532 :laughing:.

supcik commented 4 months ago

I am experiencing the same error. I checked the rc522_start procedure and I don't fully understand it :

uint8_t pass = 0;

for(uint8_t i = test_val; i < test_val + 2; i++) {
    err = rc522_write(rc522, test_addr, i);

    if(err == ESP_OK) {
        err = rc522_read(rc522, test_addr, &tmp);

        if(err == ESP_OK && tmp == i) {
            pass = 1;
        }
    }

    if(pass != 1) {
        ESP_LOGE(TAG, "Read/write test failed");
        rc522_destroy(rc522);

        return err;
    }
}

But anyhow, this does not solve our problem. The value 0x25 (or 37 decimal) is written at the address RC522_MOD_WIDTH_REG = 0x24 = 36 and this register is writable, so in theory it should work. Note however that this error is not always reproducible. I've experienced that sometimes it fails and sometimes it works.