Table of Contents
Introduction
Buoyed by my recent success with using Google’s Gemini AI to assist me in creating some I2C driver code for an MCP23017 IC (view the blog here), I wanted to see if this was a complete fluke or whether Gemini could actually reliably help accelerate code development by trying it out with another random sensor. Would it work with something a little more complicated, perhaps?
Of course, I was also dying to test out Google’s recently launched Gemini Code Assist extension for VS Code, which provides a more integrative and immersive experience.
So, I had a browse around the den and found an accelerometer carrier board from Pololu (still in its packaging, unused). The carrier board used an STMicroelectronics LSM303DLM 3-axis accelerometer and 3-axis magnetometer sensor, which after all these years had become obsolete. Still, I felt this was a great use case as there are different versions of this sensor on the market, which require unique settings for the sensor to work, and multiple I2C addresses can be used for the accelerometer and the magnetometer has its own I2C address. On the positive side, the sensor is well documented and there is also plenty of open-source code out there for other microcontrollers - just not for the RP2350.
However, before jumping straight in, experience kicks in. It's always well worth confirming that the sensor on the carrier board still actually works.
Validating that your sensor works
To validate sensor functionality, a standard approach I employ, and I suspect many others do as well, is to establish a test bed. I typically start with an Arduino UNO, or a similar board, and wire up the carrier. Then, I locate a relevant library with example code to check the sensor's output. Finding an open-source library is usually straightforward, especially with established sensors, making this my go-to method for initial verification.
This use case was certainly no different. All I had to do was search out and download a library for the LSM303 from within the Arduino IDE (I found two options), then find a suitable sketch and run. Within minutes I was relieved to see that the carrier board does still works.
Challenges switching to MCU of choice
I consistently find the next stage challenging, especially when a dedicated sensor library is unavailable for my target microcontroller SoC. Often, I an tempted or pressured to compromise due to time constraints, resorting to a less-than-ideal but familiar development platform.
This led me to wonder if AI could fundamentally change things for the better.
I wanted to see if it genuinely simplifies sensor integration or just adds another layer of potential headaches.
I hope this blog helps others kickstart a positive change in their own development methodologies.
AI assisted coding workflow
I’ll start with some spoiler alerts…
I got it to work, but it took a few iterations. Developing my driver code for the LM303DLM sensor was almost exclusively a cut and paste exercise.
My observations...
I've just discovered that this approach, where AI handles the majority of the coding process, is referred to as "vibe coding". This is a novel concept to me, as I had no prior experience with, or knowledge of, this term; I simply encountered it on social media: [Wikipedia link]
Anyway, I've now learnt, through this exercise, that the success of using AI-assisted coding to jumpstart a project hinges heavily on the precision of my prompts. Even subtle changes in wording can drastically alter the generated code. I also noticed inconsistencies in coding syntax, particularly with Pico functions for I2C initialization and verification.
When encountering compiler errors or subtle parameter issues—those the compiler misses—the speed of resolution depends significantly on my own sensor expertise. For instance, Gemini fabricated a Pico library function for I2C initialization, leading to a compilation failure. A bizarre error, indeed. However, after pointing it out, Gemini corrected it. Then, when the compiled code failed to work on the Pico, I had to explicitly request Gemini to consult the datasheet, which it did—an impressive feat! Subsequently, a manual review was necessary on my part to highlight the potential parameter error, requiring a further query to Gemini for further verification.
The truly remarkable aspect of AI is its ability to confirm my suspicions, by checking it's own responses. It then provided me with the corrected code.
Conclusion...
Ultimately, Gemini had failed to read the manuals… so it’s universal… no one ever reads the frigging manual!
Here's a detailed walk-through of my setup and embedded development process. Note, videos do not include audio.
Step 1: Installation and Sign-in
I began by installing the Gemini Code Assist extension for VS Code. Once installed, it was not immediately obvious about any login requirements or login screen. It was only that I noticed something new on my screen… at the bottom right of my VS Code screen was a new gold coloured diamond icon. Clicking on this icon opened up the Google Account login screen. This turns out to be a one-time procedure.
Step 2: Create Pico template code
I then generated some C template code for the Raspberry Pi Pico, using the Raspberry Pi Pico VS Code extension. As usual, I incorporated the necessary I2C and USB console access libraries. I also decided to experiment with the optional timer feature (out of curiosity), even though this wasn't necessary for the sensor driver.
Once the code was generated I then amended the code to reflect the I2C pins I had used to connect the sensor to the Pico on the breadboard. In my case, I used pins 16 and 17 for I2C0.
Step 3: Ask Gemini for driver template code
This is where things got interesting. I prompted Gemini for assistance, using this request syntax: "Create an I2C library for the LSM303DLM sensor to read acceleration and magnetometer data", and within seconds, it provided a response directly within VS Code.
Gemini had generated code for two new library files, namely, "lsm303dlm.h" and "lsm303dlm.c," along with modified code for my main file, "Pico2W_ReadMagAccelData.c". It also provided the necessary text amendments to the CMakeLists.txt file. Even though my template code had included some timer initialisation code and a repeating "hello_world" printf statement, these were both removed in the amended Pico2W_ReadMagAccelData.c code. So if you wanted to keep, don't block copy and paste.
After the code additions/amendments, Gemini then provided a "Explanation and Key Improvements" section, detailing the steps taken in a clear, bullet-point format. I found this quite helpful.
It's worth mentioning that when I didn't specifically request a library in my prompt request, Gemini always returned a modified main project file with the added or amended functions.
Step 4: Ask Gemini to solve problems with the code
In contrast to my previous blog, the driver library code generated by Gemini Code Assist failed to compile. Gemini had included this function check If (!i2c_is_enabled(i2c){}
, which resulted in the compilation error 'implicit declaration of function i2c_is_enabled()'.
I've learned from experience that if I get an 'implicit declaration' error, it almost always means that function or variable isn't in the SDK or the libraries I'm using. However, when prompting Gemini with the error message, it failed to properly check and returned another unworkable suggestion.
So, it's not just me. Even AI struggles to understand error messages. However, in this case I think it should have been fairly obvious.
It required an explicit prompt to check the SDK, before it acknowledged the error and provided a fix.
This solved the compile problem, but the code still did not work.
But, I did get a "sensor failed to initialise" error. Based on my experience, this typically indicates that this is an I2C address issue; however, definitive confirmation required reviewing the datasheets.
I was curious to see if Gemini AI would deduce the I2C address problem. However, the response received, merely highlighted the importance of precise phrasing, as Gemini merely confirmed that SA0 low address it had used was correct, rather than diagnosing the error.
I had to explicitly tell Gemini to check the datasheet before it spotted the error.
Then it finally produced some working code.
Closing remarks
I originally thought that the availability of open-source libraries for platforms like Arduino would be a significant advantage but when I did try (post these results) to get Gemini to port Arduino code across to the Pico 2 W it only introduced other errors (none of which I investigated). Hence, I was proven wrong in this instance.
Having only just begun exploring the potential of AI in embedded driver development, I'm already impressed by its possibilities. I can already see that with a well-documented SDK and a detailed sensor datasheet, AI tools like Gemini can make a significant improvement in developing drivers for sensors. And in this instance, the Raspberry Pi Pico's exceptional documentation makes it a particularly strong platform for leveraging these AI capabilities. Well done to Raspberry Pi. I'm sure they never imagined this benefit when they started.
All I can say is the future is very bright when it comes to productivity improvement. I estimated that this probably took me about 20 minutes in man effort (excluding some thinking time) to develop a new sensor driver for the RP2350 / Pico 2 W board. That is significantly quicker than anything I had done previously. The power comes not in how much code it provided, but in knowing just how much code to provide (all too often when porting any existing library across ourselves we include everything).
Truly remarkable.