Restart repo

This commit is contained in:
2023-12-30 22:30:42 +01:00
commit 1c4278a3d8
37 changed files with 3019 additions and 0 deletions

24
esp32/index.rst Normal file
View File

@@ -0,0 +1,24 @@
..
Copyright (C) 2023 Jeremie Salvi.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
Programmation d'un ESP32
========================
Ici je vais poser toutes mes astuces pour la programmation et le débugage d'un ESP32,
ainsi qu'une présentation de mes projets. Je tiens à noter que je suis passé sous
ArchLinux, l'installation et la configuration va donc légèrement changer par rapport à Debian.
.. toctree::
:maxdepth: 2
installation.rst
vscodium_integration.rst
qemu_emulation.rst
qemu_ethernet.rst

163
esp32/installation.rst Normal file
View File

@@ -0,0 +1,163 @@
..
Copyright (C) 2023 Jeremie Salvi.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
Installation de l'environnement sous ArchLinux
==============================================
Introduction
------------
Tout d'abord je tiens à vous rassurer, cela doit fonctionner sur la majorité des distributions.
Je vais utiliser vscodium (fork de visual studio code sans la télémétrie microsoft),
un framework basé sur electron, donc compatible multi OS et multi distributions.
L'emulateur basé sur QEMU sera compilé à la main, donc ça devrait passer sur n'importe quel linux 😊.
.. warning:: Je suis passé en root pour ne pas m'encombrer avec ``sudo``, pensez y si nécessaire
Pour plus d'infos en général, allez faire un tour sur `La documentation officielle de l'esp 32 <https://docs.espressif.com/projects/esp-idf/en/latest/esp32/>`_
Installation de vscodium
------------------------
Vscodium n'est pas disponible dans les paquets officiels ArchLinux, il faut donc aller sur les ArchLinux User Repositories (AUR.)
`Dépot AUR des binaires vscodium <https://aur.archlinux.org/packages/vscodium-bin>`_
.. code-block:: bash
:linenos:
:caption: installation de vscodium
cd /opt
git clone https://aur.archlinux.org/vscodium-bin.git
cd vscodium-bin/
makepkg
pacman -U vscodium-bin-1.72.2.22289-1-x86_64.pkg.tar.zst
.. warning:: Si vous êtes en root pour programmer, il faut utiliser les arguments suivants pour
lancer vscodium : ``codium --no-sandbox --user-data-dir ~/.config/vscodium``
Pour le confort de développement, nous allons installer une extension pour améliorer
l'autocompletion en C/C++. Elle n'est pas disponible sur le marketplace vscodium, il faut l'installer
manuellement. On la télécharge `ici <https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools>`_.
On l'installe depuis le menu des extensions comme ci dessous.
.. image:: ../images/esp32/ms_cpp_extension.png
:width: 400
Nous allons aussi utiliser l'extension native debug pour l'intégration du debugeur.
Elle se trouve dans le store. Pour l'utilistation, on verra ça dans la partie
`création d'un environnement vscodium </esp32/vscode_integration.html#configurer-le-debugeur>`_.
.. image:: ../images/esp32/native_debug_extension.png
:width: 400
Installation des prérequis pour l'esp-idf (Espressif IoT Development Framework)
-------------------------------------------------------------------------------
La commande est directement fournie dans la documentation, il suffit de la copier coller :
.. code-block:: bash
pacman -S --needed gcc git make flex bison gperf python cmake ninja dfu-util ccache libusb
Installation et configuration de l'esp-idf
------------------------------------------
Dans un premier temps, on récupère les dépots :
.. code-block:: bash
:linenos:
mkdir -p /opt/esp
cd /opt/esp
git clone --recursive https://github.com/espressif/esp-idf.git
Il faut ensuite installer les outils. Par defaut ils sont installés dans ``$HOME/.espressif``.
On peut changer cet emplacement grâce à la variable d'environnement ``IDF_TOOLS_PATH``.
.. code-block:: bash
:linenos:
export IDF_TOOLS_PATH=/opt/esp/esp-idf/.espressif
cd esp-idf
./install.sh esp32
L'environnement utilise un paquets d'outils, il est dur de mémoriser tout
les chemins et les variables d'environnement. Heureusement on nous fournit aussi un sctipt
qui rend tout ça accessible depuis la console. Pour ça il faut le charger :
.. code-block:: bash
. /opt/esp/esp-idf/export.sh
Comme il faut l'appeller dans chaque nouveau terminal, on
se créer un alias pour faciliter l'accès :
.. code-block:: bash
alias esp_idf_import=". /opt/esp/esp-idf/export.sh"
On colle cette ligne dans notre .bashrc ou notre .profile. Pour vérifier qu'on
a bien tout importé, on tappe la commande env, et on devrait avoir les infos
suivantes :
.. code-block:: bash
:linenos:
env
>> ESP_IDF_VERSION="5.1"
>> ESP_ROM_ELF_DIR="/opt/esp/esp-idf/.espressif/tools/esp-rom-elfs/20220823/"
>> IDF_DEACTIVATE_FILE_PATH="/tmp/tmpxj9n6nndidf_46523"
>> IDF_PATH="/opt/esp/esp-idf"
>> IDF_PYTHON_ENV_PATH="/opt/esp/esp-idf/.espressif/python_env/idf5.1_py3.10_env"
>> IDF_TOOLS_EXPORT_CMD="/opt/esp/esp-idf/export.sh"
>> IDF_TOOLS_INSTALL_CMD="/opt/esp/esp-idf/install.sh"
>> IDF_TOOLS_PATH="/opt/esp/esp-idf/.espressif"
>> OPENOCD_SCRIPTS="/opt/esp/esp-idf/.espressif/tools/openocd-esp32/v0.11.0-esp32-20221026/openocd-esp32/share/openocd/scripts"
>> PATH="/opt/esp/esp-idf/components/esptool_py/esptool:/opt/esp/esp-idf/components/espcoredump:/opt/esp/esp-idf/components/partition_table:/opt/esp/esp-idf/components/app_update:/opt/esp/esp-idf/.espressif/tools/xtensa-esp-elf-gdb/12.1_20221002/xtensa-esp-elf-gdb/bin:/opt/esp/esp-idf/.espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin:/opt/esp/esp-idf/.espressif/tools/esp32ulp-elf/2.35_20220830/esp32ulp-elf/bin:/opt/esp/esp-idf/.espressif/tools/openocd-esp32/v0.11.0-esp32-20221026/openocd-esp32/bin:/opt/esp/esp-idf/.espressif/python_env/idf5.1_py3.10_env/bin:/opt/esp/esp-idf/tools:/usr/local/sbin:/usr/local/bin:/usr/bin"
Si l'on à pas les chemins ``/opt/esp/esp-idf`` dans le path et les variables d'environnement ``IDF_``, les outils fournis
dans l'ESP-IDF ne fonctionneront tout simplement pas.
Compilation de qemu-system-xtensa patché pour les esp32
-------------------------------------------------------
Espressif, l'entreprise qui concoit les ESP32, nous fournit un fork de QEMU modifié pour emmuler celui ci.
On le trouve à l'addresse suivante : `GitHub du fork QEMU <https://github.com/espressif/qemu>`_.
Toute la procédure est expliquée ici : `Wiki du dépot <https://github.com/espressif/qemu>`_.
Je ne vais pas tout réexpliquer ici, ce qu'il faut savoir c'est que nous ne voulons pas
recompiler tout qemu, juste le binaire qemu-system-xtensa modifié pour esp32. Je vais donc
refaire la compilation en désactivant un maximum de fonctionnalités inutiles. On trouve la
liste des fonctionnalités dans le fichier ``configure`` du dépot.
.. code-block:: bash
:linenos:
:caption: compilation de QEMU pour esp32
#!/bin/bash
cd /opt
git clone https://github.com/espressif/qemu.git
cd qemu
./configure --target-list=xtensa-softmmu \
--enable-gcrypt \
--enable-debug --enable-sanitizers \
--disable-strip --disable-user \
--disable-capstone --disable-vnc \
--disable-sdl --disable-gtk \
--disable-opengl --disable-vfio-user-server
ninja -C build

