# Zephyr RTOS Project ## Introduction Zephyr is a scalable real-time operating system (RTOS) designed for resource-constrained embedded devices, supporting multiple hardware architectures including ARM (Cortex-A/R/M), Intel x86, ARC, RISC-V, Xtensa, SPARC, and MIPS. The project provides a small-footprint kernel optimized for microcontrollers and embedded systems ranging from simple sensors and wearables to complex IoT wireless gateways. Built with security in mind, Zephyr offers memory protection, secure boot, and cryptographic services while maintaining compatibility with a large ecosystem of supported boards and peripherals. The operating system features a comprehensive suite of kernel services including preemptive and cooperative multi-threading, inter-thread synchronization primitives (semaphores, mutexes, message queues), timers, memory management, and power management capabilities. Zephyr's architecture emphasizes portability through devicetree-based hardware abstraction, Kconfig-driven configuration, and a modular CMake build system. The project includes extensive subsystems for networking (IPv4/IPv6, TCP/UDP, Bluetooth), USB device support, file systems, shell interfaces, logging frameworks, and a rich set of device drivers for common peripherals like GPIO, UART, I2C, SPI, and ADC. ## Core Kernel APIs ### Thread Creation and Management Multi-threading support with both static and dynamic thread creation. ```c #include #define STACKSIZE 1024 #define PRIORITY 7 // Static thread definition K_THREAD_DEFINE(static_thread, STACKSIZE, thread_entry, NULL, NULL, NULL, PRIORITY, 0, 0); // Dynamic thread creation K_THREAD_STACK_DEFINE(dynamic_stack, STACKSIZE); static struct k_thread dynamic_thread_data; void thread_entry(void *p1, void *p2, void *p3) { while (1) { printk("Thread running\n"); k_msleep(1000); } } int main(void) { // Create and start dynamic thread k_thread_create(&dynamic_thread_data, dynamic_stack, K_THREAD_STACK_SIZEOF(dynamic_stack), thread_entry, NULL, NULL, NULL, PRIORITY, 0, K_NO_WAIT); k_thread_name_set(&dynamic_thread_data, "worker"); // Thread control k_thread_suspend(&dynamic_thread_data); k_msleep(500); k_thread_resume(&dynamic_thread_data); k_thread_priority_set(&dynamic_thread_data, K_PRIO_PREEMPT(5)); return 0; } ``` ### Semaphore Synchronization Binary and counting semaphores for thread synchronization. ```c #include K_SEM_DEFINE(producer_sem, 1, 1); // Initially available K_SEM_DEFINE(consumer_sem, 0, 1); // Initially unavailable void producer_thread(void) { while (1) { k_sem_take(&producer_sem, K_FOREVER); printk("Producer: producing data\n"); // Produce data k_sem_give(&consumer_sem); k_msleep(100); } } void consumer_thread(void) { while (1) { k_sem_take(&consumer_sem, K_FOREVER); printk("Consumer: consuming data\n"); // Consume data k_sem_give(&producer_sem); } } ``` ### Message Queue Communication Fixed-size message passing between threads with FIFO ordering. ```c #include #define MSG_SIZE 32 #define QUEUE_SIZE 10 struct data_item { uint32_t id; uint8_t data[MSG_SIZE]; }; K_MSGQ_DEFINE(my_msgq, sizeof(struct data_item), QUEUE_SIZE, 4); void sender_thread(void) { struct data_item msg = { .id = 42, .data = {0x01, 0x02, 0x03} }; int ret = k_msgq_put(&my_msgq, &msg, K_NO_WAIT); if (ret) { printk("Failed to send message: %d\n", ret); } } void receiver_thread(void) { struct data_item msg; while (1) { if (k_msgq_get(&my_msgq, &msg, K_FOREVER) == 0) { printk("Received message id=%u\n", msg.id); // Process message } } } ``` ### Mutex Lock Protection Priority-inheritance mutexes for protecting shared resources. ```c #include K_MUTEX_DEFINE(shared_resource_mutex); static int shared_counter = 0; void critical_section(void) { k_mutex_lock(&shared_resource_mutex, K_FOREVER); // Critical section - safely modify shared resource shared_counter++; printk("Counter: %d\n", shared_counter); k_mutex_unlock(&shared_resource_mutex); } int main(void) { critical_section(); return 0; } ``` ### Work Queue Execution Deferred work execution in system or custom work queues. ```c #include static void work_handler(struct k_work *work) { printk("Work handler executed\n"); // Perform deferred work } static void delayed_work_handler(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); printk("Delayed work executed\n"); // Reschedule for periodic execution k_work_schedule(dwork, K_MSEC(1000)); } K_WORK_DEFINE(my_work, work_handler); static struct k_work_delayable my_delayed_work; int main(void) { // Submit work to system queue k_work_submit(&my_work); // Initialize and schedule delayed work k_work_init_delayable(&my_delayed_work, delayed_work_handler); k_work_schedule(&my_delayed_work, K_MSEC(500)); return 0; } ``` ### Timer Operations Kernel timers with expiry and stop callbacks. ```c #include static void timer_expiry_fn(struct k_timer *timer) { printk("Timer expired at %u\n", k_cycle_get_32()); } static void timer_stop_fn(struct k_timer *timer) { printk("Timer stopped\n"); } K_TIMER_DEFINE(my_timer, timer_expiry_fn, timer_stop_fn); int main(void) { // Start timer: 100ms duration, 100ms period (repeating) k_timer_start(&my_timer, K_MSEC(100), K_MSEC(100)); k_sleep(K_SECONDS(1)); // Stop timer k_timer_stop(&my_timer); // Get remaining time uint32_t remaining = k_timer_remaining_get(&my_timer); printk("Remaining time: %u ms\n", remaining); return 0; } ``` ### Event Synchronization Event objects for synchronizing multiple threads on multiple conditions. ```c #include #define EVENT_FLAG_A BIT(0) #define EVENT_FLAG_B BIT(1) #define EVENT_FLAG_C BIT(2) K_EVENT_DEFINE(my_events); void worker_thread(void) { // Wait for any of the events uint32_t events = k_event_wait(&my_events, EVENT_FLAG_A | EVENT_FLAG_B, false, K_FOREVER); printk("Received events: 0x%x\n", events); // Wait for all events events = k_event_wait_all(&my_events, EVENT_FLAG_A | EVENT_FLAG_B | EVENT_FLAG_C, false, K_FOREVER); printk("All events received\n"); } int main(void) { // Post events k_event_post(&my_events, EVENT_FLAG_A); k_msleep(100); k_event_post(&my_events, EVENT_FLAG_B); // Set events (replace existing) k_event_set(&my_events, EVENT_FLAG_C); // Clear specific events k_event_clear(&my_events, EVENT_FLAG_A); return 0; } ``` ## GPIO Driver API ### Basic GPIO Control Configure and control GPIO pins for digital input/output. ```c #include #include #define LED0_NODE DT_ALIAS(led0) static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); int main(void) { int ret; // Check if device is ready if (!gpio_is_ready_dt(&led)) { printk("LED device not ready\n"); return -ENODEV; } // Configure as output with active-high polarity ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); if (ret < 0) { printk("Failed to configure LED: %d\n", ret); return ret; } while (1) { // Toggle LED gpio_pin_toggle_dt(&led); printk("LED toggled\n"); k_msleep(1000); // Set specific value gpio_pin_set_dt(&led, 1); // Turn on k_msleep(500); gpio_pin_set_dt(&led, 0); // Turn off k_msleep(500); } return 0; } ``` ### GPIO Interrupt Handling Configure GPIO pins to trigger interrupts on edge or level changes. ```c #include #include #define BUTTON_NODE DT_ALIAS(sw0) static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET(BUTTON_NODE, gpios); static struct gpio_callback button_cb_data; void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { printk("Button pressed at cycle %u\n", k_cycle_get_32()); } int main(void) { int ret; if (!gpio_is_ready_dt(&button)) { printk("Button device not ready\n"); return -ENODEV; } // Configure as input with pull-up ret = gpio_pin_configure_dt(&button, GPIO_INPUT | GPIO_PULL_UP); if (ret < 0) { printk("Failed to configure button: %d\n", ret); return ret; } // Configure interrupt on falling edge (button press) ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_FALLING); if (ret < 0) { printk("Failed to configure interrupt: %d\n", ret); return ret; } // Initialize and add callback gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); gpio_add_callback(button.port, &button_cb_data); printk("Waiting for button press...\n"); while (1) { k_sleep(K_FOREVER); } return 0; } ``` ## UART Driver API ### UART Polling Mode Simple polling-based UART communication for basic scenarios. ```c #include #include #define UART_NODE DT_CHOSEN(zephyr_shell_uart) static const struct device *const uart_dev = DEVICE_DT_GET(UART_NODE); int main(void) { const char *msg = "Hello UART\r\n"; if (!device_is_ready(uart_dev)) { printk("UART device not ready\n"); return -ENODEV; } // Transmit string using polling for (int i = 0; msg[i] != '\0'; i++) { uart_poll_out(uart_dev, msg[i]); } // Receive characters using polling while (1) { uint8_t c; if (uart_poll_in(uart_dev, &c) == 0) { // Echo received character uart_poll_out(uart_dev, c); if (c == '\r') { uart_poll_out(uart_dev, '\n'); } } k_msleep(10); } return 0; } ``` ### UART Interrupt Mode Interrupt-driven UART for efficient asynchronous communication. ```c #include #include #define UART_NODE DT_CHOSEN(zephyr_shell_uart) static const struct device *const uart_dev = DEVICE_DT_GET(UART_NODE); #define MSG_SIZE 32 K_MSGQ_DEFINE(uart_msgq, MSG_SIZE, 10, 4); static uint8_t rx_buf[MSG_SIZE]; static int rx_buf_pos = 0; void uart_isr_callback(const struct device *dev, void *user_data) { uint8_t c; if (!uart_irq_update(uart_dev)) { return; } if (uart_irq_rx_ready(uart_dev)) { while (uart_fifo_read(uart_dev, &c, 1) == 1) { rx_buf[rx_buf_pos++] = c; // Line complete if (c == '\n' || rx_buf_pos >= MSG_SIZE) { k_msgq_put(&uart_msgq, rx_buf, K_NO_WAIT); rx_buf_pos = 0; } } } } int main(void) { if (!device_is_ready(uart_dev)) { return -ENODEV; } // Configure interrupt-driven operation uart_irq_callback_user_data_set(uart_dev, uart_isr_callback, NULL); uart_irq_rx_enable(uart_dev); // Process received messages uint8_t msg[MSG_SIZE]; while (1) { if (k_msgq_get(&uart_msgq, msg, K_FOREVER) == 0) { printk("Received: %s", msg); // Echo back for (int i = 0; i < MSG_SIZE && msg[i]; i++) { uart_poll_out(uart_dev, msg[i]); } } } return 0; } ``` ## I2C Driver API ### I2C Read/Write Operations Communicate with I2C peripheral devices. ```c #include #include #define I2C_NODE DT_NODELABEL(i2c0) static const struct device *const i2c_dev = DEVICE_DT_GET(I2C_NODE); #define SENSOR_ADDR 0x48 #define REG_TEMP 0x00 #define REG_CONFIG 0x01 int main(void) { int ret; uint8_t config[] = {REG_CONFIG, 0x60}; // Configuration data uint8_t temp_data[2]; if (!device_is_ready(i2c_dev)) { printk("I2C device not ready\n"); return -ENODEV; } // Write configuration register ret = i2c_write(i2c_dev, config, sizeof(config), SENSOR_ADDR); if (ret < 0) { printk("I2C write failed: %d\n", ret); return ret; } while (1) { // Write register address then read data uint8_t reg = REG_TEMP; ret = i2c_write_read(i2c_dev, SENSOR_ADDR, ®, 1, temp_data, sizeof(temp_data)); if (ret < 0) { printk("I2C read failed: %d\n", ret); k_msleep(1000); continue; } // Process temperature data int16_t temp = (temp_data[0] << 8) | temp_data[1]; float temp_c = temp * 0.0625; printk("Temperature: %.2f C\n", temp_c); k_msleep(1000); } return 0; } ``` ## SPI Driver API ### SPI Communication Full-duplex SPI communication with external devices. ```c #include #include #define SPI_NODE DT_NODELABEL(spi0) static const struct device *const spi_dev = DEVICE_DT_GET(SPI_NODE); static struct spi_config spi_cfg = { .frequency = 1000000, // 1 MHz .operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA, .slave = 0, .cs = { .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(spi0)), .delay = 0, }, }; int main(void) { uint8_t tx_buffer[] = {0x80, 0x00}; // Read command uint8_t rx_buffer[2] = {0}; if (!device_is_ready(spi_dev)) { printk("SPI device not ready\n"); return -ENODEV; } const struct spi_buf tx_buf = { .buf = tx_buffer, .len = sizeof(tx_buffer), }; const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1, }; struct spi_buf rx_buf = { .buf = rx_buffer, .len = sizeof(rx_buffer), }; const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1, }; // Full-duplex transfer int ret = spi_transceive(spi_dev, &spi_cfg, &tx, &rx); if (ret < 0) { printk("SPI transceive failed: %d\n", ret); return ret; } printk("Received: 0x%02x 0x%02x\n", rx_buffer[0], rx_buffer[1]); return 0; } ``` ## ADC Driver API ### ADC Channel Reading Read analog values from ADC channels with devicetree configuration. ```c #include #include #define ADC_NODE DT_NODELABEL(adc) static const struct device *const adc_dev = DEVICE_DT_GET(ADC_NODE); static const struct adc_channel_cfg channel_cfg = { .gain = ADC_GAIN_1, .reference = ADC_REF_INTERNAL, .acquisition_time = ADC_ACQ_TIME_DEFAULT, .channel_id = 0, .differential = 0, }; int main(void) { int ret; uint16_t sample_buffer[1]; if (!device_is_ready(adc_dev)) { printk("ADC device not ready\n"); return -ENODEV; } // Configure channel ret = adc_channel_setup(adc_dev, &channel_cfg); if (ret < 0) { printk("ADC channel setup failed: %d\n", ret); return ret; } struct adc_sequence sequence = { .channels = BIT(channel_cfg.channel_id), .buffer = sample_buffer, .buffer_size = sizeof(sample_buffer), .resolution = 12, // 12-bit resolution .oversampling = 0, }; while (1) { // Read ADC ret = adc_read(adc_dev, &sequence); if (ret < 0) { printk("ADC read failed: %d\n", ret); k_msleep(1000); continue; } int32_t val_mv = sample_buffer[0]; // Convert to millivolts (assuming 3.3V reference, 12-bit) val_mv = (val_mv * 3300) / 4096; printk("ADC raw: %u, voltage: %d mV\n", sample_buffer[0], val_mv); k_msleep(1000); } return 0; } ``` ## Devicetree Usage ### Devicetree Node Access Access hardware configuration from devicetree. ```c #include #include #include // Get node by alias #define LED0_NODE DT_ALIAS(led0) #define BUTTON_NODE DT_ALIAS(sw0) // Get node by label #define UART_NODE DT_NODELABEL(uart0) // Get chosen node #define CONSOLE_NODE DT_CHOSEN(zephyr_console) // Check if node exists and has okay status #if DT_NODE_HAS_STATUS_OKAY(LED0_NODE) static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); #else #error "LED0 not available" #endif int main(void) { // Get properties from devicetree printk("LED port: %s\n", led.port->name); printk("LED pin: %u\n", led.pin); printk("LED flags: 0x%x\n", led.dt_flags); // Get register address (for memory-mapped devices) #if DT_NODE_HAS_PROP(UART_NODE, reg) uint32_t reg_addr = DT_REG_ADDR(UART_NODE); uint32_t reg_size = DT_REG_SIZE(UART_NODE); printk("UART base: 0x%x, size: 0x%x\n", reg_addr, reg_size); #endif return 0; } ``` ## Logging Subsystem ### Application Logging Structured logging with multiple severity levels. ```c #include #include // Register logging module LOG_MODULE_REGISTER(my_app, LOG_LEVEL_DBG); void process_data(uint8_t *data, size_t len) { LOG_INF("Processing %zu bytes", len); // Hexdump for debugging LOG_HEXDUMP_DBG(data, len, "Received data:"); if (data == NULL) { LOG_ERR("Null pointer received"); return; } if (len > 256) { LOG_WRN("Data length %zu exceeds recommended size", len); } LOG_DBG("Data processing complete"); } int main(void) { LOG_INF("Application started"); uint8_t sample_data[] = {0x01, 0x02, 0x03, 0x04}; process_data(sample_data, sizeof(sample_data)); // Log with formatting int error_code = -EINVAL; LOG_ERR("Operation failed with code: %d", error_code); return 0; } ``` ## Shell Subsystem ### Shell Command Registration Create interactive shell commands for debugging and control. ```c #include #include static int cmd_hello(const struct shell *sh, size_t argc, char **argv) { shell_print(sh, "Hello, World!"); return 0; } static int cmd_echo(const struct shell *sh, size_t argc, char **argv) { for (size_t i = 1; i < argc; i++) { shell_print(sh, "arg[%zu]: %s", i, argv[i]); } return 0; } static int cmd_status(const struct shell *sh, size_t argc, char **argv) { shell_print(sh, "System uptime: %llu ms", k_uptime_get()); shell_print(sh, "Thread count: %u", k_thread_count_get()); return 0; } static int cmd_led_on(const struct shell *sh, size_t argc, char **argv) { shell_print(sh, "LED turned on"); // Control LED here return 0; } static int cmd_led_off(const struct shell *sh, size_t argc, char **argv) { shell_print(sh, "LED turned off"); // Control LED here return 0; } // Define subcommands for 'led' SHELL_STATIC_SUBCMD_SET_CREATE(sub_led, SHELL_CMD(on, NULL, "Turn LED on", cmd_led_on), SHELL_CMD(off, NULL, "Turn LED off", cmd_led_off), SHELL_SUBCMD_SET_END ); // Register top-level commands SHELL_CMD_REGISTER(hello, NULL, "Print hello message", cmd_hello); SHELL_CMD_REGISTER(echo, NULL, "Echo arguments", cmd_echo); SHELL_CMD_REGISTER(status, NULL, "Show system status", cmd_status); SHELL_CMD_REGISTER(led, &sub_led, "LED control commands", NULL); ``` ## Bluetooth LE API ### BLE Peripheral Implementation Create a Bluetooth Low Energy peripheral device with GATT services. ```c #include #include #include #include #include #define DEVICE_NAME "Zephyr Sensor" #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) // Custom service UUID #define BT_UUID_CUSTOM_SERVICE_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) static struct bt_uuid_128 custom_service_uuid = BT_UUID_INIT_128( BT_UUID_CUSTOM_SERVICE_VAL); static struct bt_uuid_128 custom_char_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); static uint8_t sensor_value = 0; static ssize_t read_sensor(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { return bt_gatt_attr_read(conn, attr, buf, len, offset, &sensor_value, sizeof(sensor_value)); } // Define GATT service BT_GATT_SERVICE_DEFINE(custom_svc, BT_GATT_PRIMARY_SERVICE(&custom_service_uuid), BT_GATT_CHARACTERISTIC(&custom_char_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ, read_sensor, NULL, NULL), BT_GATT_CCC(NULL, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), ); static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), }; static const struct bt_data sd[] = { BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL), }; static void connected(struct bt_conn *conn, uint8_t err) { if (err) { printk("Connection failed (err %u)\n", err); } else { printk("Connected\n"); } } static void disconnected(struct bt_conn *conn, uint8_t reason) { printk("Disconnected (reason %u)\n", reason); } BT_CONN_CB_DEFINE(conn_callbacks) = { .connected = connected, .disconnected = disconnected, }; int main(void) { int err; // Enable Bluetooth err = bt_enable(NULL); if (err) { printk("Bluetooth init failed (err %d)\n", err); return err; } printk("Bluetooth initialized\n"); // Start advertising err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { printk("Advertising failed to start (err %d)\n", err); return err; } printk("Advertising started\n"); // Update sensor value periodically while (1) { sensor_value++; k_msleep(1000); } return 0; } ``` ## Networking Socket API ### TCP Socket Server Create a TCP server using BSD-style socket API. ```c #include #include #include LOG_MODULE_REGISTER(tcp_server, LOG_LEVEL_DBG); #define SERVER_PORT 4242 #define RECV_BUF_SIZE 128 int main(void) { int serv, client; struct sockaddr_in bind_addr; struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); char recv_buf[RECV_BUF_SIZE]; // Create socket serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (serv < 0) { LOG_ERR("Failed to create socket: %d", errno); return -errno; } // Set SO_REUSEADDR option int optval = 1; setsockopt(serv, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // Bind to address bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); bind_addr.sin_port = htons(SERVER_PORT); if (bind(serv, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) { LOG_ERR("Failed to bind: %d", errno); close(serv); return -errno; } // Listen if (listen(serv, 5) < 0) { LOG_ERR("Failed to listen: %d", errno); close(serv); return -errno; } LOG_INF("TCP server listening on port %d", SERVER_PORT); while (1) { // Accept connection client = accept(serv, (struct sockaddr *)&client_addr, &client_addr_len); if (client < 0) { LOG_ERR("Accept failed: %d", errno); continue; } LOG_INF("Client connected"); // Handle client while (1) { int received = recv(client, recv_buf, sizeof(recv_buf) - 1, 0); if (received <= 0) { break; } recv_buf[received] = '\0'; LOG_INF("Received: %s", recv_buf); // Echo back send(client, recv_buf, received, 0); } close(client); LOG_INF("Client disconnected"); } close(serv); return 0; } ``` ## Build Configuration ### CMakeLists.txt Structure Standard CMake configuration for Zephyr applications. ```cmake # SPDX-License-Identifier: Apache-2.0 cmake_minimum_required(VERSION 3.20.0) # Find Zephyr package find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(my_application) # Add source files target_sources(app PRIVATE src/main.c src/sensor.c src/network.c ) # Add include directories target_include_directories(app PRIVATE include ) # Conditional compilation if(CONFIG_CUSTOM_FEATURE) target_sources(app PRIVATE src/custom_feature.c ) endif() # Add compile definitions target_compile_definitions(app PRIVATE MY_CUSTOM_DEFINE=1 ) # Link external library target_link_libraries(app PRIVATE m # Math library ) ``` ### Kconfig Configuration (prj.conf) Application configuration using Kconfig options. ```kconfig # Kernel Configuration CONFIG_MAIN_STACK_SIZE=2048 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_ISR_STACK_SIZE=2048 CONFIG_IDLE_STACK_SIZE=512 # Threading CONFIG_NUM_PREEMPT_PRIORITIES=15 CONFIG_THREAD_NAME=y CONFIG_THREAD_MONITOR=y # GPIO CONFIG_GPIO=y # UART CONFIG_SERIAL=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_UART_LINE_CTRL=y # I2C CONFIG_I2C=y # SPI CONFIG_SPI=y # ADC CONFIG_ADC=y # Logging CONFIG_LOG=y CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_LOG_DEFAULT_LEVEL=3 CONFIG_UART_CONSOLE=y CONFIG_CONSOLE=y # Shell CONFIG_SHELL=y CONFIG_SHELL_BACKEND_SERIAL=y # Bluetooth CONFIG_BT=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="MyDevice" CONFIG_BT_DEVICE_APPEARANCE=833 CONFIG_BT_MAX_CONN=4 # Networking CONFIG_NETWORKING=y CONFIG_NET_IPV4=y CONFIG_NET_IPV6=y CONFIG_NET_TCP=y CONFIG_NET_UDP=y CONFIG_NET_SOCKETS=y CONFIG_NET_LOG=y # Power Management CONFIG_PM=y CONFIG_PM_DEVICE=y # Size Optimization CONFIG_SIZE_OPTIMIZATIONS=y CONFIG_MINIMAL_LIBC=y ``` ## Summary Zephyr RTOS provides a comprehensive embedded development platform with extensive kernel services, driver APIs, and subsystem support suitable for resource-constrained IoT devices and complex embedded systems. The operating system's primary use cases include wireless sensor networks, wearable devices, industrial automation, smart home appliances, and edge computing nodes. Developers leverage Zephyr's multi-threading capabilities for concurrent task management, its rich peripheral driver ecosystem for hardware abstraction, and built-in networking stacks (TCP/IP, Bluetooth LE, IEEE 802.15.4) for connectivity solutions. The platform excels in scenarios requiring secure boot, memory protection, and real-time responsiveness with deterministic scheduling. Integration patterns in Zephyr follow a devicetree-first approach where hardware configuration is declared in DTS files and accessed through compile-time macros, enabling portable code across different boards. Applications typically use Kconfig for feature selection and runtime configuration, CMake for build orchestration, and the West meta-tool for multi-repository management. Common integration workflows include: GPIO interrupts triggering work queue submissions for deferred processing; UART ISRs feeding message queues consumed by worker threads; I2C/SPI drivers communicating with external sensors in dedicated threads synchronized via semaphores; Bluetooth GATT characteristics bridging wireless connections to kernel message queues; and socket APIs enabling standard POSIX-style networking. The modular architecture allows selective subsystem inclusion, minimizing flash/RAM footprint while providing scalability from simple 8-bit microcontrollers to multi-core 64-bit processors.