Forum: Projekte & Code [STM32/HAL] generischer Treiber für die beliebten I²C-Text-Displays


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Harry L. (mysth)


Bewertung
0 lesenswert
nicht lesenswert
Für die beliebten LC-Displays mit I²C-Adapter auf HD44780-Basis hier ein 
Treiber.

Anpassungen an andere Display-Formate, I²C-Adresse etc. in lcd_config.h 
und ggf. lcd_map.inc (für exotische Displays)

Um das zu compilieren:
* Zip-File Im workspace-Folder entpacken
* die .ioc-Datei mit CubeMX öffnen und Projekt generieren.
* Projekt in Atollic importieren.

Weder schön noch fertig...

"Auf die Schnelle zusammen geklöppelt" - aber funktioniert. :)
Vielleicht kann es ja jemand brauchen.

Die jeweils aktuelle Version gibt es hier zum Download:
https://cloud.it-livetalk.de/index.php/s/sF3otLQ3dpBFJNE

: Bearbeitet durch User
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
1 lesenswert
nicht lesenswert
Harry L. schrieb:
> Die jeweils aktuelle Version gibt es hier zum Download:

Das Forum bietet die Möglichkeit, Dateien anzuhängen. Nutze sie!

von Harry L. (mysth)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Harry L. schrieb:
>> Die jeweils aktuelle Version gibt es hier zum Download:
>
> Das Forum bietet die Möglichkeit, Dateien anzuhängen. Nutze sie!

Nein, mach ich in dem Fall bewusst nicht, weil ich so die Datei 
jederzeit aktualisieren kann.

Das ist auch kein x-beliebiger Werbe-versiffter Filehoster, sondern mein 
eigener Server.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
3 lesenswert
nicht lesenswert
Und sobald Dein eigener Server ausfällt, hat niemand hier im Forum was 
davon.

Vorschlag: Lad' die Datei hier hoch, und weise deutlich darauf hin, daß 
aktuellere Versionen auf Deinem Server zu finden sein werden.

Dann hat man im Falle Deines Ablebens/Ausfalls noch was davon.

von Harry L. (mysth)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Auf besonderen Wunsch von Rufus nochmal das aktuelle File als Anhang.

Das kann (und wird vermutlich) morgen bereits veraltet sein.

Die aktuelle Version gibts immer über diesen Link:
https://cloud.it-livetalk.de/index.php/s/sF3otLQ3dpBFJNE

von Bimbo. (Gast)


Bewertung
4 lesenswert
nicht lesenswert
Harry L. schrieb:
> Das kann (und wird vermutlich) morgen bereits veraltet sein.
>
> Die aktuelle Version gibts immer über diesen Link:

Warum veröffentlicht man dann eine unstabile und noch nicht fertige 
Version?

von Harry L. (mysth)


Bewertung
3 lesenswert
nicht lesenswert
Bimbo. schrieb:
> Harry L. schrieb:
>> Das kann (und wird vermutlich) morgen bereits veraltet sein.
>>
>> Die aktuelle Version gibts immer über diesen Link:
>
> Warum veröffentlicht man dann eine unstabile und noch nicht fertige
> Version?

Woraus liest du, daß die Version instabil wäre?
Wann ist eine Software fertig?

Solche Kommentare kannst du dir auch sparen!

Nimm es oder lass es!

