実機を使ったCI – Raspberry Pi 5 × GitHub Actions × STM32

一般的な CI/CD はアプリケーションソフトウェアを対象としていますが、組み込み開発のような低レイヤのソフトウェアでは、GitHub Actions だけでは対応しきれません。特に、マイコンのファームウェア更新のような処理は、実機を伴うためクラウド上の CI では完結しません。
本記事では、GitHub Actions と Raspberry Pi を例に、実機の組み込みLinuxを含めた CI 構築する方法を紹介します。これにより、低レイヤの開発でも自動化を導入し、開発の効率と信頼性を向上させることができます!
用意したもの
RaspberryPi
Github Actionsでトリガーされたジョブを実行します。
またそのジョブの中で、STM32のファームウェア更新をします。

STM32
今回ファームウェア更新される側です。

準備
UbuntuをインストールしたRaspberryPiの用意
GitHub Actions が sudo を求めるたびにパスワード入力を回避するため、パスワードなしで sudo を実行できるように設定 します。
sudo visudo
以下の行を追加
USERNAMEはRaspberryPiのユーザーネームです。
USERNAME ALL=(ALL) NOPASSWD: ALL
self-hosted runnerの設定
GitHub Actions のジョブを Raspberry Pi 上で直接実行するため、Self-Hosted Runner をセットアップします。
GitHub リポジトリの Settings → Actions → Runners に移動し、New self-hosted runner を選択。

RunnerのイメージにはLinux, ARM64を選択し, Download, Configureのコマンドを実行していきます.
- OS: Linux
- Architecture: ARM64
- 表示されたコマンドを Raspberry Pi で実行

