Files
zhengxinandCursor 427336659b 补充 NAND 传输上位机并重写说明
将 NAND_Xfer.exe 纳入仓库,README 改为当前工程情况和上位机用法。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 22:00:48 +08:00
..
2026-10-13 21:54:50 +08:00
2026-10-13 21:54:50 +08:00
2026-10-13 21:54:50 +08:00
2026-10-13 21:54:50 +08:00
2026-10-13 21:54:50 +08:00
2026-10-13 21:54:50 +08:00
2026-10-13 21:54:50 +08:00
2026-10-13 21:54:50 +08:00
2026-10-13 21:54:50 +08:00

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:

.\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 <app.bin>. To restore the official app, run the same script with its existing app binary:

.\flash_app.ps1 -Port COM3 -AppBin "E:\PET\fin_1\branch_main\IntegratedV1\build\<official-app>.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.

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:

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

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/<relative-path> 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.