Forum: Projekte & Code DEBO OLED2 0.96 0,96" OLED-Display SSD1306 SSD1312 Initialisierung TWI I2C AVR ATmeg8 Assembler ASM


von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Ein kleines Beispiel (Version1) wie ein OLED2 SSD1306 in Assembler 
initialisiert werden kann.

Ein ganz großes Dankeschön an Steffen, wichtige Routinen konnte ich von 
ihm nutzen, super!

Beitrag "[ASM] SSD1306 text library für oled displays + AVR 0- und 1-Series"

Der 8MHz getaktete ATmega, ohne viel Schnick-Schnack bedient dieses 
kleine Display. Ganz bewußt habe ich alle Vorgänge verlangsamt, SCL und 
der µC-Takt kann nach belieben verändert und das keine Programm (12% 
Flash, 1008 Byte) aufgebohrt werden.

Besonderheit, der SSD1306 kann nur vertikale 8Bit Pixel darstellen. 
Horizontale vermutlich nicht.

Um das gesamte Display zu löschen (clear) sind 1024 TWI/I2C Bytes zu 
schreiben.

Bei 16MHz Takt, SCL 444,444kHz, gelingt das in 11,6ms.

Sehen wir kurz nach Progammstart einen wunderschönen "Sternenhimmel", 
dann ist das schon ganz gut, der Bildspeicher des Displays hat einen 
undefinierten Zustand eingenommen. Erst durch beschreiben des z.B. Clear 
Display, ändert sich dieser Zustand.

LED-grün: bereit
LED-gelb: TWI Aktivität
LED-rot:  TWI Error, ev. Hardwareproblem, z.B. Problem mit dem Sklave, 
SCL zu hoch

Anmerkung: Bei 400kHz SCL könnten ev. bei kurzen Anschlussleitungen 
keine zusätzlichen Widerstände (SCL, SDA) gegen Vcc erforderlich sein.

Diesen Beitrag fand ich u.a. auch sehr interessant:

Beitrag "SSD1306/1309 Library zum Darstellen von Text auf OLED Displays"

Für Hinweise und konstruktive Vorschläge bin ich sehr dankbar.

Bernhard

: Bearbeitet durch User
von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Version2 mit einem ATmega328p, als Grundgerüst für weitere Projekte, er 
bietet mehr SRAM um einen 1.024Byte großen virtuellen Bildspeicher im 
SRAM zu ermöglichen, das schafft leider der ATmega8 nicht.

Das Display wir in dieser Version nur gelöscht und anschließend wieder 
komplett beschrieben, sieht aus, als würde es blinken, s.Video^^

: Bearbeitet durch User
von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Version3

- mit einem virtuellen 1.024 Byte großen SRAM-Bild-Speicher für Text und
  Grafic.

- wird Byte0 des Bildspeichers mit ffh beschrieben entsteht eine
  horizontale 8 Pixel Linie oben links

- ist diese Byte eine 01h entsteht ein Pixel in der äusersten linken
  oberen Ecke, mit diesm Verfahren lassen sich sehr einfach einzelne
  Pixel plazieren, Linien und Kreise zeichnen

- im Timerinterrupt wird alle 100ms der Graficspeicher komplett
  übetragen, dauer ca. 50ms da einige Operationen notwendig sind
  um die Bits zu bearbeiten, damit eine horizontale Linie entsteht

- der Graficspeicher muss nicht zwingend im 100ms Interrupt erfolgen

- man könnte auch nur dann das Display refreshen, wenn eine Änderung
  im Bildspeicher vorliegt

-die gewohnte Clear Diplay Funktion ist natürlich in der üblichen
 Form nicht mehr vorhanden, jetzt mussen wir den virtuellen Bildspeicher
 löschen^^

: Bearbeitet durch User
von Steffen H. (avrsteffen)


Lesenswert?

Oh, das ist ja super zu sehen - du kommst weiter mit dem OLED Display.

Bernhard S. schrieb:
> - ist diese Byte eine 01h entsteht ein Pixel in der äusersten linken
>   oberen Ecke, mit diesm Verfahren lassen sich sehr einfach einzelne
>   Pixel plazieren, Linien und Kreise zeichnen

Da bin ich aber mal gespannt. Das hat mir einiges an Hirnschmalz 
gekostet dies umzusetzen :)

Gruß Steffen

von Bernhard S. (bernhard)


Lesenswert?

Steffen H. schrieb:
> Da bin ich aber mal gespannt. Das hat mir einiges an Hirnschmalz
> gekostet dies umzusetzen :)

Ja, das war nicht ganz ohne :-)

Das "i" in "OLED_REFRESHi" steht für Interrupt-tauglich

Prinzip:

es werden imer 8 SRAM-Bytes geladen, 1 Bock mit 64 Pixeln,
welche horizontal polarisiert, also graficfreundlich sind
(temp1...8)

in der "OLED_REFRESH_BLOCK_s" Routine erfolgt das bitweise 
zusammenstellen des neuen Sendebytes, also von horizontal auf vertikal

Zuerst einsammeln Bit0 von temp1...8 im Register temp,
anschließend temp senden

dann Bit1 von temp1...8 und senden usw.

und die Neuberechnung der Adresse für den SRAM


1
OLED_REFRESHi:
2
  rcall GO_HOME
3
;-------------------------------------------------------------------------------
4
  ldi temp1,(SSD1306_ADR)
5
  rcall TWI_MT_START_TEMP1
6
;-------------------------------------------------------------------------------
7
  ldi  temp,(SSD1306_CONTROL_BYTE_DATA_STREAM)  ; CONTROL Byte: DATA STREAM
8
  rcall TWI_MT_TX_TEMP
9
;-------------------------------------------------------------------------------
10
  ldi ZL,low (adr_BILD_BEREICH+0)
11
  ldi ZH,high(adr_BILD_BEREICH+0)
12
  rcall OLED_REFRESH_ZEILE
13
  ldi ZL,low (adr_BILD_BEREICH+1*128)
14
  ldi ZH,high(adr_BILD_BEREICH+1*128)
15
  rcall OLED_REFRESH_ZEILE
16
  ldi ZL,low (adr_BILD_BEREICH+2*128)
17
  ldi ZH,high(adr_BILD_BEREICH+2*128)
18
  rcall OLED_REFRESH_ZEILE
19
  ldi ZL,low (adr_BILD_BEREICH+3*128)
20
  ldi ZH,high(adr_BILD_BEREICH+3*128)
21
  rcall OLED_REFRESH_ZEILE
22
  ldi ZL,low (adr_BILD_BEREICH+4*128)
23
  ldi ZH,high(adr_BILD_BEREICH+4*128)
24
  rcall OLED_REFRESH_ZEILE
25
  ldi ZL,low (adr_BILD_BEREICH+5*128)
26
  ldi ZH,high(adr_BILD_BEREICH+5*128)
27
  rcall OLED_REFRESH_ZEILE
28
  ldi ZL,low (adr_BILD_BEREICH+6*128)
29
  ldi ZH,high(adr_BILD_BEREICH+6*128)
30
  rcall OLED_REFRESH_ZEILE
31
  ldi ZL,low (adr_BILD_BEREICH+7*128)
32
  ldi ZH,high(adr_BILD_BEREICH+7*128)
33
  rjmp  OLED_REFRESH_ZEILE
34
;-------------------------------------------------------------------------------
35
OLED_REFRESH_ZEILE:
36
  rcall OLED_REFRESH_BLOCK
37
  rcall OLED_REFRESH_BLOCK
38
  rcall OLED_REFRESH_BLOCK
39
  rcall OLED_REFRESH_BLOCK
40
  rcall OLED_REFRESH_BLOCK
41
  rcall OLED_REFRESH_BLOCK
42
  rcall OLED_REFRESH_BLOCK
43
  rcall OLED_REFRESH_BLOCK
44
  rcall OLED_REFRESH_BLOCK
45
  rcall OLED_REFRESH_BLOCK
46
  rcall OLED_REFRESH_BLOCK
47
  rcall OLED_REFRESH_BLOCK
48
  rcall OLED_REFRESH_BLOCK
49
  rcall OLED_REFRESH_BLOCK
50
  rcall OLED_REFRESH_BLOCK
51
  rjmp  OLED_REFRESH_BLOCK
52
;-------------------------------------------------------------------------------
53
OLED_REFRESH_BLOCK:
54
  LD temp1,Z
55
  adiw ZL,16
56
  LD temp2,Z
57
  adiw ZL,16
58
  LD temp3,Z
59
  adiw ZL,16
60
  LD temp4,Z
61
  adiw ZL,16
62
  LD temp5,Z
63
  adiw ZL,16
64
  LD temp6,Z
65
  adiw ZL,16
66
  LD temp7,Z
67
  adiw ZL,16
68
  LD temp8,Z
69
70
  sbiw ZL,60  ; -111
71
  sbiw ZL,51
72
;-------------------------------------------------------------------------------
73
  ldi temp9,8
74
OLED_REFRESH_BLOCK_s:
75
  LSR temp1
76
  ROR temp
77
  LSR temp2
78
  ROR temp
79
  LSR temp3
80
  ROR temp
81
  LSR temp4
82
  ROR temp
83
  LSR temp5
84
  ROR temp
85
  LSR temp6
86
  ROR temp
87
  LSR temp7
88
  ROR temp
89
  LSR temp8
90
  ROR temp
91
  rcall TWI_MT_TX_TEMP
92
  dec temp9
93
  brne OLED_REFRESH_BLOCK_s
94
ret

: Bearbeitet durch User
von Steffen H. (avrsteffen)



Lesenswert?

Bernhard S. schrieb:
> Um das gesamte Display zu löschen (clear) sind 1024 TWI/I2C Bytes zu
> schreiben.
>
> Bei 16MHz Takt, SCL 444,444kHz, gelingt das in 11,6ms.

