Restart repo
This commit is contained in:
307
esp32/qemu_emulation.rst
Normal file
307
esp32/qemu_emulation.rst
Normal 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é.
|
||||
Reference in New Issue
Block a user