> For the complete documentation index, see [llms.txt](https://docs.mtoolstec.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mtoolstec.com/hardware/rfid-nfc-and-uhf-hardware/grovenfc/build-and-flash-firmware.md).

# Build and Flash Firmware

Use the GroveNFC development API to customize the module's functionality, NFC processing, and host protocol. Firmware runs on the RP2040 and links against the supplied NFC static libraries.

## Obtain the Firmware Project

The [GroveNFC repository](https://github.com/NFC-funs/GroveNFC) provides product firmware, hardware information, and development packages. To customize module firmware, download the [20261001 API development package](https://github.com/NFC-funs/GroveNFC/blob/main/API/GroveNFC_API-20261001.zip). It contains the CMake project, application source, interface headers, and precompiled NFC libraries.

Cloning the repository alone does not place `CMakeLists.txt` at its root. Extract the development package and build from its `GroveNFC_API-20261001` directory.

For a command-line workflow:

```bash
mkdir -p grovenfc-development
cd grovenfc-development
curl -fL https://raw.githubusercontent.com/NFC-funs/GroveNFC/main/API/GroveNFC_API-20261001.zip -o GroveNFC_API-20261001.zip
unzip GroveNFC_API-20261001.zip
```

Keep the supplied `libNFC` directory: the NFC libraries are required for linking. Ready-to-install product firmware in the repository's `Firmware` directory is separate from the customizable API project, and may expose additional features.

## Development Environment

| Component        | Current project configuration |
| ---------------- | ----------------------------- |
| Pico SDK         | 2.3.0                         |
| C / C++          | C11 / C++17                   |
| Board target     | `pico`                        |
| ARM toolchain    | 13\_3\_Rel1                   |
| picotool         | 2.3.0                         |
| USB dependencies | TinyUSB and FatFs             |

Earlier projects use Pico SDK 2.1.0. Match the SDK and dependencies to the project you are building.

## Project Structure

| Path                   | Purpose                                                  |
| ---------------------- | -------------------------------------------------------- |
| `Pico_NFC.c`           | Initialization, dual-core loops, and tag Flash storage   |
| `4-I2C/X_I2C.h` / `.c` | Slave address, register layout, and IIC interrupts       |
| `4-I2C/X_RegPara.h`    | Mode, RF, CRC, status, and command constants             |
| `4-I2C/I2C_Function.c` | NFC operations triggered by register writes              |
| `4-I2C/X_Ver.h`        | Hardware and firmware version identifiers                |
| `2-NFC/ISO14A`         | ISO14443A selection and NTAG application logic           |
| `2-NFC/ISO14B`         | ISO14443B application logic                              |
| `2-NFC/ISO15`          | ISO15693 inventory and memory operations                 |
| `2-NFC/Felica`         | FeliCa application logic                                 |
| `libNFC`               | Hardware interface headers and precompiled NFC libraries |
| `1-USB`                | USB descriptors, MSC, CDC, and FAT12                     |
| `CMakeLists.txt`       | Pico SDK configuration and library linking               |

Core1 processes NFC operations requested through IIC. Core0 handles USB tasks and Flash storage. Keep host transactions serialized because the reference IIC implementation has one pending-command slot and a shared data buffer.

## Prepare the SDK and Build Tools

Install Git, CMake, a native build tool such as Make or Ninja, and an ARM bare-metal toolchain providing `arm-none-eabi-gcc`. Match the toolchain to the project configuration where possible. Install `curl` and `unzip` if using the download commands above.

From the `grovenfc-development` directory, obtain the matching [Raspberry Pi Pico SDK](https://github.com/raspberrypi/pico-sdk/tree/2.3.0) and its submodules:

```bash
git clone --branch 2.3.0 --depth 1 https://github.com/raspberrypi/pico-sdk.git pico-sdk
git -C pico-sdk submodule update --init --recursive
```

Submodules supply dependencies such as TinyUSB. Confirm that these paths exist before configuring:

* `pico-sdk/pico_sdk_init.cmake`
* `pico-sdk/lib/tinyusb/lib/fatfs/source/ff.c`
* `GroveNFC_API-20261001/libNFC/ISO14A/lib_ps_iso14a.a`

The FatFs path above is used directly by this project's CMake configuration. If it is absent, resolve the SDK dependency layout before building.

## Build the Firmware

With the SDK and extracted project alongside each other in `grovenfc-development`:

```bash
cd GroveNFC_API-20261001
cmake -S . -B build-local -DPICO_SDK_PATH="$(pwd)/../pico-sdk"
cmake --build build-local --parallel
```

Run these commands in the directory containing `Pico_NFC.c` and `CMakeLists.txt`. Use `build-local` rather than the distributed `build` directory, which contains an existing machine-specific CMake cache. If the SDK is installed elsewhere, replace the `PICO_SDK_PATH` value with its absolute path.

The output directory contains:

| Output                                       | Purpose                               |
| -------------------------------------------- | ------------------------------------- |
| `build-local/Pico_NFC.uf2`                   | Firmware image for UF2 installation   |
| `build-local/GroveNFC_API_YYYYMMDD_HHMM.uf2` | Timestamped copy of the UF2 image     |
| `build-local/Pico_NFC.elf`                   | Executable with debugging information |
| `build-local/Pico_NFC.bin` / `.hex`          | Additional firmware formats           |

To install the UF2, enter the board's RP2040 BOOTSEL USB mode using the procedure for your hardware revision. Copy the UF2 to the bootloader drive, usually named `RPI-RP2`. The device restarts after installation. The bootloader drive is separate from GroveNFC's normal USB tag-data storage drive.

After restarting, read the hardware and firmware version registers and run the [IIC REQA example](/hardware/rfid-nfc-and-uhf-hardware/grovenfc/iic-operation-guide.md#6-iso14443a-reqa-example) to check the custom firmware's host interface. Do not infer feature support from the filename alone.

## Build Troubleshooting

| Problem                                 | Check                                                                                                                                |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `PICO_SDK_PATH` is missing or invalid   | Point it to the SDK root containing `pico_sdk_init.cmake`                                                                            |
| `arm-none-eabi-gcc` cannot be found     | Install the ARM bare-metal toolchain and add its executable directory to PATH                                                        |
| TinyUSB / FatFs files are missing       | Initialize SDK submodules and check the exact FatFs path used by CMake                                                               |
| `lib_ps_*.a` cannot be found            | Preserve the development package's directory structure and supplied libraries                                                        |
| CMake refers to another machine's paths | Configure a fresh build directory rather than reusing the distributed cache                                                          |
| Built firmware lacks a product feature  | Check the API project's handlers and firmware compatibility table; product firmware and API firmware have different feature coverage |

## NFC Application Flows

| Protocol  | Typical flow                                                     | Application entry points                                                                          |
| --------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| ISO14443A | Wake/discover, anticollision, select, then exchange tag commands | `X_RF14443A_GetUid`, `X_RF14443A_AntiCL1`, `X_RF14443A_SelCL1`, cascade-level 2 equivalents       |
| ISO14443B | Request, assign/select, then read identification data            | `X_RF14443B_reqb`, `X_RF14443B_attrib`, `X_RF14443B_getuid`                                       |
| FeliCa    | Activate reader reception and perform polling                    | `X_Felica_req`                                                                                    |
| ISO15693  | Inventory, then addressed block operations                       | `X_15693_getuid`, `X_15693_readsingleblock`, `X_15693_writesingleblock`, `X_15693_readmultiblock` |

Initialize the system and NFC hardware, enable the RF field, initialize the protocol's PIO receiver, perform the operation, deinitialize the receiver, and disable the field. The earlier example application demonstrates these flows through `TEST_14443A`, `TEST_14443B`, `TEST_FELICA`, `TEST_15693ASK`, and `TEST_15693FSK` build switches.

The ISO14443A UID helper supports the 4-byte and 7-byte flows. Its output buffer includes cascade data and BCC bytes; allocate the buffer required by the API and extract the UID rather than presenting the entire buffer as a UID. The `X_RF14443A_Reqa` helper sends WUPA (`0x52`) internally despite its name.

ISO15693 inventory returns response metadata alongside the UID. Pass the API's response buffer to subsequent application helpers according to their declarations. Block size and count depend on tag type; use `X_15693_info` where applicable.

## Debugging and Storage

| Signal / area           | Configuration                          |
| ----------------------- | -------------------------------------- |
| Debug UART              | UART1, 921600 baud, TX GPIO4, RX GPIO5 |
| BUSY output             | GPIO19, active high                    |
| IIC                     | I2C0, SDA GPIO16, SCL GPIO17           |
| Tag RAM                 | 4096 bytes                             |
| Flash tag storage       | 64 KiB, sixteen 4 KiB slots            |
| USB file-storage region | 128 KiB, FAT12                         |

GPIO numbers identify internal signals. Confirm signal exposure against your board revision. USB MSC and internal FatFs share storage; coordinate access so that the host and firmware do not modify the same files concurrently.

## Extending the Host Interface

Implement handlers before exposing new mode values or shortcut commands. Keep register definitions and dispatch conditions consistent, enforce buffer bounds, and provide completion handling for long operations. Validate the product-facing behavior of your custom build before distributing it.

Consult the [IIC Operation Guide](/hardware/rfid-nfc-and-uhf-hardware/grovenfc/iic-operation-guide.md#8-firmware-compatibility) for reference-firmware compatibility limits. The [API Header Reference](/hardware/rfid-nfc-and-uhf-hardware/grovenfc/api-header-reference.md) provides declarations and constants for module development.
