A real-time 3D particle-fluid animation for the M5Stack StopWatch. The device's BMI270 accelerometer and gyroscope drive gravity, shake, and rotational motion, making the fluid respond as the hardware is tilted or moved.
Here, “StopWatch” is the name of the M5Stack hardware. This is a FluidBox visualization, not a stopwatch application. It is an unofficial community project and is not affiliated with or endorsed by M5Stack or V4C38.
Fluid simulation running on the M5Stack StopWatch.
This project is strongly inspired by V4C38/esp32-fluidbox. Its fluid simulation and rendering design is adapted from ideas and substantial algorithmic structure in that project, then modified for the M5Stack StopWatch, its circular display, BMI270 IMU, M5Unified, and M5GFX.
Many thanks to V4C38 for publishing the original project under the MIT License. The original copyright notice and license text are retained in THIRD_PARTY_NOTICES.md. Waveshare-specific display, GPIO, IMU, power-management, and ESP-IDF startup code is not included here.
- 400-particle 3D fluid simulation using double-density relaxation
- Gravity, shake, and rotation response from the BMI270 accelerometer and gyroscope
- Perspective projection with depth-dependent particle size and brightness
- Velocity- and depth-based RGB565 coloring with precomputed lookup tables
- A shallow cylindrical boundary adapted to the round StopWatch display
- Physics and rendering separated across the two ESP32-S3 cores
- Immutable triple-buffered particle snapshots for render synchronization
- Full-screen, UI-free FluidBox presentation
- Arduino IDE and PlatformIO build support
- Blue B button resets the fluid simulation
- Lightweight Serial performance diagnostics
This project targets the M5Stack StopWatch (SKU C152).
| Component | Specification |
|---|---|
| MCU | ESP32-S3R8, dual-core Xtensa LX7, up to 240 MHz |
| Memory | 16 MB Flash, 8 MB OPI PSRAM |
| Display | 1.75-inch round AMOLED, 466 × 466, CO5300 over QSPI |
| IMU | BMI270 6-axis accelerometer and gyroscope |
| Controls | Yellow A button and blue B button |
The display dimensions are read from M5GFX at runtime. M5GFX allocates the StopWatch AMOLED framebuffer in PSRAM, so OPI PSRAM must be enabled in the Arduino build settings.
The project uses the Arduino framework with:
- M5Stack board package 3.3.8 (verified configuration)
- M5Unified 0.2.19
- M5GFX 0.2.26
- PlatformIO Espressif32 platform 6.12.0 for the PlatformIO build
The M5Unified and M5GFX versions are pinned in platformio.ini. Older library
versions may not include complete M5Stack StopWatch, AMOLED, or BMI270 support.
| Control | Action |
|---|---|
| Yellow A button | Unused |
| Blue B button | Reset and reseed the fluid particles |
No control labels or diagnostics are drawn over the animation.
-
Install M5Stack board package 3.3.8 (the tested version).
-
Install M5Unified 0.2.19 and M5GFX 0.2.26.
-
Open
STOPWATCH-FluidBox.inoin Arduino IDE. -
Select the following board options:
Option Value Board M5StopWatchCPU Frequency 240MHzFlash Mode QIO 80MHzFlash Size 16MBPSRAM OPI PSRAM -
Use Verify to compile the sketch.
From the repository root:
pio run -e m5stack-stopwatchplatformio.ini uses an ESP32-S3 board profile with the StopWatch flash, OPI
PSRAM, and USB settings defined explicitly. It also pins the tested M5Unified
and M5GFX revisions. platformio_main.cpp conditionally includes the canonical
Arduino sketch so the same .ino remains usable in Arduino IDE.
The Arduino loop() runs on Core 1 and handles M5.update(), the B button,
BMI270 sampling, the simulation, and Serial statistics. A pinned FreeRTOS task
on Core 0 owns M5GFX rendering and framebuffer transfer.
After each simulation step, the physics side publishes particle position and speed into one of three fixed snapshots. The renderer reads an immutable snapshot, preventing cross-core particle-state races without holding a lock during drawing. Missed scheduler ticks are dropped rather than processed in a catch-up burst.
| Setting | Current target |
|---|---|
| Particle count | 400 |
| Simulation rate | 40 Hz |
| Rendering rate | 30 FPS |
| IMU sampling rate | 100 Hz |
These are scheduler targets, not performance guarantees. Actual rates depend on the toolchain, library versions, device conditions, and rendering cost. The firmware prints aggregated render, simulation, IMU, timing, neighbor-pair, overflow, NaN-reset, heap, and PSRAM statistics to Serial at 115200 baud about once per second. Nothing is drawn on the AMOLED except the fluid.
| Path | Purpose |
|---|---|
STOPWATCH-FluidBox.ino |
Arduino entry point, hardware setup, scheduling, and diagnostics |
FluidBox.h, FluidBox.cpp |
Particle solver, IMU motion model, snapshots, and M5GFX renderer |
FluidBoxConfig.h |
Simulation, IMU, display, and performance constants |
platformio.ini |
PlatformIO environment and pinned dependencies |
platformio_main.cpp |
PlatformIO wrapper for the canonical .ino sketch |
THIRD_PARTY_NOTICES.md |
Upstream attribution and MIT license notice |
This is a working experimental port tested on physical M5Stack StopWatch hardware. The full-screen animation, IMU response, circular boundary, and B button reset are working, but the project should not be treated as an official M5Stack product or a production-grade fluid dynamics implementation.
This repository is distributed under the MIT License. The FluidBox
implementation contains ideas and substantial algorithmic structure adapted
from V4C38's MIT-licensed esp32-fluidbox; its original copyright notice and
license are preserved in THIRD_PARTY_NOTICES.md.