307
esp32/qemu_emulation.rst Normal file
View File

@@ -0,0 +1,307 @@
..
Copyright (C) 2023 Jeremie Salvi.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
Premiers tests et emulation QEMU
================================
Espressif fournit une version de QEMU modifiée pour tester du code. Cela peut avoir
plusieurs avantages :
* Commencer à coder sans attendre la livraison de notre ESP.
* Tester du code plus rapidement sans avoir à flasher notre ESP.
* Coder toute la partie web en local sur notre machine.
* Attacher un debugeur, utiliser des berakpoints, et débuger plus facilement.
Pour cela, nous reprendront le `code de la partie précédente </esp32/vscodium_integration.html#configuration-de-l-extension-c-c>`_.
Première Execution
------------------
On reprend le projet vu dans l'intégration vscodium. Pout lancer QEMU il nous faut construire la mémonire
flash pour la donner à QEMU qu'elle puisse démarrer dessus.
.. code-block:: bash
python /opt/esp/esp-idf/components/esptool_py/esptool/esptool.py \
--chip esp32 merge_bin --output flash_img.bin \
--fill-flash-size 4MB --flash_mode dio --flash_size keep --flash_freq 40m \
0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/new_project.bin
Voilà, il ne nous reste plus qu'à lancer QEMU à partir de cette image !
Emulation du système dans une machine QEMU
------------------------------------------
Il suffit maintenant de lancer notre machine QEMU à partir de la flash que l'on vient de créer :
.. code-block:: bash
/opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
-drive file=flash_img.bin,if=mtd,format=raw
Et voilà, on emule la machine et on à la sortie série qui s'affiche. Pour quitter QEMU, on utilise
``Ctrl-A x``
Flasher ou monitorer en emulant un port série
---------------------------------------------
Cela ne va pas beaucoup nous servir, puisqu'il suffit de relancer qemu avec notre nouvelle
image du flash, mais il faut savoir que c'est possible en emulant les GPIO de notre ESP.
on à deux configurations :
* ``-global driver=esp32.gpio,property=strap_mode,value=0x12`` pour monitorer la sortie.
* ``-global driver=esp32.gpio,property=strap_mode,value=0xf`` pour flasher la carte.
Attention, le port série ne peut pas recevoir deux connexions en même temps, il faut donc
couper le moniteur pour flasher et vice versa.
Monitorer QEMU
~~~~~~~~~~~~~~
On commence par lancer QEMU avec le port série en mode monitor.
.. code-block:: bash
/opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
-drive file=flash_img.bin,if=mtd,format=raw \
-global driver=esp32.gpio,property=strap_mode,value=0x12 \
-serial tcp::5555,server,nowait
On lance ensuite le moniteur
.. code-block:: bash
idf.py --port socket://localhost:5555 monitor
Flasher QEMU
~~~~~~~~~~~~
On commence par lancer QEMU avec le port série en mode flash.
.. code-block:: bash
/opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
-drive file=flash_img.bin,if=mtd,format=raw \
-global driver=esp32.gpio,property=strap_mode,value=0xf \
-serial tcp::5555,server,nowait \
On flash ensuite notre machine
.. code-block:: bash
idf.py --port socket://localhost:5555 flash
Debuger grâce de QEMU avec gdb
------------------------------
Pour attacher GDB, on lance la commande avec ``-s -S`` qui va nous ouvrir un socket tcp sur le port 1234.
pour changer de port, on utilise : ``-gdb tcp::1235``
.. code-block:: bash
/opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
-drive file=flash_img.bin,if=mtd,format=raw \
-gdb tcp:localhost:1235 -S
On peut ensuite lancer le debugeur fourni avec l'API, mettre des breakpoints, etc.
.. code-block:: bash
:linenos:
/root/.espressif/tools/xtensa-esp-elf-gdb/12.1_20221002/xtensa-esp-elf-gdb/bin/xtensa-esp32-elf-gdb build/main.elf
(gdb) b app_main
# >> Breakpoint 1 at 0x400d5170: file /root/test/sample_project/main/main.c, line 7.
(gdb) target remote :1235
# >> Remote debugging using :1235
# >> 0x40000400 in ?? ()
(gdb) c
# Continuing.
# Thread 1 hit Breakpoint 1, app_main () at /root/test/sample_project/main/main.c:7
(gdb) n
# >> 8 int count = 0;
(gdb) n
# >> 11 ESP_LOGI("FIRST TRY", "Test loop pass n° %d", count++);
(gdb) b
# >> Breakpoint 2 at 0x400d5175: file /root/test/sample_project/main/main.c, line 11.
(gdb) c
# >> Continuing.
# >> Thread 1 hit Breakpoint 2, app_main () at /root/test/sample_project/main/main.c:11
# >> 11 ESP_LOGI("FIRST TRY", "Test loop pass n° %d", count++);
(gdb) c
# >> Continuing.
# >> Thread 1 hit Breakpoint 2, app_main () at /root/test/sample_project/main/main.c:11
# >> 11 ESP_LOGI("FIRST TRY", "Test loop pass n° %d", count++);
(gdb) print count
# >> $1 = 2
(gdb) set count=100
(gdb) c
# >> Continuing.
# >> Thread 1 hit Breakpoint 2, app_main () at /root/test/sample_project/main/main.c:11
# >> 11 ESP_LOGI("FIRST TRY", "Test loop pass n° %d", count++);
(gdb) quit
.. image:: ../images/esp32/QEMU_gdb_example.png
:width: 400
Voilà. On va voir plus tard comment configurer cela dans vscodium
Intégration dans vscodium
-------------------------
On arrive ici à ce qui pour moi donne une vraie utilité à configurer un environnement QEMU.
On va pouvoir à partir de vscode gérer nos breakpoint, naviguer dans le code, avoir sous
les yeux les variables et les call stack, etc.
Création des tâches
~~~~~~~~~~~~~~~~~~~
Je ne réexplique pas tout, on à déjà vu le fonctionnement dans la
`partie précédente </esp32/vscodium_integration.html#configurer-des-taches>`_
On rajoute quelques fonctions suivantes à notre script et on ajoute les tâches pour
lancer le débug et l'execution avec QEMU.
.. code-block:: bash
:linenos:
function kill_qemu {
for i in $(ps -elf | grep 'qemu-system-xtensa' | awk '{print $4}')
do
echo "found process $i"
kill $i
done
}
function qemu_execute {
kill_qemu
python /opt/esp/esp-idf/components/esptool_py/esptool/esptool.py \
--chip esp32 merge_bin --output flash_img.bin \
--fill-flash-size 4MB --flash_mode dio --flash_size keep --flash_freq 40m \
0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin \
0x10000 build/new_project.bin
/opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
-drive file=flash_img.bin,if=mtd,format=raw
exit 0
}
function qemu_debug {
kill_qemu
python /opt/esp/esp-idf/components/esptool_py/esptool/esptool.py \
--chip esp32 merge_bin --output flash_img.bin \
--fill-flash-size 4MB --flash_mode dio --flash_size keep --flash_freq 40m \
0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin \
0x10000 build/new_project.bin
/opt/qemu/build/qemu-system-xtensa -nographic -machine esp32 \
-drive file=flash_img.bin,if=mtd,format=raw -s -S
exit 0
}
#######################
# Main
#######################
case $1 in
kill_idf)
echo "Killing all idf process"
kill_idf
;;
kill_qemu)
echo "Killing all idf process"
kill_qemu
;;
qemu_execute)
echo "Execute with QEMU"
qemu_execute
;;
qemu_debug)
echo "Debug with QEMU"
qemu_debug
;;
*)
echo "Missing args"
exit 1
;;
esac
.. code-block:: json
:linenos:
{
"label": "Execute with QEMU",
"type": "shell",
"command": "${workspaceFolder}/.scripts/tasks.sh",
"args": [
"qemu_execute"
],
"presentation": {
"reveal": "always",
"panel": "new",
"close": true
},
"problemMatcher": []
},
{
"label": "Debug with QEMU",
"type": "shell",
"command": "${workspaceFolder}/.scripts/tasks.sh",
"args": [
"qemu_debug"
],
"presentation": {
"reveal": "always",
"panel": "new",
"close": true
},
"problemMatcher": []
},
Intégration de gdb dans vscodium
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pour cela, il faut éditer le fichier ``.vscode/launch.json``
.. code-block:: json
:linenos:
{
"configurations": [
{
"type": "gdb",
"gdbpath": "/root/.espressif/tools/xtensa-esp-elf-gdb/12.1_20221002/xtensa-esp-elf-gdb/bin/xtensa-esp32-elf-gdb",
"postDebugTask": "kill QEMU process",
"request": "attach",
"name": "Attach to QEMU",
"executable": "${workspaceFolder}/build/main.elf",
"target": ":1234",
"remote": true,
"cwd": "${workspaceRoot}",
"valuesFormatting": "parseText"
}
]
}
Voilà, on n'a plus qu'à lancer la tâche ``Debug with QEMU`` et de lancer le débugeur.
.. image:: ../images/esp32/debug.png
:width: 600
On se retrouve avec les breakpoints, les call stacks, les variables et la sortie tous affichés sans notre
environnement de travail 💪.
Prochaine étape
---------------
Les interactions avec l'électronique devant être faites avec un vrai ESP, le développement
sous QEMU ne nous sert à rien si on ne peut pas coder la partie réseau et communications depuis le PC.
Prochaine étape donc, faire tourner l'emulation avec une interface réseau pour coder notre serveur web
embarqué.

