Wie kompiliert man MicroPython vom Quellcode selbst?

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Benutzeravatar
Dennis89
User
Beiträge: 1125
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Abend,

bytearray ist ja in MP nicht sonderlich toll dokumentiert.

Wenn ich in Python folgendes mache:

Code: Alles auswählen

print(bytearray('100', 'utf-16'))
dann erhalte ich

Code: Alles auswählen

bytearray(b'\xff\xfe1\x000\x000\x00')
Wenn ich das in MP mache, dann erhalte ich:

Code: Alles auswählen

bytearray(b'100')
Wenn ich "b'\xff\xfe1\x000\x000\x00'" an blit_buffer übergebe erhalte ich einen weißen Punkt und bei "b'100' " einen hellblauen Punkt.
Es ist dabei egal ob ich die Höhe und Breite jeweils auf 1 oder auf 100 setze, es bleibt bei diesem Punkt.

Ich verstehe nicht wie ich ein bytearray so vordefiniere, das es die Pixel enthält die mir eine Zahl auf das Display schreiben und ich verstehe auch den Zusammenhang mit der Größe nicht. Du sagtest
Die Höhe und Breite geben die Gestalt dessen, was der Buffer repräsentiert
Kann ich dass dann mit der Schriftgröße eines Editors gleich setzen?

Ich fand leider nicht wirklich brauchbare Infos im Netz.

Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Blit kopiert Bytes. Nix sonst. Wenn du angibst, 3*4 Pixel an stelle( 45, 67) blitten zu wollen, dann musst du auch ein bytearray von 3*4*2 Bytes bereitstellen. Nicht eines von nur 3 bytes, [‘1’, ‘0’, ‘0’]. Und wenn du plötzlich 100*4 Pixel blitzen willst, müssen eben 100*4*2 Bytes in deinem Byte Buffer stecken. Deine ‘100’ ist also bestenfalls ein Pixel. Weil 3 Bytes nun mal nur für 1*1*2 ausreichen, schon 2*1*2 ist mehr als 3. Und da einfach die Pixel zu erhöhen, ohne an der Gestalt des arrays was zu ändern, kopiert Daten aus dem Nirvana.

Wir haben das doch alles schon so besprochen, oder nicht? Irgendwie ist mir so. War das noch im Pi Forum? Was it Pixeln und Koordinaten aufmalen?
Benutzeravatar
Dennis89
User
Beiträge: 1125
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen und vielen Dank.

Okay mit folgendem Code setze ich ein Rechteck mit der Größe von 100 x 170 Pixel in die Mitte des Displays. Und weil jedes Pixel eine Größe von 2 Bytes hat, wird das Bytearray dementsprechend mit zwei multipliziert:

Code: Alles auswählen

from machine import Pin, SPI
import st7789
from time import sleep


def main():
    spi = SPI(1, baudrate=30000000, polarity=0, phase=0)
    display = st7789.ST7789(
        spi, 135, 240,
        reset=Pin(4, Pin.OUT),
        cs= Pin(15,  Pin.OUT),
        dc=Pin(5, Pin.OUT)
    )
    display.init()
    display.fill(st7789.WHITE)
    display.blit_buffer(bytearray(100 * 170 * 2), 17, 35, 100, 170)
    while True:
        sleep(1)
    
if __name__ == '__main__':
    main()
