Home Perception & Sensor Fusion On-Device Autonomy Operator Control Strategic Consulting Pilot to Production Forward-Deployed Engineering Symage Platform Defense, Aerospace & Space Industry 4.0 Medical Technology AgTech Proof Blog Solving For Tomorrow Podcast Company Careers News Speaker FAQ Talk to an Engineer →
← All Articles

What Six Months of AI Coding Taught Me About Embedded Systems

An engineer on six months of AI-assisted embedded development: where AI helped, where it built on wrong assumptions, and how to measure it.

An engineer reviews AI-generated code beside an AI chat panel, with a robotic arm and production line visible through the window behind the monitor

TL;DR: After six months using AI to help rewrite an industrial embedded system, I’d call the experience a win, with some important qualifications. It was useful for implementation, scripts, log analysis, and documentation, but it tended to build substantial amounts of code on the basis of erroneous assumptions which often missed the big picture. Understanding and validating that work took more effort than the speed of generation suggested.

What happens when AI does most of the coding?

A colleague described AI as “a software intern with encyclopedic knowledge and no wisdom.” After six months of developing almost entirely with AI, I understood what he meant. It could explain unfamiliar code in remarkable detail, then miss the consequences of a decision an experienced engineer would question.

I work on an industrial control system at a large company whose name you would recognize. Our team was using large language models and tools such as Kiro to convert software written in a domain-specific language into C++. We were effectively rewriting the existing software, with AI doing much of the implementation.

For most of that period, I barely opened a code editor. My work shifted toward directing the AI, evaluating its decisions, and investigating the problems we found along the way.

What kept catching me out was how quickly the AI could turn an assumption into an implementation. A feature might look complete while the actual design was a disaster. That gap showed up in everything from device documentation to architecture and real-time control.

How did a convincing AI answer send us in the wrong direction?

One investigation concerned a device with two distinct reset mechanisms. We needed to understand whether they accomplished the same thing or whether one cleared faults that the other didn’t. Someone estimated it would be a 15-minute investigation, which struck me as optimistic from the start.

My usual AI tool offered an explanation but couldn’t access the relevant manual. It suggested a manual part number it had found in a code comment, but that led nowhere. While searching, I encountered a Gemini answer that seemed much more promising.

Gemini explained, confidently and in detail, that the reset restarted the device’s firmware and required step-by-step reinitialization and coordination with the state machine. It sounded technically plausible, and I shared the explanation with colleagues.

There were warning signs. When I followed up, Gemini eventually recommended two web pages that clearly didn’t address the situation. I should have paid more attention to that, but the technical detail made the explanation seem more credible than the supporting evidence justified.

I then fed the Gemini answer into my usual AI tool, which identified contradictions I’d overlooked. That prompted me to examine logs from actual runs exercising the reset path. The device hadn’t performed a hard reset or anything resembling the sequence Gemini described. With no fault present, the reset was effectively ignored.

Eventually, I located the correct manual, and its description pushed our interpretation in almost the opposite direction. Even then, having already been burned, I wasn’t entirely comfortable declaring the question settled.

That investigation stayed with me because the wrong answer was so convincing. It gave us a coherent account of the device’s behavior, but checking that account against logs and documentation changed the conclusion substantially. Asking another model helped expose the problem; observing the system and finding the right manual gave us something firmer to work with.

What can AI miss when the code controls hardware?

The same reset feature also exposed an architectural problem. The operation began in the user interface, passed through coordinating middleware, and ended by setting a register bit through a network bus transaction. The AI implemented the hardware-specific reset logic in the middleware, even though that register operation belonged in the device driver.

It had followed the functional path without respecting the separation of responsibilities between layers. The implementation addressed the request, but the location of the code was wrong for our architecture.

Another feature exposed a more consequential omission. The AI called code from a non-real-time thread that acquired a mutex needed by a real-time thread. Although it had access to the source, it didn’t account for the contention, which disrupted hard real-time cycles and caused physical movement problems.

The call looked reasonable in isolation. Understanding the problem required following the shared resource into the control loop and considering which thread needed the mutex, when it needed it, and what happened when it had to wait.

These experiences made me pay closer attention to the reasoning behind an implementation. For embedded software, reviewing the immediate function isn’t enough. You also need to understand where the operation belongs, what it can block, and how it affects behavior elsewhere in the system.

That becomes difficult when the AI produces complex code in a domain you don’t know well. I learned a lot from its explanations, but there were subtleties that still required human subject-matter expertise. Other reviewers faced similar gaps, so it could be hard for anyone to confidently vouch for all the logic.

We eventually used AI tools to explain AI-generated code in a more reviewable form. Those explanations helped, but they didn’t resolve the underlying question of whether we had enough domain knowledge to evaluate the design.

Why did apparently finished features keep turning into more work?

Some of the rework came from the AI reconsidering decisions it had already implemented. I called this the “Squirrel Effect.” There is a Speed Bump comic panel by Dave Coverly that illustrates this artfully; it shows a squirrel on the side of the road next to what would be a walk/don’t walk sign that reads instead, “Run. Freeze. Run again! Run. Freeze. Run again! Turn around. Run! No, freeze!”

