Skip to content

dotstartech/nfc-terminal-image

Repository files navigation

NFC Terminal Image - Raspberry Pi CM4

Custom Linux image built with Buildroot for Raspberry Pi Compute Module 4, carrier board dotstartech/wall-panel and 4 inch MIPI DSI LCD panel with ST7703 controller

Demo

nfc-lvgl-app.webm

Target Hardware

  • Board: Raspberry Pi Compute Module 4 (RAM: 1GB, Storage: 8GB eMMC, WiFi/BT: None)
  • Carrier: dotstartech/wall-panel
  • Display: GX040HD-30MB-A1 (720x720 IPS LCD with ST7703 controller)
  • Touch: FocalTech FT6336U (I2C0 @ 0x48)
  • NFC: NXP PN7150 (I2C1 @ 0x28)
  • RTC: DS3231 (I2C1 @ 0x68)
  • Microphone: Adafruit I2S MEMS SPH0645LM4H

Features

  • Linux Kernel 6.12 (Raspberry Pi fork)
  • ST7703 display panel driver
  • FT6336U touchscreen support
  • PN7150 NFC with kernel driver (pn5xx_i2c) and libnfc-nci
  • DS3231 RTC support
  • I2S MEMS microphone support (Adafruit SPH0645LM4H)
  • RAUC OTA updates with A/B rootfs partition scheme
  • I2C interface enabled (I2C0 and I2C1)
  • USB Ethernet (smsc95xx for PoE backplate)

Directory Structure

nfc-terminal-image/
├── buildroot/                 # Buildroot source (submodule, 2026.02.x)
├── board/nfc-terminal/        # Board-specific files
│   ├── config.txt             # Raspberry Pi boot configuration
│   ├── cmdline.txt            # Kernel command line
│   ├── genimage.cfg           # Disk image layout (A/B partitions)
│   ├── linux.config.fragment  # Kernel config additions
│   ├── logo-mid.png           # Boot splash image
│   ├── nfc-diag.sh            # NFC diagnostics script
│   ├── overlays/              # Device tree overlays
│   │   └── nfc-pn7150.dts     # NFC PN7150 overlay
│   ├── rauc/                  # RAUC OTA update configuration
│   │   ├── system.conf        # RAUC system config (slots, bootloader)
│   │   ├── rauc-boot-handler  # Custom A/B bootloader backend script
│   │   ├── certgen.sh         # Development certificate generator
│   │   └── certs/             # Signing certificates (dev only)
│   ├── post-build.sh          # Post-build rootfs customization
│   └── post-image.sh          # Image generation script
├── configs/                   # Buildroot defconfigs
│   └── nfc_terminal_cm4_defconfig
├── docs/                      # Reference documentation
│   └── AN11697.pdf            # NXP PN7150 Linux integration guide
├── external/                  # Buildroot external tree hooks
├── package/                   # Custom Buildroot packages
│   ├── libnfc-nci/            # NFC userspace library (NXP)
│   ├── nfc-lvgl-app/          # LVGL touchscreen UI application
│   │   ├── src/               # Application source (C, LVGL, fonts)
│   │   ├── images/            # UI image assets
│   │   └── nfc-console        # Init wrapper script
│   ├── pn5xx-i2c/             # PN7150 NFC kernel driver (out-of-tree)
│   └── st7703-gx040hd/        # ST7703 MIPI DSI panel driver package
├── patches/                   # Buildroot package patches
│   └── buildroot/
│       └── 0001-paho-mqtt-c-enable-MQTT5.patch
├── .github/
│   ├── instructions/          # Copilot agent instructions
│   └── workflows/build.yml    # CI build workflow
├── build.sh                   # Main build script
├── external.desc              # External tree descriptor
├── external.mk                # External tree makefile
├── Config.in                  # External tree Kconfig
├── ROADMAP.md                 # Future development plans
├── LICENSE                    # Project license
└── README.md                  # This file

Building Image

Install build dependencies (Debian/Ubuntu):

