Waveshare RP2040 LCD 0.96inch Display

Waveshare geht mit dem eigenen RP2040 und einem bereits installiertem 0.96 inch SPI Display auf den IoT Markt, welches sehr einfach mit MicroPython programmiert werden kann.

Waveshare RP2040 LCD 0.96" SPI Display

Das Unternehmen Waveshare geht mit einem eigenständigen IoT-Produkt an den Markt und bietet einen RP2040 LCD 0.96, auf Basis der Raspberry Pi Pico Architektur, mit bereits integriertem 0.96" LCD Farb-Display an. Das kleine Modul ist aktuell in zwei Versionen zu bekommen, einmal mit Stiftleiste und zum anderen ohne Stiftleiste.

Waveshare RP2040 0.96 LCD DisplayWaveshare RP2040 0.96 LCD Display (Foto: Waveshare)

Neben dem bereits installierten 0.96 inch Display, befindet sich auch ein hilfreicher Stromversorgungsanschluss für einen externen Akkupack bereits auf der Platine. Der Spannungsregler des Boards regelt die benötigten 3,3V. Ansonsten handelt es sich bei dem Board, um die übliche Raspberry Pi Pico Standard-Architektur und Ausstattung.

RP2040 LCD 0.96 DisplayRP2040 LCD 0.96 Display (Foto: NodeMCU.de)

Die Darstellung von nativem Text auf dem wirklich sehr scharfen Farb-Display, beschränkt sich auf 20 Zeichen zu 8 Zeilen in der Schriftart Monospace, die auf 160x80 Pixel aufgeteilt werden.

# Das Zeichen § wird nicht vom Display unterstützt.
import framebuf

def demoDisplay(FrameBuffer):
    FrameBuffer.fill(0x0000)   
    FrameBuffer.text("********************",0,0,0xffff)
    FrameBuffer.text("* Das Display kann *",0,10,0xffff)    
    FrameBuffer.text("* 20 Zeichen zu je *",0,20,0xffff)
    FrameBuffer.text("* 8 Zeilen in Mono-*",0,30,0xffff)
    FrameBuffer.text("* space darstellen.*",0,40,0xffff)
    FrameBuffer.text("====================",0,50,0xffff)
    FrameBuffer.text("*  by NodeMCU.de   *",0,60,0xffff)
    FrameBuffer.text("********************",0,70,0xffff)
    FrameBuffer.display()
    ...

Code-Schnipsel für die maximale Display-Aufteilung

RP2040 LCD 0.96 Display Pinout

Das Pinout zeigt zunächst die vom 0.96" Display belegten Anschlüsse und restlichen Anschlüsse des RP2040 Dev Boards.

Pinout des RP2040 LCD 0.96 (Foto: Waveshare.com)

MicroPython Demo-Code für den RP2040 LCD 0.96

Der MicroPython-Democode ist unter dem Link oben als ZIP-File verfügbar und nach Übertragung auf den RP2040 mit der Thonny IDE sofort lauffähig.

from machine import Pin,SPI,PWM
import framebuf
import time

#color is BGR
RED   = 0x00F8
GREEN = 0xE007
BLUE  = 0x1F00
WHITE = 0xFFFF
BLACK = 0x0000