Watching a reasoning session can be amusing as the model goes down one road, then exclaims, “Wait…” then reverses course, perhaps going back and forth several times. When that happened before implementation, it could be useful to see the uncertainty. When it happened after a feature was built, it was more frustrating. Testing would reveal a problem, I’d bring it back to the model, and it would acknowledge an incorrect assumption before proposing a fundamentally different design.

Human developers change their minds too. What made this challenging was the amount of code the AI could produce before we discovered that an assumption needed more investigation.

Other rework came from additions that seemed helpful but didn’t belong in the requirement. For a disk-space monitoring feature, we needed fixed warning and critical thresholds. The AI added environment variables to make those thresholds configurable, which I thought was useful, particularly for testing. The feature had to be removed because it didn’t fit the system’s conventions.

A similar issue arose when I asked the AI to monitor an upstream network connection and raise an alarm when it went down. It proposed an algorithm for deciding what “down” meant, and I accepted it without checking to ensure it addressed the requirement to preserve the previous system’s behavior.

The previous system’s behavior wasn’t documented, and the AI’s proposed algorithm looked reasonable. But preserving that behavior required checking how the existing system actually detected a lost connection before accepting the new implementation.

There was also a tendency toward continual refinement. The model would suggest another abstraction or configuration option, and because it could generate the change quickly, the addition seemed inexpensive. But every improvement still became code we had to understand, test, and maintain. “You’re not gonna need it” applies just as much when AI is doing the typing.

Automated review added its own complications. Our CI/CD analysis caught genuine bugs, including subtle ones, but it also raised findings that seemed immaterial or offered feedback that wasn’t especially useful. I’d fix three issues and resubmit, only to receive three unrelated findings that hadn’t appeared in the previous round.

Something accepted in one round could be challenged in the next. Each review could send the implementation in a new direction, leaving me to decide which findings warranted changes and when the code was ready to move forward. The review caught real bugs, but working through successive rounds of findings often took hours.

Where did AI consistently make development easier?

Some of the clearest wins came from smaller tasks with a specific purpose and a result I could check directly. One day, I needed to terminate an application within five seconds of a particular log line appearing. The logging was voluminous, so manually testing that behavior wasn’t practical.

I asked the AI to write the script, and it worked well, giving me a practical way to test behavior I couldn’t reliably check manually. I also used it to build a larger script to retrieve and analyze AWS data for a specific task, along with development tools that became part of my regular workflow.

Log analysis was another area where it earned its place. The AI could work through large amounts of output, identify patterns, and suggest useful leads for root-cause investigation. It occasionally pursued an unproductive theory, so I still needed to check its conclusions, but it usually helped me make progress.

We also used it extensively for documentation, tickets, and diagrams. Its first attempt could be too verbose or introduce terminology that wasn’t clear. Giving it a specific audience improved the result considerably. Asking for an explanation suitable for management, for example, often turned a dense technical account into something useful.

When I encountered unfamiliar code, I used AI to trace the logic, examine dependencies, and work through questions as part of my own analysis. Even summarizing the day’s work for timesheet notes saved effort.

These uses were less ambitious than having AI implement a feature across multiple software layers, but they made a practical difference. They reduced the work involved in understanding, investigating, and documenting the system.

How should a team judge whether AI coding is helping?

The speed of code generation was easy to see. The effort required to establish confidence in that code was less visible, and that affected expectations on our team.

AI could produce an implementation quickly, even in parts of the system that required specialized knowledge. Reviewing the design, checking its assumptions, and validating its behavior still took substantial work, sometimes consuming the time I thought we’d saved.

We were expected to deliver software at hypersonic speed, but I often felt we needed more time to verify what the AI had built. That was the hardest part of the experience for me: an implementation could look ready while questions about how it would behave, especially when interacting with the hardware, were still unresolved.

I’d still call those six months a win. AI helped me understand unfamiliar code, build useful tools, and handle routine work. It also taught me to examine a complete-looking solution more carefully, particularly when the underlying assumptions hadn’t been checked.

If your team is expanding its use of AI-assisted software development, take one recently completed feature and trace the work from the original requirement through implementation, review, corrections, and observed behavior. Look at where AI saved effort, where it created more work, and which decisions required an experienced engineer.

Use what you find to shape the next feature’s workflow, giving engineers time to resolve the questions that matter before the code moves forward. The payoff is getting to software you can confidently ship sooner.

What do engineers commonly ask about AI-assisted software development?

Is AI useful for embedded software development?

Yes. In this project, AI helped with implementation, development scripts, log analysis, documentation, and code explanation. Hardware behavior, architectural boundaries, and real-time interactions required careful human review and independent verification.

Can AI review AI-generated code?

AI can explain generated code and identify potential bugs. In our workflow, automated review also missed issues or produced inconsistent findings between submissions. Its feedback was useful alongside human domain expertise and tests of actual system behavior.

How should teams measure AI coding productivity?

Measure the total effort needed to deliver a validated change, including implementation, review, investigation, corrections, and testing. Also consider whether the team understands the resulting code well enough to maintain it.

Related: autonomy and decision software · operator control and real-time execution

Want more from Geisel engineers in your Google results?

Add Geisel as a preferred source on Google

Have a hard problem?
Let’s talk.

Talk to an Engineer →