Embedded development is the field where the soldering iron and the IDE sit closest together. Naturally, AI has arrived here too: ask a model to write firmware and it produces tidy code. It compiles on the first try and flashes without errors. And then the screen shows colorful noise.
The code isn't the problem. The display uses an ST7789 controller designed for a 240×320 panel, but the glass on this board is cropped to 172×320. It's the same chip, but the visible pixels occupy only the central part of its memory. So the driver has to offset the drawing window by 34 pixels. Without that, the image shifts sideways, a third of the content ends up past the edge of the glass, and garbage creeps in from the other side. On top of that, the panel requires color inversion and big-endian byte order. None of this appears in any tutorial. It's tucked away in the vendor's wiki between two fine-print warnings, and the model never looked there.
Sound familiar? The problem isn't that LLMs are dumb. The problem is that knowledge about a specific board is spread thin across a gazillion-page datasheet, a Chinese-language manual from an AliExpress listing, and the evening of debugging you spent figuring it out. The model has none of that.
A Zoo of Silent Failures
-
Waveshare ESP32-C6-LCD-1.47: the display and the microSD slot share one SPI bus, with MOSI (GPIO6) and SCLK (GPIO7) in common. A model that doesn't know this will happily route them to separate buses and cause a bus conflict. That conflict looks like a bad contact or a dead memory card. -
Raspberry Pi Pico: GPIO23, 24, 25 and 29 are real GPIOs in code, but they aren't physically on the 40-pin header. A project using them compiles, flashes, and "works," yet nothing happens on the breadboard. You end up spending hours hunting for a firmware bug with bloodshot eyes. -
ESP32: ADC2 is fully taken over by Wi-Fi, and while the radio is active it just returns a timeout. A circuit with analog sensors on ADC2 fails without a single explanation, and there's no way to learn this from the code. -
STM32F411: clocking at 100 MHz instead of the required 96 MHz silently kills USB. Separately,HAL_Delay()hangs the board because someone was supposed to define SysTick_Handler manually, which is documented almost nowhere.
And plenty more...
How to Fix This
I've started building an open collection of skills for Claude Code, one skill per board. For now I'm adding the boards from my own collection (pictured above). A skill is a directory with a few files, and Claude Code loads it automatically when you work with the matching board. It contains only the knowledge the model lacks, organized in three layers:
SKILL.md is an always-loaded summary with the pin map, chip characteristics, and rules that prevent costly mistakes.
reference/ holds in-depth details that load on demand: the full pinout with alternate functions, peripherals, and a table of gotchas.
template/ is a fully working project that builds and flashes. Every line of the skill is extracted from it, not written from memory.
At its core, this is a missing-context problem. The agent knows microcontroller families reasonably well because it has seen the datasheets. But it knows nothing about your specific board: how the pins are routed, which clock configuration actually starts up, and which HAL calls silently fail. The idea behind the repository is to collect this knowledge from datasheets, vendor wikis, and hands-on debugging on real hardware, and package it into skills for agents. A web search MCP helps somewhat, but googling every little thing burns through context. You'll also pick up tutorials written for a different revision of the board.
The repository currently covers 8 boards: two STM32s, four ESP32s, the classic, universally loved Arduino Nano (ATmega328P), and the Raspberry Pi RP2040.
How to Use It
git clone https://github.com/alexex1993/mcu-skills.git
cd mcu-skills
./scripts/install.sh --list
./scripts/install.sh stm32f411-blackpill
From there, the skill is picked up automatically when you work with that board in Claude Code. You can also invoke it explicitly, e.g. /stm32f411-blackpill. To scope a skill to a single project, copy its directory into .claude/skills/ inside your firmware project.
You don't have to assemble a new project by hand. The template includes ready-made examples that make a convenient starting point.
Now, About Long-Running Projects
The real pain of embedded development is the months-long project whose architecture keeps growing. You have FreeRTOS with a pile of tasks, custom drivers, and sensors on three buses, all sharing pins, timers, DMA channels, and interrupts. At this point, knowing the context matters more than being able to write code.
The problem: the AI has amnesia, and you don't. Every session with the assistant starts from a blank slate. By week two of a project, you remember that Timer 2 drives the backlight PWM, SPI2 is shared by the display and the memory card, and A0/A1 are reserved for the analog front end. The model doesn't. So you either re-explain all of this in every conversation, spending half an hour on rituals before each task. Or you discover the conflict when a freshly generated driver quietly grabs a pin from a working module, and everything looks like it broke on its own.
A skill breaks this cycle because it lives in the repository, not in the chat:
Knowledge survives across sessions. Copy the skill into
.claude/skills/inside your project. Every new session, task, and question then starts from a knowledge base about the hardware instead of from zero.Knowledge is versioned alongside the code. The skill files live in git next to the firmware. Found a new gotcha in week six? Add a rule to the skill (you can ask the agent to do it) and commit. Now that knowledge is available to everyone on the team and to every new conversation. It no longer lives only in one person's head or in chat logs. It becomes a project artifact, just like the code.
Knowledge defines a contract with the hardware. A complex embedded architecture is, first and foremost, about dividing finite resources among modules. Conflicts over those resources are a special class of bug: the compiler doesn't catch them, and they show up far from their cause. The skill records what is used by what, so the model stops suggesting code that violates those assignments. In effect, it's a one-way interface between your architecture and the board, like an API, but for hardware.
Context is spent deliberately. A skill is structured like a nesting doll. The short summary is always loaded, and the heavy reference material is pulled in only when the task needs it. This matters on long projects, where your own code already fills much of the context. You don't drag in a massive datasheet; you bring in the answer to a specific question.
Onboarding gets faster, for both people and sessions. The agent reads the skill and does things the way the manufacturer intended in the datasheet.
An honest caveat: a skill stores knowledge about the board, not about your application's architecture. Project conventions live separately, in the repository's AGENTS.md. But the boundary falls exactly where it should. A skill is a contract with the hardware, and it can evolve with your project. Copy it in, add your own resource assignments and the gotchas you've found, and the knowledge base grows along with your firmware.
Plans and How to Help
I plan to keep adding boards and skills to the repository.
I'd love to have contributors. The pipeline is described in the repository:
Find the spec (the board's datasheet).
Build a hello world or a blinky that actually runs on the hardware.
Write a skill based on what you learned, or ask the agent to write it.
The best skills come from boards that have already burned you.



Top comments (0)