This is an old revision of the document!


Lab 01: Zephyr RTOS, compilarea unei aplicații simple

Bine ați venit în laboratorul de Sisteme Încorporate!

În cadrul acestui laborator, ne propunem să vă familiarizăm cu sisteme de operare RTOS (Real-Time Operating System) - în speță Zephyr OS - care se pretează mai degrabă microcontrolerelor decât sistemelor de tip desktop.

Zephyr OS este un sistem de operare în timp real (RTOS), de dimensiuni reduse și cu sursă deschisă, conceput pentru dispozitive embedded și IoT cu resurse limitate, de la microcontrolere foarte mici până la platforme hardware edge mai performante. Acesta pune accentul pe un comportament predictibil, cu latență redusă, printr-un nucleu preemptiv, posibilități extinse de configurare (compilezi doar ceea ce îți trebuie) și suport pentru o gamă largă de platforme hardware, printr-un model bine structurat de drivere pentru dispozitive. Zephyr include funcționalități uzuale în sistemele embedded, precum fire de execuție, primitive de sincronizare, temporizatoare, gestionarea consumului de energie, stive de protocoale de comunicație (de exemplu, TCP/IP și Bluetooth LE) și opțiuni de securitate. Toate acestea sunt dezvoltate și întreținute sub egida Linux Foundation, cu accent pe portabilitate, modularitate și utilizarea în produse finale.

Acest tutorial te ghidează prin următorii pași:

  1. configurarea unui mediu de dezvoltare Zephyr nou („de la zero”) pe un calculator
  2. compilarea exemplului hello_world din Zephyr pentru o platformă țintă ESP32‑S3
  3. scrierea aplicației în memoria flash a ceasului Hacktor Watch
  4. vizualizarea mesajului „Hello World” prin conexiunea USB

1. Hacktor Watch

În acest laborator veți învăța cum să compilați și să încărcați sistemul de operare Zephyr OS pe smartwatch-ul Hacktor Watch, dezvoltat în facultate și bazat pe un microprocesor ESP32 S3 la care au fost adăugate:

  • două butoane externe
  • un display cu touch
  • un senzor de haptics
  • un accelerometru și giroscop

Mai jos puteți vedea diagrama hardware a ceasului:

hacktor_watch_2.0.jpg

Pentru a putea fi folosit pe microcontrolere, Zephyr are un memory-footprint foarte scăzut (de ordinul câtorva sute de kilobytes). Un alt feature care îl face potrivit sistemelor low-end este faptul că nu folosește mecanismele de memorie virtuală (mai costisitoare atât din punct de vedere hardware, cât și software) în mod implicit, acest mod de operare numindu-se flat-mode addressing.

2. Instalarea Zephyr „de la zero” pe calculator

Ghidul introductiv oficial al Zephyr reprezintă referința principală pentru configurarea calculatorului de dezvoltare (Ubuntu/macOS/Windows), a mediului Python și pentru instalarea west și a SDK-ului. Referință: https://docs.zephyrproject.org/latest/develop/getting_started/index.html

Mai jos este prezentată o procedură practică de configurare, cu pași de urmat în ordine, conform acestui ghid.

2.1 Instalarea dependențelor sistemului de operare

Urmează pasul Instalarea dependențelor din ghidul introductiv Zephyr, corespunzător sistemului tău de operare (Ubuntu/macOS/Windows). Ghid: https://docs.zephyrproject.org/latest/develop/getting_started/index.html

În mod obișnuit, vei avea nevoie de: Python 3, CMake, Ninja, Git și instrumentele de compilare ale sistemului.

2.2 Crearea unui spațiu de lucru Zephyr și a unui mediu virtual Python

Alege un director pentru spațiul de lucru. În acest tutorial voi folosi ~/zephyrproject pe Linux/macOS. (Utilizatorii Windows pot folosi, de exemplu, C:\zephyrproject.)

