Skip to content

✍️ 필사 모드: Complete Embedded Systems & IoT Programming Guide 2025: Firmware, RTOS, Protocols

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

Introduction: Why Embedded/IoT?

As of 2025, the global IoT device count has surpassed approximately 30 billion. From smart homes, industrial sensors, wearables, autonomous vehicles, and smart factories, embedded systems are core components of modern infrastructure. General application development and embedded development require fundamentally different mindsets. Memory is limited to KB, CPUs run at MHz, devices must operate for years on batteries, and they must satisfy real-time constraints.

This guide covers the full stack from embedded system fundamentals to IoT production systems: microcontroller selection, development environment, RTOS-based multitasking, hardware interfaces, sensor integration, IoT protocols, OTA, power management, Edge AI, and security.

1. Embedded Systems vs General Computing

1.1 Core Differences

ItemGeneral ComputingEmbedded Systems
CPU speedGHzMHz (tens to hundreds)
RAMGBKB to MB
StorageSSD/HDD TBFlash KB to MB
OSLinux/Windows/macOSBare-metal, RTOS, embedded Linux
PowerTens to hundreds of wattsuA to mW
Real-timeNone or weakStrong (microsecond scale)
LifetimeYears10-20 years
UpdatesFrequentOTA, rare

1.2 Resource-Constrained Mindset

Embedded developers must always be aware of resource constraints.

  • Memory allocation: Minimize malloc/free, prefer static allocation
  • Stack size: Limit recursion, watch local array sizes
  • CPU cycles: Integer over float, avoid unnecessary copies
  • Power: Spend most time in sleep, wake via interrupts

1.3 Real-Time Requirements

Real-time systems must satisfy not only correctness but also time constraints.

  • Hard Real-Time: Missed deadline = system failure (avionics, medical)
  • Firm Real-Time: Missed deadline = invalid result (live video streaming)
  • Soft Real-Time: Missed deadline = degraded quality (multimedia)

2. Microcontroller (MCU) Landscape

2.1 Major MCU Platforms

MCUCPURAMFlashPriceFeatures
Arduino Uno (ATmega328P)8-bit AVR 16MHz2KB32KB$5-25Learning, simple
ESP32Xtensa dual-core 240MHz520KB4MB+$3-10Wi-Fi + BLE built-in
STM32F4 (Cortex-M4)ARM 168MHz FPU192KB1MB$5-15Industrial
STM32L0 (Cortex-M0+)ARM 32MHz8KB64KB$1-5Low power
Raspberry Pi Pico (RP2040)Dual Cortex-M0+ 133MHz264KB2MB$4Cheap, PIO
nRF52840Cortex-M4F 64MHz256KB1MB$5-15BLE/Thread/Zigbee
ESP32-S3Xtensa dual-core 240MHz512KB8MB+$5-12Wi-Fi 6, AI accel

2.2 MCU Selection Guide

  • IoT + Wi-Fi: ESP32 or ESP32-S3
  • Low-power battery: nRF52840, STM32L series
  • High-perf control: STM32F4/F7, Teensy 4
  • Learning/prototype: Arduino Uno, Pico
  • Industrial: STM32F series, NXP iMX RT

2.3 SoC vs MCU vs SBC

  • MCU: Single chip, KB-MB memory, bare-metal/RTOS, mW power
  • SoC: Can run Linux, Raspberry Pi, higher power
  • SBC: Raspberry Pi, BeagleBone, full Linux

3. Development Environments

3.1 Major IDEs/Toolchains

Arduino IDE (beginner-friendly)

// blink.ino
const int LED_PIN = 13;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(115200);
  Serial.println("Arduino started");
}

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

PlatformIO (multi-platform)

; platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
  bblanchon/ArduinoJson @ ^7.0.0
  knolleary/PubSubClient @ ^2.8

ESP-IDF (ESP32 native SDK)

