Raspberry Pi Pico W Benchmark

In diesem Beitrag geht es um die Raspberry Pi Pico W Benchmark, wo die neue WiFi Geschwindigkeit und generelle Rechenleistung mit anderen MicroController Boards verglichen wird.

Kaum zu glauben, aber der Raspberry Pi Pico W, wieder im Folgenden einfach Pico W, ist schon released. Eigentlich wollte ich vorab noch einen Benchmark machen, aber wie es manchmal so ist, kommen dann doch unerwartet andere Themen auf. Dennoch will ich heute einmal mit kleinen Programmen zeigen, wie gut der Pico W im Vergleich zu dem D1 Mini und ESP32 Node MCU abschneidet. An der Stelle sollte aber klar sein, dass nicht auf alle Aspekte eingegangen wird, sondern erst einmal auf die pure Leistung.

Das brauchst du für die Pi Pico W Benchmark

Um das hier gezeigte nachzubauen, brauchst du folgende Komponenten

Aufgrund der hohen Nachfrage einiger Bauteile, gibt es dieses Mal keinen vorgefertigten Warenkorb. Gerade der Pico W und das Display sind aktuell schwer erhältlich, ich bitte hier um Verständnis.

Zu Erinnerung der Pico W

Der Pico W, siehe Abbildung 1, ist der neue MicroController der Raspberry Pi Fundation. Mit den gleichen Maßen wie der Pico, 51,3mm(L) x 21mm(B) X 3,9mm(H), kann dieser perfekt in bestehende Projekte eingebunden oder der alte sogar ausgetauscht werden. Das W steht an dieser Stelle für Wireless, womit klar ist, dass die Wünsche der Maker erhört wurden. Zwar ist Bluetooth, Stand 07.2022, noch nicht freigeschaltet in der Firmware, aber mit dem WLAN kann man schon einige großartige Projekte umsetzen.

Abbildung 1: Der Raspberry Pi Pico W

Die Verkabelung

Bei der Verkabelung nutzen ich für alle Codes den gleichen Aufbau. Diesen kannst du aus Tabelle 1 entnehmen.

FunktionPico WD1 MiniESP32 NodeMCU
3,3V3,3V3,3V3,3V
GroundGNDGNDGND
SCL2D2D22
SDA1D1D21
Tabelle 1: Verkabelung Display mit Controller

Da ich persönlich ein Fan von Zeichnungen bin, gebe ich natürlich auch noch die Verkabelung als Bild mit für den Pico W, siehe Abbildung 2.

Abbildung 2: Verdrahtung vom Pico W mit OLED-Display

Bei dem ESP32 NodeMCU sieht die Verkabelung wie in Abbildung 3 aus.

Abbildung 3: Verdrahtung vom ESP32 NodeMCU mit OLED-Display

Zuletzt noch der D1 Mini mit dem OLED-Display, siehe Abbildung 4.

Abbildung 4: Verdrahtung vom D1 Mini mit OLED-Display

Die benötigten Bibliotheken

Damit alles nachher funktioniert, musst du in der Paketverwaltung, siehe Abbildung 5, aufrufen.

Abbildung 5: Paketverwaltung in Thonny aufrufen

Suche im Folgendem Dialog nach „OLED“, wähle “micropython-oled“ aus und installiere es anschließend, siehe Abbildung 6.

Abbildung 6: Bibliothek OLED suchen

Beim D1 Mini musst du am Ende noch im Ordner lib -> oled die Datei __ini__.py öffnen und dort die Zeile from .lazy import * mit einem # auskommentieren, siehe Abbildung 7.

Abbildung 7: Anpassung für D1 Mini vornehmen

Machst du diese Änderung nicht, wird beim Kompilieren der Beispielprogramme eine Meldung erscheinen, dass das Programm zu groß zum für den D1 Mini ist.  Mit diesem einfachen Trick umgehst du dieser Meldung, da wir diesen Teil der OLED-Lib nicht brauchen.

Test 1 die Verbindung mit dem WiFi

