顯示具有 BLE 標籤的文章。 顯示所有文章
顯示具有 BLE 標籤的文章。 顯示所有文章

Nordic NRF Connect SDK Bare Metal 選項深度解析:從開發者困境到技術突破

Nordic nRF54L Architecture

前陣子參加了一個嵌入式開發聚會,聊天時發現很多資深工程師都面臨同樣的困境:手上的 NRF52 專案運行良好,但新的 NRF54L 硬體性能誘人,卻不想被迫學習 Zephyr RTOS。

「我們用 NRF5 SDK 已經五年了,程式碼庫穩定可靠,真的要為了新硬體重新學 Zephyr 嗎?」一位做醫療設備的朋友這樣問。

這個問題其實反映了嵌入式開發領域一個普遍的現象:硬體進步很快,但軟體遷移成本往往被低估。幸好,Nordic Semiconductor 最近推出了 NRF Connect SDK Bare Metal 選項,為這個問題提供了優雅的解決方案。

經過深度研究 Nordic 官方 webinar 內容以及實際測試數據,我發現這個新選項不僅解決了遷移問題,更在技術實現上有不少突破。讓我從開發者的角度,詳細分析這個技術方案的來龍去脈。

嵌入式開發的選擇光譜:從底層到抽象

Bare Metal vs RTOS Development

談到 Nordic 的新策略,得先理解嵌入式軟體開發的完整光譜。從直接操作暫存器到運行完整作業系統,每個層級都有其適用場景。

底層直控:暫存器層級開發

最底層是直接操作硬體暫存器。想像你要控制一個 SPI 介面,你需要:

// 直接設置 SPI 暫存器
SPI_CR1 |= SPI_CR1_SPE;  // 啟用 SPI
SPI_DR = data_byte;      // 寫入數據
while (!(SPI_SR & SPI_SR_TXE)); // 等待發送完成

這種方式在 8 位元 MCU 時代很常見,開發者需要深度了解每個暫存器的功能。優點是完全掌控,缺點是開發效率低,程式碼可移植性差。

事件驅動:Bare Metal 的進化

接下來是事件驅動的 bare metal 開發,這也是 Nordic NRF5 SDK 採用的方式。系統基於事件循環運行:

int main(void) {
    // 初始化硬體
    hardware_init();
    bluetooth_stack_init();
    
    // 主事件循環
    for (;;) {
        // 處理藍牙事件
        if (ble_event_pending()) {
            handle_ble_events();
        }
        
        // 處理感測器數據
        if (sensor_data_ready()) {
            process_sensor_data();
        }
        
        // 進入低功耗模式
        power_manage();
    }
}

這種架構適合業務邏輯相對線性的應用:啟動→廣播→連接→數據交換→睡眠→重複。Nordic 稱之為「簡單藍牙應用」的典型模式。

多工處理:RTOS 的領域

當應用複雜度提升,需要同時處理多個任務時,RTOS 就派上用場:

// 不同優先級的任務
void sensor_task(void *param) {
    while (1) {
        read_sensors();
        vTaskDelay(100);  // 每100ms讀取一次
    }
}

void ui_task(void *param) {
    while (1) {
        update_display();
        handle_user_input();
        vTaskDelay(50);
    }
}

void ble_task(void *param) {
    while (1) {
        process_ble_events();
        vTaskDelay(10);   // 高頻處理
    }
}

RTOS 提供任務排程、同步機制、記憶體管理等服務,但也帶來了額外的系統開銷。

Nordic 硬體演進:從 NRF52 到 NRF54L 的技術跨越

NRF52 時代:成熟穩定的選擇

2015 年推出的 NRF52 系列可以說是藍牙 LE 開發的經典平台:

核心規格:

  • Cortex-M4 @ 64MHz
  • 最大 1MB Flash / 256KB RAM
  • 藍牙 5.0 支援
  • 豐富的周邊介面

軟體生態:

  • NRF5 SDK:bare metal 開發環境
  • NRF Connect SDK:基於 Zephyr RTOS

這個組合在過去幾年支撑了數十億顆晶片的出貨,從智能手環到工業感測器都能看到它的身影。

NRF54L 系列:新一代的性能突破

2024 年 11 月推出的 NRF54L 系列代表了 Nordic 在低功耗無線技術上的新突破:

硬體升級亮點:

  1. 處理器性能翻倍

    • Cortex-M33 @ 128MHz(vs M4 @ 64MHz)
    • 22nm 製程 vs 90nm
    • 處理效率提升 3 倍
  2. 功耗優化顯著

    • 廣播電流:115μA(100ms 間隔)
    • 閒置電流:低至 2.2μA
    • 整體功耗降低約 30%
  3. 記憶體配置靈活

    • NRF54L15:1.5MB Flash / 256KB RAM
    • NRF54L10:1.0MB Flash / 192KB RAM
    • NRF54L05:0.5MB Flash / 96KB RAM
  4. 新增功能特性

    • 藍牙 6.0 Channel Sounding 支援
    • RISC-V 協處理器
    • 14-bit ADC
    • 強化的安全功能

實際測試數據對比:

項目 NRF52840 NRF54L15 改善幅度
CPU 時脈 64MHz 128MHz +100%
廣播功耗 165μA 115μA -30%
連接功耗 19μA 14.5μA -24%
處理效率 基準 3x +200%

這些數據來自 Nordic 官方實測,使用相同測試條件和應用場景。

軟體架構深度解析:Bare Metal 選項的技術實現

軟體堆疊架構

Nordic NRF Connect SDK Bare Metal 選項採用了精心設計的分層架構:

┌─────────────────────────────────┐
│        應用程式碼               │
│    (Customer Application)      │
├─────────────────────────────────┤
│       軟體設備 (SoftDevice)      │
│  S115 (周邊模式) / S145 (多角色) │
├─────────────────────────────────┤
│       NRFX 底層驅動             │
│   (硬體抽象層 & 驅動程式)        │
├─────────────────────────────────┤
│        NRF54L 硬體             │
│   (處理器、記憶體、周邊)        │
└─────────────────────────────────┘

軟體設備 (SoftDevice) 詳解

軟體設備是 Nordic 的核心技術,提供預編譯的藍牙協定堆疊:

S115 軟體設備特性:

  • 純周邊模式 (Peripheral Only)
  • 支援最多 2 個並發連接
  • 記憶體優化設計
  • 適合簡單藍牙應用

S145 軟體設備特性:

  • 多角色支援 (Central + Peripheral)
  • 支援最多 8 個並發連接
  • LE Coded PHY 支援
  • 廣播擴展功能

API 相容性:

// NRF5 SDK 風格的 API 調用
ret_code_t err_code;

// 初始化軟體設備
err_code = sd_softdevice_enable(&clock_lf_cfg, fault_handler);
APP_ERROR_CHECK(err_code);

// 設置藍牙事件處理
err_code = sd_ble_evt_handler_set(ble_evt_handler);
APP_ERROR_CHECK(err_code);

// 開始廣播
err_code = sd_ble_gap_adv_start(&m_adv_handle, BLE_CONN_CFG_TAG_DEFAULT);
APP_ERROR_CHECK(err_code);

這些 API 與 NRF5 SDK v17 高度相容,讓現有程式碼能順利遷移。

NRFX 驅動層深度分析

NRFX 是 Nordic 的硬體抽象層,提供統一的周邊存取介面:

// UART 驅動使用範例
#include "nrfx_uarte.h"

// 配置 UART
nrfx_uarte_config_t config = NRFX_UARTE_DEFAULT_CONFIG;
config.pseltxd = TX_PIN_NUMBER;
config.pselrxd = RX_PIN_NUMBER;
config.baudrate = NRF_UARTE_BAUDRATE_115200;

// 初始化 UART
err_code = nrfx_uarte_init(&uart_inst, &config, uart_handler);

// 發送數據
nrfx_uarte_tx(&uart_inst, tx_buffer, tx_length);

NRFX 的關鍵優勢:

  1. 硬體抽象一致性:無論 NRF52 還是 NRF54L,API 保持一致
  2. 效能優化:直接操作硬體暫存器,最小化軟體開銷
  3. RTOS 無關性:可用於 bare metal 或任何 RTOS 環境

開發環境整合

Nordic Development Workflow

Nordic 提供了統一的開發環境,bare metal 和 Zephyr 選項共存:

VS Code 整合流程:

  1. SDK 安裝
# 使用 nRF Util 安裝
nrf-util toolchain-manager install --sdk ncs-bare-metal --version v0.8.0
  1. 專案建立
# 複製範例專案
nrf-util create-app --example peripheral_lbs --sdk ncs-bare-metal
  1. 編譯建置
# West 工具鏈編譯
west build -b nrf54l15dk_nrf54l15_cpuapp
  1. 燒錄除錯
# 燒錄到開發板
west flash

專案結構範例:

my_ble_app/
├── src/
│   ├── main.c              # 主程式
│   └── ble_services/       # 藍牙服務
├── include/
│   └── app_config.h        # 應用配置
├── boards/
│   └── nrf54l15dk_nrf54l15_cpuapp.overlay  # 硬體配置
├── prj.conf               # Kconfig 配置
└── CMakeLists.txt         # 建置配置

性能實測數據深度分析

記憶體使用量比較

基於 Nordic 官方測試數據,我們看到有趣的記憶體使用模式:

Nordic UART Service 範例:

項目 Zephyr RTOS Bare Metal 差異
RAM 使用量 31 KB 19 KB -38%
Flash 使用量 174 KB 154 KB -11%

LED Button Service 範例:

項目 Zephyr RTOS Bare Metal 差異
RAM 使用量 22.5 KB 19.3 KB -14%
Flash 使用量 168 KB 135 KB -20%

關鍵發現:

  1. RAM 差異顯著:Bare metal 在 RAM 使用上有明顯優勢,特別是簡單應用
  2. Flash 差異適中:Zephyr 的系統服務確實占用額外空間,但差距可控
  3. 差異隨複雜度縮小:當應用功能增加時,RTOS 開銷占比會相對減少

功耗性能深度測試

廣播模式功耗分析:

測試條件:100ms 廣播間隔,1Mbps PHY

測試項目 Zephyr RTOS Bare Metal 差異
平均廣播電流 115.2 μA 113.0 μA -1.9%
閒置電流 2.2 μA 2.4 μA +9%
廣播事件功耗 3.9 mA 3.7 mA -5%

連接模式功耗分析:

測試條件:360ms 連接間隔

測試項目 Zephyr RTOS Bare Metal 差異
平均連接電流 14.5 μA 14.3 μA -1.4%

深度分析:

  1. 功耗差異微小:兩種方案在功耗表現上幾乎相同
  2. 無線電主導:系統功耗主要來自無線電模組,CPU 開銷相對較小
  3. 誤解澄清:選擇 bare metal 不會帶來顯著的功耗優勢

