Search › A-Z › E › ESP32-H2

ESP32-H2

2023 Open source · CC0 On-board only Online

ESP32-H2 is Espressif's Bluetooth LE 5 + 802.15.4 (Thread / Zigbee) microcontroller (no WiFi), emulated in the browser on a from-scratch RISC-V RV32IMAC interpreter (the RV32I base plus the M multiply/divide, A atomics and C compressed extensions, the machine-mode CSRs and the trap and interrupt machinery). The core is wired to an ESP32-H2 SoC model at the real hardware addresses: 320 KB unified HP SRAM, XIP flash, the GPIO block with the DevKitM-1 addressable WS2812 RGB LED on GPIO8, UART0, the systimer and a functional interrupt matrix. It runs REAL bare-metal firmware, including a WS2812 RGB cycle and an interactive UART REPL you can type into. Because the whole chip is ordinary JavaScript it plugs into the site's shared debugger: the real RISC-V disassembler, live x0-x31, pc and the machine CSRs, side-effect-free memory, single-instruction step, execution breakpoints and write-watchpoints. BLE and 802.15.4 have no radio here and are HLE stubs, so the emulator is silent.

ESP32-H2 at Espressif ↗

Runs on: Web browser

ESP32-H2 Online Emulator

Play ESP32-H2 using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
MicroPython v1.29.0ESP32-H2ESP32-H2openOpen ⛶
RGB cycle (WS2812)ESP32-H2ESP32-H2openOpen ⛶
Rainbow (WS2812 hue wheel)ESP32-H2ESP32-H2openOpen ⛶
Mini-REPL (UART0)ESP32-H2ESP32-H2openOpen ⛶
Hello UART (serial)ESP32-H2ESP32-H2openOpen ⛶

Chips

Notes

Embedding

The CPU and SoC are written from scratch for this site (public domain / CC0) — nothing here wraps a third-party core. rv32-esp32h2.js is a plain RV32IMAC interpreter plus an ESP32-H2 SoC model at the real hardware addresses (from the ESP32-H2 TRM and the esp-idf soc.h / reg_base.h). It is all inspectable JavaScript state, which is exactly what lets the shared debugger drive it.

var sys = window.ESP32H2.createSystem();       // RV32IMAC core + ESP32-H2 SoC
sys.loadImage(bytes, 0x40800000);          // flat app image into HP SRAM
sys.setEntry(0x40800000);                  // enter at the image start
sys.onUartTx = function(b){ /* UART0 TX -> console */ };
sys.feedRx(byte);                            // keyboard -> UART0 RX FIFO
sys.step();                                  // execute exactly one instruction

We own the run loop so the debugger can drive it. Each frame runs a time-boxed budget of sys.step() (one RV32IMAC instruction each); breakpoints stop it by PC, write-watchpoints by bus address. Everything is plain JavaScript state:

MemberKindWhat it does
sys.step()methodFetch → decode width (16-bit compressed vs 32-bit) → execute one instruction, advancing pc; services a pending interrupt first. The single-step primitive.
sys.regs (Int32Array 32)fieldx0-x31 (x0 pinned to 0). sys.getPc()/setPc() and sys.csrObj (mstatus/mtvec/mepc/mcause/mie/mip/…) complete the programmer's model — all readable and writable.
sys.mem.sram / .flash / .lpramfieldThe real memories as typed arrays — read side-effect-free for the hex + disassembly views.
sys.read8/16/32, sys.write8/16/32methodThe bus, decoding the ESP32-H2 memory map. The write path notes watched addresses.
sys.rgb / sys.ledOn()field / methodThe live 24-bit colour the SoC decoded from the bit-banged WS2812 waveform on GPIO8 — polled each frame to draw the on-board RGB LED.
sys.feedRx(b)methodSerial RX in — the keyboard drives the mini-REPL through UART0.

Debugger integration