von Bimbo. (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Harry L. schrieb:
> Woraus liest du, daß die Version instabil wäre?

Hieraus:

Harry L. schrieb:
> Weder schön noch fertig...

Harry L. schrieb:
> Das kann (und wird vermutlich) morgen bereits veraltet sein.
>
> Die aktuelle Version gibts immer über diesen Link:

Eine halbwegs fertige Software wird morgen noch nicht veraltet sein. Und 
der Hineis auf die aktuelle Version lässt auch auf "work in progress" 
deuten.

Ist ja nichts schlimmes - ich würds aber erst präsentieren, wenn ich 
erwarte dass meine Version morgen noch nicht bereits veraltet ist.

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
2 lesenswert
nicht lesenswert
Harry L. schrieb:
> Auf besonderen Wunsch von Rufus nochmal das aktuelle File als Anhang.

Danke.


Allerdings ist die Frage schon gerechtfertigt, was Du an einem Stück 
doch eher im Funktionsumfang noch überschaubarer Software noch so viel 
ändern willst, daß sie morgen schon veraltet ist.

Du könntest übrigens, damit Nutzer Deiner Software leicht sehen können, 
was sich getan hat, auf ein Versionskontrollsystem wie git 
zurückgreifen, und Deine Software auf gitlab o.ä. hosten.

Wie fändest Du das?

von Harry L. (mysth)


Bewertung
-2 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Harry L. schrieb:
>> Auf besonderen Wunsch von Rufus nochmal das aktuelle File als Anhang.
>
> Danke.
>
>
> Allerdings ist die Frage schon gerechtfertigt, was Du an einem Stück
> doch eher im Funktionsumfang noch überschaubarer Software noch so viel
> ändern willst, daß sie morgen schon veraltet ist.
>
> Du könntest übrigens, damit Nutzer Deiner Software leicht sehen können,
> was sich getan hat, auf ein Versionskontrollsystem wie git
> zurückgreifen, und Deine Software auf gitlab o.ä. hosten.
>
> Wie fändest Du das?

Ja, könnte ich.
Wird wohl auch früher oder später da landen.

Aktuell erweitere ich das um weitere Display-Typen - alles, was ich hier 
so finde.
Am eigentlichen Code wird sich nicht mehr viel ändern.

Für mich ist das nur ein Baustein eines anderen Projekt, den ich hier 
zur Verfügung stelle, weil die Frage danach bereits öfter auftauchte, 
aber der meiste Code, den man im Netz findet eben nicht für die 
I²C-Variante geeignet ist.

Dachte nicht, daß das zu solchen Diskussionen führen würde.

von Harry L. (mysth)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ok, also hier jetzt doch noch einmal eine Version als Anhang, da ich die 
inzwischen -für meine Bedürfnisse- als "ferig" betrachte.

Was sich geändert hat:

* ein Freund hat noch seine OLED-Varianten hinzugefügt.
* der Code wurde aufgeräumt
* zahlreiche Kommentare wurden hinzugefügt

Was noch offen ist:

* das Definieren von eigenen Zeichen - brauch ich derzeit nicht, und 
mach ich, wenn ich das brauche.

Die (leere) Funktion gibt es bereits.
Wenn jemand Lust hat, das zu ergänzen und zu testen....
bitte Mail an: dertrickreiche at gmail.com

[Disclaimer]
Die Software hat am 26.03.2019 um 23:00 hier in Witten auf ca. 180m 
ü.n.N. mit den verschiedensten Displays an einem Nucleo-F303RE 
funktioniert, und weitere Probleme konnte ich nicht identifizieren.

take it or leave it!

: Bearbeitet durch User
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Harry L. schrieb:
> Ok, also hier jetzt doch noch einmal eine Version als Anhang

Danke dafür.

von mein Name ist M (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> [Disclaimer]
> Die Software hat am 26.03.2019 um 23:00 hier in Witten auf ca. 180m
> ü.n.N. mit den verschiedensten Displays an einem Nucleo-F303RE
> funktioniert, und weitere Probleme konnte ich nicht identifizieren.
>
> take it or leave it!

Das ist doch mal eine klare Aussage. :-)

von Torben (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Noch besser wäre es auf GitHub hochzuladen, dann kann es die Community 
unterstützen.

von Harry L. (mysth)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab die Funktion zum Definieren von eigenen Zeichen und ein 
Demo-Projekt hinzu gefügt.
Außerdem wurde ein kleinerer Fehler beseitigt.

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Harry L. schrieb:
> Um das zu compilieren:
> * Zip-File Im workspace-Folder entpacken
> * die .ioc-Datei mit CubeMX öffnen und Projekt generieren.
> * Projekt in Atollic importieren.
>
> Weder schön noch fertig...
>
> "Auf die Schnelle zusammen geklöppelt" - aber funktioniert. :)
> Vielleicht kann es ja jemand brauchen.

So.
Also braucht man dafür zwingend einen Workspace (deiner Atollic IDE) und 
Cube. Wer nicht genau DAS vorliegen hat, kriegt ein Problem.

Dein Projekt enthält rund 4 MB an diversesten CMSIS-Treibern und anderem 
Zeugs. Wird das tatsächlich für so eine kleine LCD-Ausgabe benötigt? 
Wohl eher nicht.

Nun, deine eigene Einschätzung teile ich vollkommen, habe aber schwere 
Zweifel, ob das jemand wirklich gebrauchen kann. Wohlgemerkt: brauchen 
könnte es sicherlich mancher, aber brauchbar ist es eher nur auf deinem 
PC mit genau deiner Umgebung.

Ich hätte mir eher eine dramatisch zusammengeschrumpfte Version 
vorstellen können, die nur aus 4 Dateien besteht:
- display.h
- display.c
- i2c.h
- i2c.c
wobei erstere 2 Dateien unabhängig sind vom konkreten µC und nur vom 
Displaytyp abhängen - und nur i2c.c abhängig ist vom konkreten µC.

Und idealerweise sollten diese Dateien auch unabhängig sein von Packages 
deiner IDE oder deines µC-Herstellers oder sonstigen Header- und 
Projekt-Dateien.

W.S.

von Harry L. (mysth)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Und idealerweise sollten diese Dateien auch unabhängig sein von Packages
> deiner IDE oder deines µC-Herstellers oder sonstigen Header- und
> Projekt-Dateien.

Was genau hast an "[STM32/HAL] generischer Treiber" nicht verstanden?

Dieser Code ist für STM32 und HAL.

Niemand zwingt dich, den zu nutzen!

Um den in ein eigenes HAL-Projekt zu integrieren, benötigt man genau die 
folgenden 4 Files:

lcd_i2c.c

lcd_i2c.h

lcd_config.h

lcd_map.inc

Und für Projekte mit HAL für STM32 nutzen wohl die meisten Attolic oder 
CubeIDE.

Wer das nicht so macht, sollte wissen, was er tut, und in der Lage dein, 
diese 4 Files als notwendig zu identifizieren.

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Harry L. schrieb:
> Dieser Code ist für STM32 und HAL.
>
> Niemand zwingt dich, den zu nutzen!

Eben. Du sagst es. Er ist nur für STM32 und HAL (und Atollic).

Und mir ist vollkommen klar, daß mich niemand zwingt. Ich habe von 
Anfang an deine eigene Einschätzung geteilt.

Das war auch nicht das Thema, sondern der Umstand, daß dein Treiber eben 
kein generischer Treiber für diese I2C-Displays ist, sondern eben ein 
sehr spezieller Treiber. Das ist so, müßte aber nicht so sein.

W.S.

von Harry L. (mysth)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Das war auch nicht das Thema, sondern der Umstand, daß dein Treiber eben
> kein generischer Treiber für diese I2C-Displays ist,

Doch, genau das ist er:
Ein generischer Treiber für STM32 mit HAL.
Der läuft unverändert mit allen STM32 von M0 bis M7.

W.S. schrieb:
> Das ist so, müßte aber nicht so sein.

Ach so?

Dann zeig mir mal, wie du das Architektur-übergreifend machen willst, 
wenn sich die Peripherie zwischen ST und z.B. NXP komplett 
unterscheidet.

Aber w.g.: das war auch zu keinem Zeitpunkt mein Anspruch.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Bewertung
-4 lesenswert
nicht lesenswert
@Harry:
letztens hast du dich doch so sehr damit geschmückt, dass du jahrzehnte 
an Programmiererfahrung hast und dann weiste nichtmal wie man einen 
Treiber schreibt, der verschiedene I2C Hardware ansteuern kann?

Selbst einen Treiber kann man aufteilen, in den Hardwareteil und in den 
Protokollteil (bei größeren Dingen gehen durchaus noch mehr Schichten).

Der Protokolltreiber bekommt eben beim Init Funktionspointer für 
read/write/control Funktionen.
Diese Funktionen sind dann der Hardwarespezifische Teil.

So läuft bei uns auf Arbeit zB derselbe NOR Flash Treiber auf 
ST/NXP/Atmel ;)