203
esp32/qemu_ethernet.rst Normal file
View File

@@ -0,0 +1,203 @@
..
Copyright (C) 2023 Jeremie Salvi.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
Interface ethernet avec QEMU
============================
Y a pas à dire, j'ai bien galéré pour cette partie 😅. Bon, faut dire q'il y avait des choses qui
ne fonctionnent pas. J'y refient à la fin de cette section.
Après pas mal de tatonnements entre la doc et les exemples fournis par espressif, j'ai finalement
réussi à interagir entre firefox et la machine QEMU. Il y a plusieures choses à bien comprendre
dans la façon dont fonctionne l'IDF, notament comment sont gérées les
`différentes couches du modèle OSI <https://fr.wikipedia.org/wiki/Mod%C3%A8le_OSI>`_.
Principes
---------
dans l'ESP, il y à trois étapes principales pour le réseau :
#. La partie physique (couches physique + mac),
#. La partie network (couches network + transport),
#. La partie link entre physique et network.
La partie physique
~~~~~~~~~~~~~~~~~~
C'est la couche physique plus la couche mac. On la configure, on la démare, et ensuite on
la link à la partie network. Côté wifi, comme le driver de la carte est toujours le même,
on à la fonction ``esp_netif_create_default_wifi_sta()`` qui gère tout, elle créer tout.
Elle gère la partie physique, la link à la partie network, et nous retourne un handle de la
partie network.
Pour l'ethernet, c'est différent, comme plusieurs extensions ethernet sont disponible pour
l'esp32, il y a plusieurs drivers disponibles, il nous faut donc choisir le bon, et configurer ça à la main.
Dans notre cas, pour QEMU, le driver à utiliser est le driver openeth. (`cf wiki qemu <https://github.com/espressif/qemu/wiki>`_)
La configuration de la partie physique se fait à l'aide des fonctions suivantes :
.. code-block:: cpp
:linenos:
// Pysical layer configuration
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = -1;
phy_config.reset_gpio_num = -1;
phy_config.autonego_timeout_ms = 4000;
s_phy = esp_eth_phy_new_dp83848(&phy_config);
// Data link layer configuration
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.rx_task_stack_size = 4096;
mac_config.rx_task_prio = 20;
s_mac = esp_eth_mac_new_openeth(&mac_config);
// Install Ethernet driver
esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
esp_eth_driver_install(&config, &esp_eth_handle);
La partie network
~~~~~~~~~~~~~~~~~
Can cette partie, on gère la couche ip et la couche transport (TCP/UDP/ICMP). Espressif nous donne pour ça tout un tas
de fonctions, qui sont un wrapper des librairies opensource `lwIP <https://fr.wikipedia.org/wiki/LwIP>`_ (lightweight IP).
Elle nous permet d'initialiser ces couches, de gérer l'attribution de l'adressage ip (statique ou DHCP.)
Cette couche s'implémente avec les fonctions suivantes :
.. code-block:: cpp
:linenos:
// Initialize TCP/IP layers
esp_netif_init();
esp_event_loop_create_default();
esp_netif_config_t esp_netif_config = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&esp_netif_config);
// Set static ip
// esp_netif_dhcpc_stop(eth_netif);
// esp_netif_ip_info_t esp_netif_ip_info;
// esp_netif_ip_info.ip.addr = ESP_IP4TOUINT32(11,2,168,192);
// esp_netif_ip_info.netmask.addr = ESP_IP4TOUINT32(0,255,255,255);
// esp_netif_ip_info.gw.addr = ESP_IP4TOUINT32(1,2,168,192);
// esp_err_t ret2 = esp_netif_set_ip_info(eth_netif, &esp_netif_ip_info);
// ESP_ERROR_CHECK(ret2);
Lien entre les deux premières couches
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
On peut configurer les deux parties précédentes dans l'ordre de notre choix, mais c'est seulement une fois que
ces deux étapes sont réalisées qu'on peut attacher la couche TCP/IP à la couche physique/MAC.
Assez simple à faire, il suffit d'utiliser le code suivant :
.. code-block:: cpp
:linenos:
// Bind TCP/IP to Phy+MAC
esp_eth_netif_glue_handle = esp_eth_new_netif_glue(esp_eth_handle);
esp_netif_attach(eth_netif, esp_eth_netif_glue_handle);
On peut ensuite démarrer ethernet avec la fonction suivante :
.. code-block:: cpp
:linenos:
// Start ethernet
esp_eth_start(esp_eth_handle);
La partie applicative
~~~~~~~~~~~~~~~~~~~~~
Ici, on aura l'implémentation de notre serveur web. Ça se fait à partir de la librairie ``esp_http_server``
Rien de bien complexe ici quand on connait bien le fonctionnement de ce protocole.
Le code est le suivant :
.. code-block:: cpp
:linenos:
esp_err_t get_handler(httpd_req_t *req)
{
/* Send a simple response */
const char resp[] = "URI GET Response\n";
httpd_resp_send(req, resp, HTTPD_RESP_USE_STRLEN);
ESP_LOGI(TAG, "good");
return ESP_OK;
}
httpd_uri_t uri_get = {
.uri = "/uri",
.method = HTTP_GET,
.handler = get_handler,
.user_ctx = NULL
};
Une fois ces trois étapes franchies, on peut démarrer QEMU avec la commande suivante :
.. code-block:: bash
:linenos:
/opt/qemu/build/qemu-system-xtensa -m 128 -nographic -machine esp32 \
-drive file=flash_img.bin,if=mtd,format=raw \
-net nic,model=open_eth \
-net user,host=192.168.2.1,net=192.168.2.0/24,hostfwd=tcp::80-:80 \
-net tap,script=no,downscript=no
On teste avec un simple ``curl http://127.0.0.1/uri`` et on voit que ça marche.
.. image:: ../images/esp32/QEMU_http_response.png
:width: 600
Ce qui ne marche pas
--------------------
L'IPv6
~~~~~~
Ne marche pas ni en wifi avec SLAAC, en wifi avec une ip statique,
ni avec QEMU. C'est ce qui m'a le plus fait perdre de temps.
En m'acharnant, je suis tombé sur ça 😤 🤬:
.. code-block:: bash
:linenos:
esp_err_t esp_netif_add_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr, uint8_t preference)
{
return ESP_ERR_NOT_SUPPORTED;
}
Il manque clairement du travail du côté d'espressif pour implémenter la couche IPv6. C'est embêtant, ça nous
oblige à faire pleins de routes dans notre box, alors qu'on pourrait tout simplement pinger notre domotique de
l'extérieur avec du v6
.. note:: Il n'y a que la librairie loobback.c qui manque d'implémentation, dans
components/lwip/lwip/src/core/netif.c on trouve
``netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx)``
qui est bel et bien implémentée. J'ai perdu du temps dessus, ça sera un NAT v4 pour l'instant.
Si à l'avenir j'arrive à faire marcher l'IPv6, je le documenterai.
L'interface tun0 et le bridging
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
auand je lance ma commande QEMU, j'ai deux moyens d'accéder à mon ``http_server`` :
Soit via le ``hostfwd=tcp::80-:80``, soit via ``-net tap,script=no,downscript=no``.
Je fait un ``ip link set tap0 up et brctl addif br0 tap0`` pour que mon tap0 soit
pingable depuis le bridge en 192.168.2.15.
Et bien, un ``curl http://127.0.0.1/uri`` marche très bien, un ``curl http://192.168.2.15/uri``
ne parche pas, on à une erreur ``W (476492) opencores.emac: emac_opencores_isr_handler: RX frame dropped (0x14)``
J'ai essayé de mettre au max les buffers RX, testé toutes les configurations possible et imaginables,
impossible de passer par le bridge sans avoir un frame_drop. Grace au mod débug, j'arrive ici :
``components/esp_eth_src/esp_eth_mac_openeth.c``
.. image:: ../images/esp32/openeth_busy.png
:width: 600