sudo apt-get update
sudo apt-get install -y build-essential git wget cpio unzip rsync bc \
    libncurses-dev libssl-dev python3 python3-dev python3-setuptools file
  1. Clone Buildroot:
git clone https://github.com/buildroot/buildroot.git --branch 2026.02.x --depth 1
  1. Build the image:
./build.sh

This configures Buildroot with the external tree and builds everything.

  1. Build script commands:
Command Description
./build.sh Build the complete image (default, without demo app)
./build.sh build --demo-app Build the image with nfc-lvgl-app demo included
./build.sh config Apply NFC Terminal defconfig without building
./build.sh menuconfig Open Buildroot interactive configuration menu
./build.sh linux-menuconfig Open Linux kernel configuration menu
./build.sh savedefconfig Save current config back to defconfig file
./build.sh clean Remove build artifacts (keeps config)
./build.sh distclean Remove ALL build artifacts and configuration
./build.sh rebuild-kernel Rebuild only the Linux kernel
./build.sh rebuild-driver Rebuild only the ST7703 display driver
./build.sh flash /dev/sdX Flash built image to SD card or eMMC device
./build.sh rpiboot Start rpiboot for CM4 eMMC programming mode
./build.sh desktop-build Build nfc-lvgl-app for desktop (x86_64) with SDL2 for UI testing
./build.sh dist [version] Create signed RAUC bundle + version file (reads nfc-terminal.version if no version given)
  1. Output files will be in buildroot/output/images/:
    • nfc-terminal.img - Complete bootable image
    • Image - Linux kernel
    • rootfs.ext4 - Root filesystem
    • bcm2711-rpi-cm4.dtb - Device tree

Flashing Image

  1. Install boot jumpers on IO board to disable eMMC boot
  2. Connect IO board USB to host
  3. Flash using rpiboot:
sudo ./buildroot/output/host/bin/rpiboot

# Wait for eMMC to appear as mass storage, then:
# IMPORTANT: Unmount any auto-mounted partitions first!
sudo umount /dev/sdX1 /dev/sdX2 2>/dev/null || true
sudo dd if=buildroot/output/images/nfc-terminal.img of=/dev/sdX bs=4M status=progress
sync

Note: The ./build.sh flash command will automatically detect and offer to unmount any mounted partitions.

Alternatively Raspberry Pi Imager can be used to flash the image.

  1. Disconnect IO board USB from host
  2. Switch boot jumper back to eMMC boot
  3. Connect LAN cable to PoE switch

Testing with QEMU

The image can be tested in QEMU without real hardware for basic validation of boot and rootfs.

Prerequisites

Install QEMU for ARM64:

# Debian/Ubuntu
sudo apt-get install qemu-system-arm

# Fedora
sudo dnf install qemu-system-aarch64

Running

./qemu-run.sh

Press Ctrl-A X to exit QEMU.

How It Works

QEMU doesn't have Raspberry Pi 4/CM4 machine emulation, so the script uses the generic ARM64 virt machine with a Cortex-A72 CPU. It performs direct kernel boot with the rootfs mounted as a virtio block device.

What works in QEMU:

  • Kernel boot and init system
  • Network via user-mode networking (SSH available on localhost:2222)
  • Basic userspace and shell access

