1. Introduction to Embedded Systems
An embedded system is a dedicated computing system that combines hardware and software to perform specific functions. They are found everywhere — in washing machines, automotive engine control units (ECUs), smart thermostats, medical devices, and billions of other products worldwide.
Microcontroller (MCU) vs Microprocessor (MPU)
| Feature | MCU | MPU |
| -------- | -------------------- | ------------------------- |
| CPU | Simple, low-power | High-performance, complex |
| Memory | Integrated Flash/RAM | Requires external DRAM |
| OS | None or RTOS | Linux, Android, etc. |
| Power | A few mW | Several W |
| Examples | STM32, AVR, ESP32 | Raspberry Pi, i.MX8 |
Major MCU Platforms
- **STM32 (ST Microelectronics)**: ARM Cortex-M based, widely used in industrial applications. Backed by HAL libraries and the CubeMX GUI configuration tool.
- **AVR (Microchip/Atmel)**: The foundation of Arduino UNO. Familiar and beginner-friendly.
- **ESP32 (Espressif)**: Dual-core Xtensa LX6 with integrated WiFi and BLE. Ideal for IoT projects.
- **RP2040 (Raspberry Pi)**: Dual-core ARM Cortex-M0+ with unique PIO (Programmable I/O) subsystem.
- **PIC (Microchip)**: A long-established MCU family with a strong presence in industrial settings.
Development Environment
- **IDEs**: STM32CubeIDE, MPLAB X, Arduino IDE, PlatformIO (VS Code extension)
- **Compilers**: GCC (arm-none-eabi-gcc), LLVM/Clang
- **Debuggers**: JTAG, SWD (Serial Wire Debug), OpenOCD, J-Link, ST-Link
2. Hardware Control in C
The core of embedded C programming is either directly manipulating hardware registers or leveraging a HAL (Hardware Abstraction Layer) library provided by the manufacturer.
GPIO Control
GPIO (General Purpose Input/Output) is the most fundamental interface for digital I/O control.
// GPIO control using STM32 HAL library
#include "stm32f4xx_hal.h"
// Toggle LED on pin PA5
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
HAL_Delay(500);
// Read button on pin PC13 (active LOW)
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) {
// Button is pressed — turn LED on
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
}
Direct Register Manipulation
Bypassing the HAL and writing to registers directly yields faster, more compact code.
// Direct register access (STM32F4)
// Enable GPIOA peripheral clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
// Set PA5 as output (MODER register)
GPIOA->MODER &= ~(0x3 << (5 * 2)); // Clear bits
GPIOA->MODER |= (0x1 << (5 * 2)); // Output mode
// Set PA5 HIGH
GPIOA->BSRR = (1 << 5);
// Set PA5 LOW
GPIOA->BSRR = (1 << (5 + 16));
The Importance of the volatile Keyword
The compiler may optimize away hardware register accesses, assuming values only change within the program itself. The `volatile` qualifier prevents this.
// WRONG: compiler may optimize this out entirely
uint32_t *reg = (uint32_t *)0x40020000;
*reg = 0x01;
// CORRECT: declare as volatile
volatile uint32_t *reg = (volatile uint32_t *)0x40020000;
*reg = 0x01;
// Global variables modified in ISRs must also be volatile
volatile uint8_t button_pressed = 0;
3. Interrupts and Timers
Interrupt Service Routines (ISR)
An interrupt is a mechanism that allows a hardware event (button press, timer overflow, data received, etc.) to pause the CPU's current task and execute a dedicated ISR immediately.
// External interrupt callback (HAL style)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == GPIO_PIN_13) {
button_pressed = 1;
// Keep ISRs short — never call blocking functions like HAL_Delay()
}
}
// Timer period elapsed callback (called every 1ms)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
system_tick++;
}
}
PWM Output
Timer PWM (Pulse Width Modulation) is used for servo motor control, LED brightness dimming, and DC motor speed regulation.
// Start PWM on TIM3 Channel 1
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
// Set 50% duty cycle (when ARR = 999, set CCR = 500)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 500);
// Servo motor control function (0 to 180 degrees)
void servo_set_angle(uint8_t angle) {
// Map angle to timer compare value for 1ms~2ms pulse width
uint32_t pulse = 500 + (angle * 1000 / 180);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pulse);
}
4. Serial Communication Protocols
UART/USART
Asynchronous serial communication. Primarily used for debug output, GPS modules, and Bluetooth module connectivity.
// Transmit a string over UART
char msg[] = "Hello, UART!\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 100);
// Receive a byte using interrupt mode
uint8_t rx_byte;
HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART2) {
rx_buffer[rx_index++] = rx_byte;
HAL_UART_Receive_IT(&huart2, &rx_byte, 1);
}
}
SPI Communication
Master-slave synchronous serial communication. Used for high-speed peripherals such as displays, SD cards, and ADCs.
// SPI transmit/receive (reading Flash ID)
uint8_t tx_data[] = {0x9F, 0x00};
uint8_t rx_data[2];
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); // CS LOW
HAL_SPI_TransmitReceive(&hspi1, tx_data, rx_data, 2, 100);
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); // CS HIGH
I2C Communication
Two-wire (SDA, SCL) bus that supports multiple devices on the same lines. The standard choice for sensor communication.
// Read MPU6050 accelerometer over I2C
#define MPU6050_ADDR 0xD0 // 7-bit address 0x68, write = 0xD0
#define ACCEL_XOUT_H 0x3B
uint8_t data[6];
HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, ACCEL_XOUT_H,
I2C_MEMADD_SIZE_8BIT, data, 6, 100);
int16_t accel_x = (data[0] << 8) | data[1];
int16_t accel_y = (data[2] << 8) | data[3];
int16_t accel_z = (data[4] << 8) | data[5];
// Convert to real acceleration in g (at ±2g setting)
float ax = accel_x / 16384.0f;
CAN Bus
A robust differential serial communication protocol used in automotive and industrial equipment.
// Send a CAN message (STM32 HAL)
CAN_TxHeaderTypeDef tx_header;
uint8_t tx_data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
uint32_t tx_mailbox;
tx_header.StdId = 0x123;
tx_header.IDE = CAN_ID_STD;
tx_header.RTR = CAN_RTR_DATA;
tx_header.DLC = 8;
HAL_CAN_AddTxMessage(&hcan1, &tx_header, tx_data, &tx_mailbox);
5. RTOS (Real-Time Operating System)
An RTOS guarantees deterministic timing — it ensures that tasks respond to events within a bounded, predictable time. Multiple tasks are scheduled by priority, which is essential for safety-critical and real-time systems.
FreeRTOS Fundamentals
FreeRTOS is the most widely adopted open-source RTOS in the world. Maintained by Amazon, it supports STM32, ESP32, Arduino, and many other platforms.
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"
// Task function — blinks an LED
void vTaskLED(void *pvParameters) {
while(1) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
vTaskDelay(pdMS_TO_TICKS(500)); // Yield CPU for 500ms
}
}
// Task function — reads a sensor and posts to a queue
void vTaskSensor(void *pvParameters) {
QueueHandle_t xQueue = (QueueHandle_t)pvParameters;
float temperature;
while(1) {
temperature = read_temperature_sensor();
xQueueSend(xQueue, &temperature, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
HAL_Init();
SystemClock_Config();
QueueHandle_t xTempQueue = xQueueCreate(10, sizeof(float));
// Create tasks (function, name, stack depth, param, priority, handle)
xTaskCreate(vTaskLED, "LED", 128, NULL, 1, NULL);
xTaskCreate(vTaskSensor, "Sensor", 256, xTempQueue, 2, NULL);
vTaskStartScheduler(); // Hand control to the RTOS — never returns
while(1);
}
Semaphores and Mutexes
SemaphoreHandle_t xMutex;
SemaphoreHandle_t xSemaphore;
// Mutex — protects a shared resource
xMutex = xSemaphoreCreateMutex();
void vTaskA(void *pvParameters) {
while(1) {
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// Critical section
shared_data++;
xSemaphoreGive(xMutex);
}
}
}
// Binary semaphore — synchronizes ISR to task
xSemaphore = xSemaphoreCreateBinary();
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
6. The Arduino Ecosystem
Arduino is an open-source platform designed to lower the barrier to embedded development. It offers a simple API and an enormous library ecosystem.
Arduino Board Comparison
| Board | MCU | Clock | Flash | RAM | Notes |
| --------- | ---------- | ----- | ----- | ---- | ---------------------- |
| UNO R3 | ATmega328P | 16MHz | 32KB | 2KB | Classic beginner board |
| Nano | ATmega328P | 16MHz | 32KB | 2KB | Small form factor |
| Mega 2560 | ATmega2560 | 16MHz | 256KB | 8KB | Many I/O pins |
| Due | SAM3X8E | 84MHz | 512KB | 96KB | 32-bit ARM |
| UNO R4 | RA4M1 | 48MHz | 256KB | 32KB | Latest generation |
DHT22 + I2C LCD Example
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
Serial.begin(9600);
dht.begin();
lcd.init();
lcd.backlight();
lcd.print("IoT Weather Box");
delay(2000);
lcd.clear();
}
void loop() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (isnan(temp) || isnan(hum)) {
Serial.println("DHT read error!");
return;
}
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temp, 1);
lcd.print(" C ");
lcd.setCursor(0, 1);
lcd.print("Hum: ");
lcd.print(hum, 1);
lcd.print(" % ");
Serial.print("T="); Serial.print(temp);
Serial.print(" H="); Serial.println(hum);
delay(2000);
}
7. ESP32 & WiFi/BLE IoT
The ESP32 is a highly capable IoT MCU from Espressif. It features a dual-core 240MHz processor, integrated WiFi 802.11 b/g/n, and BLE 4.2/5.0 — all at an exceptionally low price point.
MQTT IoT with MicroPython
MicroPython ESP32 — publish sensor data over MQTT
from umqtt.simple import MQTTClient
from machine import Pin, ADC
def connect_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
wlan.connect(ssid, password)
while not wlan.isconnected():
time.sleep(0.5)
print('WiFi connected:', wlan.ifconfig())
def on_message(topic, msg):
print('Topic:', topic, 'Message:', msg)
connect_wifi('MySSID', 'MyPassword')
adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB)
client = MQTTClient('esp32_sensor', 'broker.hivemq.com', port=1883)
client.set_callback(on_message)
client.connect()
client.subscribe(b'device/control')
while True:
raw = adc.read()
voltage = raw * 3.3 / 4095
temp_approx = (voltage - 0.5) * 100
payload = '{:.1f}'.format(temp_approx)
client.publish(b'sensor/temperature', payload.encode())
client.check_msg()
time.sleep(5)
ESP-IDF WiFi (C/C++)
// ESP-IDF WiFi station initialization
#include "esp_wifi.h"
#include "esp_event.h"
#include "nvs_flash.h"
#define WIFI_SSID "MyNetwork"
#define WIFI_PASS "MyPassword"
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;
ESP_LOGI("WiFi", "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
}
}
void wifi_init_sta(void) {
nvs_flash_init();
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);
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL);
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL);
wifi_config_t wifi_config = {
.sta = { .ssid = WIFI_SSID, .password = WIFI_PASS },
};
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
esp_wifi_start();
}
8. Raspberry Pi & Linux Embedded
The Raspberry Pi is a single-board computer (SBC) that runs a full Linux operating system. It sits at the intersection of embedded development and general computing, making it a uniquely powerful and flexible platform.
Raspberry Pi Model Comparison
| Model | CPU | RAM | Highlights |
| ------------ | -------------------------- | ----- | -------------------------- |
| Pi Zero 2W | ARM Cortex-A53 quad 1GHz | 512MB | Ultra-compact, WiFi/BLE |
| Pi 4 Model B | ARM Cortex-A72 quad 1.8GHz | 1–8GB | General-purpose powerhouse |
| Pi 5 | ARM Cortex-A76 quad 2.4GHz | 4–8GB | Latest generation |
| Pi Pico 2 | RP2350 dual Cortex-M33 | 520KB | Microcontroller |
GPIO and Servo Motor Control
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)
pwm = GPIO.PWM(18, 50) # 50Hz for servo
pwm.start(7.5) # Neutral position (90 degrees)
def set_servo_angle(angle):
"""Set servo angle from 0 to 180 degrees."""
duty = 2.5 + (angle / 180.0) * 10.0
pwm.ChangeDutyCycle(duty)
time.sleep(0.3)
try:
for angle in [0, 45, 90, 135, 180]:
set_servo_angle(angle)
print(f"Angle: {angle} degrees")
time.sleep(1)
finally:
pwm.stop()
GPIO.cleanup()
gpiozero Library
from gpiozero import LED, Button, DistanceSensor
led = LED(17)
button = Button(4)
button.when_pressed = led.on
button.when_released = led.off
HC-SR04 ultrasonic distance sensor
sensor = DistanceSensor(echo=24, trigger=23)
while True:
dist = sensor.distance * 100 # convert to cm
print(f"Distance: {dist:.1f} cm")
if dist < 20:
led.blink(on_time=0.1, off_time=0.1)
time.sleep(0.5)
Deploying with Docker
Dockerfile for a Raspberry Pi IoT app
FROM python:3.11-slim-bullseye
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "sensor_server.py"]
docker-compose.yml — full IoT stack
version: '3'
services:
sensor-app:
build: .
privileged: true # Required for GPIO access
volumes:
- /dev:/dev
restart: unless-stopped
influxdb:
image: influxdb:2.7
ports:
- '8086:8086'
volumes:
- influx_data:/var/lib/influxdb2
grafana:
image: grafana/grafana:latest
ports:
- '3000:3000'
volumes:
- grafana_data:/var/lib/grafana
volumes:
influx_data:
grafana_data:
9. Edge AI
Edge AI refers to running AI inference directly on local devices rather than in the cloud. The key benefits are ultra-low latency, offline operation, enhanced privacy, and reduced bandwidth consumption.
TensorFlow Lite (TFLite)
TFLite is a lightweight ML framework optimized for mobile and embedded devices.
TFLite image classification on Raspberry Pi
from PIL import Image
Load and initialize the interpreter
interpreter = tflite.Interpreter(
model_path='mobilenet_v2_1.0_224_quant.tflite',
num_threads=4
)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
print("Input shape:", input_details[0]['shape']) # [1, 224, 224, 3]
print("Input dtype:", input_details[0]['dtype']) # uint8 for quantized model
def classify_image(image_path, labels):
img = Image.open(image_path).convert('RGB').resize((224, 224))
input_data = np.expand_dims(np.array(img), axis=0)
interpreter.set_tensor(input_details[0]['index'], input_data)
start = time.time()
interpreter.invoke()
elapsed = (time.time() - start) * 1000
output = interpreter.get_tensor(output_details[0]['index'])
top_idx = np.argmax(output[0])
print(f"Label: {labels[top_idx]}, Score: {output[0][top_idx]}")
print(f"Inference time: {elapsed:.1f}ms")
with open('labels.txt') as f:
labels = [line.strip() for line in f.readlines()]
classify_image('test.jpg', labels)
ONNX Runtime
Running a custom model with ONNX Runtime
from PIL import Image
session = ort.InferenceSession(
'model.onnx',
providers=['CPUExecutionProvider']
)
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name
input_shape = session.get_inputs()[0].shape
print(f"Input: {input_name}, Shape: {input_shape}")
Preprocess image
img = Image.open('test.jpg').resize((224, 224))
img_array = np.array(img).astype(np.float32) / 255.0
img_array = np.transpose(img_array, (2, 0, 1)) # HWC to CHW
img_array = np.expand_dims(img_array, axis=0) # Add batch dimension
result = session.run([output_name], {input_name: img_array})
print("Output shape:", result[0].shape)
Edge AI Platform Comparison
| Platform | Vendor | AI Performance | Power | Notes |
| ---------------- | -------------- | -------------- | ----- | ------------------- |
| Jetson Orin Nano | NVIDIA | 40 TOPS | 7–15W | CUDA GPU on-chip |
| Coral Dev Board | Google | 4 TOPS | ~2W | Dedicated Edge TPU |
| RK3588 board | Rockchip | 6 TOPS NPU | ~8W | Excellent value |
| Hailo-8 M.2 | Hailo | 26 TOPS | 2.5W | PCIe add-in module |
| Pi 5 + AI HAT+ | RPi Foundation | 26 TOPS | ~5W | Pi ecosystem native |
10. IoT Communication Protocols & Cloud
MQTT
MQTT (Message Queuing Telemetry Transport) is a lightweight publish/subscribe protocol optimized for IoT. A broker decouples publishers from subscribers, enabling scalable and efficient messaging.
Python Paho-MQTT client
BROKER = "broker.hivemq.com"
PORT = 1883
TOPIC_PUB = "home/sensor/living_room"
TOPIC_SUB = "home/control/#"
def on_connect(client, userdata, flags, rc):
print(f"Connected with code: {rc}")
client.subscribe(TOPIC_SUB)
def on_message(client, userdata, msg):
payload = json.loads(msg.payload.decode())
print(f"Topic: {msg.topic}, Payload: {payload}")
client = mqtt.Client("python_sensor_01")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
while True:
data = {
"temperature": 23.5,
"humidity": 60.2,
"timestamp": int(time.time())
}
client.publish(TOPIC_PUB, json.dumps(data))
time.sleep(10)
InfluxDB + Grafana
Write sensor data to InfluxDB 2.x
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
INFLUX_URL = "http://localhost:8086"
INFLUX_TOKEN = "your_token_here"
INFLUX_ORG = "myorg"
INFLUX_BUCKET = "iot_sensors"
client = InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG)
write_api = client.write_api(write_options=SYNCHRONOUS)
point = (
Point("environment")
.tag("location", "living_room")
.tag("device", "esp32_01")
.field("temperature", 23.5)
.field("humidity", 60.2)
.field("co2_ppm", 650)
)
write_api.write(bucket=INFLUX_BUCKET, record=point)
Cloud IoT Services
- **AWS IoT Core**: Fully managed, supports billions of devices. Uses X.509 certificate-based mTLS. Integrates natively with Lambda, DynamoDB, S3, and the broader AWS ecosystem.
- **Azure IoT Hub**: Enterprise-grade device management with built-in device twins and direct method invocation.
- **Google Cloud IoT**: Integrates with Pub/Sub, BigQuery, and Vertex AI for end-to-end ML pipelines.
11. Embedded Security
OTA (Over-the-Air) Firmware Updates
Secure OTA is centered on signature verification — rejecting unsigned or tampered firmware to prevent malicious code installation.
// ESP-IDF HTTPS OTA update
#include "esp_ota_ops.h"
#include "esp_https_ota.h"
void ota_task(void *pvParameter) {
esp_https_ota_config_t ota_config = {
.http_config = &(esp_http_client_config_t){
.url = "https://myserver.com/firmware.bin",
.cert_pem = server_cert_pem, // Server certificate verification
},
};
esp_err_t ret = esp_https_ota(&ota_config);
if (ret == ESP_OK) {
esp_restart();
} else {
ESP_LOGE("OTA", "Update failed: %s", esp_err_to_name(ret));
}
vTaskDelete(NULL);
}
AES Encryption on MCU
// mbedTLS AES-128 CBC encryption (STM32/ESP32)
#include "mbedtls/aes.h"
void aes_encrypt_data(uint8_t *plaintext, uint8_t *ciphertext,
uint8_t *key, uint8_t *iv, size_t len) {
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, key, 128); // 128-bit key
uint8_t iv_copy[16];
memcpy(iv_copy, iv, 16); // IV is mutated during encryption
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, len,
iv_copy, plaintext, ciphertext);
mbedtls_aes_free(&ctx);
}
Security Design Principles
1. **Principle of Least Privilege**: Enable only required features; disable unused interfaces.
2. **Secure Boot**: Verify firmware signature at every boot.
3. **Flash Encryption**: Encrypt all code and data stored in flash memory.
4. **Read-Out Protection (RDP)**: Block JTAG/SWD firmware extraction.
5. **Hardware RNG (TRNG)**: Use the on-chip true random number generator for cryptographic keys.
6. **Watchdog Timer**: Automatically recover from hangs and unresponsive states.
12. Quiz
**Answer**: An MCU (Microcontroller Unit) integrates a CPU, memory (Flash and RAM), and peripherals (UART, SPI, I2C, ADC, etc.) into a single chip. An MPU (Microprocessor Unit), by contrast, focuses on the CPU core and requires external memory and peripheral chips.
**Explanation**: MCUs are ideal for low-power, compact, cost-sensitive embedded applications. MPUs are suited for applications that need to run complex operating systems like Linux, such as gateways, HMI panels, or media devices.
**Answer**: A mutex has **ownership** — only the task that locked it can unlock it, and it supports priority inheritance to prevent priority inversion. A binary semaphore has no ownership — any task or ISR can signal it.
**Explanation**: Use a mutex to protect shared resources (mutual exclusion). Use a binary semaphore to synchronize tasks with events, especially for signaling from an ISR to a task. Using a mutex from within an ISR is incorrect and can cause deadlocks.
**Answer**:
- **I2C pros**: Only 2 wires (SDA + SCL), multiple devices on one bus (addressed by 7-bit ID), simple wiring.
- **I2C cons**: Slower than SPI (max ~3.4Mbps), requires pull-up resistors, open-drain bus.
- **SPI pros**: Very fast (tens of Mbps), full-duplex, electrically simple.
- **SPI cons**: Requires a dedicated Chip Select (CS) pin per device (more pins), no addressing scheme.
**Explanation**: I2C is preferred for low-speed sensors (MPU6050, BMP280, etc.) where wiring simplicity matters. SPI is used for high-speed peripherals like TFT displays, SD cards, and SPI flash memory.
**Answer**: The compiler assumes a variable's value only changes through code in the current execution path. It may therefore cache values in registers and skip re-reading from memory. However, hardware registers, variables modified by ISRs, and DMA buffers can change at any time outside the normal program flow. The `volatile` qualifier instructs the compiler never to optimize these reads — always re-fetch from memory.
**Explanation**: Without `volatile`, a flag set inside an ISR may never be seen by the main loop, because the compiler has optimized the load into a register read that only happens once. This is one of the most notorious and hard-to-debug bugs in embedded systems.
**Answer**: Quantization converts model weights and activations from 32-bit floating-point (FP32) to 8-bit integers (INT8). This reduces model size by approximately 4x, improves inference speed by 2–4x, and significantly cuts memory usage and power consumption.
**Explanation**: Embedded devices have severely constrained memory (a few MB) and compute resources. A TFLite INT8 quantized model can run in real time on a Raspberry Pi or even a Cortex-M MCU. The accuracy trade-off is usually small (within 1–2% of the original FP32 model) and acceptable for most production use cases.
References
- [FreeRTOS Official Documentation](https://www.freertos.org/Documentation/RTOS_book.html)
- [STM32 HAL Driver User Manual (UM1725)](https://www.st.com/resource/en/user_manual/um1725-description-of-stm32f4-hal-and-lowlayer-drivers-stmicroelectronics.pdf)
- [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/)
- [TensorFlow Lite for Microcontrollers](https://www.tensorflow.org/lite/microcontrollers)
- [Raspberry Pi Foundation Documentation](https://www.raspberrypi.com/documentation/)
- [Arduino Language Reference](https://www.arduino.cc/reference/en/)
- [MQTT Protocol Specification (OASIS)](https://mqtt.org/mqtt-specification/)
현재 단락 (1/466)
An embedded system is a dedicated computing system that combines hardware and software to perform sp...