Edge AI & TinyML Architecture

While datacenter inference operates in a world of high-bandwidth memory (HBM3), 80-gigabyte VRAM pools, and kilowatt power supplies, the physical frontier of AI lives at the opposite extreme: Edge AI and TinyML.

TinyML is the technical discipline of running machine learning inference on ultra-low-power microcontrollers (MCUs)—such as ARM Cortex-M0+, Cortex-M4, Cortex-M7, ESP32, and RISC-V:

  • Compute Power: 40 MHz to 200 MHz single-core clocks.
  • Memory Envelope: 64 KB to 256 KB of SRAM (working memory) and 512 KB to 2 MB of Flash ROM.
  • Power Budget: Milliwatts or microwatts (operating on coin-cell batteries or solar energy for years without human intervention).
  • Zero Operating System: Bare-metal C++ execution without virtual memory, paging, or swap files.

This chapter details the systems architecture of microcontroller inference engines, zero-copy Flash execution, and memory planning algorithms.

Imagine trying to park an 18-wheel cargo truck inside a tiny one-car residential garage. That is what running deep learning on a microcontroller feels like.

If you bring the whole truck in, it simply won't fit. You have to disassemble the truck: take off the heavy steel parts, shrink the engine, and remove anything that isn't essential.

In TinyML, the 18-wheel truck is a convolutional neural network, and the one-car garage is a 128 KB microcontroller chip. We fit the model by converting all numbers to 8-bit integers (INT8), storing the blueprint on a chip that uses zero electricity (Flash ROM), and reusing a single piece of scratchpad paper for every calculation (the Static Tensor Arena).


1. The Microcontroller Memory Architecture

Explore the division between non-volatile Flash memory (ROM) and volatile SRAM:

Edge AI & Microcontroller Architecture
TinyML Memory Architecture: Flash (ROM) vs SRAM Tensor Arena
Memory Planning Model
Flash Memory (ROM) — Read Only110 KB / 512 KB
Model weights, quantized INT8 constants, and operator kernels execute directly in place (XIP - eXecute In Place). Consumes 0 bytes of SRAM!
SRAM Working RAM — Tensor Arena48 KB / 128 KB
Activation tensors share planned buffer offsets. Layer 3 immediately reuses memory vacated by Layer 1.
Activation Memory Offsets during “Layer 2: DepthwiseConv”Peak Arena Budget: 48 KB
Offset 0..24 KBINACTIVE / REUSABLE
Offset 24..48 KBACTIVE LAYER OUTPUT
Layer Input: 24 KB | Output Tensor: 24 KB | Flash Weights: 16 KB
Memory Strategy
Zero Dynamic Malloc
Pre-allocated single uint8_t[] buffer
Fragmentation Risk
0% Fragmentation
ZERO (Deterministic Memory)
Target Platforms
ARM Cortex-M4 / ESP32 / RISC-V
Battery & solar-powered sensory edge nodes
TinyML runs on microcontrollers with milliwatt budgets and zero OS. Dynamic malloc/free causes fatal heap fragmentation on embedded systems. TensorFlow Lite Micro uses a static Tensor Arena: model weights execute directly from Flash (ROM), while intermediate layer activations overlap and reuse SRAM offsets with zero dynamic allocation.

The Embedded Memory Split

In an embedded system, memory is divided into two physically distinct semiconductor technologies:

  1. Flash Memory (ROM, Non-Volatile):
    • Size: Typically 512 KB to 2 MB.
    • Speed: Moderate read speed (~30-50ns), zero standby power.
    • Purpose: Stores compiled firmware instructions, quantized INT8 weights, bias vectors, and graph topology.
    • XIP (eXecute In Place): The microcontroller reads weights directly from Flash via memory-mapped buses (SPI / AHB). Weights never enter SRAM!
  2. SRAM (Static RAM, Volatile):
    • Size: 64 KB to 256 KB total.
    • Speed: High-speed single-cycle access (~5ns), high static leakage current.
    • Purpose: Reserved strictly for mutable state: input sensor buffers (microphones, accelerometers, camera pixels) and intermediate layer activations.
Predict First
Why does calling malloc() and free() inside a microcontroller inferencing loop lead to device crashes (Hard Faults) after several hours, even when the total allocated bytes never exceed the 128 KB SRAM limit?

2. The Static Tensor Arena: Zero Dynamic Allocation

To eliminate heap fragmentation, TensorFlow Lite for Microcontrollers (TFLite Micro) allocates a single static byte buffer at initialization:

