Forum: Projekte & Code SSD1306/1309 Library zum Darstellen von Text auf OLED Displays


von J. W. (skorpi08)


Lesenswert?

12 zeigt mir auch im SerialMonitor an.
Ich schick die Daten über RS485, nur so am rande.

#include "lcd.h"

void setup(){
Serial.begin( 19200 );
  pinMode(23,OUTPUT);  digitalWrite(23,1);
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
  lcd_puts("Hello World");  // put string from RAM to display (TEXTMODE) 
or buffer (GRAPHICMODE)
  lcd_gotoxy(0,2);          // set cursor to first column at line 3
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to 
display (TEXTMODE) or buffer (GRAPHICMODE)

  I2C_ErrorCode=12;

  Serial.print(I2C_ErrorCode);
  Serial.write("\r\n"); // Zeilenumbruch fuer die Anzeige
}

void loop(){
  Serial.print(I2C_ErrorCode);
  Serial.write("\r\n"); // Zeilenumbruch fuer die Anzeige
  delay(5000);
}

von M. K. (sylaina)


Lesenswert?

Dann bin ich leider überfragt. Wenn der Errorcode 0 bleibt (ist bei dir 
ja anscheinend so) und der setup() auch ausgeführt wird (was ja durch 
die 12 bestätigt ist) dann hat die Kommunikation mit dem Display 
funktioniert und du müsstest eigentlich was angezeigt bekommen.

von M. K. (sylaina)


Lesenswert?

Ich nehme an, du verwendest einen Arduino. Ich werd heute Abend oder 
morgen Früh daheim mal was testen, hab hier grad keinen Arduino zur 
Hand.

von J. W. (skorpi08)


Angehängte Dateien:

Lesenswert?

Arduino hat kein Atmega324PA, ich verwende aber die Arduino IDE.
So sieht die i2c.h aus:

/* TODO: setup i2c/twi */
#define F_I2C      100000UL// clock i2c
#define PSC_I2C      1    // prescaler i2c
#define SET_TWBR    (F_CPU/F_I2C-16UL)/(PSC_I2C*2UL)

Im Anhang hab ich die ohne deiner i2c.h probiert, dafür dann mit Wire.h 
von Arduino. Allerdings sind da noch punkte rechts neben dem Text.

Fuses sollten ja passen, 16 Mhz Quarz.


EDIT:
Jetzt bekomme ich Error 5, keine ahnung was ich geändert hab.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

ErrorCode 5 bedeutet schon mal, dass der Start fehlgeschlagen ist, 
sprich die Kommunikation mit dem I2C hat nicht geklappt (dafür steht das 
erste Bit im ErrorCode). Die 4 steht dafür, dass das Übertragen des 
Bytes nicht geklappt hat (ist das dritte Bit in ErrorCode, vgl. auch 
i2c.h).

Ich hab grade aus meinem github noch mal die Library herunter geladen 
weil ich dachte, ich hab vielleicht noch nen Fehler drin, und sie 
einfach Übersetzen lassen und hoch geladen auf einen Atmega328pn (make 
flash). Das hat sofort fehlerfrei geklappt. Umgestellt auf Textmode mit 
dem Ergebnis auch das klappt auf Anhieb. Die Library ist in C 
geschrieben, ich weis leider nicht ob man C++ noch irgendwie sagen muss, 
dass es eine C Library ist. Ich denke aber, der Fehler liegt nicht in 
der Library sondern wie sie eingebunden wird. Weis z.B. auch der Linker 
was er damit machen soll, welches Encoding er benutzen soll usw.?

von J. W. (skorpi08)


Lesenswert?

extern "C" {
#include "i2c.h"
}

Ich denke mal irgendwie so wirds eingebunden.
Gibts aber immer noch Fehlermeldungen mit den ich nix anfangen kann.

von J. W. (skorpi08)


Lesenswert?

Stefan U. schrieb:
> Theoretisch müsste es aber auch mit deinem AVR funktionieren.

Es funktioniert auch, auf den Pins D4 und D5.
Also ist es eine SoftI2C-OLED-Lib

von Stefan F. (Gast)


Lesenswert?

Ja, ich habe mich für das soft-I²C entschieden, um beliebige Pins 
verwenden zu können. Beim ESP8266 (für den ich das geschrieben hatte) 
gibt es ohnehin keinen freien I²C in Hardware.

von M. K. (sylaina)


Lesenswert?

So, ich bin nun noch mal dazu gekommen das Ganze mit Arduino zu testen 
und es funktioniert problemlos. Die Libraries (aus dem Github geladen) 
für das LCD und I2C habe ich in den Projektordner kopiert.
1
extern "C" {
2
  #include "lcd.h"
3
}
4
5
void setup() {
6
  // put your setup code here, to run once:
7
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
8
  
9
  lcd_puts("Hello World");  // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
10
  lcd_gotoxy(0,2);          // set cursor to first column at line 3
11
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE)
12
#if defined GRAPHICMODE
13
  lcd_drawCircle(64,32,7,WHITE); // draw circle to buffer white lines
14
  lcd_display();                 // send buffer to display
15
#endif
16
}
17
18
void loop() {
19
  // put your main code here, to run repeatedly:
20
21
}

Der Sketch belegt 2344 Bytes (GRAPHICMODE, als Vergleich: der gleiche 
Code nur in C wie im github-Beispiel belegt lediglich 1884 Bytes).

Wichtig ist, dass man
1
extern "C" {
2
  #include "lcd.h"
3
}
schreibt. Schreibt man
1
#include "lcd.h"
meckert u.a. der Linker, dass er die jeweiligen Referenzen auf die 
einzelnen Funktionen (z.B. lcd_init()) nicht auflösen kann.

Ein weiteres Manko ist, dass man dem Compiler/Linker auch noch irgendwie 
beibringen muss, welchen Charset er für die Quellcode-Dateien verwenden 
soll. Es wird nämlich beim ersten Compilieren u.a. vor den Umlauten 
(ä,ö,ü usw.) gewarnt, diese sind auch nicht verarbeitet, d.h. versucht 
man z.B. ein ä aufs Display zu bringen erscheint schlicht nichts. In 
meinem Makefile steht deshalb
1
CFLAGS += -finput-charset=utf-8 -fexec-charset=iso-8859-15
drin, wo und wie man das bei Arduino angibt weis ich allerdings nicht 
aber dazu findet sich sicher auch hier im Forum Hilfe ;)

: Bearbeitet durch User
von J. W. (skorpi08)


Lesenswert?

Ich hab noch einige andere Librarys getestet, bei den wird maximal 4% 
RAM belegt.
Bei deiner werden 50% fürs Hello World benötigt, das ist ein Grund warum 
ich mich noch nicht für deine Lib sicher entscheiden kann.
Kannst du da noch was machen?

main.c funktioniert in der Arduino IDE natürlich auch.

von M. K. (sylaina)


Lesenswert?

J. W. schrieb:
> Ich hab noch einige andere Librarys getestet, bei den wird maximal 4%
> RAM belegt.
> Bei deiner werden 50% fürs Hello World benötigt, das ist ein Grund warum
> ich mich noch nicht für deine Lib sicher entscheiden kann.

Du kannst meine Libary auch auf Textmodus umstellen (siehe lcd.h) wenn 
du nur Text ausgeben möchtest aber nicht Zeichnen willst. Dann benötigt 
sie auch nicht so viel RAM (grade mal 2 Byte wenn ich das noch recht in 
Erinnerung habe). Im Grafik-Modus benötigt sie die Display-Größe als 
Speicher im RAM da ja via I2C der SSD1306/SH1106 nicht ausgelesen werden 
kann was dann aber schon beim Zeichnen eines Diagrams recht schwierig 
bis unmöglich wird.
Ich nehme mal an die Library, die du jetzt benutzt, läuft auch nur im 
Textmodus. Zumindest ist mir kein Lib bekannt, die bei diesen 
Controllern im Grafikmodus keinen RAM in Größe des Displays als Puffer 
vorhalten. Daher hatte ich diese Lib ja geschrieben da ich so ein 
Display an einem Atmega 8 einsetzen wollte zur Textanzeige aber das mit 
den Libs, die ich damals fand, nicht ging wegen des Puffers. ;)

von Stefan F. (Gast)


Lesenswert?

Prinzipiell kann man Grafik auch ohne Pufferspeicher ausgeben. Aber man 
muss immer 8 Bits (vertikal untereinander) gleichzeitig schreiben.

Wenn ich nun z.B. ganz oben eine horizontale Linie zeichnen will, und 
dann 4 Pixel Tiefer noch eine, wird es kompliziert. Beim Zeichnen der 
zweiten Linie muss ich zwangsläufig die Bits der ersten Linie 
überschreiben.

Damit dabei die erste Linie nicht verloren geht, müsste ich den Speicher 
lesen können, das geht bei I²C aber nicht.

Unterm Strich bedeutet das, man kann immer nur 8 Pixel-Reihen am Stück 
beschreiben. Text und Bitmaps kann man auf diese Weise problemlos im 
8-Linien Raster ausgeben, aber das Zeichnen von geometrischen Figuren 
wird ohne Pufferspeicher extrem kompliziert.

von M. K. (sylaina)


Lesenswert?

Stefan U. schrieb:
> Text und Bitmaps kann man auf diese Weise problemlos im
> 8-Linien Raster ausgeben, aber das Zeichnen von geometrischen Figuren
> wird ohne Pufferspeicher extrem kompliziert.

Deswegen schrieb ich oben schwierig bis unmöglich: Text& Bitmaps gehen 
noch ohne Pufferspeicher (wobei ich grade die Bitmap-Funktion mit 
Pufferspeicher implementiert habe ;)) aber beliebige, geometrische 
Figuren bzw. beliebige Graphen gehen ohne Pufferspeicher schlicht nicht.

: Bearbeitet durch User
von J. W. (skorpi08)


Lesenswert?

Habe so ein OLED, in weiß. Damals gabs da keine Auswahl und die waren 
ohne Versandkosten.
https://de.aliexpress.com/item/-/32717936245.html

Die Lib grad neu geladen.
I2C Scanner sagt dass es die 3C Adresse ist, mit anderen Libs läufts 
auch, Verkabelung muss dann ja auch passen.
1
/* TODO: define displaycontroller */
2
#define SSD1306                              // or SSD1306, check datasheet of your display
3
/* TODO: define displaymode */
4
#define GRAPHICMODE                         // TEXTMODE for only text to display,
5
                                            // GRAPHICMODE for text and graphic
6
7
#define LCD_I2C_ADR    0x3C
1
extern "C"{
2
  #include "lcd.h"
3
}
4
5
void setup() {
6
  lcd_init(LCD_DISP_ON);    // init lcd and turn on
7
  lcd_puts("Hello Wuüorld");  // put string from RAM to display (TEXTMODE)
8
  lcd_gotoxy(0, 2);         // set cursor to first column at line 3
9
  lcd_puts_p(PSTR("String from flash"));  // puts string form flash to
10
}
11
void loop() {}

Und das Display bleibt immer noch schwarz.
Hab jetzt den Arduino UNO, mit USBasp programmiert.

von M. K. (sylaina)


Lesenswert?

Hast du das Display umkonfiguriert? Das wird default-mäßig als 
SPI-Display ausgeliefert, so les ich das oben nämlich, sie Anleitung 
dazu.

Wenn du es als I2C schon umgelötet hast: Kannst du mal dein Arduino 
Projektordner für das Display mit dem kompletten Code zippen und hier 
einem Beitrag anhängen? Ich kann hier nämlich absolut keinen Fehler 
feststellen, auch mit der Arduino IDE. Ich habs jetzt mit verschiedenen 
SSD1306 und SH1106 Display getestet, die laufen alle perfekt an.

von J. W. (skorpi08)


Angehängte Dateien:

Lesenswert?

Wo wie was konfigurieren? Das Display ist ein I2C, wie auf den Bildern 
mit SDA, SCL, VCC und GND. Da muss man nix mehr löten.
Läuft ja mit anderen I2C Libs.

von M. K. (sylaina)


Lesenswert?

Habs mir runtergeladen und compiliert bzw. versucht, Arduino IDE meldet 
sofort beim Übersetzen den folgenden Fehler:

/Users/michael/Downloads/oled-display-master-2/examples/oled-display/ole 
d-display.ino:2:19:  fatal error: lcd.h: No such file or directory
   #include "lcd.h"

Das liegt daran, dass die Library einige Dateiebenen höher liegt, durch 
das
1
extern "C" {
2
  #include "lcd.h"
3
}
wird aber erwartet, dass die Library in der selben Dateiebenen liegt wie 
die .ino. Ich hab die Library (lcd.h, lcd.c, i2c.h und i2c.c) einfach 
mal ins Verzeichnis der .ino kopiert und schon wirds fehlerfrei 
übersetzt und das Display zeigt auch was an ;)

: Bearbeitet durch User
von J. W. (skorpi08)


Angehängte Dateien:

Lesenswert?

auch so läuft es nicht.

Man kann es auch so einbinden, dann wirds in dem ganzem Library Ordner 
nach lcd21.h gesucht.
1
extern "C" {
2
  #include <lcd21.h>
3
}

: Bearbeitet durch User
von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Wie gesagt, ich kann den Fehler hier nicht reproduzieren. Weder als 
lokale Library (vgl. Dateianhang) noch als globale Library, bei mir 
läuft das stets problemlos an. OK, ich hab noch nicht geschaut wie man 
in der Arduino IDE dem Compiler sagen kann, dass er das charset 
iso-8859-15 bei den Dateien verwenden soll (ist für all die tollen, 
deutschen, Sonderzeichen wie ä,ö,ü usw.) aber sonst: fehlerfrei.

von J. W. (skorpi08)


Lesenswert?

Bei mir ist GND links (aussen), bei deinem ist VCC aussen.
Ist also schon mal ein anderes Display.
Ist mir nur aufgefallen, vielleicht hats ja nichts zu bedeuten.
Alle anderen Libs funktionieren, hab einige getestet
https://forum.arduino.cc/index.php?topic=529600.msg3610291#msg3610291

von M. K. (sylaina)


Lesenswert?

Das Bild ist von einem SH1106 (1.3"), bei meinem SSD1306 (0.96") ist 
auch GND außen ;)

von Johannes S. (Gast)


Lesenswert?

J. W. schrieb:
> Habe so ein OLED, in weiß. Damals gabs da keine Auswahl und die
> waren ohne Versandkosten.
> https://de.aliexpress.com/item/-/32717936245.html


Auf dem Bild sieht man R3/4 als 0R Widerstände, damit kann man eventuell 
SPI/I2C oder die I2C Adresse umstellen.

von M. K. (sylaina)


Lesenswert?

Das hatte ich ja weiter oben schon mal angefragt ob das Display in I2C 
konfiguriert ist oder auf SPI. Anscheinend ist es auf die I2C 
konfiguriert wenn die anderen Libraries funktionieren. Daher denke ich 
auch das ist kein Problem mit dem Wirering ist.

von J. W. (skorpi08)


Lesenswert?

Ich denke eher das ist für die I2C Adresse, nicht für SPI. Ist nur ne 
Vermutung, nicht weiter damit befasst.

von M. K. (sylaina)


Lesenswert?

Du denkst? Bist aber nicht sicher?

: Bearbeitet durch User
von J. W. (skorpi08)


Lesenswert?

Ich hab 2 Displays bestellt, 1 SPI und 1 I2C.
Beim SPI sind mehr Pins, deshalb dachte ich es ist schon richtig mit dem 
I2C.

von M. K. (sylaina)


Lesenswert?

Naja, bei mir lässt sich der Code problemlos übersetzen und das Display 
läuft problemlos. Vielleicht versuchst du mal als Adresse die 0x78 oder 
die 0x7A ggf. ist deine ermittelte Adresse nicht richtig.

von J. W. (skorpi08)


Lesenswert?

Unfassbar. Problem gelöst. Wieso kommst auch nicht früher mit der 
Adresse 0x78? :D

Die Frage bleibt jetzt aber, warum es bei anderen mit 0x3C läuft und mit 
deiner mit 0x78.

Jetzt weiß ich auch was ihr mit konfigurieren meint.
Hab das SPI Display ausgepackt und die Widerstände angeschaut, R3 und R4 
sind gelötet. Bei dem I2C Display sind R1, R4 und R8 gelötet.
Mal davon abgesehen dass die Platinen verschieden sind und bei SPI 
Version noch RES, DC und CS Pins vorhanden sind.
Habs mal auf I2C umgelötet, also R1, R4 und R8 gebrückt, I2C Scanner 
erkennt den nicht.

von Johannes S. (Gast)


Lesenswert?

Das Problem ist so alt wie I2C selbst, schiebe mal 0x78 um ein Bit nach 
rechts.
Beitrag "Re: Kann mir bitte wer beim USI-TWI helfen?"

Beitrag #5322585 wurde vom Autor gelöscht.
von M. K. (sylaina)


Lesenswert?

Johannes S. schrieb:
> Das Problem ist so alt wie I2C selbst, schiebe mal 0x78 um ein Bit nach
> rechts.
> Beitrag "Re: Kann mir bitte wer beim USI-TWI helfen?"

Das ist ein interessanter Beitrag, das war mir so auch nicht bewusst. 
Ich hab die lcd.h an der Stelle, an der die Adresse angegeben wird, 
entsprechend mit einem Kommentar versehen.
Die Displays, die ich hier hab, haben halt alle die Adresse nach dem 
Slave-Mode angegeben.

von Nico W. (nico_w)


Lesenswert?

J. W. schrieb:
> #define LCD_I2C_ADR     0x3C// 0x7A

