Hello everyone, this post is intended to add support to one of the most popular NFC chips on the market (PN532).
On this example I will use the I.MX93 EVK as reference board and focused in I2C communication for the PN532 Chip.
Details:
I.MX93 EVK
PN532 Module (I2C, SPI, UART)
BSP Linux 6.6.36_2.1.0 (Yocto)
STEP 1 (IMAGE COMPILATION).
At first, we need to compile our image for our board (in my case I.MX93 EVK) to add the NFC layer (Details on Yocto User's Guide😞😞
$ mkdir yocto-bsp
$cd yocto-bsp
$ repo init -u https://github.com/nxp-imx/imx-manifest -b imx-linux-scarthgap -m imx-6.6.36-2.1.0.xml
$ repo sync
$DISTRO=fsl-imx-wayland MACHINE=imx93evk source imx-setup-release.sh -b imx93evk-build
Then, add the support for NFC in our local.conf file:
$ nano conf/local.conf
We will add the below lines:
CORE_IMAGE_EXTRA_INSTALL += "libnfc"
CORE_IMAGE_EXTRA_INSTALL += "libnfc-dev"
Then, we can compile the image with:
$ bitbake imx-image-full
NOTE:
libnfc is a complete coverage of low-level PN53x chipset commands written in pure and plain C for portability and speed.
libnfc-dev are the development files and headers to use in our low-level applications.
By default, the NXP BSP support the NFC pn532 driver with a tool called nfctool, but this one is very limited compared with the libnfc.
STEP 2 (DEVICE TREE MODIFICATION).
We need to add the below lines to the Device tree:
&lpi2c5
{
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&pinctrl_lpi2c5>;
pinctrl-1 = <&pinctrl_lpi2c5>;
status = "okay";
nfc@24 {
compatible = "nxp,nxpnfc"; //we can set the "nxp,pn533" driver but it will just work for the nfctool mentioned before
reg = <0x24>;
clock-frequency = <400000>;
interrupt-parent = <&gpio2>;
interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
};
};
And to the iomux section(same in device tree):
pinctrl_lpi2c5: lpi2c5grp {
fsl,pins = <
MX93_PAD_GPIO_IO22__LPI2C5_SDA 0x40000b9e
MX93_PAD_GPIO_IO23__LPI2C5_SCL 0x40000b9e
MX93_PAD_GPIO_IO18__GPIO2_IO18 0x31e
>;
};
STEP 3 (Connection with PN532 MODULE).
For this example, we must connect the Module with the I.MX93 RP Header as follows:
I.MX93 SIDE
PN532 SIDE
GND
GND
VCC
VCC
GPIO_IO22
SDA
GPIO_IO23
SCL
GPIO_IO18
IRQ
STEP 4 (BOOT BOARD AND CREATE libnfc.conf FILE).
Once when we have booted our board and selected our modified Device Tree, we should see our i2c-4 under /dev of our Linux OS:
root@imx93evk:~# ls /dev | grep i2c
i2c-0
i2c-1
i2c-2
i2c-4
And see our specific device (0x24) with the i2cdetect tool:
root@imx93evk:~# i2cdetect -y 4
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- 24 -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Now, we need to create a file called libnfc.conf under /etc/nfc/ (You can create that directory if does not exist).
This file must contain information about how the libnfc layer will communicate with the i2c device:
# Allow device auto-detection (default: true)
# Note: if this auto-detection is disabled, user has to set manually a device
# configuration using file or environment variable
allow_autoscan = false
# Allow intrusive auto-detection (default: false)
# Warning: intrusive auto-detection can seriously disturb other devices
# This option is not recommended, user should prefer to add manually his device.
allow_intrusive_scan = true
# Set log level (default: error)
# Valid log levels are (in order of verbosity): 0 (none), 1 (error), 2 (info), 3 (debug)
# Note: if you compiled with --enable-debug option, the default log level is "debug"
log_level = 2
# Manually set default device (no default)
# To set a default device, you must set both name and connstring for your device
# Note: if autoscan is enabled, default device will be the first device available in device list.
#device.name = "_PN532_SPI"
#device.connstring = "pn532_spi:/dev/spidev0.0:500000"
device.name = "_PN532_I2c"
device.connstring = "pn532_i2c:/dev/i2c-4"
As you can see, the most important line to modify is the device.connstring, that is the charged of interaction and connection between the PN53x Module and the libnfc layer. In my case is pn532_i2c:/dev/i2c-4.
Now we can use the NFC module:
root@imx93evk:~# nfc-list
nfc-list uses libnfc 1.8.0
NFC device: _PN532_I2c opened
root@imx93evk:~#
And read UID of TAGs:
root@imx93evk:~# nfc-poll
nfc-poll uses libnfc 1.8.0
NFC reader: _PN532_I2c opened
NFC device will poll during 36000 ms (20 pollings of 300 ms for 6 modulations)
ISO/IEC 14443A (106 kbps) target:
ATQA (SENS_RES): 00 44
UID (NFCID1): 04 17 b5 d2 a2 11 90
SAK (SEL_RES): 00
Waiting for card removing...nfc_initiator_target_is_present: Target Released
done.
root@imx93evk:~#
Also, attached is a little application using the NFC headers installed with libnfc-dev.
Tha application will do a poll with a 10 seconds time out. If Tag is not detected in 10 seconds, the app will close. If a tag is detected before the timeout, the app will print the UID of the NFC TAG:
OUTPUT of timeout:
root@imx93evk:~# ./nfc-app
NFC reader: _PN532_I2c opened
Waiting for an NFC tag (timeout: 10 seconds)...
No NFC tag detected within the timeout period.
root@imx93evk:~#
OUTPUT when tag is detected:
root@imx93evk:~# ./nfc-app
NFC reader: _PN532_I2c opened
Waiting for an NFC tag (timeout: 10 seconds)...
Tag detected - UID: 04:16:BC:D2:A2:11:90
root@imx93evk:~#
To compile the app just copy the attached nfc-app.c file to the i.MX93 EVK and compile using this command:
root@imx93evk:~# gcc nfc-app.c -o nfc-app -lnfc
I hope this thread can be helpful!
Best regards,
Salas.
View full article