Aber du hast dich eben für den Vendor-Lock-In "HAL" entschieden mit 
Funktionsdirektaufrufen und Bugs ohne Ende.
static struct st7789spicallbacks displayspi;

static void display_ncs(uint8_t onoff){
  gpio_onoff(PORTA, 15, onoff);
}

static void display_dc(uint8_t onoff){
  gpio_onoff(PORTB, 4, onoff);
}

static void display_write(uint32_t bytes, uint8_t *buf){
  spi_w_bytes(DISP_SPI, bytes, buf);
}

static void display_read(uint32_t bytes, uint8_t *buf){
  spi_r_bytes_bidir(DISP_SPI, bytes, 0, buf);
}

void init_display(void){

  // SPI GPIO+CLK init
  rcc_enable_clock(RCC_GPIOA);
  gpio_initpin(PORTA, 15, GPO_PP, GPIO_HS, 0); // SPI_NSS
  gpio_onoff(PORTA, 15, 1);
  rcc_enable_clock(RCC_GPIOB);
  gpio_initpin(PORTB, 4, GPO_PP, GPIO_HS, 0);      // Data/Command
  gpio_initpin(PORTB, 3, AF_PP, GPIO_HS, AF5_SPI1_TO_2); // SPI_SCK
  gpio_initpin(PORTB, 5, AF_PP, GPIO_HS, AF5_SPI1_TO_2); // SPI_MOSI/MISO (bidir!)
  rcc_enable_clock(RCC_SPI1);

  // SPI Init
  spi_init_master(
    DISP_SPI,   // SPI Base
    0,       // LSB first = 1
    BR_DIV4,  // CLK div -> 60MHz/4 = 15MHz 
    0,      // CPOL
    0,      // CPHA
    SPI_8BIT);
  
  // DMA CLK
  rcc_enable_clock(RCC_DMA1);
  rcc_enable_clock(RCC_DMA2);
  
  // device descriptor init
  displayspi.ncs = display_ncs;
  displayspi.dc = display_dc;
  displayspi.write = display_write;
  displayspi.read = display_read;
  
  // sw reset
  st7789spi_SWRESET(&displayspi);
  sleep_ms(10);
  
  // display on
  st7789spi_SLPOUT(&displayspi);
  sleep_ms(10);
  st7789spi_DISPON(&displayspi);
  st7789spi_NORON(&displayspi);
  st7789spi_INVON(&displayspi);
  
  // Displaygröße
  st7789spi_CASET(&displayspi, 0, 239);
  st7789spi_RASET(&displayspi, 0, 239);
  
  // 16bit RGB
  st7789spi_COLMOD(&displayspi, st7789_col16bit);
}

