Documentation

Running kama on a microcontroller

kama's no-GC / RAII / transpile-to-C model is a natural fit for bare-metal MCUs: deterministic, no runtime, no allocator unless you ask for one. This guide shows how to turn a .kama program into firmware that boots on a Cortex-M — emulated (QEMU, no hardware needed) or on a real board.

The compiler does the language half; the board link (startup / vector table / linker script / vendor HAL) is toolchain work kept deliberately separate, so kama emits portable freestanding C and any C toolchain can finish the job. This directory (mcu/) bundles a reference startup + a board linker script + two thin scripts that wire the two halves into one command.

The two halves#

  1. kama → freestanding object. kama build --target embedded emits -ffreestanding -nostdlib C (no libc, no OS, main never returns, a weak kama_panic_handler) and stops at an object. Pass the Cortex-M triple to the C compiler with --cc (kama stays board-agnostic).
  2. object → bootable image. A C toolchain links that object against a startup (reset vector + .data/.bss init), a linker script (the chip's memory map), and a libc — producing a flashable/emulable ELF.

Turnkey: build + run under QEMU (no hardware)#

Everything below runs in the opt-in kama-mcu toolchain image (arm-none-eabi-gcc + qemu-system-arm; clang is in the base image):

tools/cdev build-image-mcu          # once — builds the kama-mcu image (kept separate so the base stays lean)

# build a kama program into a Cortex-M firmware ELF, then run it on an emulated core:
KAMA_IMAGE=kama-mcu tools/cdev exec sh -c '
  mcu/build.sh tests/embedded_blink.kama -o /tmp/blink.elf --qemu &&
  mcu/run-qemu.sh /tmp/blink.elf; echo "exit=$?"'          # -> exit=22 (the program'\''s result)

This proves the whole chain end-to-end with no board: kama → C → Cortex-M object → link (startup + vector table + linker script + newlib) → boots on the core → runs the real MMIO loop → exits with the right value.

Targeting a different board#

Two boards ship: lm3s6965evb (the reference, QEMU Cortex-M3) and microbit (QEMU nRF51822, Cortex-M0, no FPU — the soft-float proving board; on a no-FPU core the emitted float/double ops become compiler-rt/libgcc soft-float libcalls, exercised end-to-end by tools/check-softfloat.sh). To add another (real or emulated):

  1. Copy mcu/boards/lm3s6965evb/linker.ld to mcu/boards/<yourboard>/linker.ld and edit the two MEMORY origins/lengths to the chip's datasheet (e.g. STM32F103: FLASH 0x08000000/64K, RAM 0x20000000/20K). The sections are chip-independent.
  2. Add a case for the board in mcu/build.sh (its -mcpu + clang triple) and, for emulation, in mcu/run-qemu.sh (its QEMU machine). CPU/triple examples: Cortex-M0+ → cortex-m0plus / thumbv6m-none-eabi; Cortex-M4F → cortex-m4 / thumbv7em-none-eabi.

mcu/startup.c (the reset handler + vector table) is vendor-neutral and usually needs no change; a real board more often uses its SDK's startup instead — see below.

Real hardware#

kama emits portable C, so the practical path on a real board is to hand that C to the board's own SDK/toolchain (which already owns the correct startup, linker script, and clock/peripheral init). Two ways in:

Board-by-board:

If you flash a real board, the exact --cc flags, linker script, and flash command are the vendor SDK's — the kama side is just "produce the object / the .c, and call kama_main()."

Licensing (MIT-clean)#

kama is MIT (GOALS #8), and this MCU flow keeps user firmware and the kama distribution unencumbered:

So both your firmware and kama itself stay MIT-compatible; the only copyleft components are build/emulation tools whose licenses do not reach their output, confined to the opt-in image.

Edit this page on GitHub