Reputation: 1
I have:
RC522 RFID Module ESP32C3 with Micropython
I am trying to get the RC522 module connected over SPI (either hardware or SoftSPI). I haven't had any success connecting to it after trying a sketch (below) and a few variants of micropython RC522 libraries (one example below). I am seeing a lot of conflicting advice on what pins to use for SPI on the ESP32C3. Seeed studio claims SCK D8, MISO D9, and MOSI D10, while the following code would imply otherwise:
>>> spi = SPI(1)
>>> spi
SPI(id=1, baudrate=500000, polarity=0, phase=0, bits=8, firstbit=0, sck=6, mosi=7, miso=2)
Here is one variant of a sketch I have tried:
from mfrc522 import MFRC522
from machine import Pin, SoftSPI
from machine import SPI
spi = SPI(1, baudrate=500000, polarity=0, phase=0, sck=Pin(6), mosi=Pin(7), miso=Pin(2))
# To use SoftSPI,
# from machine import SOftSPI
# spi = SoftSPI(baudrate=100000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso)
spi.init()
rdr = MFRC522(spi=spi, gpioRst=4, gpioCs=5)
print("Place card")
while True:
(stat, tag_type) = rdr.request(rdr.REQIDL)
if stat == rdr.OK:
print('ok')
(stat, raw_uid) = rdr.anticoll()
if stat == rdr.OK:
card_id = "uid: 0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3])
print(card_id)
else:
print(stat)
And here is the associated mfrc522 library:
from machine import Pin, SPI
from os import uname
emptyRecv = b""
class MFRC522:
GAIN_REG = 0x26
MAX_GAIN = 0x07
OK = 0
NOTAGERR = 1
ERR = 2
REQIDL = 0x26
REQALL = 0x52
AUTHENT1A = 0x60
AUTHENT1B = 0x61
def __init__(self, spi=None, gpioRst=None, gpioCs=None):
if gpioRst is not None:
self.rst = Pin(gpioRst, Pin.OUT)
else:
self.rst = None
assert(gpioCs is not None, "Needs gpioCs") # TODO fails without cableSelect
if gpioCs is not None:
self.cs = Pin(gpioCs, Pin.OUT)
else:
self.cs = None
# TODO CH rationalise which of these are referenced, which can be identical
self.regBuf = bytearray(4)
self.blockWriteBuf = bytearray(18)
self.authBuf = bytearray(12)
self.wregBuf = bytearray(2)
self.rregBuf = bytearray(1)
self.recvBuf = bytearray(16)
self.recvMv = memoryview(self.recvBuf)
if self.rst is not None:
self.rst.value(0)
if self.cs is not None:
self.cs.value(1)
if spi is not None:
self.spi = spi
else:
sck = Pin(14, Pin.OUT)
mosi = Pin(13, Pin.OUT)
miso = Pin(12, Pin.IN)
if uname()[0] == 'WiPy':
self.spi = SPI(0)
self.spi.init(SPI.MASTER, baudrate=1000000, pins=(sck, mosi, miso))
elif uname()[0] == 'esp8266': # TODO update to match https://github.com/cefn/avatap/blob/master/python/host/cockle.py #prepareHost()
self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso)
self.spi.init()
else:
raise RuntimeError("Unsupported platform")
if self.rst is not None:
self.rst.value(1)
self.init()
def _wreg(self, reg, val):
if self.cs is not None:
self.cs.value(0)
buf = self.wregBuf
buf[0]=0xff & ((reg << 1) & 0x7e)
buf[1]=0xff & val
self.spi.write(buf)
if self.cs is not None:
self.cs.value(1)
def _rreg(self, reg):
if self.cs is not None:
self.cs.value(0)
buf = self.rregBuf
buf[0]=0xff & (((reg << 1) & 0x7e) | 0x80)
self.spi.write(buf)
val = self.spi.read(1)
if self.cs is not None:
self.cs.value(1)
return val[0]
def _sflags(self, reg, mask):
self._wreg(reg, self._rreg(reg) | mask)
def _cflags(self, reg, mask):
self._wreg(reg, self._rreg(reg) & (~mask))
def _tocard(self, cmd, send, into=None):
recv = emptyRecv
bits = irq_en = wait_irq = n = 0
stat = self.ERR
if cmd == 0x0E:
irq_en = 0x12
wait_irq = 0x10
elif cmd == 0x0C:
irq_en = 0x77
wait_irq = 0x30
self._wreg(0x02, irq_en | 0x80)
self._cflags(0x04, 0x80)
self._sflags(0x0A, 0x80)
self._wreg(0x01, 0x00)
for c in send:
self._wreg(0x09, c)
self._wreg(0x01, cmd)
if cmd == 0x0C:
self._sflags(0x0D, 0x80)
i = 2000
while True:
n = self._rreg(0x04)
i -= 1
if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)):
break
self._cflags(0x0D, 0x80)
if i:
if (self._rreg(0x06) & 0x1B) == 0x00:
stat = self.OK
if n & irq_en & 0x01:
stat = self.NOTAGERR
elif cmd == 0x0C:
n = self._rreg(0x0A)
lbits = self._rreg(0x0C) & 0x07
if lbits != 0:
bits = (n - 1) * 8 + lbits
else:
bits = n * 8
if n == 0:
n = 1
elif n > 16:
n = 16
if into is None:
recv = self.recvBuf
else:
recv = into
pos = 0
while pos < n:
recv[pos] = self._rreg(0x09)
pos += 1
if into is None:
recv = self.recvMv[:n]
else:
recv = into
else:
stat = self.ERR
return stat, recv, bits
def _assign_crc(self, data, count):
self._cflags(0x05, 0x04)
self._sflags(0x0A, 0x80)
dataPos = 0
while dataPos < count:
self._wreg(0x09, data[dataPos])
dataPos += 1
self._wreg(0x01, 0x03)
i = 0xFF
while True:
n = self._rreg(0x05)
i -= 1
if not ((i != 0) and not (n & 0x04)):
break
data[count] = self._rreg(0x22)
data[count + 1] = self._rreg(0x21)
def init(self):
self.reset()
self._wreg(0x2A, 0x8D)
self._wreg(0x2B, 0x3E)
self._wreg(0x2D, 30)
self._wreg(0x2C, 0)
self._wreg(0x15, 0x40)
self._wreg(0x11, 0x3D)
self.set_gain(self.MAX_GAIN)
self.antenna_on()
def reset(self):
self._wreg(0x01, 0x0F)
def antenna_on(self, on=True):
if on and ~(self._rreg(0x14) & 0x03):
self._sflags(0x14, 0x03)
else:
self._cflags(0x14, 0x03)
def request(self, mode):
self._wreg(0x0D, 0x07)
(stat, recv, bits) = self._tocard(0x0C, [mode])
if (stat != self.OK) | (bits != 0x10):
stat = self.ERR
return stat, bits
def anticoll(self):
ser_chk = 0
ser = [0x93, 0x20]
self._wreg(0x0D, 0x00)
(stat, recv, bits) = self._tocard(0x0C, ser)
if stat == self.OK:
if len(recv) == 5:
for i in range(4):
ser_chk = ser_chk ^ recv[i]
if ser_chk != recv[4]:
stat = self.ERR
else:
stat = self.ERR
# CH Note bytearray allocation here
return stat, bytearray(recv)
def select_tag(self, ser):
# TODO CH normalise all list manipulation to bytearray, avoid below allocation
buf = bytearray(9)
buf[0] = 0x93
buf[1] = 0x70
buf[2:7] = ser
self._assign_crc(buf, 7)
(stat, recv, bits) = self._tocard(0x0C, buf)
return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR
def auth(self, mode, addr, sect, ser):
# TODO CH void ser[:4] implicit list allocation
buf = self.authBuf
buf[0]=mode # A or B
buf[1]=addr # block
buf[2:8]=sect # key bytes
buf[8:12]=ser[:4] # 4 bytes of id
return self._tocard(0x0E, buf)[0]
# TODO this may well need to be implemented for vault to properly back out from a card session
# TODO how, why, when is 'HaltA' needed? see https://github.com/cefn/micropython-mfrc522/issues/1
def halt_a(self):
pass
def stop_crypto1(self):
self._cflags(0x08, 0x08)
def set_gain(self, gain):
assert gain <= self.MAX_GAIN
# clear bits
self._cflags(self.GAIN_REG, 0x07<< 4)
# set bits according to gain
self._sflags(self.GAIN_REG, gain << 4)
def read(self, addr, into = None):
buf = self.regBuf
buf[0]=0x30
buf[1]=addr
self._assign_crc(buf, 2)
(stat, recv, _) = self._tocard(0x0C, buf, into=into)
# TODO this logic probably wrong (should be 'into is None'?)
if into is None: # superstitiously avoid returning read buffer memoryview
# CH Note bytearray allocation here
recv = bytearray(recv)
return recv if stat == self.OK else None
def write(self, addr, data):
buf = self.regBuf
buf[0] = 0xA0
buf[1] = addr
self._assign_crc(buf, 2)
(stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR
else:
buf = self.blockWriteBuf
i = 0
while i < 16:
buf[i] = data[i] # TODO CH eliminate this, accelerate it?
i += 1
self._assign_crc(buf, 16)
(stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR
return stat
Any help would be greatly appreciated. I have tried several combinations of SPI pins, and nothing thus far has worked. I always get stat=2 for the module, which appears to be a generic error code.
Upvotes: 0
Views: 41