void display_sendout(struct gui_buf *buf, void (*callb)(void)){

  if (dma_check_active(DISP_SPI_DMA)){
    /* dma is busy with last one */
    return;
  }

  if (0 == buf->ystart){
    st7789spi_RAMWR_commandonly(&displayspi);
  }else{
    st7789spi_RAMWRC_commandonly(&displayspi);
  }
  
  display_ncs(0);
  
  int err = spi_dmamode(
    DISP_SPI,           // Welcher SPI
    (uint8_t*)buf->buf,     // SPI Sendebuffer
    NULL,            // SPI Empfangsbuffer
    DISP_SPI_DMA,        // DMA Sendestream
    NULL,              // DMA Empfangsstream
    (buf->ysize*buf->xsize),  // Anzahl der zu übertragenden Daten
    SPI_8BIT,          // Bitbreite auf dem SPI
    callb_dma_spi_int,       // IRQ Handler DMA
    callb,             // IRQ Handler DMA Daten
    callb_dma_spi_irq_spi_err,  // IRQ Handler SPI Err
    NULL            // IRQ Handler SPI Err Daten
  );
  
  if (err){
    display_ncs(1);
  }
}

Was dort zu sehen ist, ist mein HAL.
Das ist dann wirklich ein echter HAL und nicht dieser STM32 möchtegern 
HAL.
Dieser stell dem Programm Display init/send bereit.
Somit kann meine Software auch ohne große Änderungen ein anderes Display 
ansteuern.
Dabei initilisiert der HAL die STM32 Hardware und stellt das dann per 
Funktionspointer in einem Struct dem Displaytreiber bereit.

von Harry L. (mysth)


Bewertung
-1 lesenswert
nicht lesenswert
Ganz, gant toll, "dein HAL"!

Diese wunderbare Trennung zwischen Schnittstelle und Display...

Wenn man das Display nur mal -dem Layout geschuldet- an andere Pins 
anschließen will, muß an erstmal in deiner tollen Init-Funktion 
herumpfuschen.
Genau SO wünscht man sich ja einen Abstraktions-Layer....

Daß ich ST HAL nutze ist bereits im Thread-Titel erkennbar, also nerv 
hier nicht weiter rum und geh mit W.S. ein Bier trinken!

Ich hab absolut keinen Bock, mich ständig dafür rechtfertigen zu müssen,
und schon gar nicht gegenüber Leuten, die das nur vom Hörensagen 
und/oder flüchtigen Blicken in den Code kennen, und dabei sowieso der 
Ansicht sind, alles so viel besser zu können.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Bewertung
0 lesenswert
nicht lesenswert
Harry L. schrieb:
> Ich hab absolut keinen Bock, mich ständig dafür rechtfertigen zu müssen