11,6ms, da hast du dich wohl etwas vertan. Rein rechnerisch sind bei 
1024Bytes zu je 8Bits bei einer Bitzeit von 1/444,444kHz keine 11,6ms 
drin. Das wären dann ohne Overhead (Startadresse,Controll Byte, 
Adressierungsmode, Startadressen.., usw.) minimal (1024*8)/444444 = 
18,4ms ;)

Ich habe mal 2 Animierte Bilder angehangen, wo die beiden 
Adressierungsarten verdeutlicht werden.


Gruß Steffen

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Steffen H. schrieb:
> 11,6ms, da hast du dich wohl etwas vertan

Oh ja, die SCL Frequenz stimmt nicht, sie ist wesentlich höher als 
400kHz.

Hatte die Bit-Rate auf NULL gesetzt, allerdings lt. Datenblatt nicht 
empfehlenswert, daher die 11,6ms.

1.024Bytes, bei einer noch zulässigen Bitrate von 10 und 16MHz Takt habe 
ich 22,6ms gemessen

1
.equ TWI_BIT_RATE  =0        ; Bit-Rate              
2
.equ TWI_PRESCALER =0        ; Vorteiler: 0=1 1=4 2=16 3=64    
3
4
ldi temp, TWI_BIT_RATE
5
out TWBR, temp
6
7
ldi temp, TWI_PRESCALER
8
out TWSR, temp

Gruß Bernhard

: Bearbeitet durch User
von Jadiedeutschesprache (Gast)


Lesenswert?

Steffen H. schrieb:
> Ich habe mal 2 Animierte Bilder angehangen, wo die beiden
> Adressierungsarten verdeutlicht werden.

angehangen, angeschalten, aufgebauen, aufgezeichnen, eingekaufen,
frisch gewachsen, aufgeputzen, angekleben, eingebauen ....

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?


: Bearbeitet durch User
von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

Bernhard S. schrieb:
> 1.024Bytes, bei einer noch zulässigen Bitrate von 10 und 16MHz Takt habe
> ich 22,6ms gemessen

Hallo Bernhard
Das kommt schon eher hin. Das hab ich gestern nämlich auch geschafft. 
500kHz fTWI..
Und das Display hat sogar noch mitgespielt.

Bernhard S. schrieb:
> Kennt jemand Bezugsquellen für 128x128 RGB I2C TWI OLED Display?
>
> z.B. mit SSD1331

Ich habe mir bei ebay mal ein 1,5Zoll RGB OLED mit SPI und SSD1351 
geholt. Hat ca. 15€ gekostet. Die Adressierung ist bei diesem Display 
einfacher.
https://www.ebay.de/itm/283708847757

Kommst du mit deiner Pixelgenauen Adressierung weiter? Ich habe deine 
Bit/Byte Schubserei nicht mehr folgen können :)

Jadiedeutschesprache schrieb:
> Steffen H. schrieb:
>> Ich habe mal 2 Animierte Bilder angehangen, wo die beiden
>> Adressierungsarten verdeutlicht werden.
>
> angehangen, angeschalten, aufgebauen, aufgezeichnen, eingekaufen,
> frisch gewachsen, aufgeputzen, angekleben, eingebauen ....

Darüber hatte ich kurz mal nachgedacht
Ich fand es trollig

: Bearbeitet durch User
von Bernhard S. (bernhard)


Lesenswert?

Steffen H. schrieb:
> 500kHz fTWI..
> Und das Display hat sogar noch mitgespielt.

Und das ohne zusätzliche Widerstände gegen +5V, SDA und SCL am Display 
sind vermutlich relativ niederohmig.

Eine Strommessung Display-SCL gegen GND ergab 0,7mA.

R=U/I = 5V:0,7mA = 7k Widerstand,
und wenn dann noch der Pull-UP des Pins aktiviert ist, sind wir bei ca. 
5k.

Sind die Leitungskapazitäten klein, dann halten sich die 
Signalverfälschungen in Grenzen.

Oh, demnach können durchaus über 1,4mA Strom nur durch SCL und SDA
fließen, die Energiebilanz sieht etwas wacklig aus.


Steffen H. schrieb:
> Kommst du mit deiner Pixelgenauen Adressierung weiter?
Ist in Arbeit, ist aber kein Problem, bin noch mit der ASCII Darstellung 
beschäftigt.

Steffen H. schrieb:
> Darüber hatte ich kurz mal nachgedacht
> Ich fand es trollig

Wir dürfen nie nachdenken, wir müssen immer vordenken ;-)

https://www.mikrocontroller.net/attachment/489878/OLED_RGB_SSD1351.jpg

Ist leider SPI, TWI wäre mir lieber, benötigt weniger 
Anschlussleitungen,

Greta würde sich feuen.

: Bearbeitet durch User
von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Version4 mit ASCII Zeichensatz 8x12 und 16x8.

Das Display wird nur refresht, wenn sich im Bildspeicher etwas ändert,
spart Strom.

Strombedarf im Bild 16x24 ca. 6mA bei 5V.


Der Schriftfont ist in einer Tabelle hinterlegt und so konstruiert nach 
dem Motto, wie man es optisch sieht, so wird er auch auf dem Display 
dargestellt. Kann nach belieben einfach geändert werden.

Leider sind die beiden Fonts sehr speicherintensiv, momentan sind schon 
über 54% des Flashs belegt :(

Könnte man ev. in einem externen TWI-EEPROM ablegen :)



1
;-------------------------65 (h41) 'A'
2
.db 0b00000000,0
3
.db 0b00111100,0
4
.db 0b01000010,0
5
.db 0b01000010,0
6
.db 0b01000010,0
7
.db 0b01000010,0
8
.db 0b01111110,0
9
.db 0b01000010,0
10
.db 0b01000010,0
11
.db 0b01000010,0
12
.db 0b01000010,0
13
.db 0b00000000,0

: Bearbeitet durch User
von Thomas N. (tonevi)


Angehängte Dateien:

Lesenswert?

Hier mal als Diskussionsbeitrag meine OLED SSD1306 / SH1106 Assembler 
Routinen als Teil eins RDA5807 Radios mit ATtiny45.

- Thomas

von Bernhard S. (bernhard)


Lesenswert?

Thomas N. schrieb:
> ...RDA5807 Radios mit ATtiny45

Toll, Respekt!

Hättest Du noch eine Schaltung für uns?

Mir viel gleich eine Besonderheit auf, Du verwendest keinen virtuellen 
Bildschirmspeicher im SRAM, sondern konstruierst die Grafic direkt im 
Display.

Wo konntest Du dieses Radiomodul beziehen?

Wie sind die Empfangseigenschaften, besonders bei RDS-Empfang?

Was genau wird mit der "Initab" im OLED eingestellt?

Bernhard

: Bearbeitet durch User
von Thomas N. (tonevi)


Angehängte Dateien:

Lesenswert?

Anbei die Schaltung (geht aber eigentlich aus dem Listing hervor).
Die RDA5807 Module hatte ich vor ca. 1 1/2 Jahren via EBay erworben. Da 
findet man auch hiesige Lieferanten.

Die Module haben eine hohe Empfangsempfindlichkeit und liefern eine 
überraschend gute Klangqualität.

Von den RDS Signalen habe ich den Radiotext als Lauftext und die Uhrzeit 
decodiert (wie in dem Foto vom 21.01.2021 erkennbar ist). Außerdem wird 
bei Verkehrsfunk Durchsagen ein "!" eingeblendet.

Die doppelte Zeichengröße leite ich aus einer Tabelle durch Wiederholung 
der Pixel ab.

Eigentlich erlaubt die RDS Spezifikation EN50067 auch Fehlererkennung- 
und Korrektur der Datenübertragung. Meine Implementierung liefert aber 
nur die ungefilterten Rohdaten, was meist ganz brauchbar ist. Leider ist 
das englische Datenblatt an den entscheidenden Stellen hier 
unvollständig und aus dem chinesischen Programming Manual bin ich erst 
recht nicht schlau geworden ;) Ich vermute, dem RDA5807 fehlen hierzu 
auch einige Register. Da ist man mit dem Si4703 besser bedient. Hier 
habe ich noch ein paar weitere Erläuterungen: 
http://tneveling.bplaced.net/radiobasteln.html

von Steffen H. (avrsteffen)


Lesenswert?

Thomas N. schrieb:
> Hier mal als Diskussionsbeitrag meine OLED SSD1306 / SH1106 Assembler
> Routinen als Teil eins RDA5807 Radios mit ATtiny45

Ein sehr schönes Projekt. Vielen Dank dafür. Ich hab es mir soeben auf 
meine Liste geschrieben.
Ich mag auch deinen Programmierstil. Sehr übersichtlich und 
nachvollziehbar.

Wie du das mit der doppelten Schriftgröße machst find ich gut. Deine 
Multiplikation sehr schön gelöst. Mach ich auch lieber so wenn es eine 
2^x Multiplikation ist.

Wenn ich das richtig sehe hast du eine repeat Funktion in der 
Tastenabfrage integriert. Da du ja nur 3 Tasten verwendest, kannst du da 
mal bitte die einzelnen Funktionen (Menu) der Tasten zusammenstellen? 
Über Mode zeigst du ja die verschieden Menüs an, oder?

Toll gemacht!


Bernhard S. schrieb:
> Mir viel gleich eine Besonderheit auf, Du verwendest keinen virtuellen
> Bildschirmspeicher im SRAM, sondern konstruierst die Grafic direkt im
> Display.

