SearchA-ZC › Calliope mini

Calliope mini

2017 Open source · MIT/CC0 Online

The Calliope mini v1, in the browser. A from-scratch Nordic nRF51822 (a 16 MHz ARM Cortex-M0) drives the real 5x5 LED matrix, the A and B buttons and the accelerometer, decoded from the on-chip peripherals exactly as on the hardware. It runs original bare-metal programs — a flashing heart, smiley buttons, dice-on-shake and a tilt dot — and the whole Cortex-M0 plugs into this site's shared debugger to single-step real Thumb instructions and read the live nRF51 memory map.

Honest scope: this runs genuine bare-metal programs, not the full MakeCode / MicroPython runtime, which needs interrupt and SoftDevice support the core does not yet have. The Calliope mini v1 has no on-board speaker, so it is naturally silent.

Visit the official Calliope mini site ↗

Runs on: Web browser

Calliope mini Online Emulator

Play Calliope mini using JavaScript directly in your browser.

Configurations

ConfigurationEmulatorMachineOSLegal
Matrix AnimationCalliope miniCalliope miniopenOpen ⛶
MicroPython: Flashing HeartCalliope miniCalliope miniopenOpen ⛶
RGB Colour CycleCalliope miniCalliope miniopenOpen ⛶
Buzzer MelodyCalliope miniCalliope miniopenOpen ⛶
ButtonsCalliope miniCalliope miniopenOpen ⛶

Chips

Notes

Embedding

This is a two-layer stack: a real ARM CPU core underneath, and a from-scratch nRF51822 + Calliope mini board on top. It loads real Cortex-M0 flash images and runs them on the actual on-chip peripherals — original bare-metal programs that drive the LED matrix, the on-board WS2812 RGB LED and the on-board loudspeaker.

  • 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. It is byte-identical to the canonical copy used across the site's ARM emulators.
  • 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. calliope-board.js maps FLASH/RAM/APB/GPIO at their real nRF51 addresses, decodes the matrix GPIO into the 5x5 display, decodes the bit-banged WS2812 waveform on P0.18 into a live RGB value, feeds the buttons on their GPIO pins, answers the accelerometer's TWI reads, and turns the TIMER2/GPIOTE/PPI speaker path into audio.
PieceKindWhat it does
Calliope.create(canvas)factoryBuild the ARM core + the nRF51 memory map + peripherals.
load(bytes) / reset()methodCopy the flat image into FLASH; reset loads SP/PC from the vector table.
runFrame() / genAudioFrame()methodStep ~120k instructions (the LED scan is integrated over the frame) and produce one video-frame of speaker audio.
setButton(id,down) / setTilt(x,y) / shake()inputDrive the button GPIO levels and the accelerometer X/Y/Z.
present()methodDraw the 5x5 red-LED display, the RGB LED and the speaker indicator.

Debugger integration

calliope-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 real reset address 0x00000000.
  • Single-step. Step calls transport.stepInsn, which advances the core exactly one Thumb instruction. PC and the registers update after each step.
  • 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), RAM (0x20000000), the GPIO port (0x50000000 — watch OUT/DIR/IN change as the matrix scans and the RGB line bit-bangs), and the APB peripheral block (0x40000000 — CLOCK, TWI0, TIMER0/1/2, GPIOTE, PPI, RNG).

Architecture

The Calliope mini is a German educational board — a close cousin of the BBC micro:bit v1 — built on the same Nordic nRF51822: a 16 MHz ARM Cortex-M0 with 256 KB flash and 16 KB RAM. On board: a 5x5 red LED matrix, two buttons (A and B), an on-board WS2812 RGB LED, an on-board loudspeaker (via the motor H-bridge), and a BMX055 accelerometer + compass on I2C. The board wiring below is verified against the Calliope mbed target PinNames.h and the calliope-mini/microbit-dal fork.

  • The 5x5 display is a 3x9 multiplexed matrix — wired IDENTICALLY to the micro:bit v1 (MICROBIT_SB2). Rows ROW1..ROW3 = P0.13/14/15 (source, HIGH); columns COL1..COL9 = P0.04..P0.12 (sink, LOW); the same (col,row)→(x,y) map. The board integrates the scan over each frame into the logical 25-LED image.
  • Buttons A = P0.17, B = P0.16, active-low with a pull-up. (Button B differs from the micro:bit's P0.26.)
  • On-board RGB LED (WS2812B) on P0.18. The program bit-bangs the one-wire 800 kHz waveform; the board measures the HIGH-pulse width (in executed instructions) to recover each bit and latches a 24-bit GRB colour on the long reset gap — the genuine WS2812 line protocol, decoded into one live RGB value.
  • On-board loudspeaker on the motor H-bridge (P0.29). The Calliope makes SOUND (unlike the micro:bit v1). A tone is generated the real nRF51 way: TIMER2 counts to its compare value (with the COMPARE0→CLEAR short for auto-reload), each compare event toggles the speaker pin through a GPIOTE task, wired by a PPI channel — so the pin emits a square wave at the note frequency. The board recovers freq = timer_clock / (2 × CC0) from the emulated registers and synthesises that square wave to the shared audio sink. See the Sound notes.
  • Accelerometer/compass — a BMX055 at I2C address 0x18 on TWI0 (SCL P0.19, SDA P0.20). It is high-level-emulated: real nRF51 TWI transactions return CHIPID 0xFA and the settable X/Y/Z from the on-screen tilt / shake controls.
  • Timing/entropy. CLOCK, the TIMERs and RTCs, GPIOTE, PPI, and the RNG are implemented; the radio is present but stubbed (no real RF).
  • Content. Four original CC0 bare-metal programs (matrix animation, RGB colour cycle, buzzer melody, buttons), compiled with clang for thumbv6m. No proprietary firmware is used.

Sound

Pattern S (authored synthesis) driven by the real nRF51 tone path. The Calliope mini's on-board loudspeaker sits on the motor H-bridge output P0.29. The nRF51822 has no dedicated PWM peripheral, so — exactly like the Calliope's own CalliopeSoundMotor driver — a tone is generated with TIMER2 + GPIOTE + PPI: TIMER2 runs at 1 MHz (PRESCALER 4) with a COMPARE0→CLEAR short so it auto-reloads every CC0 ticks; a GPIOTE channel is configured as a Task/Toggle on the speaker pin; and a PPI channel wires TIMER2's EVENTS_COMPARE[0] to the GPIOTE TASKS_OUT. The pin therefore toggles once per CC0 period, emitting a square wave.

The board's speakerFreq() follows that exact chain: it finds an enabled PPI channel whose TEP is a GPIOTE toggle-task on the speaker pin and whose EEP is a running TIMER2 compare event, then recovers freq = (16 MHz>>PRESCALER) / (2 × CC0). Each video frame genAudioFrame() renders that square wave with a persistent phase accumulator (so notes don't click), duplicated to L+R, at exactly Math.round(EmuAudio.sampleRate/60) interleaved-stereo Int16 samples, and pushAudio() pushes it to the shared EmuAudio sink. The pitch is correct because the frequency comes straight from the emulated CC0, not a fixed table.

The transport exposes the standard mute contract — setMute/isMuted delegate to EmuAudio — and it starts muted (browsers block audio before a gesture); the shell's Sound button unmutes from a real click. The "Buzzer Melody" program plays a recognisable tune so unmuting is immediately audible.