Das müsste ich so weit begriffen haben. Diese Größe ist auch ungefähr die Grenze, bevor der ESP mit Speicherproblemen aussteigt.
Was it Pixeln und Koordinaten aufmalen?
Dennis89 hat geschrieben: Dienstag 6. September 2022, 21:12 P.S. wir hatten ja vor längerer Zeit schon mal ein ähnliches Problem, da haben wir 'uarray' genutzt. Aber da hatte ich eine Bibliothek die Texte auf ein Display schreiben konnte, da ging es nur um das buffern, damit eine reibungslose Anzeige möglich war. Ich glaube dass ist hier nicht die Lösung.
Ich hatte mir den Code natürlich schon angesehen bevor ich hier mit fragen begonnen habe. Ich konnte daraus aber für das jetzige Problem keine Lösung ableiten. Wir haben dort eine Art Tacho aufgemalt. Erst ein Array mit der Größe des Tachos erstellt, jedes Pixel schwarz gesetzt und dann die einzelnen Pixel wieder farbig, bis wir einen Tacho hatten.
*Dieser Post entstand schon um 6.45Uhr und dann hat es klick gemacht und zwar so laut, das sollte man bis zu dir gehört haben*

Ich erstelle ein Quadrat und lasse es Pixel für Pixel wieder verschwinden:

Code: Alles auswählen

from machine import Pin, SPI
import st7789
from time import sleep


def main():
    spi = SPI(1, baudrate=30000000, polarity=0, phase=0)
    display = st7789.ST7789(
        spi, 135, 240,
        reset=Pin(4, Pin.OUT),
        cs= Pin(15,  Pin.OUT),
        dc=Pin(5, Pin.OUT)
    )
    display.init()
    display.fill(st7789.WHITE)
    byte_array = bytearray(8 * 8 * 2)
    display.blit_buffer(byte_array, 37, 80, 8, 8)
    sleep(1)
    for byte in range(128):
        byte_array[byte] = st7789.WHITE
        display.blit_buffer(byte_array, 37, 80, 8, 8)
        sleep(0.1)

    
if __name__ == '__main__':
    main()
Das müsste doch jetzt ein kleines Erfolgserlebnis für mein Ziel sein?

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das wäre das blitten eines definierten Rechtecks, ja. Und wenn das bytearray mit dem framebuffer Mechanismus verändert wird, sollte es entsprechend auch funktionieren.


Wobei du da noch einen Fehler hast: du modifizierst immer ein Byte. Nicht zwei. Zumindest sieht das so aus. Musst mal genau hinschauen, ob das Pixel eine Farbänderung durchmacht.
Benutzeravatar
Dennis89
User
Beiträge: 1125
Registriert: Freitag 11. Dezember 2020, 15:13

Ich sehe nur wie das schwarze Quadrat Pixel für Pixel verschwindet. Meinst du das ich immer zwei Bytes gleichzeitig ändern soll oder wie ist das gemeint?

Also sowas(?):

Code: Alles auswählen

    for byte in range(0, 128, 2):
        byte_array[byte] = st7789.WHITE
        byte_array[byte + 1] = st7789.WHITE
        display.blit_buffer(byte_array, 37, 80, 8, 8)
        sleep(0.1)
Grüße und Danke
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja, das sollte es eigentlich sein. Um einen Unterschied zu sehen, musst du ggf. langsamere malen.
Benutzeravatar
Dennis89
User
Beiträge: 1125
Registriert: Freitag 11. Dezember 2020, 15:13

Ich habe das Gefühl, dass wenn ich zwei Bytes in einem Schritt ändere das volle Pixel auf einen Schlag die Farbe wechselt.
In der ersten Variante sieht es so aus, als ob sich erst das halbe Pixel verfärbt. Also die Stücke die die Farbe ändern sind kleiner.
Der Keks wird gleich schnell gegessen, aber die Bisse sind nicht gleich groß.

Das mit dem FrameBuffer werde ich mir dann im Laufe des Tages anschauen.

Viele Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na ein halbes pIxel gibt es nicht. Das ist eben eine Farbe, die zufällig passend diesen Eindruck vermittelt. Wenn das schreiend pink wäre, fiele dir das auf. Aber laut https://g.co/kgs/GccnsB ist das gelb, passt also als zwischen Farbe.
Benutzeravatar
Dennis89
User
Beiträge: 1125
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Abend __deets__,