#include <stdio.h>
#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 from ESP32!");
    while (1) {
        ESP_LOGI(TAG, "Tick %lld", esp_timer_get_time() / 1000000);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

3.2 Debugging Tools

  • JTAG/SWD: Hardware debuggers (ST-Link, J-Link, Black Magic Probe)
  • GDB + OpenOCD: Open-source debug chain
  • Serial Monitor: UART log output
  • Logic Analyzer: Digital signal analysis
  • Oscilloscope: Analog measurement

4. RTOS Fundamentals

4.1 RTOS vs Bare-metal vs Embedded Linux

ItemBare-metalRTOSEmbedded Linux
ComplexityLowMediumHigh
MemoryMinimalKB to hundreds of KBMB+
MultitaskingSuper loopTask-basedProcess/thread
DeterminismHighHighMedium
Boot timeInstantMillisecondsSeconds
ExampleArduinoESP32Raspberry Pi

4.2 RTOS Core Concepts

  • Task/Thread: Independent execution unit with priority
  • Scheduler: Task selection (preemptive priority-based)
  • Context Switching: Register save/restore on task switch
  • Semaphore: Synchronization primitive (binary, counting)
  • Mutex: Mutual exclusion (with priority inheritance)
  • Queue: Thread-safe inter-task messaging
  • Event Flag: Multi-event wait
  • Software Timer: Periodic/one-shot timer callbacks

4.3 Priority Inversion

A low-priority task blocks a high-priority task. Solutions:

  • Priority Inheritance: Temporarily raise mutex holder's priority
  • Priority Ceiling: Assign maximum priority to the mutex

This is a famous bug that actually occurred on Mars Pathfinder in 1997.

5. FreeRTOS Deep Dive

5.1 Task Creation and Scheduling

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

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

void led_task(void *pvParameters) {
    int pin = (int)pvParameters;
    gpio_set_direction(pin, GPIO_MODE_OUTPUT);
    while (1) {
        gpio_set_level(pin, 1);
        vTaskDelay(pdMS_TO_TICKS(500));
        gpio_set_level(pin, 0);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

void app_main(void) {
    xTaskCreate(sensor_task, "sensor", 4096, NULL, 5, NULL);
    xTaskCreate(led_task, "led", 2048, (void*)2, 3, NULL);
}

5.2 Queue Example

QueueHandle_t xSensorQueue;

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

void producer_task(void *pv) {
    sensor_data_t data;
    while (1) {
        data.temperature = read_temp();
        data.humidity = read_humid();
        data.timestamp = xTaskGetTickCount();
        if (xQueueSend(xSensorQueue, &data, pdMS_TO_TICKS(100)) != pdPASS) {
            printf("Queue full!\n");
        }
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

void consumer_task(void *pv) {
    sensor_data_t data;
    while (1) {
        if (xQueueReceive(xSensorQueue, &data, portMAX_DELAY) == pdPASS) {
            printf("Received: T=%.1f H=%.1f\n", data.temperature, data.humidity);
        }
    }
}

void app_main(void) {
    xSensorQueue = xQueueCreate(10, sizeof(sensor_data_t));
    xTaskCreate(producer_task, "prod", 4096, NULL, 5, NULL);
    xTaskCreate(consumer_task, "cons", 4096, NULL, 4, NULL);
}

5.3 Semaphores and Mutexes

SemaphoreHandle_t xMutex;
SemaphoreHandle_t xBinarySemaphore;
int shared_counter = 0;

void task_a(void *pv) {
    while (1) {
        if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
            shared_counter++;
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

void IRAM_ATTR gpio_isr_handler(void *arg) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

5.4 Memory Management

FreeRTOS provides multiple heap implementations: heap_1 (alloc only), heap_2 (with free, fragmentation), heap_3 (malloc wrapper), heap_4 (with coalescing, recommended), heap_5 (multi-region).

void *ptr = pvPortMalloc(256);
if (ptr != NULL) {
    vPortFree(ptr);
}
printf("Free heap: %u\n", xPortGetFreeHeapSize());
printf("Min ever: %u\n", xPortGetMinimumEverFreeHeapSize());

6. Zephyr RTOS

6.1 Zephyr Features

Zephyr is an open-source RTOS managed by the Linux Foundation with 450+ board support, device tree, Kconfig, POSIX compatibility, built-in BLE/802.15.4/LoRa/Thread, and West meta build tool.

6.2 Zephyr Hello World

#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) {
    if (!gpio_is_ready_dt(&led)) return 0;
    gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    while (1) {
        gpio_pin_toggle_dt(&led);
        k_msleep(1000);
    }
    return 0;
}

6.3 Device Tree Overlay

/* boards/esp32.overlay */
/ {
    aliases {
        led0 = &my_led;
    };
    leds {
        compatible = "gpio-leds";
        my_led: led_0 {
            gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
            label = "Green LED";
        };
    };
};

7. Hardware Interfaces

7.1 GPIO

#include "driver/gpio.h"

void configure_gpio(void) {
    gpio_config_t io_conf = {
        .intr_type = GPIO_INTR_POSEDGE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = (1ULL << 4),
        .pull_up_en = 1,
    };
    gpio_config(&io_conf);
    gpio_install_isr_service(0);
    gpio_isr_handler_add(4, gpio_isr_handler, (void*) 4);
}

7.2 I2C

Two-wire (SDA, SCL), supports multiple devices. Speeds: 100kHz/400kHz/1MHz/3.4MHz.

#include "driver/i2c.h"

#define I2C_MASTER_NUM 0
#define SENSOR_ADDR    0x76

esp_err_t i2c_master_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(I2C_MASTER_NUM, &conf);
    return i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
}

7.3 SPI

4-wire (MOSI/MISO/SCK/CS), full duplex, tens of MHz. Used for flash, SD cards, displays.

#include "driver/spi_master.h"

spi_device_handle_t spi;

void spi_init(void) {
    spi_bus_config_t buscfg = {
        .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_device_interface_config_t devcfg = {
        .clock_speed_hz = 10 * 1000 * 1000,
        .mode = 0,
        .spics_io_num = 5,
        .queue_size = 7,
    };
    spi_bus_initialize(HSPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
}

7.4 UART

Asynchronous serial, start/stop bits, 9600-115200+ bps.

#include "driver/uart.h"

void uart_init(void) {
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
    };
    uart_param_config(UART_NUM_1, &uart_config);
    uart_set_pin(UART_NUM_1, 17, 16, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    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 adc1_handle;

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

7.6 PWM

#include "driver/ledc.h"

void pwm_init(void) {
    ledc_timer_config_t timer = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .duty_resolution = LEDC_TIMER_13_BIT,
        .timer_num = LEDC_TIMER_0,
        .freq_hz = 5000,
        .clk_cfg = LEDC_AUTO_CLK,
    };
    ledc_timer_config(&timer);
    ledc_channel_config_t channel = {
        .gpio_num = 18,
        .duty = 4096,
    };
    ledc_channel_config(&channel);
}

8. Sensor Integration in Practice

8.1 Temperature/Humidity (DHT22, BME280)

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

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

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

8.2 Accelerometer/Gyroscope (MPU6050)

#include <Wire.h>
#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);
  Serial.printf("Accel: %d %d %d\n", ax, ay, az);
  delay(100);
}

8.3 GPS (NEO-6M)

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

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600);
}

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

9. IoT Protocol Comparison

9.1 Protocol Matrix

ProtocolLayerRangeBandwidthPowerTopologyUse Cases
Wi-FiL1-L250-100mHighHighStarHome IoT
Bluetooth LEL1-L210-50mMediumLowStar/MeshWearables
ZigbeeL1-L210-100mLowLowMeshSmart home
ThreadL1-L310-100mLowLowMeshMatter-based
LoRa/LoRaWANL1-L22-15kmVery lowVery lowStarSmart city
NB-IoTL1-L2CellularLowLowCellularRemote assets
MQTTL7Any--Pub/SubGeneral IoT
CoAPL7Any--RESTConstrained
AMQPL7Any--QueueEnterprise
HTTP/RESTL7Any--Req/ResGeneral

9.2 Wi-Fi Connection (ESP32)

#include "esp_wifi.h"
#include "esp_event.h"

static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                               int32_t event_id, void* event_data) {
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        printf("Got IP: " IPSTR "\n", IP2STR(&event->ip_info.ip));
    }
}

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 wifi_config = {
        .sta = { .ssid = "MyWiFi", .password = "MyPassword" },
    };
    esp_wifi_set_mode(WIFI_MODE_STA);
    esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
    esp_wifi_start();
}

10. MQTT Deep Dive

10.1 MQTT Core Concepts

  • Broker: Message mediator (Mosquitto, EMQX, HiveMQ)
  • Client: Publisher or subscriber
  • Topic: Hierarchical string (sensor/temperature/room1)
  • QoS: 0 (at most once), 1 (at least once), 2 (exactly once)
  • Retained Message: Broker stores, delivered to new subscribers immediately
  • Last Will Testament (LWT): Auto-published on abnormal disconnect

10.2 ESP32 MQTT Client

#include "mqtt_client.h"

esp_mqtt_client_handle_t client;

static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
                                int32_t event_id, void *event_data) {
    esp_mqtt_event_handle_t event = event_data;
    switch ((esp_mqtt_event_id_t)event_id) {
    case MQTT_EVENT_CONNECTED:
        printf("MQTT connected\n");
        esp_mqtt_client_subscribe(client, "device/cmd", 1);
        break;
    case MQTT_EVENT_DATA:
        printf("Topic: %.*s\n", event->topic_len, event->topic);
        break;
    default: break;
    }
}

