307 lines
9.4 KiB
ReStructuredText
307 lines
9.4 KiB
ReStructuredText
..
|
|
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é. |