Skip to content

esp32s3_zx3d50ce02s_usrc_4832_factory_app_flash_tools

esp32s3_zx3d50ce02s_usrc_4832_factory_app_flash_tools

Section titled “esp32s3_zx3d50ce02s_usrc_4832_factory_app_flash_tools”

This module provides the host-side Python flash tools for the ESP32-S3 ZX3D50CE02S USRC 4832 board’s factory provisioning and recovery workflow. It contains two scripts that run on a development or production PC and communicate with the target device over USB-UART to write firmware images directly to ESP32-S3 flash memory using esptool.

The tools support three distinct deployment scenarios:

ScenarioScriptDescription
First-time provisioningflash_all.py --recoveryWrites bootloader + partition table + factory recovery app
Complete flashflash_all.py --fullWrites all partitions + main firmware in one operation
Firmware update (dev)flash_all.py --fwWrites only the main firmware binary to app0
Factory re-flashflash_factory.pyRestores the factory recovery partition only

These tools are the production entry point — they are the first programs run on a new board or whenever recovery is needed. They work in conjunction with the factory recovery app documented in esp32s3_zx3d50ce02s_usrc_4832_factory_app_recovery.md, which provides the on-device SD-card update workflow that these scripts initially install.


Module Position in the Factory App Hierarchy

Section titled “Module Position in the Factory App Hierarchy”

This module is a leaf child of the full factory app module family for this board.

esp32s3_zx3d50ce02s_usrc_4832_factory_app

(parent)

esp32s3_zx3d50ce02s_usrc_4832_factory_app_display

ST7796 i80 driver + GFX layer

esp32s3_zx3d50ce02s_usrc_4832_factory_app_input

Buttons, Encoder, Touch

esp32s3_zx3d50ce02s_usrc_4832_factory_app_recovery

Recovery menu, SD update, OTA management

esp32s3_zx3d50ce02s_usrc_4832_factory_app_flash_tools

Host-side flash scripts - THIS MODULE

The flash tools are the deployment mechanism for everything the other sibling modules produce. The compiled binaries from the display, input, and recovery sub-modules are bundled into factory.bin and written to the device by these scripts.


boards/esp32s3_zx3d50ce02s_usrc_4832/Factory/tools/
├── flash_all.py # Multi-mode flash: recovery / full / firmware-only
├── flash_factory.py # Single-purpose: re-flash factory partition only
└── installer/ # Pre-built binaries (populated by build pipeline)
├── bootloader.bin
├── partitions.bin
└── factory.bin

installer/ directory: This directory is not committed to the repository. It is populated by the build pipeline (see esp32s3_zx3d50ce02s_usrc_4832_build.md) before the flash tools are invoked.


The scripts write to fixed addresses that must align with the partition table built into partitions.bin. The layout targets 8 MB flash:

ESP32-S3 Flash (8 MB total)

0x0000 - 0x0FFF (4 KB) ROM / Reserved

0x1000 - 0xBFFF (44 KB) Secondary Bootloader ← bootloader.bin

0xC000 - 0x1FFFF (80 KB) Partition Table + OTA Data ← partitions.bin

0x20000 - 0x65FFFF (~6 MB) app0 main firmware ← firmware.bin

0x660000 - 0x76FFFF (~1 MB) Flash FS / LittleFS

0x770000 - 0x7FFFFF (~576 KB) Factory Recovery App ← factory.bin (offset auto-detected)

ConstantValueTarget
BOOTLOADER_OFFSET0x1000Secondary bootloader
PARTITIONS_OFFSET0xC000Partition table (44 KB above bootloader)
APP0_OFFSET0x20000Main application (app0 OTA slot)
Factory offsetAuto-detected from CSVFactory recovery partition (default 0x7A0000 for 8 MB)

The factory partition offset is not hardcoded — both scripts parse the project’s partitions*.csv file at runtime to locate the correct address, making the tools robust to layout changes across board variants.


parse args

no --port

--recovery or --full

validate each binary

assemble file list

execute

success

CalledProcessError

FileNotFoundError

main()

argparse

--recovery / --full / --fw

--port / --baud / --fw-file

find_esp32_port()

Auto-detect via

serial.tools.list_ports

find_factory_offset()

