Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Luiz Brandao
Copyright (c) 2022 Luiz Brandao, Olaf van der Kruk

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
35 changes: 32 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,43 @@
MicroPython driver for PN532 NFC/RFID breakout boards. Based on the [CircuitPython driver by Adafruit](https://github.com/adafruit/Adafruit_CircuitPython_PN532).

### Compatibility
This driver has only been tested with the ESP32 using the [Grove NFC breakout board](https://wiki.seeedstudio.com/Grove_NFC/) in the default UART mode.
This driver has only been tested with the ESP32 and RP2040 using the [Grove NFC breakout board](https://wiki.seeedstudio.com/Grove_NFC/) and the cheap Aliexpress modules in the default UART mode and I2C mode.

Please let me know if you get this module successfully working with other hardware.

### Usage
You can install the package using `mpremote` with the following command:
```bash
mpremote mip install "github:olijf/micropython_pn532/pn532"
```


```python
from machine import Pin, I2C

i2c = I2C(0, scl=Pin(5), sda=Pin(4))

from i2c import PN532_I2C
pn532 = PN532_I2C(i2c, debug=True)

uid = pn532.read_passive_target(timeout=500)

if uid is None:
print("No card detected")
else:
print("Found card with UID:", [hex(i) for i in uid])
```

### Differences in the API from the CircuitPython version

- The timeout is expressed in milliseconds instead of seconds.
- The module name is different.
- Only UART is available
- _I2C and SPI are not available._
- Only UART and I2C is available
- _SPI is not available._

### TODO
- [ ] Implement SPI
- [ ] Rewrite the modules with asyncio support so we can use the library non blocking
- [ ] Determine if thread blocking is really an issue when used
- [ ] Add support for the other modes of the PN532, card emulation specifically

68 changes: 68 additions & 0 deletions pn532/i2c.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""
``pn532.i2c``
====================================================

This module will let you communicate with a PN532 RFID/NFC shield or breakout
using I2C.

* Author(s): Original Raspberry Pi code by Tony DiCola, CircuitPython by ladyada,
refactor by Carter Nelson, MicroPython by Olaf van der Kruk

"""
import time
from pn532 import PN532, BusyError


class PN532_I2C(PN532):
"""Driver for the PN532 connected over I2C"""

def __init__(self, i2c, *, reset=None, debug=False, address=0x24):
"""Create an instance of the PN532 class using I2C.
Optional reset pin and debugging output.
"""
self.debug = debug
self._i2c = i2c
self._i2c_addr = address
super().__init__(debug=debug, reset=reset)

def _wakeup(self):
"""Send any special commands/data to wake up PN532"""
if self.debug:
print("Waking up")
if self._reset_pin:
self._reset_pin.value = True
time.sleep(0.01)
self.low_power = False
#self._i2c.writeto(self._i2c_addr,
# b"\x55\x55\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
#) # wake up!
self.SAM_configuration()

def _wait_ready(self, timeout=1000):
"""Wait `timeout` milliseconds"""
status = bytearray(1)
start = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start) < timeout:
try:
self._i2c.readfrom_into(self._i2c_addr, status)
except OSError:
continue
if status == b"\x01":
return True # No longer busy
time.sleep(0.01) # lets ask again soon!
# Timed out!
return False

def _read_data(self, count):
"""Read a specified count of bytes from the PN532."""
frame = bytearray(count + 1)
self._i2c.readfrom_into(self._i2c_addr, frame)
if not frame:
raise BusyError("No data read from PN532")
if self.debug:
print("Reading: ", [hex(i) for i in frame])
return frame[1:]

def _write_data(self, framebytes):
"""Write a specified count of bytes to the PN532"""
self._i2c.writeto(self._i2c_addr, framebytes)
8 changes: 8 additions & 0 deletions pn532/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"urls": [
["pn532.py", "github:olijf/micropython_pn532/pn532/pn532.py"],
["uart.py", "github:olijf/micropython_pn532/pn532/uart.py"],
["i2c.py", "github:olijf/micropython_pn532/pn532/i2c.py"]
],
"version": "0.1"
}