Naja, das kommt ja nicht von ungefähr.
So wie du in fast jedem STM32 Thread den HAL als das beste der Welt 
anpreist ;)


Harry L. schrieb:
> und schon gar nicht gegenüber Leuten, die das nur vom Hörensagen
> und/oder flüchtigen Blicken in den Code kennen, und dabei sowieso der
> Ansicht sind, alles so viel besser zu können.
Also ich musste ja mal mit dem HAL arbeiten, das war einfach nur ein 
Graus und eine Schlangengrube an Bugs.
Zudem hatte ich immer Konkrete Bugs dir gegenüber genannt, für dein 
fehlendes Kurzeitfedächtnis kann ich nix.
Ist ja schön für dich, dass du nur Spielzeug entwickeltst und daher 
nicht auf diese Bugs stößt.

Harry L. schrieb:
> Wenn man das Display nur mal -dem Layout geschuldet- an andere Pins
> anschließen will, muß an erstmal in deiner tollen Init-Funktion
> herumpfuschen.

Ach? Das ist bei deinem Projekt einfacher?
CubeMX aufmachen, Pins ändern, Code neu erzeugen.

Aber ja, das sollte noch per defines in den header, da jaste recht.
(Das Projekt ist noch am entstehen)

von Vincent H. (vinci)


Bewertung
0 lesenswert
nicht lesenswert
Mw E. schrieb:
> Harry L. schrieb:
>> Wenn man das Display nur mal -dem Layout geschuldet- an andere Pins
>> anschließen will, muß an erstmal in deiner tollen Init-Funktion
>> herumpfuschen.
>
> Ach? Das ist bei deinem Projekt einfacher?
> CubeMX aufmachen, Pins ändern, Code neu erzeugen.

Hab kurz ins Projekt reingeschaut und seh auf die schnelle nur eine 
einzige Abhängigkeit des gesamten LCD Codes (Display-Eigenschaften und 
STM HAL ausgenommen). Jene Abhängigkeit ist vom Typ I2C_HandleTypeDef 
und wird sauber bei der Initialisierung übergeben.

Bei deinem Code-Snippet oben zähl ich etwa 10 Abhängigkeiten und obwohl 
du irgnedwas von Funktionspointern schreibst is davon nichts zu sehn.

: Bearbeitet durch User
von W.S. (Gast)


Angehängte Dateien:

Bewertung
-3 lesenswert
nicht lesenswert
Harry L. schrieb:
> Ich hab absolut keinen Bock, mich ständig dafür rechtfertigen zu müssen,

Also erstens habe ICH hier niemals so etwas von dir verlangt.

Und zweitens wirst du akzeptieren müssen, daß andere Leute ihre eigene 
Meinung zu deinem Projekt haben und auch das Recht haben, selbig zu 
äußern.

Und drittens kann ich das tatsächlich besser als du. Lies weiter:

Harry L. schrieb:
> W.S. schrieb:
>> Das ist so, müßte aber nicht so sein.
>
> Ach so?
>
> Dann zeig mir mal, wie du das Architektur-übergreifend machen willst,
> wenn sich die Peripherie zwischen ST und z.B. NXP komplett
> unterscheidet.

So. hier zeige ich es dir:

Ich habe dir einen Auszug aus einem meiner Projekte drangehängt. Nur 
einen Auszug, sonst nichts. Es ist ein Treiber für eines der Displays, 
die Pollin im Programm hat bzw. hatte.

Die Gemeinsamkeit mit deinem Projekt besteht darin, daß dieses Tian-Ma 
LCD auch ein alphanumerisches Display ist und daß es auch per I2C 
angesteuert werden muß.

Daß es auch noch einen speziellen Resetpin hat, muß im Treiber 
berücksichtigt werden.

Nun schau in die Zip-Datei und du findest dort tianma.c nebst tianma.h 
sowie i2c.h vor.

Hierbei enthält der eigentliche Displaytreiber tianma.c nur den 
allernötigsten Bezug auf eine Zielplattform, der darin besteht, daß man 
mit irgend einem Pin das Resetbein des LCD ansteuern muß. Das ist der 
ganze Bezug auf die konkrete Plattform. Ich hätte das auch in einen 
Extra-Lowlevel-Treiber auslagern können, dann wäre der ganze Treiber 
tianma.c plattformunabhängig.

