Pairs with firmware-v0002.ino. SD-card page: load the card’s audio/<Class>/*.wav, add clips with the browser microphone, train the same Conv-Pool-Conv-Dense network as the device (plain JS, float32 weights), clean the dataset, and write header/myWeights.bin + header/config.json back. No WebBLE, no flashing. Chrome or Edge on a desktop.
1 · Data source
Folder mode reads and writes the card directly (File System Access API). Without it, load a zip, work in memory, then “Save .zip”. Only lowercase .wav files count, exactly like the firmware.
2 · Classes and data
Class names are folder names: keep the numeric prefix so the order stays 0,1,2…
Lines to paste into the sketch
Layout and class count are compile-time in the firmware; change them in the sketch and re-flash. The page writes the same class list to header/config.json, which the sketch reads at boot (class names only).
Record clips (browser microphone, 16 kHz, 1 s — like the device)
Like the device: 0.8 s “get ready”, then 1 s is captured. Echo cancellation, noise suppression and auto gain are requested OFF. The level is shown in the PDM mic’s int16 units: compare with the device and set mic gain (and MY_MIC_GAIN in the sketch) so both hear the same loudness — needs bench tuning.
live waveform, last 1 s (faint lines = VAD threshold ±500 RMS)
live model input
Clean the dataset
Keys: ←→ move · X mark bad (deletes nothing) · P play
Sample browser
3 · Train
Model layout (compile-time in the sketch)
Changing the layout discards the model in memory (you are asked first if it is unsaved) and rebuilds every spectrogram and model input view. Sample rate 16 kHz and the 1 s window are fixed. 3×3 kernels are hard-coded in the firmware loops.
Training settings
Browser only (not in the firmware):
idle
Gradients are summed over the batch then scaled by 1/batch, Adam, gradient clip ±1 and weight clip ±10 exactly as the sketch. Page-only safety: non-finite gradients → 0, one update ≤ 0.05, a non-finite loss rolls back to the last good epoch with the learning rate halved (5 times at most). STOP keeps the model in memory and saves nothing.
4 · Analyze
Prints the answer for the last opened clip in the device’s serial format.
Misclassified clips (model input shown; click to inspect)
5 · Infer (live)
The page classifies the last second continuously; the device records the second after a VAD trigger, so expect small differences.
–
6 · Save
Never automatic. Put the card back in the XIAO: the serial log should say “Weights loaded from SD”. A weights file of the wrong size is refused by the sketch and by this page.
7 · Console
8 · Serial monitor (Web Serial)
not connected
115200 baud. Close the Arduino IDE serial monitor first; opening the port can reboot the board. Chrome or Edge only. A debug frame carries the raw 1 s audio (~43 KB of text): instant over native USB, about 4 s through a UART bridge.
Device view
Waiting for a debug frame (run Infer on the device, or record a clip).