SearchA-ZC › Circuit Playground Express

Circuit Playground Express

2017 Open source · MIT / CC0 Has sound Online

Circuit Playground Express is Adafruit's 2017 round all-in-one learning board, emulated in the browser on a real Microchip SAMD21 (a 48 MHz ARM Cortex-M0+). It runs REAL bare-metal programs on the actual SAMD21 peripherals, with nothing faked: the 10 on-board NeoPixels are driven by the firmware bit-banging the 800 kHz WS2812 one-wire protocol on pin PB23 and the board decodes the real HIGH-pulse widths into 10 live RGB values, and the on-board speaker is reconstructed from the SAMD21 DAC. Buttons, the slide switch and the LIS3DH accelerometer over the real SERCOM I2C bus are all wired. Because the whole chip is ordinary JavaScript it plugs into the site's shared debugger: the real ARM disassembler, live r0-r15 and xPSR, side-effect-free memory at the real addresses, single-instruction step, execution breakpoints and write-watchpoints.

Circuit Playground Express at Adafruit ↗

Runs on: Web browser

Circuit Playground Express Online Emulator

Play Circuit Playground Express using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
Rainbow + SoundCircuit Playground ExpressCircuit Playground ExpressopenOpen ⛶
Music BoxCircuit Playground ExpressCircuit Playground ExpressopenOpen ⛶
ButtonsCircuit Playground ExpressCircuit Playground ExpressopenOpen ⛶
Tilt BallCircuit Playground ExpressCircuit Playground ExpressopenOpen ⛶

Chips

Notes

Embedding

This is a two-layer stack: a real ARM CPU core underneath, and a from-scratch SAMD21 + Circuit Playground Express board on top. It loads real Cortex-M0+ flash images and runs them on the actual on-chip peripherals — the bundled programs are genuine bare-metal firmware compiled with clang for thumbv6m, driving the real hardware paths, not a shim.

  • The CPU. cortex-m7.js executes Thumb. The real chip is a Cortex-M0+ (ARMv6-M); this core is ARMv7-M, a strict superset, so it runs the M0+ image unchanged.
  • Real reset. The image is a real flash image with the ARM vector table at 0x00000000: on reset the board loads SP from word 0 and PC from word 1, exactly like the silicon.
  • The board, in JavaScript. cpx-board.js maps FLASH/SRAM/PORT/APB at their real SAMD21 addresses, decodes the WS2812 waveform the program bit-bangs into 10 RGB NeoPixels, feeds the buttons/slide in on their GPIO pins, answers the accelerometer's SERCOM I2C reads, and reconstructs the DAC writes into audio.
PieceKindWhat it does
CPX.create(canvas)factoryBuild the ARM core + the SAMD21 memory map + peripherals.
load(bytes) / reset()methodCopy the flat image into FLASH; reset loads SP/PC from the vector table.
runFrame()methodStep ~120k instructions; decode the NeoPixel waveform and build one frame of audio.
setButton(id,down) / setSlide(on) / setTilt(x,y) / shake()inputDrive the button/slide GPIO levels and the accelerometer X/Y/Z.
present()methodDraw the round board with the 10-NeoPixel ring.

Debugger integration

