Forum: Mikrocontroller und Digitale Elektronik Hilfe bei Bitshifting und Bytemanipulationen


von Holger K. (holgerkraehe)


Angehängte Dateien:

Lesenswert?

Hallo zusammen

Ich hoffe alle hatten/haben frohe Ostern.
Ich sitze nun seit stunden an einem Problem und habe den Faden 
inzwischen komplett verloren.

Folgende Ausgangslage:

Es gibt ein Bytearray namens uint8_t ScreenBuffer[1024];
Dieser repräsentiert mein Display welches 128x64 Pixel hat.

Das Display ist in 8 Pages zu je 128Bytes aufgeteilt.
Also in etwa so:

P0  | | | |.... | | | |
P1  | | | |.... | | | |
.
.
.
P7  | | | |.... | | | |

Wobei ein | ein Byte ist. LSB ist oben MSB ist unten.
Genau so interpretiere ich auch mein Array.

Mein Font ist ebenfalls so orientiert, dass er mir die Fontdaten als 
"stehendes byte" angibt. Somit wäre es ideal, wenn ich direkt das Byte 
in meinen Buffer schreiben könnte. An eine beliebige x,und y stelle 
natürlich.

Und hier beginnt das Problem.
Ich schaffe es nicht, das Byte auf eine elegante, vernünftige Art und 
Weise in den Buffer zu schreiben. Weil ich irgendwie auf dem Schlauch 
stehe. Wenn sich das Byte innerhalb einer Page befindet, ist es ja noch 
ziemlich einfach.

Sobald es sich aber auf zwei pages aufteil, muss ich das alte Byte 
auslesen, maskieren, die daten um den versatz schieben und mit dem alten 
verodern und schreiben. Dann die zweite Page einlesen, maskieren, daten 
schieben, verodern, schreiben.... Soviel zur theorie.

Es kann auch sein, dass man nur einen bestimmten Bereich des 
Fontdatenbyte schreiben möchte, dann brauche ich eine Funktion, welcher 
ich eine maske übergeben kann um zu wählen welche daten ich brauche.

Im Anhang ist mein Versuch es so zu lösen.
Leider klappt das nicht und ich blicke nicht mehr durch.

Ich hoffe jemand kann mir eine elegante Lösung vorschlagen oder Tipps 
geben.



Danke schonmal.

von Falk B. (falk)


Lesenswert?

@Holger Krähenbühl (holgerkraehe)

>Es gibt ein Bytearray namens uint8_t ScreenBuffer[1024];
>Dieser repräsentiert mein Display welches 128x64 Pixel hat.

>Das Display ist in 8 Pages zu je 128Bytes aufgeteilt.

Dann sollte man das aber auch so in der Definition wiederfinden,

uint8_t ScreenBuffer[8][128]

>Wobei ein | ein Byte ist.

> LSB ist oben MSB ist unten.

???

>Ich schaffe es nicht, das Byte auf eine elegante, vernünftige Art und
>Weise in den Buffer zu schreiben. Weil ich irgendwie auf dem Schlauch
>stehe. Wenn sich das Byte innerhalb einer Page befindet, ist es ja noch
>ziemlich einfach.

Wozu überhaupt die logische Einteilung in Pages? Sollte das nicht besser 
zeilenweise orientiert sein? Bei 128 Spalten macht das 16 Bytes/Zeile. 
Also so

uint8_t ScreenBuffer[64][16]

>Sobald es sich aber auf zwei pages aufteil, muss ich das alte Byte
>auslesen, maskieren, die daten um den versatz schieben und mit dem alten
>verodern und schreiben.

Ja.

>Ich hoffe jemand kann mir eine elegante Lösung vorschlagen oder Tipps
>geben.

Vergiss die Pages. Sturkturiere das Array zeilenorientiert. Dann 
übergibst man zur Zeichenausgabe die x/y Koordinaten und einen Zeiger 
auf das auszugebende Zeichen. Durch die Zeilenorientierung ist es 
einfach die Startzeile bzw. Adresse auszurechnen, denn die ist direkt 
nutzbar ;-). Bei der Spalte muss man rechnen, aber auch das ist einfach. 
Etwa so.

1
void write_char(uint8_t *letter, uint8_t x, uint8_t y) {
2
  uint8_t i, shift, mask;
3
4
  shift = x % 8;
5
  x = x & 0x7;
6
  mask = ~(0xFF >> shift);
7
8
  for(i=0; i<8; i++) {
9
    if (shift==0) {   // Zeichen exakt auf Bytegrenze, keine Maskierung nötig
10
      ScreenBuffer[y+i][x] = letter[i]
11
    } else {          // Zeichen zwischen 2 Bytes, maskieren und verknüpfen
12
      ScreenBuffer[y+i][x]   = ScreenBuffer[y+i][x] & mask |
13
                               (letter[i]>>shift) & ~mask;
14
      ScreenBuffer[y+i][x+1] = ScreenBuffer[y+i][x+1] & ~mask |
15
                               (letter[i]<<(8-shift)) & mask;
16
    }
17
  }  
18
}

Siehe auch Bitmanipulation, dort gibt es ein paar Links auf Artikel 
mit Beispielen, auch wenn die dort nur eindimensional sind.

von Holger K. (holgerkraehe)


Angehängte Dateien:

Lesenswert?

Anbei habe ich noch kurz ein PDF Erstellt, welches das ganze etwas 
verdeutlichen soll.

von Holger K. (holgerkraehe)


Lesenswert?

Vielen Dank Falk für deine Antwort.


