Architecture Overview
TikuOS is organized as a strict layered architecture, engineered from the ground up to run on microcontrollers with kilobytes of memory and microwatts of power budget. Every layer has a single responsibility, a small surface area, and a clear dependency direction: higher layers depend on lower layers, never the other way around.
The goal of this structure is three-fold: keep the kernel small enough to fit alongside application code on 2 KB SRAM parts, make porting to new silicon a matter of filling in one arch layer rather than touching the kernel, and let reusable library code (drivers, math, ML, networking) live outside the kernel without turning into a tangle of cross-cutting dependencies.
Layered Architecture
From top to bottom, the TikuOS stack looks like this. Each layer depends only on the layers beneath it.
End-user programs built as protothread processes. Includes the interactive shell (apps/cli), network stack user (apps/net), and any project-specific firmware. Apps link against TikuKits libraries and kernel APIs.
Optional, domain-specific libraries: sensor drivers, math, machine learning, signal feature extraction, networking, cryptography, data structures, codecs, text compression, and time. Each kit is namespaced under tiku_kits_<library>_* and pulls in only what the application enables.
Board-independent, index-based APIs for on-board resources. tiku_led_*, tiku_adc_*, bus adapters (I2C/SPI), 1-Wire, and wireless transports. Higher-level code talks to these interfaces; the interfaces dispatch to arch-specific backends at compile time.
The TikuOS kernel itself: cooperative process system, event queue, software and hardware timers, virtual filesystem, static memory allocators, watchdog, shell, FRAM-backed boot system. The kernel is platform-agnostic — it calls into the HAL for anything hardware-specific.
Thin header-only abstraction defining the contracts the kernel uses: clock, CPU, ADC, I2C, SPI, 1-Wire, memory, MPU, hardware timer, UART, watchdog, printf. Each HAL header names the functions an arch layer must provide.
Silicon-specific code that fulfills the HAL contracts. Device headers capture per-MCU constants (port map, memory size, crystal pins); board headers capture per-board GPIO assignments; the .c files implement the HAL using the MSP430 peripheral library. Adding a new variant requires only a device header, a board header, and a switch entry in tiku_device_select.h.
Low-power microcontrollers with FRAM non-volatile memory. Energy sources: coin cell, solar, thermal, RF harvesting, or sub-milliwatt beyond-backscatter radios.
Kernel Modules
The kernel is a small set of cooperating modules. None of them own a thread; instead, the scheduler drives the whole system with a single event loop. Every module is independently testable and most can be compiled out of the final image if the application does not need them.
Process System
Cooperative processes built on protothreads. Events are delivered via a single global queue; channels provide typed, fixed-size message passing between processes.
Scheduler
Top-level event loop. Checks expired timers, dispatches one event per iteration, and drops into a user-provided idle hook when there is nothing to do — that hook typically enters LPM.
Timers
Three layers: the free-running system clock, software timers (event or callback), and a single-shot hardware timer for ISR-precise firing.
Virtual Filesystem
A static tree that exposes peripherals, OS state, and processes as paths under /sys, /dev, and /proc. The shell and application code use the same API.
Memory
Static allocators: arenas, pools, persistent NVM key-value store, MPU protection, tier allocators, write-back cache, hibernate/resume. No heap.
Shell
Transport-agnostic interactive shell running as a kernel service. Backend can be UART, Telnet, or any pluggable I/O driver. Commands read and write VFS nodes.
Init System
FRAM-backed boot sequence. Entries are edited from the shell and survive power cycles, so the same firmware image can boot different services on different devices.
CPU & Watchdog
Watchdog configuration (timer or interval mode), blocking delays, LED helpers, and other miscellaneous HAL wrappers used across the kernel.
Event-Driven Runtime
TikuOS does not have threads in the traditional sense. It has processes — protothread functions that wait on events, react, and yield. All processes share the main stack, so a 2 KB SRAM part can host half a dozen processes without running out of memory.
The runtime is a single cooperative loop:
1. Check software timers; post TIKU_EVENT_TIMER for any that expired.
2. If the event queue is non-empty, dispatch one event to its target process.
3. If nothing is pending, call the idle hook (usually enters LPM3 or LPM4).
4. Interrupts (clock tick, UART RX, GPIO, radio) wake the CPU and may post
new events, restarting the loop from step 1.
The effect is that the CPU spends almost all of its time asleep. A typical sensor-logging device might wake up once per second, post a timer event, run a protothread for a few microseconds, and go back to sleep — consuming on average a few hundred microwatts.
How TikuKits Fit In
TikuKits is a separate repository of reusable library code that sits above the kernel but below the application. Kits have no privileged position in the system — they are ordinary C libraries that link against kernel and interface APIs. Splitting them out keeps the core kernel small and lets each library evolve independently.
Kits Overview
sensors/
Drivers for temperature, humidity, pressure, and light sensors — MCP9808, ADT7410, DS18B20, and more. Built on the interfaces/bus and interfaces/onewire layers.
maths/
Linear algebra (matrix/vector), fixed-point arithmetic, statistics primitives. Sized to run on 2 KB SRAM parts.
ml/
On-device machine learning — small inference kernels, feature pipelines, and classifiers that fit the memory budget of microwatt MCUs.
sigfeatures/
Signal-feature extraction: time-domain and spectral features used as ML inputs or for lightweight event detection.
net/
Networking stack: TCP, MQTT 3.1.1 client with optional TLS 1.3 PSK, HTTP primitives. Event-driven, no blocking.
crypto/
Symmetric primitives, hashing, and HMAC sized for MSP430-class targets.
codec/
Compact encoders/decoders — CBOR, base64, varint — for talking to clouds and other devices.
textcompression/
Lightweight text compression schemes suitable for constrained payloads (log shipping, telemetry, MQTT messages).
ds/
Static data structures: ring buffers, queues, bitmaps, hash tables — everything caller-allocated, no heap.
time/
Calendar and wall-clock helpers built on top of the kernel's free-running clock.
Naming and Layering Rules
- Every public identifier in a kit is prefixed
tiku_kits_<library>_. - Each top-level kit has a single common header (e.g.
tiku_kits_sensor.h) that defines shared types and return codes. Sub-modules include the parent and reuse those return codes. - Kits depend on kernel APIs and interfaces, never on other kits — keeping dependencies a tree, not a graph.
- The kernel does not depend on kits. A minimal firmware image can build with zero kits enabled.
Applications
The apps/ directory contains full applications shipped with the repository. Exactly one app, one test suite, or one examples build can be active at a time (selected via the APP= make variable).
| App | Description |
|---|---|
apps/cli | Legacy entry point for the interactive shell. Kept as a backward-compat shim — the shell itself now lives in kernel/shell/ and is enabled via TIKU_SHELL_ENABLE=1. |
apps/net | Networking application built on the TCP/MQTT kits. Demonstrates a full connectivity path from sensor to broker. |
User applications do not need to live inside apps/. A typical out-of-tree project adds its own process files, #include "tiku.h", and links against whichever kits it needs.
Hardware Abstraction
The HAL and arch layers are the reason TikuOS can run on several MSP430 variants without touching the kernel. The contract is a one-way interface:
hal/tiku_*_hal.hdeclares the functions the kernel uses (tiku_clock_hal_init(),tiku_adc_hal_read(), etc.). These headers are included by kernel and interface code.arch/msp430/tiku_*_arch.cimplements those functions against MSP430 peripherals. The.cfiles are device-agnostic: they use macros likeTIKU_DEVICE_HAS_LPM45andTIKU_BOARD_LED1_PORTthat are supplied by the device/board headers.arch/msp430/devices/contains one header per supported MCU (FR5969, FR5994, FR6989) with silicon constants.arch/msp430/boards/contains one header per supported board with pin assignments, LED count, and crystal configuration.arch/msp430/tiku_device_select.hroutes theTIKU_DEVICE_*define intiku.hto the correct device and board headers at compile time.
Porting to a new MSP430 variant requires adding one device header, one board header, and a single #elif branch in tiku_device_select.h. Porting to a new architecture (Ambiq Apollo, Nordic nRF54L, RISC-V) means adding a new arch/<name>/ tree that fulfills the same HAL contracts.
Boot Sequence
On reset, main() hands control to the boot code, which brings up the system in a deterministic sequence. Each stage is recorded in /sys/boot/stage so a post-mortem shell session can see how far the boot got.
1. init — earliest CPU setup; capture SYSRSTIV for /sys/boot/reason
2. cpu — clock tree, watchdog, MPU
3. memory — tiku_mem_init(): region registry, MPU activation, arenas
4. peripherals — HAL init for UART, timers, GPIO, ADC, I2C, SPI
5. services — tiku_clock_init(), tiku_sched_init(), tiku_vfs_tree_init(),
tiku_shell_init() (if enabled), tiku_init_run() (if enabled)
6. complete — tiku_sched_loop() takes over; autostart processes run
From the moment tiku_sched_loop() is entered, the system is event-driven: the CPU only wakes when there is work, and goes back to sleep as soon as the event queue is empty.
The TikuOS Ecosystem
Beyond the kernel and kits, the project ships a few supporting pieces that make development and research on microwatt devices practical:
Examples
Small, focused programs: blink an LED, read a sensor, publish to MQTT, run an ML inference. Each example is a complete firmware image that can be built and flashed.
Handbook
In-depth developer documentation: design notes, API reference, tutorials, and architecture decision records that go beyond the surface-level docs on this site.
Design Principles
- Static everything. No heap, no dynamic allocation. Every buffer is sized at compile time; memory use is auditable from a single linker map.
- Event-driven. No preemption, no blocking waits. Processes yield on events and the scheduler sleeps the CPU aggressively between them.
- Layer discipline. Kernel does not depend on kits or apps. Kits do not depend on each other. Arch layer is a one-way contract.
- Small surface area. Each module exposes the minimum needed to use it. Internal helpers stay internal.
- Observable by default. Every kernel subsystem surfaces its state through the VFS, so the shell can inspect a running system without special tooling.
- Configurable at boot. What starts on power-up is edited over the shell and stored in FRAM — one firmware image can run many configurations.
- Power-aware. Every design decision is evaluated against its impact on sleep-mode residency, because the entire reason TikuOS exists is to run on energy budgets that would starve a conventional RTOS.