Pengembangan firmware embedded seperti jam LCD sering kali menghadapi regresi build akibat perbedaan toolchain atau pembengkakan ukuran binary (ROM/RAM) yang melebihi kapasitas memori fisik mikrokontroler. Artikel ini membahas konfigurasi continuous integration (CI) menggunakan GitHub Actions dan PlatformIO Core CLI untuk memvalidasi multi-target board (ESP32 dan RP2040), menjalankan analisis statis C/C++, serta memverifikasi alokasi flash secara otomatis.

Struktur Proyek dan Konfigurasi PlatformIO Multi-Board

Untuk mendukung varian mikrokontroler tanpa redundansi kode, pisahkan konfigurasi board ke dalam environment terpisah di platformio.ini. Pendekatan ini memungkinkan kompilasi kode display driver yang sama untuk arsitektur Xtensa (ESP32) dan ARM Cortex-M0+ (RP2040).

[platformio]
default_envs = esp32dev, pico

[env]
framework = arduino
build_flags =
    -Wall
    -Wextra
    -DCORE_DEBUG_LEVEL=0
lib_deps =
    olikraus/U8g2@^2.35.9

[env:esp32dev]
platform = espressif32
board = esp32dev
board_upload.maximum_size = 1310720

[env:pico]
platform = raspberrypi
board = pico
board_upload.maximum_size = 2097152

Konfigurasi di atas menetapkan batas ukuran flash melalui properti board_upload.maximum_size. Flag -Wall dan -Wextra memastikan compiler menghasilkan peringatan ketat yang dapat diubah menjadi error jika diperlukan.

Pipeline GitHub Actions: Build Matrix & Static Analysis

Gunakan GitHub Actions matrix strategy untuk menguji setiap environment PlatformIO secara paralel. Pipeline di bawah menjalankan dua tugas utama: pemeriksaan kualitas kode menggunakan cppcheck dan kompilasi firmware via platformio run.

name: Firmware CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Cppcheck
        run: sudo apt-get update && sudo apt-get install -y cppcheck

      - name: Run Static Analysis
        run: |
          cppcheck --enable=warning,style,performance,portability \
                   --inline-suppr \
                   --error-exitcode=1 \
                   -I include \
                   src/

Flag --error-exitcode=1 memaksa proses CI gagal jika cppcheck menemukan isu kategori warning atau lebih tinggi. Pendekatan ini mencegah bug logika seperti uninitialized variables atau memory leak masuk ke repositori utama.

Verifikasi Batas Ukuran Flash Binary

PlatformIO secara default menampilkan tabel konsumsi RAM dan Flash saat build selesai. Namun, untuk integrasi CI yang ketat, kita perlu memvalidasi binary output (.bin atau .elf) terhadap alokasi partisi aplikasi secara terprogram.

  build:
    needs: lint
    runs-on: ubuntu-latest
    strategy:
      matrix:
        environment: [esp32dev, pico]
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          cache: 'pip'

      - name: Install PlatformIO Core
        run: |
          python -m pip install --upgrade pip
          pip install -U platformio

      - name: Cache PlatformIO packages
        uses: actions/cache@v4
        with:
          path: ~/.platformio
          key: ${{ runner.os }}-pio-${{ matrix.environment }}-${{ hashFiles('platformio.ini') }}
          restore-keys: |
            ${{ runner.os }}-pio-${{ matrix.environment }}-

      - name: Compile Firmware
        run: pio run -e ${{ matrix.environment }}

      - name: Assert Flash Size Limit
        run: |
          BIN_FILE=$(find .pio/build/${{ matrix.environment }} -name "firmware.bin")
          if [ ! -f "$BIN_FILE" ]; then
            echo "Binary not found!"
            exit 1
          fi
          
          SIZE=$(stat -c%s "$BIN_FILE")
          MAX_SIZE=1310720
          
          if [ "${{ matrix.environment }}" = "pico" ]; then
            MAX_SIZE=2097152
          fi
          
          echo "Firmware size: $SIZE bytes (Max: $MAX_SIZE bytes)"
          if [ $SIZE -gt $MAX_SIZE ]; then
            echo "Error: Firmware binary exceeds allocated flash size!"
            exit 1
          fi

Optimalisasi Kecepatan CI: Caching PlatformIO

PlatformIO mengunduh toolchain compiler (GCC Xtensa/ARM) dan framework core pada build pertama, yang dapat memakan waktu hingga beberapa menit. Direktori ~/.platformio harus di-cache menggunakan actions/cache dengan parameter key yang mencakup hash dari platformio.ini.

Catatan: Jangan menyertakan cache direktori build lokal (.pio/build) di dalam cache workflow, karena artefak kompilasi C/C++ incremental pada lingkungan ephemeral runner kerap menyebabkan bug kompilasi yang sulit dilacak.

Debugging dan Troubleshooting Kesalahan Umum CI

  • Runner Kehabisan Disk Space: Package Espressif32 cukup besar. Jika build gagal akibat storage, hapus toolchain yang tidak terpakai menggunakan pio system prune -f sebelum proses build baru berjalan.
  • False Positive pada Cppcheck: Makro Arduino seperti setup() dan loop() sering ditandai sebagai fungsi yang tidak digunakan. Tambahkan inline suppression comment pada source code: // cppcheck-suppress unusedFunction.
  • Ukuran Binary Berbeda antara Lokal dan CI: Periksa perbedaan versi platform package. Kunci versi framework di platformio.ini menggunakan syntax pasti, misalnya platform = espressif32 @ 6.5.0, untuk menjamin determinisme build.