Ich glaube nicht das 0x3C richtig ist.
Versuch es mal mit 0x78.
1
(0x3C << 1)

von J. W. (skorpi08)


Lesenswert?

Ich glaub auch nicht dass es richtig ist, bei dieser Lib.

von Nico W. (nico_w)


Lesenswert?

Je nach Lib ist das halt ein wenig unterschiedlich.

Die Adresse wird um 1 nach links geschoben. Im ersten Bit steht dann bei 
der Übermittlung der Adresse, ob gelesen oder geschrieben werden soll.

von M. K. (sylaina)


Lesenswert?

Richtig, bei der Adresse erwartet meine Library die 8-Bit Adresse. Da 
das SSD1306 bzw das SH1106 bei I2C nicht gelesen werden kann macht es 
keinen Sinn hier die 7-Bit Adresse anzugeben sodass die Library selbst 
zwischen Lesen und Schreiben wählen könnte. Wie gesagt, diese 
Information habe ich heute Morgen dem Quellcode als Comment hinzugefügt 
;)

von Sebastian (Gast)


Lesenswert?

Hallo und vorab eine echt gute Library!

Eine Frage. Gibt es eine Option das man den Text z.b. Zentrieren kann?

Ich muss mich nun erstmal damit auseinander setzen :) vielen Dank für 
eine Info schon mal ob es schon vielleicht möglich ist.

Verwende im übrigen ein SD1306


Gruß Sebastian

von M. K. (sylaina)


Lesenswert?

Hallo Sebastian,

ein Funktion zum Zentrieren ist nicht enthalten. Da könnte man mit der 
strlen-Funktion aus der string.h arbeiten.

von Fabian G. (fabian_g)


Angehängte Dateien:

Lesenswert?

Hi M. Köhler

Erstmal danke für die Library.
Leider funktioniert bei mir gar nichts.

Ich verwende ein 128x32 OLED mit SSD1306. Dieses steuere ich mit einem 
ATmega 644p mit 20MHz an.

Ich habe deinen Code von GitHub heruntergeladen und die nötigen 
Anpassungen vorgenommen(angehängt) und eine Codezeile hinzugefügt:
1
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)

Es zeigt mir nichts am OLED an. Ich nehme an ich habe die Hardware 
richtig verdrahtet.

SDL von Atmega->SCK des OLED mit 4.7kOhm Pull-Up
SDA von Atmega->SDA des OLED mit 4.7kOhm Pull-Up
VCC->5V

Kannst du mit weiterhlefen?

EDIT: habe ausversehen zweimal das gleiche Bild angehängt

Mit freundlichen Grüssen
Fabian

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Packe mal dein Projekt in ein ZIP-File und lade es hier hoch, dann schau 
ich es mir heute Abend an, vorher komme ich leider nicht dazu da ich 
grade unterwegs bin.

von Stefan F. (Gast)


Lesenswert?

Schließe mal LEDs (mit 2,2k oder 4,7k) Vorwiderstand parallel zu den 
Pull-up Widerständen an und schaue, ob sie beide flackern.

Am besten kann man was sehen, wenn man die Übertragung erheblich 
verlangsamt.

Hast du einen Logic Analyzer? Falls nicht wäre jetzt der richtige 
Moment, sich einen anzuschaffen. Zur Analyse von I²C Problemen sind die 
Dinger Top und kosten nicht mehr als 15 Euro.

von Fabian G. (fabian_g)


Angehängte Dateien:

Lesenswert?

Vielen Dank für die schnellen Antworten.

Ich habe mein Programm angehängt.
Wir haben, glaube ich, irgendwo noch so ein Logic Analyzer. Mal schauen, 
ob ich mit diesem etwas herausfinde.
Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.

Mit freundlichen Grüssen
Fabian

von Dieter F. (Gast)


Lesenswert?

Möglicherweise ein "déjà vu" ? (Hatten wir heute schon mal)

JTAG-Fuse aktiv?

von Stefan F. (Gast)


Lesenswert?

> Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.

Glauben ist nicht Wissen. Die Aussage ist nicht dumm, aber sie sollte 
überprüft werden. Deswegen ja mein Vorschlag mit den LEDs.

Mit einem Debugger kannst du herausfinden, ob und wo das Programm hängt. 
Hast du das wenigstens gemacht?

von M. K. (sylaina)


Lesenswert?

Fabian G. schrieb:
> Vielen Dank für die schnellen Antworten.
>
> Ich habe mein Programm angehängt.
> Wir haben, glaube ich, irgendwo noch so ein Logic Analyzer. Mal schauen,
> ob ich mit diesem etwas herausfinde.
> Aber ich glaube das Problem ist, dass er gar nicht zum senden kommt.
>
> Mit freundlichen Grüssen
> Fabian

Ich hab mir den Code angeschaut und das sieht alles soweit OK aus.

Es fällt zunächst mal auf, dass du noch eine ältere Version der Lib 
benutzt. Dennoch sollte auch diese laufen.

Die Adresse des Displays ist im 7-Bit-Mode angegeben, hast du auch mal 
versucht die Adresse im 8-Bit-Mode anzugeben (also statt 0x3c 0x78 
angeben? Und ist die Adresse auch sicher die richtige?

Und zu guter letzt: Läuft dein uC auch wirklich mit 20 MHz? Fuses alle 
richtig gesetzt? In meiner Anfangszeit hab ich z.B. gerne vergessen die 
DIV8-Fuse auszumachen => Hello World der uCs mal programmieren und 
Zeiten kontrollieren
1
//Hello World der uCs
2
#include <avr/io.h>
3
#include <util/delay.h>
4
void main void {
5
  DDRB |= (1 << PB1);
6
  for(;;) {
7
    PORTB ^= (1 << PB1); //toggel PB1
8
    delay_ms(500);
9
  }
10
}
11
//aus dem Kopf getippt, Fehler ggf. inclusive ;)

von Fabian G. (fabian_g)


Lesenswert?

So habe nun die Fehler gefunden.

Einerseits musste ich die com Ports anpassen und die Adresse, wie du 
geschrieben hast, im 8-Bit modus angeben.

Kann ich mit deiner Bibliothek die Schriftgrösse ändern? Wenn ja, wie?

Mit freundlichen Grüssen und ein schönes Wochenende
Fabian

von M. K. (sylaina)


Lesenswert?

Nein, die Schriftgröße ist damit nicht anpassbar. Die aktuelle Version 
ist in der Lage Bitmaps zu zeichnen, damit könnte man sich auch andere 
Schriftgrößen generieren.

von Fabian G. (fabian_g)


Lesenswert?

Und diese Bitmaps benötigen viel Speicherplatz/Arbeitsspeicher?
Wie viele kann ich davon zeichnen?
Ist es möglich diese Bitmaps in schneller Abfolge nacheinander 
auszugeben?

EDIT: Habe noch eine zusätzliche Frage
Du verwendest einen TIMER für den Serial Clock, sehe ich das richtig? 
Für was brauchst du den TIMER_COUNTER?
1
ISR(TIMER_INT_vec){
2
  TIMER_COUNTER = 0;
3
  LCD_PORT ^= (1 << SDC_Pin);
4
}

Kommt in der Regel ein I2C-Programm nicht ohne zusätzliches Timer aus? 
Dachte der Mikrocontroller generiert diesen Serial Clock selber, ohne 
Timer.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Nein, ich verwende keinen Timer. Wie schon gesagt, du benutzt noch eine 
sehr alte Version der Library. Der Timer war einst gedacht für 
Software-I2C, das hab ich aber nie weiter entwickelt, war eine Spinnerei 
aus den Anfangstagen der Lib.

Zu den Bitmaps: Meine Library kann Bitmaps zeichnen, sie beinhaltet aber 
keine, die musst du selbst erstellen oder dir entsprechend besorgen aus 
dem Internet. Wie schnell sie Bitmaps hintereinander zeichnen kann hängt 
von der Größe der Bitmaps ab und der eingestellten 
Kommunikationsgeschwindigkeit. 10 Pixel sind halt schneller gezeichnet 
als 100 Pixel bei gleicher Kommunikationsgeschwindigkeit.

von Fabian G. (fabian_g)


Lesenswert?

Vielen Dank für die schnelle Antwort.
Wo finde ich die aktuellste Version deiner Library? Auf Github?

von M. K. (sylaina)


Lesenswert?

Ja, auf Github, Link ist im Eröffnungspost ;)

Da gibts einige Änderungen inzwischen, z.B. sind die I2C-Funktionen in 
einer eigenen Lib ausgelagert worden sodass man auch eigenen 
I2C-Funktionen nutzen kann ;)

: Bearbeitet durch User
von Marius K. (zephram)


Lesenswert?

Guten Abend!

Eine schöne Lib, wo hast du die nötigen Informationen her ? Die 
Informationslage zu den SSD13XX Chips ist ja recht dünn gesäht...

Ist irgendwas zum Aufbau des SSD1315 im Vergleich zum SSD1306 bekannt ? 
Kann man den mit der 1306er Lib ansteuern ? Zum SSD1315er gibts leider 
iwie gar nichts zu finden...

Viele Grüße

von Stefan F. (Gast)


Lesenswert?

> Die Informationslage zu den SSD13XX Chips ist ja recht dünn gesäht...

Eigentlich steht im Datenblatt des SSD1306 alles drin, was man für 
diesen Chip wissen muss. Funktionierende Code-Beispiele helfen dabei, es 
zu verstehen.

Bezüglich des SSD1315 würde ich also ebenfalls zuerst mal das Datenblatt 
suchen, wenn ich Fragen dazu hätte.

von M. K. (sylaina)


Lesenswert?

Marius K. schrieb:
> Eine schöne Lib, wo hast du die nötigen Informationen her ?

Aus dem Datenblatt. Da stehen neben den elektrischen/mechnischen Daten 
auch alle Befehle drin und, je nach Datenblatt, auch die ganzen Routinen 
zum Initialisieren usw.

von Marius K. (zephram)


Lesenswert?

"Bezüglich des SSD1315 würde ich also ebenfalls zuerst mal das 
Datenblatt
suchen, wenn..."

Ich meinte mit dünner Informationslage, dass Google kein Datenblatt des 
SSD1315 bekannt zu sein scheint...

Ich hab das Teil mal probehalber an einen Pi angeschlossen und die 
Adafruit Bib für SSD1306 getestet. Es scheint zu funktionieren, das 
würde bedeuten ein 1315 ist softwareseitig kompatibel zu einem 1306...

Viele Grüße

von Dieter F. (Gast)


Lesenswert?

Marius K. schrieb:
> Ich meinte mit dünner Informationslage, dass Google kein Datenblatt des
> SSD1315 bekannt zu sein scheint...

https://www.google.com/search?q=SSD1315+datasheet

von Stefan F. (Gast)


Lesenswert?

Ich habe auf den Link geklickt und kein passendes Ergebnis erhalten.

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Ich habe auf den Link geklickt und kein passendes Ergebnis erhalten.

Da war ich wohl zu nachlässig ...

https://www.mouser.com/ds/2/131/LPCXpresso_Experiment_Kit_Users_Guide-908526.pdf

Die arbeiten damit.

Da gibt es auch Anregungen

https://github.com/twchad/Adafruit_Python_SSD1351

Aber ja, scheint dünn zu sein - mea culpa.

von Stefan F. (Gast)


Lesenswert?

SSD1315 und nicht SSD1351 !

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> SSD1315 und nicht SSD1351 !

Wie recht Du doch hast. Hast Du mal die Befehle mit 1306 etc. 
verglichen?

von Stefan F. (Gast)


Lesenswert?

> Hast Du mal die Befehle mit 1306 etc. verglichen?

Nein. Da ich weder ein SSD1315 noch ein SSD1551 besitze, ist das für 
mich nicht wichtig.

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Nein. Da ich weder ein SSD1315 noch ein SSD1551 besitze, ist das für
> mich nicht wichtig.

SSD1306 hast Du gelesen?

von Stefan F. (Gast)


Lesenswert?

> SSD1306 hast Du gelesen?

Ja, und eine Implementierung danach veröffentlicht. Aber ich will sie 
niemandem aufdrängen, danach hat ja auch gerade keiner gefragt.

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Aber ich will sie
> niemandem aufdrängen, danach hat ja auch gerade keiner gefragt.

Ich habe nach dem Vergleich zum 1315 gefragt ...

von Stefan F. (Gast)


Lesenswert?

> Ich habe nach dem Vergleich zum 1315 gefragt ...

Nein, du hast gefragt, ob ich das Datenblatt von SSD1306 gelesen habe.

Abgesehen davon, wie soll ich die Datenblätter miteinander vergleichen? 
Wir sich doch immer noch auf der Suche nach dem Datenblatt des SSD1315!

Das ist doch gerade das Thema dieses Threads. Jemand sucht das 
Datenblatt vom SSD1315 weil er es mit dem SSD1306 vergleichen will. Du 
hast ein paar nicht hilfreiche Links gepostet und forderst nun mich (ich 
war übrigens nicht der suchende) auf, die Datenblätter zu vergleichen.

Wo ist da die Logik?

von Dieter F. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Wo ist da die Logik?

Frag dazu bitte den Marius K. (zephram).

Auch ich habe keine Lust irgendetwas für ihn zu Suchen oder zu 
Vergleichen.

von Marius K. (zephram)


Lesenswert?

Jungs, immer mit der Ruhe, war doch nur die Frage ob wer das Datenblatt 
für den 1315er rumfliegen hat, dann hätte ich mal versucht die 1306er 
Lib anzupassen, was aber ja eh, wie gesagt, unnötig erscheint, weil der 
1315 funzt ja mit der 1306er Lib ^^\

Viele Grüße

von Dieter F. (Gast)


Lesenswert?

Marius K. schrieb:
> unnötig erscheint, weil der
> 1315 funzt ja mit der 1306er Lib ^^

Ja, scheint mir auch so. Es gibt einige Varianten 13xx lt. 
Datenblättern, welche aber wohl nur "Ausstattungsvarianten" sind. Ich 
habe noch etwas rumgeschaut, bin aber auch nicht schlauer geworden. 
Würde es mit dem 1306-Code versuchen - falls nicht O.K.den "Pseudo 
1351-Code" (ohne den verglichen zu haben, da für mich nicht relevant - 
bisher).

Ich vermute, das es sich sowieso nur um Ausstattungsvarianten handelt - 
weiß es aber ehrlich gesagt nicht.

von Marius K. (zephram)


Angehängte Dateien:

Lesenswert?

"Ich vermute, das es sich sowieso nur um Ausstattungsvarianten handelt"

Seh ich auch so ^^ Auf dem Foto wird das Teil von einer kleinen App auf 
node.js mittels dem Paket oled-js-pi angesteuert die auf nem Pi Zero W 
läuft. Diese Lib ist ebenfalls für 1306er...

Viele Grüße

von John Doe (Gast)



Lesenswert?

siehe Anhang

von Nils E. (yetanotheruser)


Lesenswert?

Ich würde die Library gerne in einem GPLv2-only-Projekt verwenden. Der 
Code auf github ist jedoch als GPLv3 ausgewiesen, so dass hier 
inkompatible Lizenzen zusammen kommen.

Ist es vielleicht möglich, diese Library auch unter GPL2 zu 
veröffentlichen?

von Max (Gast)


Lesenswert?

Hallo zusammen,
ich hoffe einer von denjenigen bei denen das Display SSD1306 schon läuft 
ist so nett und hilft mir ein wenig auf die Sprünge.

Ich würde das Display auch gerne in mein Projekt einbauen.
Mir ist klar, wie ich die Displaymatrix berechne. Nur wie ich dem 
Display das mitteile (Befehle/Daten) ist mir nicht ganz ersichtlich aus 
dem Datenblatt.
Da steht viel drinnen. Aber wo nur steht was ich brauche? ;)

I2C Grundaufbau ist eigentlich klar.
Hier mal meine Ansätze wie ich folgende Grundfunktionen aufbauen würde.
So gehts wohl nicht, das hab ich gemerkt :(

Display einschalten:
1
start condition //I2C starten
2
0x78 // Display addresse + last bit (0) is write mode /(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xAF // Display einschalten
7
ACK
8
stop condition // I2C stop

Display ausschalten:
1
start condition //I2C starten
2
0x78 // Display addresse + last bit (0) is write mode /(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xAE // Display ausschalten
7
ACK
8
stop condition // I2C stop

Display alles löschen (alle Bytes auf 0x00):
1
start condition //I2C starten
2
0x78 // Display addresse // last bit (0) is write mode //(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0x?? // Display clear
7
ACK
8
stop condition // I2C stop

Display page (Daten) setzen:
1
start condition //I2C starten
2
0x78 // Display addresse // last bit (0) is write mode //(1) is read mode
3
ACK
4
0x40 // Befehl folgt
5
ACK
6
0xB0 // Setze Page 0 0xB0-B7 für page 0-7
7
ACK
8
0xD3 // Setze Display offset
9
ACK
10
0x05 // 0x00 - 0x7F Für Spaltenoffset 0-127
11
ACK
12
0x00 // Sende folgende Daten
13
ACK
14
0xFF // Daten 0xFF zum ersten Byte
15
ACK
16
0xFF // Daten 0xFF zum zweiten Byte
17
ACK
18
... Wiederholung der Datenbytes bis alle Informationen übertragen sind
19
ACK
20
stop condition // I2C stop

Wo hab ich da Fehler eingebaut?
Wie müsste man diese Grundfunktionen richtig implementieren?

Wäre super wenn mir jemand weiterhelfen würde.

Vielen lieben Dank im Vorraus

Liebe Grüße
Max

von Stefan F. (Gast)


Lesenswert?

Bei mir sind die Sequenzen etwas länger, kannst du gerne hier abgucken: 
http://stefanfrings.de/esp8266/WIFI-Kit-8-Test2.zip

Ich habe das aus mehreren Libraries und Infos aus dem Datenblatt 
zusammen gewürfelt, weil es bei mir zuerst auch nicht richtig 
funktionierte. Mit dem jetzigen Stand habe ich allerdings nun ein gutes 
Gefühl.

Du darfst meinen Code frei ohne Lizenz-Beschränkungen nutzen. Das 
Einzige, was darin wirklich (fast*) 1:1 kopiert wurde, ist der 
Zeichensatz. Und der war vom ursprünglichen Autor als "Freeware" 
freigegeben.

*) ich habe deutsche Umlaute hinzugefügt.

