Zephyr OS – 1 – Découverte sur Raspberry Pi Pico

Publié par cpb
Oct 15 2024

Zephyr 0S est un système d’exploitation temps réel que l’on peut utiliser sur de petits microcontrôleurs pour réaliser des tâches relativement simples avec un comportement temporel précis.

Nous allons l’étudier pendant quelques articles en nous appuyant sur des modèles de microcontrôleurs répandus, peu coûteux et faciles à se procurer comme le Raspberry Pi Pico.

Attention : il s’agit bien du « Raspberry Pi Pico » et pas du « Raspberry Pi Pico 2 » sorti il y a quelques semaines. Ce dernier est architecturé autour d’un microcontrôleur différent et n’est pas encore supporté par Zephyr Os au moment de la rédaction de cet article.

Introduction

Zephyr OS

Les microprocesseurs et microcontrôleurs sont omniprésents dans l’informatique industrielle, dans l’Internet des objets (IOT) et même dans la plupart des équipements électroniques que l’on rencontre au quotidien. Lorsque la composante « informatique » d’un équipement est suffisamment importante, on délègue le travail à un microprocesseur sur lequel on fait tourner un système d’exploitation (Operating System – OS) comme Linux embarqué.

Lorsque le travail logiciel est relativement simple, répétitif et ne nécessite pas de grosse capacité de calcul ou de stockage on se tourne vers un microcontrôleur. Les microcontrôleurs existent dans des gammes très variées, de la famille des PIC à celle des STM32 en passant par les AVR, LPC, etc. Cela offre un choix très large pour le concepteur d’un circuit.

En contrepartie, les méthodes de programmation pour accéder aux fonctionnalités offertes par un microcontrôleur varient sensiblement d’un modèle à l’autre. Il est difficile d’écrire du code portable d’un microcontrôleur à un autre, car ils n’offrent pas de méthodes de développement généralisées.

Mais heureusement des efforts ont été réalisés pour offrir un socle commun, permettant de disposer d’une interface de programmation (Application Programming Interface – API) standard et riche. Il s’agit tout simplement de doter les microcontrôleurs d’un OS sur lequel on peut appuyer le développement spécifique. Plusieurs systèmes de ce type ont été développés : µC/OS, Contiki, RIOT, etc. Nous allons nous intéresser à un OS pour microcontrôleurs qui semblent de plus en plus actif aujourd’hui : Zephyr ® . Il s’agit d’une marque déposée par la Linux Foundation qui gère aujourd’hui ce projet, initialement créé par Wind River.

Raspberry Pico

Depuis 2012, la Fondation Raspberry Pi a produit de nombreux modèles de « Single Board Computer » , petits ordinateurs monocartes nécessitant simplement l’ajout d’un clavier, d’un écran, d’une alimentation et d’une carte micro-SD pour offrir toutes les fonctionnalités d’un ordinateur classique. Ce sont tous les modèles 1B/B+/A, 2B, 3B/B+/A, 4B/A, 400, 5 ainsi que les petits Zero 1/W/2W.

Un modèle très différent a été produit en 2021 : le Raspberry Pi Pico. Il n’est pas conçu autour d’un microprocesseur mais autour d’un micro-contrôleur (RP2040) spécifiquement conçu pour l’occasion, avec 264Ko de RAM et 2Mo de mémoire flash intégrée. Une seconde version, Raspberry Pi Pico 2, disponible depuis août 2024, est construite autour d’un nouveau micro-contrôleur (RP2350) et dispose de 4Mb de mémoire flash. Elle n’est pas encore supportée par Zephyr.

Malgré leur ressemblance, il est important de ne pas confondre le Raspberry Pi Zero (sur lequel on installe un système Linux normal et des applications classiques) et le Raspberry Pi Pico qui ne peut contenir qu’un OS minimal comme Zephyr et un volume de code assez réduit.

Là où les Rasberry Pi classiques (y compris le Zero) peuvent faire penser à un petit PC, le Pico est beaucoup plus proche de la famille des Arduino.

Préparations préliminaires

Je vais préparer sur un PC tournant sous Linux un fichier contenant l’OS Zephyr et un petit code d’exemple, pour pouvoir ensuite l’installer sur un Raspberry Pi Pico.

Environnement de travail

Je crée un répertoire Zephyr-lab dans mon arborescence pour stocker tous les éléments nécessaires au développement pour Zephyr.

Python

