Tips for Using AI to Write Embedded Firmware

AI tools have quickly become part of many developers’ workflows. If you’re coming from a hobbyist background or transitioning into a professional embedded role, it can feel like a shortcut: you describe what you want, and code appears almost instantly.

However, embedded systems are not the same as writing a quick script or even a web app. You’re often working with constrained memory, real-time requirements, hardware peripherals, and safety or reliability constraints.

I’ve found that the most useful way to think about AI in firmware development is as an eager junior engineer. It can move fast and is great at getting started. However, it can also misunderstand requirements, miss edge cases, and suggest things that look right but fail in subtle (and sometimes dangerous) ways.

The goal becomes AI deliberately as a way to accelerate your development cycles rather than avoiding altogether.

AI as a Prototyping Accelerator

One of the most powerful uses of AI in embedded work is rapid prototyping.

For example, I recently used AI to help prototype a person detection demo on a Renesas RA8P1. There are a lot of moving parts in something like that: camera input, preprocessing, model inference, and output handling. AI was incredibly useful for helping scaffold pieces of that pipeline and suggesting how to glue them together.

Was the output production-ready? Not even close. But it got me from “blank screen” to “something running” much faster than starting from scratch. It helped find tricky bugs and get to a working demo quickly so that I could focus on describing the process on camera.

Some examples where this shines:

  • Generating initial project structure
  • Suggesting how to connect components
  • Filling in boilerplate code
  • Exploring different approaches quickly

If you treat AI as a way to explore ideas and reduce setup friction, it can save you hours (or days) of work.

Filling in the Gaps

Another place I’ve found AI helpful is implementing small, well-scoped pieces of functionality. For example, I’ve used it to help stub out an I2C driver in embedded Rust. However, it can also get you into trouble.

AI doesn’t know your exact hardware configuration, timing constraints, interrupt model, or how your system handles errors. It might assume blocking behavior where you need non-blocking, or ignore edge cases like bus contention or clock stretching.

So while AI can give you a strong starting point, you still need to:

  • Clarify requirements and constraints
  • Cross-check against the datasheet
  • Verify register settings
  • Confirm timing and error handling behavior

In other words, treat the output as a draft. Always check the AI output to make sure the implementation details are correct. Think of it like doing a code review with a junior engineer.

AI for Unit Tests

Writing good tests is time-consuming, and it’s often one of the first things developers skip when they’re under pressure. AI can help here by:

  • Suggesting test cases you might not have considered
  • Generating test scaffolding
  • Helping mock interfaces or peripherals

I’ve found it particularly useful for functions with well-defined inputs and outputs. You can ask AI to enumerate edge cases, boundary conditions, and failure modes, and then use that as a starting point for your test suite.

That said, the same rule applies: verify everything. AI-generated tests can be incomplete, redundant, or even incorrect. But as a brainstorming partner, it’s incredibly effective.

The Risk Spectrum: From Vibe Coding to Full Verification

It’s helpful to think about using AI as a spectrum. On one end, you have what people sometimes call “vibe coding”: you describe a problem, copy the output, and trust that it works. This can be fast, but it’s also high risk (especially in embedded systems, where failures can be silent, intermittent, or hardware-dependent).

On the other end, you have a more disciplined approach: you write most of the code yourself, use AI selectively, and verify everything. This is slower, but much lower risk.

Most of us will operate somewhere in between. Early in a project (especially during exploration) it’s reasonable to lean more toward speed. As the system matures and requirements become stricter, you should move toward verification and rigor. The key is being intentional about where you are on that spectrum at any given time.

Where AI Falls Short

There are a few areas where AI consistently struggles in embedded development.

The first case is hardware context. AI doesn’t have access to your actual board, your wiring, or your electrical constraints. It can’t “see” that a pin is misconfigured or that a pull-up resistor is missing. It can suggest code that looks correct but doesn’t match your hardware setup.

Second, AI can struggle with real-time and concurrency concerns. Embedded systems often rely on interrupts, RTOS scheduling, and precise timing. AI can generate code that ignores race conditions, priority inversions, or timing deadlines.