von Max (Gast)


Lesenswert?

Hi,
wow die Antwort kam ja fix.

OK ich hab gesehen da sind viele Unterschiede
command bei dir 0x00; bei mir 0x40
write byte 0, bei mir 1....
alleine in der init schon

und viele andere Dinge gesetzt die ich nicht berücksichtigt habe.
wie: Multiplex ratio etc hab ich gar nicht vorgesehen gehabt.

Vielen Dank dafür.
Ich werd mal versuchen deine .cpp in .c umzubauen.
Ich brauche das in klasischem c.

Hoffe dann klappt das.

Braucht man wirklich all diese zusätzlichen Infos?
Oder kennt da jemand nocht nen einfachen Basis Ansteuerungssatz?

Gruß

Max

von Stefan F. (Gast)


Lesenswert?

> Ich werd mal versuchen deine .cpp in .c umzubauen.
> Ich brauche das in klasischem c.
> Hoffe dann klappt das.

Das wird Dir ganz sicher problemlos gelingen. Mein Code enthält keine 
komplizierte Tricks. Von C++ habe ich auch nur einen Bruchteil der 
möglichen Sprache-Konstrukte genutzt.

von Max (Gast)


Lesenswert?

Hallo Stefanus,
ja ich bin es gerade durchgegangen.
Das sieht alles logisch aufgebaut aus.
Und auch schön Kommentiert. Daumen hoch

Danke nochmal für die schnelle Hilfe.
Die Bytefolgen kann man da schön rausziehen.
Auch hast du Commands und Daten immer getrennt in I2C gesendet, nicht in 
ein ewig Telegramm vermischt. Hätte mir dann wohl auch Probleme dabei 
gegeben wenn ich alles auf einmal gesendet hätte.
Gruß
Max

von Stefan F. (Gast)


Lesenswert?

Man kann Kommandos und Daten auch an einem Stück hintereinander senden. 
Ich wollte den Code aber lieber übersichtlich halten, anstatt die 
letzten Mikrosekunden Performance heraus zu quetschen.

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Welches ist denn nun die letzte gültige Lib? Für Text und Grafik. 
Benutze Atmel Studio 7.
Evtl. könnte ein Datum ganz vorn/oben eingefügt werden?

: Bearbeitet durch User
von Stefan P. (form)


Lesenswert?

Reinhard O. schrieb:
> Welches ist denn nun die letzte gültige Lib?

Im 1. Post ist ein Github Repository verlinkt:
https://github.com/Sylaina/oled-display

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Danke, funktioniert!

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Wenn der Grafikmodus  (lcd.h) eingestellt ist, muß zwingend eine Grafik 
dargestellt werden. Auch wenn es nur ein winziger Kreis in einer Ecke 
ist. Ansonsten wird bei mir kein Text dargestellt. Ist das so gewollt?

von M. K. (sylaina)


Lesenswert?

Reinhard O. schrieb:
> Wenn der Grafikmodus  (lcd.h) eingestellt ist, muß zwingend eine Grafik
> dargestellt werden. Auch wenn es nur ein winziger Kreis in einer Ecke
> ist. Ansonsten wird bei mir kein Text dargestellt. Ist das so gewollt?

Öhm, das kann sein. Im Grafikmode ist auch der Text einfach nur Grafik. 
Egal ob es Grafik oder Text ist, ein lcd_display() muss im Grafikmode 
immer gesendet werden um die Anzeige zu aktualisieren. Schau mal ob du 
nicht zufällig das lcd_display(); gelöscht hast als du im Grafikmode nur 
Text anzeigen wolltest.

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

lcd_display() hatte ich rausgelöscht!
Danke!

: Bearbeitet durch User
von Bessa Wissa (Gast)


Lesenswert?

Bei der Gelegenheit sei einmal angemerkt dass es einem
nativ Englischsprechenden die Haare und Zehennägel zu
Berge stehen lässt wenn er manche englischen Ausdrücke
in den Sourcen sieht.

z.B. LCD_display:

Ja, das ist es wieder, das Liquid Crystal Display Display.

Das Display "displayed". Aber die benannte Funktion displayed
nicht sondern sie schiebt den Inhalt des Buffers in das Display-
Array. Also dürfte sie besser display_update() heissen.

z.B. actual (kommt mehrmals vor).

Das Wort steht nicht - wie der Verfasser vermutet - für
"aktuell" sondern für "tatsächlich".

Wenn ich also übersetze:  displayBuffer[actualIndex+i]
wie würde ich dann "tatsächlicher Index" verstehen sollen?
Gäbe es dann auch einen "nicht so tatsächlichen Index"?

Mir ist es ein Graus, es lebe das Kauderwelsch Englisch.

SCNR

von Welscher (Gast)


Lesenswert?

Bessa Wissa schrieb:
> Bei der Gelegenheit sei einmal angemerkt dass es einem
> nativ Englischsprechenden die Haare und Zehennägel zu
> Berge stehen lässt wenn er manche englischen Ausdrücke
> in den Sourcen sieht.

Bessa Wissa schrieb:
> Mir ist es ein Graus, es lebe das Kauderwelsch Englisch.

Dann geh doch zum Duden - Verlag und verschone uns hier mit deinem 
Gesülze.
So einen Haarspalter wie dich muss man erstmal suchen :-(

LCD-Display oder LED-Display hat sich umgangsprachlich längst etabliert.
Das kennen sogar die Kleinkinder.

von M. K. (sylaina)


Lesenswert?

Welscher schrieb:
> LCD-Display oder LED-Display hat sich umgangsprachlich längst etabliert.
> Das kennen sogar die Kleinkinder.

Genau so sieht es aus. Zudem könnte man auch noch erkennen, dass es 
später dem geneigte Leser helfen könnte. Sobald er lcd_* im Code liest 
könnte man erahnen, dass es eine Funktion für das Display ist und dass 
lcd_display eventuell bedeuten könnte, am LCD etwas zur Anzeige ("to 
display") zu bringen und genau das macht ja die Funktion.
Und zum Thema "actual"...naja, hätte sich Bessa Wissa den Code 
angeschaut wüsste er/sie, dass actualIndex sich auf die tatsächliche 
Cursor-Position bezieht, also eigentlich auch nicht soo verkehrt ist. 
Und ja, es gibt ja auch eine nicht tatsächliche Cursor-Position.

von Reinhard O. (Firma: privat) (flug52)


Lesenswert?

Da könnten wir gleich bei der deutschen Sprache weitermachen, ohne lange 
zu forschen. Und wenn man einmal mit nativ englisch sprechenden Bürgern 
in einer Gaststätte war, bäumen sich einem zu entsprechende später 
Stunde nicht nur die Zehennägel auf.
Da lobe ich mir doch das doppelt gemoppelte LCD-Display.

von 900ss (900ss)


Lesenswert?

Reinhard O. schrieb:
> rausgelöscht

Kann man auch reinlöschen? ;)

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Erstmal ein Danke an Michael Köhler für den Code!

Ich hab das Library um Unterstützung für STM32/HAL erweitert, und paar 
kleinere Fehler beseitigt.

Gegenüber der Original-Version ergeben sich folgende Äderungen:

* lcd_init wird jetzt ohne Parameter aufgerufen.
Ursprünglich wurde versucht, LCD_DISP_ON an die originale init_sequence 
anzuhängen, was aber fehlschlagen muß, da die sich im PROGMEM befindet 
(warum der Compiler da nicht meckert ist mir ein Rätsel)

* i2c.h und i2c.c wurden in i2c_master.h und i2c_master.c umbenannt, um 
Konflikte mit anderen i2c-Librarys zu vermeiden.
Wenn der Code mit einem ARM-gcc übersetzt wird, werden die nicht 
genutzt.

* die Definitionen von YES und NO wurden durch die korrekten 
Definituionen von TRUE und FALSE ersetzt.

* ein Fehler in lcd_invert wurde korigiert.

* Wenn man das Library auf einem STM32 nutzt, muß bei lcd_init() als 
einziger Parameter die Adresse des Handles der I²C-Schnittstelle 
übergeben werden.
Bsp.:
1
  lcd_init(&hi2c1);

*Der Aufruf von lcd_display() ist mit STM32 nicht mehr erforderlich, da 
das Display-Update im Hintergrund mit DMA und Interrupt erfolgt.
Aus Gründen der Kompatibilität ist die Funktion auch bei STM32 weiter 
enthalten, tut aber nichts.

* Bei Nutzung mit STM32 läuft das Lbrary IMMER im Graphic-Mode.

* Auf AVRs sollte sich das Library unverändert nutzen lassen, lediglich 
lcd_init() braucht keine LCD_DISP_ON als Parameter.
Bitte testen und Rückmeldung geben, da ich das nicht testen konnte!

* Der Code "erkennt" selbst, mit welchem Compiler er übersetzt wird, und 
es müssen keine zusätzlichen Defines gesetzt werden

* Es könnte/wird vermutlich noch Probleme mit den SH1106-Displays auf 
STM32 geben, was ich mangels Hardware nicht testen kann.

Freue mich über Rückmeldung.

Harry

: Bearbeitet durch User
Beitrag #5522868 wurde vom Autor gelöscht.
von Dieter F. (Gast)


Lesenswert?

Harry L. schrieb:
> * lcd_init wird jetzt ohne Parameter aufgerufen.

Harry L. schrieb:
> * Wenn man das Library auf einem STM32 nutzt, muß bei lcd_init() als
> einziger Parameter die Adresse des Handles der I²C-Schnittstelle
> übergeben werden.
> Bsp.:  lcd_init(&hi2c1);

Konsistenz ist Wahrheit :-) sagte mein Ex-Chef-Chef-Chef ...

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> ...
> Freue mich über Rückmeldung.
> ...

Danke für deine Mühe. Bei Gelegenheit werde ich mir das mal anschaun und 
ggf. übernehmen wenn ich darf ;).

Harry L. schrieb:
> * lcd_init wird jetzt ohne Parameter aufgerufen.
> Ursprünglich wurde versucht, LCD_DISP_ON an die originale init_sequence
> anzuhängen, was aber fehlschlagen muß, da die sich im PROGMEM befindet
> (warum der Compiler da nicht meckert ist mir ein Rätsel)

Das hast du nicht richtig gesehen. Richtig ist, dass die Init-Sequence 
im PROGMEM liegt. Bei der lcd_init wird aber die Init-Sequence aus dem 
PROGMEM in eine Array, das im SRAM liegt, geladen, dann wird der 
Parameter LCD_DISP_ON dem Array noch hinten angehangen und anschließend 
das Array zum Display übertragen ;)

Den Parameter bei lcd_init() werde ich aber lassen, eine Idee der 
Library war ja u.a. dass man ein HD44780-Display (Library von Peter 
Fleury) durch ein OLED-Display ersetzen kann und lediglich die Library 
im entsprechenden Projekt austauschen muss ohne den Code sonst zu 
ändern. Ich muss nur mal schaun dass ich noch die Cursor-Funktionen 
implementiere.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> ggf. übernehmen wenn ich darf

Du darfst nicht nur, du sollst sogar! ;)

M. K. schrieb:
> Den Parameter bei lcd_init() werde ich aber lassen, eine Idee der
> Library war ja u.a. dass man ein HD44780-Display (Library von Peter
> Fleury) durch ein OLED-Display ersetzen kann und lediglich die Library
> im entsprechenden Projekt austauschen muss ohne den Code sonst zu
> ändern.

Ok, hab ich wieder eingebaut.

Ich hab jetzt doch noch grössere Änderungen am Code vorgenommen:

* zahlreiche "MagicNumbers" durch sinnvolle Defines ersetzt
* Kommentare hinzugefügt
* Die putc()-Funktion hat mir gar nicht gefallen.

Ich hab die neu gebaut, und das jetzt so gelöst:
1
/*
2
 * maps char to index of font-table
3
 * if char not found, 0xff is returned
4
 */
5
static inline uint8_t
6
map_char2fnt (char c)
7
{
8
  uint8_t i, idx;
9
  if ((c >= 0x20) && (c <= 0x7f))
10
    idx = (uint8_t) c - 0x20;
11
  else
12
    {
13
      for (i = 0;(pgm_read_byte(&fnt_map[i].idx) != 0xff)
14
               && (pgm_read_byte(&fnt_map[i].c) != c); i++);
15
      idx = pgm_read_byte(&fnt_map[i].idx);
16
    }
17
  return idx;
18
}
19
20
21
/*
22
 * print a single character on display and advance cursor
23
 *
24
 */
25
void
26
lcd_putc (char c)
27
{
28
  uint8_t fnt_idx;
29
  fnt_idx = map_char2fnt (c);
30
  cursorPosition++;
31
  if (fnt_idx != 0xff)
32
    {
33
#ifdef TEXTMODE
34
      i2c_start(OLED_I2C_ADR);
35
      i2c_byte(OLED_DTA_PREFIX);  // 0x00 for command, 0x40 for data
36
#endif
37
      for (uint8_t i = 0; i < 6; i++)
38
  {
39
#ifdef GRAPHICMODE
40
    displayBuffer.buf[actualIndex + i] = pgm_read_byte(
41
        &oled_font6x8[fnt_idx][i]);      // print font to ram, print 6 columns
42
#else
43
    i2c_byte(pgm_read_byte(&oled_font6x8[fnt_idx][i]));  // print font to ram, print 6 columns
44
#endif
45
  }
46
#ifdef TEXTMODE
47
      i2c_stop();
48
#endif
49
    }
50
#ifdef GRAPHICMODE
51
  actualIndex += 6;
52
#endif
53
}

Die fnt_map sieht so aus und mapped nur die Sonderzeichen:
1
typedef struct
2
{
3
  char c;    // char-code
4
  uint8_t idx;    // index in font-table
5
} fnt_map_t;
6
7
// font-map for extra-chars
8
const fnt_map_t fnt_map[] PROGMEM =
9
  {
10
    { 132, 97 },    // ä
11
    { 148, 99 },    // ö
12
    { 129, 95 },    // ü
13
    { 142, 98 },    // Ä
14
    { 153, 100 },    // Ö
15
    { 154, 96 },    // Ü
16
    { 248, 101 },    // °
17
    { 225, 102 },    // ß
18
//    { 230, 103 },    // µ    * not yet implemented *
19
//    { 234, 104 },    // Omega (Ohm)  * not yet implemented *
20
    { 0, 0xff }      // end of table
21
  };

Im Lauf des Tages, sobald ich den Code mit AVR getestet hab, werde ich 
den neuen Code hochladen.

Insgesamt ist der Code (und auch das Compilat) dadurch kürzer geworden.

Harry

: Bearbeitet durch User
Beitrag #5524800 wurde vom Autor gelöscht.
von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

So, hier nun die neue Version.

Alle Dinge, die vom User einstellbar sind befinden sich jetzt in
oled_config.h.

Den Code hab ich teilweise ziemlich stark umgebaut und kommentiert.
Getestet hab ich mit einem SSD1306 auf AVR im Text- und Graphicmode,
sowie mit STM32.

Was noch offen ist, ist die Unterstützung für SH1106.
Ich werd mir mal so ein Display bestellen, damit ich das auch
vervollständigen und testen kann, aber vielleicht hat ja auch jemand von
euch Lust dazu.
Viel ist da nicht mehr zu tun.

Wie üblich:
Bitte um Rückmeldungen!


Harry

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Und noch eine neue Version

* kleinere Bugs beseitigt
* Code weiter aufgeräumt
* Redundanzen im Code beseitigt
* neue Funktion:
1
void lcd_on(uint8_t onoff);
Damit kann man das Display abschalten und in den Stromspar-Mode 
versetzen.
Der Bildschirminhalt bleibt dabei erhalten.
* Bei der Ausgabe von Strings wird am Ende einer Zeile automatisch ein 
Zeilenumbruch eingefügt und in der folgenden Zeile weiter geschrieben. 
In der letzten Zeile wird zurück auf die erste Zeile gesprungen.
* SH1106 fehlt nach wie vor
* Im Zeichensatz sollten noch 2 Zeichen eingepflegt werden:
µ -> Bsp: µV, µA, µF etc.
Omega -> das Zeichen für Ohm

Die sind derzeit nur als Dummys im Zeichensatz.(die letzten 2 Zeichen)

Details siehe Code.


Harry

: Bearbeitet durch User
von Fabian F. (fabian_f55)


Lesenswert?

Du kennst den Font Generator für das Display?
http://oleddisplay.squix.ch/#/home

Generiert sehr Speicher-effizient auch größere Fonts. Ist nur etwas 
kmplizierter zu prozessieren.

von Harry L. (mysth)


Lesenswert?

Fabian F. schrieb:
> Du kennst den Font Generator für das Display?
> http://oleddisplay.squix.ch/#/home