Parse partitions*.csv

for factory subtype

check_file(path, name)

Assert exists + print size

Build list of

(offset, path) pairs

based on selected mode

flash(port, baud, files)

Invoke esptool via subprocess

Print success + exit 0

Print error + exit 1

esptool not installed

print pip install hint + exit

No

Yes

No

Yes

--recovery

--full

--fw FILE

No

Yes

success

error

Start flash_all.py

Parse CLI arguments

--port

specified?

find_esp32_port

auto-detect USB-UART

Use specified port

Port found?

exit 1 - No port detected

Mode?

Load:

bootloader.bin

partitions.bin

factory.bin

Load:

bootloader.bin

partitions.bin

factory.bin

firmware.bin

Load:

firmware.bin only

find_factory_offset

parse partitions*.csv

check_file each binary

All files

exist?

exit 1 - missing file

flash()

esptool write_flash

offset binary ...

esptool

result?

Flash successful - exit 0

exit 1 - flash failed

The flash() function constructs and runs the following effective command:

Terminal window
python -m esptool \
--chip esp32 \
--port <port> \
--baud 460800 \
--before default_reset \
--after hard_reset \
write_flash \
<offset1> <binary1> [<offset2> <binary2> ...]

⚠️ Chip argument note: flash_all.py passes --chip esp32. For an ESP32-S3 target, --chip esp32s3 is the strictly correct value. Modern esptool versions auto-detect the chip regardless of this flag, but passing esp32s3 explicitly is preferred for strict correctness. flash_factory.py omits --chip entirely and relies on esptool auto-detection.


flash_factory.py — Factory Partition Re-Flash Tool

Section titled “flash_factory.py — Factory Partition Re-Flash Tool”

A simpler, single-purpose script for restoring only the factory recovery partition. Useful when the recovery app is corrupted or needs updating without re-provisioning the entire device.

parse args

validate binary

no --offset

no --port

execute

main()

argparse

--port / --bin / --baud / --offset

os.path.isfile(args.bin)

check installer/factory.bin

find_factory_offset()

Search multiple CSV patterns

find_esp32_port()

Auto-detect port

subprocess.run esptool

write_flash offset factory.bin

Search patterns:

partitions*.csv

boards/*/partitions*.csv

boards/*/*/partitions*.csv

Parse CSV lines

Find subtype == 'factory'

Return offset string

Featureflash_all.pyflash_factory.py
Modes--recovery / --full / --fwSingle mode (factory only)
Chip flag--chip esp32 (hardcoded)None (esptool auto-detects)
Reset sequence--before default_reset --after hard_resetNot specified (esptool defaults)
Manual offsetNot supported--offset override supported
CSV search depth2-level glob3-level glob (wider search)
Multiple filesSupports N offset+binary pairsSingle file only
Fallback offsetReturns 0x7A0000Returns None → exits with error

Both scripts share the same find_esp32_port() logic for discovering the device’s serial port:

CP210x

CH340

CH910x

FTDI

USB Serial

USB-SERIAL

No keyword match

No

Yes

serial.tools.list_ports

.comports()

Scan each port

description + manufacturer

Matches any

keyword?

Return port.device

Return first

available port

Any port

available?

Return None - exit 1

The keyword list covers the most common USB-to-UART bridge chips found on ESP32 development boards. Matching is case-insensitive and applied against the concatenation of port.description and port.manufacturer.


Both scripts parse CSV partition tables at runtime to determine the factory partition’s flash address. The CSV format follows ESP-IDF’s standard partition table schema:

# Name, Type, SubType, Offset, Size, Flags
factory, app, factory, 0x7A0000, 0x60000,

