Skip to content

ESP32-S3 ZX3D50CE02S USRC 4832 — Factory App Tools

ESP32-S3 ZX3D50CE02S USRC 4832 — Factory App Tools

Section titled “ESP32-S3 ZX3D50CE02S USRC 4832 — Factory App Tools”

This module provides the host-side Python tooling bundled with the Factory application for the ESP32-S3 ZX3D50CE02S USRC 4832 board. All scripts run on a development PC (not on the device) and cover the full production and development workflow: flashing firmware, generating embedded bitmap fonts, and converting on-device display snapshots to viewable PNG images.

The four tools live under:

boards/esp32s3_zx3d50ce02s_usrc_4832/Factory/tools/
├── flash_all.py # Multi-mode flash orchestrator
├── flash_factory.py # Single-partition factory flash
├── generate_font/
│ └── generate_font.py # Bitmap font C-source generator
└── raw2png/
└── snap2png.py # RGB565 snapshot → PNG converter

They complement the factory firmware described in esp32s3_zx3d50ce02s_usrc_4832_factory_app and are structurally identical to the tools shipped with every other board in the repository (e.g. pibot_pendant_v1_0, esp32s3_8048s070c, esp32s3_hmi43v3).


Output Artifacts

Target Device (ESP32-S3)

Dependencies

Host PC

write_flash

write_flash

write_flash

write_flash

write_flash

flash_all.py

(multi-mode flash)

flash_factory.py

(factory partition only)

generate_font.py

(bitmap font generator)

snap2png.py

(RGB565 → PNG)

esptool

(pip install esptool)

Pillow / PIL

(pip install Pillow)

pyserial

(serial.tools.list_ports)

partitions*.csv

(partition table)

Bootloader

0x1000

Partition Table

0xC000

app0 / firmware

0x20000

Factory partition

(auto-detected offset)

fontWxH.c / .h

(embedded in firmware)

snap000.png …

(visual review)


1. flash_all.py — Multi-Mode Flash Orchestrator

Section titled “1. flash_all.py — Multi-Mode Flash Orchestrator”

The primary flashing entry point. It covers three mutually exclusive modes, supporting everything from first-time production setup to day-to-day firmware iteration.

FlagWrites to device
--recoverybootloader + partition table + factory app
--full --fw <bin>bootloader + partition table + factory app + firmware
--fw <bin>firmware only → app0 at 0x20000
0x00000 ┌─────────────────────┐
0x01000 │ Bootloader │ ← BOOTLOADER_OFFSET
│ │
0x0C000 ├─────────────────────┤
│ Partition Table │ ← PARTITIONS_OFFSET
0x20000 ├─────────────────────┤
│ app0 (firmware) │ ← APP0_OFFSET
│ │
│ … │
auto ├─────────────────────┤
│ Factory App │ ← from partitions*.csv
└─────────────────────┘

The factory partition offset is not hardcoded: find_factory_offset() scans partitions*.csv files relative to the working directory and extracts the factory subtype row, falling back to 0x7A0000 (8 MB layout default) if no CSV is found.

find_esp32_port() queries all available COM/serial ports via serial.tools.list_ports and matches against known ESP32 USB-UART chipset keywords (CP210x, CH340, CH910x, FTDI). The first matching port is selected; if none match, the lexicographically first available port is used as a last resort.

--recovery

--full + --fw

--fw FILE

missing

all OK

success

CalledProcessError

FileNotFoundError esptool

Start

Parse args

Collect:

bootloader

partitions

factory

Collect:

bootloader

partitions

factory

firmware

Collect:

firmware only

find_factory_offset from CSV

find_esp32_port auto-detect

check_file

for each binary

Exit 1

flash via esptool subprocess

Done

Terminal window
# First-time production setup
python flash_all.py --recovery
# Specify port explicitly
python flash_all.py --recovery --port COM3
# Complete flash (production + firmware)
python flash_all.py --full --fw build/pibot_pendant.bin
# Development iteration: firmware only
python flash_all.py --fw build/pibot_pendant.bin

2. flash_factory.py — Factory Partition Flash

Section titled “2. flash_factory.py — Factory Partition Flash”

A focused script for updating only the factory recovery partition on an already-configured device. Useful when the production firmware has been updated and needs a fresh factory image without disturbing the rest of the flash.