# Linux/macOS
mkdir -p ~/zephyrproject
cd ~/zephyrproject
 
python3 -m venv .venv
source .venv/bin/activate

În Windows PowerShell (exemplu):

mkdir C:\zephyrproject
cd C:\zephyrproject
 
py -m venv .venv
.\.venv\Scripts\Activate.ps1

2.3 Instalarea west

Ghidul oficial Zephyr pentru instalarea west: https://docs.zephyrproject.org/latest/develop/west/install.html

pip install -U west

2.4 Inițializarea și actualizarea spațiului de lucru Zephyr

# Still inside ~/zephyrproject (or your chosen folder)
west init -m https://github.com/zephyrproject-rtos/zephyr --mr main
west update

Exportă pachetul CMake al Zephyr (pentru ca CMake să poată găsi Zephyr):

west zephyr-export

Instalează dependențele Python pentru Zephyr și modulele sale:

west packages pip --install

(Această comandă apare exact în această formă în procedura din ghidul introductiv și reprezintă, de obicei, pasul următor după west update.)

2.5 Instalarea Zephyr SDK (setul de instrumente de compilare)

Documentația Zephyr SDK: https://docs.zephyrproject.org/latest/develop/toolchains/zephyr_sdk.html

Instalează Zephyr SDK pentru sistemul tău de operare, apoi asigură-te că mediul de dezvoltare îl poate găsi (fie prin înregistrarea acestuia de către scriptul de configurare al SDK-ului, fie prin variabile de mediu precum ZEPHYR_SDK_INSTALL_DIR / ZEPHYR_TOOLCHAIN_VARIANT=zephyr).

Notă: ESP32‑S3 se bazează pe arhitectura Xtensa, așa că vei avea nevoie de setul de instrumente de compilare pentru Xtensa inclus în Zephyr SDK.

3. Cerințe preliminare pentru ESP32 (Espressif) în Zephyr

3.1 Descărcarea componentelor binare Espressif pentru RF

Stratul de abstractizare hardware (HAL) Espressif din Zephyr necesită componente binare (pentru calibrarea RF etc.). Documentația Zephyr pentru plăcile Espressif menționează acest lucru și recomandă descărcarea lor după west update. Exemplu (documentația ESP32 DevKitC): se indică explicit executarea comenzii west blobs fetch hal_espressif.

Rulează:

# From your workspace root (~/zephyrproject)
west blobs fetch hal_espressif

Dacă omiți acest pas, pot apărea erori de compilare sau de execuție pentru platformele țintă ESP32.

4. Alegerea unei plăci țintă Zephyr pentru Hacktor

Hacktor nu se află (încă) printre plăcile incluse în proiectul principal Zephyr (poate ai putea contribui la acest lucru?), așa că avem nevoie de o definiție de placă Zephyr compatibilă pentru a compila și a scrie în memoria flash o primă imagine a aplicației.

Există două abordări rezonabile:

  1. A. Varianta rapidă (recomandată pentru Hello World): folosește o definiție de placă ESP32‑S3 din proiectul principal Zephyr, care are deja 4 MB de memorie flash și permite programarea prin USB‑C.
  2. B. Portare completă: creează o definiție de placă Zephyr personalizată pentru Hacktor, în afara arborelui sursă Zephyr (cea mai bună variantă pe termen lung, necesară atunci când începi să folosești GPIO-uri și periferice și ai nevoie de o mapare corectă a pinilor).

Acest tutorial se concentrează pe A, pentru a obține rapid o primă pornire reușită, dar varianta mai serioasă ar trebui să fie B.

4.1 Abordarea A: Folosirea ''esp32s3_devkitc'' ca variantă apropiată

Zephyr include placa oficială Espressif ESP32 S3 Devkitc, descrisă explicit în documentație ca fiind bazată pe ESP32-S3-WROOM-1, cu 8 MB de memorie flash Quad și 8 MB de PSRAM Octal. Documentația plăcii: https://docs.zephyrproject.org/latest/boards/espressif/esp32s3_devkitc/doc/index.html