class LCD_0inch96(framebuf.FrameBuffer):
    def __init__(self):

        self.width  = 160
        self.height = 80

        self.cs  = Pin(9,Pin.OUT)
        self.rst = Pin(12,Pin.OUT)
        # self.bl = Pin(13,Pin.OUT)
        self.cs(1)
        # pwm = PWM(Pin(13))#BL
        # pwm.freq(1000)        
        self.spi = SPI(1)
        self.spi = SPI(1,1000_000)
        self.spi = SPI(1,10000_000,polarity=0, phase=0,sck=Pin(10),mosi=Pin(11),miso=None)
        self.dc = Pin(8,Pin.OUT)
        self.dc(1)
        self.buffer = bytearray(self.height * self.width * 2)
        super().__init__(self.buffer, self.width, self.height, framebuf.RGB565)
        self.Init()
        self.SetWindows(0, 0, self.width-1, self.height-1)

    def reset(self):
        self.rst(1)
        time.sleep(0.2) 
        self.rst(0)
        time.sleep(0.2)         
        self.rst(1)
        time.sleep(0.2) 

    def write_cmd(self, cmd):
        self.dc(0)
        self.cs(0)
        self.spi.write(bytearray([cmd]))

    def write_data(self, buf):
        self.dc(1)
        self.cs(0)
        self.spi.write(bytearray([buf]))
        self.cs(1)

    def backlight(self,value): #value:  min:0  max:1000
        pwm = PWM(Pin(13))     #BL
        pwm.freq(1000)
        if value>=1000:
            value=1000
        data=int (value*65536/1000)       
        pwm.duty_u16(data)  

    def Init(self):
        self.reset() 
        self.backlight(10000)

        self.write_cmd(0x11)
        time.sleep(0.12)
        self.write_cmd(0x21) 
        self.write_cmd(0x21) 

        self.write_cmd(0xB1) 
        self.write_data(0x05)
        self.write_data(0x3A)
        self.write_data(0x3A)

        self.write_cmd(0xB2)
        self.write_data(0x05)
        self.write_data(0x3A)
        self.write_data(0x3A)

        self.write_cmd(0xB3) 
        self.write_data(0x05)  
        self.write_data(0x3A)
        self.write_data(0x3A)
        self.write_data(0x05)
        self.write_data(0x3A)
        self.write_data(0x3A)

        self.write_cmd(0xB4)
        self.write_data(0x03)

        self.write_cmd(0xC0)
        self.write_data(0x62)
        self.write_data(0x02)
        self.write_data(0x04)

        self.write_cmd(0xC1)
        self.write_data(0xC0)

        self.write_cmd(0xC2)
        self.write_data(0x0D)
        self.write_data(0x00)

        self.write_cmd(0xC3)
        self.write_data(0x8D)
        self.write_data(0x6A)   

        self.write_cmd(0xC4)
        self.write_data(0x8D) 
        self.write_data(0xEE) 

        self.write_cmd(0xC5)
        self.write_data(0x0E)    

        self.write_cmd(0xE0)
        self.write_data(0x10)
        self.write_data(0x0E)
        self.write_data(0x02)
        self.write_data(0x03)
        self.write_data(0x0E)
        self.write_data(0x07)
        self.write_data(0x02)
        self.write_data(0x07)
        self.write_data(0x0A)
        self.write_data(0x12)
        self.write_data(0x27)
        self.write_data(0x37)
        self.write_data(0x00)
        self.write_data(0x0D)
        self.write_data(0x0E)
        self.write_data(0x10)

        self.write_cmd(0xE1)
        self.write_data(0x10)
        self.write_data(0x0E)
        self.write_data(0x03)
        self.write_data(0x03)
        self.write_data(0x0F)
        self.write_data(0x06)
        self.write_data(0x02)
        self.write_data(0x08)
        self.write_data(0x0A)
        self.write_data(0x13)
        self.write_data(0x26)
        self.write_data(0x36)
        self.write_data(0x00)
        self.write_data(0x0D)
        self.write_data(0x0E)
        self.write_data(0x10)

        self.write_cmd(0x3A) 
        self.write_data(0x05)

        self.write_cmd(0x36)
        self.write_data(0xA8)

        self.write_cmd(0x29) 

    def SetWindows(self, Xstart, Ystart, Xend, Yend): #example max:0,0,159,79
        Xstart=Xstart+1
        Xend=Xend+1
        Ystart=Ystart+26
        Yend=Yend+26
        self.write_cmd(0x2A)
        self.write_data(0x00)              
        self.write_data(Xstart)      
        self.write_data(0x00)              
        self.write_data(Xend) 

        self.write_cmd(0x2B)
        self.write_data(0x00)
        self.write_data(Ystart)
        self.write_data(0x00)
        self.write_data(Yend)

        self.write_cmd(0x2C) 

    def display(self):
        self.SetWindows(0,0,self.width-1,self.height-1)       
        self.dc(1)
        self.cs(0)
        self.spi.write(self.buffer)
        self.cs(1)        