Nous allons installer plusieurs outils Python spécifiques à Zephyr (par exemple l’outil de build west). Il est préférable de créer un environnement Python virtuel pour éviter de « polluer » notre installation Python globale.

[Zephyr-Lab]$ sudo  apt install  -y  python3-venv

[Zephyr-Lab]$ python3 -m venv  .venv

[Zephyr-Lab]$ source .venv/bin/activate

(.venv)[Zephyr-Lab]$ 

Le préfixe (.venv) au début du prompt du shell nous indique que nous utilisons cet environnement virtuel. Pour le quitter il suffit d’utiliser la commande deactivate. Bien sûr il faudra réactiver l’environnement (avec source .venv/bin/activate dans ce répertoire) à chaque fois que nous lancerons un shell pour travailler avec Zephyr.

Outil de build

Nous installons l’outil de compilation de Zephyr. Il s’appelle west (avant d’être un OS pour microcontrôleurs, le Zéphyr est un vent qui souffle de l’ouest) et servira à encadrer les appels à cmake .

(.venv)[Zephyr-Lab]$ pip  install  west
  [...]

SDK de Zephyr

Le SDK (Software Development Kit) est l’ensemble de la toolchain (chaîne de cross-compilation, permettant de générer du code pour le processeur cible) et des fichiers headers permettant d’accéder aux services de Zephyr.

Je fais mes développements sur un PC Linux, je choisis donc le SDK en conséquence. Il en existe en effet plusieurs versions :

  • zephyr-sdk-0.16.8_linux-x86_64.tar.xz pour Linux x86/64 (par exemple un PC Linux),
  • zephyr-sdk-0.16.8_linux-aarch64.tar.xz pour Linux Arm 64 (par exemple un Raspberry Pi 4 ou 5),
  • zephyr-sdk-0.16.8_macos-x86_64.tar.xz pour MacOS sur x86/64,
  • zephyr-sdk-0.16.8_macos-x86_64.tar.xz pour MacOS sur Arm 64,
  • zephyr-sdk-0.16.8_windows-x86_64.7z pour Windows sur x86/64.

Le téléchargement se fait à partir du dépôt Gihub de zephyrproject-rtos.

Une fois la toolchain décompressée, un script setup.sh vient configurer ses composants et enregistrer le package Cmake du SDK

(.venv)[Zephyr-lab]$ wget  https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.8/zephyr-sdk-0.16.8_linux-x86_64.tar.xz
  [...]
(.venv)[Zephyr-lab]$ tar  xf  zephyr-sdk-0.16.8_linux-x86_64.tar.xz 
(.venv)[Zephyr-lab]$ cd  zephyr-sdk-0.16.8/
(.venv)[zephyr-sdk-0.16.8]$ ./setup.sh
Zephyr SDK 0.16.8 Setup

** NOTE **
You only need to run this script once after extracting the Zephyr SDK
distribution bundle archive.

Install host tools [y/n]? y
Register Zephyr SDK CMake package [y/n]? y

Installing host tools ...

All done.
Press any key to exit ...

(.venv)[zephyr-sdk-0.16.8]$ cd ..

(.venv)[Zephyr-lab]$ rm  zephyr-sdk-0.16.8_linux-x86_64.tar.xz

(.venv)[Zephyr-lab]$

Lors de l’installation du SDK, un package Cmake a été enregistré pour trouver l’accès à la toolchain :

(.venv)[zephyr-sdk-0.16.8]$ ls  -l  ~/.cmake/packages/Zephyr-sdk/
total 4
-rw-rw-r-- 1 cpb cpb 51 août   7 17:09 d901fd4ba9b608aa29d7f5c12d60fef3

(.venv)[zephyr-sdk-0.16.8]$ cat  ~/.cmake/packages/Zephyr-sdk/d901fd4ba9b608aa29d7f5c12d60fef3 
/home/Builds/Lab/Zephyr-lab/zephyr-sdk-0.16.8/cmake
(.venv)[zephyr-sdk-0.16.8]$ 

Exemple de base de Zephyr

Installation du kernel

Nous initialisons un répertoire de build nommé zephyr-project . Pour cela nous utilisons la commande west init . Celle-ci va cloner un repository Github contenant entre autres un manifest listant les autres dépôts à cloner.