Wenn man den Text oder was auch immer an Grafik immer in den 8Bit einer 
Spalte abbilden kann, wozu dann einen virtuellen Speicher? Ich habe 
diesen nur eingeführt wenn man echte Grafik zeichnen will. Denn dann 
muss man Pixelweise adressieren können und da wird es bei den Displays 
unmöglich ohne virtuellen Abbild. Denn man kann den Displayspeicher der 
kleinen OLED's nicht lesen!

Und genau da beginnt die Pixel und Bit Schubserei..

Siehe hier:
Beitrag "Re: [ASM] SSD1306 text library für oled displays + AVR 0- und 1-Series"

Versuche mal etwas anders - universeller - an die Textgenerierung heran 
zu gehen. Jetzt gerade baust du für jede Schrift/Font ein riesiges 
Konstrukt um diese in den virtuellen Speicher zu bringen.

Bitte nicht falsch verstehen Bernhard. Das soll keine Kritik sein, nur 
ein Hinweis.

Gruß Steffen

von Bernhard S. (bernhard)


Lesenswert?

Steffen H. schrieb:
> Versuche mal etwas anders - universeller - an die Textgenerierung heran
> zu gehen. Jetzt gerade baust du für jede Schrift/Font ein riesiges
> Konstrukt um diese in den virtuellen Speicher zu bringen.

Ok, ich suche nach einer Lösung :-)

Eventuell hilft eine Funktion "PSET_XY".

Momentan sind die Font-Tabellen so aufgenaut, daß sie einfach geändert 
werden können.

So wie ein Datensatz in der Tabelle sichtbar ist z.B. "C", so wird er 
auch auf dem Display dargestellt und genau das macht den Assemblercode 
komplizierter mit der "ASCII_BITUMKEHR_TEMP", Zeilen und Spalten müssen 
auch gezählt werden.

> Wie du das mit der doppelten Schriftgröße machst find ich gut. Deine
> Multiplikation sehr schön gelöst.

Eine Tolle Idee, den gerade mein Font mit doppelter Schriftgröße klaut 
viel Flash.

Ich schau mir das Schriftbild mit der Schriftverdopplung mal genauer an.

Bernhard

: Bearbeitet durch User
von Steffen H. (avrsteffen)


Lesenswert?

Bernhard S. schrieb:
> Eine Tolle Idee, den gerade mein Font mit doppelter Schriftgröße klaut
> mit viel Flash.

Man darf nicht vergessen, Thomas hat das alles in ein ATtiny45 bekommen.
4k Speicher und 128bit RAM !!!

Respect nochmal dafür..

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Version5 mit Punkt setzen und löschen XY.

Schaut Euch mal bitte die "PUNKT_SET_XY" Routine an, ob man die noch 
schneller machen kann, hier kommt es auf jeden Takt an, sonst dauert das 
Zeichen der von Figuren, wie Zeiger, Kreise, gefüllte Rechtecke ziemlich 
lange.

Bedingung die Register XYZ düfen nach verlassen der Routine nicht 
verändert werden, nur temp(R16),R0 und R1.

Im Bild "B2" ist im Hintergrund ein Sternenhimmel zu sehen, per 
ZUfallsgenerator werden Punkte gesetzt und gelöscht, sieht putzig aus 
:-)

Steffen H. schrieb:
> Thomas hat das alles in ein ATtiny45 bekommen

Dafür hat er auch von mir einen dicken Pluspunkt bekommen, das hat er 
sich verdient.


Nachtrag: push ZL, push ZH konnte ich ersetzen durch MOVW ZL_KOPIE,ZL.

Kostet allerdings 2 wertvolle Register :(

: Bearbeitet durch User
von Thomas N. (tonevi)


Lesenswert?

Ich bin noch ein paar Antworten schuldig geblieben:

>@Bernhard: Was genau wird mit der "Initab" im OLED eingestellt?

Wenn man sich auf die Einstellungen beschränkt, die nicht schon beim 
Reset als Standard
definiert sind, kommt man mit 5 Byte zur Initialisierung aus!

0x8D 0x14 Ladungspumpe aktivieren
0xAF Display einschalten
0xA1 Column 127 wird auf Segment 0 gemappt
0xC0 Normal Scan Direction

>@Steffen: Tasten & Menues

Die "Mode" Taste (nicht repetierend) schaltet zwischen "Volume" 
(Lautstärke), "Mute" (Stummschaltung) und "Seek" (Sendersuche) um. Ein 
entsprechender Text in der Mitte des Displays zeigt die aktuelle 
Einstellung.

Mit den Tasten "up" und "down" kann im Modus "Volume" die Lautstärke 
geändert werden (repetierend mit Balkenanzeige)

Im Modus "Seek" wird die Sendersuche aufwärts / abwärts gestartet (nicht 
repetierend).

Der zuletzt eingestellte Sender wird im EEPROM gespeichert und steht 
beim nächsten Einschalten wieder zur Verfügung.

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

@Thomas

ich schau mir gerade Deine Font-Tabelle an (8x8 Pixel),
so sieht nach meiner Meinung Dein "A" theoretisch mit Bitverdopplung aus 
8x16.

Kannst Du uns mal bitte ein Foto mit einem "A" senden.

Welchen Font-Generator verwendest Du?

Danke

: Bearbeitet durch User
von Thomas N. (tonevi)


Angehängte Dateien:

Lesenswert?

@Bernhard

Zeichensatz und hierzu passende OLED Init Sequenz wurde aus 
Beitrag "(sehr) kleines "FrameWork" für ATtiny44" (in C codiert) 
abgeleitet. Ich habe das Ganze zunächst auch in C auf einen ATtiny85 
portiert und dann in mehreren Iterationen auf Assembler umgestellt, den 
RDS Decoder ergänzt etc.

Die doppelte Zeichengröße ist aber auch in dem ursprünglichen C-Code 
schon vorzufinden. Die Pixel werden sowohl horizontal als auch vertikal 
dupliziert, so dass aus dem 8x8 Zeichen aus der Font Tabelle ein 16x16 
Zeichen entsteht (siehe Foto von dem gewünschten "A").

Damit ich da selbst später noch durchblicke hatte ich damals eine kleine 
Doku über die OLED Ansteuerung und die Verdopplung der Zeichengröße 
erstellt, die vielleicht weitere Fragen beantwortet.

von Frank D. (Firma: Spezialeinheit) (feuerstein7)


Lesenswert?

Bernhard S. schrieb:
> Könnte man ev. in einem externen TWI-EEPROM ablegen :)

Also da hätte ich noch eine Idee, wenn schon ein weiterer Chip im 
Gespräch ist, wie wäre es mit einen kleinen Attiny. Damit könnte 
gewissermaßen ein intelligentes Display gebaut werden.
Also in etwa so:
Auf die Displayplatine kommt ein Tiny der sich nur um die Oled-Steuerung 
kümmert. Dieser wiederum kann per I2C von einen anderen µC angesprochen 
werden. Dafür gibt es dann eine Befehlsliste, wie OLED_Init; 
SET_Curser....

von leo (Gast)


Lesenswert?

Bernhard S. schrieb:
> OLED_REFRESH_ZEILE:
>   rcall OLED_REFRESH_BLOCK
>   rcall OLED_REFRESH_BLOCK

Und beim naechsten mal lernen wir das voellig neue Konstrukt einer 
Schleife ...

SCNR, leo

von Steffen H. (avrsteffen)


Lesenswert?

Bernhard S. schrieb:
> Schaut Euch mal bitte die "PUNKT_SET_XY" Routine an, ob man die noch
> schneller machen kann, hier kommt es auf jeden Takt an, sonst dauert das
> Zeichen der von Figuren, wie Zeiger, Kreise, gefüllte Rechtecke ziemlich
> lange.

Hallo Bernhard
Ich hab es versucht - blicke aber bei deinem Algorithmus zur 
Adressierung nicht durch. Kann das sein, dass du das alles sehr 
kompliziert machst weil du dich so sehr auf die einfach ersichtliche 
Datenabbildund deiner Fontdaten konzentrierst?
In welchem Adressoerungsmode schreibst du denn die Daten zum Display?
Verikal oder Horizontal?
Bedenke bitte, dass selbst wenn deine Daten im RAM schön in - ich sag 
mal Reihe - Byte1,Byte2,..,ByteX im RAM liegt, kann es doch im Display 
trotzdem nur Senkrecht und nicht - wie von dir erzwungen - waagerecht 
abgebildet werden. Dies alles verkompliziert, meiner Meinung nach, die 
ganze Adressierung.
Denn wenn du ein Byte mit mehreren gesetzten Bits (Pixeln) hast rechnest 
du diese irgendwie erst in Byte|Bit um und setzt jedes Bit aus dem 
Ursprungsdatenbyte dann einzeln
im RAM. Das dauert doch alles viel zu lange.

@Thomas
Heute ist der Radio Empfänger gekommen. Bin voll in Bastellaune :)

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

@alle hat jemand eine Idee, wie man die Font-Tabelle komprimieren kann, 
um wertvollen Speicher zu sparen?


Thomas N. schrieb:
> eine kleine Doku über die OLED Ansteuerung und die Verdopplung der
> Zeichengröße erstellt

Es kommt nicht immer auf die Größe an, sehr gut gelungen, Daumen hoch!

Einen kleinen selbsgefummelten Visual-Basic Fontgenerator nutze ich 
gern.


leo schrieb:
>>   rcall OLED_REFRESH_BLOCK
>>   rcall OLED_REFRESH_BLOCK
> Und beim naechsten mal lernen wir das voellig neue Konstrukt einer
> Schleife ...

Hat Gründe. z.B. Schnelligkeit und Registerersparnis um pushen und popen 
zu ersparen, Vorbereitung auf Graficfähigkeit

Frank D. schrieb:
>> Könnte man ev. in einem externen TWI-EEPROM ablegen :)

Oder in einem internen EEPROM, ca.1k müsste er groß sein.


