π·πΊ Π ΡΡΡΠΊΠ°Ρ Π²Π΅ΡΡΠΈΡ Β· π¬π§ English
Step-by-step guide: from a bare board to a working spectrum in your browser.
| Component | Why |
|---|---|
| ESP32-S3-DevKitC-1 N16R8 | The gateway board. It must be the S3 β you need USB OTG Host (GPIO19/20). A regular ESP32 / C3 will not work β they have no USB Host. 16 MB Flash + 8 MB PSRAM. Buy on Ozon |
| USB-C OTG cable | Connects the ESP32-S3 USB port (host) to the spectrometer USB port (device). The ESP32-S3-DevKitC-1 has two USB-C connectors β use the one labeled βUSBβ (not βUARTβ). |
| USB cable for flashing | Connects the ESP32-S3 UART port (labeled βUARTβ) to the PC for the first flash. |
| KB Radar βAtom Spectraβ | A gamma spectrometer with a USB port. Inside β FTDI FT232R (VID 0403, PID 6001), 600000 baud. |
| 5V USB power supply | For continuous operation (after flashing, the USB-UART cable can be removed). |

Option A β local ESP-IDF (recommended for development):
Option B β Docker (simpler, nothing to install):

USB-C "UART" USB-C "USB" (OTG)
(for flashing) (for the spectrometer)
β β
βββββββββββ ββββββ΄ββββββββββββββββββββββββββ΄βββββ ββββββββββββββββ
β PC βββββββββΊβ ESP32-S3-DevKitC-1 βββββββββΊβ Atom Spectra β
β (COM14) β USB β N16R8 β USB β (FTDI FT232R β
βββββββββββ βββββββββββββββββββββββββββββββββββββ OTG β 600 kBd) β
β ββββββββββββββββ
β WiFi 2.4 GHz
βΌ
βββββββββββββ
β Browser β
β BecqMoni β
βββββββββββββ
Important: the ESP32-S3-DevKitC-1 has two USB-C connectors. Use the UART port for flashing. Use the USB (OTG) port to connect the spectrometer. Do not mix them up!

# Clone the repository
git clone https://github.com/VibeEngineering-LLC/atomspectra-waterfall-esp32.git
cd atomspectra-waterfall-esp32
# Set the target chip
idf.py set-target esp32s3
# Build
idf.py build
Dependencies (usb_host_cdc_acm, littlefs) are downloaded automatically on the first build
via the ESP-IDF Component Manager (main/idf_component.yml).
git clone https://github.com/VibeEngineering-LLC/atomspectra-waterfall-esp32.git
cd atomspectra-waterfall-esp32
# Build inside a Docker container
docker run --rm -v "$(pwd):/project" -w /project espressif/idf:v5.4 \
bash -c ". /opt/esp/idf/export.sh && idf.py build"
On Windows (PowerShell):
docker run --rm -v "${PWD}:/project" -w /project espressif/idf:v5.4 `
bash -c ". /opt/esp/idf/export.sh && idf.py build"
Build output: build/atomspectra.bin (+ bootloader + partition table).
# Connect the ESP32-S3 to the PC via the UART port
# Find the COM port (Device Manager β CH340/CH343/CP2102/FTDI)
idf.py -p COM14 flash
pip install esptool
# Flash all three images
esptool.py -p COM14 -b 460800 \
--before default_reset --after hard_reset \
write_flash --flash_mode dio --flash_size 16MB \
0x0 build/bootloader/bootloader.bin \
0x8000 build/partition_table/partition-table.bin \
0x10000 build/atomspectra.bin
http://192.168.4.1/)idf.py -p COM14 monitor
http://<board-IP>/ in a browser| Button | What it does |
|---|---|
| βΆ Start | Start spectrum acquisition on the instrument (command -sta) |
| β Stop | Stop acquisition (command -sto) |
| β» Reset | Reset the accumulated spectrum (command -rst) |
| Log / Lin | Toggle logarithmic / linear Y scale |
| CPS / Counts | Toggle Y units: count rate / accumulated pulses |
| Ch / keV | Toggle X scale: channels / energy in keV |
| Save | Save the current spectrum to the ESP flash |
| Load | Load a saved spectrum (overlaid on the live one) |
| XML | Download a BecqMoni-compatible file |
| CSV | Download an InterSpec-compatible file |
Hover over the chart β info appears below it:
Calibration is read from the instrument automatically on connection (command -inf).
If calibration is received β the keV button enables the energy scale.
Polynomial: E(ch) = cβ + cβΒ·ch + cβΒ·chΒ² + cβΒ·chΒ³ + cβΒ·chβ΄.
Two ways:
idf.py -p COM14 erase-otadata + reflashIf you want to use the desktop BecqMoni or AtomSpectra software over WiFi:
<board-IP> port 8234The TCP bridge and the Web UI work simultaneously β data is duplicated.
nvs, data, nvs, 0x9000, 0x6000 (24 KB β WiFi settings)
phy_init, data, phy, 0xf000, 0x1000 (4 KB)
factory, app, factory, 0x10000, 3M (3 MB β firmware)
storage, data, littlefs, , 12944K (12.9 MB β saved spectra)
Your WiFi password is stored in the nvs partition in plaintext. Anyone with
physical access to the board can read the flash contents with a standard tool and
extract the password:
esptool.py -p COM14 read_flash 0x9000 0x6000 nvs.bin
strings nvs.bin # the SSID and password will be among the strings
The Web UI (basic auth) and OTA passwords are stored the same way (unencrypted). This is a deliberate trade-off for the typical scenario β the board sits on a trusted home LAN and only the owner has physical access to it.
Enable encryption if:
The only correct way to protect the password in NVS is flash encryption (NVS
encryption works on top of it). The template in sdkconfig.defaults
is commented out:
#CONFIG_SECURE_FLASH_ENC_ENABLED=y
#CONFIG_NVS_ENCRYPTION=y
β IRREVERSIBLE. Flash encryption burns eFuses on the ESP32-S3 chip. The process cannot be rolled back, the chip cannot be returned to its original state, and in Release mode reflashing over UART is blocked forever. A configuration mistake can brick the board.
Steps (only deliberately, after reading the Espressif documentation):
sdkconfig.defaults.idf.py fullclean && idf.py build.The firmware ships with encryption disabled by default β the decision is left to you precisely because it is irreversible.
USB device enumerated: VID=0403 PID=6001-inf command via the input field in the Web UIshproto and Text(...) lines β a sign of data exchangeidf.py set-target esp32s3build/ and managed_components/, then rebuild