Was ich zuerst unbedingt ausprobieren musste war, wie schnell sich der Pico W im Vergleich zu den anderen MicroControllern mit meinem Router verbindet. I. Der Code dazu kannst du Code 1 entnehmen.

import network
import time
import machine
from oled import SSD1306_I2C,gfx,Write
from oled.fonts import ubuntu_mono_12, ubuntu_mono_15

bPrintDiag = False 
ssid = ‘YOUR-WLAN-ID‘
password = 'WIFI-PASSWORD'

I2C_PORT = 0
I2C_SDA = machine.Pin(0) #Pin on ESP32: 21(D21) D1Mini: 4(D1) Pico W: 0(Pin 1)
I2C_SCL = machine.Pin(1) #Pin on ESP32: 22(D22) D1Mini: 5(D2) Pico W: 1(Pin 2)
#i2c = machine.I2C(I2C_PORT,sda=I2C_SDA, scl=I2C_SCL) # For ESP32 only
i2c = machine.I2C(sda=I2C_SDA, scl=I2C_SCL) # For Pico W and D1 Mini

#Definitions and init for OLED-Display
WIDTH = 128
HIGHT = 64
oled = SSD1306_I2C(WIDTH, HIGHT, i2c)
font = Write(oled,ubuntu_mono_12)
Y_Shift = 13

#Function to connect with the wifi
def connect():
    #Connect to WLAN
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)
    print('Waiting for network . . .')
    while wlan.isconnected() == False:
       print() 
    print(' DONE')
    print(wlan.ifconfig())


try:
    oled.fill(0)
    if bPrintDiag:
        i2cScan = i2c.scan()
        counter = 0
        print('-----------------')
        print('Found I2C-Devices')
        for i in i2cScan:
            print("I2C Address " + f'{counter:03d}' + " : "+hex(i).upper())
            counter+=1
    xPos = 10
    yPos = 1
    font.text('---Start system---', xPos, yPos)
    yPos += Y_Shift
    font.text('Start: ' + str(start_time) + 'ms', xPos, yPos)
    yPos += Y_Shift
    font.text('Try to connect', xPos, yPos)
    oled.show()
    start_time = time.ticks_ms()
    connect()
    yPos += Y_Shift
    font.text('Connected to WiFi', xPos, yPos)
    end_time = time.ticks_ms()
    execution_time = round(end_time - start_time,4)
    yPos += Y_Shift
    font.text('Needed time: ' + str(execution_time) + 'ms', xPos, yPos)
    oled.show()
    print('Time to connect:' + str(execution_time))
except KeyboardInterrupt:
    machine.reset()

Code 1: Auswertung bis WLAN verbunden

Der Code für diesen Test ist recht schlank und überschaubar. Zunächst werden die benötigten Bibliotheken geladen und das OLED-Display wird initialisiert. Ist das erledigt, werden die ersten drei Zeilen auf dem Display ausgegeben und im Anschluss die Verbindung zum Netzwerk durchgeführt. Um messen zu können wie lange es dies gedauert hat, wird vor dem Aufruf der Funktion „connect()“ die aktuelle MicroController-Zeit genommen und nach dem Durchlauf noch einmal. Die Zeitspanne zwischen diesen beiden Zeiten wird gerundet und in den nächsten Zeilen vom OLED-Display ausgegeben.

Das Programm zeigt im Terminal noch mehr Informationen an, dies war aber für mich nur rein interessehalber, um mich mit der Bibliothek „network“ auseinanderzusetzen.

Wenn alles funktioniert hat, sollte das OLED wie in Abbildung 8 aussehen.

Abbildung 8: Ausgabe OLED

Diesen Code habe ich dann auf allen MicroControllern fünf Mal laufen lassen und dann ein Mittelwert der Zeiten gebildet, siehe Tabelle 2.

PosPico WESP32 NodeMCUD1 Mini
Connection Time [ms]
1105628642751
2104020643887
3104220692559
4104220693111
5106820693086
Mittelwert105022273079
Tabelle 2: Auswertung der Zeiten