> Also da hätte ich noch eine Idee, wenn schon ein weiterer Chip im
> Gespräch ist, wie wäre es mit einen kleinen Attiny. Damit könnte
> gewissermaßen ein intelligentes Display gebaut werden.

Es wäre gut, wenn er eine Harware TWI besäße, ausgangsseitig kann das 
Display mit einer Software TWI angesteuert werden.

Für ASCII-Darstellung wäre das eine gute Idee.

Grafic, so wie in einem sehr teuren TFT:
Beitrag "Spektrumanalysator Frequenzspektrumanalysator Frequenzspektrometer Speki Wobbelgenerator TFT Atmega8"

Ein ATmega328p hätte genügend SRAM, um derartige Figuren zu zeichnen.


Steffen H. schrieb:
> Heute ist der Radio Empfänger gekommen. Bin voll in Bastellaune :)

Wo konntest Du ihn bestellen?

Ich wäre auch gern in derartiger Bastellaune :)

Steffen H. schrieb:
> Ich hab es versucht - blicke aber bei deinem Algorithmus zur
> Adressierung nicht durch.

Nicht schlimm, das ist auch nicht ganz einfach zu durchschauen, gebe ich 
echt zu, schlussendlich sollen solche Figuren entstehen:

Beitrag "NF Spectrum Analyzer selber bauen Eigenbau TV FBAS ATmega1284p Assembler low cost"

> Kann das sein, dass du das alles sehr
> kompliziert machst weil du dich so sehr auf die einfach ersichtliche
> Datenabbildund deiner Fontdaten konzentrierst?

Ja, die zu entstehende Grafic z.B. schräge Linien, muss später schnell 
errechenbar sein, sonst dauert die Figurendarstellung zu lange, das 
bereitet wenig Freude.

> In welchem Adressoerungsmode schreibst du denn die Daten zum Display?
> Verikal oder Horizontal?

Die Daten werden Vertikal geschrieben, aber horizontal im SRAM abgelegt.

Das Konstrukt
rcall OLED_REFRESH_BLOCK
rcall OLED_REFRESH_BLOCK
rcall OLED_REFRESH_BLOCK
...
dient dazu das horizontale flink in das vertikale umzuwandeln und zu 
senden. Es werden immer 8x8Pixel in einem Block zusammengefasst und dann 
dieser Block mit 8Bytes gesendet, so das Prinzip.


> Bedenke bitte, dass selbst wenn deine Daten im RAM schön in - ich sag
> mal Reihe - Byte1,Byte2,..,ByteX im RAM liegt, kann es doch im Display
> trotzdem nur Senkrecht und nicht - wie von dir erzwungen - waagerecht
> abgebildet werden. Dies alles verkompliziert, meiner Meinung nach, die
> ganze Adressierung.

Ja, Du hast Recht. Wenn Du ein 8Pixel breiten horizontalen Strich 
darstellen möchtest, brauchst Du nur ein SRAM Byte auf ffh setzen, den 
Rest erledigt die seltsam ausschauende "LED_REFRESH_BLOCK" Routine, die 
flott sein muss.

> Denn wenn du ein Byte mit mehreren gesetzten Bits (Pixeln) hast rechnest
> du diese irgendwie erst in Byte|Bit um und setzt jedes Bit aus dem
> Ursprungsdatenbyte dann einzeln
> im RAM. Das dauert doch alles viel zu lange.

Das erledigt alles die "LED_REFRESH_BLOCK" Routine, der gesamte Display 
Inhalt wird in 128 Blöcke unterteilt (8x8 Pixel), jeder Block besteht 
aus 8 vertikalen Bytes die an das Display gesendet werden.

Ich find Thorstens Font, gestreckt auf 8x16, auch ganz schick^^

Somit passen 16 große schlanke Asciis auf eine Zeile,

so wie die pummeligen^^

: Bearbeitet durch User
von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

@Thorsten

könntest Du, wenn's keine große Umstände macht, die Bits in Deinem Font 
tauschen Bsp: 0b00000001 ---> 0b10000000

Momentanes Bitgefummle:
1
  clr temp
2
  sbrc temp1,0    ;Skip if Bit in Register Cleared
3
  ori temp,0b10000000
4
  sbrc temp1,1    ;
5
  ori temp,0b01000000
6
  sbrc temp1,2    ;
7
  ori temp,0b00100000
8
  sbrc temp1,3    ;
9
  ori temp,0b00010000
10
  sbrc temp1,4    ;
11
  ori temp,0b00001000
12
  sbrc temp1,5    ;
13
  ori temp,0b00000100
14
  sbrc temp1,6    ;
15
  ori temp,0b00000010
16
  sbrc temp1,7    ;
17
  ori temp,0b00000001
Danke

PS: die 3 Schriftgrößen, generiert aus einem Font, sehen vernünftig aus, 
finde ich.

: Bearbeitet durch User
von Thomas N. (tonevi)


Angehängte Dateien:

Lesenswert?

@ die Radiobastler:

Hier noch ein kleines Update meines Assembler Codes zur Korrektur der 
Zeitzone beim RDS Decoder. Wie gesagt hatte ich das Ganze zunächst in C 
programmiert und erst danach in Assembler. Meinen C-Code findet ihr 
hier:
Beitrag "Re: DIY UKW-Receiver mit Padauk PFS154 und RDA5807"

Läuft auf der gleichen Hardware und passt immer noch in einen ATtiny45.

von Steffen H. (avrsteffen)


Lesenswert?

Bernhard S. schrieb:
> Steffen H. schrieb:
>> Heute ist der Radio Empfänger gekommen. Bin voll in Bastellaune :)
>
> Wo konntest Du ihn bestellen?
>
> Ich wäre auch gern in derartiger Bastellaune :)

Tja, schön wäre es gewesen, aber das Modul funktioniert nicht. Echt 
schade. Ich hab es geahnt als ich es ausgepackt habe. Da war schon 
Lötzinn an dem Vcc und GND Anschluss. Da konnt ich es mir schon denken. 
Der Empfänger gibt immer ein NACK zurück. Ist also nicht ansprechbar.
Ich hab dem Verkäufer heute eine Mail geschickt. Er will mir umgehend 
ein Ersatz schicken.

Na dann heißt es wieder warten..


@Bernhard:
Das RAD5807M Modul hatte ich bei ebay bestellt. Es gibt da mehrere 
Anbieter in Deutschland, die diese Vorrätig haben für wenig Geld (ca. 
4€, Versand kostenlos im Brief).
https://www.ebay.de/itm/Mini-I2c-Stereo-FM-Radio-Modul-RDA5807M-RRD-102V2-0-fur-Arduino-Raspberry-Pi-DIY/171832050685?_trkparms=ispr%3D1&hash=item2801fd03fd:g:GNoAAOSwsB9WCNIe&amdata=enc%3AAQAFAAACcBaobrjLl8XobRIiIML1V4Imu%252Fn%252BzU5L90Z278x5ickkSG%252BOFgrj2Yvbvmrj2TAdMztoD3pA0tr5%252BY6r7O%252Bh2XECOSTrjQBwSB2WWLr3pknDhiZt3rJXljxUPZZXgQ8UeKw%252BX35o8Wgvl9jjRTqurYxHkyijnbElUK1EQjpNXSxiZWo1zqnm2RDjZ3O4NrXNh%252Bk%252FrJF6jYvV25hnpHzFAoJaKOSaUBYvHiJh6GM3i6cStYzUep2Qodf4D5KCW3ZpD669VthtV32Bi6pee%252FORcs%252FxDqCLDfgFb0Mdq8e1DbdPATjORg5U21JTCi9geTapWw3pMRj30UvuSMx1KPmozluPhdfciev8xU74LyWJ1aOnp4iExP3AYTpqBCbUi5jqObyWGgcpfGv69d4AUPGHN1RBafYbbb913GocQpaqD1HRH8WXDSWVM7NvR6efh1XouNFLRs%252FJhDvjbsR72K5im7nbozIR6tl5M6AJw9OrjHBQxSk7priHp%252BKXjymiEfk%252BTxown1E%252BTehI8gA5XwNrZ5tiZ%252B%252FHsLFHGEpe8ZYbIfR7QW3lYY%252FSDuP7rOSnOq%252Bf8XlEdY7%252BA8Iu7sTwJQvPyx6%252BZgOKXKvrVPO7xKjUi5hHK3VWafv6NbnL46z3ADGae7s%252Fkl4W5mQQBpx54RCrL2PQASiU52%252BZSR1Ff3Z03jrgFOk6kc0cbH6r7Ija8ag0lg%252FWSPca3XRtzSLuhTNsJ0fS%252FkjQD2WlcnbAOVCjpijr5fDM1Y65coXF%252Fp8FX7DuD4TPHS1bv%252FOsc83qOj8UKf0MWUsDNuP2LulGHUSJGxghMrQcrwhDmlbJo4A0aemLYQ%253D%253D%7Ccksum%3A1718320506851f309b3836904b2b946f2ff38d80a274%7Campid%3APL_CLK%7Cclp%3A2334524
oder
https://www.ebay.de/itm/RDA5807-FM-Radio-Empfanger-Modul-V2-0-I2C-ESP8266-ESP32-STM-32-Arduino-Raspberry/284124772008?hash=item422727f6a8:g:7fUAAOSwhadf4yAX

von Steffen H. (avrsteffen)


Lesenswert?

Bernhard S. schrieb:
> @Thorsten
>
> könntest Du, wenn's keine große Umstände macht, die Bits in Deinem Font
> tauschen Bsp: 0b00000001 ---> 0b10000000

Du reitest dich immer tiefer rein und verkomplizierst alles. Oha, ich 
glaub das Wort gibt es gar nicht, aber egal. Ich sagte schon, du musst 
umdenken. Wenn du erst eine Linie oder sogar einen Kreis nach Bresenhan 
zeichnen willst wird das ganze Ausmaße annehmen und langsam werden.