View File

@@ -0,0 +1,313 @@
..
Copyright (C) 2023 Jeremie Salvi.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
Création d'un environnement vscodium
====================================
Le but ici va être d'automatiser un maximum d'actions, comme par exemple la compilation, le débug,
tout en les intégrant dans vscodium. Nous allons aussi configurer l'autocomplétion, la navigation
dans les fonctions et les librairies, et tout ce qui peut rendre notre IDE plus ergonomique.
Je vais essayer de maintenir cette section à jour au fur et à mesure que j'améliore
le projet.
.. warning:: pensez à importer les variables d'environnement avec esp_idf_import
comme vu dans l'installation si nécessaire.
Créer un nouveau project
------------------------
On commence par créer un projet a l'aide le l'utilitaire IDF :
.. code-block:: bash
idf.py create-project new_project
On peut ensuite ouvrir vscodium et ouvrir ce dossier ``Ctrl+O`` ou ``File -> Open Folder``.
Déclarer le $PATH et les variables d'environnement pour le terminal
-------------------------------------------------------------------
Si on lance notre terminal vscode et qu'on fait un ``export``, on ne retrouve pas les variables
d'environnement nécessaires à bon fonctionnement des outils IDF. Pour cela, il faut les renseigner
dans notre espace de travail.
Pour cela, on fait ``F1`` et on cherche settings.json.
.. image:: ../images/esp32/settings.json.png
:width: 600
Il va nous ouvrir le fichier ``.vscode/settings.json`` qui va contenir nos paramètres
propre au projet. Dans celui ci, on va renseigner toutes les variables d'environnement
qu'on à après un ``esp_idf_import`` comme vu dans la partie
`installation </esp32/installation.html#installation-et-configuration-de-l-esp-idf>`_.
On ajoute les lignes suivantes :
.. code-block:: json
:linenos:
{
"C_Cpp.intelliSenseEngine": "Tag Parser",
"terminal.integrated.cwd": "/root/test/new_project",
// environnement variables needeed by ESP_IDF
"terminal.integrated.env.linux": {
"ESP_IDF_VERSION": "5.1",
"ESP_ROM_ELF_DIR": "/opt/esp/esp-idf/.espressif/tools/esp-rom-elfs/20220823/",
"IDF_DEACTIVATE_FILE_PATH": "/tmp/tmpxj9n6nndidf_46523",
"IDF_PATH": "/opt/esp/esp-idf",
"IDF_PYTHON_ENV_PATH": "/opt/esp/esp-idf/.espressif/python_env/idf5.1_py3.10_env",
"IDF_TOOLS_EXPORT_CMD": "/opt/esp/esp-idf/export.sh",
"IDF_TOOLS_INSTALL_CMD": "/opt/esp/esp-idf/install.sh",
"IDF_TOOLS_PATH": "/opt/esp/esp-idf/.espressif",
"OPENOCD_SCRIPTS": "/opt/esp/esp-idf/.espressif/tools/openocd-esp32/v0.11.0-esp32-20221026/openocd-esp32/share/openocd/scripts",
"PATH": "/opt/esp/esp-idf/components/esptool_py/esptool:/opt/esp/esp-idf/components/espcoredump:/opt/esp/esp-idf/components/partition_table:/opt/esp/esp-idf/components/app_update:/opt/esp/esp-idf/.espressif/tools/xtensa-esp-elf-gdb/12.1_20221002/xtensa-esp-elf-gdb/bin:/opt/esp/esp-idf/.espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin:/opt/esp/esp-idf/.espressif/tools/esp32ulp-elf/2.35_20220830/esp32ulp-elf/bin:/opt/esp/esp-idf/.espressif/tools/openocd-esp32/v0.11.0-esp32-20221026/openocd-esp32/bin:/opt/esp/esp-idf/.espressif/python_env/idf5.1_py3.10_env/bin:/opt/esp/esp-idf/tools:/usr/local/sbin:/usr/local/bin:/usr/bin"
},
}
Configuration de l'extension C/C++
----------------------------------
Commencons par un simple code pour vérifier que tout fonctionne :
.. code-block:: c
:linenos:
#include <stdio.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
void app_main(void)
{
int count=0;
while (true)
{
ESP_LOGI("NEW PROJECT", "my first test %d", count++);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
On teste notre code avec les commandes suivantes :
.. code-block:: bash
:linenos:
idf.py set-target esp32
idf.py build
idf.py flash
idf.py monitor
Pour quitter le moniteur, il suffit d'un ``Ctrl+]``.
Ok, une fois que tout marche, on peut quitter le terminal.
On voit que vscodium affiche des erreurs au niveau des include qu'il ne trouve pas. Réglons tout ça.
En appuyant sur ``F1`` et en cherchant ``C/C++ configuration`` on trouve soit l'interface utilisateur soit un
racourci pour créer et renseigner le fichier ``.vscode/c_cpp_properties.json``.
Pour que la recherche intelligente foncrionne, il faut configurer l'extension pour qu'elle
sache ou chercher les librairies fournies par l'IDE. Des templates sont déjà disponibles
sur `le github d'espressif <https://github.com/espressif/vscode-esp-idf-extension/tree/master/templates/.vscode>`_.
.. image:: ../images/esp32/c_cpp_config.png
:width: 600
En m'inspirant de ce qu'esperssif fournit pour son extension vscodium,
voilà à quoi je suis arrivé pour que tout fonctionne bien :
.. code-block:: json
:linenos:
{
"configurations": [
{
"name": "ESP_IDF",
"includePath": [
"${workspaceFolder}/**",
"/opt/esp/esp-idf/components/**",
"/opt/esp/esp-idf/.espressif/tools/**"
],
"defines": [],
"compilerPath": "",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "linux-gcc-x64",
"browse": {
"path": [
"${workspaceFolder}/**",
"/opt/esp/esp-idf/components/**",
"/opt/esp/esp-idf/.espressif/tools/**"
],
"limitSymbolsToIncludedHeaders": false
}
}
],
"version": 4
}
Voilà, ça c'est pour que vscode et intellisense trouvent toutes les ressources dont ils ont besoin.
Configurer des tâches
---------------------
C'est ici, à mon sens, la fonctionnalié qui donne le plus de confort et qui va nous faire gagner un temps précieux.
Dans vscodium, on peut définir des tâches personnalisées pour le projet en cours, et les executer rapidement avec un raccourci clavier.
Dans un premier temps, je créer un script dans ``.scripts/tasks.sh`` que je rend executable, et dans lequel je vais coder toutes les actions
que je vais répéter souvent, comme builder le code, flasher l'esp, lancer QEMU pour débuger, etc. Voici le code, il est améliorable bien
entendu et on va y rajouter toutes les fonctionnalités que nous voudrons par la suite.
.. code-block:: bash
:linenos:
#!/bin/bash
function kill_idf {
for i in $(ps -elf | grep 'idf.py' | awk '{print $4}')
do
echo "found process $i"
kill $i
done
}
function build {
$IDF_PATH/tools/idf.py build
}
function flash {
kill_idf
$IDF_PATH/tools/idf.py flash
exit 0
}
function monitor {
kill_idf
$IDF_PATH/tools/idf.py monitor
exit 0
}
#######################
# Main
#######################
case $1 in
kill_idf)
echo "Killing all idf process"
kill_idf
;;
build)
echo "Building project"
build
;;
flash)
echo "Flashing memory"
flash
;;
monitor)
echo "Monitoring output"
monitor
;;
*)
echo "Missing args"
exit 1
;;
esac
Voilà, une fois ce script fait, on va y assigner des tâches vscodium. Je vais aller vite sur les explications, je
vous met un lien vers `la documentation officielle du fichier tasks.json <https://code.visualstudio.com/docs/editor/tasks>`_.
On créer un fichier ``.vscode/tasks.json`` et on y renseigne le code suivant :
.. code-block:: json
:linenos:
{
"version": "2.0.0",
"tasks": [
{
"label": "kill idf.py process",
"type": "shell",
"command": "${workspaceFolder}/.scripts/tasks.sh",
"args": [
"kill_idf"
],
"presentation": {
"reveal": "always",
"panel": "shared",
"close": false
},
"problemMatcher": []
},
{
"label": "build project",
"type": "shell",
"command": "${workspaceFolder}/.scripts/tasks.sh",
"args": [
"build"
],
"presentation": {
"reveal": "always",
"panel": "shared",
"close": false
},
"problemMatcher": []
},
{
"label": "flash esp memory",
"type": "shell",
"command": "${workspaceFolder}/.scripts/tasks.sh",
"args": [
"flash"
],
"presentation": {
"reveal": "always",
"panel": "shared",
"close": false
},
"problemMatcher": []
},
{
"label": "monitor",
"type": "shell",
"command": "${workspaceFolder}/.scripts/tasks.sh",
"args": [
"monitor"
],
"presentation": {
"reveal": "always",
"panel": "new",
"close": true
},
"problemMatcher": []
},
{
"label": "build, flash, and monitor",
"dependsOrder": "sequence",
"dependsOn": ["build project", "flash esp memory", "monitor"],
"problemMatcher": []
},
]
}
Et voilà, comme vous pouvez le voir, vous avez toutes les tâches de compilation, execution, et debug imtégrées à
vscodium. on peut y accéder en tappant ``F1 -> run task``, et pour gagner du temps, on peut même définir un raccourci clavier
Pour gagner encore une étape.
.. image:: ../images/esp32/run_tasks.png
:width: 600
Et voilà, un appui sur ``Ctrl+F1`` me donne accès à autant de tâches que je voidrai en créer.
.. image:: ../images/esp32/tasks.png
:width: 600