das mit dem halben Pixel hatte ich geschrieben, weil ich dachte so bekommst du eine bessere Vorstellung davon, was auf dem Display los ist. (auch wenn du es ja schon richtig vermutet hattest)

Schau mal, ich kann auf dem Display von 0 bis 9 hoch zählen:

Code: Alles auswählen

from machine import Pin, SPI
import st7789
from time import sleep
import framebuf


def main():
    spi = SPI(1, baudrate=30000000, polarity=0, phase=0)
    display = st7789.ST7789(
        spi, 135, 240,
        reset=Pin(4, Pin.OUT),
        cs= Pin(15,  Pin.OUT),
        dc=Pin(5, Pin.OUT)
    )
    display.init()
    display.fill(st7789.WHITE)
    frame_buffer = framebuf.FrameBuffer(bytearray(10 * 10 * 2), 10, 10, framebuf.RGB565)
    for number in range(10):
        frame_buffer.text(str(number), 1, 1, st7789.WHITE)
        display.blit_buffer(frame_buffer, 62, 120, 10, 10)
        sleep(1)
        frame_buffer.text(str(number), 1, 1, st7789.BLACK)


    
if __name__ == '__main__':
    main()
Ist die Vorgehensweise so richtig?

In der Doku steht zu 'text':
All characters have dimensions of 8x8 pixels and there is currently no way to change the font.

Falls ich mit dem obigen Code richtig liege, hast du noch einen Trick auf Lager, wie ich die Zahlen in eine lesbare Größe bekomme?

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sieht gut aus. Eine Idee für größere zahlen kann dann nur sein, dass man Byte-arrays vordefiniert mit zahlen, und die dann blittet.
Benutzeravatar
Dennis89
User
Beiträge: 1125
Registriert: Freitag 11. Dezember 2020, 15:13

Das freut mich, vielen lieben Dank für deine Geduld und deine Hilfe!

Mir fällt schon auf, dass dein zweiter Satz gleich ist, wie ein paar Posts davor :)

Ich kann mir nur nicht vorstellen, wie ich das Bytearray vordefinieren soll, ohne die Methode 'text'. Ich kann ja schlecht alle Pixel manuell setzen?

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wieso denn ohne die Methode `text()`? Die kann man doch benutzen um die Bytearrays vorzudefinieren.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1125
Registriert: Freitag 11. Dezember 2020, 15:13

Vielleicht verstehe ich es mehr, wenn ich wüsste was nach dem vordefinieren passiert.

Ich kann das Bytearray, das mit der 'text'-Methode definiert wurde als Vorlage nehmen und muss es dann hoch skalieren. So kann ich das von Hand mit einem Bleistift und einem Geodreieck machen. Wenn dass die Idee dahinter ist, dann habe ich momentan keine Idee wie das ein Computer machen könnte.

Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dennis89: Du kannst Doch ein Bytearray mit dem Framebuffer und `text()` mit Zeichen/Ziffern bemalen. Und dann diese Bytearrays ausgeben/speichern und in ein anderes Programm einbauen/einlesen. Oder ”von Hand“ zeichnen — das würde man heute aber nicht mehr mit Papier und Bleistift machen, sondern mit einem Malprogramm und dann Code schreiben der aus den Bildern entsprechende Bytearrays/Konstanten berechnet.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1125
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen und danke für die Antwort.

Den zweiten Teil verstehe ich theoretisch und das wäre wohl ein ähnliches vorgehen, wie du hier mit den GIFS angesprochen hast?

Zum ersten Teil: Ich komme noch soweit mit, dass ich das Bytearray in einem anderen Programm einlesen kann. Dann sehe ich zwar an welcher Stelle ich "andere" Bytes habe, die die Zahl darstellen, ich verstehe nur nicht woher ich dann weis welche weiteren Bytes ich verändern muss, damit das Ganze vergrößert wird.

Das hier ist jetzt zum Beispiel eine 3:

Code: Alles auswählen

bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
          b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