Danke!
Schau ich mir an.

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Die Änderungen an dem originalen Code von Michael Köhler sind inzwischen 
so umfangreich geworden, daß kein Stein mehr auf dem Anderen geblieben 
ist.

Hinzu gekommen ist u.A. ein 6- und 4-Zeilen Modus
Besonders der 6-Zeilen Mode sieht wirklich schick aus (siehe Anhang)
Der läuft allerdings leider nur im Grafik-Mode.

Was geblieben ist, ist die Möglichkeit, weiter den Text-Mode mit einem 
Speicherbedarf von <2k Flash und 21 Byte RAM zu nutzen. (nur auf 
8bit-AVR)

Zusätzlich steht im Text-Mode jetzt auch ein 4-zeiliger Mode zur 
Verfügung, der die Portierung von einem klassischen HD44780-Display 
erleichtern sollte.
Der funktioniert zwar im Textmode, sieht aber auch erst im Grafik-Modus 
wirklich schick aus, da ich da das gesamte Bild auf dem Screen 
zentrieren kann.

Zusätzlich wurden \n, \r und \b in der putc()-Funktion implementiert.

Aktuell muß ich noch einen Bug in der STM32-Umsetzung beseitigen, und 
sobald das auch läuft, werde ich einen neuen Thread eröffnen, da mein 
Fork mit dem Original ohnehin nicht mehr viel zu tun hat.

Der neue Code wird dann auch via GitHub zur Verfügung stehen.

Harry

: Bearbeitet durch User
von Frank D. (Firma: Spezialeinheit) (feuerstein7)


Lesenswert?

Ich hasse ja eigentlich meckerrei in der Codeecke. Aber hättest du das 
Display nicht mal abwischen können? Sieht ja aus wie 10 Jahre 
Industrieeinsatz.
Ansonsten, danke für deine Arbeit, ich habe ein wenig in asm mit dem 
Display gespielt, wenn mal mehr Zeit ist geht es da hoffentlich weiter.

von Harry L. (mysth)


Lesenswert?


: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Hallo Harry,

ich hab mir mal deine Lib angeschaut und mir ist der ein und andere 
Schnitzer aufgefallen. Ich fang mal mit was einfachem an:
1
void lcd_command(uint8_t cmd[], uint8_t size, uint8_t fromFlash)
2
{
3
  i2c_start(OLED_I2C_ADR);
4
  i2c_byte(OLED_CMD_PREFIX);  // 0x80 for command
5
  for (uint8_t i = 0; i < size; i++)
6
  {
7
    if (fromFlash == TRUE)
8
      i2c_byte(pgm_read_byte(&cmd[i]));
9
    else
10
      i2c_byte((uint8_t)cmd[i]);
11
  }
12
  i2c_stop();
13
}
Hier schon mal eine Frage: Warum hast du die Unterscheidung, ob die 
Daten im RAM oder im FLASH liegen in die Command-Funktion verschoben? Du 
(und auch ich) laden nur ein einziges Mal Daten aus dem Flash: Bei der 
Initialisierung. Da so eine if-Schleife für einen µC eigentlich immer 
doof ist, die Command-Funktion aber öfter aufgerufen wird, ist das 
eigentlich nicht sehr sinnvoll. Und bei lcd_data() hast du das auch 
gemacht und auch da ist es genauso wenig sinnvoll.

Dann musst du noch mal überprüfen, ob wirklich alles so geht wie du dir 
das vorgestellt hast. Willst zu z.B. wirklich niemals auf einem ARM 
einen String aus dem Flash laden? Mir fielen nämlich folgende Zeilen 
auf:
1
...
2
#ifndef __ARM_ARCH
3
void lcd_puts_p(const char* progmem_s)
4
...
Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen 
müssen?

von Johannes S. (Gast)


Lesenswert?

M. K. schrieb:
> Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen
> müssen?

Der ARM hat einen linearen Adressraum für RAM und Flash, da ist die 
unterschiedliche Behandlung wie beim AVR nicht nötig. Der (kopierte?) 
Kommentar in dem STM32 Beispiel ist da irreführend.

Die paar Zyklen für die if-Abfrage dürften kaum wehtun, dafür ist der 
Code sicher wenn die Daten im Ram liegen. Wenn man das 'fromFlash' Flag 
beim Aufruf richtig setzt.

von Stefan F. (Gast)


Lesenswert?

Ich mische mich da mal ein:

M. K. schrieb:
> Warum hast du die Unterscheidung, ob die
> Daten im RAM oder im FLASH liegen in die Command-Funktion verschoben?

Vielleicht, weil es nur eine kleine if Anweisung kostet. Ich vermute, 
dass der Compiler sie heraus optimiert, wenn die Funktion mit einer 
Konstante aufgerufen wird. Aber selbst wenn nicht: Ein if mehr oder 
weniger macht den Kohl nicht fett.

> Willst zu z.B. wirklich niemals auf einem ARM
> einen String aus dem Flash laden?
> Beim ARM solls also wirklich nötig sein, dass alle Strings im RAM liegen
> müssen?

Die mir bekannten ARM Controller haben einen gemeinsamen Adressraum für 
Flash und RAM. Die ganze _P Funktionen sind dort schlicht unnötig.

Nachtrag: Jetzt merke ich gerade, dass Johannes S. schon das selbe 
schrieb. Egal, kommt mein Senf halt noch oben drauf :-)

von M. K. (sylaina)


Lesenswert?

Johannes S. schrieb:
> Der ARM hat einen linearen Adressraum für RAM und Flash, da ist die
> unterschiedliche Behandlung wie beim AVR nicht nötig.

Ah, OK. Mit ARMs hatte ich bisher wenig bis gar nichts zu tun.

Johannes S. schrieb:
> Die paar Zyklen für die if-Abfrage dürften kaum wehtun, dafür ist der
> Code sicher wenn die Daten im Ram liegen.

Naja, die Unterscheidung gibts bei mir ja auch, allerdings nur da, wo 
sie gebraucht wird. Die Frage war ja, warum er (Harry) es verschoben 
hat. Bei einem ARM würde ich wahrscheinlich eh zur u8g-lib oder 
ähnliches greifen.

von 900ss (900ss)


Lesenswert?

M. K. schrieb:
> if-Schleife

Aua......

von Harry L. (mysth)


Lesenswert?

Wie oben schon erklärt:
Die einzelne if-Bedingung tut nicht weh.
Auf die Art hab ich aber eine Funktion um Daten auf den I²C-Bus zu 
schreiben und nicht unübersichtlich viele Einzelabfragen quer über den 
Code verstreut.


M. K. schrieb:
> Du
> (und auch ich) laden nur ein einziges Mal Daten aus dem Flash
Ich schreibe im Textmode auch die Fonts diekt aus dem Flash.
Das spart mehr CPU-Zyklen als ich schlimmstenfalls durch die 
if.Bedingung verliere.

Alles, was mit AVR-PROGMEM zu tun hat, wird via Makro unwirksam gemacht, 
sobald für ARM compiliert wird (bei ARM reicht const um das ins Flash zu 
legen):
1
#ifdef __ARM_ARCH
2
/*
3
 * ARM-speciffic macros and functions
4
 */
5
#define PROGMEM
6
#define pgm_read_byte(a)  (*(a))
7
#define PSTR(a)      (a)
8
#define lcd_puts_p(a)    lcd_puts(a)
9
#define memcpy_P(a,b,c)    memcpy(a,b,c)

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Die einzelne if-Bedingung tut nicht weh.
Aber sie unnötig oft aufrufen muss ja auch nicht sein ;)

Harry L. schrieb:
> Auf die Art hab ich aber eine Funktion um Daten auf den I²C-Bus zu
> schreiben und nicht unübersichtlich viele Einzelabfragen quer über den
> Code verstreut.

Nun, die waren vorher auch nicht da ;)

900ss D. schrieb:
> M. K. schrieb:
>> if-Schleife
>
> Aua......

Oh, ein Genauer. Ich denke jeder weiß, was gemeint war, auch du. ;)

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Bei einem ARM würde ich wahrscheinlich eh zur u8g-lib oder
> ähnliches greifen.

Weshalb?

Genau DAS wolltest du ja mit deinem Library vermeiden, und warum sollte 
man das auf einem ARM brauchen?
Dem Display ist es herzlich egal, welcher Controller die (korrekten) 
Daten liefert.

Auch ARM hat nur eine endliche Menge Speicher, und bei der 
µC-Programmierung sollte man immer den Speicherverbrauch im Auge 
behalten.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Nun, die waren vorher auch nicht da ;)

Jede Art von Redundanz reduziert die Wartbarkeit eines Code.
Ausserdem lese ich (s.o.) im Textmode die Font-Daten direkt aus dem 
Flash ohne die im RAM zwischen zu speichern.
1
#ifdef GRAPHICMODE
2
#if (OLED_LINES == 8)
3
      memcpy_P(&displayBuffer.buf[cursor.y][(cursor.x * OLED_FONT_WIDTH) + OLED_HSHIFT],
4
          &oled_font6x8[fnt_idx], OLED_FONT_WIDTH);
5
#else

Mir ist ein sauberer Programmierstil wichtiger, als irgendwo einzelne 
Takt-Zyklen einzusparen.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Weshalb?
>
> Genau DAS wolltest du ja mit deinem Library vermeiden

Und genau da beißt sich die Katze in den Schwanz. Ich hab die Lib 
erstellt weil u.a. die u8g-lib einfach zu groß für einen Atmega48/88 
ist.

Harry L. schrieb:
> Jede Art von Redundanz reduziert die Wartbarkeit eines Code.
> Mir ist ein sauberer Programmierstil wichtiger, als irgendwo einzelne
> Takt-Zyklen einzusparen.

Ja, aber viele kleine, gesparte Taktzyklen, können zu unschönen 
Nebeneffekten führen. Ist ja auch so ein netter Nebeneffekt, dass meine 
Lib auch noch schneller ist als die u8g-lib ;)

von Harry L. (mysth)


Lesenswert?

Vergleich doch einfach mal die Codegrösse der ursprünglichen mit meiner 
Library!

Da ist kein grosser Unterschied, und wenn du die Geschwindigkeit im 
8Zeilen-Mode vergleichst, ist meine Version theoretisch sogar schneller, 
da ich mir das Zwischenspeichern der Font-Daten im RAM erspare.

"Theoretisch" deshalb, da der wirklich limitierende Faktor die 
Geschwindigkeit des I²C-Bus ist.

Die erstmal auf 400 kHz hoch zu drehen bringt erheblich mehr, als der 
Versuch irgendwo einzelne Taktzyklen zu sparen.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Vergleich doch einfach mal die Codegrösse der ursprünglichen mit meiner
> Library!

Hab ich, meine Code braucht weniger Flash-Speicher.

Harry L. schrieb:
> Da ist kein grosser Unterschied, und wenn du die Geschwindigkeit im
> Text-Mode vergleichst, ist meine Version sogar schneller, da ich mir das
> Zwischenspeichern der Font-Daten im RAM erspare.

Nö, da irrst du da du mit deinem Umstricken sehr viel öfters ein 
i2c_start und i2c_stop aufrufst. Meine Lib braucht bei 400 kHz Taktrate 
rund 5 ms zum Beschreiben einer Zeile, deine Lib braucht rund 10 ms

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Meine Lib braucht bei 400 kHz Taktrate
> rund 5 ms zum Beschreiben einer Zeile, deine Lib braucht rund 10 ms

Dann würde ich aber gern mal sehen, wie du auf diese Werte kommst...

Btw. erreich ich auf einem STM32F1xx >40fps
Schnell genug?

von Harry L. (mysth)


Lesenswert?

J. W. schrieb:
> oled-display:11: error: 'lcd_display' was not declared in this scope
>  lcd_display();
>              ^
> exit status 1
> 'lcd_display' was not declared in this scope

Dann zeig mal deinen Code!

im Verz. AVR-sample befindet sich ein Beispiel.
1
/*
2
 * main.c
3
 *
4
 *  Created on: 16.08.2018
5
 *      Author: harry
6
 */
7
8
#include <avr/io.h>
9
#include <stdio.h>
10
#include "lcd.h"
11
12
int main()
13
{
14
char s[21];
15
    // put your setup code here, to run once:
16
  lcd_init(OLED_DISPLAYON);    // init lcd and turn on
17
18
#if defined GRAPHICMODE
19
  sprintf(s, "%d-Line graphic-mode\r\n", OLED_LINES);
20
#else
21
  sprintf(s, "%d-Line text-mode\r\n", OLED_LINES);
22
#endif
23
    lcd_puts(s);  // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
24
    lcd_puts("20 chars per line\r\n");
25
    lcd_puts_p(PSTR("special chars:\r\n\x84\x94\x81\x8e\x99\x9a\xf8\xe1\r\n"));
26
    for (uint8_t i=4;i < (OLED_LINES - 1);i++)
27
    {
28
        sprintf(s, "Line %2d\r\n", i+1);
29
        lcd_puts(s);  // put string from RAM to display (TEXTMODE) or buffer (GRAPHICMODE)
30
    } /**/
31
#if defined GRAPHICMODE
32
    lcd_puts ("Isn't it nice?");
33
#else
34
    lcd_puts ("Isn't it ugly?");
35
#endif
36
37
//    lcd_gotoxy(0,2);          // set cursor to first column at line 3
38
//    lcd_puts_p(PSTR("String from flash"));  // puts string form flash to display (TEXTMODE) or buffer (GRAPHICMODE)
39
  #if defined GRAPHICMODE
40
    lcd_drawRect(0,0,127,63,WHITE);
41
    lcd_drawCircle(96,42,7,WHITE); // draw circle to buffer white lines
42
    lcd_display();                 // send buffer to display
43
  #endif
44
45
    while(1)
46
    {
47
48
    }
49
50
}

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Btw. erreich ich auf einem STM32F1xx >40fps
> Schnell genug?

Aber sicher nicht bei 400 kHz Taktrate.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Harry L. schrieb:
>> Btw. erreich ich auf einem STM32F1xx >40fps
>> Schnell genug?
>
> Aber sicher nicht bei 400 kHz Taktrate.

Aber Ja!

Rechne mal nach! ;)

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> M. K. schrieb:
>> Harry L. schrieb:
>>> Btw. erreich ich auf einem STM32F1xx >40fps
>>> Schnell genug?
>>
>> Aber sicher nicht bei 400 kHz Taktrate.
>
> Aber Ja!
>
> Rechne mal nach! ;)

Hab ich. Das Display besteht aus 128*64 Pixel, macht also 12288 Bits zum 
übertragen. Bei 40 fps musst du 327680 Bits übertragen. Wird eng bei 400 
kHz. Und der Overhead ist da nicht mit drin.

Harry L. schrieb:
> Dann zeig mal deinen Code!

Öhm, der steht doch oben.

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Das Display besteht aus 128*96 Pixel

128 * 64 Pixel = 8192 Bit = 1024 Byte = 1kB

Ich sende via DMA den kompletten Buffer in einem Rutsch an den 
Controller, und sobald der fertig ist, geht das Spielchen von Vorne los.
Die Präambel (1 Byte) muss dabei nur 1mal pro Buffer-Write gesendet 
werden.

Das Programm läuft während dessen ungebremst weiter.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> M. K. schrieb:
>> Das Display besteht aus 128*96 Pixel
>
> 128 * 64 Pixel = 1024 Byte = 1kB

Ja, hatte mich oben vertan mit der größe. Eng wirds dennoch.

Dass es auf dem STM besser/schneller geht als auf nem AVR glaub ich dir 
ja gern. Ich habs halt hier auf nem Atmega328p verglichen und da zeigt 
sich, dass mein Code schneller unterwegs ist.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Ich habs halt hier auf nem Atmega328p verglichen und da zeigt
> sich, dass mein Code schneller unterwegs ist.

Den Beweis bist du bisher aber schuldig geblieben.
Und ich meine nicht die Anzahl der Taktzyklen, sondern die tatsächliche
Geschwindigkeit der Ausgabe auf dem Display.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Den Beweis bist du bisher aber schuldig geblieben.
> Und ich meine nicht die Anzahl der Taktzyklen, sondern die tatsächliche
> Geschwindigkeit der Ausgabe auf dem Display.

Welchen Beweis denn bitte schön? Was genau erwartest du? Verstehe ich 
nicht.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Welchen Beweis denn bitte schön? Was genau erwartest du? Verstehe ich
> nicht.

Eine nachvollziehbare Erklärung/Beweis, daß deine Funktionen so viel 
schneller sind wie du behauptest (5ms vs. 10ms)

Zeig mir ein Code-Beispiel an dem das erkennbar ist!

von M. K. (sylaina)


Lesenswert?

Ach das meinst du, da hab ich meinen Code von damals genommen:
1
#include "main.h"
2
3
#include <stdlib.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include "i2c_master.h"
7
#include "lcd.h"
8
9
volatile uint16_t overflows=0;
10
11
int main(void)
12
{
13
    
14
    i2c_init();
15
    
16
    lcd_init(OLED_DISPLAYON);
17
    lcd_clrscr();
18
    
19
    sei();
20
    
21
    TCCR1B |= (1 << CS00);
22
    lcd_puts("M. Koehler 2016/2017");
23
    TCCR1B &= ~(1 << CS00);
24
    
25
    
26
    char time[6];
27
    
28
    dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3,
29
            6,
30
            3,
31
            time);
32
    lcd_gotoxy(0,6);
33
    lcd_puts("Time to print Line 1:");
34
    lcd_gotoxy(0,7);
35
    lcd_puts(time);
36
    lcd_puts("ms");
37
    
38
    lcd_display();
39
    for(;;){
40
        /* insert your main loop code here */
41
    }