void mqtt_start(void) {
    esp_mqtt_client_config_t mqtt_cfg = {
        .broker.address.uri = "mqtts://mqtt.example.com:8883",
        .credentials.username = "device01",
        .credentials.authentication.password = "secret",
        .session.last_will.topic = "device/status",
        .session.last_will.msg = "offline",
        .session.last_will.qos = 1,
        .session.last_will.retain = 1,
    };
    client = esp_mqtt_client_init(&mqtt_cfg);
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
    esp_mqtt_client_start(client);
}

10.3 Topic Design Best Practices

  • Hierarchical and intuitive: tenant/site/device/metric
  • Use wildcards: + (single level), # (multi-level)
  • Examples: home/+/temperature, factory/line1/#
  • No PII
  • Separate read/write paths: device/+/cmd vs device/+/state

11. CoAP, LoRaWAN, BLE

11.1 CoAP

RFC 7252, REST style, UDP-based, very lightweight.

#include "coap3/coap.h"

void coap_client_example(void) {
    coap_context_t *ctx = coap_new_context(NULL);
    coap_address_t dst;
    coap_address_init(&dst);
    coap_session_t *session = coap_new_client_session(ctx, NULL, &dst, COAP_PROTO_UDP);
    coap_pdu_t *pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_CODE_GET,
        coap_new_message_id(session), coap_session_max_pdu_size(session));
    coap_add_option(pdu, COAP_OPTION_URI_PATH, 4, (const uint8_t*)"temp");
    coap_send(session, pdu);
}