Third, we have resource constraints. It’s easy for AI to suggest solutions that are too heavy (e.g. too much RAM, flash, or CPU usage) because it’s drawing from examples that may not be optimized for constrained systems.

Finally, AI might know about best practices for your particular device, framework, environment, or use case. AI has seen a lot of code, but not all of it is good. It might suggest patterns that are outdated, unsafe, or not aligned with your project’s requirements for robustness and security. You should always understand the context, constraints, standards, and best practices for your project and use cases so that you are capable of writing good code. With that knowledge, you are better equipped to verify the AI’s output.

Why Fundamentals Still Matter

One of the biggest misconceptions about AI-assisted programming is that it reduces the need to understand the underlying system. In embedded development, the opposite is true. You should have a firm grasp of the fundamentals, such as peripherals, memory allocation, timing, concurrency, and the ability to read datasheets.

If you don’t have that foundation, it’s very easy to accept code that “looks right” but fails in subtle ways. And in embedded systems, those subtle failures can be the hardest to debug. AI can accelerate your work, but it doesn’t replace the need for engineering judgment.

Practical Tips for Using AI Effectively

If you’re just starting to incorporate AI into your firmware workflow, here are a few practical guidelines:

  • Use it to get started, not to finish. Let AI help you break through the blank page problem, but expect to refine and rewrite much of the output.
  • Keep your prompts specific. The more context you provide (target MCU, constraints, requirements), the better the output.
  • Always verify against primary sources. Datasheets, reference manuals, and known-good examples should take precedence over AI suggestions.
  • Test on real hardware. Simulations and static analysis are helpful, but nothing replaces running code on the actual device.
  • Ask it to explain its reasoning. This can help you spot misunderstandings and deepen your own understanding.
  • Use the AI to help generate context prompt (i.e. ask it to help generate a CLAUDE.md file for your project), which will help define your requirements and constraints

These habits help you get the benefits of AI while minimizing the risks.

Treat AI as a Teammate Rather Than a Replacement

At its best, AI feels like working with a fast, knowledgeable teammate who’s always available to help you think through a problem. Like any teammate (especially a junior one), it needs guidance, oversight, and review.

If you rely on it blindly, you’ll eventually run into problems that are hard to diagnose and even harder to fix. If you use it thoughtfully, it can dramatically improve your productivity and help you explore ideas more quickly.

In embedded systems, where correctness, reliability, and efficiency matter, that balance is everything. AI isn’t replacing firmware engineers anytime soon. But firmware engineers who know how to use AI effectively will have a clear advantage. The trick is learning how to sit in that middle ground: moving fast when it’s safe, slowing down when it matters, and always understanding the system well enough to know the difference.

4 thoughts on “Tips for Using AI to Write Embedded Firmware

  • I have also found it useful to occasionally ask the AI to provide citations usually for complex work or hardware specific tasks. It makes it easier to mark the AIs homework.

    Regards,
    Mark

  • To set the stage, I’m just a hobbyist when it comes to embedded, but my day job is mostly in enterprise software.

    I’ve been playing with a project for fun and to avoid a lot of manual work for testing what AI did I just offloaded it to my copilot:
    – connect a programmer to the board and tell the copilot how to use it (now it builds and flashes the board by itself).
    – I’m doing some audio signal to usb, so I connected the signal generator, and told the copilot what signal to expect on which port – and let it work.
    – installed USB monitoring tools and told the copilot how to use them to debug the usb problems by itself.
    – once signal in path was working, i told it to work on the usb audio out path, and wired the pin back to the input so it can test when the signal is being output and at correct amplitude and frequency.
    – connecting the oscilloscope to the computer was the other alternative, and let it use the protocol to capture signals.
    – A UART channel with the board helps the AI compile the firmware with test bits it can invoke for testing, or get logs.

    In conclusion: set a way for the AI agent to be able to test that the expected outcome is achieved. set guardrails and constraints so it does not solve the problem with a “creative” solution that defies the whole purpose.

    AI resurrected an old project of mine which I never managed to get working and I’ve spent at least a hundred hours on it. AI figured it out in less then 2 hours.

Leave a Reply

Your email address will not be published. Required fields are marked *