Limitări:

  • Maparea pinilor (LED, I2C etc.) nu va corespunde celei de pe Hacktor.
  • Pentru hello_world, maparea pinilor nu contează.

5. Compilarea aplicației „Hello World” pentru Hacktor și redirecționarea consolei prin USB

În această secțiune trebuie acordată atenție unor aspecte specifice Hacktor:

  • asigură-te că memoria flash este configurată la 8 MB
  • asigură-te că ieșirea consolei este transmisă prin portul USB Serial/JTAG (nu prin UART0)

Vom:

1. crea un director pentru o aplicație simplă
2. adăuga un fișier overlay devicetree care selectează dispozitivul serial USB pentru consolă
3. compila aplicația și o vom scrie în memoria flash

5.1 Crearea directorului pentru o aplicație minimală

Din directorul rădăcină al spațiului de lucru Zephyr:

cd ~/zephyrproject
 
mkdir -p hacktor_hello
cd hacktor_hello

Creează următoarele fișiere:

  • CMakeLists.txt
  • prj.conf
  • src/main.c
  • un fișier overlay pentru placă

Poți copia exemplul hello_world, dar recomand crearea unei aplicații minimale, pentru a avea control deplin asupra configurației consolei.

CMakeLists.txt

cmake_minimum_required(VERSION 3.20.0)
 
set(BOARD esp32s3_devkitc/esp32s3/procpu CACHE STRING "Default Zephyr board")
 
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(minimal_zephyr_app)
 
target_sources(app PRIVATE
    src/main.c
)

src/main.c

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
 
int main(void)
{
	while (1) {
		printk("Hello World!\n");
		k_sleep(K_SECONDS(1));
	}
}

prj.conf (configurație minimală pentru jurnalizare/consolă)

CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_SERIAL_ESP32_USB=y
CONFIG_PRINTK=y

5.2 Overlay devicetree: forțarea utilizării USB Serial/JTAG pentru consolă

Pe cipurile ESP32 care dispun de un dispozitiv USB Serial/JTAG expus în Zephyr ca UART, poți redirecționa consola modificând nodurile chosen din devicetree.

O discuție despre o problemă raportată în proiectul Zephyr, referitoare la ieșirea serială USB pe ESP32, prezintă următorul model de overlay:

  • setează zephyr,console la &usb_serial
  • activează nodul usb_serial

(Consultă problema #60825 din proiectul Zephyr, despre utilizarea usb_serial pentru consolă pe dispozitive din familia ESP32.)

În rădăcina directorului proiectului, creează:

app.overlay

/ {
	chosen {
		zephyr,console = &usb_serial;
	};
};
 
&usb_serial {
	status = "okay";
};

De ce este important acest lucru pentru Hacktor:

  • Plăcile ESP32 de tip DevKit folosesc adesea implicit UART0 pentru consolă (destinat unei punți USB‑UART externe).
  • Hacktor folosește USB Serial/JTAG prin conectorul USB, așa că ieșirea consolei trebuie redirecționată acolo.

5.3 Compilarea aplicației

Activează mai întâi mediul virtual Python, dacă nu este deja activ:

build.sh
cd ~/zephyrproject
source .venv/bin/activate

Apoi accesează directorul hacktor_hello și creează următorul script de compilare, cu numele build.sh:

#!/usr/bin/env bash
 
set -euo pipefail
 
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$SCRIPT_DIR"
DEFAULT_BOARD="esp32s3_devkitc/esp32s3/procpu"
 
if [ -d "$PROJECT_ROOT/../.venv/bin" ]; then
    export PATH="$PROJECT_ROOT/../.venv/bin:$PATH"
fi
 
if [ -z "${ZEPHYR_BASE:-}" ]; then
    if [ -d "$PROJECT_ROOT/../zephyr" ]; then
        export ZEPHYR_BASE="$PROJECT_ROOT/../zephyr"
    else
        echo "ZEPHYR_BASE is not set and ../zephyr was not found." >&2
        exit 1
    fi
fi
 
BOARD="${BOARD:-$DEFAULT_BOARD}"
BUILD_DIR="${BUILD_DIR:-$PROJECT_ROOT/build}"
FLASH_PORT="${FLASH_PORT:-${ESPTOOL_PORT:-}}"
FLASH_BAUD="${FLASH_BAUD:-}"
 
PRISTINE=0
RUN_FLASH=0
ERASE_FLASH=0
 
while [ $# -gt 0 ]; do
    case "$1" in
        -p|--pristine)
            PRISTINE=1
            ;;
        -f|--flash|--upload)
            RUN_FLASH=1
            ;;
        --erase)
            ERASE_FLASH=1
            ;;
        --port)
            shift
            if [ $# -eq 0 ]; then
                echo "--port requires a value." >&2
                exit 1
            fi
            FLASH_PORT="$1"
            ;;
        --baud)
            shift
            if [ $# -eq 0 ]; then
                echo "--baud requires a value." >&2
                exit 1
            fi
            FLASH_BAUD="$1"
            ;;
        -h|--help)
            cat <<EOF