11.2 LoRaWAN

Long range (km), low bandwidth (kbps), low power (years battery). Good for agriculture, environmental monitoring.

#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();
    deviceState = DEVICE_STATE_CYCLE;
  }
  LoRaWAN.cycle(txDutyCycleTime);
}

11.3 BLE

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

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

BLECharacteristic *pCharacteristic;

void setup() {
  BLEDevice::init("ESP32_Sensor");
  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  pService->start();
  pServer->getAdvertising()->start();
}

void loop() {
  float temp = readTemp();
  pCharacteristic->setValue((uint8_t*)&temp, sizeof(temp));
  pCharacteristic->notify();
  delay(1000);
}

12. OTA Firmware Updates

12.1 OTA Basics

  • A/B partitions: Current firmware (A) keeps running while new one (B) is written
  • Rollback: Automatic fallback on boot failure or sanity check failure
  • Security: HTTPS + signature verification required
  • Interrupt-resilient: Must survive power loss during download

12.2 ESP-IDF OTA Example

#include "esp_ota_ops.h"
#include "esp_https_ota.h"

void ota_task(void *pv) {
    esp_http_client_config_t config = {
        .url = "https://ota.example.com/firmware.bin",
        .cert_pem = (char *)server_cert_pem_start,
        .timeout_ms = 5000,
    };
    esp_https_ota_config_t ota_config = { .http_config = &config };
    esp_err_t ret = esp_https_ota(&ota_config);
    if (ret == ESP_OK) {
        printf("OTA successful. Restarting...\n");
        esp_restart();
    }
    vTaskDelete(NULL);
}