cpx-debug.js reads window.EMU_BOOT and hands the shared debugger a genuine ARM Cortex-M0+ machine — the same core the program runs on, exposed instruction-accurately.

  • Registers. registers() reads r0-r12, SP, LR, PC, xPSR and the APSR flags N/Z/C/V live each refresh; each has a set() that writes straight back into the core's register file.
  • Disassembly. FLASH is decoded with the shared cortex-m7 decoder (the Thumb-2 disassembler; ARMv6-M is a subset), so the code window shows real ARM mnemonics at the reset address 0x00000000.
  • Single-step. Step calls transport.stepInsn, which advances the core exactly one Thumb instruction; watch the WS2812 bit-bang toggle the PORT OUT register on PB23 as you step through the NeoPixel driver.
  • Breakpoints & watchpoints. Execution breakpoints are a PC set the run-loop checks before each instruction; write watchpoints wrap the board's memory-write path and pause when a watched address is written. Both are real.
  • Memory map. Four chips read the real address space side-effect-free: FLASH (program, disassembled), SRAM (0x20000000), the PORT block (0x41004400 — watch the two GPIO groups' OUT/DIR/IN), and the APBC block (0x42000000 — SERCOM1 I2C + DAC).

Architecture

The Adafruit Circuit Playground Express is a round education board built on a Microchip SAMD21G18A — a 48 MHz ARM Cortex-M0+ with 256 KB flash and 32 KB RAM. Everything is on-board: 10 WS2812 NeoPixels in a ring, a speaker (class-D amp on the DAC), two buttons (A/B), a slide switch, and sensors (light, temperature, sound, and a 3-axis LIS3DH accelerometer).

  • NeoPixels (real WS2812 decode). The 10 NeoPixels hang off PB23 on a single one-wire bus. A program clocks them by bit-banging the WS2812 800 kHz protocol — each bit is a HIGH pulse (long = 1, short = 0) then a LOW gap, and a long LOW latches the frame. The board watches the PORT OUT edges on PB23, measures each HIGH pulse in executed instructions to recover the bit, packs 24 bits/pixel (G,R,B) and lights the 10 live RGB values. This is the genuine line protocol, decoded — not a framebuffer poke.
  • Buttons + slide. Button A = PA28, Button B = PA14 (active HIGH on the CPX — a press reads 1), slide switch = PA15. The page/debugger drive those input levels; the program reads them from the PORT IN register.
  • Speaker (real DAC path). The speaker is on A0 = PA02, driven by the SAMD21's 10-bit DAC. A program plays a tone by writing a square wave to DAC.DATA; the board timestamps those writes and reconstructs the exact waveform into audio (see the Sound note).
  • Accelerometer. An ST LIS3DH at I2C address 0x19 on SERCOM1. It is high-level-emulated: real SAMD21 SERCOM I2C-master transactions (write the register pointer, repeated-start read) return WHO_AM_I = 0x33 and the settable X/Y/Z high bytes from the on-screen tilt / shake controls, so tilt and shake drive real code.
  • Clocks. The SAMD21 PM/GCLK/SYSCTRL block is modelled enough to boot: the SYSCTRL PCLKSR ready bits read back ready and GCLK reports not-busy, so a clock bring-up spins through. The programs run on the default clock; the emulator's instruction rate is the time base.
  • Content. Four original CC0 programs: Rainbow + Sound (default), Music Box, Buttons, and Tilt Ball. No proprietary firmware is used.
  • Honest limits. The light, temperature and sound (microphone) sensors and the on-board IR are not modelled; the accelerometer is HLE'd (tilt/shake, not a full LIS3DH register model). The tone pitch is calibrated to the emulator's instruction rate rather than a literal 48 MHz.

Sound

Pattern S (authored): the Circuit Playground Express speaker is on the SAMD21 DAC (pin A0 / PA02), which drives an on-board class-D amp. There is no separate sound chip — the CPU is the synthesiser — so the board reconstructs audio straight from the DAC output.

  • Where the samples come from. A program plays a note by writing a square wave to DAC.DATA at 0x42004808 (high, delay, low, delay, …). The board timestamps every DAC write with the executed-instruction count, so it has the exact output waveform the firmware produced.
  • Reconstruction. Each video frame spans a known instruction range. The board resamples the recorded DAC transitions to exactly Math.round(EmuAudio.sampleRate/60) interleaved-stereo Int16 samples (centring the 10-bit DAC at mid-scale so silence is a flat 0 and a played square wave is a real AC tone), carries the DAC level across frame boundaries, and EmuAudio.push()es it. No frequency is inferred — the pitch simply falls out of how fast the firmware toggles the DAC.
  • Mute contract. transport.setMute/isMuted delegate to EmuAudio; it starts muted (browsers block audio before a gesture) and the Sound button unmutes from a real click. The slide switch in the program also gates the tone.
  • Caveat. Because the emulated instruction rate is the time base (not a literal 48 MHz), the tone pitch is calibrated to that rate — the default note lands near ~450 Hz.