Try Live
Add Docs
Rankings
Pricing
Enterprise
Docs
Install
Theme
Install
Docs
Pricing
Enterprise
More...
More...
Try Live
Rankings
Create API Key
Add Docs
Zephyr
https://github.com/zephyrproject-rtos/zephyr
Admin
Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized,
...
Tokens:
2,326,248
Snippets:
13,991
Trust Score:
8.6
Update:
1 week ago
Context
Skills
Chat
Benchmark
78.1
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Zephyr RTOS Zephyr is a scalable, open-source real-time operating system (RTOS) designed for resource-constrained devices across multiple architectures including ARM Cortex-M, Intel x86, ARC, Nios II, Tensilica Xtensa, and RISC-V. It provides a small-footprint kernel optimized for connected, resource-constrained devices with built-in support for Bluetooth Low Energy, Wi-Fi, Thread, and various other networking protocols. The project is hosted by the Linux Foundation and supports over 600 boards from different vendors. Zephyr's modular architecture allows developers to configure exactly what they need, from a minimal kernel to a full-featured system with networking stacks, file systems, and security features. The kernel provides essential RTOS primitives including threads, semaphores, mutexes, message queues, and memory management, while the device driver model offers a consistent API for hardware abstraction across different platforms. ## Kernel Thread Management Zephyr provides comprehensive thread management APIs for creating, scheduling, and synchronizing concurrent execution contexts. Threads can be created statically at compile time using macros or dynamically at runtime, with configurable stack sizes and priorities. ```c #include <zephyr/kernel.h> #define STACKSIZE 1024 #define PRIORITY 7 /* Static thread stack definition */ K_THREAD_STACK_DEFINE(my_stack_area, STACKSIZE); static struct k_thread my_thread_data; /* Thread entry function */ void my_thread_entry(void *p1, void *p2, void *p3) { while (1) { printk("Thread running on %s\n", CONFIG_BOARD); k_msleep(1000); } } int main(void) { k_tid_t my_tid; /* Create thread dynamically */ my_tid = k_thread_create(&my_thread_data, my_stack_area, K_THREAD_STACK_SIZEOF(my_stack_area), my_thread_entry, NULL, NULL, NULL, PRIORITY, 0, K_NO_WAIT); /* Set thread name for debugging */ k_thread_name_set(my_tid, "my_worker"); return 0; } /* Alternative: Static thread definition (starts automatically) */ K_THREAD_DEFINE(static_thread_id, STACKSIZE, my_thread_entry, NULL, NULL, NULL, PRIORITY, 0, 0); ``` ## Semaphore Synchronization Semaphores provide counting-based synchronization primitives for coordinating access to shared resources or signaling between threads. They support both binary and counting modes with configurable initial counts and limits. ```c #include <zephyr/kernel.h> /* Define semaphores statically */ K_SEM_DEFINE(thread_a_sem, 1, 1); /* Available initially */ K_SEM_DEFINE(thread_b_sem, 0, 1); /* Not available initially */ void producer_thread(void *p1, void *p2, void *p3) { while (1) { /* Wait for permission to proceed */ k_sem_take(&thread_a_sem, K_FOREVER); printk("Producer: Processing data\n"); k_msleep(500); /* Signal consumer thread */ k_sem_give(&thread_b_sem); } } void consumer_thread(void *p1, void *p2, void *p3) { while (1) { /* Wait for producer to signal */ k_sem_take(&thread_b_sem, K_FOREVER); printk("Consumer: Data received\n"); k_msleep(500); /* Signal producer can continue */ k_sem_give(&thread_a_sem); } } /* Output alternates: * Producer: Processing data * Consumer: Data received * Producer: Processing data * Consumer: Data received */ ``` ## Mutex and Condition Variables Mutexes provide mutual exclusion for protecting critical sections, while condition variables enable threads to wait for specific conditions while holding a mutex. This pattern is essential for producer-consumer scenarios and complex synchronization. ```c #include <zephyr/kernel.h> #define NUM_THREADS 5 K_MUTEX_DEFINE(data_mutex); K_CONDVAR_DEFINE(data_condvar); static int shared_counter = 0; static int threads_done = 0; void worker_thread(void *id, void *p2, void *p3) { int my_id = (int)(long)id; /* Simulate work */ for (int i = 0; i < 3; i++) { printk("[Worker %d] Working iteration %d\n", my_id, i); k_msleep(200); } /* Update shared state under mutex protection */ k_mutex_lock(&data_mutex, K_FOREVER); threads_done++; shared_counter += my_id; printk("[Worker %d] Done. Total done: %d\n", my_id, threads_done); /* Signal waiting thread */ k_condvar_signal(&data_condvar); k_mutex_unlock(&data_mutex); } int main(void) { /* Create worker threads */ for (int i = 0; i < NUM_THREADS; i++) { /* Thread creation code here */ } /* Wait for all workers to complete */ k_mutex_lock(&data_mutex, K_FOREVER); while (threads_done < NUM_THREADS) { printk("[Main] Waiting, %d/%d done\n", threads_done, NUM_THREADS); k_condvar_wait(&data_condvar, &data_mutex, K_FOREVER); } printk("[Main] All workers done! Counter: %d\n", shared_counter); k_mutex_unlock(&data_mutex); return 0; } ``` ## Message Queue Communication Message queues enable safe data transfer between threads or from ISRs to threads. They support fixed-size messages with blocking and non-blocking operations, including priority insertion for urgent messages. ```c #include <zephyr/kernel.h> #define BUF_SIZE 10 #define PRIORITY 5 /* Define message queue: 10 messages, each sizeof(char) */ K_MSGQ_DEFINE(my_msgq, sizeof(char), BUF_SIZE, 1); void producer_function(void *p1, void *p2, void *p3) { char normal_data = '0'; char urgent_data = 'A'; while (1) { /* Send normal messages */ printk("[Producer] Sending: %c\n", normal_data); k_msgq_put(&my_msgq, &normal_data, K_NO_WAIT); normal_data++; /* Send urgent message to front of queue */ printk("[Producer] Sending urgent: %c\n", urgent_data); k_msgq_put_front(&my_msgq, &urgent_data); urgent_data++; k_msleep(100); } } void consumer_function(void *p1, void *p2, void *p3) { char received; while (1) { /* Block until message available */ if (k_msgq_get(&my_msgq, &received, K_FOREVER) == 0) { printk("[Consumer] Received: %c\n", received); } } } /* Urgent messages appear first due to k_msgq_put_front */ ``` ## FIFO Queue Operations FIFOs provide dynamic memory-based queuing for variable-sized data structures, commonly used for inter-thread communication where message sizes vary or data must be processed in order. ```c #include <zephyr/kernel.h> #include <string.h> K_FIFO_DEFINE(my_fifo); struct data_item { void *fifo_reserved; /* Required: 1st word reserved for FIFO use */ uint32_t value; char name[16]; }; void sender_thread(void *p1, void *p2, void *p3) { for (int i = 0; i < 10; i++) { /* Allocate item dynamically */ struct data_item *item = k_malloc(sizeof(struct data_item)); if (item == NULL) { printk("Failed to allocate memory\n"); continue; } item->value = i; snprintf(item->name, sizeof(item->name), "Item_%d", i); printk("[Sender] Queuing: %s (value=%d)\n", item->name, item->value); k_fifo_put(&my_fifo, item); k_msleep(100); } } void receiver_thread(void *p1, void *p2, void *p3) { while (1) { /* Block until item available */ struct data_item *item = k_fifo_get(&my_fifo, K_FOREVER); printk("[Receiver] Got: %s (value=%d)\n", item->name, item->value); /* Free the allocated memory */ k_free(item); } } ``` ## GPIO Driver API The GPIO driver provides a unified interface for controlling General Purpose Input/Output pins across all supported hardware platforms. It supports input/output configuration, interrupts, and devicetree-based pin specifications. ```c #include <zephyr/kernel.h> #include <zephyr/drivers/gpio.h> /* Get LED0 from devicetree alias */ #define LED0_NODE DT_ALIAS(led0) static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); /* Get button from devicetree alias */ #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 %" PRIu32 "\n", k_cycle_get_32()); gpio_pin_toggle_dt(&led); } int main(void) { int ret; /* Verify devices are ready */ if (!gpio_is_ready_dt(&led) || !gpio_is_ready_dt(&button)) { printk("Error: GPIO devices not ready\n"); return -1; } /* Configure LED as output */ ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); if (ret < 0) { printk("Error configuring LED: %d\n", ret); return ret; } /* Configure button as input with interrupt */ ret = gpio_pin_configure_dt(&button, GPIO_INPUT); if (ret < 0) { printk("Error configuring button: %d\n", ret); return ret; } ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_TO_ACTIVE); if (ret < 0) { printk("Error configuring interrupt: %d\n", ret); return ret; } /* Set up callback */ gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); gpio_add_callback(button.port, &button_cb_data); printk("Press the button to toggle LED\n"); while (1) { gpio_pin_toggle_dt(&led); k_msleep(1000); } return 0; } ``` ## Sensor Driver API The sensor subsystem provides a unified API for reading data from various sensors including accelerometers, gyroscopes, temperature sensors, and environmental sensors. It supports both polling and triggered modes with async RTIO operations. ```c #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/sensor.h> /* Get BME280 sensor from devicetree */ const struct device *const sensor = DEVICE_DT_GET_ANY(bosch_bme280); int main(void) { struct sensor_value temp, press, humidity; int ret; if (!device_is_ready(sensor)) { printk("Sensor device not ready\n"); return -1; } printk("Sensor: %s\n", sensor->name); while (1) { /* Trigger sensor sampling */ ret = sensor_sample_fetch(sensor); if (ret < 0) { printk("Failed to fetch sample: %d\n", ret); continue; } /* Read temperature channel */ ret = sensor_channel_get(sensor, SENSOR_CHAN_AMBIENT_TEMP, &temp); if (ret < 0) { printk("Failed to get temperature: %d\n", ret); } /* Read pressure channel */ ret = sensor_channel_get(sensor, SENSOR_CHAN_PRESS, &press); if (ret < 0) { printk("Failed to get pressure: %d\n", ret); } /* Read humidity channel */ ret = sensor_channel_get(sensor, SENSOR_CHAN_HUMIDITY, &humidity); if (ret < 0) { printk("Failed to get humidity: %d\n", ret); } /* sensor_value: val1 is integer part, val2 is fractional (millionths) */ printk("Temp: %d.%06d C, Press: %d.%06d kPa, Humidity: %d.%06d %%\n", temp.val1, temp.val2, press.val1, press.val2, humidity.val1, humidity.val2); k_msleep(1000); } return 0; } ``` ## Bluetooth Low Energy Peripheral Zephyr provides a comprehensive Bluetooth stack supporting both BLE and Bluetooth Classic. The peripheral example demonstrates advertising, GATT services, and connection handling for heart rate monitoring applications. ```c #include <zephyr/kernel.h> #include <zephyr/bluetooth/bluetooth.h> #include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/gatt.h> #include <zephyr/bluetooth/services/bas.h> #include <zephyr/bluetooth/services/hrs.h> /* Advertising data */ static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HRS_VAL), BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)), }; static const struct bt_data sd[] = { BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1), }; /* Connection callbacks */ static void connected(struct bt_conn *conn, uint8_t err) { if (err) { printk("Connection failed (err 0x%02x)\n", err); } else { printk("Connected\n"); } } static void disconnected(struct bt_conn *conn, uint8_t reason) { printk("Disconnected (reason 0x%02x)\n", reason); } BT_CONN_CB_DEFINE(conn_callbacks) = { .connected = connected, .disconnected = disconnected, }; int main(void) { int err; uint8_t heartrate = 90; /* Initialize Bluetooth */ err = bt_enable(NULL); if (err) { printk("Bluetooth init failed (err %d)\n", err); return -1; } 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 -1; } printk("Advertising started\n"); /* Main loop: simulate heart rate measurements */ while (1) { k_sleep(K_SECONDS(1)); /* Update heart rate (simulated) */ heartrate++; if (heartrate > 160) { heartrate = 90; } /* Notify connected clients */ bt_hrs_notify(heartrate); /* Update battery level */ bt_bas_set_battery_level(bt_bas_get_battery_level() - 1); } return 0; } ``` ## MQTT Client Networking The networking stack includes full MQTT 3.1.1 and 5.0 support for IoT cloud connectivity. This example demonstrates connecting to an MQTT broker, publishing messages with different QoS levels, and handling connection events. ```c #include <zephyr/kernel.h> #include <zephyr/net/socket.h> #include <zephyr/net/mqtt.h> #include <zephyr/random/random.h> static uint8_t rx_buffer[256]; static uint8_t tx_buffer[256]; static struct mqtt_client client_ctx; static struct sockaddr_storage broker; static bool connected; void mqtt_evt_handler(struct mqtt_client *const client, const struct mqtt_evt *evt) { switch (evt->type) { case MQTT_EVT_CONNACK: if (evt->result == 0) { connected = true; printk("MQTT connected!\n"); } break; case MQTT_EVT_DISCONNECT: printk("MQTT disconnected: %d\n", evt->result); connected = false; break; case MQTT_EVT_PUBACK: printk("PUBACK received for msg id: %u\n", evt->param.puback.message_id); break; default: break; } } static int mqtt_publish_message(struct mqtt_client *client, const char *topic, const char *payload) { struct mqtt_publish_param param = { .message.topic.topic.utf8 = (uint8_t *)topic, .message.topic.topic.size = strlen(topic), .message.topic.qos = MQTT_QOS_1_AT_LEAST_ONCE, .message.payload.data = (uint8_t *)payload, .message.payload.len = strlen(payload), .message_id = sys_rand16_get(), .dup_flag = 0, .retain_flag = 0, }; return mqtt_publish(client, ¶m); } int main(void) { int err; struct sockaddr_in *broker4 = (struct sockaddr_in *)&broker; /* Configure broker address */ broker4->sin_family = AF_INET; broker4->sin_port = htons(1883); inet_pton(AF_INET, "192.168.1.100", &broker4->sin_addr); /* Initialize MQTT client */ mqtt_client_init(&client_ctx); client_ctx.broker = &broker; client_ctx.evt_cb = mqtt_evt_handler; client_ctx.client_id.utf8 = (uint8_t *)"zephyr_client"; client_ctx.client_id.size = strlen("zephyr_client"); client_ctx.rx_buf = rx_buffer; client_ctx.rx_buf_size = sizeof(rx_buffer); client_ctx.tx_buf = tx_buffer; client_ctx.tx_buf_size = sizeof(tx_buffer); client_ctx.transport.type = MQTT_TRANSPORT_NON_SECURE; /* Connect to broker */ err = mqtt_connect(&client_ctx); if (err) { printk("MQTT connect failed: %d\n", err); return -1; } /* Main loop */ while (1) { /* Process MQTT events */ mqtt_input(&client_ctx); mqtt_live(&client_ctx); if (connected) { /* Publish sensor data */ char payload[32]; snprintf(payload, sizeof(payload), "{\"temp\":%d}", sys_rand8_get()); mqtt_publish_message(&client_ctx, "sensors/temp", payload); } k_msleep(5000); } return 0; } ``` ## TCP/UDP Socket Server Zephyr implements BSD-style sockets for network communication. This example shows a simple echo server supporting both TCP and UDP protocols with proper connection management. ```c #include <zephyr/kernel.h> #include <zephyr/net/socket.h> #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(echo_server, LOG_LEVEL_DBG); #define PORT 4242 #define BUFFER_SIZE 1024 static char rx_buffer[BUFFER_SIZE]; void tcp_server(void) { int server_fd, client_fd; struct sockaddr_in addr, client_addr; socklen_t client_addr_len = sizeof(client_addr); ssize_t received; /* Create TCP socket */ server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server_fd < 0) { LOG_ERR("Failed to create socket: %d", errno); return; } /* Bind to address */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { LOG_ERR("Failed to bind: %d", errno); close(server_fd); return; } /* Listen for connections */ if (listen(server_fd, 5) < 0) { LOG_ERR("Failed to listen: %d", errno); close(server_fd); return; } LOG_INF("TCP Echo server listening on port %d", PORT); while (1) { /* Accept connection */ client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len); if (client_fd < 0) { LOG_ERR("Accept failed: %d", errno); continue; } LOG_INF("Client connected"); /* Echo loop */ while ((received = recv(client_fd, rx_buffer, sizeof(rx_buffer), 0)) > 0) { LOG_INF("Received %zd bytes", received); send(client_fd, rx_buffer, received, 0); } close(client_fd); LOG_INF("Client disconnected"); } } void udp_server(void) { int sock; struct sockaddr_in addr, client_addr; socklen_t client_addr_len = sizeof(client_addr); ssize_t received; /* Create UDP socket */ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) { LOG_ERR("Failed to create UDP socket: %d", errno); return; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(PORT); if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { LOG_ERR("Failed to bind UDP: %d", errno); close(sock); return; } LOG_INF("UDP Echo server listening on port %d", PORT); while (1) { received = recvfrom(sock, rx_buffer, sizeof(rx_buffer), 0, (struct sockaddr *)&client_addr, &client_addr_len); if (received > 0) { LOG_INF("UDP received %zd bytes", received); sendto(sock, rx_buffer, received, 0, (struct sockaddr *)&client_addr, client_addr_len); } } } ``` ## Work Queue and Delayed Work Work queues enable deferred execution of functions outside of interrupt context. Delayed work items can schedule execution after a specified timeout, useful for periodic tasks and debouncing. ```c #include <zephyr/kernel.h> /* System work queue item */ static struct k_work my_work; /* Delayed work item */ static struct k_work_delayable periodic_work; /* Custom work queue */ #define MY_STACK_SIZE 1024 #define MY_PRIORITY 5 K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE); static struct k_work_q my_work_q; void work_handler(struct k_work *work) { printk("Work executed at %" PRIu32 "\n", k_uptime_get_32()); } void periodic_handler(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); printk("Periodic work at %" PRIu32 "\n", k_uptime_get_32()); /* Reschedule for next period */ k_work_schedule(dwork, K_MSEC(1000)); } int main(void) { /* Initialize work items */ k_work_init(&my_work, work_handler); k_work_init_delayable(&periodic_work, periodic_handler); /* Start custom work queue */ k_work_queue_init(&my_work_q); k_work_queue_start(&my_work_q, my_stack_area, K_THREAD_STACK_SIZEOF(my_stack_area), MY_PRIORITY, NULL); /* Submit work to system work queue */ k_work_submit(&my_work); /* Submit to custom work queue */ k_work_submit_to_queue(&my_work_q, &my_work); /* Schedule delayed work */ k_work_schedule(&periodic_work, K_MSEC(500)); /* Cancel delayed work if needed */ /* k_work_cancel_delayable(&periodic_work); */ k_sleep(K_FOREVER); return 0; } ``` ## Logging Subsystem Zephyr's logging subsystem provides thread-safe, configurable logging with multiple backends (UART, RTT, network). Log levels can be set per-module at compile time or runtime. ```c #include <zephyr/kernel.h> #include <zephyr/logging/log.h> /* Register module with default log level */ LOG_MODULE_REGISTER(my_module, CONFIG_MY_MODULE_LOG_LEVEL); /* Or with explicit level */ LOG_MODULE_REGISTER(sensor_driver, LOG_LEVEL_DBG); void process_sensor_data(int value) { /* Different log levels */ LOG_ERR("Critical error: sensor failure"); LOG_WRN("Warning: value %d out of range", value); LOG_INF("Info: processing value %d", value); LOG_DBG("Debug: raw sensor value %d", value); /* Conditional logging */ if (value > 100) { LOG_WRN("High value detected: %d", value); } /* Hexdump for binary data */ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04}; LOG_HEXDUMP_INF(buffer, sizeof(buffer), "Sensor data:"); } int main(void) { LOG_INF("Application started on %s", CONFIG_BOARD); for (int i = 0; i < 10; i++) { process_sensor_data(i * 20); k_msleep(100); } /* Runtime log level change (if enabled) */ /* log_filter_set(NULL, CONFIG_LOG_DOMAIN_ID, log_source_id_get("my_module"), LOG_LEVEL_ERR); */ return 0; } /* prj.conf settings: * CONFIG_LOG=y * CONFIG_LOG_DEFAULT_LEVEL=3 * CONFIG_MY_MODULE_LOG_LEVEL=4 */ ``` ## Devicetree Hardware Configuration Devicetree provides a hardware-independent way to describe hardware configuration. Zephyr uses devicetree overlays to customize board configurations without modifying source code. ```c /* main.c - Using devicetree macros */ #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/i2c.h> /* Get nodes by alias */ #define LED_NODE DT_ALIAS(led0) #define I2C_NODE DT_NODELABEL(i2c0) /* Check if node exists */ #if DT_NODE_HAS_STATUS_OKAY(LED_NODE) static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED_NODE, gpios); #endif /* Get device from DT node */ static const struct device *i2c_dev = DEVICE_DT_GET(I2C_NODE); /* Get property values */ #define SENSOR_ADDR DT_PROP(DT_NODELABEL(temp_sensor), reg) int main(void) { /* Verify device is ready */ if (!device_is_ready(i2c_dev)) { printk("I2C device not ready\n"); return -1; } /* Use devicetree-configured GPIO */ #if DT_NODE_HAS_STATUS_OKAY(LED_NODE) if (gpio_is_ready_dt(&led)) { gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); gpio_pin_set_dt(&led, 1); } #endif printk("I2C sensor address: 0x%02x\n", SENSOR_ADDR); return 0; } /* app.overlay - Board-specific overlay file: * * / { * aliases { * led0 = &myled; * }; * }; * * &i2c0 { * status = "okay"; * temp_sensor: tmp102@48 { * compatible = "ti,tmp102"; * reg = <0x48>; * }; * }; * * &gpio0 { * myled: led_0 { * gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; * }; * }; */ ``` ## Building and Flashing Applications Zephyr uses CMake and west for build management. Here's how to build, configure, and flash applications across different boards. ```bash # Install west (Zephyr's meta-tool) pip install west # Initialize Zephyr workspace west init ~/zephyrproject cd ~/zephyrproject west update # Set up environment source zephyr/zephyr-env.sh # Build for specific board west build -b nrf52840dk/nrf52840 samples/basic/blinky # Build with configuration options west build -b esp32_devkitc/esp32/procpu samples/basic/blinky -- \ -DCONFIG_LOG=y \ -DCONFIG_GPIO_LOG_LEVEL_DBG=y # Flash to connected board west flash # Debug with GDB west debug # Build with overlay file west build -b nucleo_f401re samples/sensor/bme280 -- \ -DDTC_OVERLAY_FILE=app.overlay # Clean build directory west build -t clean # Generate compile_commands.json for IDE west build -t compile_commands # Run tests west twister -T tests/kernel/threads/ # CMakeLists.txt for custom application: # cmake_minimum_required(VERSION 3.20.0) # find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) # project(my_app) # target_sources(app PRIVATE src/main.c) # prj.conf - Kconfig options: # CONFIG_GPIO=y # CONFIG_SERIAL=y # CONFIG_LOG=y # CONFIG_BT=y # CONFIG_BT_PERIPHERAL=y ``` Zephyr RTOS is particularly well-suited for IoT applications requiring reliable connectivity, real-time performance, and security features on resource-constrained devices. Common use cases include wearable devices, smart home sensors, industrial automation controllers, and medical monitoring equipment. The unified driver model and comprehensive networking stack enable rapid prototyping while the security subsystem provides features like secure boot, TLS/DTLS, and hardware crypto acceleration. Integration with Zephyr typically involves defining hardware through devicetree overlays, configuring features via Kconfig, and implementing application logic using the kernel and driver APIs. The extensive board support (600+ boards) and vendor-neutral approach allow the same application code to run across different hardware platforms with minimal changes. For production deployments, Zephyr supports firmware updates via MCUboot, LwM2M, and custom protocols, making it suitable for long-lived IoT deployments requiring field updates.