if __name__=='__main__':
    lcd = LCD_0inch96()

    while True:
        lcd.fill(BLACK)   
        lcd.text("NodeMCU.de",   35,15,RED)
        lcd.text("on a",         50,35,GREEN)    
        lcd.text("Pico LCD 0.96",30,55,GREEN)
        lcd.display()

        time.sleep(5)

        lcd.fill(BLACK)   
        lcd.text("running on",   40,15,GREEN)
        lcd.text("Demo Code",    45,35,GREEN)    
        lcd.text("Pico LCD 0.96",30,55,GREEN)
        lcd.display()

        time.sleep(5)

Nahezu identischer DemoCode von Waveshare

Der Aufwändigsten Bestandteil des MicroPython Codes ist der Constructor und der Init, in denen der Betriebsmodus des SPI-Displays festgelegt wird, befor es hinter dem

if __name__=='__main__':

Startet den Main-Teil des Programms

schließlich zum Leben erwacht. In diesem Codebeispiel, gibt das Display abwechselnd zwei verschiedene Schriftzüge in einer Endlos-Schleife aus.

Code als main.py statt boot.py speichern

In diesem Zusammenhang sei nochmals erwähnt, das der Code bitte als main.py auf dem RP2040 zu speichern ist. Speichern Sie den Code dennoch als boot.py, kann es Ihnen passieren, das Sie das laufende Programm nur sehr schwer abbrechen können, da nach einem Reset der Boot-Vorgang sofort ausgelöst wird - dies ist bei main.py nicht der Fall.

Geheimnis MicroPython Framebuffer

Geheimnis des Betriebs dieses kleinen Displays, ist der MicroPython Framebuffer, der bereits in den ersten Zeilen importiert wird. Erst durch den Import der unscheinbaren Klasse Framebuffer ist es möglich Texte auf dem Display zu zeigen oder geometrische Primitiven wie Pixel, Linien oder Rechtecke zu zeichnen. Die genaue Dokumentation finden Sie oben unter den Source-Links bzw. in diesem Absatz.

Ausgabe von Text und Grafik auf dem RP2040 LCD 0.96

Die Ausgabe von Text und einfachen Grafiken, beruht auf der pixelgenauen Angabe der Zeichen- und Kursor-Position. Folglich existiert kein komfortabler Zeilenumbruch oder ähnliches. Sie müssen daher die Darstellung von Grafiken und Zeichen zuvor genau durchdenken, denn sonst werden diese gnadenlos abgeschnitten oder verschwinden im Nirvana.

Anpassen der Schriftgröße

Leider ist es in der aktuellen Version von MicroPython noch nicht möglich die Schriftgröße zu beeinflussen, jedweder Text wird mit einem nativen Zeichensatz auf dem kleinen Display angezeigt, was letztendlich dazu führt, das dieses Display weniger für Textdarstellungen statt mehr für die Anzeige von Grafiken geeignet scheint.

Fazit zum RP2040 LCD 0.96 SPI Display

Das kleine Dev Board mit Display ist sehr gut gelungen. Die Qualität ist sehr hoch und die Unterstützung durch reichlichen Beispielcode ist mehr als ausreichend. Besonders positiv fällt auf, alles funktioniert auf anhieb ohne viel herumprobieren zu müssen.

Interessant in diesem Zusammenhang ist die Tatsache, das Waveshare ein weiteres 40Pin Dev Board mit dem leistungsfähigeren ESP32 und dem gleichen Display in exakt dieser Bauform anbietet. Damit steht noch mehr Leistung und mehr Konnektivität zur Verfügung.

Es soll darauf hingewiesen werden, das das RP2040 LCD 0.96 Board zwar kein Raspberry Pi Pico ist, jedoch auf Grund des Open-Source Standards mit dem Pi Pico vollständig kompatibel ist. Folglich sind alle Pico-Projekte auch auf dem Waveshare RP2040 LCD 0.96 lauffähig - zusätzlich mit einem sehr nützlichen Display für die Ausgabe von (vorzugsweise) Grafiken.