Das physische Ansteuern des LCD erfolgt über den Treiber i2c.c, den ich 
hier aber nicht beifüge, da dieser eben hardwareabhängig ist.

Dem Displaytreiber tianma.c kann und SOLL das auch egal sein, denn er 
baut auf dem Interface desjenigen I2C-Treibers auf, der zur konkreten 
Plattform paßt.

Ich habe für die I2C-Ansteuerung mehrere Lowlevel-Treiber im Portfolio: 
sowohl solche, die die vorhandene I2C-Peripherie des Chips verwenden als 
auch einen, der rein softwaremäßig arbeitet und lediglich zwei beliebige 
Pins des Chips zugewiesen kriegen muß - allerdings müssen diese als Open 
Drain benutzbar sein und der tatsächliche Pinzustand muß lesbar sein 
(trifft z.B. für den LPC1114 nicht! zu).

So, dieser Display-Treiber kann damit auf fast völlig beliebigen 
Plattformen benutzt werden, ARM, MIPS, PIC, MSP und so weiter. Einzig 
das o.g. Reset und ein allgemeiner I2C Lowlevel-Treiber müssen vorhanden 
sein.

So macht man so etwas. Ich hoffe, daß du damit etwas dazugelernt hast.

W.S.

von Vincent H. (vinci)


Bewertung
2 lesenswert
nicht lesenswert
W.S. schrieb:
> Und drittens kann ich das tatsächlich besser als du. Lies weiter:

Das seh ich nicht so. Es ist "anders" und nicht "besser". Bei deinem 
Beispiel muss I2C Code hinzugefügt werden. Das Beispiel ganz oben ist 
plug&play tauglich.

Ansonsten ist der Code trotz all deiner Überheblichkeit ziemlich 
ähnlich. Er unterscheidet sich eigentlich nur darin dass die HAL-Aufrufe 
als Customization-Points herausgeführt sind.

von Harry L. (mysth)


Bewertung
2 lesenswert
nicht lesenswert
W.S. schrieb:
> Und drittens kann ich das tatsächlich besser als du.

Wissen wir alle bereits.
Deine unerträgliche Arroganz nervt!

W.S. schrieb:
> So macht man so etwas.

Nein, nur du meinst, daß man "es so macht".

Dein Code ist wie üblich  gespickt mit Magic Numbers und wird dadurch 
nicht gerade lesbarer.

Dein I²C-Code (lt. i2c.h) bildet auch nur die minimale Funktionalität 
ab.
So lange das Display das Einzige ist, was an diesem Bus hängt mag das 
ausreichend sein, aber sobald da noch was Anderes dranhängt, für das man 
evtl. Interrupts benötigt, fängt man wieder von Vorne an.

Das geht mit HAL deutlich besser und komfortabler, aber, das wirst du 
ohnehin nicht akzeptieren, da du ja offenbar keine anderen Götter neben 
dir duldest...


Also verschon mich mit deinen "Weisheiten" von vor >20J.
Ich schau mir gerne bei Leuten, die das wirklich können Coding-Techniken 
ab, aber dein Code gehört definitiv nicht dazu.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
3 lesenswert
nicht lesenswert
Harry L. schrieb:
> Also verschon mich mit deinen "Weisheiten" von vor >20J.

Sehe ich genauso. W.S. meint desöfteren, Code hier in P&C 
schlechtzumachen, nur weil er nicht so programmiert wurde, wie er es 
machen würde.

Statt einen eigenen Thread unter "Projekte und Code" aufzumachen, um 
seinen Code vorzustellen, redet er mittels Binsenweisheiten, die jedes 
kleine Kind bereits kennt, erstmal alles platt.

P.S.
Der Code von W.S. ist gespickt mit gotos innerhalb von while-Schleifen, 
wo ein einfaches "break" denselben Effekt hätte. "break" scheint er aber 
nicht zu kennen. Naja, C ist nicht gerade seine Stärke.

: Bearbeitet durch Moderator
von Mw E. (Firma: fritzler-avr.de) (fritzler)


Bewertung
0 lesenswert
nicht lesenswert
Harry L. schrieb:
> und geh mit W.S. ein Bier trinken!
Lieber nich, seine Magic Numbers kann er behalten.

Harry L. schrieb:
> also nerv
> hier nicht weiter rum