void mark_valid_after_tests(void) {
    esp_ota_img_states_t state;
    const esp_partition_t *running = esp_ota_get_running_partition();
    if (esp_ota_get_state_partition(running, &state) == ESP_OK) {
        if (state == ESP_OTA_IMG_PENDING_VERIFY) {
            if (self_tests_passed()) {
                esp_ota_mark_app_valid_cancel_rollback();
            } else {
                esp_ota_mark_app_invalid_rollback_and_reboot();
            }
        }
    }
}

12.3 Secure Boot + Flash Encryption

  • Secure Boot: RSA/ECDSA signature on bootloader, firmware
  • Flash Encryption: AES-256 encryption of external flash
  • eFuse: Store keys in one-time programmable on-chip memory

13. Power Management

13.1 ESP32 Sleep Modes

ModeCurrentRAM retainedWake timeWake sources
Active100-240 mAYes--
Modem-Sleep3-20 mAYesusAuto
Light-Sleep0.8 mAYesmsTimer, GPIO, UART
Deep-Sleep10 uARTC onlyHundreds of msTimer, EXT0/1, Touch, ULP
Hibernation5 uANoFrom bootRTC Timer, EXT1

13.2 Deep Sleep Example

#include "esp_sleep.h"

RTC_DATA_ATTR int boot_count = 0;

void app_main(void) {
    boot_count++;
    printf("Boot count: %d\n", boot_count);
    collect_and_send();
    esp_sleep_enable_timer_wakeup(30 * 60 * 1000000ULL);
    esp_sleep_enable_ext0_wakeup(GPIO_NUM_25, 0);
    printf("Entering deep sleep\n");
    esp_deep_sleep_start();
}

13.3 Battery Life Calculation

Battery: 2000 mAh
Avg current = (Active_mA * Active_time + Sleep_mA * Sleep_time) / Total_time

Example: 5s active (100 mA) + 30 min sleep (0.01 mA)
Avg = (100*5 + 0.01*1800) / 1805 = 0.29 mA
Life = 2000 / 0.29 / 24 = ~287 days

14. Edge AI on MCU

14.1 TensorFlow Lite Micro

#include "tensorflow/lite/micro/micro_interpreter.h"
#include "model_data.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;
  resolver.AddConv2D();
  resolver.AddMaxPool2D();
  resolver.AddFullyConnected();
  resolver.AddSoftmax();
  resolver.AddRelu();

  static tflite::MicroInterpreter interpreter(
    model, resolver, tensor_arena, kTensorArenaSize);
  interpreter.AllocateTensors();

  TfLiteTensor* input = interpreter.input(0);
  for (int i = 0; i < input->bytes; i++) {
    input->data.uint8[i] = sensor_reading[i];
  }
  interpreter.Invoke();
  TfLiteTensor* output = interpreter.output(0);
}

14.2 Edge Impulse

No-code ML pipeline tool: data collection, preprocessing, training, MCU deployment automated.

15. Security

15.1 Embedded Security Checklist

  • Enable Secure Boot (signed firmware only)
  • Enable Flash Encryption (protect sensitive data)
  • TLS 1.2+ for all network traffic
  • Verify TLS certificate chain
  • Use hardware crypto accelerators (AES, SHA, RSA/ECC)
  • Disable debug ports in production (JTAG/SWD)
  • Sign firmware (ECDSA), verify in bootloader
  • Use TRNG for random numbers
  • Enable key rotation via OTA
  • Least privilege, disable unused services/ports

15.2 Mutual TLS Example

esp_mqtt_client_config_t mqtt_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. Production Considerations

16.1 Logging and Monitoring

  • Local log levels: DEBUG/INFO/WARN/ERROR
  • Remote log transmission only on anomaly (bandwidth save)
  • Telemetry: CPU/memory/battery/signal strength
  • Crash dumps: ESP32 Core Dump, store on flash and transmit