Deutlich zu sehen ist, dass der Pico W sich hier am schnellsten mit dem Router verbinden konnte, wobei mich die Zeiten doch etwas überrascht haben. Gerade der D1 Mini, mit im Schnitt knapp 3 Sekunden, brauchte fast dreimal so lange wie der Pico W! Mir ist an dieser Stelle klar, dass ich hier nicht unter Laborbedingungen arbeite, aber um einen ersten Eindruck der Verbindungsgeschwindigkeit zu bekommen, sollte es vollkommen ausreichen.

Test 2 Pi berechne Pi

Der zweite Test der Pico W Benchmark widmet sich der Berechnung der Konstante Pi. Mit der Ailey–Borwein–Plouffe Formel kann, je nachdem wie viele Durchläufe man einstellt, sehr genau Pi und seine Nachkommastellen berechnet werden. Den vollständigen Code findest du in Code 2, der wieder für alle MicroController funktioniert. Beachte bitte wieder den Kommentar in den ersten Zeilen, damit auch die i2c-Schnittstelle funktioniert.

import time
import machine
from oled import SSD1306_I2C,Write,gfx
from oled.fonts import ubuntu_mono_12

I2C_PORT = 0
I2C_SDA = machine.Pin(0) #Pin on ESP32: 21(D21) D1Mini: 4(D1) Pico W: 0(Pin 1)
I2C_SCL = machine.Pin(1) #Pin on ESP32: 22(D22) D1Mini: 5(D2) Pico W: 1(Pin 2)
#i2c = machine.I2C(I2C_PORT,sda=I2C_SDA, scl=I2C_SCL) # For ESP32 only
i2c = machine.I2C(sda=I2C_SDA, scl=I2C_SCL) # For Pico W and D1 Mini

#Definitions and init for OLED-Display
WIDTH = 128
HIGHT = 64
oled = SSD1306_I2C(WIDTH, HIGHT, i2c)
graphics = gfx.GFX(WIDTH, HIGHT, oled.pixel)
font = Write(oled,ubuntu_mono_12)
Y_Shift = 13

def calculate_pi(n):
    """
    Calculate the value of pi using the Bailey–Borwein–Plouffe formula.
    """
    pi = 0
    k = 0
    while k < n:
        pi += (1 / (16 ** k)) * ((4 / (8 * k + 1)) - (2 / (8 * k + 4)) - (1 / (8 * k + 5)) - (1 / (8 * k + 6)))
        k += 1
        if k%50 == 0:
          graphics.fill_rect(10,27,int(k/n*100),10,1)
          oled.show()
    return pi

try:
    oled.fill(0)
    xPos = 10
    yPos = 1
    font.text('---Calculate Pi---', xPos, yPos)
    start_time = time.ticks_ms()
    yPos += Y_Shift
    font.text('Calculating', xPos, yPos)
    oled.show()
    pi = calculate_pi(1500)
    yPos += Y_Shift*2
    end_time = time.ticks_ms()
    execution_time = round(end_time - start_time,4)/1000
    font.text('Time: ' + str(execution_time) + 's', xPos, yPos)
    yPos += Y_Shift
    font.text('Result: ' + str(pi) , xPos, yPos)
    oled.show()
except KeyboardInterrupt:
    machine.reset()

Code 2: Annäherung von Pi mittels Ailey–Borwein–Plouffe Formel

In diesem Code werden wieder Bibliotheken geladen und die i2c-Schnittstelle samt OLED-Display wird initialisiert. Direkt im Anschluss werden die ersten beiden Zeilen auf dem OLED-Display ausgegeben und die Startzeit, also die aktuelle Laufzeit vom MicroController ermittelt. Direkt im Anschluss wird die Funktion calculate_pi() ausgeführt, die 1500 mal eine Schleife durchlaufen lassen soll. Damit du zu diesem Zeitpunkt auch siehst, dass etwas passiert, wird immer bei einem Wert, der ohne Rest durch 50 teilbar ist (Stichwort Modulo), ein Fortschrittsbalken aktualisiert. Ist die Berechnung abgeschlossen wird wieder die aktuelle Laufzeit ermittelt und die Differenz errechnet. Das Resultat von Pi und die benötigte Zeit werden im Anschluss auf dem OLED-Display präsentiert, siehe Abbildung 9.

