M5Stack Cardputer ADV · Volume 7
M5Stack Cardputer ADV Volume 7 — Programming Environments
Arduino + PlatformIO + MicroPython + UiFlow 2 + ESP-IDF — the five paths to writing custom code
Contents
1. About this volume
Vol 7 covers the programming environments for writing custom code on Cardputer ADV. Five paths:
| Environment | Friction | Performance | Best for |
|---|---|---|---|
| Arduino IDE 2.x | Low | Compiled (good) | One-off sketches, learning |
| PlatformIO | Low-medium | Compiled (good) | Serious dev — the recommended default for non-trivial projects |
| MicroPython + mpremote | Lowest | Interpreted (~50% of compiled speed for typical code) | Scripting, education, rapid prototyping |
| UiFlow 2 | Lowest | Compiles to MicroPython | Non-coders, block-style learning |
| ESP-IDF | High | Compiled (excellent — full FreeRTOS access) | Low-level work, custom partitions, monitor-mode Wi-Fi |
The decision matrix in § 10 picks among them per use case.
2. Arduino IDE 2.x
Setup:
- Install Arduino IDE 2.x from https://www.arduino.cc/en/software.
- Add ESP32 board manager URL: Preferences → Additional Board Manager URLs → add
https://espressif.github.io/arduino-esp32/package_esp32_index.json. - Install ESP32 board package: Tools → Board → Boards Manager → search “esp32” → install “esp32 by Espressif Systems” (v3.0.0 or newer).
- Install M5Cardputer library: Sketch → Include Library → Manage Libraries → search “M5Cardputer” → install. Pulls M5Unified + M5GFX as dependencies.
Board settings (Tools menu):
| Setting | Value |
|---|---|
| Board | ”M5Stack-Cardputer” (covers ADV) OR generic “ESP32S3 Dev Module” |
| Upload Speed | 1500000 |
| USB CDC On Boot | Enabled |
| USB Mode | Hardware CDC and JTAG |
| Flash Size | 8 MB |
| Partition Scheme | ”8M with spiffs (3MB APP/1.5MB SPIFFS)“ |
| PSRAM | Disabled (Cardputer ADV has no PSRAM) |
| Core Debug Level | None (or Info for development) |
| Port | Auto-detect from Tools → Port (usually /dev/ttyACM0 or COM-N) |
Hello-world sketch:
#include <M5Cardputer.h>
void setup() {
auto cfg = M5.config();
M5Cardputer.begin(cfg, true);
M5Cardputer.Display.setTextSize(2);
M5Cardputer.Display.setCursor(10, 10);
M5Cardputer.Display.println("Hello, Cardputer!");
}
void loop() {
M5Cardputer.update();
if (M5Cardputer.Keyboard.isChange()) {
if (M5Cardputer.Keyboard.isPressed()) {
Keyboard_Class::KeysState keys = M5Cardputer.Keyboard.keysState();
for (auto c : keys.word) {
M5Cardputer.Display.print(c);
}
}
}
delay(10);
}
Upload, see “Hello, Cardputer!” on screen, type on the keyboard to see characters appear.
3. PlatformIO (the recommended default)
Setup:
- CLI:
pip install -U platformio - IDE: VS Code + PlatformIO extension (Extensions panel, search “PlatformIO IDE”, install, restart VS Code)
Project skeleton for Cardputer ADV:
platformio.ini:
[env:cardputer-adv]
platform = [email protected]
board = esp32-s3-devkitc-1
framework = arduino
upload_speed = 1500000
monitor_speed = 115200
build_flags =
-DBOARD_HAS_PSRAM=0
-DARDUINO_USB_CDC_ON_BOOT=1
-DARDUINO_USB_MODE=1
-DESP32S3
-DCORE_DEBUG_LEVEL=3
lib_deps =
https://github.com/m5stack/M5Cardputer.git
https://github.com/m5stack/M5Unified.git
jgromes/RadioLib@^6.6.0 ; only if doing LoRa work
src/main.cpp:
#include <Arduino.h>
#include <M5Cardputer.h>
void setup() {
auto cfg = M5.config();
M5Cardputer.begin(cfg, true);
M5Cardputer.Display.setTextSize(2);
M5Cardputer.Display.setCursor(10, 10);
M5Cardputer.Display.println("Hello PlatformIO");
}
void loop() {
M5Cardputer.update();
delay(100);
}
Build + flash:
cd ~/cardputer-project
pio run -e cardputer-adv # Compile
pio run -e cardputer-adv -t upload # Compile + flash
pio device monitor # Serial monitor
Why PlatformIO over Arduino IDE for non-trivial projects:
- Dependency pinning —
lib_depslocks library versions; reproducible builds across machines and time. - Multi-environment —
[env:cardputer-adv]+[env:t-display-s3]etc. in the sameplatformio.inifor cross-platform builds. - Better source tree —
src/+lib/+test/conventions match how Bruce / Marauder / NEMO source trees are laid out. - Integrated debugger — JTAG / SWD debugging via Espressif’s USB-JTAG bridge (works on Cardputer ADV’s native USB).
- CI/CD friendly —
pio runworks in GitHub Actions, GitLab CI, etc.
For modifying existing community firmwares (Bruce, Marauder, NEMO): they all use PlatformIO. Clone the repo, open in VS Code, build.
4. MicroPython + mpremote
Setup:
- Flash M5Stack-flavored MicroPython build to Cardputer ADV. M5Burner has this in its firmware catalog as “UIFlow Code” (the underlying MicroPython is the same).
- Install
mpremote:pip install -U mpremote - Access REPL:
mpremote connect /dev/ttyACM0 repl
Hello-world:
# At the REPL:
import M5
M5.begin()
# Display text
Lcd.print("Hello MicroPython", 10, 10)
# Read a key
key = Keyboard.read()
print(f"You pressed: {key}")
File operations:
# Upload a script
mpremote connect /dev/ttyACM0 cp myapp.py :/myapp.py
# Run a script
mpremote connect /dev/ttyACM0 exec "exec(open('/myapp.py').read())"
# List files
mpremote connect /dev/ttyACM0 ls /
# Delete a file
mpremote connect /dev/ttyACM0 rm /myapp.py
Why MicroPython over Arduino/PlatformIO:
- No compile step — write Python, run immediately. Edit-test loop measured in seconds, not minutes.
- REPL — interactive exploration of the hardware. Probe sensors, test display drawing, experiment.
- Easier for non-C++ devs — Python syntax is more accessible.
Why NOT MicroPython:
- ~50% slower than compiled C++ for typical workloads. CPU-bound code (audio FFT, emulators, packet capture at high rate) is materially slower.
- More RAM-hungry (interpreter overhead).
- Smaller library ecosystem than Arduino ecosystem.
For Cardputer ADV: MicroPython is excellent for scripting + learning + custom MicroHydra apps. For high-performance / production firmware: Arduino + PlatformIO.
5. UiFlow 2 (block coding)
Setup:
- Flash UiFlow firmware to Cardputer ADV (M5Burner catalog → “UIFlow 2 Cardputer-Adv” → Burn).
- Open https://flow.m5stack.com in browser. Pair via USB-CDC (Web Serial).
- Drag blocks from the toolbox onto the canvas. Compile to MicroPython under the hood. Run.
Block categories:
- M5Stack blocks: display, keyboard, speaker, microphone, IMU, IR, LED, SD card
- M5 Units / HATs / Caps: drag-and-drop blocks for every M5Stack peripheral with auto-detected pin assignments
- Logic blocks: if/else, loops, conditions
- Math blocks: arithmetic, comparison, etc.
- Variables blocks: read / write
- Functions blocks: define + call
Why UiFlow over MicroPython / Arduino:
- Lowest barrier of any path. Useful for: education, kids, non-coders, very rapid prototyping.
- Visual debugging — see the program flow as blocks light up during execution.
Power users typically graduate to MicroPython (mpremote) once they hit UiFlow’s expressiveness ceiling — at which point the underlying MicroPython is the natural next step (UiFlow generates MicroPython, so the transition is gradual).
6. ESP-IDF (native Espressif SDK)
Setup:
# Clone ESP-IDF
git clone -b master --recursive https://github.com/espressif/esp-idf.git ~/esp-idf
cd ~/esp-idf
# Install toolchain for ESP32-S3
./install.sh esp32s3
# Source the environment (every shell session)
. ./export.sh
Hello-world project:
cd ~/projects
idf.py create-project cardputer_hello
cd cardputer_hello
idf.py set-target esp32s3
idf.py menuconfig # Configure: USB CDC on boot, flash 8 MB, etc.
idf.py build
idf.py -p /dev/ttyACM0 -b 1500000 flash monitor
Why ESP-IDF over Arduino + PlatformIO:
- Custom partition tables — Arduino’s partition options are predefined; ESP-IDF lets you build any layout.
- Monitor-mode Wi-Fi —
esp_wifi_set_promiscuous(true)works in Arduino too, but ESP-IDF exposes more control over the underlying ESP32-S3 Wi-Fi peripheral. - Secure boot v2 — ESP-IDF’s secure-boot toolchain is much better than Arduino’s (which mostly hides it).
- Native FreeRTOS — direct task scheduling, custom IPC, priority management.
- Flash encryption — fully exposed in ESP-IDF.
- 802.11 frame injection — works in Arduino, but ESP-IDF has more reliable / well-documented APIs.
Why NOT ESP-IDF:
- Steeper learning curve.
- More boilerplate per project.
- Smaller community than Arduino + PlatformIO for Cardputer ADV specifically.
When to reach for ESP-IDF: building production firmware with secure boot, custom flash encryption, or hardware-feature work Arduino doesn’t cleanly expose. For most Cardputer ADV use cases, Arduino + PlatformIO suffices.
M5Stack publishes the official factory firmware as an ESP-IDF starting point. Useful reference for IDF-on-Cardputer-ADV.
7. Sketch / project skeletons
Three canonical project skeletons (templates live in ../../04-templates/):
Arduino single-file .ino (one-off sketches):
#include <M5Cardputer.h>
void setup() {
auto cfg = M5.config();
M5Cardputer.begin(cfg, true);
M5Cardputer.Display.println("Hello");
}
void loop() {
M5Cardputer.update();
// ... your code ...
delay(10);
}
PlatformIO multi-file project:
my-project/
├── platformio.ini
├── src/
│ ├── main.cpp
│ └── my_module.cpp
├── include/
│ └── my_module.h
└── lib/
└── (auto-fetched via lib_deps)
MicroHydra app (.py on SD at /apps/<AppName>/__init__.py):
from lib.hydra.app import App
from lib.display import Display
class HelloApp(App):
name = "HelloWorld"
icon = "rocket"
def main(self):
d = Display()
d.text("Hello", 10, 10)
while not self.exit_pressed():
self.tick()
8. M5Cardputer + M5Unified library reference
Key APIs from m5stack/M5Cardputer (which extends m5stack/M5Unified):
Initialization:
#include <M5Cardputer.h>
void setup() {
auto cfg = M5.config();
M5Cardputer.begin(cfg, true); // true = enable M5GFX display backend
}
Display (M5Cardputer.Display, descended from M5GFX):
M5Cardputer.Display.fillScreen(BLACK);
M5Cardputer.Display.setTextColor(WHITE, BLACK);
M5Cardputer.Display.setTextSize(2); // Multiplier on 6×8 default font
M5Cardputer.Display.setCursor(10, 20);
M5Cardputer.Display.printf("Hello %d", value);
M5Cardputer.Display.drawLine(0, 0, 100, 100, RED);
M5Cardputer.Display.fillRect(0, 0, 50, 50, BLUE);
M5Cardputer.Display.drawString("Centered", 120, 67);
Keyboard (M5Cardputer.Keyboard):
M5Cardputer.update(); // Must call every loop
if (M5Cardputer.Keyboard.isChange()) { // True on any key state change
if (M5Cardputer.Keyboard.isPressed()) { // True if any key currently pressed
Keyboard_Class::KeysState keys = M5Cardputer.Keyboard.keysState();
// keys.word: characters of currently-pressed keys
// keys.modifiers: ctrl, alt, shift, fn states
// keys.del: backspace key pressed
// keys.enter: enter key pressed
}
}
Speaker / audio:
M5Cardputer.Speaker.tone(440, 100); // 440 Hz for 100 ms
M5Cardputer.Speaker.playRaw(audioBuffer, length); // Play PCM audio
IMU (BMI270):
auto data = M5Cardputer.Imu.getAccelData();
float ax = data.x, ay = data.y, az = data.z; // in g
data = M5Cardputer.Imu.getGyroData();
// rotation rates in deg/sec
Battery telemetry:
int level = M5Cardputer.Power.getBatteryLevel(); // 0-100
float voltage = M5Cardputer.Power.getBatteryVoltage();
SD card (use Arduino SD.h):
#include <SD.h>
SD.begin(12); // CS = GPIO 12 on Cardputer ADV
File f = SD.open("/myfile.txt", FILE_WRITE);
f.println("Hello SD");
f.close();
Full API reference: M5Cardputer / M5Unified GitHub READMEs.
9. Build-flag inventory for Cardputer ADV
Key build_flags in platformio.ini for Cardputer ADV builds:
| Flag | Purpose | Required |
|---|---|---|
-DBOARD_HAS_PSRAM=0 | Disable PSRAM (Cardputer ADV has none) | Yes |
-DARDUINO_USB_CDC_ON_BOOT=1 | Native USB-CDC at boot | Yes for serial console |
-DARDUINO_USB_MODE=1 | Device mode (1) or Host OTG (0) | 1 for typical apps; 0 for USB-host work |
-DESP32S3 | Compile-time ESP32-S3 identifier | Implicit but explicit for clarity |
-DCORE_DEBUG_LEVEL=3 | Serial debug verbosity (0-5) | 0 for production, 3 for development |
-DCONFIG_ESP32_PHY_MAX_TX_POWER=20 | Max Wi-Fi TX power in dBm | Optional |
-DDISABLE_ALL_LIBRARY_WARNINGS | Suppress library warnings | Optional |
If using TFT_eSPI directly (rare — M5GFX wraps it):
build_flags =
-DUSER_SETUP_LOADED=1
-DST7789_DRIVER
-DTFT_WIDTH=240
-DTFT_HEIGHT=135
-DTFT_MISO=39
-DTFT_MOSI=14
-DTFT_SCLK=40
-DTFT_CS=10
-DTFT_DC=9
-DTFT_RST=8
-DTFT_BL=13
-DTFT_BACKLIGHT_ON=HIGH
-DLOAD_GLCD
-DLOAD_FONT2
-DLOAD_FONT4
-DLOAD_FONT6
-DSPI_FREQUENCY=40000000
(Cross-ref Vol 3 § 2 for the GPIO assignments these flags reference.)
10. When to use which environment
| Use case | Environment | Why |
|---|---|---|
| Learning, education | UiFlow 2 → MicroPython | Lowest barrier, visual feedback first |
| Quick test / one-off sketch | Arduino IDE | Compile + flash in one click |
| Rapid scripting prototype | MicroPython + mpremote | REPL iteration, no compile |
| Multi-file production project | PlatformIO | Better than Arduino IDE for >1 source file; reproducible builds |
| Modifying existing firmware (Bruce, Marauder, NEMO, M5Launcher) | PlatformIO | All major firmwares use PlatformIO |
| Custom partition table | PlatformIO or ESP-IDF | Arduino IDE has predefined options only |
| Wi-Fi monitor mode | Arduino + PlatformIO | esp_wifi_set_promiscuous() works fine |
| 802.11 frame injection | ESP-IDF (preferred) or Arduino | ESP-IDF has cleaner APIs |
| Secure boot v2 | ESP-IDF | Arduino doesn’t cleanly expose |
| Production firmware with flash encryption | ESP-IDF | Same |
| MicroHydra app | MicroPython | Required (MicroHydra IS MicroPython) |
| ESPHome device | ESPHome (own toolchain) | Required |
| BadUSB DuckyScript | Either text file on SD (no compile) or compile a BadCard fork in PlatformIO | DuckyScript runs interpreted |
The recommended default for tjscientist: Arduino IDE for first-time learning + PlatformIO for serious development.
11. Resources
Tools / IDEs
- Arduino IDE: https://www.arduino.cc/en/software
- PlatformIO: https://platformio.org/
- VS Code: https://code.visualstudio.com/
- ESP-IDF: https://github.com/espressif/esp-idf
- mpremote: https://docs.micropython.org/en/latest/reference/mpremote.html
M5Stack libraries
- M5Cardputer: https://github.com/m5stack/M5Cardputer
- M5Unified: https://github.com/m5stack/M5Unified
- M5GFX: https://github.com/m5stack/M5GFX
Espressif docs
- ESP32-S3 datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf
- ESP-IDF programming guide: https://docs.espressif.com/projects/esp-idf/
- Arduino-ESP32 reference: https://docs.espressif.com/projects/arduino-esp32/
MicroPython
- MicroPython for ESP32: https://micropython.org/download/?port=esp32
- M5Stack MicroPython firmware: https://github.com/m5stack/UIFlow-Code
UiFlow 2
Forward references
- Adding a custom firmware module: Vol 10
- Build errors triage: Vol 10 § 10
- Flashing the built binary: Vol 8
This is Volume 7 of a twelve-volume series. Next: Vol 8 covers flashing and updating firmware — M5Burner, web flashers, esptool.py, OTA, factory backup, and crash-loop recovery.