Rust auf Pi Pico
Aufgabenstellung
Bei diesem Thema untersuchen Sie wie schnell der ARM Cortex M0 auf dem Raspberry Pi Pico arbeitet. Dazu wird der Ausgang an einem GPIO geändert und die Änderung wird mit dem Oszilloskop gemessen. Dazu kommt dann die Messung der Ausführungszeit einer Primzahlensuche auf dem RP2040 und der Vergleich mit einer Ausführung auf dem Hostsystem. Der Code ist in Rust geschrieben.
Vorbereitung
Toolchain
Die Toolchain ist die gleiche wie im von Claudia Meitinger.
- auf ihrem Rechner
- Installieren Sie oder Microsoft Codium
- In Codium:
FĂĽr Rust noch
rustup target add thumbv6m-none-eabi cargo install elf2uf2-rs
Projekt
Im ist ein git Repository, das die zwei Projekte
- blinky - FĂĽr den Pi Pico
- prime - FĂĽr den Hostrechner
enthält. Sie können das Repository auf ihrem Rechner mit
git clone https://caeis.etech.fh-augsburg.de/beckmanf/picofirst.git
installieren.
blinky
Das Rustprojekt Blinky enthält ein kleines Programm mit dem auf dem Pi Pico Board ohne Wifi die Onboard LED ein- und ausgeschaltet wird. Wechseln Sie in das Verzeichnis “picofirst/blinky”. Sie können das Programm mit
cargo run
kompilieren und auf den Raspberry Pi Pico laden. Das funktioniert nur wenn der Pi Pico im Mass Storage Mode ist. Dazu muss der “BOOTSEL” Taster auf dem Board gedrückt und gehalten werden während man das USB Kabel mit dem Rechner verbindet. Man kann sehen, dass der Pi Pico im Mass Storage Mode ist, wenn ein neues Laufwerk im Betriebssystem angezeigt wird. Mit “cargo run” wird das Programm kompiliert, auf den Pi Pico geladen. Damit wird der Mass Storage Mode verlassen und der Code ausgeführt.
Auf dem Pi Pico sollte jetzt die LED blinken.
Die blinkende LED dient zur ĂśberprĂĽfung, dass die Toolchain und der Pi Pico richtig funktioniert. Auf dem Pi Pico W mit Wifi ist die LED nicht direkt am RP2040 Prozessor angeschlossen, sondern am Wifichip CYW43439. Um dort die LED anzusteuern muss der Wifichip in Betrieb genommen werden. Das habe ich deshalb hier nicht gemacht.
prime
Das Projekt “prime” enthält ein Programm zur Suche nach Primzahlen. Das Programm soll nicht auf dem Pi Pico, sondern auf dem Host - also ihrem Rechner oder dem Laborrechner - ausgeführt werden. Wechseln Sie in das Verzeichnis “picofirst/prime”. Sie können das Programm direkt mit
cargo run
starten. Das Programm in sucht die nächstkleinere Primzahl ausgehend von einer Zahl, die im Programm festgelegt ist. Die Zahl n ist im Code im Repository auf “1«56” = 2^56 = 72057594037927936 festgelegt. Sie sollten auf dem Terminal eine ähnliche Ausgabe wie diese sehen:
Mac:prime fritz$ cargo run Compiling prime v0.1.0 (/Users/fritz/pico/picofirst/prime) Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s Running `target/debug/prime` What is the next prime number smaller than 72057594037927936? Found: 72057594037927931. This took 2.328603083s. Mac:prime fritz$
Das Programm dient dazu eine Berechnung durchzuführen, die etwas länger dauert. Starten Sie das Programm einige Male und notieren Sie die Ausführungszeiten. In “blinky” ist diese Primzahlensuchfunktion auch schon integriert, aber noch nicht aktiv.
Kompilieren Sie das Programm jetzt im “Release” Modus. Damit wird der Rustcompiler eine höhere Codeoptimierung durchführen.
cargo run --release
Sie können das Programm nach dem Kompilieren auch direkt starten mit
./target/release/prime
./target/debug/prime
Vergleichen Sie die AusfĂĽhrungszeiten.
- Schätzen Sie anhand des Rustcodes für die Primzahlensuche ab, wie sich die Ausführungszeit mit der Zahl n verhält. Es geht nicht um die absolute Zeit, sondern ob der Zusammenhang zwischen Ausführungszeit und Zahl konstant, linear oder sonstwie ist.
Aufgaben
Messung der maximal möglichen Frequenz an Pin GP15
In diesem Versuch soll jetzt nicht mehr die LED wechseln, sondern der Pin GP15 in Abbildung 1 links unten.
Dazu muss der Code in geändert werden.
- Kommentieren Sie die delays in der loop aus. In der loop soll nur der Pin aus- und eingeschaltet werden.
- Ändern Sie den Pin von GP25 für die LED auf GP15 für den Pin links unten.
- Messen Sie mit dem Oszilloskop die Frequenz und das an/aus Verhältnis des Signals am Pin 15.
- Testen Sie “cargo run” und “cargo run –release”
Analyse des Assemblercodes
Man kann sich mit
cargo rustc --release -- --emit asm
den Assemblercode generieren lassen. Der Assemblercode ist im Verzeichnis target/thumbv6m-none-eabi/release/deps und fängt mit dem Projektnamen “blinky” and und endet mit der Endung “.s”. Ein Pfad kann z.B. so aussehen: “target/thumbv6m-none-eabi/release/deps/blinky-cbc27bc4200d17af.s”.
Öffnen Sie die Datei mit Codium. Die Datei enthält sehr viel Code… Finden Sie die Schleife. Fügen Sie dazu die delay Funktionen nochmal in den Code ein und kompilieren Sie nochmal. Dann sollten Sie etwas ähnliches wie das hier:
ldr r6, .LCPI2_8 .LBB2_6: ldr r0, .LCPI2_5 str r4, [r0] add r5, sp, #8 mov r0, r5 mov r1, r6 bl _ZN8cortex_m5delay5Delay8delay_us17hb904cf74fb062a91E ldr r0, .LCPI2_5 str r4, [r0, #4] mov r0, r5 mov r1, r6 bl _ZN8cortex_m5delay5Delay8delay_us17hb904cf74fb062a91E b .LBB2_6 .LBB2_7: strb r5, [r0]
finden. Sie sehen die “cortex_m5delay” Funktionen. Das sind die Aufrufe für die delay Funktion. Nehmen Sie dann die Delayaufrufe wieder aus dem Code. Die Loop sollte jetzt kürzer sein. Erläutern Sie den Code, der den Pin 15 an- und ausschaltet.
Vergleich RP2040 Datenblatt
Im finden Sie im Kapitel 2.3.1.7 die Register
- SIO: GPIO_OUT_SET
- SIO: GPIO_OUT_CLR
mit denen der Pegel an einem Pin eingestellt werden kann. Wenn man beispielsweise 1«3 = 0x00000008 in das Register GPIO_OUT_SET schreibt, dann wird der Ausgangspegel von GP03 auf High gesetzt. Damit das funktioniert muss vorher die Konfiguration des Pins gemacht werden - also beispielsweise, dass das ein Ausgang ist.
- Erläutern Sie im Code wie auf die beiden Register geschrieben wird.
AusfĂĽhrung Primzahlensuche
Die Primzahlensuche dauert im Vergleich zu dem Ein- und Ausschalten der Pins relativ lang. Jetzt geht es darum die AusfĂĽhrungszeiten auf dem Pi Pico mit den AusfĂĽhrungszeiten auf dem Hostrechner zu vergleichen. Dazu sollen die AusfĂĽhrungszeiten auf dem Pi Pico mit dem Oszilloskop gemessen werden.
- FĂĽgen Sie die Primzahlensuchfunktion in die Loop ein.
- Aktivieren Sie das Delay nach dem Ausschalten der LED/Pins.
- Die Zeitdauer wie lange das Signal am Pin auf High ist, soll durch die Laufzeit der Primzahlensuche bestimmt sein. Die Zeitdauer wie lange das Signal auf low ist, soll konstant durch die Delayfunktion bestimmt sein.
- Verändern Sie die Werte für die Zahl n, messen Sie die Highphasen am Oszilloskop und notieren Sie die Zeiten
- Erstellen Sie einen Graphen, der die AusfĂĽhrungszeit gegen die Zahl n darstellt.
- Vergleichen Sie den Graphen mit den Überlegungen aus Vorbereitung für “prime”
- Vergleichen Sie die AusfĂĽhrungszeit auf dem Pi Pico mit der AusfĂĽhrungszeit auf dem Host.
Direkter Registerzugriff
Um die Pins ein- und auszuschalten haben wir im Code die Funktionen wie “led_pin.set_low().unwrap()” aus dem “Hardware-Abstraction-Layer” HAL verwendet. Jetzt soll direkt auf die Register geschrieben werden. Das kann mit der Funktion “write_volatile(REG, 1«25)” gemacht werden. Die Funktion muss als “unsafe” markiert werden. Kommentieren Sie den Code für die Definition des REG Wertes und das “write_volatile” aus und ersetzten so den “led_pin.set_low()” Code.
- Ersetzten Sie led_pin.set_low() durch einen direkten Registerzugriff
- PrĂĽfen Sie ob der Code noch funktioniert
- Schreiben Sie nun Code, der gleichzeitig GP15 und GP25 in der Loop ändert.
- Schreiben Sie eine Variante mit direktem Registerzugriff und eine Variante mit HAL.
- Gibt es einen Unterschied in der AusfĂĽhrungszeit?