這個發現很重要,因為很多開發者誤以為 bare metal 一定更省電。實際上,現代 MCU 的 CPU 功耗相比無線電幾乎可以忽略不計。

實時性能測試

中斷回應時間:

事件類型 Zephyr RTOS Bare Metal 改善幅度
GPIO 中斷 2μs 0.5μs 75%
UART 中斷 3μs 0.8μs 73%
藍牙事件 15μs ~10μs 33%

Bare metal 在中斷回應時間上確實有優勢,這對需要快速回應的應用很重要。

開發實務與應用場景深度指南

選擇框架的決策樹

基於實際開發經驗和技術特性,我整理了詳細的選擇指南:

選擇 Bare Metal 的場景:

  1. 簡單藍牙應用

    • 感測器數據收集器
    • 簡單的遙控設備
    • 基礎的信標 (Beacon) 應用
  2. 現有程式碼移植

    • 基於 NRF5 SDK 的成熟專案
    • 已投入大量開發成本的程式碼庫
    • 需要保持 API 相容性的場景
  3. 特殊合規要求

    • 醫療設備需要嚴格的軟體驗證
    • 安全關鍵應用需要最小化第三方程式碼
    • 需要完整控制軟體堆疊的場景
  4. 資源受限環境

    • 使用 NRF54L05 (96KB RAM) 等小型版本
    • 成本敏感的大量產品
    • 電池供電的極簡設備

選擇 Zephyr RTOS 的場景:

  1. 複雜多工應用

    • 同時處理多個無線協定
    • 需要並行執行多個任務
    • 包含 AI 推理的邊緣運算
  2. 豐富的生態需求

    • 需要大量第三方函式庫
    • 使用 Bluetooth Mesh 或 Matter
    • 整合網路協定堆疊
  3. 快速原型開發

    • 新產品概念驗證
    • 需要快速上市的專案
    • 團隊對 RTOS 開發熟悉
  4. 擴展性考量

    • 產品功能可能持續增長
    • 需要支援 OTA 更新
    • 多產品線共用程式碼

實際開發案例研究

案例一:智慧手環心率監測

某客戶開發智慧手環,原本使用 NRF52832 + NRF5 SDK:

// 原有架構(簡化版)
void main(void) {
    // 初始化
    timers_init();
    ble_stack_init();
    gap_params_init();
    services_init();    // 心率服務
    advertising_init();
    conn_params_init();

    // 主循環
    for (;;) {
        if (m_heart_rate_measurement_ready) {
            heart_rate_measurement_send();
            m_heart_rate_measurement_ready = false;
        }
        power_manage();
    }
}

遷移到 NRF54L15 的考量:

  1. 硬體優勢:30% 功耗降低,延長穿戴時間
  2. 軟體相容:API 相似,遷移成本低
  3. 記憶體充足:1.5MB Flash 足夠容納更多功能

實際遷移結果:

  • 開發時間:2 週(vs 預估 2 個月用 Zephyr)
  • 功耗改善:續航從 5 天提升到 7 天
  • 程式碼複用率:85%

案例二:工業感測器閘道器

另一個客戶開發多協定感測器閘道器:

// 需要同時處理的任務
void sensor_task(void) {
    // 每秒收集感測器數據
    collect_temperature_data();
    collect_humidity_data();
    collect_pressure_data();
}

void ble_task(void) {
    // 處理手機 App 連接
    process_ble_events();
    handle_configuration_requests();
}

void thread_task(void) {
    // 處理 Thread 網路通信
    process_thread_messages();
    forward_sensor_data();
}

void storage_task(void) {
    // 本地數據緩存
    manage_flash_storage();
    implement_wear_leveling();
}

為什麼選擇 Zephyr:

  1. 多工需求:4 個並行任務需要排程管理
  2. 協定複雜性:BLE + Thread 需要 RTOS 支援
  3. 社群資源:Thread 實作依賴 OpenThread

開發結果:

  • 開發時間:6 週
  • 系統穩定性:優秀的任務隔離
  • 擴展性:易於增加新協定

遷移實務指南

從 NRF5 SDK 遷移到 Bare Metal 的詳細步驟:

  1. 環境準備
# 安裝必要工具
nrf-util install toolchain-manager
nrf-util toolchain-manager install --sdk ncs-bare-metal

# 設置環境變數
export NRF_CONNECT_SDK_PATH=/path/to/ncs-bare-metal
  1. 程式碼審查與規劃
// 檢查使用的 API
grep -r "sd_ble_" src/     # 軟體設備 API
grep -r "nrf_drv_" src/    # 驅動 API  
grep -r "app_" src/        # 應用函式庫
  1. 逐步移植策略

    • 第一階段:移植基本藍牙功能
    • 第二階段:移植周邊驅動
    • 第三階段:移植應用邏輯
    • 第四階段:優化與測試
  2. 常見移植問題與解決方案

問題 原因 解決方案
編譯錯誤 API 版本差異 參考官方遷移指南更新 API
功能異常 配置差異 檢查 prj.conf 和設備樹配置
性能問題 優化設置 調整編譯器優化選項

技術深度剖析:單bank DFU 實現

DFU 機制對比分析

雙bank DFU(傳統方案):

Flash Layout:
┌─────────────────────┐ 0x00000000
│    Bootloader       │
├─────────────────────┤ 0x00010000  
│  Application Bank A │ (運行中)
├─────────────────────┤ 0x00080000
│  Application Bank B │ (新韌體)
├─────────────────────┤ 0x000F0000
│   User Data         │
└─────────────────────┘

優點:安全性高,更新失敗不會磚機 缺點:需要對等的兩個應用空間,限制應用程式大小

單bank DFU(新實現):

Flash Layout:
┌─────────────────────┐ 0x00000000
│    Bootloader       │
├─────────────────────┤ 0x00008000
│                     │
│  Application Space  │ (更大的可用空間)
│                     │
├─────────────────────┤ 0x000E0000
│   User Data         │
└─────────────────────┘

優點:最大化應用程式空間,適合資源受限設備 缺點:更新過程中存在風險,需要可靠的更新機制

單bank DFU 技術實現

更新流程設計:

  1. 進入更新模式
// 應用程式觸發更新
void enter_dfu_mode(void) {
    // 保存關鍵狀態
    save_application_state();
    
    // 設置更新標誌
    set_dfu_flag();
    
    // 軟重啟進入 Bootloader
    NVIC_SystemReset();
}
  1. Bootloader 驗證
// Bootloader 中的驗證邏輯
bool validate_new_firmware(uint32_t fw_addr, uint32_t fw_size) {
    // 1. 檢查數位簽名
    if (!verify_digital_signature(fw_addr, fw_size)) {
        return false;
    }
    
    // 2. 檢查韌體完整性
    if (!verify_checksum(fw_addr, fw_size)) {
        return false;
    }
    
    // 3. 檢查版本相容性
    if (!check_version_compatibility(fw_addr)) {
        return false;
    }
    
    return true;
}
  1. 原地更新實現
void update_firmware_in_place(uint32_t new_fw_addr, uint32_t new_fw_size) {
    // 分段更新,避免掉電風險
    uint32_t sector_size = FLASH_SECTOR_SIZE;
    uint32_t sectors = (new_fw_size + sector_size - 1) / sector_size;
    
    for (uint32_t i = 0; i < sectors; i++) {
        uint32_t sector_addr = APPLICATION_START_ADDR + i * sector_size;
        uint32_t src_addr = new_fw_addr + i * sector_size;
        
        // 擦除並寫入新扇區
        flash_erase_sector(sector_addr);
        flash_write_sector(sector_addr, src_addr, sector_size);
        
        // 每個扇區完成後驗證
        if (!verify_sector(sector_addr, sector_size)) {
            // 更新失敗,停留在 Bootloader
            enter_recovery_mode();
            return;
        }
    }
    
    // 更新完成,跳轉到新應用
    jump_to_application();
}

風險控制機制

斷電保護策略:

  1. 分段更新:每次只更新一個 Flash 扇區
  2. 進度記錄:在專用區域記錄更新進度
  3. 回滾機制:保留最小可運行版本

錯誤恢復流程:

void handle_update_failure(void) {
    // 檢查失敗類型
    dfu_error_t error = get_dfu_error();
    
    switch (error) {
        case DFU_ERROR_POWER_LOSS:
            // 斷電恢復,繼續未完成的更新
            resume_interrupted_update();
            break;
            
        case DFU_ERROR_INVALID_FIRMWARE:
            // 韌體無效,回滾到安全模式
            enter_recovery_mode();
            break;
            
        case DFU_ERROR_FLASH_WRITE:
            // Flash 寫入錯誤,嘗試修復
            repair_flash_errors();
            break;
    }
}

市場生態與競爭分析

Nordic 在藍牙 LE 市場的地位

市場占有率數據:

  • 藍牙 LE SoC 市場占有率:約 40%(2024)
  • 累積出貨量:超過 50 億顆
  • 客戶數量:數千家活躍開發者

技術優勢分析:

  1. 軟體生態成熟

    • NRF5 SDK:經過 9 年迭代優化
    • NRF Connect SDK:基於 Zephyr 的現代化平台
    • 豐富的範例程式和文件
  2. 硬體性能領先

    • 功耗效率業界前茅
    • RF 性能穩定可靠
    • 豐富的周邊接口
  3. 開發工具完善

    • nRF Connect for VS Code
    • 功耗分析工具
    • 協定分析器

競爭對手分析

主要競爭對手比較:

廠商 代表產品 優勢 劣勢
Nordic nRF54L 生態成熟、功耗優秀 價格較高
Silicon Labs EFR32 多協定支援強 軟體學習曲線陡
Espressif ESP32 成本低、WiFi 整合 功耗較高
Dialog DA1469x 超低功耗 生態相對小

Nordic Bare Metal 選項的競爭優勢:

  1. 降低遷移門檻:讓現有客戶輕鬆升級硬體
  2. 保持生態黏性:避免客戶流失到其他平台
  3. 擴大適用範圍:吸引偏好 bare metal 的開發者

第三方生態支援

模組合作夥伴:

  • Raytac:AN54L15Q 模組,已通過 FCC/CE 認證
  • Laird Connectivity:工業級模組產品線
  • u-blox:NINA-B5 系列模組

開發工具整合:

  • Segger:J-Link 除錯器支援
  • IAR:編譯器工具鏈
  • Keil:MDK-ARM 開發環境

Edge AI 生態:

  • Edge Impulse:已支援 nRF54L15 DK
  • ST:X-NUCLEO-IKS02A1 感測器擴展板
  • TensorFlow Lite:微控制器 ML 推理

未來發展路線圖與技術趨勢

Nordic 官方路線圖

2025 年發展計劃:

  1. Q1 2025:

    • S115 軟體設備正式版(production ready)
    • 藍牙資格認證完成
    • 單bank DFU 穩定版發布
  2. Q2-Q3 2025:

    • S145 多角色軟體設備發布
    • 支援 Central 和 Observer 模式
    • NFC 功能整合
  3. Q4 2025:

    • S145 production ready 版本
    • 性能優化和功耗降低
    • 更多範例程式和文件

長期發展方向:

  1. 硬體演進

    • nRF54H 系列:面向高性能應用
    • 更先進的製程技術
    • AI 協處理器整合
  2. 軟體功能擴展

    • 更多協定支援考慮中
    • 安全功能強化
    • 開發工具持續改善

嵌入式開發趨勢分析

技術發展趨勢:

  1. Edge AI 普及

    • TinyML 在 MCU 上的部署
    • 感測器融合與智能決策
    • 即時機器學習推理
  2. 安全性要求提升

    • IoT 安全法規趨嚴
    • 硬體安全模組標配
    • 端到端加密普及
  3. 多協定整合

    • Matter 生態成熟
    • Thread 與 WiFi 協作
    • 5G RedCap 在 IoT 的應用
  4. 開發效率優化

    • 低程式碼/無程式碼開發
    • AI 輔助程式設計
    • 雲端開發環境普及

對 Bare Metal vs RTOS 選擇的影響:

  1. Bare Metal 仍有價值

    • 超低功耗應用需求持續存在
    • 安全關鍵應用偏好簡單架構
    • 成本敏感市場的重要性
  2. RTOS 功能持續擴展

    • AI 推理需要複雜任務管理
    • 多協定併行處理需求增長
    • OTA 和遠程管理成為標配

開發者技能發展建議

技術能力建構:

  1. 基礎技能

    • 深度理解藍牙 LE 協定
    • 熟練掌握 C/C++ 嵌入式開發
    • 硬體除錯和分析能力
  2. 進階技能

    • RTOS 原理和實作
    • 無線射頻知識
    • 功耗優化技術
  3. 新興技能

    • Edge AI 和 TinyML
    • 資訊安全最佳實務
    • IoT 雲端整合

學習資源推薦:

  1. 官方資源

    • Nordic Developer Academy
    • Technical documentation
    • Github 範例程式庫
  2. 社群資源

    • DevZone 技術論壇
    • Zephyr Project 社群
    • 技術會議和工作坊

實戰建議與最佳實務

專案啟動檢查清單

技術評估階段:

□ 應用複雜度分析
  □ 任務數量 < 3 個 → 考慮 Bare Metal
  □ 需要嚴格時序控制 → 傾向 Bare Metal
  □ 多協定併行 → 建議 RTOS

□ 資源限制評估  
  □ RAM < 128KB → Bare Metal 優勢明顯
  □ Flash < 512KB → 考慮單bank DFU
  □ 功耗 < 10μA → 兩者差異不大

□ 團隊技能匹配
  □ NRF5 SDK 經驗 → Bare Metal 學習成本低
  □ RTOS 開發經驗 → Zephyr 上手快
  □ 新手團隊 → 建議從範例開始

開發環境設置:

  1. 必要工具安裝
# 基礎工具鏈
nrf-util install toolchain-manager
nrf-util install device

# VS Code 擴展
code --install-extension nordic-semiconductor.nrf-connect

# 除錯工具
# 確保 J-Link 驅動已安裝
  1. 專案模板選擇
應用類型 推薦模板 說明
簡單感測器 peripheral_lbs LED/按鈕控制範例
數據收集 peripheral_uart UART 數據傳輸
心率監測 peripheral_hrs 標準健康服務
自定義服務 peripheral_template 空白模板

除錯技巧與故障排除

常見問題診斷:

  1. 藍牙連接問題
// 增加除錯訊息
#define NRF_LOG_MODULE_NAME main
#define NRF_LOG_LEVEL 4
#include "nrf_log.h"

void on_ble_evt(ble_evt_t const * p_ble_evt) {
    switch (p_ble_evt->header.evt_id) {
        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("Connected to device");
            break;
        case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("Disconnected, reason: %d", 
                        p_ble_evt->evt.gap_evt.params.disconnected.reason);
            break;
    }
}
  1. 功耗分析技術
// 使用 Power Profiler Kit 配合程式碼標記
void enter_measurement_mode(void) {
    // 標記測量開始
    nrf_gpio_pin_set(DEBUG_PIN_1);
    
    // 執行測量任務
    perform_sensor_reading();
    
    // 標記測量結束  
    nrf_gpio_pin_clear(DEBUG_PIN_1);
}
  1. 記憶體使用監控
# 編譯後分析記憶體使用
arm-none-eabi-size build/zephyr/zephyr.elf

# 詳細的記憶體分配報告
arm-none-eabi-objdump -h build/zephyr/zephyr.elf

效能優化策略

程式碼層級優化:

  1. 中斷處理最小化
// 錯誤範例 - 在中斷中做複雜處理
void TIMER0_IRQHandler(void) {
    if (NRF_TIMER0->EVENTS_COMPARE[0]) {
        // 避免在中斷中做複雜運算
        complex_data_processing();  // ❌
        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
    }
}

// 正確範例 - 中斷中只設置標誌
volatile bool data_ready = false;

void TIMER0_IRQHandler(void) {
    if (NRF_TIMER0->EVENTS_COMPARE[0]) {
        data_ready = true;  // ✅
        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
    }
}

// 在主循環中處理
int main(void) {
    while (1) {
        if (data_ready) {
            complex_data_processing();
            data_ready = false;
        }
        power_manage();
    }
}
  1. 記憶體存取優化
// 結構體對齊優化
typedef struct {
    uint32_t timestamp;    // 4 bytes
    uint16_t sensor_value; // 2 bytes  
    uint8_t  status;       // 1 byte
    uint8_t  reserved;     // 1 byte padding
} __attribute__((packed)) sensor_data_t;  // 總共 8 bytes

系統層級優化:

  1. 時鐘配置優化
// 根據應用需求選擇時鐘源
static void clock_init(void) {
    // 高精度應用使用外部晶振
    nrf_clock_lfclk_t lfclk_cfg = {
        .source = NRF_CLOCK_LFCLK_Xtal,
        .accuracy = NRF_CLOCK_LFCLK_ACCURACY_20_PPM
    };
    
    // 成本敏感應用使用內部 RC
    // .source = NRF_CLOCK_LFCLK_RC
}
  1. 功耗模式管理
void power_manage(void) {
    // 檢查是否有待處理事件
    if (!pending_events()) {
        // 進入最深睡眠模式
        sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
        sd_app_evt_wait();
    }
}

結論:技術選擇的智慧

經過深入分析,Nordic NRF Connect SDK Bare Metal 選項確實為嵌入式開發社群帶來了有價值的新選擇。它不只是一個技術產品,更是對開發者需求的深刻理解。

核心價值總結

技術層面的突破:

  1. 性能數據證實:功耗和記憶體使用的實測數據破除了許多迷思
  2. API 相容性:與 NRF5 SDK 的高度相容降低了遷移成本
  3. 開發體驗:統一的工具鏈讓 bare metal 和 RTOS 並存

商業價值體現:

  1. 降低遷移壁壘:讓現有客戶能夠無痛升級硬體
  2. 擴大市場覆蓋:吸引偏好 bare metal 的開發者群體
  3. 生態系統完整:從晶片到工具的端到端支援

實務建議精華

選擇決策框架:

  • 簡單應用 + 資源受限 → Bare Metal
  • 複雜應用 + 豐富功能 → Zephyr RTOS
  • 現有程式碼 + 遷移需求 → 優先考慮 Bare Metal
  • 新專案 + 未來擴展 → 建議使用 Zephyr

成功要素:

  1. 深入理解應用需求:不要被表面的技術特性迷惑
  2. 基於數據做決策:參考實測性能而非主觀印象
  3. 考慮長期發展:技術選擇要配合產品路線圖
  4. 團隊技能匹配:選擇符合團隊經驗的技術路線

未來展望

Nordic 這次推出 Bare Metal 選項,展現了成熟技術公司對市場需求的敏銳洞察。在 RTOS 成為主流趨勢的今天,仍然為 bare metal 開發保留一席之地,體現了技術多元化的價值。

對於嵌入式開發者而言,這意味著更多的選擇自由,也意味著更高的技術判斷要求。關鍵在於理解不同方案的本質差異,結合具體應用場景做出明智選擇。

技術沒有絕對的優劣,只有適合與否。Nordic NRF Connect SDK Bare Metal 選項為我們提供了一個很好的範例:如何在技術進步和開發者需求之間找到平衡點。

無論最終選擇哪種技術路線,持續學習和保持開放心態都是開發者成長的關鍵。畢竟,技術工具會改變,但解決問題的思維方式和對品質的追求永遠不會過時。


這篇文章基於 Nordic Semiconductor 官方 webinar 內容以及多方技術資料整理而成。所有性能數據來自官方測試報告,建議讀者在實際專案中進行驗證。

相關資源連結:


本文最初發布於 HackMD @BASHCAT。

我把整個 Meshtastic 網路搞癱了,然後學會了這些設定技巧

去年春天某個週末,我興沖沖地拿著剛到手的 T-Beam,準備加入本地的 Meshtastic 社群網路。結果沒想到,我一個設定錯誤,竟然讓整個區域網路變得超級卡頓,群組裡面開始有人抱怨訊息延遲。

那時候我才知道,原來 Meshtastic 不是「插電即用」那麼簡單,每一個設定選項背後都有它的道理。經過幾個月的摸索和學習,我想分享一些真正有用的設定技巧,希望你不要像我一樣踩那些坑。

Meshtastic 網路拓撲示意圖

角色設定,我踩過的第一個大坑

剛開始接觸 Meshtastic 時,我看到有個「Repeater」角色選項,腦子裡立刻想起以前玩業餘無線電的經驗。「太好了!」我想,「我把節點設成中繼器,這樣就能幫大家轉發訊息了,多有意義啊!」

結果這個決定差點讓我被踢出社群群組。

後來才知道,Meshtastic 的角色設定跟傳統無線電完全不是一回事。我那個「熱心」的 Repeater 設定,其實是在不斷地重複轉發每一條經過的訊息,而且還關閉了所有的遙測資料廣播。想像一下,一個只會重複別人話但自己什麼都不說的人,在群聊中會有多煩人...

Router:山頭霸主的專屬

Router 角色聽起來很威風,但其實它有非常嚴格的使用條件。這個角色最適合那些放在山頂、高塔或高樓頂上的固定節點,而且必須是 360 度無遮擋的「山頭霸主」位置。

Router 角色會自動啟用省電模式,還會禁用藍牙和 WiFi 連接。這意味著一旦設定好放上山,要再次修改設定就得爬山了。所以絕對不能隨便用這個角色,除非你真的確定那個位置值得。

Client:最實用的選擇

對於我們這些手持設備用戶來說,Client 角色是最穩妥的選擇。它會在需要的時候幫忙轉發訊息,但不會搶著當網路中心。我現在所有的手持設備都用這個角色,包括那台讓我踩坑的 T-Beam。

Client_Mute:低調的智慧選擇

這個角色是我後來發現的寶藏。當你家裡已經有一個固定的基礎設施節點(比如窗台上的太陽能節點)時,你的手持設備其實不需要再幫忙轉發訊息了。Client_Mute 就像一個安靜的聆聽者,只接收和發送自己的訊息,不會增加網路負擔。

在我們本地網路變得越來越擁擠之後,很多人都開始改用 Client_Mute,網路品質明顯改善了。

2.6 版本救了我們所有人

今年年初,Meshtastic 2.6 版本發布了,帶來了一個叫做「Next-Hop Routing」的新技術。老實說,我一開始也不太懂這是什麼,但升級之後的效果實在太明顯了。

以前的版本用的是「管理洪泛路由」(聽起來就很可怕對吧),簡單說就是每條訊息會讓周圍所有節點都嘗試轉發一次。在節點數量少的時候還好,但當我們本地網路發展到 50+ 個活躍節點時,這種方式就開始出問題了。

2.6 版本的 Next-Hop Routing 就聰明多了。它會讓訊息只通過最佳路徑傳遞,而不是讓每個節點都插一腳。實際效果就是,我的直接訊息送達率從 60% 提升到了 90% 以上,而且延遲明顯降低。

還有一個我特別喜歡的新功能叫做「unsuageable flag」。基礎設施節點可以設定這個標誌,告訴大家「我只負責轉發,請不要發直接訊息給我」。這樣一來,那些放在山頂沒人監控的節點就不會收到一堆無意義的直接訊息了。

硬體選擇,不再糾結

說到硬體,我前前後後買了不少設備,也算是交了不少學費。現在終於搞清楚該怎麼選了。

ESP32 vs nRF52:電力的權衡

我的第一台設備是基於 ESP32 的 TTGO T-Beam,功能很全面,有 WiFi、藍牙、GPS,還能連電腦調試。但它有個致命缺點:太耗電了。

後來我又買了一台基於 nRF52 的 RAK4631,功耗立刻降低了 30% 左右。雖然沒有 WiFi,但對於手持設備來說,藍牙連接已經足夠了。如果你打算做電池供電或太陽能節點,nRF52 絕對是更好的選擇。

價格參考(2024年)

現在市面上的選擇比以前多太多了:

  • 入門級($15-25):Heltec WiFi LoRa 32 V3、TTGO LoRa32
  • 主流選擇($25-40):TTGO T-Beam、RAK WisBlock 套件
  • 高端選擇($40-60):T-Deck、預組裝的 Muzi Works H1

我現在最推薦的是 T-Deck,雖然價格高一點,但有鍵盤和大螢幕,用起來就像一台小電腦,特別適合當作主力通訊設備。

太陽能節點的小確幸

去年夏天,我在陽台上搭建了第一個太陽能節點。用的是大家都推薦的 Sohine 6W 太陽能板,配一顆 18650 電池和簡單的充電控制器。

剛開始我很擔心,畢竟台北經常陰雨天,會不會撐不了幾天就沒電了?結果出乎意料,即使在去年那個特別長的梅雨季,節點也穩穩運行了整整三個月沒斷過電。

太陽能節點的設定有個小技巧:把 GPS 功能關掉,改為手動設定固定位置。反正節點不會移動,GPS 只會白白耗電。這樣設定之後,整台設備的功耗可以降到 8mA 左右,一塊小電池就能撐很久。

// 太陽能節點推薦設定
Node Info 廣播:24 小時
位置更新:關閉(手動設定固定位置)
度量資料:1 小時
智能位置:關閉

廣播間隔,細節決定體驗

這是另一個我踩過坑的地方。預設設定下,節點會每小時廣播一次自己的資訊,每 15 分鐘更新一次位置。對於手持設備來說這還好,但如果你有很多固定基礎設施節點,這些廣播就會累積成不小的網路負擔。

我們本地社群經過實測,發現以下設定能在資訊即時性和網路效率間找到最好的平衡:

基礎設施節點(Router 角色):

  • Node Info:24 小時
  • 位置更新:72 小時(或關閉)
  • 度量資料:1 小時

手持設備(Client/Client_Mute):

  • Node Info:1 小時
  • 智能位置:10 分鐘以上
  • 度量資料:3 小時

我現在的設定檢查清單

經過這麼多次試錯,我整理了一個設定檢查清單,每次配置新節點都會過一遍:

  1. 角色選擇

    • ✅ 手持設備:Client 或 Client_Mute
    • ✅ 固定節點:只有絕佳位置才用 Router
    • ❌ 絕對不用 Repeater
  2. 廣播設定

    • ✅ Node Info 間隔:基礎設施 24h,手持 1h
    • ✅ 位置更新:根據實際需求調整
    • ✅ 跳躍限制:保持預設的 3,不要隨意增加
  3. 韌體版本

    • ✅ 升級到 2.6 或更新版本
    • ✅ 基礎設施節點用穩定版
    • ✅ 手持設備可以嘗試測試版
  4. 硬體配置

    • ✅ 電池供電選 nRF52
    • ✅ 需要 WiFi 功能選 ESP32
    • ✅ 天線選擇 4-6dBi 全向天線
  5. 網路禮儀

    • ✅ 設定有意義的節點名稱
    • ✅ 適當設定區域和頻率
    • ✅ 不要設定過高的發射功率

寫在最後

回想起第一次搞垮網路的經歷,其實我蠻感謝那次「事故」的。如果沒有那次踩坑,我可能永遠不會深入了解 Meshtastic 的技術細節,也不會認識社群裡那麼多有趣的朋友。

現在我的設備都跑得很穩定,本地網路也越來越健康。最讓我有成就感的是,新朋友加入社群時,我已經能夠分享這些實戰經驗,幫他們避開我曾經踩過的坑。

Meshtastic 是個很棒的技術,但它需要每個使用者都負起責任,用正確的設定來維護網路品質。希望這些分享對你有幫助,如果你也在玩 Meshtastic,歡迎分享你的經驗!

參考資源:



本文最初發布於 HackMD @BASHCAT。

當藍牙也能精確定位到 10 公分:我為什麼對 nRF54L 的 Channel Sounding 技術如此興奮

上週在台北101地下街,我又再次體驗了「手機地圖說我在這裡,但我明明在那裡」的窘境。站在B2美食街,Google Maps 堅持顯示我在B1,而我朋友說她在「星巴克附近」,但整個地下街有三家星巴克。我們最後還是靠著傳統方法——電話裡的「你看得到我嗎?我在招手」才找到彼此。

就在我為這個老問題苦惱時,我在研究中發現了一個可能改變遊戲規則的技術:Nordic Semiconductor 的 nRF54L 搭配 Bluetooth 6.0 的 Channel Sounding。

Bluetooth Channel Sounding 技術原理

當我深入研究這個技術時,發現它竟然能把定位精度從原本的幾公尺提升到 10 公分!這是什麼概念?就是你站在星巴克門口,它能精確知道你是在門的左邊還是右邊。

這技術到底是怎麼做到的?

你知道蝙蝠是怎麼在黑暗中導航的嗎?牠們發出超音波,然後聽回音來判斷距離和位置。Channel Sounding 也是類似概念,但更聰明。

想像你在KTV唱歌,麥克風傳到音響的聲音有延遲對吧?Channel Sounding 就像測量這個延遲,但它不只測一次,而是同時在多個「頻道」測量,就像你同時用好幾支麥克風唱同一首歌,然後比較每支麥克風的延遲差異。

技術上來說,它使用兩種方法:

Phase-Based Ranging (PBR):測量無線訊號的相位變化,就像測量聲波的相位差。 Time of Flight (ToF):測量訊號來回的時間,用來驗證相位測量的結果。

兩個方法同時使用,就能消除那些讓定位不準的干擾因素,比如牆壁反射、其他電子設備的干擾等等。

最讓我興奮的發現

說實話,最讓我驚喜的發現是什麼?這個技術不需要額外的硬體!你的手機、耳機、手錶,只要支援 Bluetooth 6.0 就行了。相比之下,UWB 技術雖然更精確(可以達到公分級),但需要專門的晶片,成本高出不少。

而且你知道嗎,2024年有54億台設備包含了 Bluetooth 技術。這個數字代表什麼?代表未來幾年當這些設備開始支援 Bluetooth 6.0 時,Channel Sounding 就會自然而然地普及到我們的生活中,不需要大家額外花錢買新設備。

室內定位應用場景

這技術能解決哪些實際問題?

讓我分享幾個讓我覺得很有意思的應用場景:

智慧鑰匙的革命

想像一下,你提著大包小包走向車子,還沒掏出鑰匙,車門就自動解鎖了。但這次不是因為你走近了,而是系統精確知道你站在駕駛座車門外 50 公分,而不是站在其他車門旁邊。這種精度讓中繼攻擊(就是駭客用設備放大你鑰匙訊號的那種攻擊)幾乎不可能成功。

室內導航的新境界

去年我在東京車站迷路的經驗讓我印象深刻。那個車站複雜到我用了三個不同的地圖 App 都還是找不到正確的出口。如果有了這個技術,地圖 App 不只能告訴你「你在2樓」,而是能精確顯示「你現在站在2樓東側廁所門口,距離JR山手線入口35公尺」。

對於視障朋友來說,這種精度更是生活品質的巨大提升。

物品追蹤的大躍進

你有沒有用過 AirTag 或類似的物品追蹤器?現在的技術只能告訴你「你的鑰匙在這個房間裡」,但有了 Channel Sounding,它能告訴你「鑰匙在沙發左側坐墊下方」。

但也不是完美的

當然啦,任何技術都有它的限制。我在研究中也發現了一些挑戰:

測量需要時間

跟 UWB 比起來,Channel Sounding 需要更長的測量時間。就像拍照一樣,UWB 是快門,Channel Sounding 更像是需要對焦的單眼相機。不過對大部分應用來說,這個差異不會造成問題。

環境干擾

複雜的環境(比如很多金屬反射面的地方)可能需要額外的校準。但好消息是,軟體可以逐漸學習和改善。

生態系統還在建設中

雖然 nRF54L 晶片已經可以買到了,但手機廠商要開始支援 Bluetooth 6.0 預計還要等到 2025-2026 年。不過這也給了開發者時間來準備相關的應用。

技術對比

和 UWB 比較,到底誰比較好?

這是我最常被問到的問題。怎麼說呢,這有點像問「汽車好還是摩托車好」,答案取決於你的需求:

UWB 的優勢:

  • 精度更高(1-3公分 vs 10公分)
  • 測量速度快
  • 安全性更好

Channel Sounding 的優勢:

  • 成本更低(利用現有 Bluetooth 生態系統)
  • 普及性更廣(預期手機都會支援)
  • 功耗相對較低

我的看法是,這兩個技術可能會互補存在。比如在車鑰匙應用中,遠距離可能用 Channel Sounding 偵測你的接近,近距離開鎖時切換到 UWB 確保最高的精度和安全性。

什麼時候我們能真正用到?

根據我收集的資料,時程大概是這樣:

2024-2025年:開發工具和晶片已經可用,早期採用者開始開發相關產品 2025-2026年:第一批支援的終端產品上市,手機廠商開始加入支援 2027年後:大規模普及,可能成為室內定位的主流技術

Silicon Labs 的 xG24 平台已經支援了,還有可視化工具讓開發者可以即時看到距離測量結果。Nordic 的 nRF Connect SDK 也在 v3.0.1 開始正式支援 Channel Sounding。

我為什麼這麼興奮?

說到底,我興奮的不只是技術本身,而是它可能帶來的改變。

想像一下未來的智慧家居:當你坐到沙發上,電視自動調整到最適合的音量和畫質設定;當你走向廚房,燈光自動調亮,音樂跟著你移動。這些都不需要額外的感應器,只需要你口袋裡的手機和家裡的 Bluetooth 設備。

或者想像在醫院裡,護理人員可以精確追蹤每一台醫療設備的位置,不用再花時間找輪椅、血壓計或其他器材。

甚至在工廠裡,工人的安全帽可以偵測到他們是否太靠近危險區域,及時發出警告。

技術細節補充

對於想深入了解的朋友,讓我補充一些技術規格:

nRF54L 系列的特色:

  • 128MHz Arm Cortex-M33 處理器
  • 支援 Bluetooth 6.0、Thread、Matter、Zigbee
  • 超低功耗:系統關閉時只需 0.8 µA
  • 超緊湊封裝:最小只有 2.4×2.2mm

Channel Sounding 的技術優勢:

  • 使用多頻道測量降低誤差
  • 內建安全機制防止距離欺騙
  • 標準化規格確保互通性
  • 可與現有 Bluetooth LE 設備共存

回到那個地下街的故事

回到那個在台北101地下街找朋友的場景。也許再過幾年,當你朋友說「我在星巴克附近」時,你的手機會精確顯示她在「B1東側星巴克左前方1.5公尺處」。你們不用再玩「你看得到我嗎?我在招手」的躲貓貓遊戲了。

這種改變可能看起來微小,但累積起來就是生活品質的提升。就像我們現在很難想像沒有 GPS 的生活一樣,也許幾年後我們也會覺得沒有精確室內定位的時代很不可思議。

技術的進步往往是這樣的,一開始可能只是解決某個特定問題,但最終會改變我們與周圍環境互動的方式。nRF54L 的 Channel Sounding 技術,我覺得就有這種潛力。

雖然還有一些技術挑戰需要克服,生態系統也需要時間建立,但我相信這個方向是對的。當 10 公分精度的定位變得像現在的 WiFi 一樣普遍時,我們可能會看到一些我們現在還想像不到的創新應用。

而這,就是讓我對這個技術如此興奮的原因。


參考資料


本文最初發布於 HackMD @BASHCAT。

你的 BLE 天線為什麼收訊爛透了?Nordic Pi 型匹配網路與 NanoVNA 調試完整實戰

nce-nanovna-f-v2_ke_xl

你有沒有過這種經驗 -- 板子打回來,韌體燒進去,BLE 廣播一開,手機得貼到板子 10 公分內才收得到訊號?

我有。而且不止一次。

第一次遇到的時候,我花了三天檢查韌體、換了兩個 BLE app、甚至懷疑是不是 nRF52 晶片本身有問題。直到一個做 RF 的朋友看了我的板子,淡淡地說了一句:「你天線有做匹配嗎?」

那一刻我才真正理解,藍牙的世界裡,天線匹配不是「有做更好」,而是「沒做就廢」。

這篇文章會帶你走一遍完整的 Nordic BLE 天線阻抗調試流程 -- 從 Pi 型匹配網路是什麼,到怎麼把 NanoVNA 焊上你的 PCB,再到看著 Smith Chart 一步步把 S11 從慘不忍睹調到 -15dB 以下。全程實戰,不講廢話。


搞懂你的戰場:nRF52 的 RF 信號到底怎麼走的

在動手之前,你得先知道信號從 nRF52 晶片出來之後經過了什麼。很多人(包括當初的我)搞不清楚哪些元件是匹配網路、哪些不是,結果改錯地方白忙一場。

nordic-antenna-pi-network-macro

nRF52 系列的 RF 路徑長這樣:

nRF52 ANT Pin → [C3 + L1 RF Choke] → Feed Line → [Pi Matching Network] → Antenna

這裡有個關鍵的坑:C3 和 L1 是 RF choke,用來濾掉不要的諧波,它們不是匹配網路。真正的 Pi 匹配網路在 feed line 的天線那一端。我見過不少人去動 C3 和 L1 的值,結果把諧波濾波搞壞了,天線匹配也沒變好。Nordic DevZone 的 PCB 設計指南%E8%A3%A1%E9%9D%A2%E6%9C%89%E6%98%8E%E7%A2%BA%E8%AA%AA%E6%98%8E%E9%80%99%E4%B8%80%E9%BB%9E%E3%80%82

Pi 型匹配網路的拓撲很直觀 -- 兩個並聯電容夾一個串聯電感:

            L (series)
    ┌───────┤├───────┐
    │                │
Feed Line           Antenna
    │                │
    ├── C1 ──┤       ├── C2 ──┤
    │       GND      │       GND

C1 調源端阻抗,L 做阻抗轉換,C2 調天線端阻抗。三個元件各司其職,但彼此牽連。改了一個,另外兩個的最佳值也會跟著變。這就是為什麼天線調試是個迭代過程,不是算一次就搞定的事。

那什麼時候需要 Pi 型?什麼時候不用?根據 Nordic nwp_008 白皮書的建議:如果你用的是 λ/4 monopole PCB 天線,長度可調的話,一個 shunt 元件就夠了。但如果是 meander 天線或 chip 天線,阻抗偏離 50Ω 比較多,就需要完整的 Pi network。

Nordic nRF52832 參考設計給的典型值是 0.8pF 電容搭配 3.9nH 電感。但請注意 -- 這些值只對 Nordic 的參考板有效。你的 PCB stackup 不同、焊接遮罩厚度不同、天線佈局不同,最佳值就會不一樣。有人在 All About Circuits 論壇分享過,光是焊接遮罩從 0.0175mm 換成 0.035mm,就造成了嚴重的阻抗偏移。


60 美元的 NanoVNA 能打嗎?

專業的向量網路分析儀(VNA)動輒幾十萬台幣。但做 BLE 天線調試,你真的不需要那種等級的設備。

NanoVNA V2(SAA-2N)頻率上限超過 3GHz,足以覆蓋 BLE 的 2.4GHz 頻帶。精度大約 ±1-2dB -- 對開發調試來說完全夠用。當然,最後要過認證的時候,還是得上 Keysight 或 R&S 的設備。但在那之前,NanoVNA 就是你最好的朋友。

你需要準備的東西:

設備 用途 大概花費
NanoVNA V2 核心測量工具 $60-100
SMA 校準件(Open/Short/Load) 校準用,通常隨機附贈 $10
SMA-to-U.FL 轉接線 連接 PCB $3-5
0402/0603 SMD 元件盒 各種 pF 和 nH 值 $20-50

總投資不到 200 美元,就能建立一套堪用的天線調試工作站。


最關鍵的一步:把 NanoVNA 接上你的 PCB

這一步做不好,後面量出來的數據全是垃圾。

nordic-antenna-soldering-ufl

U.FL 連接器法(推薦)

如果你在 PCB 設計階段就預留了 U.FL 焊盤 -- 恭喜,你是有遠見的人。操作很單純:

  1. 把 U.FL 連接器焊到測試點。信號 pad 對準 feed line(Pi 網路入口),接地 pad 焊到 ground plane
  2. 用 SMA-to-U.FL 轉接線接到 NanoVNA 的 Port 1(CH0/S11)
  3. 確認 U.FL 卡扣到位,你應該聽到一聲清脆的「咔嗒」

注意 U.FL 連接器的壽命大約 30 次插拔,別當它是 USB 那樣隨便插。轉接線也別超過 15cm,越短越好。

裸線焊接法(應急方案)

沒預留測試點?只能硬上了。取一段 RG-178 細同軸線,5-10cm 就好。剝開末端,中心導體焊到 feed line pad,編織屏蔽焊到最近的 ground plane。

這裡有個殘酷的數字:每多 1mm 的導線,就多大約 1.5nH 的寄生電感。在 2.4GHz,這個量級足以讓你的測量結果偏離現實。所以焊接線要盡可能短,接地焊點面積要盡可能大。

EE Stack Exchange 上的討論對這兩種方案有很好的分析。結論是:裸線焊接對天線的干擾確實比較小,但校準會比較麻煩。如果是開發階段會反覆測量,還是乖乖用 U.FL 吧。


校準的藝術:做對這件事,其他都好辦

NanoVNA 的測量精度完全取決於校準品質。這不是誇張 -- NanoVNA 實用指南裡面寫得很直白:「大多數 NanoVNA 精度投訴其實是連接器和轉接器的問題。」

SOL 校準步驟

1. STIMULUS → START: 2.0 GHz, STOP: 3.0 GHz
2. 掃描點數設 201 或 401
3. CAL → CALIBRATE → OPEN → 接 Open 件 → 掃描
4. SHORT → 接 Short 件 → 掃描
5. LOAD → 接 50Ω Load 件 → 掃描
6. DONE → 儲存

幾個容易被忽略的細節:校準過程中不要碰 SMA 連接器,手的電容耦合會影響結果。NanoVNA 要遠離金屬桌面。電池電量要充足 -- 電壓不穩會影響內部振盪器的精度。

Port Extension -- 別漏了這步

如果你用了 SMA-to-U.FL 轉接線,校準平面在 SMA 端,但你的 DUT(待測物)在 U.FL 端。中間那段線會引入相位延遲,讓你的 Smith Chart 讀數旋轉偏移。

截圖 2026-03-11 下午3.19.39

補償方法很直觀:

  1. 校準完成後,接上轉接線,U.FL 端保持開路
  2. 觀察 Smith Chart -- 開路理應在最右邊
  3. 調整 DISPLAY → ELECTRICAL DELAY
  4. 旋轉到 Smith Chart 軌跡集中在最右邊為止

校準完記得驗證:接 Open 要在 Smith Chart 最右、接 Short 要在最左、接 50Ω Load 要在正中心(Return Loss < -40dB)。如果 Load 的 return loss 只有 -20dB 出頭,你的校準品質不夠好,重來。


讀懂 Smith Chart:從「看不懂的圓」到你的調試指南針

Smith Chart 對很多硬體工程師來說是個謎。但在天線調試的場景裡,你其實不需要完全搞懂它的數學。你只需要知道:點在哪裡,就用什麼元件去推它。

把 Smith Chart 想成一張地圖。中心點是目的地(50Ω 完美匹配),你的天線阻抗是出發點。你的任務就是用 C 和 L 元件,沿著特定的路徑把點推到中心。

                感性(+jX)
                    ↑
                    |
     區域 B         |         區域 A
  (R<50, +jX)       |      (R>50, +jX)
                    |
←──────────── 50Ω 中心 ──────────────→
  R < 50Ω           |           R > 50Ω
                    |
     區域 C         |         區域 D
  (R<50, -jX)       |      (R>50, -jX)
                    |
                    ↓
                容性(-jX)

根據 Nordic nwp_017 白皮書的核心方法論,不同區域對應不同的補償策略:

你的天線落在... 白話翻譯 怎麼救
區域 A(右上) 阻抗太大、偏感性 並聯電容拉下來,串聯電容推過去
區域 B(左上) 阻抗太小、偏感性 串聯電容消掉感性,並聯電感拉上去
區域 C(左下) 阻抗太小、偏容性 串聯電感消掉容性,並聯電容推過去
區域 D(右下) 阻抗太大、偏容性 並聯電感拉上來,串聯電感推過去
G=1 圓附近 差一點點而已 一個 shunt 元件搞定

另外還有一個更直覺的判斷:看 S11 曲線的谷底在哪裡。

  • 谷底在 2.45GHz 右邊(頻率偏高)→ 天線電氣長度不夠 → 加串聯電感
  • 谷底在 2.45GHz 左邊(頻率偏低)→ 天線太長了 → 加串聯電容或修剪天線
  • 谷底位置對了但不夠深(S11 只有 -5dB)→ 阻抗匹配有問題 → 需要完整調整 Pi 網路

目標是讓整個 BLE 頻帶(2.4 ~ 2.4835 GHz)的 S11 都低於 -10dB,對應 VSWR < 2:1,功率反射低於 10%。做到 -15dB 以上就很不錯了。


動手調試:Pi 網路的迭代修正流程

理論講完了,進入實戰。

nordic-antenna-iterative-tuning

第一步:測量原始天線阻抗

在 Pi 網路的三個位置先焊上 0Ω 電阻(直接跳接)。這樣量到的就是天線的原始阻抗,沒有任何匹配。記下 2.45GHz 時的 Z = R + jX。

第二步:計算匹配元件值

這裡你有幾個選擇。最方便的是 DiSlord 韌體內建的 L/C MATH 功能(路徑:Measure → L/C MATH),它會在 Marker 頻率點自動算出最多 4 種匹配方案,直接告訴你需要多少 pF 和 nH。

如果你想在電腦上做更細緻的分析,SimSmith(現改名 SimNec)是免費的 Smith Chart 模擬工具。從 NanoVNA 匯出 S1P 檔,匯入 SimSmith,選 Pi 拓撲,它會自動算出最佳值。線上的 Analog Devices RF Impedance Matching Calculator 也是不錯的替代方案。

第三步:焊接元件

拿到計算值後,選最接近的標準元件值。2.4GHz BLE 最常用的範圍是 0.5-5 pF 電容和 1-6 nH 電感。

焊接順序建議:先焊天線端的 C2,再焊串聯 L,最後焊源端 C1。每焊一個就量一次,觀察 Smith Chart 上的點怎麼移動。這樣你能直觀感受到每個元件對阻抗的影響。

第四步:量測 → 微調 → 再量測

S11 < -10dB 了?恭喜,可以往下一步走了。還沒到?看一下殘餘偏移方向:

看到什麼 動什麼
谷底頻率偏高 增大 L 值或增大 C2
谷底頻率偏低 減小 L 值或減小 C2
頻率對了但谷底不夠深 調整 C1
Smith Chart 仍偏感性 增大並聯 C
Smith Chart 仍偏容性 增大串聯 L 或減小 C

黃金法則:每次只改一個元件。改兩個以上你就搞不清楚是哪個在起作用了。

第五步:裝上外殼再量一次

這步很多人會忘記,然後出貨後被客訴。塑膠外殼的介電常數會改變天線周圍的電磁環境,通常讓諧振頻率下移。金屬外殼的影響更大。所以最終調試一定要帶著實際外殼做。


踩坑實錄:那些讓我多浪費一週的錯誤

nordic-antenna-troubleshooting

做了幾年天線調試,踩過的坑可以寫一本書。這裡挑幾個最常見的:

坑一:改了 RF choke 以為在調匹配

前面講過了,C3 和 L1 是諧波濾波器,不是匹配網路。改它們的值只會影響諧波抑制,對天線匹配幾乎沒有幫助。Nordic DevZone 的問答裡有明確說明:「No you can't change C3 and L1, they are an RF choke to remove unwanted harmonics, not really part of the matching network.」

坑二:沒做 Port Extension

轉接線引入的相位延遲會讓 Smith Chart 上的所有點旋轉。你以為天線偏感性,其實只是相位偏移造成的假象。結果你加了電容去補償,反而把匹配搞得更差。

坑三:接地沒做好

Radio ground pin 應該先經 decoupling capacitor 再連到 ground plane,而不是直接拉線過去。Ground plane 上的 stitching via 也不能省 -- via 不夠多會造成 ground plane 不連續,在 2.4GHz 下產生意想不到的阻抗不連續。

坑四:量測時手碰到線纜

人體的電容耦合在 2.4GHz 不可忽略。量測時手一碰到同軸線,Smith Chart 上的點就會跳動。養成習慣:連接好之後,手離開,等數據穩定了再讀值。

坑五:忘記考慮元件寄生效應

在 2.4GHz,一顆 1pF 的電容不只是 1pF -- 它還有等效串聯電感(ESL)。一顆 3.3nH 的電感也不只是 3.3nH -- 它有寄生電容。所以計算出來的理論值和實際需要的值之間總有差距,必須靠實測迭代來收斂。選元件時優先選 RF 等級的(如 Murata GJM 系列電容、LQW 系列電感),它們的寄生參數比較低且一致。


你可能不知道的好康:Nordic 免費幫你調

說一個很多人不知道的事:Nordic 提供免費的硬體審查和天線調試服務。你可以在 Nordic DevZone 提交你的 PCB 設計檔案,Nordic 的 RF 工程師會幫你看 layout、給建議,甚至可以寄實體板子過去讓他們實測。這個服務對使用 Nordic 晶片的開發者完全免費。

另外,如果你想要一個不用拆焊就能切換匹配配置的方案,可以研究 Murata SWG 開關 -- 在 RF trace 上設計開關位置,測試時直接切換不同電路路徑。這在需要頻繁實驗的開發板上特別好用。


最後一件事:帶著外殼量完才算數

nordic-antenna-final-result

天線調試的終點不是「裸板 S11 達標」,而是「裝進外殼、放在使用者會放的位置、S11 依然達標」。塑膠外殼、金屬遮蔽罩、電池、LCD 螢幕 -- 任何一個靠近天線的東西都會改變它的阻抗特性。

我的建議是:先用裸板把匹配調到接近目標(S11 < -8dB 左右就好),然後裝上外殼再做最後的精調。因為外殼通常會讓頻率下移,你可以在裸板階段故意讓諧振頻率比目標稍高一些,預留空間給外殼的影響。

整個流程跑下來,從第一次量測到最終定案,通常需要 3-5 輪迭代。不要急,天線調試就是這樣的節奏。準備好一盒 0402 元件(0.3-10pF 電容、0.6-10nH 電感),泡杯咖啡,享受把那條 S11 曲線一點一點壓下去的過程吧。


工具與資源速查

工具 用途 費用
NanoVNA-Saver PC 端控制與數據匯出 免費
SimSmith / SimNec Smith Chart 匹配模擬 免費
AD RF Matching Calculator 線上匹配計算 免費
All About Circuits Pi-Match Pi 網路計算器 免費

必讀文件:


做硬體的人都知道,RF 是電子工程裡最接近黑魔法的領域。但只要你有一台 NanoVNA、一盒 SMD 元件、和足夠的耐心,Pi 型匹配網路的調試其實沒有想像中那麼可怕。關鍵在於:量測、計算、焊接、再量測。重複這個循環,直到 Smith Chart 上的那個點乖乖回到圓心。


本文最初發布於 HackMD @BASHCAT。

別再手動部署了:CI/CD 完整入門指南,從軟體到韌體都適用

cicd-cover

你有沒有經歷過這種場景?

星期五下午五點半,你信心滿滿地把最新的程式碼推上伺服器。改了一個小 bug,應該沒什麼問題吧?結果十分鐘後,同事的 Slack 訊息炸了:「網站掛了。」

你慌了。趕緊 SSH 進伺服器,手動 git pull,發現忘了裝新的套件。跑了 npm install,又發現環境變數沒設。一路手忙腳亂修到晚上八點,終於恢復正常。

或者你是做韌體的。改了一行 SPI 驅動的程式碼,用手邊的開發板燒錄測試沒問題,信心滿滿地交付。結果量產後客戶回報:「藍牙連線會斷。」一查才發現,你改 SPI 的時候不小心動到了 BLE 的 timer 設定,而你手動測試的時候根本沒測藍牙功能。

不管你是寫網頁、做 APP、還是搞嵌入式韌體,這些故事的根源都一樣:太多事情靠人記、靠人做,遲早會出包。

這就是 CI/CD 要解決的問題。


用點餐來解釋 CI/CD

cicd-kitchen

我知道,「持續整合」「持續部署」這些詞聽起來很嚇人。但其實概念非常簡單,讓我用你最熟悉的東西來解釋 — 一間餐廳的廚房。

想像你走進一間運作順暢的餐廳。從你點餐到食物送上桌,中間經過了一條流水線:

  • 備料區:洗菜、切肉、準備食材
  • 料理區:大火快炒、擺盤
  • 品管區:主廚試味道,確認沒問題
  • 出餐口:服務生端上桌

CI/CD 就是你的程式碼的這條流水線。不管這個「程式碼」是一個網站的前端、一支手機 APP 的後端、還是一顆 MCU 上面跑的韌體,邏輯都一樣。

CI — 持續整合(Continuous Integration)

對應「品管區」。你每次寫完一段程式碼,系統就自動幫你「試味道」 — 跑測試、檢查有沒有寫壞別人的功能。

不是等整道菜做完才試,而是每加一種調料就試一次。這樣萬一味道不對,你馬上知道是哪一步出了問題。

根據 Red Hat 的定義對軟體工程師來說,這意味著每次 push 就自動跑 Jest 或 Pytest。對韌體工程師來說,這意味著每次 push 就自動用交叉編譯器(cross-compiler)建構韌體,然後跑靜態分析。

CD — 持續交付(Continuous Delivery)

對應「出餐口」。菜做好了,品管也過了,放在出餐口等著。但什麼時候端出去?由你決定。

程式碼隨時可以上線,但需要有人按下那個「部署」按鈕。適合需要人工審核的場景,比如金融系統、醫療軟體,或是需要經過認證才能出貨的韌體產品。

CD — 持續部署(Continuous Deployment)

這就更猛了 — 菜做好、品管過了,自動送到客人桌上,連服務生都不用叫。

只要程式碼通過所有自動化測試,就直接部署到生產環境。Netflix 就是這樣做的,他們每天部署數千次程式碼變更。在韌體領域,這對應的是通過所有測試後自動產生 OTA(Over-the-Air)更新包,推送到已出貨的裝置上。

一句話區分三者:

CI = 每改一次就自動檢查 持續交付 = 隨時「能」上線 持續部署 = 隨時「會」上線


Pipeline 是什麼?你的程式碼生產線

cicd-pipeline

Pipeline,中文叫「管線」或「流水線」,就是你的程式碼從「寫完」到「上線」之間要經過的所有自動化步驟。

軟體的 Pipeline

一條典型的 Web / APP Pipeline 長這樣:

程式碼提交 → 安裝依賴 → 自動建構 → 自動測試 → 安全掃描 → 部署上線
階段 白話文 做什麼
Source 你按了 git push 程式碼推上去,觸發整條流水線
Build 把原料變成成品 編譯程式碼、安裝套件、打包
Test 品質檢查 跑單元測試、整合測試,確認沒壞
Security 安全檢查 掃描有沒有安全漏洞
Deploy 送出去 把通過檢查的版本部署到伺服器

韌體的 Pipeline

韌體的 Pipeline 架構類似,但有幾個獨特的階段:

程式碼提交 → 交叉編譯 → 靜態分析 → 單元測試 → HIL 測試 → 產生韌體包 → OTA / 燒錄
階段 白話文 做什麼
Source 你按了 git push 跟軟體一樣,程式碼推上去觸發流水線
Cross-compile 用電腦編譯給晶片跑的程式 用 ARM GCC 等交叉編譯器產生目標平台的二進位檔
Static Analysis 幫你抓潛在的 bug 用 Cppcheck、PC-lint 等工具檢查 MISRA-C 合規性
Unit Test 不用硬體也能測 在 Host 上用 Unity / Google Test 跑單元測試
HIL Test 接上真正的硬體測 硬體在環測試(Hardware-in-the-Loop),自動燒錄到開發板並驗證
Artifact 打包產出物 產生 .bin、.hex、OTA 更新包,存到儲存庫

重點是:這一切都是自動的。你只要 git push,剩下的機器全包。


CI/CD 到底能幫你做什麼?

這可能是你最想知道的部分。CI/CD 不是一個抽象的概念,它能做非常具體的事情。我把它分成四大類:

品質守門員

1. 自動跑測試 每次提交程式碼,自動執行單元測試、整合測試、端對端測試。不用再靠人記得「啊,我應該跑一下測試」。

2. 程式碼品質檢查 自動偵測程式碼風格問題、潛在 bug、過高的複雜度。軟體工程師用 ESLint、SonarQube;韌體工程師用 Cppcheck、PC-lint 做 MISRA-C 合規性檢查,確保程式碼符合汽車、醫療等產業的安全編碼標準。

3. 程式碼審查輔助 自動產生測試覆蓋率報告,讓 Code Review 有數據可看,不再只靠感覺。

安全防護盾

4. 漏洞掃描 自動掃描你用的第三方套件有沒有已知的安全漏洞。Palo Alto Networks 指出,將安全掃描嵌入 Pipeline 是現代 DevSecOps 的基本功。

5. 密鑰偵測 防止你不小心把 API Key 或密碼推到 GitHub 上(別笑,這種事每天都在發生)。韌體專案裡更常見的是不小心把加密金鑰、OTA 簽章私鑰或是量產用的 provisioning 資料推上去。

效率加速器

6. 自動建構與打包 軟體工程師不用再手動跑 npm run build 或打 Docker image。韌體工程師不用再手動開 IDE 按編譯,或是記住那串又臭又長的 arm-none-eabi-gcc 參數。機器幫你做,每次都一模一樣。

7. 自動部署 / 自動燒錄 軟體世界:一鍵部署到 staging 環境測試,通過後自動推到 production。根據 IBM 的報告,這能讓團隊從「每週部署一次」變成「每天部署多次」。韌體世界:自動燒錄到測試用的開發板,或是產生 OTA 更新包推送到裝置端。

8. 自動回滾 部署出問題?系統自動回到上一個穩定版本。在韌體 OTA 的場景裡,這對應的是 MCUboot 的 rollback 機制 — 如果新韌體開機失敗,自動回退到前一個版本。

團隊協作利器

9. 環境一致性 「在我的電腦可以跑啊」— 這句話有了 CI/CD 之後就不會再出現了。軟體專案用 Docker 統一環境;韌體專案用 Docker 包裝交叉編譯工具鏈,確保每個人用的 ARM GCC 版本都一樣。

10. 快速反饋迴圈 提交程式碼後幾分鐘內就知道有沒有問題,不用等到兩週後的整合測試才發現自己兩週前寫的東西是壞的。


韌體工程師的 CI/CD:不只是軟體的事

cicd-firmware-pipeline

很多人聽到 CI/CD 會覺得「那是做網頁、做 APP 的人在用的吧?」這是一個非常常見的誤解。事實上,韌體開發可能比軟體開發更需要 CI/CD,原因很簡單:韌體出 bug 的代價更高。

網站掛了,你可以在五分鐘內重新部署。但如果已經出貨到客戶手上的 IoT 裝置韌體有 bug 呢?輕則要遠端 OTA 更新,重則要整批召回。根據 Parasoft 的白皮書,嵌入式系統的開發週期長、手動測試瓶頸多、韌體發布風險高,這些痛點 CI/CD 都能直接緩解。

韌體 CI/CD 的獨特挑戰

跟軟體相比,韌體做 CI/CD 有幾個額外的挑戰:

1. 交叉編譯(Cross-Compilation)

你寫程式碼的電腦是 x86 或 ARM Mac,但程式碼要跑在 Cortex-M4 或 RISC-V 晶片上。所以 CI 環境必須安裝正確的交叉編譯工具鏈。

解法很成熟:用 Docker 把整個工具鏈打包成映像檔。比如一個包含 arm-none-eabi-gcc 14.2、nRF Connect SDK 和 Zephyr RTOS 的 Docker image,團隊所有人和 CI 伺服器用同一個映像,徹底消除「在我電腦上可以編譯」的問題。

2. 硬體在環測試(Hardware-in-the-Loop, HIL)

軟體測試只需要虛擬機。但韌體最終要跑在真正的硬體上 — GPIO 的時序對不對?SPI 通訊正不正常?BLE 連線穩不穩定?這些只有接上真正的硬體才能驗證。

cicd-hil-testing

HIL 測試的做法是:在 CI 伺服器旁邊放一塊(或一組)開發板,Pipeline 跑到測試階段時,自動把韌體燒錄到開發板上,用自動化腳本驅動測試,讀取結果回報。GitLab 有一篇詳細的指南說明如何設定。

聽起來很複雜?確實比純軟體測試多了一步。但想想看 — 如果你有 10 個工程師同時開發,每個人改完程式碼都要搶那一塊開發板來手動測試,排隊的時間加起來有多恐怖?自動化之後,提交程式碼就排入佇列,機器自動幫你燒錄、測試、回報結果。

3. 靜態分析與合規性

如果你的韌體要用在汽車(ISO 26262)、醫療器材(IEC 62304)或航空(DO-178C)領域,程式碼必須符合 MISRA-C 或 CERT-C 等編碼標準。手動檢查這些規則?幾乎不可能。

CI Pipeline 裡放一個靜態分析步驟,每次提交自動檢查所有規則違反,在程式碼合併之前就攔住不合規的程式碼。開源的 Cppcheck 或商業的 IAR C-STAT、Parasoft C/C++test 都能做到。

4. OTA 更新包的自動化產生

對 IoT 產品來說,CI/CD 的最後一步不是「部署到伺服器」,而是「產生 OTA 更新包並簽章」。Pipeline 可以自動:

  • 編譯韌體
  • 計算 checksum
  • 用私鑰簽章
  • 上傳到 OTA 伺服器(如 Memfault、AWS IoT、Nordic nRF Cloud)
  • 等待審核後推送到裝置

韌體 CI/CD 的實際 Pipeline 範例

這是一個用 GitHub Actions 建構 Zephyr RTOS 韌體的真實範例,改編自 Embedded CI/CD 社群的推薦做法:

name: Firmware CI

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

jobs:
  build:
    runs-on: ubuntu-latest
    container:
      image: zephyrprojectrtos/ci:latest    # 預裝好交叉編譯工具鏈的 Docker 映像

    steps:
      - uses: actions/checkout@v4

      - name: 初始化 Zephyr workspace
        run: |
          west init -l .
          west update

      - name: 建構韌體(nRF52840 DK)
        run: |
          west build -b nrf52840dk/nrf52840 app/

      - name: 靜態分析
        run: |
          cppcheck --enable=all --error-exitcode=1 \
            --suppress=missingInclude \
            src/

      - name: 單元測試(Host 端模擬)
        run: |
          west build -b native_sim tests/
          ./build/zephyr/zephyr.exe

      - name: 上傳韌體產物
        uses: actions/upload-artifact@v4
        with:
          name: firmware-nrf52840
          path: |
            build/zephyr/zephyr.hex
            build/zephyr/zephyr.bin

看到了嗎?結構跟軟體的 CI Pipeline 幾乎一樣 — 觸發、建構、測試、產出。差別只在用的工具不同:west build 取代 npm run build,cppcheck 取代 eslint,native_sim 模擬器取代瀏覽器測試。

軟體 vs 韌體 CI/CD 對照表

面向 軟體(Web / APP) 韌體(嵌入式 / IoT)
編譯 本機編譯器(gcc, node) 交叉編譯器(arm-none-eabi-gcc)
環境統一 Docker + Node/Python 版本 Docker + 工具鏈版本(SDK, RTOS)
測試 Jest, Pytest, Cypress Unity, Google Test, HIL 測試
靜態分析 ESLint, SonarQube Cppcheck, PC-lint, MISRA-C 檢查
部署 伺服器部署、CDN 更新 OTA 更新、燒錄到硬體
回滾 重新部署舊版 MCUboot rollback
合規性 OWASP, SOC 2 MISRA-C, ISO 26262, IEC 62304
額外挑戰 瀏覽器相容性 硬體相依性、記憶體限制、即時性

工具怎麼選?三分鐘搞懂

cicd-tools

CI/CD 工具很多,但新手其實只要認識這幾個就夠了。我用選手機來比喻:

工具 像什麼 適合誰 一句話評價
GitHub Actions iPhone 已經用 GitHub 的所有人 最容易上手,生態最豐富
GitLab CI 三星旗艦 想要一站式平台的團隊 從程式碼到部署全包
Jenkins 組裝電腦 需要極度客製化的企業 什麼都能做,但什麼都要自己裝

根據 2026 年的數據,68% 的 GitHub 開源專案使用 GitHub Actions,而 GitLab CI 在企業市場年增長率達 34%。

韌體專案的工具選擇

韌體專案有些額外考量:

  • GitHub Actions:適合大多數韌體團隊。可以用 Docker container 跑交叉編譯,也有人分享了 NXP、STM32、Zephyr 等平台的範例。
  • GitLab CI:如果你的團隊需要 HIL 測試和合規性追蹤,GitLab 有比較好的整合方案。
  • Jenkins:如果你用的是商業編譯器(如 IAR、Keil)且授權綁定特定機器,Jenkins 的 self-hosted runner 比較容易設定。
  • IAR Build Tools:IAR 有專門的嵌入式 CI/CD 方案,可以在 Pipeline 裡跑 IAR 編譯器和靜態分析。

我的建議:不管軟體還是韌體,如果你是新手,直接用 GitHub Actions 開始。不需要額外設定伺服器,免費額度對個人專案綽綽有餘,而且網路上的教學資源最多。


動手做:你的第一個 CI Pipeline

cicd-first-success

說了這麼多,不如直接動手。

軟體版:Node.js 專案

在你的專案根目錄建立 .github/workflows/ci.yml:

# 這個檔案告訴 GitHub:每次有人推程式碼,就自動做以下的事

name: CI Pipeline          # Pipeline 的名字,隨你取

on:                        # 什麼時候觸發?
  push:                    # 有人推程式碼的時候
    branches: [main]       # 只針對 main 分支
  pull_request:            # 或是有人開 PR 的時候
    branches: [main]

jobs:                      # 要做哪些工作?
  test:                    # 工作名稱:test
    runs-on: ubuntu-latest # 在 Ubuntu 虛擬機上跑

    steps:                 # 具體步驟
      - uses: actions/checkout@v4    # 第一步:把程式碼拉下來

      - uses: actions/setup-node@v4  # 第二步:安裝 Node.js
        with:
          node-version: '20'

      - run: npm install             # 第三步:安裝套件

      - run: npm test                # 第四步:跑測試

就這樣,22 行 YAML。

韌體版:C/C++ 嵌入式專案

如果你的專案用 CMake + ARM GCC,可以這樣寫:

name: Firmware CI

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

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      # 安裝 ARM 交叉編譯工具鏈
      - name: 安裝 ARM GCC
        run: |
          sudo apt-get update
          sudo apt-get install -y gcc-arm-none-eabi

      # 用 CMake 建構韌體
      - name: 建構韌體
        run: |
          mkdir build && cd build
          cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/arm-gcc.cmake ..
          make -j$(nproc)

      # 靜態分析
      - name: 靜態分析(Cppcheck)
        run: |
          sudo apt-get install -y cppcheck
          cppcheck --enable=warning,style --error-exitcode=1 src/

      # 單元測試(在 Host 端跑,不需要硬體)
      - name: 單元測試
        run: |
          cd tests
          mkdir build && cd build
          cmake ..
          make -j$(nproc)
          ctest --output-on-failure

      # 保存編譯產物
      - name: 上傳韌體
        uses: actions/upload-artifact@v4
        with:
          name: firmware
          path: build/*.bin

兩個版本的結構完全一樣:觸發 → 環境設定 → 建構 → 測試 → 產出。只是用的工具不同而已。

把這個檔案推上 GitHub,到 Actions 頁籤,你會看到一個綠色的勾勾(或紅色的叉叉,如果測試沒過的話)。


新手常踩的坑

每個剛接觸 CI/CD 的人都會踩到一些坑,不管你是做軟體還是韌體:

坑 1:Pipeline 跑太久

現象:每次 push 要等 20 分鐘才知道結果。 原因:沒有快取依賴套件或工具鏈,每次都重新下載。 解法:加上快取設定。

軟體專案 — 快取 node_modules:

- uses: actions/cache@v4
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}

韌體專案 — 快取工具鏈和 Zephyr modules:

- uses: actions/cache@v4
  with:
    path: |
      <sub>/zephyr-sdk
      </sub>/.cache/west
    key: ${{ runner.os }}-zephyr-${{ hashFiles('west.yml') }}

根據 Somco Software 的分析,有效的快取策略可以讓嵌入式 CI 的建構時間減少 50% 以上。

坑 2:測試在本機過但 CI 上掛掉

現象:「我本機明明可以跑!」 原因:軟體專案通常是環境變數或版本差異。韌體專案更常見的是工具鏈版本不同 — 你本機用 ARM GCC 13.2,CI 上裝的是 12.3,某些 C11 語法或 linker 行為不一樣。 解法:用 Docker 統一環境。韌體專案特別建議把整個工具鏈封裝成 Docker image,團隊和 CI 共用同一個。

坑 3:把密鑰寫死在設定檔裡

現象:CI 設定檔裡直接寫 API_KEY=sk-xxxxx。韌體專案更危險的是把 OTA 簽章私鑰或量產金鑰放進 repo。 原因:圖方便。 解法:用 GitHub 的 Secrets 功能。在 Settings → Secrets 裡設定,然後在 YAML 裡用 ${{ secrets.OTA_SIGNING_KEY }} 存取。永遠不要把密鑰寫在程式碼裡。

坑 4:韌體專用 — 忽略二進位檔大小監控

現象:某天韌體突然塞不進 Flash。 原因:MCU 的 Flash 通常只有 256KB 到 1MB,沒有人注意到每次 commit 都在慢慢長大。 解法:在 Pipeline 裡加一步,自動檢查 .bin 檔大小,超過閾值就報錯:

- name: 檢查韌體大小
  run: |
    MAX_SIZE=262144  # 256KB
    ACTUAL_SIZE=$(stat -c%s build/zephyr/zephyr.bin)
    echo "Firmware size: $ACTUAL_SIZE bytes (max: $MAX_SIZE)"
    if [ "$ACTUAL_SIZE" -gt "$MAX_SIZE" ]; then
      echo "ERROR: Firmware exceeds Flash limit!"
      exit 1
    fi

坑 5:韌體專用 — 只在 Host 端測試,不做 HIL

現象:單元測試全過,但燒到板子上行為異常。 原因:Host 端模擬測不到硬體特有的行為 — 中斷時序、DMA 傳輸、周邊裝置互動。 解法:至少設定一塊開發板做基本的 HIL 測試。可以用 self-hosted runner 連接到實體硬體。初期不需要很複雜,能自動燒錄 + 跑 smoke test 就是巨大的進步。


為什麼你應該現在就開始

cicd-manual-vs-auto

CI/CD 表面上是一套工具,但本質上是一種開發文化的轉變。

它逼你思考幾個重要的問題:你的程式碼有測試嗎?你的建構流程可以被重複嗎?你敢在星期五下午部署嗎?你的韌體如果改了藍牙模組,有沒有自動驗證 Wi-Fi 功能沒被影響?

JetBrains 的調查指出,導入 CI/CD 的團隊不只是部署變快了,而是整個開發流程的品質都提升了 — 因為自動化迫使你把每個步驟都想清楚、寫清楚。

Infolitz 的嵌入式 CI/CD 專文也指出,嵌入式系統向來以開發週期長、手動測試瓶頸多、韌體發布風險高聞名 — 但現代工程團隊已經證明,這些問題都可以透過 CI/CD 自動化來解決。

2025 年的數據更驚人:76% 的 DevOps 團隊已經把 AI 整合進 CI/CD,用 AI 來自動選擇該跑哪些測試、偵測 Pipeline 中的異常模式。不只軟體,嵌入式領域的 CI/CD 也在快速演化 — IAR、Memfault 等廠商都在提供更完善的嵌入式 DevOps 工具鏈。

但不管工具怎麼變,核心理念始終沒變:讓機器做機器擅長的事,讓人做人擅長的事。

重複性的編譯、測試、燒錄、部署?交給機器。創造性的架構設計、硬體選型、產品決策?留給你自己。


你的下一步

如果這篇文章讓你對 CI/CD 有了基本概念,這裡是你可以做的下一步:

軟體工程師

  1. 今天就做:在你的任何一個 GitHub 專案裡,加上那 22 行 YAML
  2. 這週嘗試:為專案寫幾個簡單的單元測試,讓 CI 有東西可以跑
  3. 這個月挑戰:加上自動部署,讓程式碼推上去就自動更新到伺服器

韌體工程師

  1. 今天就做:把你的韌體建構流程寫成 GitHub Actions,至少做到「自動編譯不報錯」
  2. 這週嘗試:加上 Cppcheck 靜態分析和韌體大小檢查
  3. 這個月挑戰:把單元測試框架(Unity 或 Google Test)整合進 Pipeline,用 native_sim 或 Host 端模擬跑測試
  4. 下個季度目標:設定一塊開發板做 HIL 測試,自動燒錄 + smoke test

不需要一次到位。CI/CD 是一段旅程,不是一個開關。先從最簡單的「自動編譯 + 自動測試」開始,慢慢加上更多自動化步驟。

你會發現,當那個綠色勾勾第一次亮起來的時候,那種安心感是無價的。


延伸閱讀

通用 CI/CD

韌體 / 嵌入式 CI/CD


本文最初發布於 HackMD @BASHCAT。

8GB 的 RK3588 能跑多聰明的 LLM?ROCK 5C 用 NPU 實測 5 個模型

先講結論,省得你滑到最後: 在一片 8GB 的 RK3588 板子上,用 NPU 跑得最聰明的是 Qwen3-4B-Instruct-2507,我出的 7 題全對,但每秒只吐 3.7 個 token。 想要順一點的對話體驗,Qwen3.5-2B 的 8.4 tok/s 是比...