Files
zhengxinandCursor 851e347cf5 初始提交卡包 USB 工程
纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。

Co-authored-by: Cursor <[email protected]>
2026-10-13 21:54:50 +08:00

96 lines
4.4 KiB
Markdown

# 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 <app.bin>`. 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\<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.
```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/<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.