The plug-in (esp32h2-debug.js) describes the ESP32-H2 to the shared debugger and nothing more — the core is not patched:

  • Reused decoder. The core runs RISC-V, so the existing /debugger/src/cpus/riscv.js disassembler (RV32I + M + the C compressed forms) is reused as-is under the display name "RISC-V RV32IMAC (ESP32-H2)". No new decoder was written.
  • Registers are read live each refresh: x0-x31 with their ABI names, the pc, and the machine CSRs (mstatus, mtvec, mepc, mcause, mie, mip, mscratch, mtval, misa). Each has a set() that writes straight back into sys.regs / sys.csrObj.
  • Memory is exposed as three chips, all read side-effect-free directly off the typed arrays, each with its real base so the disassembly lines up with PC: HP SRAM at 0x40800000 (320 KB, unified I+D bus, disassembled), XIP flash at 0x42000000 (disassembled), and LP SRAM at 0x50000000. The peripheral window is deliberately not a chip, because reading the UART FIFO pops a byte — memory reads stay side-effect-free.
  • Single step is one sys.step(). Breakpoints are host-side checks of the PC (in the running code chip's offset space, so a click in the disasm gutter halts) run instruction-by-instruction when any are set. Write-watchpoints are a set the SoC's write path checks, pausing the loop the moment a watched bus address is written.

Architecture

The Espressif ESP32-H2 (2023) is a low-power Bluetooth LE 5 + IEEE 802.15.4 (Thread / Zigbee) microcontroller built on a single 32-bit RISC-V core — notably it has no WiFi (that is the sibling ESP32-C6):

  • RISC-V RV32IMAC — one 32-bit core at up to 96 MHz implementing the I base, the M (multiply/divide), A (atomics) and C (compressed) extensions, with machine-mode CSRs, a trap unit and an interrupt matrix. This emulator implements all four extensions, the CSR/trap machinery and a functional interrupt matrix from scratch.
  • Memory — 320 KB on-chip HP SRAM, reachable from both the instruction and data bus at the same address 0x40800000 (unified); code also executes in place (XIP) from external SPI flash mapped at 0x42000000; a small 4 KB LP (RTC) SRAM sits at 0x50000000. All are at their real hardware addresses.
  • On-board RGB LED — the ESP32-H2-DevKitM-1 fits an addressable WS2812 RGB LED on GPIO8, driven through the GPIO block at 0x60091000. Firmware bit-bangs the 800 kHz one-wire waveform; this model decodes the colour straight from the real GPIO edge timing (the same NeoPixel decode used by the Circuit Playground Express / Feather boards).
  • Serial — UART0 at 0x60000000 is the console the ROM bootloader and apps log to; its TX FIFO drives the serial panel and its RX FIFO is fed by the keyboard.

The default is MicroPython v1.29.0, running unmodified. The emulator models the ESP32-H2 mask ROM (the addresses come from the public linker scripts; no ROM code is involved) and boots the real ESP-IDF + FreeRTOS: clock and PLL bring-up over the analog I2C master, the ROM's esp_flash and spi_flash_mmap layers over the flash image, the ROM heap, soft-float and C library, the interrupt matrix and systimer, and the FreeRTOS scheduler, reaching a live Python >>> prompt. Flash behaves as NOR flash in memory, so on first boot MicroPython formats its littlefs filesystem and writes boot.py; files last across resets until the page reloads. The timer groups back machine.Timer, and the RMT transmitter backs neopixel, whose pulses are decoded onto the on-board LED. Also bundled is original CC0 machine code (RGB / rainbow / mini-REPL / hello), compiled freestanding (clang --target=riscv32 -march=rv32imac). Because it is all real machine code on the real memory map, every instruction single-steps in the debugger.

Honest limits. The Bluetooth LE and 802.15.4 radios have no RF: their register windows are RAM-backed, so no packets move, and bluetooth.BLE().active(True) never returns. machine.lightsleep() and machine.deepsleep() also do not return, because the power-management unit is not modelled (the Reboot button recovers). The chip reads back a blank MAC address, I2C and SPI hardware have nothing attached, and ADC readings are noise. Timing is instruction-approximate, not cycle-exact: Python's clocks are consistent with each other, but idle time passes faster than real time. The board has no on-board audio, so this emulator is naturally silent.