// Static allocation in global BSS segment -- zero heap malloc()!
constexpr int kTensorArenaSize = 60 * 1024; // 60 KB budget
alignas(16) uint8_t tensor_arena[kTensorArenaSize];

// Initialize TFLite Micro runtime
tflite::MicroInterpreter interpreter(
    model,
    resolver,
    tensor_arena,
    kTensorArenaSize,
    error_reporter
);

Offline Activation Lifetime Planning

Because the layer execution order of a neural network is deterministic, an offline memory planner computes the exact lifetime intervals for every intermediate activation tensor:

Layer Execution Timeline:
Layer 0 (Input):   [======== Lifetime ========]
Layer 1 (Conv):              [======== Lifetime ========]  (Reuses Offset A)
Layer 2 (Pool):                         [======== Lifetime ========]  (Reuses Offset B)
Layer 3 (Dense):                                   [==== Lifetime ====] (Reuses Offset A!)

Tensors whose lifetimes do not overlap are assigned the exact same byte offset inside tensor_arena. This buffer reuse reduces peak SRAM consumption by up to 75%, allowing models with 180 KB of total activations to execute inside a 48 KB arena!


3. System-Algorithm Co-Design: MCUNet & Depthwise Convolutions

Standard convolutional layers are computationally prohibitive on microcontrollers.

For a standard convolution with input channels CinC_{\text{in}}, output channels CoutC_{\text{out}}, and kernel size K×KK \times K:

FLOPsConv=H×W×Cin×Cout×K2\text{FLOPs}_{\text{Conv}} = H \times W \times C_{\text{in}} \times C_{\text{out}} \times K^2

In Depthwise-Separable Convolutions (MobileNet / MCUNet):

  1. Depthwise Step: Applies a single K×KK \times K spatial filter per input channel independently.
  2. Pointwise Step: Applies a 1×11 \times 1 linear projection across channels.

FLOPsSep=H×W×Cin×K2+H×W×Cin×Cout\text{FLOPs}_{\text{Sep}} = H \times W \times C_{\text{in}} \times K^2 + H \times W \times C_{\text{in}} \times C_{\text{out}}

Compute Reduction=HWCinK2+HWCinCoutHWCinCoutK2=1Cout+1K2≈19 of original compute!\text{Compute Reduction} = \frac{H W C_{\text{in}} K^2 + H W C_{\text{in}} C_{\text{out}}}{H W C_{\text{in}} C_{\text{out}} K^2} = \frac{1}{C_{\text{out}}} + \frac{1}{K^2} \approx \frac{1}{9} \text{ of original compute!}


4. Python Simulation: Microcontroller Memory Arena Planner

Run this live in-browser Python implementation to simulate how an offline activation memory planner assigns buffer offsets to minimize peak SRAM:

Run it yourself
class TensorBuffer:
def __init__(self, name: str, size_kb: int, start_step: int, end_step: int):
self.name = name
self.size_kb = size_kb
self.start_step = start_step
self.end_step = end_step
self.offset_kb = -1

def plan_memory_arena(tensors: list[TensorBuffer]) -> int:
# Greedy offline memory planner (TFLite Micro algorithm)
# Sort tensors by size descending to pack largest buffers first
sorted_tensors = sorted(tensors, key=lambda t: t.size_kb, reverse=True)
peak_memory_kb = 0
for t in sorted_tensors:
assigned_offset = 0
while True:
# Check collision with already placed tensors
collision = False
for placed in sorted_tensors:
if placed.offset_kb == -1 or placed == t:
continue
# Overlap in time?
time_overlap = not (t.end_step <= placed.start_step or t.start_step >= placed.end_step)
# Overlap in memory space?
t_end_offset = assigned_offset + t.size_kb
placed_end_offset = placed.offset_kb + placed.size_kb
mem_overlap = not (t_end_offset <= placed.offset_kb or assigned_offset >= placed_end_offset)
if time_overlap and mem_overlap:
assigned_offset = placed_end_offset
collision = True
break
if not collision:
t.offset_kb = assigned_offset

Embedded Deployment Rules
  1. Never allocate heap dynamically (malloc): Use static byte arrays in the BSS segment.
  2. Quantize to INT8 symmetrically: Eliminates cross-term corrections and allows single-cycle ARM Cortex-M DSP instructions (SMLAD).
  3. Keep Model Weights in Flash (XIP): Never copy weights into SRAM.
Next in Curriculum

Learn how modern accelerators fuse operators and eliminate memory roundtrips in Hardware Acceleration & Custom Kernels.

Last updated Oct 30, 2026Edit this pageReport an issue