Bernhard S. schrieb:
> PS: die 3 Schriftgrößen, generiert aus einem Font, sehen vernünftig aus,
> finde ich.

Find ich auch.


@Thomas -> Danke für deine Codes

: Bearbeitet durch User
von Bernhard S. (bernhard)


Lesenswert?

Steffen H. schrieb:
> Du reitest dich immer tiefer rein und verkomplizierst alles.

Du hast bestimmt für den Grafic-Modus bessere Ideen,
lass es uns wissen :-)

> Wenn du erst eine Linie oder sogar einen Kreis nach Bresenhan
> zeichnen willst wird das ganze Ausmaße annehmen und langsam werden.

Ja, es wird langsamer, aber möglich, eine Uhr mit Sekundenzeiger ist der 
Prüfstein, die alte Zeigerstellung muss berechnet und gelöscht, die 
neue Zeigerstellung berechnet und gezeichnet werden und so ganz nebenbei 
ein FBAS-Bild generiert werden, ein 22MHz getakteter AVR kommt dabei 
ganz schön in's Schwitzen.

: Bearbeitet durch User
von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Version6, eine kleine Spielerei^^

B0 Begrüßung
B1 verfügbare Schrift-Fonts Font0, Font1, Font2
B2 TWI-Scanner, momentan nur h3c (Display am Bus)
B3 Zeit für ein Display-Clear
B4 Uhrzeit, Zeit für diese Anzeige, Betriebsspannung, Frequenzzähler
B5 oh Schreck, der ATmega8 ist schon zu 48% belegt

Die größeren Fonts sind etwas rechenintensiver, 32 Bytes SRAM werden 
benötigt.

Zuerst wird der obere Teil des ASCII-Zeichens (8 oder 16Bytes) 
gezeichnet, anschließend der untere.

Hat den Vorteil, dass nicht ständig die zeitintensive "OLED_GOTO_XY" 
aufgerufen werden muss.

Ein gut gefülltes Display s. "B4" benötigt ca, 84ms. Könnt Ihr mal bei 
Euch nachmessen?

Wenn die Bitrate auf die nicht empfehlenswerte 1 gesetzt wird sind es 
nur noch 48ms.

PS: Momentan versuche ich den Code für schnelle Darstellung zu 
optimieren.

: Bearbeitet durch User
von Steffen H. (avrsteffen)


Lesenswert?

Bernhard S. schrieb:
> Ja, es wird langsamer, aber möglich, eine Uhr mit Sekundenzeiger ist der
> Prüfstein, die alte Zeigerstellung muss berechnet und gelöscht, die neue
> Zeigerstellung berechnet und gezeichnet werden und so ganz nebenbei ein
> FBAS-Bild generiert werden, ein 22MHz getakteter AVR kommt dabei ganz
> schön in's Schwitzen.

Da hast du dir aber ganz schön was vorgenommen.
Wegen der Uhr, wenn man genug RAM an Bord hat kann man mit mehreren 
Layern arbeiten. Das Ziffernblatt kann man in einem Layer halten und die 
Zeiger dann in einem Anderen.
Falls du dich fragst, Warum? Der Gedanke dahinter ist folgender:
Wenn du den Zeiger zum Beispiel über das Ziffernblatt oder eine Ziffer 
zeichnest (Sekundenzeiger), dann ist das ja kein Problem. Löscht du 
diesen aber nun um den nächsten zu zeichnen, dann löscht du auch dein 
Ziffernblatt oder Ziffern an der Stelle wo vorher der Zeiger war.

Bernhard S. schrieb:
> Du hast bestimmt für den Grafic-Modus bessere Ideen, lass es uns wissen
> :-)

Ich hab das schon alles hinter mir. Wie schnell meine Routinen bei einem 
einzelnen Pixel sind, hab ich noch nicht verifiziert. Aber den Schriften 
bin ich schnell und sehr flexiebel. Die Fonts sind gepackt. Das bedeutet 
zwar mehr rechnen aber das geht schon. Dabei bediene ich mich der 
Tatsache, das verschiedene Zeichen verschiedene Pixelweiten haben und 
somit nicht mit konstanter Datenbreite pro Zeichen als Fontdaten 
gespeichert werden muss.
Zum Beispiel:
Ein "I" ist schmaler als ein "W".  Außerdem benötigt man eher selten den 
kompletten ASCII Zeichensatz (256 Zeichen). Ich fange zum Beispiel erst 
beim Leerzeichen (0×20) an und dann bloß 96 Zeichen bis zum Charter 127 
(~). Das spart Platz im Speicher.
Dazu gibt es dann zu jedem Font einen Daten Header (Kopf) wo die feste 
Pixelhöhe der Zeichen, den Charcode des ersten Zeichens der Chardaten 
und die Anzahl der Zeichen für die Daten vorliegen. Bevor jetzt die 
eigentlichen Daten der Zeichen kommen, ist da noch ein Datensatz zu den 
Pixelbreiten jedes einzelnen Zeichens. Also bei 96 Zeichen sind das dann 
auch 96 Bytes. Danach beginnen die Daten für die einzelnen Zeichen.

Ich könnt noch mehr darüber schreiben, aber das wäre dann wohl eher was 
für eine Bachelor Arbeit oder einen Artikel hier im Forum.

Ich hoffe ich habe dich/euch nicht verwirrt.

von Steffen H. (avrsteffen)


Lesenswert?

@Bernhard
Aber die 3 verschiedenen Schriftgrößen aus ein und demselben Datensatz 
sieht gut aus. Vielleicht werde ich auch noch eine abgespeckte 
Textversion meiner Lib bauen.

Übrigens, wenn du deine RAM Variablen mal anders deklarieren würdest, 
dann siehst du auch deinen RAM Verbrauch..

Statt:
1
.equ  adr_DATEN           = SRAM_START+0
2
.equ  adr_ss10               = SRAM_START+10
3
.equ  adr_ss                    = SRAM_START+11
gibt man einfach die Anzahl zu reservierender Bytes der Daten an. Der 
Name bleibt erhalten.
Und zwar so:
1
.dseg
2
.org SRAM_START
3
adr_DATEN:                .BYTE 10    ; reserviere 10 Bytes im SRAM
4
adr_ss10:                    .BYTE 1      ; reserviere 1 Byte
5
adr_ss:                        .BYTE 1      ; reserviere 1 Byte
6
....
7
....
8
.org SRAM_START+99
9
adr_SRAM_CHECK_A:     .BYTE 1
10
adr_BILD_BEREICH:         .BYTE 1024-1
11
adr_BILD_BEREICH_ENDE:   .BYTE 1024
12
adr_SRAM_CHECK_B:     .BYTE 1
13
14
.org SRAM_END
15
adr_SRAM_CHECK:         .BYTE 1
Das sind alles Hilfen des AVR Assemblers..

MfG
Steffen

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

@Bernhard
Sag mal, bist jetzt doch wieder zurück auf einen ATmega8 gewechselt???

Laut deinem letztem Post habe ich einen ATmega328 verwendet und nur 
Fehlermeldungen bekommen. Dann hab ich entdeckt, dass du da einen Mega8 
eingebunden hast und du alles nicht mehr über ein im RAM angelegten 
virtuellen Displayspeicher machst.

Wie gesagt, bei Schrift mit vordefinierter Zeichenhöhe von 8,16,24,32,.. 
Pixeln geht das noch. Bei Linien und anderen grafischen Funktionen bin 
ich schon gespannt wie du das machen willst.

Ich hab dein letzten Post (Version6) für einen ATmega328 umgestrickt und 
getestet. Läuft gut. Auch wenn die Error LED ständig leuchtet. Warum 
auch immer..

Ich habe auch die Zeit zum Display löschen mit einem LA kontrolliert. 
45,79ms hab ich gemessen. Stimmt also.

Was ich auch noch nicht verstanden habe sind deine Variablen 
SRAM_CHECK_ und _BILD_BEREICH_ENDE ?
Wozu sind die gut?

MfG Steffen

: Bearbeitet durch User
von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

Hier noch die geänderten Dateien

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Version-7, Achtung wieder ATmega328p

ASCII, Punkte, Linien, gerade und schräge.

B0 freundliche Begrüßung mit Helligkeitsänderung
B1 Zeitmessung für OLED-Clear
B2 Zeitmessung für 1s Wait, die 1ms Timerinterrupts bremsen die
   Warteschleifen aus
B3 Linienbeispiele
B4 Zeit, Zeit Bildberechnung mit Refresh des Displays
   Betreibsspannung, OLED 1Bytes auslesen


Nun macht sich der "seltsame" Aufbau des SRAMs bezahlt, die Berechnung 
der Linien ist relativ einfach.

Die Koordinaten für X1, Y1, X2, Y2 sind in den Registern R2 bis R5 
hinterlegt.

Linienberechnung:
Zuerst wird untersucht, ob es senkrechhte oder waagerechte Linen sind, 
diese lassen sich sehr flott berechnen.

Bei den schrägen linien wirds komplizierter, hier untersuche ich den 
Anstieg, ob positiv oder negativ. Anschließend wird die Linie 2x 
gezeichnet, beim ersten Durchgang wird X hochgezählt und Y berechnet, 
beim zweiten Y hochezählt und X berechnet, damit auch sehr flache und 
sehr steile Linien ohne Lücken gezeichnet werden, sonnst sieht etwas 
komisch aus.

Steffen H. schrieb:
> Was ich auch noch nicht verstanden habe sind deine Variablen
> SRAM_CHECK_ und _BILD_BEREICH_ENDE ?
> Wozu sind die gut?

SRAM_CHECK dient zur Programmüberwachung, wenn dieses Byte überschrieben 
wird, warum auch immer, blinken die LEDs wie wild.