Shares the same find_factory_offset() and find_esp32_port() logic as flash_all.py, and calls esptool directly via subprocess.

missing

found

--offset given

auto-detect

found

not found

--port given

auto-detect

found

not found

success

error

Start

Check binary

exists

Exit 1

Offset provided

or auto-detect?

Use manual offset

find_factory_offset

scan CSV files

Port provided

or auto-detect?

Use provided port

find_esp32_port

esptool write_flash

offset + binary

Done

Terminal window
# Auto-detect everything
python flash_factory.py
# Specify port
python flash_factory.py --port /dev/ttyUSB0
# Custom binary and manual offset
python flash_factory.py --bin my_factory.bin --offset 0x7A0000
# Custom baud rate
python flash_factory.py --port COM3 --baud 115200

3. generate_font/generate_font.py — Bitmap Font Generator

Section titled “3. generate_font/generate_font.py — Bitmap Font Generator”

Generates a 1-bit-per-pixel bitmap font as ready-to-compile C source files (.c + .h) for embedding in the factory firmware. This is the font used by the factory app’s raw display layer (see esp32s3_zx3d50ce02s_usrc_4832_factory_app_display).

  • Coverage: ASCII printable range 0x20 (space) through 0x7E (tilde) — 95 characters
  • Encoding: 1 bit per pixel, MSB = leftmost pixel, packed into (width + 7) / 8 bytes per row
  • Storage: bytes_per_row × height × 95 bytes total in flash
Glyph layout for 8×16 font:
byte 0: row 0, pixels 7-0
byte 1: row 1, pixels 7-0
…
byte 15: row 15, pixels 7-0
Access: font8x16_get_glyph('A') → const uint8_t* (16 bytes)

TTF font

or system font

Pillow

ImageFont.truetype

Find best

point size

fit within WxH

Measure all

glyph metrics

Compute global

y_offset for

consistent baseline

Render each

ASCII char

to grayscale image

Threshold at 127

→ 1-bit bitmap

Pack bits

MSB-first

bytes per row

fontWxH.c

fontWxH.h

Rather than aligning each glyph independently (which causes visual inconsistency), the generator:

  1. Scans all characters to find the global max_top (highest ascender) and max_bottom (lowest descender).
  2. Computes a single y_offset that vertically centers the entire glyph set within the target cell height.
  3. Uses this same offset for all 95 characters, ensuring consistent baseline across the rendered font.
  1. --font path/to/font.ttf (explicit)
  2. System monospace fonts searched in order:
    • Linux: DejaVu Sans Mono, Liberation Mono
    • macOS: Menlo, Monaco, Courier New
    • Windows: Consolas, Courier New, Lucida Console
/* fontWxH.h */
#define FONT_WIDTH W
#define FONT_HEIGHT H
#define FONT_BYTES_PER_ROW ((W + 7) / 8)
const uint8_t *fontWxH_get_glyph(char c);
/* Returns FONT_BYTES_PER_ROW * FONT_HEIGHT bytes.
Characters outside 0x20-0x7E return the space glyph. */
Terminal window
# 8×16 font, output to current directory
python generate_font.py 8x16 .
# 8×16 with DOS-style CP437 font
python generate_font.py 8x16 ./main --font "Perfect DOS VGA 437.ttf"
# 6×12 compact font
python generate_font.py 6x12 ./main
# 10×20 larger font with custom TTF
python generate_font.py 10x20 ./main --font /path/to/MyFont.ttf
SizeBytes/GlyphTotal (95 chars)
6×12121,140 bytes
8×16161,520 bytes
10×20302,850 bytes
12×24363,420 bytes

4. raw2png/snap2png.py — RGB565 Snapshot Converter

Section titled “4. raw2png/snap2png.py — RGB565 Snapshot Converter”

Converts raw display snapshots captured by the factory app (see gfx_snapshot_begin / gfx_snapshot_end in esp32s3_zx3d50ce02s_usrc_4832_factory_app_display) into standard PNG images for visual inspection and debugging.

Offset Size Description
────── ──── ─────────────────────────────────────
0x00 4 Width (uint32_t, little-endian)
0x04 4 Height (uint32_t, little-endian)
0x08 W×H×2 Raw RGB565 pixels, row-major order
RGB565 bit layout: RRRRR GGGGGG BBBBB
R8 = (R5 << 3) | (R5 >> 2) — scale 0-31 → 0-255
G8 = (G6 << 2) | (G6 >> 4) — scale 0-63 → 0-255
B8 = (B5 << 3) | (B5 >> 2) — scale 0-31 → 0-255