Abbildung 9: Berechnung von Pi mit Anzeige

An der Stelle war ich ein bisschen erstaunt über das Ergebnis, siehe Tabelle 3! Zwar wusste ich, dass der Pico W mit seinem RP2040 nicht so schnell arbeitet wie der ESP32 NodeMCU, aber dass der ESP32 NodeMCU fast nur die Hälfte der Zeit braucht, war beeindruckend.

PosPico WESP32 NodeMCUD1 Mini
Calc Pi [s]
111,1424,50122,485
211,1434,50122,470
311,1424,50322,485
411,1434,50122,459
511,1434,522,465
Mittelwert11,1434,50122,473
Tabelle 3: Auswertung Berechnung Pi

Die Taktfrequenz vom ESP32 spielt natürlich eine wesentliche Rolle, da dieser mit bis zu 240 MHz arbeitet. Da kann der RP2040 mit „gerade einmal“ 133 MHz nicht mithalten. Deutliches Schlusslicht macht hier der D1 Mini bzw. der ESP8266 mit fast der doppelten Zeit vom Pico W.

Test 3 Primzahlen ermitteln

Mein letzter Test schlug auch noch einmal in die Kerbe Rechengeschwindigkeit und sollte etwas Klarheit für mich schaffen. Nach kurzem Überlegen wurde ein Programm geschrieben, was Primzahlen ab einer bestimmten Zahl ermitteln, die durchschnittlich gebrauchte Zeit anzeigen und die letzten 8 Primzahlen anzeigen soll. Herausgekommen ist der Code aus Code 3.

import time
import machine
from oled import SSD1306_I2C,Write,gfx
from oled.fonts import ubuntu_mono_12
import array

I2C_PORT = 0
I2C_SDA = machine.Pin(0) #Pin on ESP32: 21(D21) D1Mini: 4(D1) Pico W: 0(Pin 1)
I2C_SCL = machine.Pin(1) #Pin on ESP32: 22(D22) D1Mini: 5(D2) Pico W: 1(Pin 2)
i2c = machine.I2C(I2C_PORT,sda=I2C_SDA, scl=I2C_SCL) # For ESP32 only
#i2c = machine.I2C(sda=I2C_SDA, scl=I2C_SCL) # For Pico W and D1 Mini

#Definitions and init for OLED-Display
WIDTH = 128
HIGHT = 64
oled = SSD1306_I2C(WIDTH, HIGHT, i2c)
graphics = gfx.GFX(WIDTH, HIGHT, oled.pixel)
font = Write(oled,ubuntu_mono_12)
Y_Shift = 13

numbers = [0 ,0 ,0 ,0, 0, 0, 0, 0]
value = 100000
foundPrimes = 0
sumTime = 0

def drawScreen(exTime):
    global foundPrimes, sumTime
    foundPrimes += 1
    sumTime += exTime
    averageTime = round(sumTime / foundPrimes,2)
    oled.fill(0)
    xPos = 10
    yPos = 1
    font.text('T: ' + str(averageTime) + ' s - F: ' + str(foundPrimes) , xPos, yPos)
    yPos += Y_Shift
    if numbers[4] > 0:
        font.text(str(numbers[0]) + '  ' + str(numbers[4]), xPos, yPos)
    else:
        font.text(str(numbers[0]), xPos, yPos)
    yPos += Y_Shift
    if numbers[5] > 0:
        font.text(str(numbers[1]) + '  ' + str(numbers[5]), xPos, yPos)
    else:
        font.text(str(numbers[1]), xPos, yPos)
    yPos += Y_Shift
    if numbers[6] > 0:
        font.text(str(numbers[2]) + '  ' + str(numbers[6]), xPos, yPos)
    else:
        font.text(str(numbers[2]), xPos, yPos)
    yPos += Y_Shift
    if numbers[7] > 0:
        font.text(str(numbers[3]) + '  ' + str(numbers[7]), xPos, yPos)
    else:
        font.text(str(numbers[3]), xPos, yPos)
    oled.show()
    
    