BILD_BEREICH_ENDE... Dummy, keine Bedeutung mehr

> Übrigens, wenn du deine RAM Variablen mal anders deklarieren würdest,
> dann siehst du auch deinen RAM Verbrauch..

Da hast Du Recht, gib mir angemessen Zeit, um mich daran zu gewöhnen, 
danke für den Tipp


> Dann hab ich entdeckt, dass du da einen Mega8
> eingebunden hast und du alles nicht mehr über ein im RAM angelegten
> virtuellen Displayspeicher machst.

Und nun ist es wieder ein ATmega328p.

> Wegen der Uhr, wenn man genug RAM an Bord hat kann man mit mehreren
> Layern arbeiten.

Das stimmt, ist aber in diesem Fall nicht erforderlich, Linien bzw 
Zeiger lassen sich sehr schnell zeichnen, wenn der jedes mal der 
Bildbereich im SRAM gelöscht wird, die Uhr dann komplett neu berechnet 
und anschließend das Display refresht wird, dann sieht das richtig 
schick aus, selbst mit einem Sekundenzeiger.

Steffen H. schrieb:
> Ein "I" ist schmaler als ein "W".
> Dazu gibt es dann zu jedem Font einen Daten Header (Kopf)

Man könnte auch im Programm diese Header-Daten berechnen, d.h. ein "i" 
wird aus einem Standart-Font geladen un dann untersucht, auf welche 
Spalten könnte man versichten, damits noch schöner aussieht :-)

Dieser Assemblercode besitzt noch eine Menge Optimierungspotential, 
momentan steht die Zeichengeschwindigkeit im Vordergrund^^

Bernhard

: Bearbeitet durch User
von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Steffen H. schrieb:
> Ich habe mir bei ebay mal ein 1,5Zoll RGB OLED mit SPI und SSD1351
> geholt. Die Adressierung ist bei diesem Display
> einfacher.

Sieht auch schick aus :-)
https://www.mikrocontroller.net/attachment/489878/OLED_RGB_SSD1351.jpg

@Steffen,

nun ist auch bei mir ein solches SSD1351 Display eingetroffen, noch ist 
es dunkel, hättest Du ein Assembler-Beispiel und eine Schaltung für uns?

Ein hex-File für einen ATmega8 wäre schön, um wenigstens die Hardware zu 
testen.

So mehr ich mich mit diesem OLED 128x128 RGB Color Farbe theoretisch 
beschäftige, um so mehr Fragen ergeben sich z.B.

- Betriebsspannung max wirklich nur 3,3V?
- Welche Pins müssen wie beschaltet werden?
- muss Reset beschaltet werden?
- wie erfolgt die Initialisierung?

Da das Display nicht ausgelesen werden kann, wäre z.B. der Betrieb einer 
SD-Card am SPI-Bus ohne Aufwand möglich.

Danke

Bernhard

: Bearbeitet durch User
von Steffen H. (avrsteffen)



Lesenswert?

Bernhard S. schrieb:
> nun ist auch bei mir ein solches SSD1351 Display eingetroffen, noch ist
> es dunkel, hättest Du ein Assembler-Beispiel und eine Schaltung für uns?
>
> Ein hex-File für einen ATmega8 wäre schön, um wenigstens die Hardware zu
> testen.

Ich mache nicht mehr viel mit den uralten AVR wie dem Mega8. Ich habe 
mich jetzt vollkommen auf die neuen AVR der Serie-0 und Serie-1 
eingeschossen. Da ich vorher schon einiges mit den Xmegas vorher zu tun 
hatte, war es nicht so schwer sich in die neue Architektur 
einzuarbeiten.
Außerdem benötigen die neuen AVR nur noch eine einzige Ader (und GND 
natürlich) um diese zu programmieren und zu debuggen! Nennt sich UPDI.

Ich habe mir meinen eigenen UPDI Programmer/Debugger selber gebaut. Aus 
einem Arduino Micro. Firmware drauf und schon hat man einen UPDI 
Programmer/Debugger.

Ich hab dir aber mal ein Testfile für einen ATtiny1614 dran gehangen. Da 
kannst dir wenigstens die Initialisierung raus suchen. Ach ja, mit dabei 
sind ein paar pdf Dokumente.

Bernhard S. schrieb:
> So mehr ich mich mit diesem OLED 128x128 RGB Color Farbe theoretisch
> beschäftige, um so mehr Fragen ergeben sich z.B.
>
> - Betriebsspannung max wirklich nur 3,3V?
JA!

> - Welche Pins müssen wie beschaltet werden?
CLK, DIN, CS, DC, RESET, GND, Vcc
Also alle!

> - muss Reset beschaltet werden?
JA

> - wie erfolgt die Initialisierung?
Siehe ZIP-File



Mfg Steffen

von Steffen H. (avrsteffen)


Angehängte Dateien:

Lesenswert?

Bernhard, ich hab hier mal eine .hex Datei für einen ATmega328 mit einer 
Testsequenz zum SSD1351 aus Arduino erstellt. Wenn du diesen mit nur 
3,3V und 8MHz betreibst, sollte das doch auch ohne Level Shifter gehen.

In einen Mega8 passt das ganze schon nicht mehr hinein.

MfG Steffen

von Olaf (Gast)


Lesenswert?

> Das Display wird nur refresht, wenn sich im Bildspeicher etwas ändert,
> spart Strom.

Ein kleiner Tip:

Ich mach das so das ich den Bildspeicher aufteile. Zum Beispiel in 
4Segmente und 8Pages. Dann ist ein solches Segment nur 32Byte gross. 
(bei 128x64Pixel) Ausserdem hab ich noch ein paar Byte in dem ich mir 
merke wenn sich in einem Segment etwas gaendert hat.
Dann macht man einen Ticker-IRQ und sorgt dafuer das alle 5ms ein 
Segment uebertragen wird wenn es sich geaendert haben sollte. Dadurch 
hat man in der Praxis kaum Datenuebertragung zum Display da sich selten 
viel aendert und trotzdem wirkt das Display extrem responsiv.

Olaf

