Building a Firmware Image and Flashing a Device from a GitHub Workflow

Before running a system integration test on an embedded device, the device needs to be flashed with the firmware. Here’s how to do this from a GitHub Workflow.

First we need to checkout the firmware and build it. Checking out the project is easy with the checkout action from GitHub. Building it can be a little trickier, but if you have taken the time to Dockerize your build environment, building the project is also easy. Here’s an example Job for checking out and building a project using a Docker build environment.

build_firmware:
    name: Build firmware
    runs-on: ubuntu-20.04
    container:
      image: docker://lagerdata/devenv-cortexm:latest

    steps:
      - name: Checkout project
        uses: actions/checkout@v4
        with:
          fetch-depth: '0'
          submodules: 'recursive'

      - name: Build
        run: mkdir -p _build;cd _build;cmake .. -G Ninja;cmake --build .

The CMake build command mkdir -p _build;cd _build;cmake .. -G Ninja;cmake --build . is run inside the lagerdata/devenv-cortexm:latest Docker image so no setup has to be done on the GitHub runner itself.

Once the project is built we can flash our device using either the Lager CLI command lager debug flash or with a method from Lager’s Python library, dut.flash("path/to/image.hex").

CLI Command

build_firmware:
    name: Build firmware
    runs-on: ubuntu-20.04
    container:
      image: docker://lagerdata/devenv-cortexm:latest

    steps:
      - name: Checkout project
        uses: actions/checkout@v4
        with:
          fetch-depth: '0'
          submodules: 'recursive'

      - name: Build
        run: mkdir -p _build;cd _build;cmake .. -G Ninja;cmake --build .

      - name: Power Device
        run: lager supply V_IN enable --yes

      - name: Flash Device
        run: lager debug flash --hexfile _build/image.hex

In the above Workflow, we first power up the device using lager supply which allows us to control power to the device

And then we flash the image that was built in the previous step, image.hex.

Python

Or we could combine both those steps into a small python script:

from lager import lager
from lager.pcb.net import Net, NetType

power_net = Net.get('V_IN', type=NetType.PowerSupply) # Used to control power
power_net.enable() # Power the device
dut = lager.DUT() #Create a device under test object
dut.flash("_build/image.hex") #flash the device

Assuming this script is saved in the project as tests/flash.py you could then run

build_firmware:
    name: Build firmware
    runs-on: ubuntu-20.04
    container:
      image: docker://lagerdata/devenv-cortexm:latest

    steps:
      - name: Checkout project
        uses: actions/checkout@v4
        with:
          fetch-depth: '0'
          submodules: 'recursive'

      - name: Build
        run: mkdir -p _build;cd _build;cmake .. -G Ninja;cmake --build .
        
      - name: Power and Flash Device
        run: lager python tests/flash.py

And that’s it!

Reach out to learn more about Lager's hardware test automation platform.

Try One Month Free

hello@lagerdata.com