Usage: ./build.sh [--pristine] [--flash] [--port <device>] [--baud <rate>] [--erase]
 
Environment overrides:
  BOARD=<board target>       Default: $DEFAULT_BOARD
  BUILD_DIR=<build dir>      Default: $PROJECT_ROOT/build
  ZEPHYR_BASE=<zephyr path>  Auto-detected from ../zephyr if unset
  FLASH_PORT=<device>        Serial port for flashing
  FLASH_BAUD=<rate>          Serial baud rate for flashing
EOF
            exit 0
            ;;
        *)
            echo "Unknown argument: $1" >&2
            exit 1
            ;;
    esac
    shift
done
 
if [ "$PRISTINE" -eq 1 ]; then
    rm -rf "$BUILD_DIR"
fi
 
cmake -GNinja -B "$BUILD_DIR" -S "$PROJECT_ROOT" -DBOARD="$BOARD"
cmake --build "$BUILD_DIR"
 
if [ "$RUN_FLASH" -eq 1 ]; then
    flash_cmd=(west flash --no-rebuild -d "$BUILD_DIR" -r esp32)
    runner_args=()
 
    if [ -n "$FLASH_PORT" ]; then
        runner_args+=(--esp-device "$FLASH_PORT")
    fi
 
    if [ -n "$FLASH_BAUD" ]; then
        runner_args+=(--esp-baud-rate "$FLASH_BAUD")
    fi
 
    if [ "$ERASE_FLASH" -eq 1 ]; then
        runner_args+=(--erase)
    fi
 
    if [ ${#runner_args[@]} -gt 0 ]; then
        flash_cmd+=(-- "${runner_args[@]}")
    fi
 
    "${flash_cmd[@]}"
fi
 
echo
echo "Build complete:"
echo "  Board: $BOARD"
echo "  Build dir: $BUILD_DIR"
echo "  ELF: $BUILD_DIR/zephyr/zephyr.elf"
 
if [ "$RUN_FLASH" -eq 1 ]; then
    echo "  Flash: completed"
    echo "Opening serial terminal on ${FLASH_PORT} (115200)..."
    exec screen "${FLASH_PORT}" 115200
fi

5.4 Scrierea aplicației pe Hacktor prin USB

Conectează ceasul Hacktor prin USB‑C.

Apoi compilează aplicația și scrie-o în memoria flash, rulând:

./build.sh --upload --port [your_usb_port]

Vei vedea cum aplicația este compilată și încărcată pe dispozitiv, după care un terminal serial va afișa mesajul Hello World.

si/laboratoare/2026/01.1790609445.txt.gz · Last modified: 2026/09/28 18:30 by dan.tudose
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0