adafruit / Adafruit_CircuitPython_PN532

CircuitPython driver for the PN532 NFC/RFID Breakout and PN532 NFC/RFID Shield
MIT License
91 stars 47 forks source link

Example using interrupt #67

Closed samzmann closed 9 months ago

samzmann commented 9 months ago

I'm trying to use this lib with interrupts but so far I've struggled to figure it out and I haven't found any examples. I see various other issues mentioning the need for the interrupt method vs. polling, but still no solution is shown.

Could you please add an example of how to use the PN532 with interrupts, such that a function is executed when a card is detected, not detected anymore (not sure if this case is supported).

I'm especially curious how to implement this in best practice Circuitpython (use countio/keypad for interrupt?).

Thx!

samzmann commented 9 months ago

I figured it out. Below is a minimal example which demonstrates how to detect a NFC card, while at the same time blinking the onboard LED on a Raspberry Pi Pico.

I am using the I2C interface. To make the interrupt method work I had to add a wire between pin IRQ on the PN532 module and a pin on the controller (in my case board.GP17). The IRQ pin goes LOW when it detects a card, and also when it finished reading a card (get_passive_target).

Finally, I found that I had to manually call listen_for_passive_target after every read in order to "reset" the interrupt.

from adafruit_pn532.i2c import PN532_I2C
import countio
import asyncio
import digitalio
import busio
import board

i2c_0 = busio.I2C(board.GP5, board.GP4)

pn532 = PN532_I2C(
    i2c_0, 
    debug=False,
    irq=board.GP17
    )

pn532.SAM_configuration()

pn532.listen_for_passive_target()

async def catch_pn532_interrupt():
    with countio.Counter(board.GP17) as counter:
        while True:
            if counter.count == 1:
                print('interrupt fired, must read card')
                uid = pn532.get_passive_target()
                if uid is not None:
                    print("UID:", [hex(i) for i in uid])
                pn532.listen_for_passive_target()
                counter.reset()
            await asyncio.sleep(0)

async def blink():
    with digitalio.DigitalInOut(board.GP25) as led:
        led.switch_to_output()
        while True:
            led.value = not led.value
            await asyncio.sleep(1)

async def main():
    read_nfc_task = asyncio.create_task(catch_pn532_interrupt())
    blink_led_task = asyncio.create_task(blink())

    await asyncio.gather(
        read_nfc_task,
        blink_led_task
        )

asyncio.run(main())

I'm gonna close the issue because my problem is solved, but if you have any comments to help me improve I'd be happy to hear them :)