A hardware simulation of firefly synchronization running on a Lattice iCE40HX1K FPGA (iCEstick evaluation board). Five pulse-coupled phase oscillators naturally synchronize their flashing — just like real fireflies.
- 5 LED fireflies blink at slightly different rates (~1.4–1.6 s periods)
- Phase-gated pulse coupling gradually pulls them into synchronization
- PWM brightness creates smooth flash-then-fade envelopes on each LED
- I2S audio — each firefly plays a sine tone on an A minor pentatonic scale (A4, C5, D5, E5, G5) via BRAM wavetable, with soft-attack envelopes and Haas stereo delay
- UART telemetry streams phase/brightness data at ~11 Hz for a live terminal UI
- Auto-disruption — every ~45 seconds, an LFSR scrambles the phases so the synchronization process replays from scratch
| Component | Connection |
|---|---|
| iCEstick | Lattice iCE40HX1K-TQ144, 12 MHz oscillator |
| LEDs | 4 red (pins 99–96) + 1 green (pin 95), active high |
| Pmod I2S2 | DAC on PMOD top row: MCLK/LRCLK/SCLK/SDIN (pins 78–81) |
| UART | 115200 8N1 on FTDI Channel B (pin 8 TX) → /dev/ttyUSB1 |
12 MHz clk
│
├── 5× Phase Accumulators (32-bit DDS, TW 235–243)
│ │
│ ├── Flash Detection (top 1/8 of phase = "flash zone")
│ ├── Phase-Gated Coupling (2^27 per kick, upper-half only)
│ └── PWM Brightness (linear decay in flash zone)
│
├── Audio Pipeline (serialized, 1 channel/clock)
│ ├── 5× Tone DDS (16-bit, 440–784 Hz) + Sine Wavetable (256×16 BRAM)
│ ├── Soft-Attack Envelope (+3/sample ramp, ~1.8 ms)
│ ├── Rule 30 CA Melody (C major pentatonic, activates on sync)
│ ├── Haas Stereo (BRAM delay line, ~0.36 ms)
│ └── I2S Serializer (46.875 kHz, 16-bit, standard format)
│
├── UART TX (115200 8N1)
│ └── 16-byte packets: sync + 5×(phase_hi + phase_lo + brightness)
│
└── Disruption Timer (LFSR + 29-bit counter, ~45 s period)
Resource usage: ~1215 / 1280 logic cells (95%), Fmax well above 12 MHz.
Requires the open-source iCE40 toolchain: Yosys, nextpnr, IceStorm.
make # synthesize fireflies (default)
make PROJ=musicbox # synthesize musicbox instead
make prog # program the iCEstick via USBA Python terminal UI displays live phase, brightness, and synchronization status:
pip install pyserial
python monitor.py🔥 Firefly Synchronization Monitor
══════════════════════════════════════════════════════════════════
🔴 Fly 0 (A4) Phase: 87.91% Bright: 254 ⚡ [██████████████████████████████]
🔴 Fly 1 (C5) Phase: 88.02% Bright: 251 ⚡ [█████████████████████████████░]
🔴 Fly 2 (D5) Phase: 87.95% Bright: 253 ⚡ [█████████████████████████████░]
🔴 Fly 3 (E5) Phase: 88.10% Bright: 249 ⚡ [█████████████████████████████░]
🟢 Fly 4 (G5) Phase: 88.15% Bright: 248 ⚡ [█████████████████████████████░]
Phase spread: 0.24% 🔥 SYNCHRONIZED
The design is inspired by Mirollo & Strogatz (1990), which proves that pulse-coupled integrate-and-fire oscillators synchronize when the rise-to-threshold function is concave down. This implementation departs from the formal M-S model in a few ways:
- Linear phase accumulator. Each firefly is a 32-bit DDS counter with a slightly different tuning word (235–243). There is no concave function mapping phase to state — the phase is the state. M-S notes that linear dynamics alone would not synchronize.
- Phase-gated coupling replaces concavity as the convergence mechanism. Kicks are delivered only to oscillators in the upper half of their cycle that are not already flashing (
vulnerable = upper_half & ~in_flash). Oscillators near their flash point receive kicks; those that just flashed do not. This asymmetric window drives convergence in a similar spirit to how M-S's concavity makes near-threshold oscillators more responsive. - Non-identical frequencies. The five tuning words span ~3.3% (1175–1215), whereas M-S assumes identical oscillators.
- Refractory flash zone. The top 1/8 of the phase space is a "flash zone" where an oscillator is visibly flashing and ignores incoming kicks — analogous to the biological refractory period described by Buck, which M-S cites but excludes from the formal model.
The coupling strength cycles through four levels every ~11 s (strong → medium → weak → near-chaotic), and a kick's magnitude scales with the number of simultaneously flashing neighbors — up to 2^27 (~3.1% of a full cycle) per neighbor at the strongest setting.
The audio pipeline is time-multiplexed: a single set of arithmetic processes all 5 channels sequentially during clock cycles 1–5 of each PWM period. Each voice reads a 256-entry sine wavetable from BRAM, amplitude-scaled by a shift-based envelope. When all five fireflies synchronize, a 16-cell Rule 30 cellular automaton selects notes from a C major pentatonic scale across 4 octaves — turning the sync event into a generative melody. Stereo imaging uses a BRAM-based Haas delay (~0.36 ms) that narrows when synced. The mix is serialized over I2S at 46.875 kHz.
- Tone phase resets to 0 at flash onset for consistent waveform start
- Per-channel envelope ramps +3/sample (~1.8 ms attack) instead of jumping to full amplitude
- -6 dB per voice headroom prevents clipping when all 5 fire simultaneously
| File | Description |
|---|---|
fireflies.v |
Complete RTL — oscillators, coupling, audio, I2S, UART |
icestick.pcf |
Pin constraints for iCEstick |
Makefile |
Build flow (yosys → nextpnr → icepack → iceprog) |
musicbox.v |
Algorithmic wind chimes — 5 voices play random C major pentatonic notes at different tempos and octaves, sine wavetable synthesis |
monitor.py |
Python TUI for serial telemetry display |
web/index.html |
WebGL2 browser visualization — animated fireflies with synchronized audio oscillators |
sim/tb_fireflies.cpp |
Verilator testbench — verifies sync convergence, disruption/re-sync, audio output, and UART telemetry over 100 simulated seconds |
sim/sb_ram40_4k.v |
Behavioral model of iCE40 SB_RAM40_4K for simulation (256×16 mode) |
web/index.html is a standalone WebGL2 visualization of the same firefly synchronization algorithm. Open it in a browser — no build step required. Click to start; fireflies synchronize their flashes with spatial audio using the Web Audio API.
make sim # build and run Verilator testbench (~2 min for 100 simulated seconds)The testbench verifies phase convergence, disruption recovery, non-zero audio output, and valid UART telemetry packets.
MIT — see LICENSE.