run.shを実行すると, runnerが開始され, githubからのトリガーが来るのを待ち始めます.
GitHub Actions のログ
~/setup/actions-runner$ ./run.sh
√ Connected to GitHub
Current runner version: '2.321.0'
2025-01-19 02:43:25Z: Listening for Jobs
起動直後からサービスとして自動実行したい場合は、下記のコマンドを実行することで登録してくれます。
再起動後もRunnerを常に起動するには、以下のコマンドを実行
~/setup/actions-runner$ sudo ./svc.sh start
下記コマンドでサービスとしての実行状況を確認できます。active(running)であれば動作しています。
~/setup/actions-runner$ sudo ./svc.sh status
Self-Hosted Runner でジョブを実行
まず、GitHub Actions を設定して、Raspberry Pi 上で実行できることを確認しましょう。
.github/workflows/self-hosted-runner.yml
name: Test self-hosted Runner
on:
push:
branches: [ "main" ]
jobs:
build:
# Runner側のラベルに合わせて指定
runs-on: [ self-hosted, ARM64, raspi ]
steps:
# 1) ソースが必要ならチェックアウト
- uses: actions/checkout@v3
# 2) テスト用コマンドを実行
- name: Just echo something
run: |
echo "Hello from Raspberry Pi!"
uname -a
github actionsの設定ファイルにはruns-on: self-hostedを指定します.
以上の設定はHelloを出力するだけのサンプルソースですが, RaspberryPiで実行してくれます.
GitHub Actions のログ
CIが開始されると下記のように成功, 失敗の状態を表示してくれます.
2025-01-19 02:53:04Z: Running job: build
2025-01-19 02:53:21Z: Job build completed with result: Succeeded
STM32のファームウェア更新をして、テストをしてみる
次に、GitHub に .bin
ファイルを push すると、自動で STM32 のファームウェアを更新 するCIを構築します!
.github/workflows/update_firmware.yml
name: Update STM32 Firmware
on:
push:
branches:
- main
paths:
- "firmware/*.bin"
jobs:
update-firmware:
runs-on: self-hosted # Raspberry Pi の self-hosted runner で実行
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y stm32flash python3-gpiozero python3-serial
- name: Run firmware updater
run: |
BIN_FILE=$(ls firmware/*.bin | head -n 1)
echo "Using firmware: $BIN_FILE"
python3 updater.py --bin "$BIN_FILE" --device /dev/ttyAMA0 --baudrate 115200
GitHub に .bin ファイルを push すると、Raspberry Pi 上の Self-Hosted Runner が updater.py を実行し、STM32 にファームウェアを書き込みます。
GitHub Actions のログ
Run BIN_FILE=$(ls firmware/*.bin | head -n 1)
Using firmware: firmware/test.bin
Entering bootloader mode...
STM32 is now in bootloader mode.
Waiting for /dev/ttyAMA0 to be ready...
/dev/ttyAMA0 is ready.
Flashing firmware...
stm32flash 0.7
http://stm32flash.sourceforge.net/
Using Parser : Raw BINARY
Size : 11484
Interface serial_posix: 115200 8E1
Version : 0x31
Option 1 : 0x00
Option 2 : 0x00
Device ID : 0x0439 (STM32F301xx/F302x4(6/8)/F318xx)
- RAM : Up to 16KiB (6144b reserved by bootloader)
- Flash : Up to 64KiB (size first sector: 2x2048)
- Option RAM : 16b
- System RAM : 8KiB
Write to memory
Erasing memory
Wrote and verified address 0x08000100 (2.23%)
Wrote and verified address 0x08000200 (4.46%)
Wrote and verified address 0x08000300 (6.69%)
Wrote and verified address 0x08000400 (8.92%)
Wrote and verified address 0x08000500 (11.15%)
Wrote and verified address 0x08000600 (13.38%)
Wrote and verified address 0x08000700 (15.60%)
Wrote and verified address 0x08000800 (17.83%)
Wrote and verified address 0x08000900 (20.06%)
Wrote and verified address 0x08000a00 (22.29%)
Wrote and verified address 0x08000b00 (24.52%)
Wrote and verified address 0x08000c00 (26.75%)
Wrote and verified address 0x08000d00 (28.98%)
Wrote and verified address 0x08000e00 (31.21%)
Wrote and verified address 0x08000f00 (33.44%)
Wrote and verified address 0x08001000 (35.67%)
Wrote and verified address 0x08001100 (37.90%)
Wrote and verified address 0x08001200 (40.13%)
Wrote and verified address 0x08001300 (42.35%)
Wrote and verified address 0x08001400 (44.58%)
Wrote and verified address 0x08001500 (46.81%)
Wrote and verified address 0x08001600 (49.04%)
Wrote and verified address 0x08001700 (51.27%)
Wrote and verified address 0x08001800 (53.50%)
Wrote and verified address 0x08001900 (55.73%)
Wrote and verified address 0x08001a00 (57.96%)
Wrote and verified address 0x08001b00 (60.19%)
Wrote and verified address 0x08001c00 (62.42%)
Wrote and verified address 0x08001d00 (64.65%)
Wrote and verified address 0x08001e00 (66.88%)
Wrote and verified address 0x08001f00 (69.10%)
Wrote and verified address 0x08002000 (71.33%)
Wrote and verified address 0x08002100 (73.56%)
Wrote and verified address 0x08002200 (75.79%)
Wrote and verified address 0x08002300 (78.02%)
Wrote and verified address 0x08002400 (80.25%)
Wrote and verified address 0x08002500 (82.48%)
Wrote and verified address 0x08002600 (84.71%)
Wrote and verified address 0x08002700 (86.94%)
Wrote and verified address 0x08002800 (89.17%)
Wrote and verified address 0x08002900 (91.40%)
Wrote and verified address 0x08002a00 (93.63%)
Wrote and verified address 0x08002b00 (95.86%)
Wrote and verified address 0x08002c00 (98.08%)
Wrote and verified address 0x08002cdc (100.00%) Done.
Firmware flashed successfully!
Firmware update succeeded.
Running application...
STM32 is now running the application.
まとめ
この仕組みを導入すれば、リモートでのファームウェア管理が効率化され、製品の保守性も向上します!
Raspberry Pi を Self-Hosted Runner に設定
- GitHub Actions のジョブを Raspberry Pi で直接実行できる
- run.sh を systemd や svc.sh で自動起動可能
GitHub Actions を活用して STM32 の CI/CD
- .bin ファイルを push すると自動で Raspberry Pi に転送
- stm32flash で STM32 のファームウェアを更新