(.venv)[Zephyr-lab]$ west  init  zephyr-project
=== Initializing in /home/Builds/Lab/Zephyr-lab/zephyr-project
--- Cloning manifest repository from https://github.com/zephyrproject-rtos/zephyr
Cloning into '/home/Builds/Lab/Zephyr-lab/zephyr-project/.west/manifest-tmp'...
remote: Enumerating objects: 1088209, done.
remote: Counting objects: 100% (231/231), done.
remote: Compressing objects: 100% (138/138), done.
remote: Total 1088209 (delta 101), reused 156 (delta 89), pack-reused 1087978
Receiving objects: 100% (1088209/1088209), 650.48 MiB | 25.04 MiB/s, done.
Resolving deltas: 100% (821755/821755), done.
Updating files: 100% (36170/36170), done.
--- setting manifest.path to zephyr
=== Initialized. Now run "west update" inside /home/Builds/Lab/Zephyr-lab/zephyr-project.

(.venv)[Zephyr-lab]$ 

Le répertoire créé contient un sous-répertoire avec la configuration de west et un second avec les sources du kernel Zephyr :

(.venv)[Zephyr-lab]$ ls  -a  zephyr-project/
.  ..  .west  zephyr

(.venv)[Zephyr-lab]$ ls  -a  zephyr-project/.west/
.  ..  config

(.venv)[Zephyr-lab]$ ls  -a  zephyr-project/zephyr/
.                   doc                Kconfig.zephyr   share
..                  drivers            kernel           snippets
arch                dts                lib              soc
boards              .editorconfig      LICENSE          submanifests
.checkpatch.conf    .git               .mailmap         subsys
.clang-format       .gitattributes     MAINTAINERS.yml  tests
cmake               .github            misc             VERSION
CMakeLists.txt      .gitignore         modules          version.h.in
.codecov.yml        .gitlint           README.rst       west.yml
CODE_OF_CONDUCT.md  include            samples          .yamllint
CODEOWNERS          Kconfig            scripts          zephyr-env.cmd
CONTRIBUTING.rst    Kconfig.constants  SDK_VERSION      zephyr-env.sh
(.venv)[Zephyr-lab]$ 

Comme la commande west init nous y invitait, nous allons exécuter west update pour mettre à jour tous les modules nécessaires (cela rappelle un peu la commande git submodule update).

(.venv)[Zephyr-lab]$ cd  zephyr-project/

(.venv)[zephyr-project]$ west  update
=== updating acpica (modules/lib/acpica):
--- acpica: initializing
Initialized empty Git repository in /home/Builds/Lab/Zephyr-lab/zephyr-project/modules/lib/acpica/.git/
  [...]
 * [new tag]         inital-pr         -> inital-pr
 * [new tag]         old-structure     -> old-structure
HEAD is now at 75d0880 tests: Update mps2 board name
HEAD is now at 75d0880 tests: Update mps2 board name
(.venv)[zephyr-project]$ 
[...]
Successfully installed Deprecated-1.2.14 MarkupSafe-2.1.5 Pillow-10.4.0 PyGithub-2.3.0 anytree-2.12.1 appdirs-1.4.4 arrow-1.2.3 astroid-3.2.4 bz-1.0 canopen-2.3.0 capstone-4.0.2 cbor-1.0.0 cbor2-5.6.4 certifi-2024.7.4 cffi-1.17.0 charset-normalizer-3.3.2 clang-format-18.1.8 click-8.1.3 cmsis-pack-manager-0.5.3 colorlog-6.8.2 coverage-7.6.1 cryptography-43.0.0 dill-0.3.8 exceptiongroup-1.2.2 gcovr-7.2 gitlint-0.19.1 gitlint-core-0.19.1 graphviz-0.20.3 grpcio-1.65.4 grpcio-tools-1.65.4 idna-3.7 imgtool-2.1.0 importlib-metadata-8.2.0 importlib-resources-6.4.0 iniconfig-2.0.0 intelhex-2.3.0 intervaltree-3.1.0 isort-5.13.2 jinja2-3.1.4 junit2html-31.0.2 junitparser-3.1.2 lark-1.1.9 libusb-package-1.0.26.2 lpc_checksum-3.0.0 lxml-5.2.2 mccabe-0.7.0 mock-5.1.0 msgpack-1.0.8 mypy-1.11.1 mypy-extensions-1.0.0 natsort-8.4.0 pathspec-0.12.1 platformdirs-4.2.2 pluggy-1.5.0 ply-3.11 prettytable-3.10.2 progress-1.6 protobuf-5.27.3 psutil-6.0.0 pycparser-2.22 pyelftools-0.31 pygments-2.18.0 pyjwt-2.9.0 pylink-square-1.2.1 pylint-3.2.6 pynacl-1.5.0 pyocd-0.36.0 pyserial-3.5 pytest-8.3.2 python-can-4.4.2 python-magic-0.4.27 pyusb-1.2.1 regex-2024.7.24 requests-2.32.3 sh-1.14.3 sortedcontainers-2.4.0 tabulate-0.9.0 tomli-2.0.1 tomlkit-0.13.0 typing-extensions-4.12.2 urllib3-2.2.2 wcwidth-0.2.13 wrapt-1.16.0 yamllint-1.35.1 zcbor-0.8.1 zipp-3.19.2

