Skip to content

Debugging Layers

Problems usually fall into three layers. Learning to identify which layer you’re in separates frustrated students from successful ones.


Symptoms: Code runs, but nothing happens. Or behaves weirdly.

IssueWhat Happened
ButtonsUsing IsPressed (checks once) vs WasPressed (event trigger)
ServosForgetting to set the pin number in the Hardware tab
LoopsMissing Wait blocks causing instant loops
ScreensForgetting Update blocks for dynamic content

Quick fix: Re-watch the UIFlow Interface video. Most issues are “oh, that’s where that setting lives.”


Layer 2: “The hardware isn’t talking…” (Configuration)

Section titled “Layer 2: “The hardware isn’t talking…” (Configuration)”

Symptoms: Error messages like [Errno 19] ENODEV or EIO, or silent failures.

Check physical first, code second.

CheckHowWhy It Matters
Power switchLook for tiny slide switch on bases/hubsBases need their own power
Cable orientationYellow=SDA, White=SCL, Red=VCC, Black=GNDWrong wiring = no communication
Port vs PinPort A = I2C (G1/G2). Header pins = PWM/GPIOMixing these causes “ENODEV” errors
I2C address conflictsTwo sensors can’t share address 0x44Use a scan to check

Run this code to see what your StickS3 actually detects:

import machine
i2c = machine.I2C(0, scl=machine.Pin(1), sda=machine.Pin(2), freq=100000)
print("I2C devices found:", [hex(addr) for addr in i2c.scan()])

Reading results:

  • Empty list [] → Hardware/wiring issue (Layer 2)
  • Shows [0x38] or similar → Configuration/code issue (Layer 1 or 3)

Layer 3: “This should work but doesn’t…” (Firmware/Bugs)

Section titled “Layer 3: “This should work but doesn’t…” (Firmware/Bugs)”

Symptoms: Code that looks correct throws weird errors, or works inconsistently.

ProblemWhat’s HappeningWorkaround
”Motion base not in hardware list”UIFlow 2 filters by device type; StickS3 hides Atom MotionUse raw I2C blocks at address 0x38 instead
Servo180Unit(None, ...) in generated codeUIFlow didn’t detect pin assignmentManually set pin in Hardware tab, or use Pin(2) in Python
Servo jitters, device resetsServo drawing too much power from StickS3 batteryKeep USB plugged in during testing
ENV III reads 85C constantlySensor needs status register resetAdd 1s delay after init, or use raw SHT30 driver

You’ve checked Layer 1 (blocks look right) and Layer 2 (I2C scan finds device), but behavior is still wrong.

What to do:

  1. Switch to Python view in UIFlow
  2. Check the generated code for None or missing values
  3. Try raw I2C blocks instead of unit-specific blocks
  4. Check the M5Stack Community Forum for known issues

Understanding what’s happening under the hood helps with debugging:

Your Blocks → Python Code (MicroPython) → ESP32-S3 Firmware → Hardware
↑ ↑ ↑
Visual REPL/Files Drivers (I2C, PWM, WiFi)

Key insight: UIFlow is just generating Python. You can always:

  1. Build in blocks (fast prototyping)
  2. Switch to Python tab to see the code
  3. Edit Python directly for precision
  4. Use mpremote or M5Burner to manage files directly

When you click the Python tab in UIFlow, look for:

CodeWhat It Does
M5.begin()Initializes the device
i2c0 = I2C(0, scl=Pin(1), sda=Pin(2))I2C on Port A
Pin(17) or similarDirect GPIO (header pins)
while True:The main loop (your Loop blocks)

Red flags in generated code:

  • None instead of a Pin() object → Hardware not configured
  • Missing time.sleep() → Blocking loop consuming 100% CPU
  • Hardcoded addresses without scan → Brittle I2C assumptions
Current page
🤖