16.2 Device Lifecycle

  1. Provisioning: Factory setup
  2. Onboarding: User Wi-Fi/account linking (BLE, SoftAP, WPS)
  3. Operation: Normal operation, OTA updates
  4. Decommissioning: Delete keys, factory reset

16.3 Manufacturing and Volume

  • Partition table: bootloader, app, NVS, OTA, user data
  • MAC-based unique ID
  • Automated test fixtures with JTAG + test firmware
  • Certifications: FCC, CE, IC, KC

17. Practical Project Ideas

  1. Environment Monitor: ESP32 + BME280 + MQTT → Grafana dashboard
  2. Smart Doorlock: ESP32 + RFID/fingerprint + BLE mobile app
  3. Farm Sensor Network: LoRaWAN + soil moisture + gateway
  4. Wearable Heart Monitor: nRF52 + MAX30102 + BLE
  5. Voice-Controlled Hub: ESP32-S3 + microphone + TFLite Micro
  6. Factory Asset Tracking: LoRaWAN + GPS + NB-IoT fallback

18. Quiz

Q1. What are two solutions to priority inversion in FreeRTOS?

A: Priority Inheritance and Priority Ceiling. The former temporarily raises the priority of a mutex holder to that of the highest-priority waiter; the latter pre-assigns a maximum priority to the mutex when created.

Q2. What are the differences between MQTT QoS levels 0, 1, and 2?

A: QoS 0 is "at most once" (fire and forget, may be lost), QoS 1 is "at least once" (requires PUBACK, may duplicate), QoS 2 is "exactly once" (4-way handshake, slowest). Sensor telemetry typically uses 0 or 1; critical commands use 2.

Q3. Why do OTA updates use A/B partitions?

A: New firmware is written to a separate partition (B) while the current one (A) keeps running. On failure, automatic rollback to the previous firmware occurs. The device cannot be bricked by power loss during download.

Q4. What are the main differences between I2C and SPI?

A: I2C uses 2 wires (SDA/SCL), addresses distinguish devices, speeds 100kHz-3.4MHz, relatively slow. SPI uses 4 wires (MOSI/MISO/SCK/CS), CS line selects devices, full-duplex, tens of MHz. Simple multi-sensor setups use I2C; high-speed displays/flash use SPI.

Q5. How do you persist data across ESP32 deep sleep?

A: Use the RTC_DATA_ATTR macro to place variables in RTC memory (8KB limit), which survives deep sleep. Example: RTC_DATA_ATTR int boot_count = 0;. For larger data, use NVS (Non-Volatile Storage) or flash.

19. References

  1. FreeRTOS Documentation - freertos.org
  2. Zephyr Project Documentation - docs.zephyrproject.org
  3. ESP-IDF Programming Guide - docs.espressif.com
  4. STM32 HAL and Low-Layer Driver - st.com
  5. MQTT 5.0 Specification - docs.oasis-open.org
  6. CoAP RFC 7252 - datatracker.ietf.org
  7. LoRa Alliance Technical Docs - lora-alliance.org
  8. TensorFlow Lite Micro - tensorflow.org/lite/microcontrollers
  9. Edge Impulse Docs - docs.edgeimpulse.com
  10. Arm Mbed OS Documentation - os.mbed.com
  11. Making Embedded Systems - Elecia White, O'Reilly
  12. Mastering STM32 - Carmine Noviello
  13. The Hardware Hacker - Andrew Huang

Conclusion

Embedded/IoT development sits at the intersection of hardware, real-time constraints, networking, and security. Starting from Arduino and evolving through ESP32/STM32/Zephyr, developers can build production-grade systems with robust OTA, security, and power management. In 2025, Matter, Thread, and Edge AI standards are maturing, expanding opportunities for embedded developers. From blinking a single LED to networking entire cities, the journey is limitless.

현재 단락 (1/579)

As of 2025, the global IoT device count has surpassed approximately 30 billion. From smart homes, in...

작성 글자: 0원문 글자: 22,270작성 단락: 0/579