00 Zephyr nedir
Zephyr, Linux Foundation çatısı altında geliştirilen, küçük MCU'lardan karmaşık SoC'lere kadar geniş donanım yelpazesini destekleyen açık kaynaklı gerçek zamanlı işletim sistemidir.
Proje özellikleri
Zephyr RTOS, 2016'da Intel tarafından Linux Foundation'a bağışlanan Rocket OS'tan türetilmiştir. Günümüzde Nordic Semiconductor, STMicroelectronics, NXP, Intel, Espressif ve diğer büyük yarı iletken firmaların katkılarıyla gelişmektedir. Apache 2.0 lisansıyla dağıtılır — ticari kullanımda lisans ücreti yoktur.
Desteklenen önemli board'lar
| Board | MCU | Özellik | Zephyr adı |
|---|---|---|---|
| nRF52840 DK | ARM Cortex-M4F | BLE 5.0, Zigbee, Thread, USB | nrf52840dk/nrf52840 |
| nRF9160 DK | ARM Cortex-M33 | LTE-M, NB-IoT, GPS, TrustZone | nrf9160dk/nrf9160 |
| STM32F4 Discovery | ARM Cortex-M4F | USB OTG, CAN, SDIO | stm32f4_disco |
| STM32H7 Nucleo | ARM Cortex-M7 | 480 MHz, Ethernet, DSP | nucleo_h743zi |
| ESP32-S3 | Xtensa LX7 | WiFi, BLE 5.0, USB OTG | esp32s3_devkitc |
| Raspberry Pi Pico | ARM Cortex-M0+ | PIO, USB, dual-core | rpi_pico |
| BBC micro:bit v2 | ARM Cortex-M4F | BLE, sensörler, eğitim | bbc_microbit_v2 |
west — birleşik meta araç
west (Werkzeug for Embedded Systems Tool), Zephyr ekosisteminin bütünleşik komut satırı aracıdır. Birden fazla Git deposunu (Zephyr kernel + HAL'lar + modüller) yönetir ve build, flash, debug, boards gibi subcommand'lar sunar.
Bu bölümde
- Zephyr: Linux Foundation, Apache 2.0, 700+ board, 8 KB RAM'de çalışır
- Nordic, ST, NXP, Espressif — büyük fabrikalar tarafından desteklenir
- west: çoklu repo yönetimi + build + flash + debug — tek araç
01 Geliştirme ortamı kurulumu
Zephyr geliştirme ortamı west, Python sanal ortamı, Zephyr SDK (toolchain) ve CMake'ten oluşur. Kurulum adımları tüm platformlarda benzerdir.
Sistem bağımlılıkları
# Temel araçlar
sudo apt install --no-install-recommends \
git cmake ninja-build gperf \
ccache dfu-util device-tree-compiler wget \
python3-dev python3-pip python3-setuptools python3-tk \
python3-wheel xz-utils file make gcc gcc-multilib \
g++-multilib libsdl2-dev libmagic1
west ve Python sanal ortam
# Python sanal ortam oluştur (önerilir)
python3 -m venv ~/zephyrproject/.venv
source ~/zephyrproject/.venv/bin/activate
# west kur
pip install west
# Zephyr deposunu başlat (tüm bağımlılıklarla)
west init ~/zephyrproject
cd ~/zephyrproject
# Tüm bağımlı depoları indir (HAL'lar, modüller, vb.)
west update
# Python bağımlılıklarını kur
pip install -r ~/zephyrproject/zephyr/scripts/requirements.txt
Zephyr SDK (toolchain) kurulumu
# SDK indirme (aarch64 Linux için örnek — minimal)
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.8/\
zephyr-sdk-0.16.8_linux-x86_64_minimal.tar.xz
tar xvf zephyr-sdk-0.16.8_linux-x86_64_minimal.tar.xz -C ~/
# SDK'yı kur (toolchain'leri ekle)
cd ~/zephyr-sdk-0.16.8
./setup.sh
# Yalnızca belirli toolchain'leri kur (ARM + RISC-V)
./setup.sh -t arm-zephyr-eabi -t riscv64-zephyr-elf
# udev kurallarını kur (Linux — USB probe erişimi)
sudo cp ~/zephyr-sdk-0.16.8/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules \
/etc/udev/rules.d/
sudo udevadm control --reload
Ortam değişkenleri
# Zephyr ortam değişkenleri
export ZEPHYR_BASE=~/zephyrproject/zephyr
export ZEPHYR_SDK_INSTALL_DIR=~/zephyr-sdk-0.16.8
# west workspace'i aktifleştir
source ~/zephyrproject/.venv/bin/activate
# Zephyr cmake modüllerini aktifleştir
source $ZEPHYR_BASE/zephyr-env.sh
Bu bölümde
- west init + west update: çoklu repo workspace oluşturur
- Python venv: bağımlılık çakışmalarını önler — her zaman önerilir
- Zephyr SDK: platform başına toolchain; minimal kurulumda yalnızca hedef mimari
- ZEPHYR_BASE ve ZEPHYR_SDK_INSTALL_DIR ortam değişkenleri şart
02 İlk uygulama: hello world
Zephyr'de uygulama yapısı CMakeLists.txt, prj.conf ve kaynak dosyalardan oluşur. west build komutu hedef board için derler.
Uygulama yapısı
my_app/
├── CMakeLists.txt
├── prj.conf
└── src/
└── main.c
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)
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
int main(void)
{
printk("Hello, Zephyr! Board: %s\n", CONFIG_BOARD);
while (1) {
printk("Uptime: %lld ms\n", k_uptime_get());
k_msleep(1000);
}
return 0;
}
Build, flash ve debug
# nRF52840 DK için derle
west build -b nrf52840dk/nrf52840 my_app
# STM32F4 Discovery için derle
west build -b stm32f4_disco my_app
# ESP32 için derle
west build -b esp32_devkitc_wroom/esp32/procpu my_app
# Build çıktısı
ls build/zephyr/
# zephyr.elf zephyr.hex zephyr.bin zephyr.map
# Flash (probe otomatik algılanır)
west flash
# Temiz build (önce CMake cache'i temizle)
west build -p always -b nrf52840dk/nrf52840 my_app
# GDB ile debug başlat
west debug
# Seri konsol (minicom, picocom veya screen)
minicom -D /dev/ttyACM0 -b 115200
Mevcut board'ları listele
# Tüm board'ları listele
west boards
# Belirli SoC ailesi için filtrele
west boards --soc-series stm32f4
# Board hakkında detay
west boards --arch arm | grep nrf52
Bu bölümde
- Uygulama: CMakeLists.txt + prj.conf + src/main.c — minimal 3 dosya
west build -b <board>: board hedefini belirler; çoklu mimari için aynı kaynakwest flash: J-Link, OpenOCD veya ESP-IDF araçlarını otomatik seçer-p always: temiz build; geliştirme sırasında nadiren gerekir
03 Devicetree
Devicetree, donanım topolojisini kaynak koddan ayıran bir veri formatıdır. Zephyr, Linux'la aynı DTS sözdizimini kullanır ancak runtime çözünürlük yerine derleme zamanında işler.
DTS dosya hiyerarşisi
| Dosya türü | Yer | Görev |
|---|---|---|
.dtsi | Zephyr kaynak (SoC tanımı) | SoC registerları, varsayılan konfigürasyon |
.dts | Board dizini | Board-spesifik bağlantılar, pinmux, flash/RAM boyutu |
.overlay | Uygulama dizini | Uygulama ihtiyaçlarına göre board DTS'yi override et |
DTS sözdizimi
/* boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts (sadeleştirilmiş) */
/dts-v1/;
#include <nordic/nrf52840.dtsi>
#include "nrf52840dk_nrf52840-pinctrl.dtsi"
/ {
model = "Nordic nRF52840 DK";
compatible = "nordic,nrf52840-dk-nrf52840";
chosen {
zephyr,console = &uart0; /* konsol UART'ı */
zephyr,shell-uart = &uart0;
zephyr,sram = &sram0;
zephyr,flash = &flash0;
};
aliases {
led0 = &led0;
sw0 = &button0;
};
leds {
compatible = "gpio-leds";
led0: led_0 {
gpios = &gpio0 13 GPIO_ACTIVE_LOW;
label = "Green LED 0";
};
};
};
&uart0 {
compatible = "nordic,nrf-uarte";
status = "okay";
current-speed = <115200>;
pinctrl-0 = &uart0_default;
pinctrl-names = "default";
};
Overlay ile özelleştirme
/* boards/nrf52840dk_nrf52840.overlay — uygulama dizininde */
/* Var olan UART baud hızını değiştir */
&uart0 {
current-speed = <9600>;
};
/* Yeni bir I2C cihazı ekle */
&i2c0 {
status = "okay";
bme280: bme280@76 {
compatible = "bosch,bme280";
reg = <0x76>;
};
};
/* Alias ekle */
/ {
aliases {
mysensor = &bme280;
};
};
C kodunda DT makroları
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
/* DT nodespec'i al (alias üzerinden) */
#define LED0_NODE DT_ALIAS(led0)
/* GPIO spec oluştur */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
int main(void)
{
if (!gpio_is_ready_dt(&led)) {
return -ENODEV;
}
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
while (1) {
gpio_pin_toggle_dt(&led);
k_msleep(500);
}
return 0;
}
Bu bölümde
- .dtsi (SoC) → .dts (board) → .overlay (uygulama): katmanlı özelleştirme
- chosen: konsol, sram, flash bağlamaları
- aliases: cihaz bağımsız erişim —
DT_ALIAS(led0) DEVICE_DT_GET()/GPIO_DT_SPEC_GET(): derleme zamanı DT bağlaması
04 Kconfig
Kconfig, kernel özelliklerini seçmenin sistematik yoludur. Her CONFIG_ seçeneği derleme zamanında C koduna, bağlayıcıya ve CMake'e yansır.
prj.conf — uygulama konfigürasyonu
# Temel sistem
CONFIG_PRINTK=y
CONFIG_STDOUT_CONSOLE=y
# Thread yapılandırması
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_HEAP_MEM_POOL_SIZE=4096
# BLE etkinleştir
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Zephyr BLE"
# UART
CONFIG_UART_ASYNC_API=y
# Logging
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3 # 3 = INFO
# Shell
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
menuconfig — interaktif konfigürasyon
# Grafik Kconfig arayüzü (ncurses)
west build -t menuconfig
# Sadece Zephyr kernel Kconfig'i göster
west build -t guiconfig # Qt tabanlı GUI
# Mevcut build konfigürasyonunu göster
cat build/zephyr/.config | grep CONFIG_BT
# Hangi dosyanın hangi CONFIG_'i ayarladığını bul
west build -t kconfig_old_defconfig
Kconfig fragment ve çakışma çözümü
# Birden fazla .conf dosyasını birleştir
west build -b nrf52840dk/nrf52840 \
-DCONF_FILE="prj.conf;debug.conf"
# debug.conf — debug derlemesi için ek ayarlar
# CONFIG_DEBUG=y
# CONFIG_LOG_DEFAULT_LEVEL=4
# CONFIG_ASSERT=y
# Board spesifik override (boards/nrf52840dk_nrf52840.conf)
# west otomatik yükler
Kconfig C kodunda kullanım
#include <zephyr/kernel.h>
int main(void)
{
#if defined(CONFIG_BT)
printk("BLE desteği aktif\n");
printk("Cihaz adı: %s\n", CONFIG_BT_DEVICE_NAME);
#endif
/* Sayısal CONFIG değeri */
printk("Main stack: %d bytes\n", CONFIG_MAIN_STACK_SIZE);
/* IS_ENABLED makrosu — daha güvenli */
if (IS_ENABLED(CONFIG_LOG)) {
printk("Logging aktif\n");
}
return 0;
}
Bu bölümde
- prj.conf: uygulama Kconfig seçimleri — CONFIG_X=y veya =n veya =sayı
west build -t menuconfig: interaktif ncurses arayüzü- Fragment: -DCONF_FILE ile birden fazla .conf birleştirme
- C kodunda
IS_ENABLED()— preprocessor güvenli kontrol
05 Thread'ler ve zamanlama
Zephyr, öncelik tabanlı preemptive (ve cooperative) zamanlama ile çoklu thread desteği sunar. Thread'ler statik veya dinamik olarak oluşturulabilir.
K_THREAD_DEFINE ile statik thread
#include <zephyr/kernel.h>
/* Thread fonksiyonu */
void sensor_thread(void *arg1, void *arg2, void *arg3)
{
ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3);
while (1) {
printk("Sensör okuyor...\n");
k_msleep(500);
}
}
/* Statik thread: stack 1024 byte, öncelik 5, hemen başlat */
K_THREAD_DEFINE(sensor_tid, /* thread ID değişkeni */
1024, /* stack boyutu */
sensor_thread, /* giriş fonksiyonu */
NULL, NULL, NULL, /* arg1, arg2, arg3 */
5, /* öncelik (düşük sayı = yüksek öncelik) */
0, /* seçenekler */
0); /* gecikme (ms) — 0 = hemen başlat */
k_thread_create ile dinamik thread
#include <zephyr/kernel.h>
/* Stack tanımı (statik — gömülü sistemlerde heap yerine tercih edilir) */
K_THREAD_STACK_DEFINE(worker_stack, 2048);
static struct k_thread worker_data;
void worker_func(void *a, void *b, void *c)
{
int *count = (int *)a;
while (1) {
(*count)++;
k_msleep(100);
}
}
int main(void)
{
static int counter = 0;
k_tid_t tid = k_thread_create(
&worker_data, /* k_thread struct */
worker_stack, /* stack bellek */
K_THREAD_STACK_SIZEOF(worker_stack),
worker_func, /* giriş fonksiyonu */
&counter, NULL, NULL, /* argümanlar */
3, /* öncelik */
0, /* seçenekler */
K_NO_WAIT /* hemen başlat */
);
k_thread_name_set(tid, "worker");
while (1) {
printk("Counter: %d\n", counter);
k_msleep(1000);
}
return 0;
}
Öncelik sistemi ve zamanlama modları
| Kavram | Açıklama |
|---|---|
| Öncelik aralığı | -CONFIG_NUM_COOP_PRIORITIES (-16)…+CONFIG_NUM_PREEMPT_PRIORITIES (+15) |
| Cooperative (negatif) | Gönüllü yield veya blocking çağrı olana kadar CPU bırakmaz |
| Preemptive (0 ve üzeri) | Daha yüksek öncelikli thread hazır olduğunda kernel preempt eder |
| k_yield() | Cooperative thread'de aynı öncelikli thread'e CPU ver |
| k_sleep() / k_msleep() | Thread'i belirli süre uyut — scheduler başka thread çalıştırır |
| Round-robin | Aynı öncelikli preemptive thread'ler time-slice alır (CONFIG_TIMESLICING=y) |
/* prj.conf */
/* CONFIG_TIMESLICING=y */
/* CONFIG_TIMESLICE_SIZE=10 (10 ms time slice) */
/* CONFIG_TIMESLICE_PRIORITY=0 */
/* Runtime öncelik değiştirme */
k_thread_priority_set(tid, 2);
/* Thread'i askıya al / devam ettir */
k_thread_suspend(tid);
k_thread_resume(tid);
/* Thread sonlandırma */
k_thread_abort(tid);
Bu bölümde
K_THREAD_DEFINE: derleme zamanı statik thread — gömülü için idealk_thread_create: çalışma zamanı dinamik thread oluşturma- Negatif öncelik = cooperative; 0+ = preemptive
- CONFIG_TIMESLICING ile aynı öncelikli thread'ler round-robin paylaşır
06 Senkronizasyon primitifleri
Zephyr, thread'ler ve ISR'lar arasında güvenli veri paylaşımı için zengin senkronizasyon API'si sunar. Her primitifin kullanım amacı farklıdır.
k_sem — semafor
#include <zephyr/kernel.h>
/* Statik semafor: başlangıç değeri 0, maksimum 1 */
K_SEM_DEFINE(data_ready_sem, 0, 1);
/* ISR içinden semafor ver (sinyal gönder) */
void uart_isr_callback(const struct device *dev, void *user_data)
{
k_sem_give(&data_ready_sem); /* ISR güvenli */
}
/* Thread: veriyi bekle */
void consumer_thread(void *a, void *b, void *c)
{
while (1) {
/* Semafor alınana kadar bekle (500 ms timeout) */
int ret = k_sem_take(&data_ready_sem, K_MSEC(500));
if (ret == 0) {
printk("Veri hazır, işleniyor\n");
} else {
printk("Timeout!\n");
}
}
}
k_mutex — mutex
#include <zephyr/kernel.h>
K_MUTEX_DEFINE(shared_resource_mutex);
static int shared_counter = 0;
void increment_safely(void)
{
k_mutex_lock(&shared_resource_mutex, K_FOREVER);
/* Kritik bölge başlangıcı */
shared_counter++;
/* Kritik bölge sonu */
k_mutex_unlock(&shared_resource_mutex);
}
/* NOT: Zephyr mutex öncelik devralma (priority inheritance) destekler */
/* CONFIG_MUTEX_INIT_PRIORITY_DEFAULT ile yapılandırılır */
k_fifo ve k_msgq — kuyruk yapıları
#include <zephyr/kernel.h>
/* ─── k_fifo: dinamik bağlı liste ─── */
K_FIFO_DEFINE(sensor_fifo);
struct sensor_data {
void *fifo_reserved; /* k_fifo için ilk alan ayrılmış kalmalı */
uint32_t timestamp;
int16_t temperature;
};
/* Üretici thread */
void producer(void *a, void *b, void *c)
{
while (1) {
struct sensor_data *data = k_malloc(sizeof(*data));
data->timestamp = k_uptime_get_32();
data->temperature = 2500; /* 25.00 °C */
k_fifo_put(&sensor_fifo, data);
k_msleep(100);
}
}
/* Tüketici thread */
void consumer(void *a, void *b, void *c)
{
while (1) {
struct sensor_data *data = k_fifo_get(&sensor_fifo, K_FOREVER);
printk("T=%u, temp=%d\n", data->timestamp, data->temperature);
k_free(data);
}
}
/* ─── k_msgq: sabit boyutlu, statik bellek ─── */
K_MSGQ_DEFINE(uart_msgq, sizeof(char), 64, 1); /* 64 char kapasiteli kuyruk */
void uart_isr(void)
{
char c = uart_read_char();
k_msgq_put(&uart_msgq, &c, K_NO_WAIT); /* ISR güvenli */
}
void uart_consumer(void *a, void *b, void *c)
{
char c;
while (1) {
k_msgq_get(&uart_msgq, &c, K_FOREVER);
printk("%c", c);
}
}
Senkronizasyon primitif karşılaştırması
| Primitif | Kullanım senaryosu | ISR güvenli | Bellek |
|---|---|---|---|
| k_sem | Olay sinyali, kaynak sayacı | Evet (give) | Statik |
| k_mutex | Kritik bölge koruması | Hayır | Statik |
| k_condvar | Koşul değişkeni (mutex ile birlikte) | Hayır | Statik |
| k_fifo | Değişken boyutlu veri kuyruğu | Evet | Dinamik (heap) |
| k_msgq | Sabit boyutlu mesaj kuyruğu | Evet | Statik |
| k_pipe | Byte akışı (üretici-tüketici) | Kısıtlı | Statik |
Bu bölümde
- k_sem: olay sinyali — ISR'dan thread'e en yaygın iletişim yolu
- k_mutex: öncelik devralmalı — gömülü RT sistemlerde kritik
- k_msgq: sabit boyut, statik bellek — ISR güvenli, gömülü için tercih edilir
- k_fifo: dinamik bağlı liste — heap gerektirir; büyük değişken veri için
07 Peripheral sürüş
Zephyr'de tüm periferallar Devicetree tabanlı, tutarlı bir driver API'siyle sürülür. Cihaz nesnesi DT'den alınır; HAL fonksiyonları MCU bağımsızdır.
GPIO
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
/* DT alias'larından GPIO spec al */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
static const struct gpio_dt_spec btn = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios);
/* GPIO interrupt callback */
static struct gpio_callback btn_cb_data;
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
printk("Butona basıldı!\n");
}
int main(void)
{
/* Çıkış konfigürasyonu */
gpio_pin_configure_dt(&led, GPIO_OUTPUT_INACTIVE);
/* Giriş konfigürasyonu + interrupt */
gpio_pin_configure_dt(&btn, GPIO_INPUT | GPIO_PULL_UP);
gpio_pin_interrupt_configure_dt(&btn, GPIO_INT_EDGE_TO_ACTIVE);
gpio_init_callback(&btn_cb_data, button_pressed, BIT(btn.pin));
gpio_add_callback(btn.port, &btn_cb_data);
while (1) {
gpio_pin_toggle_dt(&led);
k_msleep(1000);
}
return 0;
}
UART
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart)
static const struct device *uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
static uint8_t rx_buf[64];
void uart_callback(const struct device *dev, struct uart_event *evt, void *user_data)
{
switch (evt->type) {
case UART_RX_RDY:
printk("UART RX: %d byte\n", evt->data.rx.len);
break;
case UART_TX_DONE:
printk("UART TX tamamlandı\n");
break;
default:
break;
}
}
int main(void)
{
uart_callback_set(uart_dev, uart_callback, NULL);
uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), 100 /* timeout us */);
const char *msg = "Merhaba UART!\r\n";
uart_tx(uart_dev, msg, strlen(msg), SYS_FOREVER_US);
return 0;
}
I2C
#include <zephyr/drivers/i2c.h>
#define I2C_NODE DT_NODELABEL(i2c0)
static const struct device *i2c_dev = DEVICE_DT_GET(I2C_NODE);
#define BME280_ADDR 0x76
#define BME280_REG_ID 0xD0
int main(void)
{
uint8_t chip_id;
uint8_t reg = BME280_REG_ID;
/* Register yaz, sonra oku (write-then-read) */
struct i2c_msg msgs[] = {
{ .buf = ®, .len = 1, .flags = I2C_MSG_WRITE },
{ .buf = &chip_id, .len = 1, .flags = I2C_MSG_READ | I2C_MSG_STOP },
};
int ret = i2c_transfer(i2c_dev, msgs, ARRAY_SIZE(msgs), BME280_ADDR);
if (ret == 0) {
printk("BME280 chip ID: 0x%02X (beklenen: 0x60)\n", chip_id);
}
return 0;
}
Bu bölümde
- GPIO:
GPIO_DT_SPEC_GET+gpio_pin_configure_dt— DT-first API - UART async: callback tabanlı, DMA arkasında — ISR overhead yok
- I2C:
i2c_transferile write-then-read;i2c_write_readkısayol - Tüm driver'lar:
DEVICE_DT_GETile cihaz nesnesi, derleme zamanı doğrulama
08 Logging ve Shell
Zephyr'nin yerleşik logging altyapısı defer modunda çalışır — ISR veya kritik bölgelerde log mesajı güvenle çağrılabilir. Interaktif shell komutları kolayca eklenir.
Logging — LOG_MODULE_REGISTER
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
/* Modül kaydı — her .c dosyasında bir kez */
LOG_MODULE_REGISTER(my_sensor, LOG_LEVEL_DBG);
void sensor_read(void)
{
int temperature = 2543; /* 25.43 °C * 100 */
LOG_DBG("Ham değer: %d", temperature);
LOG_INF("Sıcaklık: %d.%02d C", temperature / 100, temperature % 100);
LOG_WRN("Değer yüksek sınıra yakın: %d", temperature);
LOG_ERR("Sensör iletişim hatası!");
/* Hex dump */
uint8_t buf[] = {0x01, 0x02, 0xAB, 0xCD};
LOG_HEXDUMP_DBG(buf, sizeof(buf), "I2C yanıtı");
}
# prj.conf
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3 # 0=none 1=err 2=warn 3=inf 4=dbg
CONFIG_LOG_MAX_LEVEL=4 # derleme zamanı maksimum seviye
CONFIG_LOG_BACKEND_UART=y # UART backend
CONFIG_LOG_BACKEND_RTT=y # Segger RTT backend (J-Link)
# Modül bazlı seviye override
CONFIG_LOG_OVERRIDE_LEVEL=4 # Tüm modülleri debug seviyesine çek
# ya da bireysel:
# CONFIG_MY_SENSOR_LOG_LEVEL=4
Zephyr Shell — komut ekleme
#include <zephyr/shell/shell.h>
/* Shell komutu implementasyonu */
static int cmd_hello(const struct shell *sh, size_t argc, char **argv)
{
if (argc > 1) {
shell_print(sh, "Merhaba, %s!", argv[1]);
} else {
shell_print(sh, "Merhaba, Zephyr!");
}
return 0;
}
static int cmd_stats(const struct shell *sh, size_t argc, char **argv)
{
shell_print(sh, "Uptime: %lld ms", k_uptime_get());
shell_print(sh, "Free heap: %zu bytes", k_mem_free_get());
return 0;
}
/* Komut ağacı tanımı */
SHELL_STATIC_SUBCMD_SET_CREATE(sub_demo,
SHELL_CMD(hello, NULL, "Selamlama komutu", cmd_hello),
SHELL_CMD(stats, NULL, "Sistem istatistikleri", cmd_stats),
SHELL_SUBCMD_SET_END
);
SHELL_CMD_REGISTER(demo, &sub_demo, "Demo komutları", NULL);
# prj.conf
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y # UART üzerinden shell
CONFIG_SHELL_BACKEND_RTT=y # RTT üzerinden shell (J-Link)
CONFIG_SHELL_HISTORY=y # Yukarı/aşağı tuş geçmişi
CONFIG_SHELL_TAB=y # Tab ile otomatik tamamlama
CONFIG_SHELL_CMDS_RESIZE=y # Ekran boyutuna uyum
Bu bölümde
LOG_MODULE_REGISTER(name, level): her dosyada bir kez; LOG_INF/WRN/ERR/DBG- Backend: UART (her zaman) veya RTT (J-Link bağlıyken latency yok)
SHELL_CMD_REGISTER: tab-complete, history, subcmd ağacı — sıfır ekstra kod- Shell + RTT: seri kablo olmadan interaktif debug
09 Pratik uygulamalar
Üç mini uygulama: nRF52840'ta BLE beacon, STM32F4'te UART echo ve ESP32'de WiFi station.
nRF52840 — BLE iBeacon
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
/* iBeacon veri yapısı */
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA,
0x4C, 0x00, /* Apple Company ID */
0x02, 0x15, /* iBeacon type & length */
/* UUID: 12345678-1234-1234-1234-123456789ABC */
0x12, 0x34, 0x56, 0x78,
0x12, 0x34, 0x12, 0x34,
0x12, 0x34, 0x12, 0x34,
0x56, 0x78, 0x9A, 0xBC,
0x00, 0x01, /* Major */
0x00, 0x01, /* Minor */
0xC5) /* TX Power (-59 dBm) */
};
int main(void)
{
int err = bt_enable(NULL);
if (err) {
printk("BT etkinleştirme hatası: %d\n", err);
return err;
}
/* Non-connectable undirected advertising */
err = bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
printk("Advertising başlatma hatası: %d\n", err);
return err;
}
printk("iBeacon yayını başladı\n");
return 0;
}
# prj.conf
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Zephyr Beacon"
CONFIG_BT_DEVICE_APPEARANCE=0
STM32F4 — UART echo
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
static const struct device *uart = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
static uint8_t rx_buf[1];
void uart_cb(const struct device *dev, struct uart_event *evt, void *ud)
{
switch (evt->type) {
case UART_RX_RDY:
/* Alınan karakteri geri gönder (echo) */
uart_tx(dev, evt->data.rx.buf + evt->data.rx.offset,
evt->data.rx.len, SYS_FOREVER_US);
break;
case UART_RX_DISABLED:
/* RX yeniden etkinleştir */
uart_rx_enable(dev, rx_buf, sizeof(rx_buf), 1000);
break;
default:
break;
}
}
int main(void)
{
uart_callback_set(uart, uart_cb, NULL);
uart_rx_enable(uart, rx_buf, sizeof(rx_buf), 1000);
printk("UART Echo hazır — yazmaya başlayın\n");
k_sleep(K_FOREVER);
return 0;
}
ESP32 — WiFi Station
#include <zephyr/kernel.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/wifi_mgmt.h>
#include <zephyr/net/net_event.h>
#define WIFI_SSID "MyNetwork"
#define WIFI_PASSWORD "MyPassword"
static struct net_mgmt_event_callback wifi_cb;
static void wifi_event_handler(struct net_mgmt_event_callback *cb,
uint32_t mgmt_event, struct net_if *iface)
{
if (mgmt_event == NET_EVENT_WIFI_CONNECT_RESULT) {
printk("WiFi bağlandı!\n");
} else if (mgmt_event == NET_EVENT_WIFI_DISCONNECT_RESULT) {
printk("WiFi bağlantısı kesildi\n");
}
}
int main(void)
{
struct net_if *iface = net_if_get_default();
net_mgmt_init_event_callback(&wifi_cb, wifi_event_handler,
NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT);
net_mgmt_add_event_callback(&wifi_cb);
struct wifi_connect_req_params params = {
.ssid = WIFI_SSID,
.ssid_length = strlen(WIFI_SSID),
.psk = WIFI_PASSWORD,
.psk_length = strlen(WIFI_PASSWORD),
.security = WIFI_SECURITY_TYPE_PSK,
.channel = WIFI_CHANNEL_ANY,
};
int ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, ¶ms, sizeof(params));
if (ret) {
printk("WiFi bağlanma isteği hatası: %d\n", ret);
return ret;
}
printk("WiFi bağlanıyor: %s\n", WIFI_SSID);
k_sleep(K_FOREVER);
return 0;
}
# prj.conf
CONFIG_WIFI=y
CONFIG_WIFI_ESP32=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
Bu bölümde
- BLE beacon: bt_enable + bt_le_adv_start — connectable olmadan advertisement
- UART echo: async callback tabanlı — UART_RX_DISABLED'da RX yeniden etkinleştir
- ESP32 WiFi: NET_REQUEST_WIFI_CONNECT + net_mgmt event callback
- Her örnek aynı kaynak kodu farklı board overlay ile çalışır