Nous terminons la préparation du répertoire en installant les modules Python supplémentaires réclamés par Zephyr :

(.venv)[zephyr-project]$ pip  install  -r  zephyr/scripts/requirements.txt
  [...]

Compilation pour Raspberry Pi Pico

Le dossier du kernel Zephyr que nous avons installé plus haut contient un sous-répertoire samples/ avec plusieurs exemples des possibilités de l’OS.

(.venv)[zephyr-project]$ cd  zephyr/

(.venv)[zephyr]$ ls  samples/
application_development  fuel_gauge    sample_definition_and_criteria.rst
arch                     hello_world   sensor
basic                    index.rst     shields
bluetooth                kernel        subsys
boards                   modules       synchronization
classic.rst              net           sysbuild
cpp                      philosophers  tfm_integration
drivers                  posix         userspace

Nous allons nous intéresser aux plus simples des exemples, dans le sous-répertoire basic/ :


(.venv)[zephyr]$ ls  samples/basic/
basic.rst  blinky_pwm  custom_dts_binding  hash_map  rgb_led      sys_heap
blinky     button      fade_led            minimal   servo_motor  threads

L’équivalent pour les systèmes embarqués du classique « Hello World » s’appelle blinky, c’est le clignotement d’une led.

Nous pouvons demander à west de compiler cet exemple en lui précisant via son option -b le nom du microcontrôleur concerné rpi_pico. Pour connaître la liste des cartes connues par Zephyr, voir le lien ci-dessous.


(.venv)[zephyr]$ west  build  -b rpi_pico  samples/basic/blinky
-- west build: generating a build system
Loading Zephyr default modules (Zephyr base).
-- Application: /home/Builds/Lab/Zephyr-lab/zephyr-project/zephyr/samples/basic/blinky
 [...]
[2/2] Linking ASM executable boot_stage2
[134/134] Linking C executable zephyr/zephyr.elf
Memory region         Used Size  Region Size  %age Used
      BOOT_FLASH:         256 B        256 B    100.00%
           FLASH:       15432 B    2096896 B      0.74%
             RAM:        3968 B       264 KB      1.47%
        IDT_LIST:          0 GB        32 KB      0.00%
Generating files from /home/Builds/Lab/Zephyr-lab/zephyr-project/zephyr/build/zephyr/zephyr.elf for board: rpi_pico
Converted to uf2, output size: 31744, start address: 0x10000000
Wrote 31744 bytes to zephyr.uf2
(.venv)[zephyr]$ 

En sortie du build, un message nous annonce la création d’un fichier .uf2.

Le format UF2 (pour “USB Flashing Format” ), développé par Microsoft est prévu pour flasher des microcontrôleurs en utilisant l’interface “mass storage” .

Le Raspberry Pi Pico possède une telle interface, il suffit de le connecter au PC avec un câble de connexion USB/micro-USB en maintenant son bouton “Bootsel” pressé pendant le banchement. Sur le PC une interface est détectée au bout de cinq secondes environ, semblable à une clé USB habituelle. C’est probablement la méthode la plus simple pour flasher un microcontrôleur (nous en verrons d’autres dans les prochains articles).

Cinq secondes après avoir raccordé mon Raspberry Pico à mon PC de développement, je le vois apparaître dans mon arborescence :

(.venv) [zephyr]$ lsblk
NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
  [...]
sdd           8:48   1   128M  0 disk 
└─sdd1        8:49   1   128M  0 part /media/cpb/RPI-RP2
  [...]

(.venv)[zephyr]$ ls  /media/cpb/RPI-RP2/
INDEX.HTM  INFO_UF2.TXT

