This is an old revision of the document!
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:
hello_world din Zephyr pentru o platformă țintă ESP32‑S3Î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:
Mai jos puteți vedea diagrama hardware a ceasului:
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.
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.
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.
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
Ghidul oficial Zephyr pentru instalarea west: https://docs.zephyrproject.org/latest/develop/west/install.html
pip install -U west
# 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.)
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.
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.
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:
Acest tutorial se concentrează pe A, pentru a obține rapid o primă pornire reușită, apoi prezintă pe scurt B.
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:
În această secțiune trebuie acordată atenție unor aspecte specifice Hacktor:
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
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.txtprj.confsrc/main.cPoț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
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:
zephyr,console la &usb_serialusb_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:
Activează mai întâi mediul virtual Python, dacă nu este deja activ:
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
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.