42
    return 0;   /* never reached */
43
}
44
ISR(TIMER1_OVF_vect){
45
    overflows++;
46
}

Und wie gesagt, bei meinem Code bekomme ich knapp 5ms angezeigt, bei 
deinem knapp 10ms.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Und wie gesagt, bei meinem Code bekomme ich knapp 5ms angezeigt, bei
> deinem knapp 10ms.

Text- oder GraphicMode?
Für den Text-Mode kann ich mir das kaum vorstellen.

Mein Graphic-Mode ist allerdings deutlich aufwendiger als deiner, da ich 
die Ausgabe vertikal wie horizontal zentriere was einiges an Bit-Shifts 
erfordert, aber auch das erklärt nicht so einen Unterschied.

Allerdings stört mich das bei reiner Textausgabe sowieso wenig,da das 
immer noch mehr als schnell genug für unsere Augen ist.

Am meisten Zeit und Platz vergeudest du übrigens hiermit:
1
dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3,
2
            6,
3
            3,
4
            time);

Wozu du da float brauchst, ist mir vollkommen schleierhaft.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Am meisten Zeit und Platz vergeudest du übrigens
> hiermit:dtostrf((overflows*65536.0+TCNT1)/F_CPU*1e3,
>             6,
>             3,
>             time);
>
> Wozu du da float brauchst, ist mir vollkommen schleierhaft.

Das ist in der Zeitmessung nicht mehr mit drin und wenn es dir 
vollkommen schleierhaft ist wozu ich da float benutze kann ich da auch 
nicht weiter helfen. Das war die einfachste/schnellste Variante x,yz ms 
anzuzeigen.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Das war die einfachste/schnellste Variante x,yz ms
> anzuzeigen.

Die einfachste vielleicht, aber ganz sicher nicht die schnellste..

von Harry L. (mysth)


Lesenswert?

Sei mir bitte  nicht böse, aber ich gewinne zunehmend den Eindruck, daß 
du angepisst bist, weil jemand es gewagt hat, deinen Code einem 
kompletten Redesign zu unterziehen, und du darum so lange mit dem Kopf 
schüttelst, bis du das Haar in der Suppe findest.

Glaub mir einfach, daß unsere Design-Goals die Selben sind:
Größe und Geschwindigkeit

Es macht aber imho wenig Sinn, einige gesparte Taktzyklen mit schlecht 
les-/wartbarem Code zu erkaufen, und erst Recht dann nicht, wenn diese 
Einsparungen nur minimalen Einfluss auf das Gesamt-Ergebnis haben.

Das Ziel meines Redesign war nicht, deine Programmier-Fähigkeiten in 
Frage zu stellen, sondern die Usability dieses Library zu verbessern.

Du hängst dich an Kleinigkeiten auf, aber die wirklich relevanten 
Unterschiede hast du bisher mit keinem Wort erwähnt:

* die deutlich verbesserte putc-Routine
* die leichte Erweiterbarkeit des Font um individuelle Sonderzeichen.
* Die Möglichkeit bei den Graphic-Funktionen nicht nur s/w sondern auch 
invertierend zu zeichnen.

Sowas ist mir die paar Bytes mehr an Code wert, und selbst wenn meine 
Funktionen in einzel-Aspekten vielleicht sogar etwas langsamer als deine 
laufen, so sind das bezogen auf den gesamten Bildaufbau ganz sicher 
keine 100% Unterschied, und ich behaupte, daß das ein normaler Mensch 
auf dem Display ganz sicher nicht wahrnehmen wird.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Sei mir bitte  nicht böse, aber ich gewinne zunehmend den Eindruck, daß
> du angepisst bist, weil jemand es gewagt hat, deinen Code einem
> kompletten Redesign zu unterziehen, und du darum so lange mit dem Kopf
> schüttelst, bis du das Haar in der Suppe findest.

Nö, das ist überhaupt nicht der Fall, es ist gar das Gegenteil. Ich 
finde toll was du gemacht hast, das ist keine Frage. Mir sind halt 
gestern nur zwei, ich sag mal, Merkwürdigkeiten aufgefallen und die hab 
ich angesprochen da sie aus meiner Sicht keinen Sinn machten.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Nö, das ist überhaupt nicht der Fall, es ist gar das Gegenteil. Ich
> finde toll was du gemacht hast, das ist keine Frage. Mir sind halt
> gestern nur zwei, ich sag mal, Merkwürdigkeiten aufgefallen und die hab
> ich angesprochen da sie aus meiner Sicht keinen Sinn machten.

Ok, dann hab ich das wohl falsch interprettiert.
Sorry!

Du beziehst dich auf den aktuellen Code im Github?
Der Link wurde in diesem Thread ja noch gar nicht genannt.

https://github.com/HarryLipphaus/OledLib

von M. K. (sylaina)


Lesenswert?

Sodele, hab ein wenig an meiner Lib rumgeschnitzt.

- lcd_putc()

Habe ich vereinfacht wodurch sie übersichtlicher (und noch mal 
schneller) wurde.

- Sonder-/Extrazeichen

und deren Auswertung sind nun, wie auch der Font, in eine eigenen 
Header-Datei gewandert.

- einige Steuerzeichen wurde ergänzt

die Lib erkennt nun die Steuerzeichen tab, linefeed und carrige-return.

- lcd-invert()

wurde gefixt, hier war noch ein Fehler drin denn unabhängig vom Argument 
wurde das Display da immer auf Not-Inverted gesetzt, da ist mir ein 
Tippfehler unterlaufen gewesen.

Der Referenzstring aus meinem Eröffnungpost benötigt nun im Fastmode 
(400 kHz I2C-Taktrate) ca. 2.6 ms bis er geschrieben ist im Textmode.

https://github.com/Sylaina/oled-display

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Sodele, hab ein wenig an meiner Lib rumgeschnitzt.
>
> - lcd_putc()
>
> Habe ich vereinfacht wodurch sie übersichtlicher (und noch mal
> schneller) wurde.

Und es gibt immer noch 2 komplett unabhängige lcd_put() (Text- und 
Graphic-Mode), die sich nur in wenigen Zeilen unterscheiden.

Wozu?

Wartbarer Code sieht anders aus!

M. K. schrieb:
> - einige Steuerzeichen wurde ergänzt

Und gleich ne ganze switch-Kaskade um das Sonderzeichen auszuwählen...
Mag vielleicht paar ns sparen, ist aber hässlicher Stil und dazu 
unflexibel.

Was stört dich an meiner Variante?
* Die 22 Byte Flash für die Tabelle?
* Die paar ns, die er bei dem selten auftretenden Sonderzeichen zum 
Durchsuchen der Tabelle benötigt?

Meine Version ist flexibler/generischer bei Erweiterungen um einzelne 
Zeichen, funktioiert mit allen Zeichen und belegt weniger Flash
1
// font-map for extra-chars
2
const fnt_map_t fnt_map[] PROGMEM =
3
{
4
    { 132, 97 },    // ä
5
    { 148, 99 },    // ö
6
    { 129, 95 },    // ü
7
    { 142, 98 },    // Ä
8
    { 153, 100 },    // Ö
9
    { 154, 96 },    // Ü
10
    { 248, 101 },    // °
11
    { 225, 102 },    // ß
12
    { 230, 103 },    // µ      * only dummy in font *
13
    { 234, 104 },    // Omega (Ohm)  * only dummy in font *
14
    { 0, 0xff }      // end of table
15
};
16
17
18
19
/*
20
 * maps char to index of font-table
21
 * if char not found, 0xff is returned
22
 */
23
static uint8_t map_char2fnt(char c)
24
{
25
  uint8_t i, idx;
26
  if ((c >= 0x20) && (c <= 0x7f))
27
    idx = (uint8_t) c - 0x20;
28
  else
29
  {
30
    for (i = 0;
31
        (pgm_read_byte(&fnt_map[i].idx) != 0Xff)
32
            && (pgm_read_byte(&fnt_map[i].c) != c); i++)
33
      ;
34
    idx = pgm_read_byte(&fnt_map[i].idx);
35
  }
36
  return idx;
37
}

M. K. schrieb:
> Der Referenzstring aus meinem Eröffnungpost benötigt nun im Fastmode
> (400 kHz I2C-Taktrate) ca. 2.6 ms bis er geschrieben ist im Textmode.

Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den 
Unterschied zw. 2,6ms und 12,5ms "sieht"?

Genau die Punkte, die mich zum Redesign bewogen haben sind in dieser 
Version genauso enthalten - nur teilweise "verschlimmbessert"

Das sind genau die Optimierungen, die in der Praxis genau gar nichts 
bringen, aber den Code alles Andere als schöner machen.

von Stefan F. (Gast)


Lesenswert?

Harry L. schrieb:
> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den
> Unterschied zw. 2,6ms und 12,5ms "sieht"?

Ob der Rest des Programms 9,9ms mehr oder Weniger zur Verfügung hat, 
kann schon einen erheblichen Unterschied machen.

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Harry L. schrieb:
>> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den
>> Unterschied zw. 2,6ms und 12,5ms "sieht"?
>
> Ob der Rest des Programms 9,9ms mehr oder Weniger zur Verfügung hat,
> kann schon einen erheblichen Unterschied machen.

Jaja....weil man natürlich die zeitkritischen Dinge in der main() 
erledigt....

Wenn man programmieren kann, ist es vollkommen unerheblich, wie lange 
die Ausgabe eines String auf einem Display dauert.
Die Display-Ausgabe hat sowieso die niedrigste Priorität von Allen.
Da zählt nur, daß es für den Bediener (Mensch) schnell genug ist damit 
der nicht ungeduldig wird.

von Harry L. (mysth)


Lesenswert?

Ich hab jetzt auch mal nachgemessen:

Meine Ausgabe (Textmode, 20 Zeichen/Zeile) dauert 4,4ms pro volle Zeile 
(20 Zeichen schreiben)

So gemessen:
MyTimer wird im ms-Takt von einem HW-Timer incrementiert.
1
uint16_t *MyTimer;
2
3
uint32_t uptime;
4
5
#define MYTIMER (*(MyTimer))
6
7
#define TIMETEST
8
9
int main()
10
{
11
char s[21];
12
uint32_t fulltime, linetime;
13
14
    // put your setup code here, to run once:
15
  lcd_init(OLED_DISPLAYON);    // init lcd and turn on
16
  lcd_clrscr();
17
  uint8_t teststring[]="01234567890123456789";
18
19
#ifdef TIMETEST
20
  init_SysTimer(&uptime);
21
  MyTimer = request_SysTimer();
22
23
  MYTIMER = 0;
24
  for (uint8_t i=0; i<7;i++)
25
  {
26
    lcd_gotoxy(0,i);
27
    lcd_puts(teststring);
28
  }
29
  fulltime = (uint32_t)MYTIMER;
30
  linetime = (fulltime * 10) / 7;
31
  sprintf(s, "%ld,%ld ms/line", linetime / 10, linetime % 10);
32
  lcd_gotoxy(0,7);
33
  lcd_puts(s);
34
#endif

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Noch mehr Timing:

Das Schreiben 1 kompl. Zeile (20 Zeichen) im aufwendigen 6-Zeilen-Mode 
in den Framebuffer: 1,0ms

Das Übertragen des Framebuffer auf das Display: 25,4ms

Für das Beschreiben des vollst. Display im 6-Zeilen-Mode macht das dann:

((6 * 1ms) + 25,4ms) / 6 = 5,23ms pro Zeile.


Da beim Überragen einer Zeile des Framebuffe auf das Display 25,4 ms / 8 
= 3,18 ms/Zeile benötigt werden, erscheinen mir die von Michael 
gemessenen 2,6ms unglaubwürdig.

Entweder war das keine vollst. Zeile mit 20 Zeichen, oder da ist 
irgendwo ein Messfehler.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Und es gibt immer noch 2 komplett unabhängige lcd_put() (Text- und
> Graphic-Mode), die sich nur in wenigen Zeilen unterscheiden.
>
> Wozu?

Das steht weiter oben warum das so ist. Das werde ich mit Sicherheit 
nicht noch einmal erklären.

Harry L. schrieb:
> Wartbarer Code sieht anders aus!

Was willst du daran warten, was soll daran unübersichtlich sein?

Harry L. schrieb:
> M. K. schrieb:
>> - einige Steuerzeichen wurde ergänzt
>
> Und gleich ne ganze switch-Kaskade um das Sonderzeichen auszuwählen...
> Mag vielleicht paar ns sparen, ist aber hässlicher Stil und dazu
> unflexibel.

In wiefern soll das unflexibel sein? Und was daran ist hässlicher Stil? 
Ich mein, die Steuerzeichen wählst auch du über ne Switch aus, warum ist 
das bei dir kein hässlicher Stil aber bei mir? Den check ich nicht.

Harry L. schrieb:
> Meine Version ist flexibler/generischer bei Erweiterungen um einzelne
> Zeichen, funktioiert mit allen Zeichen und belegt weniger Flash

Ob meine Variante weniger Flash belegt muss ich mal gleich schaun aber 
weniger flexibel ist sie definitiv nicht. Wie kommst du darauf?

Harry L. schrieb:
> Und du glaubst wirklich, daß ein Mensch bei einer Textausgabe den
> Unterschied zw. 2,6ms und 12,5ms "sieht"?

Nö, aber je schneller das Display abgefrühstückt ist desto eher hat man 
Zeit in der Main andere Dinge zu tun. Es wäre ja schon irgendwie, 
überspitzt formuliert, blöd wenn man in der Main nur Zeit hätte das 
Display zu beschreiben.

Harry L. schrieb:
> Genau die Punkte, die mich zum Redesign bewogen haben sind in dieser
> Version genauso enthalten - nur teilweise "verschlimmbessert"

Das ist natürlich Unsinn.

Harry L. schrieb:
> Das sind genau die Optimierungen, die in der Praxis genau gar nichts
> bringen, aber den Code alles Andere als schöner machen.

Du findest es jetzt also unschöner, dass die Suche&Auswahl des 
Sonderzeichens nicht mehr in der putc() geschieht sondern 
übersichtlicher in der Headerdatei, die auch den Font beinhaltet? 
Interessant.

Harry L. schrieb:
> Meine Ausgabe (Textmode, 20 Zeichen/Zeile) dauert 4,4ms pro volle Zeile
> (20 Zeichen schreiben)

Das ist bei mir ebenso ;)

Harry L. schrieb:
> Das Übertragen des Framebuffer auf das Display: 25,4ms

Das dauert bei mir im Grafikmode 26,858ms. Übrigens: 25,4ms entsprechen 
nicht > 40fps sondern < 40fps ;)

Harry L. schrieb:
> Da beim Überragen einer Zeile des Framebuffe auf das Display 25,4 ms / 8
> = 3,18 ms/Zeile benötigt werden, erscheinen mir die von Michael
> gemessenen 2,6ms unglaubwürdig.
>
> Entweder war das keine vollst. Zeile mit 20 Zeichen, oder da ist
> irgendwo ein Messfehler.

War ein Messfehler. Ich hatte doch in der Tat die falsche Taktquelle für 
den Atmega ausgewählt sodass der Atmega nicht mit 8 MHz lief. Blöder 
Fehler.

Am Besten finde ich deine Kritik an der Wartbarkeit des Codes, und dann 
lese ich z.B. bei dir solche Dinge:
1
...
2
#ifdef __ARM_ARCH
3
...
4
#endif
5
...
6
#ifdef __ARM_ARCH
7
...
8
#endif
9
...

Also wirklich übersichtlicher/besser Wartbar ist das ja nicht. Am besten 
gefällt mir das:
1
...
2
// line 153
3
#ifndef __ARM_ARCH
4
...
5
#endif
6
//line 187
7
#ifdef __ARM_ARCH
8
...
9
#endif
10
...

Warum du bei sowas kein #elif benutzt versteh ich nicht.
Aber, bzgl. Wartbarkeit, wirklich übersichtlich durch diese ganzen, ich 
sag mal, Spagetti-#if's ist dein Code nicht wirklich. Warum hast du hier 
nicht mal richtig nach Architektur sortiert wie etwa so:
1
...
2
#ifdef __ARM_ARCH
3
// alles was zum ARM gehört hier rein
4
#elif
5
// hier alles was zum AVR gehört
6
#endif
7
// hier (oder vor das ifdef) hin alles, was für ARM und AVR benutzt werden soll
8
...

Das wäre erheblich übersichtlicher als so, wie du es jetzt hast.

EDIT:

Ich habe nun auch noch mal verglichen. Mikrocontroller ist ein AVR 
Atmega328p mit internen RC, auf 8 MHz eingestellt (Standardfuse mit 
CLKDIV8 ausgeschaltet)

Im TEXTMODE belegt deine Library mit der nachfolgenden Main 5118 Bytes 
im Flash und es dauert 4.903ms bis die Zeile auf dem Display steht (kein 
Overflow vom Timer und der Count steht bei 39227).
Meine Library belegt 4936 Bytes und sie braucht grade mal 4.399ms bis 
der Text im Display steht (kein Overflow vom Timer und der Count steht 
bei 35195)

Im GRAPHICMODE belegt deine Library mit der nachfolgenden Main 6426 
Bytes im Flash und es dauert 28.177ms bis die Zeile auf dem Display 
steht (3 Overflows vom Timer und der Count steht bei 28810).
Meine Library belegt 6138 Bytes und sie braucht grade mal 27.766ms bis 
der Text im Display steht (3 Overflows vom Timer und der Count steht bei 
25517).

