DevOps and Agile methodologies have transformed software development by emphasizing collaboration, automation, and continuous improvement. Applying DevOps principles to my designs and projects has been a game-changer, enhancing efficiency and reliability. In this article, we’re going to walk through setting up a continuous integration (CI) workflow for an existing embedded systems project that uses the ATmega328P microcontroller. By the end of this article, you'll see how these practices can streamline your development process and deliver higher quality products.
DevOps is a set of practices, popularized by the software world, that bridges software development (Dev) and IT operations (Ops) into a continuous flow. In the software world, it used to be common to develop software and “throw it over the wall” to the operations folks for deployment to the customers. DevOps introduced a way to not only tear down that wall but automate the whole process end to end. In the hardware world we find similarities between product development and production, constantly throwing the design “over the wall” to our manufacturing engineering teams to ensure that everything is ready to go for production.
In embedded product design we still have to get our software through production but face the challenge of moving faster than ever and delivering at the highest quality possible. With DevOps principles we aim to solve some of those challenges.
By applying DevOps principles we’re able to iterate quickly using Agile methodologies within the build-test-deploy paradigm for each additional feature we wish to release to production.
“Build, test, and deploy” is a common set of words you’ll often hear when discussing DevOps. In embedded systems we do the same thing as our deployment also goes to production (and then the end customer). In the project’s repository we’re using Gitlab CI to drive our end-to-end workflow for Embedded DevOps. We use what’s called “pipelines” to create jobs that achieve certain tasks such as compiling the software, running tests on target, or releasing it as an official package. In Gitlab, a pipeline is a collection of jobs that run in a sequential flow like this:
Figure 1: Example pipeline used with the ATmega328P DevOps workflow in Gitlab
Here is a breakdown of the CI script (.gitlab-ci.yml file) to give you an idea of how this works.
There are some minor details that take this workflow from a barebones DevOps implementation to a smoothly running, well-documented and easily observed system. There are a few subtle details within the CI workflow that are important to point out.
if [ "$CI_COMMIT_REF_SLUG" == "$CI_DEFAULT_BRANCH" ]; then
export IMAGE_TAG=$CI_REGISTRY_IMAGE/$IMAGE_TYPE:latest
else
export IMAGE_TAG=$CI_REGISTRY_IMAGE/$IMAGE_TYPE:$CI_COMMIT_REF_SLUG
fi
This logic sets the stage for our “latest” tag to only use the Docker image built on the main branch (i.e. after a merge request successfully passes). This ensures that only successful merge requests publish the latest and greatest docker image that everyone and every pipeline pulls from.
Figure 2: Code coverage within a merge request
In this screenshot, Gitlab summarizes the tests run on the target using hardware in the loop:
Figure 3: Test summary for tests run on target
In the end, once our code has been validated both with unit testing and on target, the publish and release stages generate a nice package that can be consumed by the production team:
Figure 4: Software package release
With all these automated steps we can release a new feature iteratively in an Agile fashion. There is no need for developing many features, sending them to the QA department, and then a review for package release by the production team. Everything here happens in a single workflow and it’s completely automated.
In this article, we explored how DevOps and Agile methodologies can be applied to embedded systems development, specifically using the ATmega328P microcontroller. We discussed the benefits of implementing a CI workflow in Gitlab, which includes automation, faster build times, and efficient testing. By breaking down the CI script and explaining each stage, we showed how to create a robust and streamlined development process that increases efficiency and product quality. By following this practical guide (and the source code within the repository) you should be able to set up your own Embedded DevOps workflow as well.
The project’s source code can be found here:https://gitlab.com/embedded-designs/atmega328p-serial-led-control.