# SPI NAND file transfer app This is a standalone ESP32-P4 application. The existing application and `E:\PET\fin_1\branch_main\IntegratedV1` are not modified. Its `/extflash` mount prefix and IntegratedV1's `/nandflash` prefix point to the same FAT volume on the external GD5F1GM7: `/extflash/eaf/a.eaf` corresponds to `/nandflash/eaf/a.eaf`. Neither prefix exists as a directory on the NAND. ## Build and flash (PowerShell) Use ESP-IDF 5.5.4 and the installed P4 toolchain. From this directory: ```powershell .\build_app.ps1 .\flash_app.ps1 -Port COM3 -AppBin .\build_release\nand_xfer.bin ``` `flash_app.ps1` checks the parent `partitions.csv` for `ota_0 = 0x70000, 10M`, validates the app image, and invokes **only** `esptool write_flash 0x70000 `. To restore the official app, run the same script with its existing app binary: ```powershell .\flash_app.ps1 -Port COM3 -AppBin "E:\PET\fin_1\branch_main\IntegratedV1\build\.bin" ``` Confirm which official binary to use before restoring. Neither script flashes a bootloader, partition table, `otadata`, NVS, nor any data partition. **Do not use** `idf.py flash`, `erase-flash`, or generated `flash_args` / `flasher_args.json`: IDF generates entries for partitions outside the app. The actual board must already boot `ota_0` at `0x70000` and have a compatible partition table; the script does not change the boot selection. ## Transfer Install pyserial once: `py -3 -m pip install pyserial`. Close other serial programs, including `idf.py monitor`. Use the P4 USB-Serial/JTAG COM port; baud rate is opened at 115200. After NAND initialization the device sends its capacity and mount result, followed by `NAND-XFER READY`. No text follows READY on that USB byte stream; binary requests also work if READY has already been printed when the host opens the port. ```powershell py -3 nand_put.py COM3 "C:\files\demo.eaf" "/extflash/eaf/demo.eaf" py -3 nand_put.py COM3 "C:\files\eaf" "/extflash/eaf" --recursive py -3 nand_put.py COM3 --info py -3 nand_put.py COM3 --list "/extflash/eaf" py -3 nand_put.py COM3 --verify "/extflash/eaf/demo.eaf" py -3 nand_put.py COM3 --mkdir "/extflash/empty" ``` The directory command uploads the directory *contents* under the destination and retains empty subdirectories. Completed files are closed, synced, read back and CRC-checked before reporting success. An interrupted current file may be incomplete; running the upload again overwrites it. Reconnecting cancels any unfinished open file, not previously completed files. Mounts are never automatically formatted. An unformatted NAND reports `mounted=False` and refuses file writes. Formatting requires this distinct command and a typed confirmation: ```powershell py -3 nand_put.py COM3 --format ``` **This erases all files on the NAND FAT volume.** Do not accept a Windows Explorer format prompt: its sector-size assumptions are incompatible with the NAND page-backed FAT. Formatting is done only by the device using 16KB clusters. SPI3 matches this repo's `main/FLASH/flash.h`: MOSI39, MISO41, CLK40, CS42, SIO, mode 0, 40MHz; WP and HOLD are tied high, not GPIOs. ## Validation ```powershell py -3 -m unittest -v test_nand_put.py ``` On the board: check capacity/READY, transfer a file and a nested directory, compare reported size/CRC, reset and list again, reboot without `--format`, then restore the official app at `0x70000`. Its `fopen` check through `/nandflash/` is **pending board validation**. As of October 8, 2026, IntegratedV1's `board_config.h` still contains the obsolete NAND GPIO assignments; this transfer app does not modify that firmware. A stock IntegratedV1 binary is therefore not guaranteed to mount this board's NAND. Protocol: `NXFR`, version 1, command byte, two reserved zero bytes, LE uint32 sequence and LE uint32 payload length, payload (at most 4352 bytes), then IEEE CRC32 over header and payload. Responses set command bit 7 and prefix their payload with a status byte. HELLO (11) starts a new session; INFO (1), LIST (2, LE uint16 cursor + UTF-8 path), MKDIR (3), BEGIN (4), BLOCK (5, LE uint32 offset + up to 4096 bytes), END (6, LE uint64 size + uint32 CRC), VERIFY (7), CANCEL (8), PREPARE (9), CONFIRM (10) operate in sequence. PREPARE returns a 4-byte challenge, and CONFIRM requires the challenge plus the PREPARE sequence within 30 seconds. The host requests confirmation *before* PREPARE; it never automatically retries CONFIRM.