The parser skips comment lines (#) and blank lines, splits on commas, and matches on SubType == "factory" (case-insensitive). If no CSV is found, flash_all.py falls back to 0x7A0000 (the default for the 8 MB flash layout). flash_factory.py has no fallback and exits with an error, requiring --offset to be supplied manually in that case.

Yes

No

No

Yes

Exhausted

glob(pattern)

Iterate matching

CSV files

Read each line

Comment '#'

or empty?

Split by comma

parts[0..n]

parts[2] ==

'factory'?

Return parts[3]

(offset string)

Found offset

flash_all.py: return '0x7A0000'

flash_factory.py: return None - exit


pip install

pip install

stdlib

USB-UART

reads

reads

flash_all.py

flash_factory.py

esptool

Espressif flash utility

pyserial

serial.tools.list_ports

argparse · glob · os

sys · subprocess · csv

ESP32-S3

Target Device

partitions*.csv

partition table layout

installer/

bootloader.bin

partitions.bin

factory.bin

Install runtime requirements:

Terminal window
pip install esptool pyserial

Both packages must be available in the Python environment used to run the scripts. esptool is invoked as a Python module (python -m esptool) rather than as a bare shell command, ensuring the version from the active virtual environment is always used.


Terminal window
# First-time board provisioning (recovery mode)
python flash_all.py --recovery
# Provisioning with an explicit port
python flash_all.py --recovery --port COM3 # Windows
python flash_all.py --recovery --port /dev/ttyUSB0 # Linux/macOS
# Full flash: recovery partitions + main firmware in one pass
python flash_all.py --full --fw path/to/firmware.bin
python flash_all.py --full --fw-file path/to/firmware.bin # alternate flag
# Development: update main firmware only (leaves factory app intact)
python flash_all.py --fw path/to/firmware.bin
# Custom baud rate
python flash_all.py --recovery --port /dev/ttyUSB0 --baud 115200
Terminal window
# Auto-detect port and offset from CSV
python flash_factory.py
# Specify port only
python flash_factory.py --port COM3
# Custom binary path
python flash_factory.py --port /dev/ttyUSB0 --bin my_factory.bin
# Manual offset override (skip CSV parsing)
python flash_factory.py --offset 0x7A0000
# Custom baud rate
python flash_factory.py --port COM3 --baud 115200

flash_all.py

ArgumentDefaultDescription
--recovery—Mode: flash bootloader + partitions + factory
--full—Mode: flash everything including firmware
--fw FILE / --firmware FILE—Mode: flash firmware to app0 only
--fw-file FILE—Firmware binary path (companion to --full)
--port / -pauto-detectSerial port
--baud460800Baud rate

flash_factory.py

ArgumentDefaultDescription
--port / -pauto-detectSerial port
--bin / -binstaller/factory.binFactory binary path
--baud460800Baud rate
--offset / -oauto-detect from CSVFlash offset for factory partition

The following sequence diagram shows how the flash tools fit into the end-to-end provisioning sequence for a new board:

SPI FlashESP32-S3 Deviceflash_all.pyDevelopment PCSPI FlashESP32-S3 Deviceflash_all.pyDevelopment PCBuild pipeline produces:bootloader.bin, partitions.bin,factory.bin → installer/On-screen menu available:SD update, OTA boot selectionLater: deploy main firmwarepython flash_all.py --recoveryfind_esp32_port() - auto-detectfind_factory_offset() - parse CSVcheck_file() × 3 - validate binariesesptool --before default_reset (enter download mode)write 0x1000 ← bootloader.binwrite 0xC000 ← partitions.binwrite 0x7A0000 ← factory.bin--after hard_reset (boot into factory app)Boot → factory recovery app startspython flash_all.py --fw firmware.binwrite 0x20000 ← firmware.binhard_reset → boots main firmware

This module follows an identical pattern used across all boards in the project. The same two-script structure (flash_all.py + flash_factory.py) appears in:

Board-specific differences are limited to the partition layout (CSV) and the resulting factory partition offset — the script logic is otherwise identical across all boards. Any fixes or enhancements to the flash tool pattern should be applied consistently across all boards.


DocumentRelationship
esp32s3_zx3d50ce02s_usrc_4832_factory_app.mdParent module — full factory app overview
esp32s3_zx3d50ce02s_usrc_4832_factory_app_recovery.mdThe factory app binary that these scripts install
esp32s3_zx3d50ce02s_usrc_4832_factory_app_display.mdST7796 i80 display driver used inside the factory app
esp32s3_zx3d50ce02s_usrc_4832_factory_app_input.mdButton, encoder, and touch input used inside the factory app
esp32s3_zx3d50ce02s_usrc_4832_bsp.mdBoard support package — hardware pin definitions and LVGL integration
factory_tools.mdSame flash tool pattern applied across all other boards in the project