Les fichiers présents sur le Pico sont des documentations nous indiquant que c’est bien l’emplacement où nous devons copier le fichier .uf2 . Il faut à présent trouver ce fichier dans l’arborescence de Zephyr :

(.venv)[zephyr]$ find  .  -name '*.uf2'
./build/zephyr/zephyr.uf2

Tout logiquement, le fichier se trouve dans le sous-dossier build/.

Je copie le fichier, et dès que la copie est terminée, le microcontrôleur se réinitialise et commence à exécuter le code.

(.venv)[zephyr]$ cp  build/zephyr/zephyr.uf2  /media/cpb/RPI-RP2/

(.venv)[zephyr]$ 

Interface série

Nous étudierons dans le prochain article la structure d’un répertoire pour une application. Voyons juste le fichier samples/basic/blinky/src/main.c :

/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>

/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS   1000

/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)

/*
 * A build error on this line means your board is unsupported.
 * See the sample documentation for information on how to fix this.
 */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

int main(void)
{
        int ret;
        bool led_state = true;

        if (!gpio_is_ready_dt(&led)) {
                return 0;
        }

        ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
        if (ret < 0) {
                return 0;
        }

        while (1) {
                ret = gpio_pin_toggle_dt(&led);
                if (ret < 0) {
                        return 0;
                }

                led_state = !led_state;
                printf("LED state: %s\n", led_state ? "ON" : "OFF");
                k_msleep(SLEEP_TIME_MS);
        }
        return 0;
}

Outre le clignotement de la LED, nous pouvons apercevoir, dans la boucle principale une ligne « printf("LED state..."); » qui indique que ce programme affiche un message sur sa sortie standard.

Suivant l’état d’un paramètre de configuration, Zephyr redirige la sortie standard vers l’interface série principale du microcontrôleur (la plupart des microcontrôleurs ont plusieurs interfaces séries). Pour le Raspberry Pi Pico, cette interface est lUART0 dont les connecteurs sont TX sur la broche 1, et RX sur la broche 2. En outre nous avons une masse GND sur la broche 3, nous pouvons donc utiliser un petit adaptateur USB-Série comme pour le port série du Raspberry Pi classique.

Attention toutefois, sur les Raspberry Pi habituel (1B, 2B, 3B, 3B+, 4, 5, etc.) l’ordre des broches est GNDTXRX alors qu’avec le Pico c’est GNDRXTX.

Une fois la connexion physique établie, je lance sur mon PC le terminal série minicom (dont la sortie est facile à capturer dans le cadre de cet article), mais il est possible d’utiliser de nombreuses variantes putty, tio, picocom, gtkterm, cutecom, etc.

(.venv)[zephyr]$ minicom

Welcome to minicom 2.8

OPTIONS: I18n 
Port /dev/ttyUSB0, 07:46:09

Press CTRL-A Z for help on special keys

Après avoir branché l’alimentation du Raspberry Pico, j’observe sur la sortie :

*** Booting Zephyr OS build v3.7.0-711-gd590c1867284 ***
LED state: OFF
LED state: ON
LED state: OFF
LED state: ON
LED state: OFF
LED state: ON
LED state: OFF
LED state: ON
LED state: OFF
LED state: ON
LED state: OFF
LED state: ON
LED state: OFF
LED state: ON
LED state: OFF
LED state: ON
LED state: OFF

Sources

Conclusion

Nous voyons que l’installation et l’utilisation de Zephyr sur un microcontrôleur est assez simple, l’outil west offre une interface simple pour configurer, compiler et installer le code sur la cible. Nous n’avons pas utilisé west pour installer le code ci-dessus sur le Raspberry Pico car ce dernier offre une méthode beaucoup plus simple, mais nous l’utiliserons dans un article à venir.

Nous avons compilé un exemple tout fait, sans modifier quoique ce soit. Nous verrons dans le prochain article comment développer notre propre code et le compiler avec Zephyr.

Si vous préférez assister à une session de formation sur « Zephyr OS » en mode présentiel ou distanciel, ou disposer d’une assistance technique personnalisée pour vos développement n’hésitez pas à me contacter.

2 Réponses

  1. Seb dit :

    Je pense qu’il y a une petite coquille apreès l’install du sdk.
    ls -l ~/.cmake/packages/
    c’est plutôt
    ls -l ~/.cmake/packages/Zephyr-sdk/

URL de trackback pour cette page