zusatztip: Seit kurzem findet man immer mehr Oled (1.3") mit dem SH1106. 
Der ist fast baugleich zum SSD1306, lediglich die Uebergabe der 
Columnadresse braucht einen anderen Befehl.

von Pat B. (pat_b)


Lesenswert?

Olaf schrieb:
> zusatztip: Seit kurzem findet man immer mehr Oled (1.3") mit dem SH1106.
> Der ist fast baugleich zum SSD1306, lediglich die Uebergabe der
> Columnadresse braucht einen anderen Befehl.

Könnten wir einmal einen aktuellen Benchmark im Vergleich zur Adafruit 
Library bekommen? Der Charme der Adafruit Library ist: extrem 
umfangreicher Funktionsumfang, sehr viele Displays werden unterstüzt, 
und das API ist (fast) identisch für verschiedene Displays, was 
Portierung auf unterschiedliche Display extrem einfach macht... 
minimalste Sourcecode-Änderungen.

Ich frage mich halt, ob der Performanz-Vorsprung den man durch diese 
Library evtl. erreicht (gegenüber Adafruit Libraries) den Zeitaufwand 
rechtfertigt. Eine Entscheidungshilfe wäre nett!

: Bearbeitet durch User
von Steffen H. (avrsteffen)


Lesenswert?

Pat B. schrieb:
> Ich frage mich halt, ob der Performanz-Vorsprung den man durch diese
> Library evtl. erreicht (gegenüber Adafruit Libraries) den Zeitaufwand
> rechtfertigt. Eine Entscheidungshilfe wäre nett!

Ich denke nicht, dass das entwickeln eines Treibers für die kleinen OLED 
Dinger etwas mit Performance als Entscheodungshilfe zu tun hat.
Auch wenn Bernhard immer schreibt wie schnell doch seine Routinen sind. 
Der Hauptgrund ist sicherlich dies selber mal gemacht zu haben um das 
"Dahinter" zu verstehen. Es in Assembler zu machen und nur das zu 
implementieren, was man auch wirklich braucht! Und nicht so eine 
aufgeblasene Bibliothek in C oder C++. Auch wenn die Bibliotheken 
wirklich gut sind.
Bestes Beispiel ist das RDS Radio mit OLED und ATtiny45 !

MfG Steffen

: Bearbeitet durch User
von Olaf (Gast)


Lesenswert?

> Ich denke nicht, dass das entwickeln eines Treibers für die kleinen OLED
> Dinger etwas mit Performance als Entscheodungshilfe zu tun hat.

Doch, aber nicht so wie man zuerst denkt. Keiner wird den Treiber fuer 
ein 128x64 Pixel Display so optimieren eine moeglichst hohe Framerate zu 
schaffen damit er damit Videos darstellen kann. Aber es gibt andere 
Optimierungsziele.

1. Mir ist es heute wichtig das mein (eigenes!) printf moeglichst 
schnell ist. Damit kann es auch mal in zeitkritischen Funktionen 
verwenden. (Z.b fuer Diagnosezwecke in einem PID)

2. Mir war es frueher mal wichtig das meine LCD Ansteuerung moeglichst 
wenig Ram hatte weil meine Controller nur 1-2kb hatten. (Bufferram war 
gepackt)

3. Im professionellem Bereich kann Redundanz interessant sein. Wenn du 
sagen wir mal alle 100ms das Display neu initialisiert dann ist es nicht 
schlimm wenn der LCD-Controller beim ESD Test abstuerzt.

4. Bei manchen Anwendungen will man das moeglichst selten auf ein 
Display geschrieben wird weil der Controller moeglichst lange im 
Sleepmode sein soll damit die Batterie so lange wie moeglich haelt.

Diese Ziele widersprechen sich. Deshalb ist die Verwendung von fertigen 
Libaries anderer Leute immer schlechter als was eigenes zu machen. 
Ausnahmen gibt es nur dort wo man massiv mit unbekannter Hardware im 
Kontakt kommt. (SD-Karten, Bluetooth)

Olaf

von Michael W. (Gast)


Lesenswert?

Olaf schrieb:

> Diese Ziele widersprechen sich. Deshalb ist die Verwendung von fertigen
> Libaries anderer Leute immer schlechter als was eigenes zu machen.
> Ausnahmen gibt es nur dort wo man massiv mit unbekannter Hardware im
> Kontakt kommt. (SD-Karten, Bluetooth)

Sofern man unendlich viel Zeit hat sich mit Problemen zu beschäftigen, 
die andere schon vor Jahrzehnten gelöst haben, UND wenn die Hardware 
nicht sonderlich komplex ist, ist das natürlich richtig. Am Besten baut 
man sich auch noch seinen eigenen Computer dann, dann kommt man richtig 
schnell vom Fleck (sofern man denn auch noch die Zeit hat, das Rad neu 
zu erfinden) :-D

von Olaf (Gast)


Lesenswert?

> Sofern man unendlich viel Zeit hat sich mit Problemen zu beschäftigen,
> die andere schon vor Jahrzehnten gelöst haben, UND wenn die Hardware

Du hast ein Verstaendnisproblem. Andere haben vor Jahrzehnten genau ihr 
Problem geloest. Fuer dich haben sie nur eine Loesung der zweiten Wahl. 
Zweite Wahl mag manchmal ausreichend sein, aber nicht immer. Hinzu kommt 
das Leute die es sich angewoehnen immer nur die zweite Wahl zu verwenden 
niemals die Faehigkeiten entwickeln selber etwas auf die Beine zu 
stellen. Ich sehe ja sogar oft Leute welche die Libaries anderer Leute 
verwenden die derart dumme Fragen stellen das klar ist das sie da noch 
nicht mal versucht haben reinzuschauen, vom echten Verstaendnis sind sie 
dann noch meilenweit entfernt. Das schafft dann auch irgendwie Probleme. 
.-)

Olaf

von Michael W. (Gast)


Lesenswert?

Olaf schrieb:
>> Sofern man unendlich viel Zeit hat sich mit Problemen zu beschäftigen,
>> die andere schon vor Jahrzehnten gelöst haben, UND wenn die Hardware
>
> Du hast ein Verstaendnisproblem.

Ach ja, jetzt wird wieder selektiv zitiert... nein habe ich nicht. Ich 
verstehe genau was Du meinst, und wie gesagt, wenn die Hardware 
hinreichend einfach gestrickt ist, kann man mit halbwegs vertretbarem 
Aufwand so einen Treiber auch noch in Assembler machen. Damals haben ein 
Freund und ich unseren eigenen VGA Graphik-Treiber bzw. schnellen 
Linienalgorithmus (Bresenham) für TopSpeed Modula 2 in Assembler auf dem 
PC programmiert (1992?), weil das mitgelieferte Zeug von TopSpeed zu 
lahm war für mein selbstgeschriebenes CAD-Programm.

Allerdings ist Dein Anspruch "ich mache alles selbst, alles ist besser 
was ich mache!" nicht realistisch. Du hast wohl nicht verstanden, über 
wieviele Abstraktionsebenen wir heutzutage operieren. Ohne Abstraktion 
geht GAR NIX mehr heutzutage. D.h., Libraries und Layers and Layers and 
Layers and Layers of abstraction. Für triviales Zeug braucht man das 
nicht, da gebe ich Dir Recht!

Es war nicht meine Absicht, Deinen Treiber schlecht zu machen. Deine 
Aussage in dieser Allgemeinheit ist allerdings Müll.

Wie gesagt, der ANSPRUCH hinter die Dinge auf der untersten Ebene zu 
schauen, und selbst einen kleinen Treiber in Assembler für ein nicht 
sehr kompliziertes Device zu schreiben, ist sicherlich ehrenwert. Aber 
SKALIERBAR für ECHTE SYSTEME is dieser Vorgehen bzw. Anspruch - mit 
vertretbarem Zeitaufwand für Projekte in der Praxis - eben nicht. 
Lobenswert ist es natürlich, es dennoch zu machen. Würde ich meine Zeit 
lieber in etwas anderes stecken? Bestimmt :-)

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

@Steffen,

Danke für Dein Testprogramm, es funktionierte auf Anhieb.

Was mich wunderte, der ATmega328p scheint schon total vollgepackt zu 
sein, bleibt da noch Platz für weiteres, oder ist das nur der 
OLED-Treiber?

Mit Deinem Test-Programm konnte ich mich noch nicht beschäftigen, hab's 
aber schon auf dem Radar.

Kannst Du uns mal ganz grob erklären, wie ein farbiger Balken entsteht, 
schließlich müssen die Farbwerte auch mit übertragen werden.

Danke

Steffen H. schrieb:
> Wenn du diesen mit nur
> 3,3V und 8MHz betreibst, sollte das doch auch ohne Level Shifter gehen.

Notfalls ist dieser durch Widerstände schnell zusammengefriemelt.

Vorsichtshalber werde ich an das Display eine 3,3V Z-Diode anschließen, 
es könnte ev. sein, daß der AVR-Rogrammer über SPI eine Spannung über 
SPI einspeist, wie empfindlich der SSD1351 ist, kann ich nicht 
einschätzen.

Olaf schrieb:
> Dann macht man einen Ticker-IRQ und sorgt dafuer das alle 5ms ein
> Segment uebertragen wird wenn es sich geaendert haben sollte. Dadurch
> hat man in der Praxis kaum Datenuebertragung zum Display da sich selten
> viel aendert und trotzdem wirkt das Display extrem responsiv.

Ein sehr guter Tipp :-)

Damit befindet sich zwar der µC eine gewisse Zeit in der 
Interrupt-Routine, aber für einige Anwendungen sicherlich gut geeignet.


PS: Wer Assembler, klein und verdammt schnell, nicht mag, kein Problem 
<ALT+F4> hilft garantiert ^^

: Bearbeitet durch User
von Michael W. (Gast)


Lesenswert?

Bernhard S. schrieb:

> Linienberechnung:
> Zuerst wird untersucht, ob es senkrechhte oder waagerechte Linen sind,
> diese lassen sich sehr flott berechnen.
>
> Bei den schrägen linien wirds komplizierter, hier untersuche ich den
> Anstieg, ob positiv oder negativ. Anschließend wird die Linie 2x
> gezeichnet, beim ersten Durchgang wird X hochgezählt und Y berechnet,
> beim zweiten Y hochezählt und X berechnet, damit auch sehr flache und
> sehr steile Linien ohne Lücken gezeichnet werden, sonnst sieht etwas
> komisch aus.

Da würde ich Dir den Bresenham empfehlen. Auch da braucht man das Rad 
nicht neu erfinden (und schneller als da geht's auch nicht...):

https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm

>> von Olaf (Gast)
> Du hast ein Verstaendnisproblem. Andere haben vor Jahrzehnten genau ihr
> Problem geloest. Fuer dich haben sie nur eine Loesung der zweiten Wahl.

Ist das so? Wahrscheinlich ist das so eine Art Geheim-Wissenschaft, wie 
man den Bresenham in Assembler implementiert?

von Bernhard S. (bernhard)


Lesenswert?

Michael W. schrieb:
> Da würde ich Dir den Bresenham empfehlen.

Erklär uns mal bitte einfach diesen Algorithmus.

An einer ganz flachen Linie: Linie X1,Y1=0,0 nach X2,Y2=127,1

Vielleicht ist dann die Umsetzung in ASM gar nicht so schwer.

Würde mich interessieren.

: Bearbeitet durch User
von Michael W. (Gast)


Lesenswert?

Bernhard S. schrieb:
> Michael W. schrieb:
>> Da würde ich Dir den Bresenham empfehlen.
>
> Erklär uns mal bitte einfach diesen Algorithmus.
>
> An einer ganz flachen Linie: Linie X1,Y1=0,0 nach X2,Y2=127,1
>
> Vielleicht ist dann die Umsetzung in ASM gar nicht so schwer.
>
> Würde mich interessieren.
1
x0 = 0
2
y0 = 0
3
4
x1 = 127 
5
y1 = 1
6
7
abs(y1 - y0) = 1
8
abs(x1 - x0) = 127 
9
10
plotLine(x0, y0, x1, y1)
11
    if abs(y1 - y0) < abs(x1 - x0)
12
        if x0 > x1
13
            plotLineLow(x1, y1, x0, y0)
14
        else
15
            plotLineLow(x0, y0, x1, y1)
16
            ************************** HIER GEHTS WEITER! 
17
        end if
18
    else
19
        if y0 > y1
20
            plotLineHigh(x1, y1, x0, y0)
21
        else
22
            plotLineHigh(x0, y0, x1, y1)
23
        end if
24
    end if
25
26
27
Also: 
28
29
plotLineLow(x0, y0, x1, y1)
30
    dx = x1 - x0 = 127 
31
    dy = y1 - y0 = 1 
32
    yi = 1 
33
/*
34
    if dy < 0
35
        yi = -1
36
        dy = -dy
37
    end if
38
*/ 
39
    D = (2 * dy) - dx = 2  - 127 = - 125 
40
    y = y0 = 0 
41
42
    for x from 0 to 127 
43
        plot(x, y)
44
        if D > 0
45
            // y = y + yi
46
            // D = D + (2 * (dy - dx))
47
            y = y + 1
48
            D = D + 2 * ( 1 - 127 ) = D + 2 * - 126 = D - 254 
49
        end if
50
        else
51
            // D = D + 2*dy 
52
            D = D + 2 
53
54
D.h., nach x + 63 Schritten wird von plot(x, 0) auf plot(x, 1) "umgeschaltet". 
55
56
Also: 
57
58
von x = 0 bis 63: plot(x,0)
59
von x = 63 bis 127: plot(x,1) 
60
61
(Toleranz: +/-1 ) ;-) :-D