Mit deiner Library braucht der Atmega 1. länger bis die Anzeige da ist 
und 2. belegt sie mehr Flash-Speicher
1
//Testcode
2
#include <stdlib.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include "i2c_master.h"
6
#include "lcd.h"
7
#include <util/delay.h>
8
volatile uint32_t overflows=0;
9
10
int main(void)
11
{
12
    TIMSK1 |= (1 << TOIE1);
13
    i2c_init();
14
    
15
    lcd_init(OLED_DISPLAYON);
16
    lcd_clrscr();
17
  
18
    sei();
19
    lcd_gotoxy(0, 0);
20
    TCCR1B |= (1 << CS10);
21
    lcd_puts(("M. Koehler 2016/2017"));
22
#ifdef GRAPHICMODE
23
  lcd_display();
24
#endif
25
  TCCR1B &= ~(1 << CS10);
26
  
27
  char time[6];
28
  lcd_gotoxy(0, 2);
29
  lcd_puts_p(PSTR("OVF: "));
30
  ltoa(overflows,
31
     time,
32
     10);
33
  lcd_puts(time);
34
  
35
  lcd_gotoxy(0, 3);
36
  lcd_puts_p(PSTR("TCNT1: "));
37
  ltoa(TCNT1,
38
     time,
39
     10);
40
  lcd_puts(time);
41
  
42
    dtostrf((overflows*65536.0+TCNT1)/(float)F_CPU*1e3,
43
            6,
44
            3,
45
            time);
46
  
47
    lcd_gotoxy(0,5);
48
    lcd_puts_p(PSTR("Time to print line 1:\r\n"));
49
    lcd_puts(time);
50
    lcd_puts_p(PSTR("ms"));
51
#ifdef GRAPHICMODE
52
  lcd_display();
53
#endif
54
    for(;;){
55
        /* insert your main loop code here */
56
    }
57
    return 0;   /* never reached */
58
}
59
ISR(TIMER1_OVF_vect){
60
    overflows++;
61
}

EDIT2: Ich hab natürlich die Library von Harry auf 8-Zeilen-Modus 
gesetzt und den I2C-Bus auf 400 kHz eingestellt (I2C_HIGHSPEED definiert 
in der i2c_master.h).

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Du findest es jetzt also unschöner, dass die Suche&Auswahl des
> Sonderzeichens nicht mehr in der putc() geschieht sondern
> übersichtlicher in der Headerdatei, die auch den Font beinhaltet?
> Interessant.

Die Aussage ist schlicht und einfach falsch!
In der .fnt-Datei befindet sich nur die Tabelle mit der Zuordnung.
Die Funktion um den Index eines Zeichen innerhalb des Font zu ermitteln 
steht in lcd.c.

M. K. schrieb:
> Am Besten finde ich deine Kritik an der Wartbarkeit des Codes, und dann
> lese ich z.B. bei dir solche Dinge:
> ...
> #ifdef __ARM_ARCH
> ...
> #endif
> ...
> #ifdef __ARM_ARCH
> ...
> #endif
> ...

Das ist geradezu lächerlich!
Hättest du dir die Mühe gemacht, den Code zu verstehen würdst du hier 
nicht solche Pseudo-Argumente auffahren.

M. K. schrieb:
> Im TEXTMODE belegt deine Library mit der nachfolgenden Main 5118 Bytes
> im Flash und es dauert 4.903ms bis die Zeile auf dem Display steht (kein
> Overflow vom Timer und der Count steht bei 39227).
> Meine Library belegt 4936 Bytes und sie braucht grade mal 4.399ms bis
> der Text im Display steht (kein Overflow vom Timer und der Count steht
> bei 35195)
>
> Im GRAPHICMODE belegt deine Library mit der nachfolgenden Main 6426
> Bytes im Flash und es dauert 28.177ms bis die Zeile auf dem Display
> steht (3 Overflows vom Timer und der Count steht bei 28810).
> Meine Library belegt 6138 Bytes und sie braucht grade mal 27.766ms bis
> der Text im Display steht (3 Overflows vom Timer und der Count steht bei
> 25517).
>
> Mit deiner Library braucht der Atmega 1. länger bis die Anzeige da ist
> und 2. belegt sie mehr Flash-Speicher

Jaja, wer misst, misst Mist!
Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung 
selbst) als Summe ist völlig nichts-sagend.

Für meine Version hab ich valide Werte ermittelt:
Beitrag "Re: Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL"

Demnach brauch ich in der kleinsten Variante 1853 Byte Flash und 9 Byte 
RAM.

Wenn du unbedingt vergleichen willst, dann bitte auch mit belastbaren 
Zahlen.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Leute, streitet euch doch nicht um solche Nichtigkeiten!

Jeder Programmierer hat seinen eigenen Stil. Ich arbeite seit vielen 
Jahren in Teams und hätte es nicht vom ungelernten Anfänger zum Senior 
mit Führungsverantwortung gebracht, wenn ich mich an solchen 
Kleinigkeiten aufgezogen hätte.

Ihr solltet beide akzeptieren, dass andere Lösung auch OK sind. Im 
echten Leben ist es völlig egal, welche Lösung die Beste ist, solange 
man damit das Ziel erreicht.

Schau euch doch nur mal Microsoft an. Jeder Dummkopf sieht, das deren 
Produkte bei weitem nicht optimal sind, und doch ist es eines der 
erfolgreichsten Softwarehäuser. Ein Grund ist ganz sicher der, dass die 
Manager sich nicht auf der Suche nach Perfektion festbeißen.

Lasst es gut sein und freut eich statt dessen darüber, dass eure 
Software tut, was sie soll. Es gibt genug Menschen, die sich mit nicht 
funktionierendem Schrott auseinandersetzen müssen.

Ihr habt hier echt ein Luxusproblem. Lernt bitte, andere Lösungen und 
Meinungen zu akzeptieren. Es verlangt doch niemand, dass ihr euch auf 
die eine einzig wahre Wahrheit einigt. Die gibt es ohnehin nur bei 
religiösen Fanatikern. Über dieses Stadium sollten wir Techniker doch 
erhaben sein, oder nicht?

von Harry L. (mysth)


Lesenswert?

So funktioniert Open-Source aber nicht!

Da setzt sich nämlich die bessere Lösung durch, und die übernimmt man 
dann in seinem Code.

Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um 
Eitelkeiten geht.

von Stefan F. (Gast)


Lesenswert?

Harry L. schrieb:
> So funktioniert Open-Source aber nicht!
> Da setzt sich nämlich die bessere Lösung durch

Nein, das ist die Theorie des Herrn Darwin.

Die Philosophie von Open-Source ist, dass jeder den Code nach seinem 
Gusto ändern kann und dadurch eine große Vielfalt entsteht.

> Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um
> Eitelkeiten geht.

Wenn schon, dann geht es um deine Eitelkeiten.

Nachtrag: Dein -1 kommt von woanders her. Ich finde deine Beiträge 
lesenswert weil du deine Meinung nachvollziehbar kund getan hast. Es 
sagt ja niemand, dass ich gleicher Meinung sein muss. Aber du hast das 
sicher schon bemerkt, dass die Bewertung von "lesenswert/nicht 
lesenswert" oft einfach als "stimme zu/stimme nicht zu" missbraucht 
wird.

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Die Philosophie von Open-Source ist, dass jeder den Code nach seinem
> Gusto ändern kann und dadurch eine große Vielfalt entsteht.

Und genau aus dieser Vielfalt setzt sich das Bessere durch.
Wäre es anders, wäre ein Linux wie wir es heute kennen niemals 
entstanden.

Stefanus F. schrieb:
>> Ich gewinne hier zunehmend den Eindruck, daß es eben doch primär um
>> Eitelkeiten geht.
>
> Wenn schon, dann geht es um deine Eitelkeiten.

Wir sind doch hier nicht im Kindergarten, wo der Sandhaufen von Kevin 
eine genau so tolle Sandburg ist wie der Sandhaufen von Jaqueline.

Wir reden doch über Fakten.

ich hätte/habe jedenfalls kein Problem damit, fremden Code zu 
übernehmen, "wenn" er tatsächlich nach Fakten-Lage besser/effektiver als 
meine Lösung ist.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung
> selbst) als Summe ist völlig nichts-sagend.

Sorry, aber das zeigt eindeutig, dass du anscheinend absolut keine 
Ahnung hast, wie man Zeiten mit einem AVR misst.

Harry L. schrieb:
> Wenn du unbedingt vergleichen willst, dann bitte auch mit belastbaren
> Zahlen.

Ich habe meinen Test-Code gepostet, auf Github gib es die entsprechende 
Library zum herunter laden und das kann so nun jeder selber gegenprüfen.

Damit ich meine Library (i2c + lcd) mit deiner (ebenfalls i2c + lcd) 
Vergleichen kann habe ich den selben Testcode verwendet, der Controller 
war/ist exakt gleich eingestellt und dabei habe ich obige Werte schlicht 
mit gemessen. Ich habe sogar zuvor mittels Portpin auch noch einen Puls 
erzeugt (Pin setzen vor dem Beschreiben und löschen nach dem 
Beschreiben) um sicher sein zu können, dass ich diesmal auch richtig 
messe und der Puls hatte stets auch die Zeit, die ich gemessen habe. 
Mein Test ist damit mehr als nur belastbar, er ist verifizierbar.

Stefanus F. schrieb:
> Die Philosophie von Open-Source ist, dass jeder den Code nach seinem
> Gusto ändern kann und dadurch eine große Vielfalt entsteht.

Und genau das war auch meine Intention und es freut mich sehr, dass 
Harry meine Lib als Ausgangsbasis benutzt hat um sie auf den ARM zu 
bringen. Sowas finde ich toll und ich bin diesbezüglich auch riesig 
Stolz darauf.

Harry L. schrieb:
> ich hätte/habe jedenfalls kein Problem damit, fremden Code zu
> übernehmen, "wenn" er tatsächlich nach Fakten-Lage besser/effektiver als
> meine Lösung ist.

Anscheinend schon ;)

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Harry L. schrieb:
>> Das ganze inkl. main, startup und deinem Timer-Zeugs (für die Messung
>> selbst) als Summe ist völlig nichts-sagend.
>
> Sorry, aber das zeigt eindeutig, dass du anscheinend absolut keine hast,
> wie man Zeiten mit einem AVR misst.

Und was hat das mit Zeiten zu tun?
Dabei ging es um Code/RAM-Grösse.

Wie ich meine Zeiten ermittelt hab, hab ich hier beschrieben:
Beitrag "Re: Universelles Oled-Libary (SSD1306) für AVR(8bit) und STM32/HAL"

M. K. schrieb:
> Damit ich meine Library (i2c + lcd) mit deiner (ebenfalls i2c + lcd)
> Vergleichen kann habe ich den selben Testcode verwendet, der Controller
> war/ist exakt gleich eingestellt und dabei habe ich obige Werte schlicht
> mit gemessen. Ich habe sogar zuvor mittels Portpin auch noch einen Puls
> erzeugt (Pin setzen vor dem Beschreiben und löschen nach dem
> Beschreiben) um sicher sein zu können, dass ich diesmal auch richtig
> messe und der Puls hatte stets auch die Zeit, die ich gemessen habe.
> Mein Test ist damit mehr als nur belastbar, er ist verifizierbar.

Du wirfst wahllos Performace und Grösse durcheinander.
Zur Laufzeit-Ermittlung: s.o.

belastbar und valide ist anders.

Tip: die tatsächliche Code-Grösse eines Object-File ermittelt man mit 
"size"
https://linux.die.net/man/1/size

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Und was hat das mit Zeiten zu tun?
> Dabei ging es um Code/RAM-Grösse.

1. Wenn du nicht weißt wie man mit einem Timer auf dem AVR Zeiten misst 
halte ich es für sehr anmaßend, dass du die Ergebnisse anzweifelst
2. Es ging nicht nur um die Code-Größe sondern auch um die Zeiten. Um 
die RAM-Größe ging es bisher noch gar nicht.

Harry L. schrieb:
> Du wirfst wahllos Performace und Grösse durcheinander.
> Zur Laufzeit-Ermittlung: s.o.
>
> belastbar und valide ist anders.

Wo? Wo würfel ich das durcheinander? Nur weil dir das nicht passt? Dein 
Code kann gar nicht schneller sein als meiner. Und zwar ganz einfach 
weil ich ein Zeichen so übermittele
1
i2c_start(LCD_ADRESSE);
2
i2c_byte(LCD_DATA_PREFIX);
3
for(uint8_t i; i<CHAR_FONT_SIZE;i++){
4
  i2c_byte(CHAR[pos_in_FONT][i]);
5
}

und du machst das so
1
for(uint8_t i; i<CHAR_FONT_SIZE;i++){
2
  lcd_data(CHAR[pos_in_FONT][i]);
3
}
mit
1
void lcd_data(uint8_t data){
2
i2c_start(LCD_ADRESSE);
3
i2c_byte(LCD_DATA_PREFIX);
4
i2c_byte(data);

Ich habs vereinfacht nur um was zu verdeutlichen: Ich sende die 
LCD-Adresse mit jedem Zeichen, die bei dir und mir aus 8 Bytes bestehen, 
lediglich ein mal.
Das Gleiche gilt für das Kommando, dass dem LCD nun Daten übermittelt 
werden.

Du sendest aber mit jedem Byte eines Zeichens die LCD-Adresse und das 
Kommando für Daten. Damit musst du 7*2 Bytes = 14 Bytes mehr als ich dem 
Display schicken mit jedem Zeichen, dass du darstellen willst.

Und wenn wir beide das Display mit gleicher Geschwindigkeit betreiben 
musst du länger brauchen da du viel mehr Daten ans Display übermittelst 
als ich.

Übrigens: Du hast immer noch nicht erklärt was du überhaupt an der 
lcd_putc-Funktion warten willst.

Harry L. schrieb:
> Tip: die tatsächliche Code-Grösse eines Object-File ermittelt man mit
> "size"

Beim avr-gcc Toolchain heist es avr-size. Und was meinst du wie ich die 
Größe ermittelt hatte? Kannst du in meinem Github nachlesen ;)

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Ich habs vereinfacht nur um was zu verdeutlichen: Ich sende die
> LCD-Adresse mit jedem Zeichen, die bei dir und mir aus 8 Bytes bestehen,
> lediglich ein mal.
> Das Gleiche gilt für das Kommando, dass dem LCD nun Daten übermittelt
> werden.
>
> Du sendest aber mit jedem Byte eines Zeichens die LCD-Adresse und das
> Kommando für Daten. Damit musst du 7*2 Bytes = 14 Bytes mehr als ich dem
> Display schicken mit jedem Zeichen, dass du darstellen willst.

Du vergisst dabei, daß bei mir die 20 Zeichen (im Text-Mode) zentriert 
werden.
D.h.: ich muß mindestens am Anfang jeder Zeile einmal den RAM-Cursor neu 
initialisieren.
Das könnte man darauf beschränken, aber bläht imho den Code nur unnötig 
auf.
Die paar µs durch das zusätzliche gotoxy kratzen mich nicht wirklich.
4,4ms/Zeile sind für mich ok, und weitere Optimierungen stehen imho in 
keinem sinnvollen Verhältnis zum Aufwand.

M. K. schrieb:
> Übrigens: Du hast immer noch nicht erklärt was du überhaupt an der
> lcd_putc-Funktion warten willst.

2 nahezu identische Funktionen für putc für die Text- bzw. 
Graphic-Ausgabe ist alles Andere als wartungsfreundlich.