Da würde ich dich bitten dies auch nicht in anderen Threads zu tun mit 
deinem HAL Fanboytum.

von Daniel B. (daniel_3d)


Bewertung
0 lesenswert
nicht lesenswert
@Harry

Vielen Dank für die Mühe und die Veröffentlichung.

Gruß
Daniel

von W.S. (Gast)


Bewertung
-4 lesenswert
nicht lesenswert
Frank M. schrieb:
> Der Code von W.S. ist gespickt mit gotos innerhalb von while-Schleifen,
> wo ein einfaches "break" denselben Effekt hätte. "break" scheint er aber
> nicht zu kennen.

Ach nö.
Ich kenne break durchaus, genauso wie for, mag beides jedoch nicht 
wirklich.

Und?

Break ist hier die schlechtere Wahl, weil es ne ganze Kette von Aufrufen 
gibt, bei denen man die folgenden nicht ausführen darf, wenn der 
vorherige ein false geliefert hat - also ist ohnehin goto angesagt. 
Alternativ könnte man daraus ein tief verschachteltes if(.... if(... 
machen, aber das ist nun wirklich unleserlich.

Der eigentliche Punkt ist jedoch, daß dieser Treiber für das besagte LCD 
eben wirklich weitestgehend unabhängig ist von Plattform, Compiler und 
Hersteller. Der Code des TO hingegen ist strikt an ST und deren Zeugs 
gebunden, was dessen Verwendung eben genau so einschränkt, wie ich das 
weiter oben geschrieben habe.

Plattformunabhängig macht man sowas, indem man aus einem Treiber alles 
herausnimmt, was plattformabhängig ist und selbiges in einem quasi 
darunter liegenden Treiber hat. Der wiederum braucht sich nicht um die 
Befindlichkeiten eines LCD's zu scheren.

Genau DAS wollte der TO ausdrücklich gezeigt kriegen - und ich habe es 
ihm gezeigt!

Also mault nicht herum.

W.S.

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
3 lesenswert
nicht lesenswert
W.S. schrieb:
> Break ist hier die schlechtere Wahl, weil es ne ganze Kette von Aufrufen
> gibt, bei denen man die folgenden nicht ausführen darf, wenn der
> vorherige ein false geliefert hat - also ist ohnehin goto angesagt.

Unsinn. Hier ein Beispiel, ich habe mir direkt mal Deine Funktion 
LCD_BufOut() herausgepickt:
bool LCD_BufOut (void)
{ int i;
  bool erg;

  erg = Do_I2C_Start(LcdAdr, I2CWRITE);
  if (!erg) goto raus;

  erg = Do_I2C_Write(0x80);  // CO=1, RS=0 -> Control schreiben
  if (!erg) goto raus;

  erg = Do_I2C_Write(2);     // Home
  if (!erg) goto raus;

  erg = Do_I2C_Write(0x80);  // CO=1, RS=0 -> Control schreiben
  if (!erg) goto raus;

  erg = Do_I2C_Write(0x80);  // set DDRAM Adr
  if (!erg) goto raus;

  erg = Do_I2C_Write(0x40);  // CO=0, RS=1 -> Daten schreiben
  if (!erg) goto raus;

  i = 0;
  while (i<cbuflen)
  { erg = Do_I2C_Write(LCDBUF[i]);
    if (!erg) goto raus;
    ++i;
  }
  raus:
  Do_I2C_Stop();
  return erg;
}

Umgeschrieben ohne goto:
bool LCD_BufOut (void)
{
    int  i;
    bool erg = false;

    if (Do_I2C_Start(LcdAdr, I2CWRITE) &&
        Do_I2C_Write(0x80) &&                // CO=1, RS=0 -> Control schreiben
        Do_I2C_Write(2) &&                   // Home
        Do_I2C_Write(0x80) &&                // CO=1, RS=0 -> Control schreiben
        Do_I2C_Write(0x80) &&                // set DDRAM Adr
        Do_I2C_Write(0x40))                  // CO=0, RS=1 -> Daten schreiben
    {
        erg = true;

        for (i = 0; i < cbuflen; ++i)
        {
            if (! Do_I2C_Write(LCDBUF[i]))
            {
                erg = false;
                break;
            }
        }
    }
    Do_I2C_Stop();
    return erg;
}

Meine Variante ist nicht nur kürzer, sondern auch noch lesbarer, weil 
der Lesefluss nicht mehr durch die dauernden Aufrufe von gotos behindert 
wird. Dabei musste ich noch nichtmals auf Deine Platzspartricks wie die 
Positionierung von Statements nach '{' zurückgreifen. Die Krücke von 
while-Schleife habe ich direkt mal zwecks besserer Lesbarkeit in eine 
for-Schleife geändert.

> Alternativ könnte man daraus ein tief verschachteltes if(.... if(...
> machen, aber das ist nun wirklich unleserlich.

Unsinn, das ist nix tief verschachtelt. Gegenbeweis siehe oben: Man 
sieht jetzt schön die Reihenfolge der Bytes, die da fließen. Die 
Funktionskette im if-Statement wird von oben nach unten abgearbeitet und 
automatisch abgebrochen, sobald einer der Aufrufe false zurückliefert. 
Das dauernde Setzen der Variablen erg kann man sich auch dabei sparen.

> Der eigentliche Punkt ist jedoch, daß dieser Treiber für das besagte LCD
> eben wirklich weitestgehend unabhängig ist von Plattform, Compiler und
> Hersteller.

Mit dem Editor brauche ich weniger als eine Minute, um per 
Global-Replace den Aufruf der HAL-I2C-Funktionen auf eine 
Mapper-Funktion zu ändern. Das habe ich übrigens so gemacht, um meine 
eigene I2C-Lib ohne HAL hier einzubinden. Das ist überhaupt keine Kunst.

> Der Code des TO hingegen ist strikt an ST und deren Zeugs
> gebunden, was dessen Verwendung eben genau so einschränkt, wie ich das
> weiter oben geschrieben habe.

Du lamentierst stundenlang über eine Sache, die sich in wenigen Sekunden 
beheben lässt.

P.S.
Du scheinst ein Problem mit der Bezeichnung "generisch" zu haben. Dieses 
"generisch" bezog der TO auf die STM32-Familie durch Verwendung von HAL. 
Zugegeben: ich mag auch kein HAL, aber deshalb hänge ich mich nicht 
stundenlang an einer Bezeichnung auf, indem ich sie absichtlich 
missverstehe.

: Bearbeitet durch Moderator
von lol (Gast)


Bewertung
4 lesenswert
nicht lesenswert
Wenn W.S. vom C Programmieren erzählt klingt das so als würde ein 
Blinder vom Sehen erzählen.

von Gerne auch (Gast)


Bewertung
3 lesenswert
nicht lesenswert
Frank M. schrieb:
> W.S. schrieb:
>> Break ist hier die schlechtere Wahl, weil es ne ganze Kette von Aufrufen
>> gibt, bei denen man die folgenden nicht ausführen darf, wenn der
>> vorherige ein false geliefert hat - also ist ohnehin goto angesagt.
Befindlichkeiten mit angeblicher Expertenkenntnis um sich selber hoch 
herauszustellen.

> Unsinn. Hier ein Beispiel, ich habe mir direkt mal Deine Funktion
> LCD_BufOut() herausgepickt:
> ...
> Umgeschrieben ohne goto:
> ...
> Meine Variante ist nicht nur kürzer, sondern auch noch lesbarer, weil
> der Lesefluss nicht mehr durch die dauernden Aufrufe von gotos behindert
> wird.
Wirklich gut! Sehr viel lesbarer, kürzer und logischer aufgebaut. So 
wünsche ich mir Code von Entwicklerkollegen. Ich würde sogar noch weiter 
gehen und die Bitpatterns per #define o.ä. mit lesbaren Namen versehen. 
Ist schneller zu verstehen und man ändert das bei Bedarf an einer 
einzigen Stelle und fertig.

W.S. schrieb:
> So, dieser Display-Treiber kann damit auf fast völlig beliebigen
> Plattformen benutzt werden, ARM, MIPS, PIC, MSP und so weiter. Einzig
> das o.g. Reset und ein allgemeiner I2C Lowlevel-Treiber müssen vorhanden
> sein.
>
> So macht man so etwas. Ich hoffe, daß du damit etwas dazugelernt hast.
Ohje, ohje: Heute noch 'goto' außerhalb der Sondererlaubnis im 
Linux-Kernel zu benutzen und sich über andere Leute aufzuregen ist schon 
wirklich ziemlich hart. Und ich dachte immer, daß hier alles nur Profis 
unterwegs sind, wenn sie sich derart hervortun. Muß wohl meine 
Wahrnehmung mal neu justieren.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.