Falk B. schrieb:
> Wozu überhaupt die logische Einteilung in Pages? Sollte das nicht besser
> zeilenweise orientiert sein? Bei 128 Spalten macht das 16 Bytes/Zeile.
> Also so

Dies wäre mir auch lieber, das Problem ist, dass das Display mit Pages 
arbeitet. SSD1306 Controller. Ich schreibe den Buffer mit dem DMA 
automatisch per SPI zum Display. deshalb muss mein Buffer ebenfalls in 
Pages orientiert sein. Oder übersehe ich hier gerade etwas?

Falk B. schrieb:
> Bei der Spalte muss man rechnen, aber auch das ist einfach.
> Etwa so.

Vielen Dank für dein Beispiel.
Ist das jetzt für ein Buffer mit Pages ala [8][128]?

Falk B. schrieb:
1
} else {          // Zeichen zwischen 2 Bytes, maskieren und verknüpfen
2
       ScreenBuffer[y+i][x]   = ScreenBuffer[y+i][x] & mask |
3
                                (letter[i]>>shift) & ~mask;
4
       ScreenBuffer[y+i][x+1] = ScreenBuffer[y+i][x+1] & ~mask |
5
                                (letter[i]<<(8-shift)) & mask;
6
     }



Falls ja, müsste es im obigen code nicht y+i +1 sein anstelle von x +1?

Denn Man muss ja die Page und nicht die Column wechseln

Danke

von Falk B. (falk)


Lesenswert?

@ Holger Krähenbühl (holgerkraehe)

>Dies wäre mir auch lieber, das Problem ist, dass das Display mit Pages
>arbeitet. SSD1306 Controller. Ich schreibe den Buffer mit dem DMA
>automatisch per SPI zum Display. deshalb muss mein Buffer ebenfalls in
>Pages orientiert sein. Oder übersehe ich hier gerade etwas?

Ja. Man kann das auch trennen. Es ist ja im Endeffekt nur eine 
Berechungsweise für Adressen. Die sollte man so legen, das die 
Schreibzugriffe möglichst einfach und logisch erfolgen.

>Ist das jetzt für ein Buffer mit Pages ala [8][128]?

Nein, für [64][16]. Ich hab übersehen, daß du 7x12 Zeichen hast. Mein 
Beispiel ist für 8x8 Zeichen. Aber das Prinzip bleibt gleich.

>Denn Man muss ja die Page und nicht die Column wechseln

Das mit den Pages sollte man vermeiden! Sonst wird es zuviel Chaos!

von Holger K. (holgerkraehe)


Angehängte Dateien:

Lesenswert?

Falk B. schrieb:
> Nein, für [64][16]. Ich hab übersehen, daß du 7x12 Zeichen hast. Mein
> Beispiel ist für 8x8 Zeichen. Aber das Prinzip bleibt gleich.

Ich verwende sowieso unterschiedlich grosse und breite fonts.
Dehslab würde ich dort einfach die jeweilige breite auslesen und 
verwenden.


Das mit den [64][16] verwirrt mich jetzt ungemein.
mir ist bewusst, dass es schlussendlich auch "nur" 1024bytes sind.
Und man damit einfach anderst auf die Daten zugreifen kann.

Jedoch erwartet das Display von mir die Bytes momentan wie im Bild im 
Anhang dargestellt. (rot markierter Bereich)

Zuerst also 128Bytes für die erste Page.
Dann die nächsten für die zweite usw...

Ich sende mommentan mit dem DMA alle 1024Bytes in einem rutsch.

Deshalb bin ich nach meine Verständnis an die Pages gebunden oder nicht?

Wäre ich eventuell besser dran, wenn ich das DIsplay auf den Vertical 
Mode umstellen würde?

Danke

von Falk B. (falk)


Lesenswert?

@Holger Krähenbühl (holgerkraehe)

>Ich verwende sowieso unterschiedlich grosse und breite fonts.
>Dehslab würde ich dort einfach die jeweilige breite auslesen und
>verwenden.

Das macht die Sache aber nicht einfacher. Schreib erst einmal ein paar 
Funktion für einen gegbenen Font. Wenn das alles läuft und du es 
WIRKLICH verstanden hast, kannst du Funktionen für verschieden große 
Fonts schreiben.

>Das mit den [64][16] verwirrt mich jetzt ungemein.

Das war eine Annahme von mir.

>mir ist bewusst, dass es schlussendlich auch "nur" 1024bytes sind.
>Und man damit einfach anderst auf die Daten zugreifen kann.

??
Was soll man mit so einer Aussage anfangen? Willst du alles ala 
Turingmaschine programmieren? Viel Spaß! ;-)

Der Sinn einer SINNVOLLEN Datenstruktur ist es ja eben, bestimmte 
Datenzuordnungen verständlich zu machen und leicht auf die Daten 
zugreifen zu können.

>Jedoch erwartet das Display von mir die Bytes momentan wie im Bild im
>Anhang dargestellt. (rot markierter Bereich)

>Zuerst also 128Bytes für die erste Page.
>Dann die nächsten für die zweite usw...

Sicher, aber ich sehe da keinen nennenswerten Unterschied zu einer 
linearen Adressierung ohne Pages.

>Deshalb bin ich nach meine Verständnis an die Pages gebunden oder nicht?

Oder nicht.

Was in dem Bild fehlt ist der Zusammenhang zwischen den Zeilen und den 
Daten, denn dein LCD hat sicher nicht nur 8 Zeilen ;-)

>Wäre ich eventuell besser dran, wenn ich das DIsplay auf den Vertical
>Mode umstellen würde?

Nein.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.