Und solche Konstruktionen:
1
uint8_t getCharPosition(char value){
2
  // getting chars position at font-array
3
  switch (value) {
4
        case 'ü':
5
            value = 95; // ü
6
            break;
7
        case 'Ü':
8
            value = 96; // Ü
9
            break;
10
        case 'ä':
11
            value = 97; // ä
12
            break;
13
        case 'Ä':
14
            value = 98; // Ä
15
            break;
16
...
17
...
18
...

sind einfach nur übel!

von Dieter F. (Gast)


Lesenswert?

Harry L. schrieb:
> Kindergarten

Scheint so.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> 2 nahezu identische Funktionen für putc für die Text- bzw.
> Graphic-Ausgabe ist alles Andere als wartungsfreundlich.

Nochmal: Es hat seinen Grund warum sie nahezu identisch sind und was 
willst du daran warten?

Harry L. schrieb:
> 4,4ms/Zeile sind für mich ok, und weitere Optimierungen stehen imho in
> keinem sinnvollen Verhältnis zum Aufwand.

Mein Testcode hat gezeigt, dass meine Lib, dein Ausgang also, rund 10% 
schneller ist. Eigentlich hast du Aufwand reingesteckt um es langsamer 
zu machen. Dass dir das aber dennoch genügt ist auch völlig OK.

Harry L. schrieb:
> Und solche Konstruktionen:
> ...
> sind einfach nur übel!

Was ist daran übel? Das ist genauso übersichtlich wie deine Tabelle. Ich 
hab das Mapping nur auf anderem Wege gelöst, das ist aber deshalb nicht 
schlechter wie ich oben auch gezeigt habe. Weder von der Codegröße noch 
von der Performance

von Harry L. (mysth)


Lesenswert?

Ich bin raus aus dieser Diskussion.
Hab keine lust mehr, gegen Wände zu reden.

Du mußt noch viel lernen!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Und genau aus dieser Vielfalt setzt sich das Bessere durch.

Auch das passiert nicht immer … davon abgesehen: was „das Bessere“ 
ist, legen die Nutzer fest, nicht die Autoren.

von Johannes S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Auch das passiert nicht immer … davon abgesehen: was „das Bessere“ ist,
> legen die Nutzer fest, nicht die Autoren.

Und danach gibt es nichts besseres als Arduino :  (weiß gerade nicht ob 
und welchen Smiley ich anbringen soll).

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Ich bin raus aus dieser Diskussion.
> Hab keine lust mehr, gegen Wände zu reden.
>
> Du mußt noch viel lernen!

Das Problem ist ja nur, dass du gegen die Wand redest, die du selbst 
erbaut hast.

Ich gehe ja auf deine Vorschläge ein, so habe ich ja z.B. die 
lcd_putc()-Funktion umgebaut. Da war deine Kritik auch völlig 
berechtigt.

Dann habe ich, weil ich eben der Meinung war, dass dein Code länger 
brauchen müsste als meiner (das hatte ich ja an deiner Library 
kritisiert), einen Performance-Test durchgeführt.
Es stellte sich stets heraus, dass meine Vermutung zu traf.

Das hast du nicht geglaubt: Post #5552007

Ich habe dann meinen Code mit dem ich das getestet hatte, gepostet: Post 
#5552108

Hier hast du z.b. bemängelt, dass ich mit float gerechnet habe, wie ich 
die Zeit bestimmt habe, war die trotz Code und Angabe, wie der 
Mikrocontroller eingestellt ist, überhaupt nicht klar.
Wirklich gegengemessen hast du zu diesem Zeitpunkt nicht.

Ich habe zwischenzeitlich aufgrund deiner berechtigten Kritik am Umgang 
mit Sonderzeichen in der putc-Funktion meine Library umgebaut.

Auch hier führte ich den obigen Performance-Test durch und kam auf eine 
neue, noch schnellere, Zeit.
Auch das hast du bemängelt: Post #5557315
Du hattest es als unglaubwürdig bezeichnet, darauf hin hab ich meine 
Code nochmal überprüft und festgestellt, dass der Mikrocontroller falsch 
eingestellt war: Post #5557816
Auch dafür danke ich dir denn du hast mir so einen Fehler gezeigt.

Hier habe ich dann den Mikrocontroller richtig eingestellt und deine und 
meine Library miteinander verglichen. Das Ergebnis davon war, dass meine 
Library immer noch kleiner und auch schneller ist als deine Library.

Und an diesem Punkt hast du meine Testmethode als nicht geeignet 
bezeichnet du hattest ja zwischenzeitlich einen eigenen Test ins Feld 
geführt.
Mein Test soll ja nicht valide und belastbar sein. Und das obwohl der 
Code zum Test oben für jeden, sogar für Gäste, zugänglich und nachlesbar 
ist. Ich weis hier ehrlich nicht wie man mehr valide sein will, sein 
kann, wenn man schon alles für jederman sichtbar veröffentlicht hat. 
Mehr valide&belastbar geht dabei gar nicht.

Nachfragen, was du z.B. an der putc() warten willst oder warum das 
Handhaben von Sonderzeichen schlecht sein soll hast du bisher nicht 
beantwortet.

Ich bin jetzt aber dennoch darauf eingegangen und habe meine Library nun 
noch einmal umstrukturiert.

- Es gibt jetzt keine gleichnamigen Funktionen mehr, die sich bzgl. 
Textmode und Graphicmode nur minimal unterscheiden. Die Unterscheidung, 
ob das Display im Graphicmode oder Textmode ist, ist nun direkt in den 
Funktionen untergebracht (das gilt auch für die lcd_gotoxy() und 
lcd_clrscr()).
- Sonderzeichen werden nun durch ein zweidimensionales Array zugeordnet 
wo sie im Font-Satz stehen, die lcd_putc()-Funktion durchsucht dieses 
Array.

Die Performance meiner Library hat sich dadurch im Graphicmode noch 
einmal minimal gesteigert (knapp eine Millisekunde), beim Textmode ist 
die Performance gleich geblieben.
Die Code-Größe hat sich nicht nennenswert verändert.

Unterm Strich: Meine Library ist immer noch schneller als deine Variante 
und benötigt weniger Flash/RAM. Um es mal in deiner Darstellung zu 
visualisieren (meine war ja anscheinend nicht ausreichend):

Speicherbedarf
1
Modul       | Code (Flash) | Stat. RAM
2
------------+--------------+------------
3
I2C-Core    | 120 Byte     |    0
4
Oled (TXT)  | 1569 Byte    |    2 Byte
5
Oled (GFX)  | 2789 Byte    | 1026 Byte

Ich finde es schade, dass du dich so aus der Diskussion verabschiedest.

: Bearbeitet durch User
von Otto (Gast)


Lesenswert?

Ich hätte da einen Vorschlag:
jetzt, wo das Wetter wieder besser wird, stellt Ihr euch gegenüber, 
jeder mit einem Wasserschlauch bewaffnet, und tragt den Streit aus!

von 900ss (900ss)


Lesenswert?

M. K. schrieb:
> Ich finde es schade, dass du dich so aus der Diskussion verabschiedest.

Nein es ist gut damit der Kindergarten-Zank aufhört. Echt albern.

von OLEDer (Gast)


Lesenswert?

Hi sylaina,

vielen Dank zunächst für die ganze Arbeit!

Ich bräuchte allerdings einmal Hilfe, da ich die Lib nicht lauffähig 
bekomme.

Als Display benutze ich das 0,96" Display von 42project (mit SSD1306 
Treiber), als uC den ATMega164PA.

Mit einem Arduino Uno und der U8glib funktioniert es problemlos, 
allerdings ist mit diese Lib zu groß und unübersichtlich für persönliche 
Erweiterungen.

SDA und SCL sind direkt an dem uC angeschlossen, da das Display soweit 
ich weiß über interne Pull-Ups verfügt.

Zum Test habe ich dein Beispiel aus der Lib (Git) genommen, das dort in 
der Main hinterlegt ist.
Muss ich selbst an dem uC noch Einstellungen vornehmen, die dort nicht 
vermerkt sind?
Den mit diesem simplen Code bleibt das Display leider schwarz.

Danke für deine Hilfe.

von OLEDer (Gast)


Lesenswert?

Treiber habe ich in der "lcd.h" auf SSD1306 geändert und von "Graphic" 
in "textmode" gewechselt.

Hab grade noch mal mit meinem ATMega328P probiert, auch hier 
funktioniert es nicht.

Mit meinem Messgerät messe ich auf der "SCL" Leitung einen Takt von 
50kHz, in der "lcd.h" sind 100.000 eingetragen. Ist dem so richtig?

von Harry L. (mysth)


Lesenswert?

Ohne PullUps wird das nix...

Wer misst, misst Mist

von Stefan F. (Gast)


Lesenswert?

> SDA und SCL sind direkt an dem uC angeschlossen, da das Display soweit
> ich weiß über interne Pull-Ups verfügt.

Du kannst das ganz einfach nachmessen: Im Ruhezustand muss der Pegel 
HIGH sein und ein Amperemeter (von SDA nach GND bzw. SCL nach GND) 
müsste ca. 1mA anzeigen.

von Dieter F. (Gast)


Lesenswert?

Harry L. schrieb:
> Ohne PullUps wird das nix..

Sind auf dem OLED.

von Harry L. (mysth)


Lesenswert?

Dieter F. schrieb:
> Harry L. schrieb:
>> Ohne PullUps wird das nix..
>
> Sind auf dem OLED.

Auf Deinem vielleicht...auf meinem nicht.
Und die gehören da auch nicht hin!

von Dieter F. (Gast)


Lesenswert?

Harry L. schrieb:
> Und die gehören da auch nicht hin!

Habe es mal auf chinesich übersetzt - für die Zielgruppe:

他们也不属于那里!

von OLEDer (Gast)


Lesenswert?

Stefanus F. schrieb:
> Du kannst das ganz einfach nachmessen: Im Ruhezustand muss der Pegel
> HIGH sein und ein Amperemeter (von SDA nach GND bzw. SCL nach GND)
> müsste ca. 1mA anzeigen.

Habe ich grade mal gemacht. Es fließen jeweils 0.33mA.

von Stefan F. (Gast)


Lesenswert?

Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel.

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel.

Bei 3,3V...

Bei 5V wären das sogar 15k....

https://www.nxp.com/docs/en/user-guide/UM10204.pdf

von Stefan F. (Gast)


Lesenswert?

Die I²C Spezifikation alleine reicht so nicht. Man muss die Kapazitäten 
der Leitungen und Bauteile berücksichtigen.

von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Muss ich selbst an dem uC noch Einstellungen vornehmen, die dort nicht
> vermerkt sind?
> Den mit diesem simplen Code bleibt das Display leider schwarz.

Ja, in der lcd.h musst du z.B. einstellen, dass es ein SSD1306-Display 
ist, das Github ist auf SH1106 eingestellt.
Die Adresse musst du auch korrekt einstellen. Auf den Displays, so meine 
Erfahrung, ist meist die Adresse im 8-Bit-Format angegeben. Daher ist da 
in meiner Lib diese merkwürdige Shift-Option. Willst du die Adresse 
direkt im 7-bit-Format angeben (statt z.B. 0x78 gleich 0x3c angeben) 
dann darfst du natürlich nicht shiften.

Zudem viel mir grade beim Github auf, dass ich vergessen hatte, die 
font.c dem Linker hinzuwerfen, das habe ich grade noch korrigiert (das 
wirft aber typischerweise Fehler da er dann den Font nicht linken kann).

von Harry L. (mysth)


Lesenswert?

Stefanus F. schrieb:
> Die I²C Spezifikation alleine reicht so nicht. Man muss die Kapazitäten
> der Leitungen und Bauteile berücksichtigen.
Kann man bei Kabellängen unter ~50cm komplett ignorieren...

So, wie es in o.g. DB steht funktioniert das auch.

: Bearbeitet durch User
von OLEDer (Gast)


Lesenswert?

Stefanus F. schrieb:
> Dann hast du 10k Ohm. Fuer die maximale Bitrate ist das zu viel.

Ja es sind 3.3 V für das Display.
Aber da es mit der normalen U8glib funktioniert, dürfte es eigentlich 
kein Problem darstellen.

von OLEDer (Gast)


Lesenswert?

M. K. schrieb:
> Ja, in der lcd.h musst du z.B. einstellen, dass es ein SSD1306-Display
> ist, das Github ist auf SH1106 eingestellt.

Hatte ich oben noch beigefügt, Treiber ist entsprechend eingestellt. Die 
F_CPU muss ich auch noch manuell einfügen, ist das richtig? Das habe ich 
auch bereits gemacht.

> Die Adresse musst du auch korrekt einstellen. Auf den Displays, so meine
> Erfahrung, ist meist die Adresse im 8-Bit-Format angegeben. Daher ist da
> in meiner Lib diese merkwürdige Shift-Option. Willst du die Adresse
> direkt im 7-bit-Format angeben (statt z.B. 0x78 gleich 0x3c angeben)
> dann darfst du natürlich nicht shiften.

Das hatte ich auch noch nicht so ganz verstanden. Die Adresse meines 
Displays (I2C-Scanner) ist 0x3C, ich habe jetzt vermutet das es sich um 
die Adresse handelt, die Bereits in der lcd.h angegeben ist, jedoch in 
einem anderen Format. Diese habe ich soweit nicht verändert.

Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler 
sein?
Gleich mal ausprobieren.

von OLEDer (Gast)


Lesenswert?

OLEDer schrieb:
> Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler
> sein?
> Gleich mal ausprobieren.

Auch mit 0x78 bleibt es dunkel.

von Harry L. (mysth)


Lesenswert?

OLEDer schrieb:
> Allerdings steht in der "lcd.h" 0x7A nicht 0x78, kann das der Fehler
> sein?
> Gleich mal ausprobieren.

Für unmodifizierte Displays muß die Adresse 0x78 sein

0x78 = 0x3c << 1

Bit 0 ist für R/W zuständig.
Die I²C-Adresse steht in den oberen 7bit.

: Bearbeitet durch User
von OLEDer (Gast)


Lesenswert?

Harry L. schrieb:
> 0x78 = 0x3c << 1
>
> Bit 0 ist für R/W zuständig.
> Die I²C-Adresse steht in den oberen 7bit.

Danke für den Hinweis, das macht es etwas verständlicher.

von Ralph S. (jjflash)


Lesenswert?

... in einem Buch (vor Jahren, welches weiß ich nicht mehr), wurde 
behauptet, ein I2C Device besitze 2 Adressen, eine Adresse zum Lesen, 
eine zum Schreiben.

Wenn man dieses so betrachtet hat ein Display die Adresse 0x78 und 0x79 
und das R/W Flag ist somit Bestandteil der Adresse (und nicht wirklich 
ein Flag).

Wenn man es als Flag und nicht als Bestandteil der Adresse sieht, dann 
besteht die Adresse aus 7 Bits deren niederwertiges Bit in D1 im Byte 
(und nicht D0) ist.

Ist das nirgendwo festgelegt, wie das zu betrachten ist ?

von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Hatte ich oben noch beigefügt, Treiber ist entsprechend eingestellt. Die
> F_CPU muss ich auch noch manuell einfügen, ist das richtig? Das habe ich
> auch bereits gemacht.

Ich schau mal was du so geschrieben hattest, hab mir nicht alles genau 
durchgelesen.

OLEDer schrieb:
> Mit meinem Messgerät messe ich auf der "SCL" Leitung einen Takt von
> 50kHz, in der "lcd.h" sind 100.000 eingetragen. Ist dem so richtig?

Öhm...das ist nicht richtig, wenn du 100 kHz einstellst soll es auch mit 
100 kHz laufen. Entweder stimmt das F_CPU nicht oder was anderes. Was 
direkt aber auffällt: Die I2C-Settings werden in der i2c.h eingestellt, 
nicht in der lcd.h.

Bevor wir weiter lang rumraten: Zippe doch mal dein Projekt und lade es 
hier hoch, dann könnten wir es runter laden und mal schaun. Benutzt du 
z.B. einen Arduino Nano/Uno mit der Arduino-IDE? Da sind besondere 
Einstellungen dann noch nötig die im Github in der Readme ganz unten 
beschrieben sind.

Ralph S. schrieb:
> ... in einem Buch (vor Jahren, welches weiß ich nicht mehr), wurde
> behauptet, ein I2C Device besitze 2 Adressen, eine Adresse zum Lesen,
> eine zum Schreiben.

Hm, das kann man so sehen, dann muss man aber sagen, dass jeder 
I2C-Baustein aus mindestens 2 I2C-Geräten besteht. Ne, diese 
Betrachtungsweise ist im Prinzip unsinn.
Man kann sagen, dass ein I2C-Device eine 8-bit Adresse hat bei der das 
LSB dem Device schlicht nur mitteilt, ob das Device gelesen oder 
beschrieben werden soll.
Die OLED-Displays mit SSD1306 bzw. SH1106 können jedoch mit dem 
I2C-Interface nicht quatschen, deshalb muss man bei diesen Displays mit 
einem Puffer arbeiten wenn man darauf zeichnen will und dabei den 
aktuellen Inhalt nicht löschen möchte. Und deshalb werte ich auch das 
Ack/NAck bei den Displays nicht aus (das ist das Einzige, dass sie einem 
zurück liefern), es ist mir wurscht wie sie Antworten wenn ich ihnen 
Daten schicke. Wenn was schief geht könnten sie mir eh nicht sagen, was 
schief gegangen ist.

von Ralph S. (jjflash)


Lesenswert?

M. K. schrieb:
> Wenn was schief geht könnten sie mir eh nicht sagen, was
> schief gegangen ist

Wenn sie nicht antworten weißt du aber, DASS etwas schief gegangen 
ist...

von OLEDer (Gast)


Angehängte Dateien:

Lesenswert?

M. K. schrieb:
> Bevor wir weiter lang rumraten: Zippe doch mal dein Projekt und lade es
> hier hoch, dann könnten wir es runter laden und mal schaun. Benutzt du
> z.B. einen Arduino Nano/Uno mit der Arduino-IDE? Da sind besondere
> Einstellungen dann noch nötig die im Github in der Readme ganz unten
> beschrieben sind.

Wie gesagt nutze ich einen ATMega164PA, den Code erstelle ich in Atmel 
Studio 7 und nutze einen ISP zum übertragen, da der chip45 Bootloader 
nicht für den PA funktioniert.

von Dieter F. (Gast)


Lesenswert?

Setze den
1
#define PSC_I2C      1    // prescaler i2c

mal auf 2.

So wird der Wert für TWBR zu groß - bzw. nach Zuweisung unpassend (das 
sollte im Header mit einer Meldung bedacht werden ... - nur so, als 
Anregung :-) )

von M. K. (sylaina)


Lesenswert?

Dieter F. schrieb:
> So wird der Wert für TWBR zu groß

Dann hätte er nicht weiter compilieren können, der gcc wäre mit Fehler 
stehen geblieben. Kann man sich auch selbst ausrechnen: Bei 16 MHz und 
100 kHz I2C Taktrate kommt da 72 bei raus. Das ist bei weitem nicht zu 
groß für TWBR.

OLEDer schrieb:
> Wie gesagt nutze ich einen ATMega164PA, den Code erstelle ich in Atmel
> Studio 7 und nutze einen ISP zum übertragen, da der chip45 Bootloader
> nicht für den PA funktioniert.

Ich glaube auch nicht, dass es am ISP liegt.

Ich hab mal rein geschaut, mit dem Atmel Studio kenn ich mich aber nicht 
aus. Das nutze ich idR nur wenn ich einen Attiny4 oder ähnliches 
(TPI-Schnittstelle) programmieren/flashen will.