The bit-expansion replicates the most significant bits into the vacated low bits, giving accurate brightness scaling across the full 8-bit range.

snap000.raw

…snapNNN.raw

Read 8-byte header

width × height

Read W×H×2 bytes

pixel data

For each pixel:

RGB565 → RGB888

PIL Image.new RGB

set pixel by pixel

img.save .png

snap000.png

…snapNNN.png

Terminal window
# Convert single file (output: snap000.png)
python snap2png.py snap000.raw
# Convert all raw files in directory
python snap2png.py snap*.raw
# Convert single file with custom output name
python snap2png.py snap000.raw -o screenshot.png
# Process specific range
python snap2png.py snap00?.raw

Sibling Modules

File Inputs

Python Packages (pip)

This Module - Factory Tools

gfx_snapshot_begin/end

produces .raw files

uses font data

generated by

SD card stores .raw

snapshots

factory binary

flashed by

flash_all.py

flash_factory.py

generate_font.py

snap2png.py

esptool

Pillow

pyserial

partitions*.csv

installer/

bootloader.bin

partitions.bin

factory.bin

*.raw snapshots

(from device)

*.ttf font file

(optional)

[Display Module]

esp32s3_zx3d50ce02s_usrc_4832

_factory_app_display

[Storage Module]

esp32s3_zx3d50ce02s_usrc_4832

_factory_app_storage

[Main Module]

esp32s3_zx3d50ce02s_usrc_4832

_factory_app_main


ESP32-S3 Boardesptoolflash_all.pyDeveloperESP32-S3 Boardesptoolflash_all.pyDeveloperpython flash_all.py --recoveryfind_factory_offset() → scan CSVfind_esp32_port() → scan USB portscheck_file() × 3 (bootloader, partitions, factory)esptool write_flash\n0x1000 bootloader.bin\n0xC000 partitions.bin\n<offset> factory.binerase + program flash sectorsACKexit 0Flash successful! ESP32-S3 Boardflash_all.pyidf.py buildDeveloperESP32-S3 Boardflash_all.pyidf.py buildDeveloperidf.py buildbuild/app.binpython flash_all.py --fw build/app.binfind_esp32_port()check_file(app.bin)esptool write_flash 0x20000 app.bindoneFlash successful! snap2png.pySD CardESP32-S3 BoardDevelopersnap2png.pySD CardESP32-S3 BoardDeveloperFactory app running\nSnapshot triggered by menuWrite snap000.raw\n(4B width + 4B height + RGB565 pixels)Copy snap*.raw to PCpython snap2png.py snap*.rawParse header → W×HRGB565 → RGB888 per pixelsnap000.png … (viewable images) Factory Firmware (gfx.c)generate_font.pyDeveloperFactory Firmware (gfx.c)generate_font.pyDeveloperpython generate_font.py 8x16 ./mainLocate system monospace fontfind_best_font_size() → point sizeCompute global y_offset (baseline align)Render 95 ASCII glyphs\nto 1-bit bitmapsfont8x16.c + font8x16.hInclude font8x16.h in gfx.c\nCall font8x16_get_glyph(c)Render text using bitmap data

This tools module is board-agnostic in practice. Identical scripts (same functions, same logic) are present in every board’s Factory tools directory:

BoardTools Module
pibot_pendant_v1_0pibot_pendant_v1_0_factory_app_tools
esp32s3_8048s070cesp32s3_8048s070c_factory_app_tools
esp32s3_bzm_tft35_gt911esp32s3_bzm_tft35_gt911_factory_app_tools
esp32s3_hmi43v3esp32s3_hmi43v3_factory_app_tools
esp32s3_zx3d50ce02s_usrc_4832this module

The only board-specific element is the factory partition offset, which is always derived at runtime from the board’s partitions*.csv — no hardcoding required.


Install all required Python packages before running any tool:

Terminal window
pip install esptool pillow pyserial
PackageUsed ByPurpose
esptoolflash_all.py, flash_factory.pyESP32 flash programming
Pillowgenerate_font.py, snap2png.pyImage/font rendering
pyserialflash_all.py, flash_factory.pySerial port enumeration