Xtensa-Assembler oder aBelle schreiben, mit F9 aufs Board bringen und Schritt für Schritt debuggen – ohne Debug-Probe, ohne OpenOCD, ohne ESP-IDF.
Der ESP32-S3 von Espressif hat zwei Xtensa-LX7-Kerne (240 MHz) und einen USB-Anschluss, der zugleich serieller Port und JTAG-Debugger ist. Asmonite assembliert seinen Code (.target esp32s3) und übersetzt Programme in aBelle für ihn (target "esp32s3"). Alles, was der ursprüngliche ESP32 in Asmonite hat, gibt es auch hier: die Konsole mit Dateien im Flash, F9 und das Debuggen über die Konsole ohne Reset, das Menü Board und das WLAN als Dienst der Konsole, mit WPA2, DHCP, DNS, Ping und TCP.
Getestet mit einem Board mit zwei USB-C-Anschlüssen und einer RGB-LED WS2812 an GPIO 48 (ein Anschluss geht an den Chip, der andere über einen CH343 an UART0). Andere Boards, deren USB-Anschluss direkt zum Chip geht (GPIO 19 und 20), sollten genauso gehen. Die ausführliche Anleitung steht im Quelltext-Repository unter docs/de/esp32s3.md.
| Assembler | Xtensa mit Registerfenstern, Literal-Pool und den 16-Bit-Befehlen; .target esp32s3 für das RAM, .target esp32s3 flash für den Flash. |
| aBelle | target "esp32s3", derselbe Compiler abelle_esp32.exe wie für den ESP32; der Debugger zeigt den Quelltext. |
| F9 | Über die Konsole ins RAM und gestartet: ohne Download-Modus, ohne Reset. Die Ausgabe im Reiter Serial, Stop beendet das Programm. |
| Debugger | Über den USB-JTAG des Chips: Breakpoints, Einzelschritte, Pause, Register, Speicher; mit der Konsole ohne Reset. |
| Konsole | Ein Dateisystem im Flash (gut 14 MB bei 16 MB Flash), das Menü Board, Programme als Befehle. |
| WLAN | Ein Dienst der Konsole auf Kern 1: wlan set, offene Netze und WPA2, DHCP, DNS, Ping, UDP, TCP; die WLAN-Beispiele des ESP32. |
examples\abelle\esp32s3\hello_usb.abel öffnen und F9 drücken: „Hello, world!“ und ein Zähler im Reiter Serial. Stop beendet es. Mit einem Breakpoint (F5) startet F9 den Debugger.Eine Firmware mit eigenem USB. Erscheint das Board nicht als „USB JTAG/serial debug unit“, sondern als anderes Espressif-Gerät (seine Firmware benutzt den USB-Anschluss selbst, zum Beispiel ein Arduino-Sketch mit USB-CDC oder MicroPython), dann einmal BOOT halten, RST drücken und BOOT loslassen: Der Chip wartet dann in seinem Boot-ROM und zeigt seinen USB-JTAG. Asmonite sagt das, wenn es so ein Board findet. Sobald die Konsole von Asmonite im Flash steht, ist das nicht mehr nötig.
Updates von selbst. Vor F9 und vor dem Debuggen vergleicht Asmonite die Konsole im Flash mit seiner eigenen. Stammt sie von einer anderen Version von Asmonite, schreibt es seine eigene (etwa 2 Sekunden), danach ein anderes WLAN-Paket. Die Dateien und das Netz des Boards bleiben.
Mit der Konsole. Mit einem Breakpoint, F7 oder F8 startet der Debugger ohne Reset: Asmonite verbindet sich mit dem USB-JTAG, wie er ist, die Konsole ruft ihren Gastgeber dbg_host auf wie ein Programm, und der Kern hält dort an; der Debugger lädt das Programm über JTAG und startet es von dort. Nach dem Ende des Programms (auch mit exit() oder einer Ausnahme, die die Konsole fängt) oder nach Stop ist die Konsole wieder da; die nächste Sitzung beginnt nach einer halben Sekunde.
Ohne Konsole und für ein Programm für den Flash setzt der Debugger den Chip über den USB-Seriell-Port in den Download-Modus seines Boot-ROMs zurück (mit den Leitungen DTR und RTS, wie esptool), hält Kern 0 dort an, lädt das Programm nach 0x40378000 und lässt es laufen oder hält bei _start. So beginnt jede Sitzung mit demselben sauberen Chip: der Kern mit 40 MHz, die Watchdogs aus, die Peripherie wie nach einem Reset.
Dann: Schritte (F7, F8), Breakpoints (F5), die Register a0 .. a15, pc, ps, sar, windowbase, windowstart und die Schleifenregister, der Speicher (auch als Code). Der Stackpointer a1 beginnt bei 0x3FCAFFE0. Beginnt _start mit entry, kommt das Programm wie aus der Konsole (callx8, mit Registerfenster), und retw beendet die Sitzung mit seinem a2; ohne entry kommt es wie bei call0, und ret beendet sie.
rgb.abel an einem Breakpoint im Farbkreis: rechts round und h, die Register des RMT und seines RAM; unten im Reiter Output, wie Asmonite vorher die ältere Konsole des Boards selbst ersetzt hat.
.target esp32s3 ; or: .target esp32s3 flash .arch xtensa .imagebase 0x40378000 _start: ...
.target esp32s3 | Das Programm im RAM ab 0x40378000: Der Assembler nimmt es bis 0x403BFFFF (288 KB) an, darüber liegt die Konsole. Das normale Fenster, das aBelle nutzt und mit dem auch das WLAN läuft: Code bis 0x4038FFFF (96 KB), Daten 0x3FCA0000 .. 0x3FCAFFFF. |
.target esp32s3 flash | F9 oder F7 schreiben das Programm über den seriellen Port des Chips in den Flash an die Adresse 0, als Image des Boot-ROMs; danach debuggt es der Debugger im RAM. Nach RST startet das Boot-ROM es von selbst. Das ersetzt, was vorher im Flash war, auch die Konsole. |
Ein Programm, das das Boot-ROM aus dem Flash startet, muss die Watchdogs selbst abschalten (Timergruppe 0 und 1, den RTC-Watchdog und den Super-Watchdog) und den Takt setzen, wenn es Zeit misst: Aus dem Flash lässt das Boot-ROM den Kern auf 20 MHz. examples\esp32s3\rgb_ws2812_flash.asm zeigt beides mit ein paar Zeilen bei _start.
Die serielle Ausgabe. Der USB-Anschluss des Chips hat zwei Teile: den JTAG des Debuggers und einen seriellen Port (im Geräte-Manager „USB Serial Device“). Was ein Programm in das Peripheral USB Serial/JTAG schreibt (0x60038000), kommt an diesem COM-Port heraus, auch während der Debugger den JTAG hat; der Reiter Serial zeigt es. Die Baudrate spielt keine Rolle. In aBelle schreibt inc/usb.abel Text und Zahlen dorthin.
Bytes im RAM. Das RAM des Programms ist ein Speicher an zwei Bussen. Unter seiner IRAM-Adresse (0x40378000 ..) liest und schreibt der Kern nur Wörter; am Datenbus liegt dasselbe Byte 0x6F0000 tiefer (0x3FC88000 für 0x40378000), und dort gehen Bytes.
Ein Programm in aBelle mit target "esp32s3" übersetzt abelle_esp32.exe in den Code für das RAM ab 0x40378000 (bis 96 KB) und die Daten ab 0x3FCA0000 (bis 60 KB, dasselbe RAM über den Datenbus; darüber der Stack und das WLAN). F9 startet es und debuggt es im Quelltext: Breakpoints, F7/F8 Zeile für Zeile, Variablen unter der Maus und im Fenster Watch. Funktionen des Boot-ROMs werden wie beim ESP32 mit at und ihrer Adresse bekannt gemacht; sie liegen beim S3 woanders (ets_delay_us bei 0x40000600, beim ESP32 bei 0x40008534).
Die RGB-LED: rgb.abel. Das Beispiel lässt die RGB-LED des Boards (eine WS2812 an GPIO 48) rot, grün und blau leuchten und einmal durch den Farbkreis, drei Runden, dann geht sie aus und das Programm kehrt zur Konsole zurück. Eine WS2812 braucht Impulse von 0,35 und 0,7 µs; die erzeugt der RMT des Chips, der die 40 MHz des Quarzes zählt, also unabhängig vom Takt des Kerns. Die Register stehen mit ihren Quellen im Kopf der Datei.
Ein großes Programm ohne WLAN. Braucht ein aBelle-Programm mehr als 96 KB Code oder 60 KB Daten, nimmt abelle_esp32 das große Fenster (Code bis 156 KB, Daten bis 128 KB) und sagt das bei der Übersetzung („it runs without the WiFi“). Die Konsole hält das WLAN dann vorher an und startet es danach im Hintergrund wieder.
examples\esp32s3\console.asm ist die Konsole des ESP32 für den S3: dieselben Befehle (ls, cat, put, rm, df, format, run, load, boot, wlan, help), dasselbe Dateisystem im Flash ab 2 MB bis zu seinem Ende und dieselben Pakete für Asmonite. Sie spricht über den USB-Anschluss des Chips: jedes Terminalprogramm am COM-Port des Chips.
Das Menü Board arbeitet mit dem S3 wie mit dem ESP32 (Asmonite nimmt den S3, wenn kein Board mit USB-Seriell-Chip angeschlossen ist):
| Board > Prepare Board | Schreibt die Konsole über das Boot-ROM in den Flash (an die Adresse 0) und legt das Dateisystem an, wenn es noch keins gibt. |
| Board > Files | Das Fenster ESP32-S3 Board Files: Upload File, Download, Delete, Upload This Program, Run, Autostart, Reset Board und Format. Upload This Program nimmt ein Programm mit .target esp32s3 oder target "esp32s3" und weist eines für den ESP32 ab. |
| Board > Set This Program as Autostart | Lädt das Programm im Editor auf das Board und startet es nach jedem Reset. |
| Board > Advanced | Write to Flash and Run (das Programm ersetzt die Konsole; Asmonite fragt vorher), Erase Flash, Install WiFi Again (das WLAN-Paket neu, selten nötig). |
Wenn ein Programm endet, ist die Konsole wieder da, wie beim ESP32: retw (Meldung Program ended (code n)), exit(code) mit callx8 auf 0x403C0800, eine Ausnahme oder ein break (Program stopped: …) oder Ctrl+C: der Knopf Stop im Reiter Serial, auch bei gesperrten Interrupts. Ein Programm aus der Konsole darf das ganze RAM der Programme nutzen: Code 0x40378000 .. 0x403BFFFF, Daten über den Datenbus 0x3FC88000 .. 0x3FCCFFFF; mit dem WLAN gehört der obere Teil davon dem WLAN.
Funktionen der Konsole für Programme wie beim ESP32, ab 0x403C0800: exit, version, put_char, get_char, poll_char, print, millis, file_size, file_read, file_write, flash_read, args, je 4 Bytes (die Tabelle steht auf der Seite zum ESP32). Auch Programme als Befehle wie dort: name args startet name oder name.bin aus den Dateien. In aBelle: include "inc/console.abel", Beispiel runs.abel.
Nach einem Reset wartet die Konsole vor einem Autostart 3 Sekunden (beim ESP32 eine): Mit dem Reset geht der USB-Anschluss kurz weg und kommt wieder, erst dann kann ein Terminal eine Taste schicken. Ein Reset über RTS (wie Reset Board) setzt nur den Chip zurück, der USB-Anschluss bleibt: Ein Terminal darf offen bleiben.
Das WLAN des S3 kommt aus den Bibliotheken von Espressif, mit einer eigenen Betriebssystem-Schicht in Assembler statt FreeRTOS, wie beim ESP32. Ein Dienst läuft auf Kern 1, während ein Programm oder die Konsole auf Kern 0 läuft; der Debugger hält nur Kern 0 an, das WLAN läuft weiter.
wlan set im Reiter Serial, dann Name und Passwort (offen oder WPA2, 2,4 GHz), wie beim ESP32. Die Konsole speichert den Namen und den Schlüssel, nicht das Passwort (etwa 2,3 Sekunden). Mit einem gespeicherten Netz verbindet sie sich bei jedem Start im Hintergrund.examples\abelle\esp32s3\ntp.abel öffnen und F9 drücken. Fehlt das WLAN-Paket auf dem Board oder passt es nicht, schreibt Asmonite es vorher über die Konsole (rund 300 KB, etwa 8 Sekunden). Das Programm verbindet sich mit wifi_connect_saved(), endet mit wifi_done() und kehrt zur Konsole zurück; die Server laufen bis Stop.Die Beispiele sind die des ESP32: scan, dhcp, ping, dns, ntp, httpget, webserver, udpecho, wol, arpscan und telnetd (die Dateien des Boards über die MMU des S3, led schaltet die RGB-LED). Ihren Text schreiben sie über den USB-Anschluss des Chips (inc/usb.abel statt inc/uart.abel); net.abel und tcp.abel sind die des ESP32. Während die Konsole den Flash benutzt, parkt sie Kern 1: Dateien lassen sich bei laufendem WLAN schreiben, eine Verbindung bleibt bestehen. Für WPA2 entpackt der Dienst den Gruppenschlüssel selbst (AES Key Unwrap nach RFC 3394): Das ROM des S3 hat dafür keine Funktion, anders als das des ESP32.
httpget.abel holte example.com über die Verbindung der Konsole, im Reiter Serial das Ende seiner Ausgabe.
Code- und Datenbus sind dasselbe RAM, 0x6F0000 auseinander.
| Bereich | Was dort liegt |
|---|---|
Flash 0x000000 | die Konsole (oder das Programm von Write to Flash and Run) |
Flash 0x0FE000, 0x0FF000 | das Netz des Boards (wlan set): Name und Schlüssel |
Flash 0x100000 .. 0x1FFFFF | das WLAN-Paket: die Bibliothek, bei 0x1F0000 ein Kopf, dahinter die Teile von wlan.rom für das RAM und wlansvc |
| Flash ab 2 MB .. Ende | das Dateisystem der Konsole |
0x40378000 .. 0x4038FFFF | Code des Programms (im großen Fenster bis 0x4039EFFF, dann ohne WLAN) |
0x3FCA0000 .. 0x3FCAFFFF | Daten des Programms, der Stack in den oberen 4 KB |
0x403A0000 .., Daten ab 0x3FCB6000 | der Dienst wlansvc |
0x403A8000 .., 0x3FCBC000 .. | wlan.rom |
0x3FCC1000 .. 0x3FCCFFFF | Heap des WLAN |
0x403C0000 .., Daten ab 0x3FCD8000 | die Konsole (ihre Funktionen ab 0x403C0800) |
0x3FCDF000 .. 0x3FCE7FFF | Puffer des WLAN, Stack von Kern 1 |
| Meldung oder Anzeichen | Was zu tun ist |
|---|---|
| „an Espressif chip is plugged in, but its firmware uses the USB port itself“ | BOOT halten, RST drücken, BOOT loslassen; dann noch einmal F9 |
| „No ESP32-S3 with its USB JTAG (303A:1001) is plugged in“ | Den anderen USB-Anschluss des Boards nehmen (den am Chip), oder Debug targets > ESP32-S3 > Set up the USB JTAG |
| „COM13 is open in another program“ | Das Terminal schließen, dann noch einmal F9 |
| Die Farben des RGB-Beispiels in Assembler stimmen nicht oder sind weiß | Die Zeiten der WS2812 sind dort in Takten gerechnet: Das Programm muss mit 40 MHz laufen (rgb.abel nimmt den RMT und hängt nicht vom Takt ab) |
| Das Board startet alle paar Sekunden neu | Ein Programm im Flash, das die Watchdogs nicht abschaltet; F9 mit einem Programm, das es tut |
ee.*) des ESP32-S3, Programme im externen Flash oder PSRAM (nur das interne RAM), Bluetooth.Die Beispiele für den ESP32-S3 in Assembler und aBelle, mit der RGB-LED und dem WLAN.
Der ursprüngliche ESP32: die Konsole, ihre Funktionen, das WLAN und seine Funktionen im Einzelnen.
Jeder Xtensa-Befehl mit Bitkodierung und Pseudocode, für den ESP32 und den ESP32-S3.