1. Frage: Das Projekt kompiliert absolut ohne Fehlermeldung, ja? Ich 
erhalte beim Build die Meldung "recipe for target "Display_test.elf" 
failed.". Ich kann das aber auf die Schnelle nicht interpretieren, mir 
scheint aber, dass er irgend etwas nicht findet. Beim zweiten 
Build-Versuch wird dann fehlerfrei übersetzt. Es sollte aber auch schon 
beim 1. Build funktionieren.
2. Hinweis: F_CPU kann man auch als Projektvariable anlegen, dann ist 
sie jedem File bekannt. Ich mein das ging irgendwie über 
Properties-Symbols. Google weis hier sicher mehr.

von Stefan F. (Gast)


Lesenswert?

Ralph S. schrieb:
> Ist das nirgendwo festgelegt, wie das zu betrachten ist ?

In der I²C Spezifikation 
(https://www.nxp.com/docs/en/user-guide/UM10204.pdf) steht:

> After the START condition (S), a slave address is sent. This address
> is seven bits long followed by an eighth bit which is a data direction
> bit (R/W).

Für mich ist damit klar, dass die Slave Adresse 7bit groß ist. Dieses 
R/W Bit ist nicht Bestandteil der Adresse. Das wird auch in sämtlichen 
folgenden Diagrammen und Tabellen so dargestellt.

Deswegen halte ich es für falsch, dass viele Libraries als Input 8bit 
Werte inclusive R/W Bit erwarten und dass dann "address" nennen.

Richtig verwirrend wird es bei dieser kruden 8bit Variante, wenn man 
einen I²C Slave ansprechen will, der nur Write Operationen kennt. Dann 
muss man nämlich immer noch die 8bit Adresse mit bit0=Low konfigurieren, 
obwohl tatsächlich immer bit0=High gesendet wird.

von Dieter F. (Gast)


Lesenswert?

M. K. schrieb:
> Dann hätte er nicht weiter compilieren können, der gcc wäre mit Fehler
> stehen geblieben. Kann man sich auch selbst ausrechnen: Bei 16 MHz und
> 100 kHz I2C Taktrate kommt da 72 bei raus. Das ist bei weitem nicht zu
> groß für TWBR.

Hast Recht - schlechter Morgen ...

von OLEDer (Gast)


Lesenswert?

M. K. schrieb:
> 1. Frage: Das Projekt kompiliert absolut ohne Fehlermeldung, ja? Ich
> erhalte beim Build die Meldung "recipe for target "Display_test.elf"
> failed.". Ich kann das aber auf die Schnelle nicht interpretieren, mir
> scheint aber, dass er irgend etwas nicht findet. Beim zweiten
> Build-Versuch wird dann fehlerfrei übersetzt. Es sollte aber auch schon
> beim 1. Build funktionieren.

Beim ersten mal bekomme ich nur eine Warnung für die Umlaute.

"case lable value less than minimum value for type"
"multi-character character constant [-Wmultichar]"

Ansonsten läuft es problemlos durch.

Auch eine Änderung am prescaler hat nichts bewirkt.

von OLEDer (Gast)


Lesenswert?

Ich hab nochmal etwas rum probiert, jetzt funktioniert es.
Zum einen lag es wohl an der falschen Adresse in der "lcd.h", da dort 
standardmäßig 0x7A steht und zum anderen das ich im Projekt selbst noch 
328P stehen hatte, beim flaschen aber 164PA ausgewählt habe.

Vielen dank für eure Hilfe und ganz besondern nochmal an sylaina für die 
tolle Lib, wirklich hervorragende Arbeit!!

von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Beim ersten mal bekomme ich nur eine Warnung für die Umlaute.
>
> "case lable value less than minimum value for type"
> "multi-character character constant [-Wmultichar]"

Da wird das Encoding des Quellcodes nicht richtig erkannt, schau dir 
noch mal die Readme an, da steht drin welches Flag man wie setzen muss 
damit der Compiler die Quellcode-Dateien auch richtig dekodiert mit dem 
richtigen Encoding.

Zudem hab ich gesehen, dass du noch eine alte Version meiner Lib 
benutzt. Geh mal auf:

https://www.github.com/Sylaina/oled-display/

da findest du die aktuelle Version. Die braucht zum einem noch etwas 
weniger Flash und ist noch schneller als die alte Version.

von OLEDer (Gast)


Lesenswert?

M. K. schrieb:
> Da wird das Encoding des Quellcodes nicht richtig erkannt, schau dir
> noch mal die Readme an, da steht drin welches Flag man wie setzen muss
> damit der Compiler die Quellcode-Dateien auch richtig dekodiert mit dem
> richtigen Encoding.

Da steht nur drin, was ich ändern muss, aber nicht der Befehl dafür. 
Wenn ich den Befehl "-finput-charset=utf-8 -fexec-charset=iso-8859-15" 
aus dem Makefile nehme, bekomme ich den Fehler:

"no iconv implementation, cannot convert from UTF - 8 to iso..."

Den oben genannten befehl füge ich bei

Toolchain -> AVR/GNU C Compiler -> Miscellanneous

ein.

> Zudem hab ich gesehen, dass du noch eine alte Version meiner Lib
> benutzt.

Dann müsste der Link im ersten Post korrigiert werden, denn der verweißt 
noch auf die ältere Version.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

OLEDer schrieb:
> "no iconv implementation, cannot convert from UTF - 8 to iso..."

Ohne ein erreichbares iconv bleibt dir nur übrig, den Quelltext selbst 
gleich als ISO-8859-1[5] abzuspeichern.  Wie das geht (und ob es 
überhaupt geht), hängt vom jeweils benutzten Editor ab.

von Harry L. (mysth)


Lesenswert?

Die Lösung ist, statt der Umlaute im Source die numerischen Konstanten 
zu nutzen.
Also z.B. statt 'ä' '\x84'

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Also z.B. statt 'ä' '\x84'

Das wäre allerdings nicht ISO8859-1[5].

Dort liegen die Umlaute wie folgt:
1
$ echo -n 'äöüÄÖÜß' | iconv -f utf-8 -t iso8859-1 | hd
2
00000000  e4 f6 fc c4 d6 dc df                              |.......|
3
00000007

: Bearbeitet durch Moderator
von Harry L. (mysth)


Lesenswert?

Jörg W. schrieb:
> Harry L. schrieb:
>> Also z.B. statt 'ä' '\x84'
>
> Das wäre allerdings nicht ISO8859-1[5].
>
> Dort liegen die Umlaute wie folgt:
>
>
1
> $ echo -n 'äöüÄÖÜß' | iconv -f utf-8 -t iso8859-1 | hd
2
> 00000000  e4 f6 fc c4 d6 dc df                              |.......|
3
> 00000007
4
>

"welchen" 8Bit-Zeichensatz man nutzt, ist dabei doch vollkommen egal.
So lange man im Source numerische Konstanten für die Sonderzeichen nutzt 
ist das eindeutig, und der Compiler hat nix zu meckern.
.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Da steht nur drin, was ich ändern muss, aber nicht der Befehl dafür.

Richtig, aber ich dachte auch, dass das eindeutig ist. So wie z.B. ein 
"make all" das entsprechende Programm samt EEPROM-File und Co erzeugt.

OLEDer schrieb:
> Dann müsste der Link im ersten Post korrigiert werden, denn der verweißt
> noch auf die ältere Version.

Öhm, nö. Nicht den Dateianhang laden sondern dem Link im ersten Post 
folgen, der führt dich zur aktuellen Version der Lib

M. K. schrieb:
>> Edit: Github link https://github.com/Sylaina/oled-display.git

Harry L. schrieb:
> So lange man im Source numerische Konstanten für die Sonderzeichen nutzt
> ist das eindeutig, und der Compiler hat nix zu meckern.

Das ist zwar richtig aber später in der main wird wohl kaum einer auf 
die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben und schon wirds 
wieder wichtig, was der Editor/Compiler benutzt. Wenn der nämlich ein 
Charset benutzt, bei dem ein 'ä' z.B. nicht bei '0x84' steht sondern bei 
z.B. '0xe4' (da stehts bei ISO 8859-1, unserem typischen Latin-1) 
bekommt man wieder nicht das, was man eigentlich will.

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Harry L. schrieb:
>> So lange man im Source numerische Konstanten für die Sonderzeichen nutzt
>> ist das eindeutig, und der Compiler hat nix zu meckern.
>
> Das ist zwar richtig aber später in der main wird wohl kaum einer auf
> die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben und schon wirds
> wieder wichtig, was der Editor/Compiler benutzt. Wenn der nämlich ein
> Charset benutzt, bei dem ein 'ä' z.B. nicht bei '0x84' steht sondern bei
> z.B. '0xe4' (da stehts bei ISO 8859-1, unserem typischen Latin-1)
> bekommt man wieder nicht das, was man eigentlich will.

Das Kunststück,das für alle denkbaren IDE/Editoren/OS hinzubekommen will 
ich sehen!

: Bearbeitet durch User
von OLEDer (Gast)


Lesenswert?

M. K. schrieb:
> Richtig, aber ich dachte auch, dass das eindeutig ist. So wie z.B. ein
> "make all" das entsprechende Programm samt EEPROM-File und Co erzeugt.

Das stimmt, aber dafür müsste man sich dann mit Compiler Befehlen und 
deren Implementierung auskennen.

> Öhm, nö. Nicht den Dateianhang laden sondern dem Link im ersten Post
> folgen, der führt dich zur aktuellen Version der Lib

Ich hab den Thred anfangs erst einmal durchgelesen und dann wie weiter 
unten geschrieben im ersten Post den github Link benutzt. Da bin ich auf 
die Lib gekommen die ich bisher benutzt habe.
Wie auch immer, jetzt habe ihc ja die aktuelle Version.

Zu den Umlauten:

Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt. Naja, so 
kann man sich täuschen. Aber ich denke, ich kann auf die Umlaute gut 
verzichten, dann spare ich mir den switch vergleich und der code wird 
noch etwas schneller ^^

von M. K. (sylaina)


Angehängte Dateien:

Lesenswert?

Harry L. schrieb:
> Das Kunststück,das für alle denkbaren IDE/Editoren/OS hinzubekommen will
> ich sehen!

Ist doch einfach:

Mein Beispielcode von oben.
Font von meiner Library, 'ä' gegen 0x84 ersetzt, die 
Charset-Konfiguration aus dem Makefile entfernt.
Im main meines Beispielcodes folgende beide Zeilen direkt nach dem Code 
zum print von Zeile 1 eingefügt:
1
lcd_gotoxy(0,1);
2
lcd_puts("Test: ä");

Ergebnis ist das angehangene Bild. Ich mag was mit dem Auge habe aber 
ich sehe kein "ä", du etwa? Sowie ich aber den Charset wieder einfüge 
gibts auch ein "ä".
Ich kann alternativ auch im Font 'ä' durch 0xe4 ersetzen, dann steht da 
auch ein ä auf dem Display.
Das zeigt: Es kommt drauf an, welches Textencoding der Compiler benutzt 
um ein 0x84 (oder 0xe4) als 'ä' zu erkennen.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

OLEDer schrieb:
> Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt. Naja, so
> kann man sich täuschen. Aber ich denke, ich kann auf die Umlaute gut
> verzichten, dann spare ich mir den switch vergleich und der code wird
> noch etwas schneller ^^

Nimm doch die aktuelle Lib, da ist auch kein Switch-Vergleich mehr drin 
;)

von Harry L. (mysth)


Lesenswert?

M. K. schrieb:
> Das zeigt: Es kommt drauf an, welches Textencoding der Compiler benutzt
> um ein 0x84 (oder 0xe4) als 'ä' zu erkennen.

So ein Blödsinn!
Es kommt bei solchen Anwendungen (das ist kein PC-Programm bei dem es so 
hübsche Dinge wie i18n gibt!!) darauf an, was du als "ä" definierst!

Außerdem nutzt nicht jeder Makefiles, und IDEs haben z.T. sehr 
unterschiedliche Vorstellungen von der Zeichencodierung.

Bei Displays, die einen integrierten Char-Generator haben, kommt es 
zusätzlich darauf an, an welcher Position das "ä" steht.

So, wie du das gelöst hast, funktioniert das bei dir - eine allgemein 
gültige Lösung ist das jedenfalls nicht.

Aber, wenn du meinst, daß du das alles so richtig verstanden 
hast....bitte sehr!

Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> Das ist zwar richtig aber später in der main wird wohl kaum einer auf
> die Idee kommen, statt z.B. 'ä' ein '0x84' zu schreiben

Ich habe mir dann immer mit sowas beholfen:
1
#define sz "\xdf"
2
#define ae "\xe4"
3
4
...
5
   printf("Damit geht das verl"ae sz"lich");

Harry L. schrieb:
> Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.

Fein, wir haben vom letzten noch genug. :/

OLEDer schrieb:
> Zu den Umlauten:
>
> Ich hätte jetzt gedacht, das Atmel Studio so etwas hin bekommt.

Offensichtlich haben sie bei Atmel/Microchip nicht dran gedacht, ein 
iconv-Binary mitzuliefern.

Mach doch bei ihnen einfach mal einen Bugreport auf.

: Bearbeitet durch Moderator
von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> So ein Blödsinn!
> Es kommt bei solchen Anwendungen (das ist kein PC-Programm bei dem es so
> hübsche Dinge wie i18n gibt!!) darauf an, was du als "ä" definierst!

Das ist völlig richtig aber: Der Compiler ist doch ein PC-Programm und 
der muss doch den Kram 1. erstmal einlesen (Quellcode usw.) und 2. 
daraus was für den Mikrocontroller Ausführbares machen (Hex-Files, 
EEPRom-Files usw.). Deswegen heißt das eine ja auch input und das andere 
exec.

Harry L. schrieb:
> So, wie du das gelöst hast, funktioniert das bei dir - eine allgemein
> gültige Lösung ist das jedenfalls nicht.

Wenn man die Randbedingungen beachtet, die ich in der Readme angegeben 
habe, dann funktioniert das nicht nur bei mir so sondern bei jedem.

Harry L. schrieb:
> Hab keinerlei Lust, hier ein weiteres Faß auf zu machen.

Gute Idee.

von Harry L. (mysth)


Lesenswert?

Jörg W. schrieb:
> Ich habe mir dann immer mit sowas beholfen:
> #define sz "\xdf"
> #define ae "\xe4"
>
> ...
>    printf("Damit geht das verl"ae sz"lich");

Ein der wenigen sinnvollen Lösungen!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Harry L. schrieb:
> Jörg W. schrieb:
>> Ich habe mir dann immer mit sowas beholfen:
>> #define sz "\xdf"
>> #define ae "\xe4"
>>
>> ...
>>    printf("Damit geht das verl"ae sz"lich");
>
> Ein der wenigen sinnvollen Lösungen!

Sinnvoll ist es natürlich auch, wenn man den Text flüssig schreiben 
kann. Bei dieser Variante ist man halt komplett unabhängig vom host und 
execution charset.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Jörg W. schrieb:
>> Ich habe mir dann immer mit sowas beholfen:
>> #define sz "\xdf"
>> #define ae "\xe4"
>>
>> ...
>>    printf("Damit geht das verl"ae sz"lich");
>
> Ein der wenigen sinnvollen Lösungen!

Würde nur mit deinem Font nicht funktionieren da da ä als 0x84 definiert 
ist und ß mit 0xe1. 0xdf (223) und 0xe4 (228) kennt dein Font nicht. 
Wenn die Codes nicht zum geplanten Charset passen kannst du dich auf den 
Kopf stellen und mit den Füßen wackeln und es wird nicht fnuktionieren.

von Harry L. (mysth)


Lesenswert?

Jörg W. schrieb:
> innvoll ist es natürlich auch, wenn man den Text flüssig schreiben
> kann. Bei dieser Variante ist man halt komplett unabhängig vom host und
> execution charset.

Einen Tod musst du sterben....

Mich mit dem Compiler über den verwendeten Zeichensatz herum zu streiten 
wiederstrebt mir zu tiefst.
Der Code sollte auf jedem System mit jeder Codepage zum selben Ergebnis 
führen.

von M. K. (sylaina)


Lesenswert?

Harry L. schrieb:
> Einen Tod musst du sterben....

Ja, und bevor ich den Tod sterbe mit irgendwelchen kryptischen 
Hex-Zahlen geh ich lieber her und sage konkret, welches Charset zu 
verwenden ist. Ich finde nämlich ein
1
#define sz "\xdf"
2
#define ae "\xe4"
3
4
...
5
   printf("Damit geht das verl"ae sz"lich");

ist bei weitem nicht so leicht zu lesen wie ein
1
printf("Damit geht das verläßlich");


Harry L. schrieb:
> Mich mit dem Compiler über den verwendeten Zeichensatz herum zu streiten
> wiederstrebt mir zu tiefst.

Was hat das mit herumstreiten zu tun. Das sind stink normale 
Einstellparameter. Wenn man so Sachen wie delay_ms verwendet muss man 
dem Compiler ja auch die korrekte Taktfrequenz des µCs mitteilen. Da 
kann man im makefile, das man ja eigentlich auch beim Code mitliefert, 
auch direkt die flags für die entsprechenden Charsets setzen.

Harry L. schrieb:
> Der Code sollte auf jedem System mit jeder Codepage zum selben Ergebnis
> führen.

Das kann schon per Definition nicht funktionieren da es unterschiedliche 
Charsets ad absurdum führen würde. Latin-1 und DOS-Latin-1 z.B. klingen 
ähnlich und haben Umlaute und Co doch nicht an den gleichen Stellen 
stehen. Zwei Charsets, die insbesondere beim extenden Set definitiv zu 
unterschiedlichen Ergebnissen kommen.

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.