Read UID

Alright, let's get to the fun part and dive into some action! We'll start by writing a simple program to read the UID of the RFID tag.

mfrc522 Driver

We will be using the awesome crate "mfrc522". It is still under development. However, it has everything what we need for purposes.

USB Serial

To display the tag data, we'll use USB serial, which we covered in the last chapter. This will allow us to read from the RFID tag and display the UID on the computer.

Project from template

To set up the project, run:

cargo generate --git https://github.com/ImplFerris/pico2-template.git

When prompted, give your project a name, like "rfid-uid" and select RP-HAL as the HAL.

Then, navigate into the project folder:

cd PROJECT_NAME
# For example, if you named your project "rfid-uid":
# cd rfid-uid

Additional Crates required

Update your Cargo.toml to add these additional crate along with the existing dependencies.

#![allow(unused)]
fn main() {
usbd-serial = "0.2.2"
usb-device = "0.3.2"
heapless = "0.8.0"
mfrc522 = "0.8.0"
embedded-hal-bus = "0.2.0"
}

We have added embedded-hal-bus, which provides the necessary traits for SPI and I2C buses. This is required for interfacing the Pico with the RFID reader.

Additional imports

#![allow(unused)]
fn main() {
use hal::fugit::RateExtU32;
use core::fmt::Write;

// to prepare buffer with data before writing into USB serial
use heapless::String;

// for setting up USB Serial
use usb_device::{class_prelude::*, prelude::*};
use usbd_serial::SerialPort;

// Driver for the MFRC522
use mfrc522::{comm::blocking::spi::SpiInterface, Mfrc522};

use embedded_hal_bus::spi::ExclusiveDevice;
}

Make sure to check out the USB serial tutorial for setting up the USB serial. We won't go over the setup here to keep it simple.

Helper Function to Print UID in Hex

We'll use this helper function to convert the u8 byte array (in this case UID) into a printable hex string. You could also just use raw bytes and enable hex mode in tio(requires latest version) or minicom, but I find this approach easier. In hex mode, it prints everything in hex, including normal text.

#![allow(unused)]
fn main() {
fn print_hex_to_serial<B: UsbBus>(data: &[u8], serial: &mut SerialPort<B>) {
    let mut buff: String<64> = String::new();
    for &d in data.iter() {
        write!(buff, "{:02x} ", d).unwrap();
    }
    serial.write(buff.as_bytes()).unwrap();
}
}

Setting Up the SPI for the RFID Reader

Now, let's configure the SPI bus and the necessary pins to communicate with the RFID reader.

#![allow(unused)]
fn main() {
let spi_mosi = pins.gpio7.into_function::<hal::gpio::FunctionSpi>();
let spi_miso = pins.gpio4.into_function::<hal::gpio::FunctionSpi>();
let spi_sclk = pins.gpio6.into_function::<hal::gpio::FunctionSpi>();
let spi_bus = hal::spi::Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));
let spi_cs = pins.gpio5.into_push_pull_output();
let spi = spi_bus.init(
    &mut pac.RESETS,
    clocks.peripheral_clock.freq(),
    1_000.kHz(),
    embedded_hal::spi::MODE_0,
);
}

Getting the SpiDevice from SPI Bus

To work with the mfrc522 crate, we need an SpiDevice. Since we only have the SPI bus from RP-HAL, we'll use the embedded_hal_bus crate to get the SpiDevice from the SPI bus.

#![allow(unused)]
fn main() {
let spi = ExclusiveDevice::new(spi, spi_cs, timer).unwrap();
}

Initialize the mfrc522

#![allow(unused)]
fn main() {
let itf = SpiInterface::new(spi);
let mut rfid = Mfrc522::new(itf).init().unwrap();
}

Read the UID and Print

The main logic for reading the UID is simple. We continuously send the REQA command. If a tag is present, it send us the ATQA response. We then use this response to select the tag and retrieve the UID.

Once we have the UID, we use our helper function to print the UID bytes in hex format via USB serial.

#![allow(unused)]
fn main() {
loop {
    // to estabilish USB serial
    let _ = usb_dev.poll(&mut [&mut serial]);

    if let Ok(atqa) = rfid.reqa() {
        if let Ok(uid) = rfid.select(&atqa) {
            serial.write("\r\nUID: \r\n".as_bytes()).unwrap();
            print_hex_to_serial(uid.as_bytes(), &mut serial);
            timer.delay_ms(500);
        }
    }
}
}

Clone the existing project

You can clone (or refer) project I created and navigate to the rfid-uid folder.

git clone https://github.com/ImplFerris/pico2-rp-projects
cd pico2-projects/rfid-uid/

How to Run ?

The method to flash (run the code) on the Pico is the same as usual. However, we need to set up tio to interact with the Pico through the serial port (/dev/ttyACM0). This allows us to read data from the Pico or send data to it.

tio

Make sure you have tio installed on your system. If not, you can install it using:

apt install tio

Connecting to the Serial Port

Run the following command to connect to the Pico's serial port:

tio /dev/ttyACM0

This will open a terminal session for communicating with the Pico.

Flashing and Running the Code

Open another terminal, navigate to the project folder, and flash the code onto the Pico as usual:

cargo run

If everything is set up correctly, you should see a "Connected" message in the tio terminal.

Reading the UID

Now, bring the RFID tag near the reader. You should see the UID bytes displayed in hex format on the USB serial terminal.