Most people point an LLM at a microcontroller the same way they point it at a blog post: "write me a sketch that reads a DHT22 and posts to MQTT." It works — for about ten minutes. Then the servo jitters, the I2C bus hangs after the third sensor, and the model cheerfully rewrites the whole file instead of telling you that your pull-up resistors are missing.
The real fork in the road is not which model you use. It is whether you already have a board in front of you and what exactly is broken. If the project lives only in your head, you go spec-first: prompts that force the LLM to produce a pinout, a state machine and a sketch in that order. If the device already misbehaves, you go log-first: prompts that turn Serial output, bus scans and symptoms into a diagnosis instead of a rewrite.
Below are twelve prompts split across those two modes, with the failure modes each one is designed to catch. The same discipline that keeps CI pipelines honest (see the CI/CD Without Surprises) applies here: give the model constraints and evidence, not vibes.
Mode A — Spec-first: from a task to a sketch that survives contact with hardware
1. The pinout contract before a single line of code
Task: stop the model from inventing pins that collide with your board.
Prompt:
You are an embedded engineer. Board: ESP32-WROOM-32 DevKit.
Task: read a DHT22 (temp/humidity) and drive one 5V relay.
Before any code, produce a table: signal, GPIO, reason for the choice,
and every ESP32 pin this signal MUST NOT use (strapping pins, input-only
34-39, pins used by flash). Flag any conflict with UART0.
Only after I approve the table, write the sketch.
Why it matters: the model's default is to pick GPIO2 or GPIO15 because they look nice in examples — both are strapping pins that change boot behavior. Forcing a table first makes the collision visible before it becomes a boot loop.
2. State machine instead of delay()
Task: convert a blocking tutorial sketch into a non-blocking one.
Prompt:
Refactor this sketch to a non-blocking state machine using millis().
List states, transitions and timeouts as a table first.
No delay() calls in the result. Show the loop() body.
Example result: states IDLE → READ_SENSOR → PUBLISH → BACKOFF, with a 2s sensor timeout and a 30s backoff on MQTT failure. The loop() becomes a switch over state plus one if (now - lastRead > INTERVAL).
3. Protocol-specific prompt for I2C/SPI/UART setup
Task: get the bus parameters right the first time.
Prompt:
For an SSD1306 over I2C on ESP32: give the Wire.begin() call with
SDA/SCL pins, the address, the clock speed, and explain what happens
if two devices share address 0x3C. Then show a bus scan sketch that
prints every responding address.
Example result: Wire.begin(21, 22); Wire.setClock(400000); plus a scan loop from 1 to 126 printing hex addresses. The explanation of the address collision is the part most tutorials skip — and it is exactly why the second OLED never lights up.
4. Power and level-shifting audit
Task: catch the 3.3V/5V mismatch before the magic smoke.
Prompt:
My ESP32 (3.3V logic) drives this 5V relay module and reads a 5V sensor.
List every wire, state whether a level shifter or divider is required,
and give the resistor values if a divider is needed. Show the math.
Example result: a divider for a 5V signal into a 3.3V input: 10k and 20k give 5 × 20/(10+20) ≈ 3.33V, which is safe. The model shows the arithmetic, so you can check it instead of trusting it.
5. Library and version pinning
Task: avoid the "works on my machine" of the Arduino world.
Prompt:
For this sketch, list every library with the exact version you assume,
and the board core version (ESP32 core). Where the API differs between
major versions (e.g. WiFi vs WiFiClient changes), note it explicitly.
Why it matters: a sketch that compiles against one core version fails on another with errors that look unrelated to the change. Pinning versions in platformio.ini or the Library Manager is the embedded equivalent of a lockfile.
Mode B — Log-first: when the board is already misbehaving
6. The Serial log autopsy
Task: turn a wall of Serial output into a ranked hypothesis list.
Prompt:
Here is the full Serial output from boot to hang, plus the sketch.
Do not rewrite the code. Produce: (1) the last healthy line,
(2) three ranked hypotheses with the evidence line for each,
(3) one test per hypothesis that costs under a minute.
Example result: last healthy line is I2C scan: 0x3C found; hypotheses are a watchdog reset, a blocking while(!client.connected()) loop, and a brownout on the relay coil. Each gets a one-minute test — comment out the relay, add esp_task_wdt logging, replace the while with a timeout.
7. The reset-loop detector
Task: distinguish a crash from a reboot from a hang.
Prompt:
This log shows the boot banner repeating. Identify the reset reason
from the ESP32 reset codes in the log, and tell me which of these it is:
panic, watchdog, brownout, or software restart. Cite the exact line.
Example result: rst:0xc (SW_CPU_RESET) plus a Guru Meditation Error line points to a panic in application code, not power. The distinction matters: chasing brownout when it is a null pointer wastes an evening.
8. Bus-level diagnosis for I2C/SPI/UART
Task: find out why a device does not answer.
Prompt:
My I2C scanner finds nothing. Walk me through, in order:
pull-ups, wiring, address, clock speed, and power.
For each, give the measurement or test that confirms or rules it out.
Example result: pull-ups first (many breakout boards omit them; the bus needs them somewhere), then continuity, then a scan at 100kHz instead of 400kHz. The order is the value — checking the address before the pull-ups is the classic wasted hour.
9. Symptom-to-protocol mapping
Task: translate a vague complaint into a bus-level question.
Prompt:
Symptom: the SPI display shows garbage after 10 minutes of running.
Map this to likely causes on SPI (clock too high, long wires, missing CS
timing, power droop). Give one change per cause and the expected effect.
Example result: drop SPI clock from 40MHz to 20MHz and shorten the jumper wires; if the garbage interval doubles, it is signal integrity, not the library.
10. Protocol decoder prompt for UART
Task: read raw bytes instead of guessing.
Prompt:
Here are the raw bytes my UART receives in hex. The device datasheet
says frames start with 0xAA and end with a checksum. Decode the frames,
verify the checksum, and tell me where framing breaks.
Example result: the model splits frames at 0xAA, computes the checksum, and reports that frame 4 fails — which points to a baud-rate mismatch or a missed byte, not a protocol error.
The trade-off nobody mentions
Spec-first gives you clean, reviewable code but costs you the evidence — the model designs against your description, and if the description is wrong the sketch is confidently wrong. Log-first gives you grounded diagnosis but costs you the overview — you fix symptoms one at a time and can miss that the architecture caused them.
The non-obvious move: run both, in this order. Write the spec prompt first to get a pinout and state machine, then paste the real logs back and ask the model to compare its design against the evidence. The gap between what it designed and what the board reports is usually the bug. The same detective discipline that works on web DevTools traces — see the LLM detective prompt set — applies to a Serial monitor.
What to keep in your prompt kit
| Mode | Prompt | Catches |
|---|---|---|
| Spec | Pinout contract | Strapping-pin collisions |
| Spec | State machine refactor | Blocking delay() bugs |
| Spec | Bus setup | Address and clock errors |
| Spec | Power audit | 3.3V/5V mismatch |
| Log | Serial autopsy | Wrong root cause |
| Log | Reset detector | Crash vs power |
| Log | Bus diagnosis | Missing pull-ups |
| Log | UART decoder | Framing errors |
Start with one board, one sensor, one bus. Write the pinout contract, flash the sketch, then break it on purpose — pull a jumper, drop the clock — and run the autopsy prompt on the resulting log. That loop teaches more about embedded debugging than any tutorial, and it is exactly what an LLM is good at when you stop asking it to write and start asking it to reason.