Hi,
I'm trying to make a small battery powered RFID Reader with and RC522 and ESP32 vemos D1 mini.
I found this thread github, where there is a suggestion for deep sleep card detection with RC522 and ESP32
I have a ESP Now server set up on a ESP8226 and that is working. The IDEA is to use ESP now to send the ID tag to save battery instead of powering up Wifi.
Using a standard tutorial online for an ESP32 and RC522 I can read all my tags (i only have 4 different ones).
If use the code from github I can only read 1 of the 4 tags.
My attemt to use the code from github and combine it with ESP now. It works for the 1 tag, but no luck on the rest.
I believe my issue is with the fast detection mode, but I can not figure out how to tweak it.
Any help would be much appreciated:
/* This is an example that show how to use MFRC522 with ESP32's deep sleep mode efficiently.
* In the deep sleep stub handler a quick check to see if a card is present is done (~1.5ms).
* Only if there is a card the full wake up sequence is initiated.
*
* In this handler almost all hardware is still uninitialized. Therefore all functions and data
* must be put into RTC RAM. That means you can't call any of the IDF or Arduino functions.
* Only ROM functions and direct register accesses are available.
* Therefore all hardware access functions had to be reimplemented. All functions intended to be
* called in deep sleep stub got an "ds" prefix.
*
* ATTENTION: Don't call these functions from your normal application. Only core 0 can access
* RTC fast RAM and normal arduino programms run on core 1.
*
* TODO: Hardware reset is unsupported at the moment.
*/
/******************* Configuration *****************/
#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>
//ESP Now
#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#define DEBUG_PRINT_ENABLED 1
#define MFRC_CS 5
#define MFRC_SCK 18
#define MFRC_MOSI 23
#define MFRC_MISO 19
#define sleep_time_in_us 1000000ll
#include "rom/rtc.h"
#include "soc/rtc_cntl_reg.h"
// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 1
//MAC Address of the receiver
uint8_t broadcastAddress[] = {0x5C, 0xCF, 0x7F, 0x9A, 0x09, 0x90};
//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
int id;
char tag[14];
} struct_message;
//Create a struct_message called myData
struct_message myData;
MFRC522 mfrc522 { MFRC_CS, UINT8_MAX };
#if DEBUG_PRINT_ENABLED
#include "soc/uart_reg.h"
static const char RTC_RODATA_ATTR debug_fmt_str[] = "---------> dbg: %d\n";
static const char RTC_RODATA_ATTR stub_fmt_str[] = "Deep sleep stub entered!\n";
static const char RTC_RODATA_ATTR wake_fmt_str[] = "Card detected. Waking up!\n";
static const char RTC_RODATA_ATTR sleep_fmt_str[] = "Sleeping again!\n";
#define DEBUG_PRINT ets_printf
#else
#define DEBUG_PRINT(...) do {} while (0)
#endif
/* Remember register offsets in RTC memory as esp32_gpioMux table is not available in deep sleep stub. */
uint32_t RTC_DATA_ATTR cs_reg = esp32_gpioMux[MFRC_CS].reg;
uint32_t RTC_DATA_ATTR sck_reg = esp32_gpioMux[MFRC_SCK].reg;
uint32_t RTC_DATA_ATTR mosi_reg = esp32_gpioMux[MFRC_MOSI].reg;
#define MFRC_REGISTER_READ_TIME 7 //us, used to calculate timeouts
static inline __attribute__((always_inline)) void dsGpioAsOutput(uint8_t pin, uint32_t reg_offset)
{
GPIO.enable_w1ts = ((uint32_t) 1 << pin);
ESP_REG(DR_REG_IO_MUX_BASE + reg_offset) = ((uint32_t) 2 << FUN_DRV_S) | FUN_IE | ((uint32_t) 2 << MCU_SEL_S);
}
static inline __attribute__((always_inline)) void dsDigitalWrite(uint8_t pin, bool value)
{
if (value) {
GPIO.out_w1ts = ((uint32_t) 1 << pin);
} else {
GPIO.out_w1tc = ((uint32_t) 1 << pin);
}
}
static inline __attribute__((always_inline)) uint32_t dsDigitalRead(uint8_t pin)
{
return (GPIO.in >> pin) & 0x1;
}
/* Hardware SPI is not initialized in deep sleep stub. */
uint8_t RTC_IRAM_ATTR dsSpiTransfer(uint8_t data)
{
dsDigitalWrite(MFRC_SCK, 0);
for (int i = 0; i < 8; i++) {
dsDigitalWrite(MFRC_MOSI, data & 0x80);
dsDigitalWrite(MFRC_SCK, 1);
data <<= 1;
data |= dsDigitalRead(MFRC_MISO);
dsDigitalWrite(MFRC_SCK, 0);
}
return data;
}
uint8_t RTC_IRAM_ATTR dsPCD_ReadRegister(MFRC522::PCD_Register reg)
{
dsDigitalWrite(MFRC_CS, 0);
dsSpiTransfer(0x80 | reg);
uint8_t result = dsSpiTransfer(0);
dsDigitalWrite(MFRC_CS, 1);
return result;
}
void RTC_IRAM_ATTR dsPCD_WriteRegister(MFRC522::PCD_Register reg, uint8_t value)
{
dsDigitalWrite(MFRC_CS, 0);
dsSpiTransfer(reg);
dsSpiTransfer(value);
dsDigitalWrite(MFRC_CS, 1);
}
bool RTC_IRAM_ATTR dsMFRC522_FastDetect()
{
dsPCD_WriteRegister(MFRC522::CollReg, 0);
dsPCD_WriteRegister(MFRC522::ComIrqReg, 0x7F);
dsPCD_WriteRegister(MFRC522::FIFOLevelReg, 0x80);
dsPCD_WriteRegister(MFRC522::FIFODataReg, MFRC522::PICC_CMD_REQA);
dsPCD_WriteRegister(MFRC522::BitFramingReg, 7);
dsPCD_WriteRegister(MFRC522::CommandReg, MFRC522::PCD_Transceive);
dsPCD_WriteRegister(MFRC522::BitFramingReg, 0x80 | 7);
// 50ms timeout. Much longer than required, but should not ever be used at all => does not matter.
for (uint32_t timeout = 0; timeout < 50000 / MFRC_REGISTER_READ_TIME; timeout++) {
uint8_t irq_flags = dsPCD_ReadRegister(MFRC522::ComIrqReg);
if (irq_flags & 0x30) {
// RxIrq || IdleIrq
return true;
}
if (irq_flags & 0x01) {
// TimeoutIrq
return false;
}
}
printf("Error\r\n");
return false;
}
void RTC_IRAM_ATTR dsMFRC522_FastReset()
{
dsGpioAsOutput(MFRC_CS, cs_reg);
dsGpioAsOutput(MFRC_SCK, sck_reg);
dsGpioAsOutput(MFRC_MOSI, mosi_reg);
// TODO: Set hardreset pin
// Reset & Wakeup
dsPCD_WriteRegister(MFRC522::CommandReg, MFRC522::PCD_SoftReset);
while ((dsPCD_ReadRegister(MFRC522::CommandReg) & (1 << 4))) {
// ~ 200us wake up time from power down
}
// Init timer
dsPCD_WriteRegister(MFRC522::TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds
dsPCD_WriteRegister(MFRC522::TPrescalerReg, 67); // 13.56MHz / (2 * 67 + 1) = ~100kHz => 10μs
dsPCD_WriteRegister(MFRC522::TReloadRegH, 0); // Reload timer with 30, ie 0.3ms before timeout.
dsPCD_WriteRegister(MFRC522::TReloadRegL, 30);
dsPCD_WriteRegister(MFRC522::TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting
dsPCD_WriteRegister(MFRC522::ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4)
dsPCD_WriteRegister(MFRC522::TxControlReg, 0x83); // Antenna on
}
void RTC_IRAM_ATTR dsMFRC522_SoftPowerDown()
{
dsPCD_WriteRegister(MFRC522::CommandReg, MFRC522::PCD_NoCmdChange | 0x10);
}
void RTC_IRAM_ATTR esp_wake_deep_sleep(void)
{
DEBUG_PRINT(stub_fmt_str);
dsMFRC522_FastReset();
if (dsMFRC522_FastDetect()) {
// Card detected => Wake up system
DEBUG_PRINT(wake_fmt_str);
return;
} else {
// No card => go to sleep again
dsMFRC522_SoftPowerDown();
DEBUG_PRINT(sleep_fmt_str);
#if DEBUG_PRINT_ENABLED
//Wait till uart buffer is empty
while (REG_GET_FIELD(UART_STATUS_REG(0), UART_ST_UTX_OUT)) {
}
#endif
// https://gist.github.com/igrr/54f7fbe0513ac14e1aea3fd7fbecfeab with addition of setting new wake up time
// Add a fixed time offset to the current wake up time
uint64_t current_ticks = READ_PERI_REG(RTC_CNTL_SLP_TIMER0_REG) | (static_cast<uint64_t>(READ_PERI_REG(RTC_CNTL_SLP_TIMER1_REG)) << 32);
// same as rtc_time_us_to_slowclk(sleep_time_in_us, esp_clk_slowclk_cal_get())
uint64_t sleep_time_in_ticks = (sleep_time_in_us << 19) / REG_READ(RTC_SLOW_CLK_CAL_REG);
uint64_t new_ticks = current_ticks + sleep_time_in_ticks;
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, new_ticks & UINT32_MAX);
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, new_ticks >> 32);
// Set the pointer of the wake stub function.
REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t )&esp_wake_deep_sleep);
// Go to sleep.
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_SLEEP_EN);
// A few CPU cycles may be necessary for the sleep to start...
while (true) {
;
}
// never reaches here.
}
}
// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup()
{
Serial.begin(115200);
printf("setup() started\n");
if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
printf("Found card\n");
SPI.begin(MFRC_SCK, MFRC_MISO, MFRC_MOSI); //Enable hardware SPI
if (mfrc522.PICC_ReadCardSerial()) {
Serial.print("UID tag :");
String content = "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++)
{
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
Serial.println();
//Write data out and to the myData struct
//Set values to send
myData.id = BOARD_ID;
content.toCharArray(myData.tag, 14);
Serial.println(myData.tag);
//Begin ESP NOW Setup
// Set device as a Wi-Fi Station and set channel
WiFi.mode(WIFI_STA);
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(9, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
//Init ESP-NOW
int count1 = 0;
while (esp_now_init() != ESP_OK) {
delay(5);
count1++;
}
Serial.print("Number of 5ms to initialize: ");
Serial.println(count1);
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);
printf("ESP package sendt\n");
//Register peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.encrypt = false;
//Add peer
int count2 = 0;
while (esp_now_add_peer(&peerInfo) != ESP_OK){
delay(5);
count2++;
//Serial.println("Failed to add peer");
}
Serial.print("Number of 5ms to add per: ");
Serial.println(count2);
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
int count3 = 0;
while (result != ESP_OK) {
delay(5);
count3++;
//Serial.println("Sent with success");
}
Serial.print("Number of 5ms to send and receive package: ");
Serial.println(count3);
//END OF ESP NOW
/*
else {
Serial.println("Error sending the data");
}*/
}
} else {
printf("No card present\n");
}
printf("Entering deep sleep\n");
esp_deep_sleep(sleep_time_in_us);
}
void loop()
{
}