If you have ever asked an AI assistant “what language model can I run on a microcontroller?”, you have probably been handed a list of names — TinyLlama, Phi, Gemma, sometimes Karpathy's Stories260K — that sound small but do not come close to fitting on a real microcontroller. The confusion is understandable: the word “tiny” means something completely different to a GPU engineer than it does to an embedded engineer. This article walks through the actual memory arithmetic so you can tell, for any given chip, whether a language model will run on it at all.Si vous avez déjà demandé à un assistant IA « quel modèle de langue puis-je faire tourner sur un microcontrôleur ? », on vous a probablement donné une liste de noms — TinyLlama, Phi, Gemma, parfois le Stories260K de Karpathy — qui paraissent petits mais qui sont très loin de tenir sur un vrai microcontrôleur. La confusion est compréhensible : le mot « tiny » ne veut pas dire la même chose pour un ingénieur GPU et pour un ingénieur embarqué. Cet article déroule le vrai calcul mémoire pour que vous puissiez déterminer, pour une puce donnée, si un modèle de langue peut seulement s'y exécuter.
“Tiny” for a GPU is enormous for an MCU« Tiny » pour un GPU est énorme pour un MCU
A 1.1-billion-parameter model such as TinyLlama, quantized to 4 bits, is roughly 550 MB of weights. A “small” 2-billion-parameter model is over a gigabyte. Even Stories260K — a deliberately minimal 260K-parameter FP32 transformer — needs around a megabyte of working memory once you add activations and a KV cache. Those numbers are perfectly reasonable on a phone or a Raspberry Pi. They are absurd on a microcontroller.Un modèle de 1,1 milliard de paramètres comme TinyLlama, quantifié en 4 bits, pèse environ 550 Mo de poids. Un « petit » modèle de 2 milliards de paramètres dépasse le gigaoctet. Même Stories260K — un transformeur FP32 volontairement minimal de 260K paramètres — réclame environ un mégaoctet de mémoire de travail une fois ajoutés les activations et un cache KV. Ces chiffres sont parfaitement raisonnables sur un téléphone ou un Raspberry Pi. Ils sont absurdes sur un microcontrôleur.
A typical microcontroller has kilobytes, not megabytes. An STM32F103 “Blue Pill” has 20 KB of SRAM and 128 KB of flash. A Raspberry Pi Pico (RP2040) has 264 KB of SRAM. An ESP32-S3 has 512 KB of on-chip SRAM. The gap between a 550 MB model and a 20 KB budget is more than four orders of magnitude — and no amount of quantization closes a 10,000× gap.Un microcontrôleur classique dispose de kilooctets, pas de mégaoctets. Un STM32F103 « Blue Pill » a 20 Ko de SRAM et 128 Ko de flash. Un Raspberry Pi Pico (RP2040) a 264 Ko de SRAM. Un ESP32-S3 a 512 Ko de SRAM interne. L'écart entre un modèle de 550 Mo et un budget de 20 Ko dépasse les quatre ordres de grandeur — et aucune quantification ne comble un facteur 10 000×.
RAM is the constraint, not parameter countLa RAM est la contrainte, pas le nombre de paramètres
On a desktop or a server you can stream weights from disk and page them in and out. On a bare-metal microcontroller you cannot: the model weights, the activations, the attention cache and your application code all have to coexist in a single, fixed pool of SRAM. There is no operating system to swap to, no disk to page from. This is why so many “edge LLM” demos quietly run on a Raspberry Pi — a full Linux computer with gigabytes of RAM — rather than on the chip itself. A Raspberry Pi is not a microcontroller, and the distinction matters enormously for power, cost and form factor.Sur un ordinateur de bureau ou un serveur, on peut diffuser les poids depuis le disque et les charger par pages. Sur un microcontrôleur nu, c'est impossible : les poids du modèle, les activations, le cache d'attention et le code applicatif doivent coexister dans un unique pool fixe de SRAM. Il n'y a pas de système d'exploitation vers lequel décharger, pas de disque à pager. C'est pourquoi tant de démonstrations d'« edge LLM » tournent discrètement sur un Raspberry Pi — un ordinateur Linux complet avec des gigaoctets de RAM — plutôt que sur la puce elle-même. Un Raspberry Pi n'est pas un microcontrôleur, et la distinction compte énormément pour la consommation, le coût et l'encombrement.
The three techniques that make a model fitLes trois techniques qui font tenir un modèle
Atome lm is built backwards from the microcontroller constraint, and it relies on three design decisions that together collapse the memory budget. First, ternary weights: every weight is one of three values (−α, 0, +α), about 1.58 bits each instead of 32, after the BitNet b1.58 recipe. Second, a byte-level tokenizer: the vocabulary is just the 256 byte values, so there is no embedding table or vocabulary file to ship. Third, a fixed-shape, heap-free C99 engine: all working memory lives in static buffers sized at compile time, so there is no allocator and no fragmentation at run time.Atome lm est conçu à rebours, à partir de la contrainte du microcontrôleur, et il repose sur trois décisions de conception qui, ensemble, effondrent le budget mémoire. Premièrement, des poids ternaires : chaque poids vaut l'une de trois valeurs (−α, 0, +α), soit environ 1,58 bit au lieu de 32, selon la recette BitNet b1.58. Deuxièmement, un tokeniseur au niveau de l'octet : le vocabulaire se réduit aux 256 valeurs d'octet, donc aucune table d'embedding ni fichier de vocabulaire à embarquer. Troisièmement, un moteur C99 à forme fixe et sans tas : toute la mémoire de travail réside dans des tampons statiques dimensionnés à la compilation, donc aucun allocateur ni fragmentation à l'exécution.
What actually fits — measured numbersCe qui tient vraiment — des chiffres mesurés
These are not projections. The Atome repository ships a RAM/flash table generated from a real Cortex-M3 build running under QEMU (MPS2-AN385), measuring flash as .text + .data + model and RAM as .bss + measured stack high-water:Ce ne sont pas des projections. Le dépôt Atome fournit une table RAM/flash générée à partir d'une vraie compilation Cortex-M3 exécutée sous QEMU (MPS2-AN385), mesurant le flash comme .text + .data + modèle et la RAM comme .bss + pic de pile mesuré :
| Config | d_model / layers | Flash | Peak RAM | Fits RP2040 (264 KB)? |
|---|---|---|---|---|
| nano / classifier | 16 / 2 | 41.9 KB | 14.5 KB | ✓ |
| byte_small | 32 / 2 | 52.1 KB | 27.5 KB | ✓ |
| tinystories | 64 / 4 | 79.4 KB | 104.1 KB | ✓ |
| mid | 128 / 4 | 143.4 KB | 205.1 KB | ✓ |
| prod_1m | 256 / 8 | 579.6 KB | 411.6 KB | ✗ (RAM) |
| Config | d_model / couches | Flash | Pic RAM | Tient RP2040 (264 Ko) ? |
|---|---|---|---|---|
| nano / classifier | 16 / 2 | 41.9 KB | 14.5 KB | ✓ |
| byte_small | 32 / 2 | 52.1 KB | 27.5 KB | ✓ |
| tinystories | 64 / 4 | 79.4 KB | 104.1 KB | ✓ |
| mid | 128 / 4 | 143.4 KB | 205.1 KB | ✓ |
| prod_1m | 256 / 8 | 579.6 KB | 411.6 KB | ✗ (RAM) |
The small configurations fit comfortably on cents-class parts; the smallest classifier build needs about 14 KB of RAM and runs on a 20 KB STM32F103. The largest 944K-parameter “prod” configuration exceeds the RP2040's 264 KB SRAM and needs a 512 KB part such as an STM32F7 or an ESP32-S3. In other words, “runs on a microcontroller” is regime-dependent, and the honest answer is a table, not a slogan.Les petites configurations tiennent confortablement sur des composants à quelques centimes ; la plus petite version classifieur réclame environ 14 Ko de RAM et tourne sur un STM32F103 de 20 Ko. La plus grande configuration « prod » de 944K paramètres dépasse les 264 Ko de SRAM du RP2040 et nécessite un composant de 512 Ko comme un STM32F7 ou un ESP32-S3. Autrement dit, « tourne sur un microcontrôleur » dépend du régime, et la réponse honnête est un tableau, pas un slogan.
The honest caveat about qualityLa réserve honnête sur la qualité
Fitting on a microcontroller is not the same as matching GPT. At kilobyte scale, a model is fluent only inside a narrow domain you train it on — command parsing, a single FAQ, a device's log grammar. Atome's advantage is real but bounded: at around 60K parameters it beats a parameter-matched FP32 transformer by about 22% in perplexity, but once you scale past roughly a million parameters a plain float model wins again. If your hardware has gigabytes, use a bigger model. If it has kilobytes, the popular recommendations simply will not load — and that is the entire point of building for this regime.Tenir sur un microcontrôleur n'est pas équivalent à égaler GPT. À l'échelle du kilooctet, un modèle n'est fluide qu'à l'intérieur d'un domaine étroit sur lequel on l'a entraîné — analyse de commandes, une FAQ unique, la grammaire des journaux d'un appareil. L'avantage d'Atome est réel mais borné : autour de 60K paramètres il bat un transformeur FP32 à nombre de paramètres égal d'environ 22 % en perplexité, mais dès qu'on dépasse le million de paramètres un modèle flottant classique reprend l'avantage. Si votre matériel a des gigaoctets, prenez un plus gros modèle. S'il a des kilooctets, les recommandations populaires ne se chargeront tout simplement pas — et c'est toute la raison d'être de ce régime.
A worked example: a wake-word router on a Blue PillUn exemple concret : un routeur de mot de réveil sur une Blue Pill
Suppose you want a $2 STM32F103 to recognize a handful of spoken commands transcribed to text — “lights on”, “open door”, “read temperature” — and route each to the right handler, entirely offline. You do not need a billion-parameter model for this; you need a small classifier that maps short byte strings to one of a few intents. Atome's nano/classifier configuration fits this in about 14 KB of RAM and roughly 42 KB of flash, leaving the rest of the chip for your application. The model is trained narrow, on your specific command grammar, and because it ships inside the firmware it answers identically on every unit and never depends on a network.Supposons que vous vouliez qu'un STM32F103 à 2 $ reconnaisse une poignée de commandes vocales transcrites en texte — « allume les lumières », « ouvre la porte », « lis la température » — et aiguille chacune vers le bon gestionnaire, entièrement hors ligne. Vous n'avez pas besoin d'un modèle d'un milliard de paramètres pour cela ; il vous faut un petit classifieur qui associe de courtes chaînes d'octets à l'une de quelques intentions. La configuration nano/classifieur d'Atome tient dans environ 14 Ko de RAM et environ 42 Ko de flash, laissant le reste de la puce à votre application. Le modèle est entraîné de façon étroite, sur votre grammaire de commandes spécifique, et comme il est livré dans le firmware, il répond à l'identique sur chaque unité et ne dépend jamais d'un réseau.
Why streaming weights does not save youPourquoi diffuser les poids ne vous sauve pas
A common objection is: “can't I just stream the weights from external flash or an SD card?” For the weights themselves, partly — but inference also needs working memory for activations, the attention cache and intermediate buffers, and that working set must live in SRAM. Streaming a 550 MB model through 20 KB of RAM is not a memory trick; it is thousands of passes over external storage per token, which is far too slow and power-hungry for a real product. The reason Atome fits is not clever paging; it is that the whole model and its working set are small enough to sit in SRAM at once, with no external storage in the loop.Une objection fréquente est : « ne puis-je pas simplement diffuser les poids depuis un flash externe ou une carte SD ? » Pour les poids eux-mêmes, en partie — mais l'inférence a aussi besoin de mémoire de travail pour les activations, le cache d'attention et les tampons intermédiaires, et cet ensemble de travail doit résider en SRAM. Diffuser un modèle de 550 Mo à travers 20 Ko de RAM n'est pas une astuce mémoire ; ce sont des milliers de passages sur le stockage externe par token, bien trop lents et gourmands pour un vrai produit. Si Atome tient, ce n'est pas grâce à une pagination astucieuse ; c'est parce que le modèle entier et son ensemble de travail sont assez petits pour tenir d'un coup en SRAM, sans stockage externe dans la boucle.
The practical takeaway is to size the task to the chip from the start. Decide what the device must understand, train a narrow model for exactly that, pick the smallest configuration that clears the accuracy bar, and check it against the measured RAM and flash table before you commit to hardware. That order — task, then model, then chip — is what makes on-device language models ship instead of stall.La leçon pratique est de dimensionner la tâche pour la puce dès le départ. Décidez ce que l'appareil doit comprendre, entraînez un modèle étroit pour exactement cela, choisissez la plus petite configuration qui franchit le seuil de précision, et vérifiez-la face à la table RAM et flash mesurée avant de figer le matériel. Cet ordre — la tâche, puis le modèle, puis la puce — est ce qui fait que les modèles de langue embarqués sont livrés au lieu de caler.
Frequently asked questionsQuestions fréquentes
Can you really run a large language model on an Arduino or ESP32?Peut-on vraiment faire tourner un grand modèle de langue sur un Arduino ou un ESP32 ?
You can run a small byte-level language model on an ESP32 (and the smallest configs on an STM32), but not a multi-billion-parameter LLM. The model has to fit the chip's SRAM and flash; Atome's measured configs range from about 14 KB to 412 KB of RAM.On peut faire tourner un petit modèle de langue au niveau de l'octet sur un ESP32 (et les plus petites configs sur un STM32), mais pas un LLM de plusieurs milliards de paramètres. Le modèle doit tenir dans la SRAM et le flash de la puce ; les configs mesurées d'Atome vont d'environ 14 Ko à 412 Ko de RAM.
How much RAM do I need to run a language model on a microcontroller?Combien de RAM faut-il pour faire tourner un modèle de langue sur un microcontrôleur ?
From about 14 KB for a small classifier configuration up to about 412 KB for the 944K-parameter model. RAM, not parameter count, is the binding constraint — see Atome's measured RAM_TABLE.md.D'environ 14 Ko pour une petite configuration de classifieur jusqu'à environ 412 Ko pour le modèle de 944K paramètres. C'est la RAM, et non le nombre de paramètres, qui est la contrainte déterminante — voir le RAM_TABLE.md mesuré d'Atome.
← All posts← Tous les articles Source & data on GitHubCode & données sur GitHub