while(True):
    if value > 1:
        start_time = time.ticks_ms()
        for i in range(2, value):
            if(value % i) == 0:
                value+=1
                break
        else:
            for j in range(7, 0, -1):
                prev = j-1
                numbers[j] = numbers[prev]
            numbers[0] = value
            end_time = time.ticks_ms()
            execution_time = round(end_time - start_time,4)/1000
            drawScreen(execution_time)
            value+=1

Code 3: Code zur Berechnung von Primzahlen

Wieder werden die Bibliotheken geladen, die ic2-Schnittstelle und das OLED-Display initialisiert. Dieses Mal wird aber nicht direkt etwas ins Display geschrieben, sondern zunächst wird die erste Primzahl ab der Zahl 100.000 ermittelt. Vorher muss noch die Start- und Endzeit bis zum Finden der nächsten Primzahl ermittelt werden und die letzten 8 Ergebnisse in ein Array geschrieben werden. Damit immer die letzten acht gefunden Primzahlen angezeigt werden, wird bei einer neu gefundenen Primzahl, jeder Wert im Array um eine Position verschoben und der aktuelle Wert an den Anfang vom Array gesetzt.

Mit der Funktion drawScreen() wird dann alles kompakt auf dem Display angezeigt, siehe Abbildung 10.

Abbildung 10: Berechnung von Primzahlen samt Ergebnissen

Für die Erfassung einer Durchschnittszeit, siehe Tabelle 4, wurde immer nach 50 gefundenen Primzahlen, die errechnete Durchschnittszeit erfasst.

PosPico WESP32 NodeMCUD1 Mini
Calc Prime [s]
11,181,045,83
21,181,045,84
31,181,045,84
41,181,055,84
51,181,055,84
Mittelwert1,181,045,838
Tabelle 4: Berechnungszeit für Primzahlen

Hier bin ich vom Pico W und dem ESP32 wieder begeistert. Beide MicroController liegen fast gleichauf, auch wenn nun einige behaupten, dass 0,14s eine lange Zeitspanne ist. Ja im Prinzip sind 0,14s für MicroController eine lange Zeit Allerdings wurde hier nichts Zeitkritisches gesteuert. Schlusslicht war wieder einmal der D1 Mini, mit der fast 5-fachen Zeit zu den anderen MicroControllern!

Zusammenfassung der Pico W Benchmark

In meinem ersten Beitrag zum Pico W wurde bereits viel diskutiert, Fragen gestellt und auch auf Fehler meinerseits eingegangen. Diese Tests sind parallel zu den vielen Kommentaren entstanden. Im Prinzip habe ich das Thema WiFi nur angekratzt, ich habe aber nicht die technischen Mittel, um z.B. das WiFi-Signal genau zu analysieren. Hier gibt es andere Fachmagazine, die da durchaus interessante Beiträge zu verfasst haben und ich mit Spannung verfolge. Die hier gezeigte Pico W Benchmark sollte aber, unabhängig ob nun WiFi oder nicht, zeigen, wozu der Pico (W) im Vergleich zu seinen MicroController-Kollegen im Stande ist. Der Pico (W) mag nicht der schnellste Rechenkünstler sein, aber er kann mit einem ESP32 gut mithalten. Wem Zeit egal ist und nur wenige digitale Pins braucht, kann sich gerne einmal den D1 Mini ansehen. Wer von euch hingegen mehr Rechenpower und mehr Pins für diverse Schnittstellen braucht, sollte den Pico W durchaus in Betracht ziehen. Gut gefallen hat mir in diesem Zuge auch die einfache Einleitung ins Thema Wifi mit dem Pico W durch das PDF-Dokument oder die Projektseite der Raspberry Pi Fundation. Es gab mir einen super Einstieg und ich hatte direkt Lust auf mehr.

Mittlerweile habe ich einige ESP32 und ESP8266 auf MicroPython geflasht, da ich immer mehr gefallen an MicroPython und dem Pico W gefunden habe.

Für weitere spannende MicroController Artikel schaue hier vorbei!

Die mobile Version verlassen