What doesn't work (requires real hardware):

  • NFC (/dev/pn544 won't exist - nfc-console will timeout after 30s)
  • Display (ST7703) and touch
  • I2C, GPIO, and other Pi-specific peripherals

SSH into the QEMU instance:

ssh -p 2222 root@localhost
# Password: nfc-terminal

Configuration

Key display, I2C, I2S and peripheral settings in /boot/config.txt:

# I2C
dtparam=i2c_arm=on    # I2C1 (GPIO 2/3) - RTC, NFC
dtparam=i2c_vc=on     # I2C0 (GPIO 0/1) - Touch controller

# I2S
dtparam=i2s=on

# Display
dtoverlay=vc4-kms-v3d
dtoverlay=st7703-gx040hd
dtoverlay=ft6336u-gx040hd

# DS3231 RTC on I2C1
dtoverlay=i2c-rtc,ds3231

# PN7150 NFC on I2C1 with kernel driver
dtoverlay=nfc-pn7150

# SPH0645LM4H mic uses the Google VoiceHAT soundcard driver via I2S
dtoverlay=googlevoicehat-soundcard

I2C Bus Usage

Bus Address Device Driver
I2C0 (i2c_vc) 0x48 FT6336U Touch Controller edt_ft5x06
I2C1 (i2c_arm) 0x28 PN7150 NFC Controller pn5xx_i2c
I2C1 (i2c_arm) 0x68 DS3231 RTC rtc-ds1307
  • I2C0 (GPIO 0/1): Reserved for DSI display peripherals (touch controller)
  • I2C1 (GPIO 2/3): General peripherals (RTC, NFC, user devices)

NFC Architecture

The NFC subsystem uses NXP's PN7150 chip interfaced via I2C, with kernel-level GPIO control as recommended by NXP's Linux integration guide (AN11697, sections 3.1 and 4.2).

Software Stack

┌─────────────────────────────────────────────┐
│           nfcDemoApp (poll mode)            │  User Application
├─────────────────────────────────────────────┤
│              libnfc-nci (R2.4)              │  NFC Middleware
│        (dotstartech/linux_libnfc-nci)       │
├─────────────────────────────────────────────┤
│         /dev/pn544 (char device)            │  Device Node
├─────────────────────────────────────────────┤
│           pn5xx_i2c.ko (kernel)             │  Kernel Driver
│      (GPIO control, I2C communication)      │
├─────────────────────────────────────────────┤
│    i2c1 @ 0x28    │    GPIO5 (INT)          │  Hardware
│                   │    GPIO6 (VEN)          │
├───────────────────┴─────────────────────────┤
│              NXP PN7150 Chip                │
└─────────────────────────────────────────────┘

Key design choice: The --enable-alt flag for libnfc-nci (userspace GPIO control via sysfs) does not work on modern kernels/CM4 because the GPIO sysfs interface fails for GPIOs managed by pinctrl. The kernel driver approach handles GPIO control internally, which is more reliable.

pn5xx Kernel Driver (Kernel 6.x Patches)

The pn5xx_i2c driver from NXP required several modifications to compile on Linux kernel 6.x:

Original Code Fixed Code Reason
pr_warning(...) pr_warn(...) pr_warning removed in kernel 5.x
no_llseek noop_llseek no_llseek removed in kernel 6.x
of_get_named_gpio_flags(node, name, 0, &flags) of_get_named_gpio(node, name, 0) API simplified, flags parameter removed
static int pn54x_probe(struct i2c_client *client, const struct i2c_device_id *id) static int pn54x_probe(struct i2c_client *client) i2c_device_id parameter removed in 6.3+
static int pn54x_remove(...) static void pn54x_remove(...) Return type changed to void in 6.1+

The patched source is located at package/pn5xx-i2c/pn5xx_i2c.c.

Device Tree Overlay

The NFC overlay (board/nfc-terminal/overlays/nfc-pn7150.dts) configures:

pn7150@28 {
    compatible = "nxp,pn547";       // Driver compatible string
    reg = <0x28>;                   // I2C address
    interrupt-gpios = <&gpio 5 0>;  // GPIO5 for data-ready interrupt
    enable-gpios = <&gpio 6 0>;     // GPIO6 for chip enable (VEN)
    interrupts = <5 1>;             // GPIO5, rising edge trigger
};

GPIO pin functions:

  • GPIO5 (BCM): Interrupt - signals when NFC data is ready to read
  • GPIO6 (BCM): Enable (VEN) - powers on/off the NFC chip

Autostart

The nfcDemoApp poll command starts automatically at boot via the init script /etc/init.d/S95nfc. The script:

  1. Waits for /dev/pn544 device node (up to 15 seconds)
  2. Sets appropriate permissions on the device
  3. Launches nfcDemoApp poll in background

Logs are written to /var/log/nfc.log.

Touch Integration (FT6336U)

The touchscreen uses a FocalTech FT6336U controller connected via I2C0 at address 0x48. The kernel driver edt_ft5x06 handles the hardware, exposing touch events through the Linux input subsystem.

Hardware Configuration

Parameter Value
Controller FocalTech FT6336U
I2C Bus I2C0 (i2c_vc)
I2C Address 0x48
Interrupt GPIO GPIO25 (falling edge)
Reset GPIO GPIO24 (active-low)
Kernel Driver edt_ft5x06
Input Device /dev/input/event4

Device Tree Overlay

The touch overlay (ft6336u-gx040hd.dtbo) configures:

  • I2C address and compatible string (focaltech,ft6236)
  • Interrupt on GPIO25, falling edge trigger
  • Reset control on GPIO24

LVGL Application Integration

Key implementation details for integrating with LVGL v9.x:

  1. Input Device Setup: Open /dev/input/event4 with O_RDONLY | O_NONBLOCK

  2. Multitouch Protocol B: The FT6336U uses Linux MT Protocol B with slots:

    • ABS_MT_POSITION_X / ABS_MT_POSITION_Y for coordinates
    • ABS_MT_TRACKING_ID >= 0 indicates touch down, -1 indicates touch up
    • Also sends BTN_TOUCH key events
  3. Coordinate Scaling: Query touch range using EVIOCGABS(ABS_MT_POSITION_X/Y) and scale to display resolution (720x720)

  4. Display Refresh: After UI changes from touch events, call:

    • lv_obj_invalidate(obj) to mark objects for redraw
    • lv_refr_now(display) to force immediate refresh

Touch Event Flow

FT6336U Hardware
      │ (I2C0)
      ▼
edt_ft5x06 Kernel Driver
      │ (GPIO25 interrupt)
      ▼
Input Subsystem (/dev/input/event4)
      │ (read() with O_NONBLOCK)
      ▼
LVGL touch_read_cb()
      │ (parse EV_ABS events)
      ▼
LVGL Input Device (LV_INDEV_TYPE_POINTER)
      │
      ▼
LVGL Event System (LV_EVENT_CLICKED, etc.)

MQTT Client

The nfc-lvgl-app uses the Eclipse Paho C MQTT library with asynchronous operation and automatic reconnection.

Configuration

Parameter Value
Broker mqbase.io
Client ID nfc-term-/
Protocol MQTT 5.0 (async)
QoS 2
Auto-Reconnect Enabled (1-60s backoff)

Topics

Topic Description Retained
data/<MAC>/nfc NFC tag events (tagId, type) No
data/<MAC>/state Device state (on/off) Yes

The <MAC> is the device's eth0 MAC address without colons (e.g., DCDCA284B7C8).

Last Will and Testament (LWT)

On connection, the client registers an LWT message:

  • Topic: data/<MAC>/state
  • Payload: {"state":"off"}
  • Retained: Yes

This ensures the broker publishes the offline state if the device disconnects unexpectedly.

Auto-Reconnect Behavior

The async MQTT client automatically handles reconnection:

  • Min retry interval: 1 second
  • Max retry interval: 60 seconds
  • Backoff: Exponential between min and max
  • Reconnection trigger: Automatic on connection loss (no manual intervention required)

When connection is restored, the client automatically publishes {"state":"on"} to the state topic.

I2S MEMS Microphone (Adafruit SPH0645LM4H)

The image supports the Adafruit I2S MEMS Microphone Breakout using the Google VoiceHAT soundcard driver.

Driver Stack

  • Device tree overlay: googlevoicehat-soundcard (enables I2S and registers ASoC card)
  • Kernel modules: snd-soc-bcm2835-i2s (I2S controller), snd-soc-googlevoicehat-codec (codec driver), snd-soc-rpi-simple-soundcard (machine driver)
  • config.txt: dtparam=i2s=on and dtoverlay=googlevoicehat-soundcard
  • Sample rate: Fixed at 48 kHz

Recording

The microphone captures audio at 24 kHz / 16-bit mono WAV (~2.9 MB/min, a 4× reduction vs. the native 48 kHz / 32-bit format). Recording starts automatically when roles are checked in and stops when all roles go idle. Files are named <TAGID>-YYYYMMDDTHHMMSS.wav (e.g. 04a23b1c2d3e4f-20260310T143022.wav) and saved to /tmp/.

Record manually from the command line:

arecord -D dmic -c1 -r 24000 -f S16_LE -t wav -V mono -v recording.wav

OTA Updates (RAUC)

The image uses RAUC for robust over-the-air (OTA) updates with an A/B partition scheme. Updates are atomic — the system either boots the new version or automatically stays on the old one.

Partition Layout

┌────────────┬────────────┬────────────┬────────────┐
│    boot    │  rootfs_a  │  rootfs_b  │    data    │
│   (FAT32)  │   (ext4)   │   (ext4)   │   (ext4)   │
│    64 MB   │   96 MB    │   96 MB    │   16 MB    │
│  /dev/     │  /dev/     │  /dev/     │  /dev/     │
│  mmcblk0p1 │  mmcblk0p2 │  mmcblk0p3 │  mmcblk0p4 │
├────────────┼────────────┼────────────┼────────────┤
│  Active    │  Slot A    │  Slot B    │  Persistent│
│  kernel,   │  rootfs +  │  rootfs +  │  state,    │
│  DTBs,     │  kernel,   │  kernel,   │  rauc.     │
│  overlays, │  DTBs,     │  DTBs,     │  status,   │
│  firmware, │  overlays  │  overlays  │  ota-url.  │
│  boot.ini, │  (factory  │  (empty    │  conf      │
│  cmdline   │   image)   │  initially)│            │
└────────────┴────────────┴────────────┴────────────┘
  • boot: Shared boot partition with firmware (start4.elf, fixup4.dat), boot state (boot.ini, cmdline.txt), and a copy of the active slot's kernel, DTB, and overlays. The boot partition is 64 MB to accommodate the kernel image (~22 MB) plus a temporary copy during RAUC updates.
  • rootfs_a / rootfs_b: A/B root filesystem slots. Each slot contains the complete rootfs plus the kernel (/boot/Image), device tree (/boot/bcm2711-rpi-cm4.dtb), and overlays (/boot/overlays/). This makes RAUC bundles fully self-contained — a single rootfs update carries the matching kernel. The factory image populates slot A; slot B is left empty for the first OTA update.
  • data: Persistent partition mounted at /data, stores rauc.status, ota-url.conf, and survives updates.

How A/B Updates Work

  1. The RPi CM4 firmware reads cmdline.txt from the boot partition at power-on — this selects which rootfs partition to mount via the root= parameter.
  2. RAUC detects the currently booted slot by reading rauc.slot=A|B from /proc/cmdline.
  3. When an update bundle is installed, RAUC writes the new rootfs image to the inactive slot.
  4. RAUC calls the custom boot handler (rauc-boot-handler) to set the new slot as primary — this rewrites cmdline.txt to point to the new partition and syncs the kernel (Image), device tree (bcm2711-rpi-cm4.dtb), and overlays from the new slot's /boot/ directory to the shared boot partition.
  5. On reboot, the firmware boots into the updated slot with the matching kernel and device trees.
  6. An init script (S99rauc) calls rauc status mark-good after a successful boot, confirming the update.

Since the RPi CM4 uses the Raspberry Pi firmware bootloader (not U-Boot or Barebox), a custom bootloader backend script manages slot selection by rewriting cmdline.txt and tracking state in boot.ini on the FAT boot partition.

System Configuration

RAUC system config is at /etc/rauc/system.conf on the target:

[system]
compatible=nfc-terminal-cm4
bootloader=custom
statusfile=/data/rauc.status
bundle-formats=-plain
max-bundle-download-size=100663296

[keyring]
path=/etc/rauc/ca.cert.pem

[handlers]
bootloader-custom-backend=/usr/lib/rauc/rauc-boot-handler

[slot.rootfs.0]
device=/dev/mmcblk0p2
type=ext4
bootname=A

[slot.rootfs.1]
device=/dev/mmcblk0p3
type=ext4
bootname=B

Key settings:

  • compatible: Bundles must match nfc-terminal-cm4 or they are rejected
  • bundle-formats=-plain: Only verity-signed bundles accepted (plain format disabled for security)
  • bootloader=custom: Uses the shell script backend at /usr/lib/rauc/rauc-boot-handler

Certificate Management

RAUC uses X.509 certificates for bundle verification. The target device has a CA certificate (keyring) installed at /etc/rauc/ca.cert.pem, and only bundles signed with a certificate chaining to this CA are accepted.

Development Certificates

Generate development certificates for testing:

cd board/nfc-terminal/rauc
./certgen.sh

This creates board/nfc-terminal/rauc/certs/:

  • ca.key.pem / ca.cert.pem — Certificate Authority (keyring)
  • signing.key.pem / signing.cert.pem — Bundle signing key/cert

Security: The certs/ directory is gitignored. Never commit private keys. For production, use a proper PKI with an HSM or secure key storage.

Production Certificates

For production deployments:

  1. Generate a production CA with a strong key stored in an HSM
  2. Create separate signing certificates per release channel
  3. Replace board/nfc-terminal/rauc/certs/ca.cert.pem with your production CA certificate before building the image
  4. Keep signing keys on a secure build server only

Creating Update Bundles

Update bundles are SquashFS images containing the new rootfs, signed with the signing certificate.

1. Build the image

./build.sh

2. Create a RAUC bundle manifest

Create a temporary directory with the manifest and rootfs:

mkdir -p /tmp/rauc-bundle
cat > /tmp/rauc-bundle/manifest.raucm << 'EOF'
[update]
compatible=nfc-terminal-cm4
version=1.0.0

[bundle]
format=verity

[image.rootfs]
filename=rootfs.ext4
type=ext4
EOF

cp buildroot/output/images/rootfs.ext4 /tmp/rauc-bundle/

3. Sign and create the bundle

buildroot/output/host/bin/rauc bundle \
    --cert=board/nfc-terminal/rauc/certs/signing.cert.pem \
    --key=board/nfc-terminal/rauc/certs/signing.key.pem \
    /tmp/rauc-bundle \
    buildroot/output/images/nfc-terminal.raucb

4. Verify the bundle (optional)

buildroot/output/host/bin/rauc info \
    --keyring=board/nfc-terminal/rauc/certs/ca.cert.pem \
    buildroot/output/images/nfc-terminal.raucb

Installing Updates

Local Update via SSH

Copy the bundle to the device and install:

# Copy bundle to device
scp buildroot/output/images/nfc-terminal.raucb root@<device-ip>:/tmp/

# SSH into device and install
ssh root@<device-ip>
rauc install /tmp/nfc-terminal.raucb

# Reboot to activate the update
reboot

Network Update via HTTP(S)

Host the bundle on an HTTP server and install directly from the URL:

# On the build host — serve bundles
cd buildroot/output/images
python3 -m http.server 8080

# On the device — install from network
rauc install http://<host-ip>:8080/nfc-terminal.raucb

For production, use an HTTPS server with a proper TLS certificate.

Checking Update Status

# Show full slot status
rauc status

# Example output:
# === System Info ===
# Compatible:  nfc-terminal-cm4
# Booted from: rootfs.0 (A)
#
# === Slot Status ===
# o [rootfs.0] (/dev/mmcblk0p2, ext4, booted)
#     bootname: A
#     boot status: good
# o [rootfs.1] (/dev/mmcblk0p3, ext4, inactive)
#     bootname: B
#     boot status: bad

# Show only the booted slot
rauc status --detailed

# Mark current slot as good (done automatically by S99rauc init script)
rauc status mark-good

# Mark current slot as bad (triggers rollback on next reboot)
rauc status mark-bad

Testing the Full Update Cycle

Test 1: First OTA Update (populates slot B)

# 1. Flash the factory image to eMMC
# 2. Boot the device — it starts on slot A

# On device:
rauc status
# → Booted from rootfs.0 (A), rootfs.1 (B) is inactive/bad

# 3. Make a change to the rootfs (e.g., bump version) and create a new bundle
# 4. Install the update
rauc install /tmp/nfc-terminal.raucb
# → RAUC writes to slot B, sets B as primary

# 5. Reboot
reboot
# → Device boots from slot B

# 6. Verify
rauc status
# → Booted from rootfs.1 (B), rootfs.0 (A) is still good

Test 2: Rollback (mark current slot bad)

# On device (booted from slot B):
rauc status mark-bad
reboot
# → Device boots back to slot A (the last known-good slot)

Test 3: Verify boot state persistence

# Check boot state file on the boot partition
cat /boot/boot.ini
# → Shows PRIMARY, A_OK, A_ATTEMPTS, B_OK, B_ATTEMPTS

# Check kernel command line
cat /proc/cmdline
# → Shows root=/dev/mmcblk0p2 or p3, and rauc.slot=A or B

RAUC OTA Troubleshooting

Bundle installation fails with "incompatible"

The bundle's compatible field must exactly match the system config. Check:

rauc info /tmp/update.raucb   # on host or device
cat /etc/rauc/system.conf     # on device

Bundle rejected with signature error

The bundle must be signed with a certificate that chains to the CA keyring on the device:

# Verify the keyring matches
openssl x509 -in /etc/rauc/ca.cert.pem -noout -subject
# Compare with the CA used to sign the bundle

Boot handler errors

Check that the boot handler is executable and functional:

# Test handler commands manually
/usr/lib/rauc/rauc-boot-handler get-current    # Should print A or B
/usr/lib/rauc/rauc-boot-handler get-primary     # Should print A or B
/usr/lib/rauc/rauc-boot-handler get-state A     # Should print good or bad

# Check boot partition is mounted
mountpoint /boot

# Check boot state
cat /boot/boot.ini

Device stuck on wrong slot

Manually fix the boot state:

# Mount boot partition if needed
mount -t vfat /dev/mmcblk0p1 /boot

# Manually set primary slot to A
/usr/lib/rauc/rauc-boot-handler set-primary A

# Verify cmdline.txt was updated
cat /boot/cmdline.txt
# → root=/dev/mmcblk0p2 ... rauc.slot=A

reboot

Checking available space

# Check rootfs usage (must fit in 64MB)
df -h /

# Check data partition
df -h /data

Credentials

  • Username: root
  • Password: nfc-terminal

Customization

Adding Packages

Edit configs/nfc_terminal_cm4_defconfig or use make menuconfig.

Kernel Configuration

Modify board/nfc-terminal/linux.config.fragment for kernel options.

Boot Configuration

Edit board/nfc-terminal/config.txt for Raspberry Pi boot parameters.

Troubleshooting

Display not working

# Check kernel messages
dmesg | grep -E "(st7703|dsi|panel|vc4)"

# Verify overlays in device tree
ls /proc/device-tree/soc/dsi@*/

Touch not responding

# Check I2C devices
i2cdetect -y 0    # Should show 0x48

# Check touch input device exists
ls -la /dev/input/event*

# Read raw touch events (hex dump)
cat /dev/input/event0 | hexdump -C

I2C Issues

# List I2C buses
ls /dev/i2c-*

# Scan for devices
i2cdetect -y 1

NFC Issues

# Check if kernel module loaded
lsmod | grep pn5xx

# Verify device node exists
ls -la /dev/pn544

# Check kernel messages for NFC driver
dmesg | grep -i "pn54x\|nfc"

# View autostart log
cat /var/log/nfc.log

# Verify NFC chip on I2C bus (should show 28)
i2cdetect -y 1

# Manually test NFC polling
/etc/init.d/S95nfc stop
nfcDemoApp poll

# Check GPIO status in sysfs
cat /sys/kernel/debug/gpio | grep -E "gpio-5|gpio-6"

References

About

Buildroot external tree for Raspberry Pi CM4-based NFC terminal with ST7703 720x720 display, FT6336U touch, DS3231 RTC, and PN7150 NFC

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors