Skip to content
Published on

組込みシステム(くみこみしすてむ)&IoTプログラミング完全ガイド2025:ファームウェア、RTOS、通信プロトコル

Authors

はじめに:なぜ組込み/IoTか?

2025年現在(げんざい)、世界のIoTデバイス数(すう)は約(やく)300億(おく)を超(こ)えました。スマートホーム、産業(さんぎょう)センサー、ウェアラブル、自動運転車(じどううんてんしゃ)、スマートファクトリーに至(いた)るまで、組込みシステムは現代(げんだい)インフラの中核(ちゅうかく)です。一般的(いっぱんてき)なアプリ開発(かいはつ)と組込み開発は根本的(こんぽんてき)に異(こと)なる考(かんが)え方(かた)を必要(ひつよう)とします。メモリはKB単位(たんい)に限(かぎ)られ、CPUはMHz級(きゅう)、数年(すうねん)バッテリー動作(どうさ)、そしてリアルタイム制約(せいやく)を満(み)たさなければなりません。

本(ほん)ガイドでは組込みシステムの基礎(きそ)からIoT本番(ほんばん)システムまでフルスタックで扱(あつか)います。マイコン選定(せんてい)、開発環境(かんきょう)、RTOSベースのマルチタスク、ハードウェアインターフェース、センサー統合(とうごう)、IoTプロトコル、OTA、電力(でんりょく)管理(かんり)、Edge AI、セキュリティまで。

1. 組込みシステム vs 一般(いっぱん)コンピューティング

1.1 核心(かくしん)の違(ちが)い

項目(こうもく)一般組込み
CPU速度(そくど)GHzMHz
RAMGBKB〜MB
記憶(きおく)SSD/HDD TBFlash KB〜MB
OSLinux/Windows/macOSベアメタル/RTOS/組込みLinux
電力数十〜数百WμA〜mW
リアルタイムなし/弱(よわ)い強(つよ)い
寿命(じゅみょう)数年10-20年

1.2 資源(しげん)制約(せいやく)の思考(しこう)

組込み開発者(かいはつしゃ)は常(つね)に資源制約を意識(いしき)します。

  • メモリ割(わ)り当(あ)て:malloc/freeは最小限(さいしょうげん)、静的(せいてき)割り当てを優先(ゆうせん)
  • スタック:再帰(さいき)制限、ローカル配列(はいれつ)サイズ
  • CPU:浮動小数点(ふどうしょうすうてん)より整数(せいすう)
  • 電力:ほとんどの時間(じかん)スリープ、割り込みで起床(きしょう)

1.3 リアルタイム要件(ようけん)

  • Hard:締切(しめきり)遅延(ちえん)=システム失敗(しっぱい)(航空(こうくう)、医療(いりょう))
  • Firm:遅延=結果(けっか)無効(むこう)(ライブ動画(どうが))
  • Soft:遅延=品質(ひんしつ)低下(ていか)(マルチメディア)

2. マイコン(MCU)のラインナップ

2.1 主要(しゅよう)MCUプラットフォーム

MCUCPURAMFlash価格(かかく)特徴(とくちょう)
Arduino UnoAVR 16MHz2KB32KB$5-25学習(がくしゅう)
ESP32Xtensa 240MHz520KB4MB+$3-10Wi-Fi+BLE内蔵(ないぞう)
STM32F4Cortex-M4 168MHz192KB1MB$5-15産業用(さんぎょうよう)
STM32L0Cortex-M0+ 32MHz8KB64KB$1-5低電力
RP2040Dual M0+ 133MHz264KB2MB$4低価格
nRF52840M4F 64MHz256KB1MB$5-15BLE/Thread/Zigbee
ESP32-S3Xtensa 240MHz512KB8MB+$5-12Wi-Fi 6

2.2 MCU選定(せんてい)ガイド

  • IoT+Wi-Fi:ESP32
  • 低電力バッテリー:nRF52840、STM32L
  • 高性能(こうせいのう)制御(せいぎょ):STM32F4/F7
  • 学習/試作(しさく):Arduino Uno、Pico

3. 開発環境構築(こうちく)

3.1 主要(しゅよう)IDE/ツールチェーン

Arduino IDE (初心者(しょしんしゃ)向(む)け)

const int LED_PIN = 13;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
}

PlatformIO

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

ESP-IDF

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

static const char *TAG = "main";

void app_main(void) {
    ESP_LOGI(TAG, "Hello ESP32!");
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

3.2 デバッグツール

  • JTAG/SWD:ST-Link、J-Link
  • GDB+OpenOCD
  • シリアルモニター
  • ロジックアナライザー
  • オシロスコープ

4. RTOS(りあるたいむおーえす)の基礎

4.1 RTOS vs ベアメタル vs 組込みLinux

項目ベアメタルRTOS組込みLinux
複雑度(ふくざつど)
メモリ最小(さいしょう)KB〜数百KBMB+
マルチタスクスーパーループタスクプロセス
決定論(けっていろん)

4.2 RTOS核心概念(かくしんがいねん)

  • タスク:独立(どくりつ)実行(じっこう)単位、優先度(ゆうせんど)あり
  • スケジューラ:プリエンプティブ優先度ベース
  • コンテキストスイッチング
  • セマフォ、ミューテックス、キュー、イベントフラグ、ソフトウェアタイマー

4.3 優先度反転(はんてん)

低優先度タスクが高優先度タスクをブロックする現象(げんしょう)。

  • Priority Inheritance(優先度継承(けいしょう))
  • Priority Ceiling(優先度上限(じょうげん))

1997年 Mars Pathfinderで発生(はっせい)した有名(ゆうめい)なバグ。

5. FreeRTOS 深(ふか)掘(ぼ)り

5.1 タスク生成(せいせい)

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

void sensor_task(void *pv) {
    while (1) {
        float temp = read_temperature();
        printf("T: %.2f\n", temp);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void app_main(void) {
    xTaskCreate(sensor_task, "sensor", 4096, NULL, 5, NULL);
}

5.2 キュー

QueueHandle_t xQ;

typedef struct {
    float temperature;
    float humidity;
} sensor_data_t;

void producer(void *pv) {
    sensor_data_t d;
    while (1) {
        d.temperature = read_temp();
        d.humidity = read_humid();
        xQueueSend(xQ, &d, pdMS_TO_TICKS(100));
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

void consumer(void *pv) {
    sensor_data_t d;
    while (1) {
        if (xQueueReceive(xQ, &d, portMAX_DELAY)) {
            printf("T=%.1f H=%.1f\n", d.temperature, d.humidity);
        }
    }
}

5.3 セマフォとミューテックス

SemaphoreHandle_t xMutex;
int counter = 0;

void task(void *pv) {
    while (1) {
        if (xSemaphoreTake(xMutex, portMAX_DELAY)) {
            counter++;
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

5.4 メモリ管理(かんり)

heap_1/2/3/4/5が提供(ていきょう)されます。heap_4が推奨(すいしょう)。

void *p = pvPortMalloc(256);
if (p) vPortFree(p);
printf("Free: %u\n", xPortGetFreeHeapSize());

6. Zephyr RTOS

Linux Foundationが管理(かんり)するオープンソースRTOS。450以上(いじょう)のボードサポート、Device Tree、Kconfig。

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

int main(void) {
    gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    while (1) {
        gpio_pin_toggle_dt(&led);
        k_msleep(1000);
    }
    return 0;
}

7. ハードウェアインターフェース

7.1 GPIO

#include "driver/gpio.h"

void cfg_gpio(void) {
    gpio_config_t c = {
        .intr_type = GPIO_INTR_POSEDGE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = (1ULL << 4),
        .pull_up_en = 1,
    };
    gpio_config(&c);
}

7.2 I2C

2線(SDA/SCL)、100kHz-3.4MHz。

#include "driver/i2c.h"
#define SENSOR_ADDR 0x76

esp_err_t i2c_init(void) {
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = 21,
        .scl_io_num = 22,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000,
    };
    i2c_param_config(0, &conf);
    return i2c_driver_install(0, conf.mode, 0, 0, 0);
}

7.3 SPI

4線、全二重(ぜんにじゅう)、高速(こうそく)。

#include "driver/spi_master.h"

void spi_init(void) {
    spi_bus_config_t cfg = {
        .miso_io_num = 19,
        .mosi_io_num = 23,
        .sclk_io_num = 18,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 4096,
    };
    spi_bus_initialize(HSPI_HOST, &cfg, SPI_DMA_CH_AUTO);
}

7.4 UART

#include "driver/uart.h"

void uart_init(void) {
    uart_config_t c = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
    };
    uart_param_config(UART_NUM_1, &c);
    uart_driver_install(UART_NUM_1, 1024, 0, 0, NULL, 0);
}

7.5 ADC

#include "esp_adc/adc_oneshot.h"

adc_oneshot_unit_handle_t h;

void adc_init(void) {
    adc_oneshot_unit_init_cfg_t init = { .unit_id = ADC_UNIT_1 };
    adc_oneshot_new_unit(&init, &h);
    adc_oneshot_chan_cfg_t cfg = {
        .bitwidth = ADC_BITWIDTH_12,
        .atten = ADC_ATTEN_DB_12,
    };
    adc_oneshot_config_channel(h, ADC_CHANNEL_0, &cfg);
}

7.6 PWM

#include "driver/ledc.h"

void pwm_init(void) {
    ledc_timer_config_t t = {
        .duty_resolution = LEDC_TIMER_13_BIT,
        .freq_hz = 5000,
    };
    ledc_timer_config(&t);
}

8. センサー統合(とうごう)

8.1 温湿度(おんしつど)(DHT22、BME280)

#include <DHT.h>
#define DHTPIN 4
DHT dht(DHTPIN, DHT22);

void setup() {
  Serial.begin(115200);
  dht.begin();
}

void loop() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  Serial.printf("T:%.1f H:%.1f\n", t, h);
  delay(2000);
}

8.2 加速度(かそくど)(MPU6050)

#include <MPU6050.h>

MPU6050 mpu;

void setup() {
  Wire.begin();
  mpu.initialize();
}

void loop() {
  int16_t ax, ay, az, gx, gy, gz;
  mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  delay(100);
}

8.3 GPS(NEO-6M)

#include <TinyGPS++.h>
TinyGPSPlus gps;

void loop() {
  while (Serial2.available()) {
    if (gps.encode(Serial2.read()) && gps.location.isValid()) {
      Serial.printf("%.6f %.6f\n", gps.location.lat(), gps.location.lng());
    }
  }
}

9. IoT通信(つうしん)プロトコル比較(ひかく)

プロトコル範囲(はんい)帯域電力用途(ようと)
Wi-Fi50-100mホーム
BLE10-50mウェアラブル
Zigbee10-100mスマートホーム
Thread10-100mMatter
LoRaWAN2-15km極低極低スマートシティ
NB-IoTセル遠隔資産(えんかくしさん)

9.1 Wi-Fi接続(せつぞく)

#include "esp_wifi.h"

void wifi_init_sta(void) {
    esp_netif_init();
    esp_event_loop_create_default();
    esp_netif_create_default_wifi_sta();
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    esp_wifi_init(&cfg);
    wifi_config_t wc = {
        .sta = { .ssid = "MyWiFi", .password = "MyPass" },
    };
    esp_wifi_set_mode(WIFI_MODE_STA);
    esp_wifi_set_config(WIFI_IF_STA, &wc);
    esp_wifi_start();
}

10. MQTT 深(ふか)掘(ぼ)り

10.1 核心概念(かくしんがいねん)

  • ブローカー:Mosquitto、EMQX、HiveMQ
  • クライアント:Publisher/Subscriber
  • トピック:階層的(かいそうてき)文字列(もじれつ)
  • QoS:0/1/2
  • Retained Message
  • LWT(遺言(ゆいごん)メッセージ)

10.2 ESP32 MQTTクライアント

#include "mqtt_client.h"

esp_mqtt_client_handle_t client;

static void mqtt_event_handler(void *args, esp_event_base_t base,
                                int32_t id, void *data) {
    esp_mqtt_event_handle_t e = data;
    switch ((esp_mqtt_event_id_t)id) {
    case MQTT_EVENT_CONNECTED:
        esp_mqtt_client_subscribe(client, "device/cmd", 1);
        break;
    case MQTT_EVENT_DATA:
        printf("%.*s\n", e->data_len, e->data);
        break;
    default: break;
    }
}

void mqtt_start(void) {
    esp_mqtt_client_config_t cfg = {
        .broker.address.uri = "mqtts://mqtt.example.com:8883",
    };
    client = esp_mqtt_client_init(&cfg);
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
    esp_mqtt_client_start(client);
}

10.3 トピック設計(せっけい)

  • 階層的に直感的(ちょっかんてき):tenant/site/device/metric
  • ワイルドカード:+単一(たんいつ)、#複数(ふくすう)
  • 読(よ)み書(か)きパス分離(ぶんり)

11. CoAP、LoRaWAN、BLE

11.1 CoAP

RFC 7252、REST、UDP、軽量(けいりょう)。

11.2 LoRaWAN

#include "LoRaWan_APP.h"
uint8_t devEui[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };

void setup() {
  Mcu.begin();
  LoRaWAN.init(loraWanClass, loraWanRegion);
}

void loop() {
  if (deviceState == DEVICE_STATE_SEND) {
    prepareTxFrame(appPort);
    LoRaWAN.send();
  }
  LoRaWAN.cycle(txDutyCycleTime);
}

11.3 BLE

#include <BLEDevice.h>
#include <BLEServer.h>

BLECharacteristic *pChar;

void setup() {
  BLEDevice::init("ESP32_Sensor");
  BLEServer *s = BLEDevice::createServer();
  BLEService *svc = s->createService("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
  pChar = svc->createCharacteristic(
    "beb5483e-36e1-4688-b7f5-ea07361b26a8",
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  svc->start();
  s->getAdvertising()->start();
}

12. OTA ファームウェア更新(こうしん)

12.1 基本(きほん)

  • A/Bパーティション
  • ロールバック
  • HTTPS+署名(しょめい)検証(けんしょう)
  • 電源(でんげん)喪失(そうしつ)耐性(たいせい)

12.2 ESP-IDF OTA

#include "esp_https_ota.h"

void ota_task(void *pv) {
    esp_http_client_config_t cfg = {
        .url = "https://ota.example.com/firmware.bin",
        .cert_pem = (char *)server_cert_pem_start,
    };
    esp_https_ota_config_t ota = { .http_config = &cfg };
    if (esp_https_ota(&ota) == ESP_OK) {
        esp_restart();
    }
    vTaskDelete(NULL);
}

12.3 Secure Boot + Flash暗号化(あんごうか)

  • Secure Boot:RSA/ECDSA署名
  • Flash Encryption:AES-256
  • eFuse:ワンタイムプログラマブル

13. 電力(でんりょく)管理(かんり)

13.1 ESP32スリープモード

モード電流(でんりゅう)RAM復帰(ふっき)
Active100-240mA--
Modem-Sleep3-20mA保持(ほじ)μs
Light-Sleep0.8mA保持ms
Deep-Sleep10μARTCのみ数百ms
Hibernation5μAなし起動(きどう)

13.2 Deep Sleep

#include "esp_sleep.h"

RTC_DATA_ATTR int boot_count = 0;

void app_main(void) {
    boot_count++;
    esp_sleep_enable_timer_wakeup(30 * 60 * 1000000ULL);
    esp_deep_sleep_start();
}

13.3 バッテリー寿命(じゅみょう)計算(けいさん)

平均電流(へいきんでんりゅう)=(アクティブ電流×アクティブ時間 + スリープ電流×スリープ時間)/全時間(ぜんじかん)

14. Edge AI on MCU

14.1 TensorFlow Lite Micro

#include "tensorflow/lite/micro/micro_interpreter.h"

constexpr int kTensorArenaSize = 100 * 1024;
uint8_t tensor_arena[kTensorArenaSize];

void setup() {
  const tflite::Model* model = tflite::GetModel(g_model);
  static tflite::MicroMutableOpResolver<5> resolver;
  static tflite::MicroInterpreter interpreter(
    model, resolver, tensor_arena, kTensorArenaSize);
  interpreter.AllocateTensors();
  interpreter.Invoke();
}

14.2 Edge Impulse

ノーコード機械学習(きかいがくしゅう)パイプライン。

15. セキュリティ

15.1 チェックリスト

  • Secure Boot有効化(ゆうこうか)
  • Flash Encryption
  • TLS 1.2+
  • 証明書(しょうめいしょ)検証
  • ハードウェア暗号(あんごう)加速(かそく)
  • デバッグポート無効化(むこうか)
  • ファームウェア署名
  • TRNG
  • 鍵(かぎ)ローテーション
  • 最小権限(さいしょうけんげん)

15.2 Mutual TLS

esp_mqtt_client_config_t cfg = {
    .broker.address.uri = "mqtts://broker.example.com:8883",
    .broker.verification.certificate = (const char*)server_ca_pem,
    .credentials.authentication.certificate = (const char*)client_cert_pem,
    .credentials.authentication.key = (const char*)client_key_pem,
};

16. 本番(ほんばん)考慮(こうりょ)事項(じこう)

16.1 ログと監視(かんし)

  • ローカルログレベル
  • 異常(いじょう)時(じ)のみ遠隔(えんかく)送信(そうしん)
  • テレメトリ:CPU/メモリ/電池(でんち)
  • クラッシュダンプ

16.2 デバイスライフサイクル

  1. プロビジョニング
  2. オンボーディング
  3. 運用(うんよう)
  4. 廃棄(はいき)

16.3 製造(せいぞう)

  • パーティションテーブル
  • MACベース固有(こゆう)ID
  • 自動(じどう)テスト治具(じぐ)
  • 認証(にんしょう):FCC、CE、IC、KC

17. 実習(じっしゅう)プロジェクト案

  1. 環境(かんきょう)モニター:ESP32+BME280+MQTT
  2. スマートドアロック:ESP32+RFID+BLE
  3. 農場(のうじょう)センサーネットワーク:LoRaWAN
  4. ウェアラブル心拍計(しんぱくけい):nRF52
  5. 音声(おんせい)制御(せいぎょ)ハブ:ESP32-S3+TFLite Micro
  6. 工場(こうじょう)資産(しさん)追跡(ついせき):LoRaWAN+GPS

18. クイズ

Q1. FreeRTOSにおける優先度反転(ゆうせんどはんてん)問題(もんだい)の解決策(かいけつさく)二(ふた)つは?

A:Priority Inheritance(優先度継承(けいしょう))とPriority Ceiling(優先度上限(じょうげん))です。前者(ぜんしゃ)はミューテックスを保持(ほじ)している低優先度タスクの優先度を一時的(いちじてき)に上(あ)げ、後者(こうしゃ)は最大(さいだい)優先度を事前(じぜん)に指定(してい)します。

Q2. MQTT QoSレベル0/1/2の違い?

A:QoS 0は「最大(さいだい)1回(かい)」(損失(そんしつ)可能(かのう))、QoS 1は「最低(さいてい)1回」(重複(じゅうふく)可能)、QoS 2は「正確(せいかく)に1回」。センサーテレメトリは通常(つうじょう)0か1、重要(じゅうよう)なコマンドは2を使(つか)います。

Q3. OTA更新でA/Bパーティションが必要(ひつよう)な理由(りゆう)?

A:新(あたら)しいファームウェアを別(べつ)のパーティションに書(か)き込(こ)みながら現在(げんざい)のファームウェアが動作を維持(いじ)し、失敗(しっぱい)時(じ)に自動(じどう)ロールバックが可能です。ダウンロード中(ちゅう)の電源(でんげん)喪失(そうしつ)でもブリックしません。

Q4. I2CとSPIの主(おも)な違い?

A:I2Cは2線(SDA/SCL)でアドレスで機器(きき)を識別(しきべつ)、100kHz-3.4MHz。SPIは4線(MOSI/MISO/SCK/CS)でCS線で機器選択、全二重、数十MHz。単純(たんじゅん)な複数センサーはI2C、高速ディスプレイ/FlashはSPIが適切(てきせつ)です。

Q5. ESP32 Deep Sleepでデータを保持(ほじ)する方法(ほうほう)?

A:RTC_DATA_ATTRマクロで変数(へんすう)をRTCメモリに配置(はいち)するとDeep Sleep中(ちゅう)も保持されます(8KB制限(せいげん))。例:RTC_DATA_ATTR int boot_count = 0;。より大(おお)きなデータはNVSまたはフラッシュに保存(ほぞん)します。

19. 参考(さんこう)資料(しりょう)

  1. FreeRTOS公式(こうしき)ドキュメント
  2. Zephyr Project Documentation
  3. ESP-IDF Programming Guide
  4. STM32 HAL Driver
  5. MQTT 5.0 Specification
  6. CoAP RFC 7252
  7. LoRa Alliance Technical Docs
  8. TensorFlow Lite Micro
  9. Edge Impulse Docs
  10. Arm Mbed OS Documentation
  11. Making Embedded Systems - Elecia White
  12. Mastering STM32 - Carmine Noviello
  13. The Hardware Hacker - Andrew Huang

結論(けつろん)

組込み/IoT開発はハードウェア、リアルタイム、制約環境、ネットワーキング、セキュリティが交差(こうさ)する魅力的(みりょくてき)な分野(ぶんや)です。ArduinoからESP32/STM32/Zephyrへ進化(しんか)し、本番(ほんばん)水準(すいじゅん)のOTA、セキュリティ、電力管理を備(そな)えたシステムを作(つく)れます。2025年、Matter、Thread、Edge AI標準(ひょうじゅん)が成熟(せいじゅく)し、組込み開発者(かいはつしゃ)の機会(きかい)はさらに拡大(かくだい)しています。