Klar ist dass das ganz Bytearray größer gemacht werden muss, aber damit die 3 auch größer dargestellt wird müssen ja noch weitere '\xff' hinzukommen. Und die kann ich ja nicht einfach anhängen.

Noch mal bildlich gesprochen, das ihr wisst was in meinem Kopf vor geht. Das Bytearray stelle ich mir wir ein karriertes Blatt Papier vor und jetzt muss ich alle Kästchen ankreuzen damit ich nachher eine große 3 da stehen habe. Dazu benötige ich eine logische Vorschrift, sonst sieht das katastrophal aus. Selbst wenn eine kleine 3 schon angekreuzt ist, ist das für mich bis jetzt nur raten.

Denke ich mal wieder ganz falsch oder wie geht man da vor?

Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du malst die Zahlen im Bilder der entsprechenden Größe. Auf deinem PC. Und schreibst ein Skript, das aus einem eingelesenen Bild ein Bytearray macht. Du kannst das als Code generieren lassen, aber das ist verschwenderisch. Du kannst stattdessen auch einfach eine Datei mit den Pixelwerten als Rohe Bytes schreiben, und die mit open(…,“rb“) einmal am Anfang einlesen auf dem ESP.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das karierte Blatt Papier ist doch letztlich nichts anderes als eine Bitmap in einem Malprogramm. Sagen wir mal Du hast wirklich nur Schwarz Weiss und ein Bild mit 50×100 Pixel, dann brauchst Du für ein 16-Bit pro Pixel Zielbild ein Bytearray mit 50×100×2 Bytes. Die ersten 100 Bytes sind die erste Pixelreihe, die nächsten 100 Bytes die zweite Pixelreihe, und so weiter. Für jedes schwarze Pixel müssen zwei 0 Bytes in das Bytearray gesetzt werden, und für jedes weisse Pixel zwei 0xFF Bytes.

Falls Speicher auf dem Zielgerät knapp ist, könnte man diese Expansion auf dem Zielgerät selbst vornehmen, tatsächlich aus einer Bitmap, also 8 Pixel pro Byte. Oder man berechnet die Bytearrays, die man direkt blitten kann, schon vor und packt die ins Programm oder in eine Datei.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Oh, oh, oh, man könnte run length encoding machen. Aber da platzt dem armen Dennis der Kopf 🫣 Wenn es wirklich Speicher Probleme gibt, können wir nochmal schauen.

Erstmal aus einem Bild eine Datei mit 2 Byte / Pixel machen reicht. Das sollte mit Pillow kein Problem sein.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Hm, es gibt `more_itertools.run_length` und ein reines Python `packbits`-Modul auf PyPi, das den gleichnamigen Algorithmus implementiert, beliebt und bekannt aus diversen historischen Grafikformaten, und einfache `encode()`/`decode()` Funktionen bereit stellt.

Code: Alles auswählen

In [255]: image
Out[255]: bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\x
ff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x
ff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x
ff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\x
ff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00')

In [256]: len(image)
Out[256]: 200

In [257]: packbits.encode(image)
Out[257]: b'\xe7\x00\xf9\xff\xf7\x00\xfd\xff\xfd\x00\xfd\xff\xf1\x00\xfd\xff\xf5
\x00\xfb\xff\xef\x00\xfd\xff\xf9\x00\xfd\xff\xfd\x00\xfd\xff\xf7\x00\xf9\xff\xd3
\x00'

In [258]: len(packbits.encode(image))
Out[258]: 38
Nächste Frage wäre ob das `zlib`-Modul in Micropython verfügbar ist:

Code: Alles auswählen

In [263]: zlib.compress(image)
Out[263]: b'x\x9cc`\xc0\x05\xfeC\x01\xaa\x082\x8d\xae\x1aS7vS\xf1\x9b\x87i/1\x00
\x00\xa30-\xd3'

In [264]: len(zlib.compress(image))
Out[264]: 31
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nett.
Antworten