Interessant ist nun natürlich, wie Du die horizontalen Segmente 
plot(x,0) und plot(x,1) in DrawLine umsetzt... mit BlockMove / Copy oder 
was auch immer ;-) Auf dem Z80 nahm dafür dann die BlockMove Befehle 
wenn ich mich recht erinnere um ohne explizite Schleife auszukommen etc.

von Steffen H. (avrsteffen)


Lesenswert?

Also wie man Linien in der Rastergrafik zeichnet ist nach Bresenham 
überall, Wikipedia, YouTube, u.s.w wirklich sehr gut beschrieben und 
erklärt. Und das sogar auf Deutsch!
;)
https://www.youtube.com/watch?v=vlZFSzCIwoc&t=40s

Und hier ein Auszug aus meinem Assembler Code:
1
oled_draw_line:      ; XL = Xstart  |  XH = Xend  |  YL = Ystart  |  YH = Yend
2
    sbrc  XL,7
3
    ldi    XL,((display_Xsize)-1)
4
    sbrc  XH,7
5
    ldi    XH,((display_Xsize)-1)
6
    sbrc  YL,6
7
    ldi    YL,((display_Ysize)-1)
8
    sbrc  YH,6
9
    ldi    YH,((display_Ysize)-1)
10
    movw  r2,XL          ; copy  Xstart | Xend
11
    movw  r4,YL          ; copy  Ystart | Yend
12
    cp    r2,r3          ; (x0 == x1)
13
    brne  oled_draw_line_b    ; -------------> (x0 != x1)
14
    cp    r5,r4          ; if (x0 == x1)  -->  (y0 > y1)? -> (y1 <= y0)?
15
    brsh  oled_draw_line_a    ; -> (y1 >= y0)?
16
    mov    YL,r5
17
    mov    YH,r4          ; swap(Ystart,Yend)
18
oled_draw_line_a:
19
    sub    YH,YL
20
    inc    YH            ; Ylenght = Yend - Ystart
21
    rjmp  oled_draw_vline
22
oled_draw_line_b:            ; -------------> (x0 != x1)
23
    cp    r4,r5          ; (y0 == y1)
24
    brne  oled_write_line      ; -------------> (y0 != y1)
25
    cp    r3,r2          ; if (y0 == y1)  -->  (x0 > x1)? -> (x1 <= x0)?
26
    brsh  oled_draw_line_c    ; -> (x1 >= x0)?
27
    mov    XL,r3
28
    mov    XH,r2          ; swap(Xstart,Xend)
29
oled_draw_line_c:
30
    sub    XH,XL
31
    inc    XH            ; Xlenght = Xend - Xstart
32
    rjmp  oled_draw_hline
33
;***************************************************************************************************************************************
34
oled_write_line:
35
; bool steep = abs(y1 - y0) > abs(x1 - x0)
36
    mov    r6,r3
37
    sub    r6,r2          ; r6 = (x1 - x0)
38
    sbrc  r6,7
39
    neg    r6            ; r6 = abs(x1 - x0)
40
    mov    r7,r5
41
    sub    r7,r4          ; r7 = (y1 - y0)
42
    sbrc  r7,7
43
    neg    r7            ; r7 = abs(y1 - y0)
44
    clr    r12            ; clr --> steep = 0  (bool)
45
    cp    r6,r7          ; wenn (abs(x1 - x0) >= abs(y1 - y0)) -----> ueberspringe folgende Anweisungsliste
46
    brsh  oled_write_line_aa
47
; if (steep)
48
    mov    r12,ONE          ; set --> steep = 1 (bool)
49
; swap(x0, y0)
50
    mov    r8,r4          ; (temp) r8 <-- r4 (y0)
51
    mov    r4,r2          ;  (y0) r4 <-- r2 (x0)
52
    mov    r2,r8          ;  (x0) r2 <-- r8 (temp/y0)
53
; swap(x1, y1)
54
    mov    r8,r5          ; (temp) r8 <-- r5 (y1)
55
    mov    r5,r3          ;  (y1) r5 <-- r3 (x1)
56
    mov    r3,r8          ;  (x1) r3 <-- r8 (temp/y1)
57
oled_write_line_aa:
58
; if (x0 > x1)
59
    cp    r3,r2          ; wenn  (x1 >= x0) -----> ueberspringe folgende Anweisungsliste
60
    brsh  oled_write_line_bb
61
; swap(x0, x1)
62
    mov    r8,r3          ; (temp) r8 <-- r3 (x1)
63
    mov    r3,r2          ;  (x1) r3 <-- r2 (x0)
64
    mov    r2,r8          ;  (x0) r2 <-- r8 (temp/x1)
65
; swap(y0, y1)
66
    mov    r8,r5          ; (temp) r8 <-- r5 (y1)
67
    mov    r5,r4          ;  (y1) r5 <-- r4 (y0)
68
    mov    r4,r8          ;  (y0) r4 <-- r8 (temp/y1)
69
oled_write_line_bb:
70
; dx = x1 - x0
71
    mov    r6,r3          ; r6 = dx
72
    sub    r6,r2          ; r6 = (x1 - x0)
73
; dy = abs(y1 - y0)
74
    mov    r7,r5          ; r7 = dy
75
    sub    r7,r4          ; r7 = (y1 - y0)
76
    sbrc  r7,7
77
    neg    r7            ; r7 = abs(y1 - y0)
78
; err = dx / 2
79
    mov    r10,r6          ; r10 = err(lo)
80
    clr    r11            ; r11 = err(hi)
81
    lsr    r10            ; r10 = dx/2
82
; if(y0 < y1)
83
    cp    r4,r5          ; wenn (y0 >= y1) -----> ueberspringe folgende Anweisungsliste
84
    brsh  oled_write_line_cc
85
; ystep = 1
86
    mov    r9,ONE          ; r9 = ystep = 1
87
    rjmp  oled_write_line_loop
88
oled_write_line_cc:
89
; ystep = -1
90
    clr    r9
91
    dec    r9            ; r9 = ystep = -1
92
oled_write_line_loop:
93
; if(; x1 < x0) ----> break 
94
    cp    r3,r2
95
    brlo  oled_write_line_end
96
; if(steep)
97
    sbrs  r12,0
98
    rjmp  oled_write_line_loop_else
99
; Draw_Pixel(y0, x0)
100
    mov    XL,r4
101
    mov    YL,r2
102
    rcall  oled_set_pixel
103
    rjmp  oled_write_line_loop_err
104
oled_write_line_loop_else:
105
; Draw_Pixel(x0, y0)
106
    mov    XL,r2
107
    mov    YL,r4
108
    rcall  oled_set_pixel
109
oled_write_line_loop_err:
110
; err -= dy
111
    sub    r10,r7
112
    sbc    r11,ZERO
113
; if(err < 0)
114
    cp    ZERO,r10
115
    cpc    ZERO,r11        ; wenn if(0 >= err) -----> ueberspringe folgende Anweisungsliste
116
    brlt  oled_write_line_loop_next
117
; y0 += ystep
118
    add    r4,r9
119
; err += dx
120
    add    r10,r6
121
    adc    r11,ZERO
122
oled_write_line_loop_next:
123
; x0++
124
    add    r2,ONE
125
    rjmp  oled_write_line_loop
126
oled_write_line_end:
127
    ret

Die Funktionen "draw_hline", "draw_vline" und "draw_pixel" hab ich jetzt 
nicht mit hinzugefügt.

: Bearbeitet durch User
von Steffen H. (avrsteffen)


Lesenswert?

Bernhard S. schrieb:
> Danke für Dein Testprogramm, es funktionierte auf Anhieb.

Bitte schön


Bernhard S. schrieb:
> Was mich wunderte, der ATmega328p scheint schon total vollgepackt zu
> sein, bleibt da noch Platz für weiteres, oder ist das nur der
> OLED-Treiber?

Ja, ein mächtiger OLED Treiber womit man auch viel machen kann. Aber 
voll ist der ATmega328 noch nicht.
17114 Bytes Flash (53%)
  683 Bytes RAM   (33%)


Bernhard S. schrieb:
> Kannst Du uns mal ganz grob erklären, wie ein farbiger Balken entsteht,
> schließlich müssen die Farbwerte auch mit übertragen werden.

Man schreibt die Pixeladresse pixelgenau an das Display und dann ein 
Write zum DRAM Command gefolgt von  2 Datenbytes für jeden Pixel (RGB555 
Farbwert). Der interne Adresszähler des DRAM wird nach jedem Pixel 
hochgezählt.

von Michael W. (Gast)


Lesenswert?

Steffen H. schrieb:
> Und hier ein Auszug aus meinem Assembler Code:

Sehr gut, wie von der Wikipedia-Seite bzw. aus dem Lehrbuch! Also doch 
keine Geheimwissenschaft :-)

von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

@Steffen
ich würde gern zur SSD1351 Initialisierung einen separaten Beitrag 
verfassen, vorausgesetzt Du stimmst dem zu, da ich sehr viel 
Assembler-Code aus Deinem Programm nutze.

Danke

von Steffen H. (avrsteffen)


Lesenswert?

Bernhard S. schrieb:
> @Steffen
> ich würde gern zur SSD1351 Initialisierung einen separaten Beitrag
> verfassen, vorausgesetzt Du stimmst dem zu, da ich sehr viel
> Assembler-Code aus Deinem Programm nutze.
>
> Danke

Kein Problem, kanst machen.

von Bernhard S. (bernhard)


Lesenswert?


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.