Electronic Assembly (EA) DOGM081x-A Spi Ansteuerung

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Electronic Assembly (EA) DOGM081x-A Spi Ansteuerung

      Hallo,

      neues Projekt, neue Probleme...
      Ea geht um Spannungs- und Stromanzeigen für 3 Phasen (32A, 2x 16A), wo ich 4 Anzeigen pro Phase verwende.
      Es geht nicht um die Hardware, die läuft schon gut.
      1. Anzeige: Phase, 2. Anzeige: Spannung, 3. Anzeige: Strom 16 A, 4. Anzeige: Strom 16 A
      Nach doch langem hin und her überlegen, welche Anzeigen ich verwende, habe ich mich für die DOGM081x-A von EA entschieden.
      Ich verwende nur die Displays von EA, die OLED-Displays sind super, teuer, aber gut. Habe aber bisher die Displays im 4 Bit-Mode angesteuert.

      Ansteuerung geht halt nur per SPi, da 4 Anzeigen, aber ich habe inzwischen SPi lieben gelernt. :D
      Also, zum Test ein Display.
      Initialisierung funktioniert, alles gut.
      Das Problem was ich habe, ist, daß die Aktualisierung des Displays sehr langsam ist.
      Zum Test einen Temp-Sensor verwendet.
      So alle 5 Sekunden wird das Display aktualisiert. MMhhhh...
      Liegt das an der Aufbereitung und senden der Werte für das Display?
      Weiter habe ich Probleme mit der "Formatierung" und Positionierung der Werte auf dem Display.
      Vielleicht kann mir jemand bitte weiterhelfen.
      Anbei das Testprogramm, und ja Stack-Werte sind angegeben.

      Danke und Gruß
      Dagobert
      Files
      • Test_081_02.bas

        (7.33 kB, downloaded 13 times, last: )
    • Hi, das kann mehrere Ursachen haben.
      Zuerst solltest du prüfen, ob das Programm tatsächlich mit den 12MHz getaktet wird.

      Füge mal in dein Programm vor der Hauptschleife den Blinktest ein (Pin einstellen!).

      BASCOM Source Code

      1. LED Alias Port.Deinerwahl
      2. Config LED = Output
      3. Do
      4. Toggle LED
      5. Waitms 500
      6. Loop
      7. ' hier beginnt deine alte Hauptschleife.
      Die LED muss im Sekundentakt blinken.

      Wenn der Takt des Controllers passt, dann weiter.

      Die eingefügte Schleife entfernen. LED-Ausgang wird noch gebraucht.
      Dann kannst du den LED-Ausgang zum Debuggen nehmen mit einem Oszi.

      Dann würde ich schauen, ob das Lesen vom I2C, das Berechnen oder die Ausgabe per SPI die Bremse ist.
      Dazu davor die LED einschalten und danach wieder aus.
      Das musst du für die 3 Möglichen "Bremsen" nacheinander machen, also immer eins nach dem anderen.

      Dann die Pulsbreite im Oszi messen, also die Verarbeitungsdauer der jeweiligen Routine.
      So kannst du mal die Ursache einkreisen.

      Aber ich würde die Stackwerte mit 20 mal auf 40 erhöhen. Vielleicht ist das schon das Problem.

      The post was edited 1 time, last by Mitch64 ().

    • @Mitch64
      danke für deine Antwort.

      jo, Takt ist 12 MHz.
      Hab die Stackwerte auf 40 erhöht, es war eine minimale Verbesserung erkennbar.
      Das Wait bei der Temp-Abfrage war das Problem.
      Dadurch hält ja alles an....
      Hab die Temp-Abfrage wieder mit einer Schleife realisiert, wie in meinen anderen Thermometer-Projekten.
      Damit hält der Code nicht an.

      Das Display braucht ca. 20 - 30µs Zeit um die Befehle zu verarbeiten.
      Deswegen nach dem Spiout ein wait von 20µs.
      Wieder ein Wait und es gefällt mir nicht.
      Wie kann ich das Wait ersetzen?
      Ich benutze die Hardware-SPi.
      Muss ich umsteigen auf Software-SPi um Shiftout mit Delay benutzen zu können um das Wait zu eleminieren?

      Gruß
      Dagobert
    • Ein Wait umgeht man, indem man es nicht benutzt.
      Mir ist klar, dass du an einer Stelle x ms warten willst, aber dann muss man eben so vorgehen, dass man am Anfang eine "Zeit" holt und dann pollt, bis die Zeit um ist. Dazu braucht man im Programm aber eine andere Struktur. Eine Variante ist die Statemachine. Dazu gibts auch ein Lexikon-Eintrag.

      Wenn du nicht nachvollziehen kannst was ich meine, dann sag Bescheid, ich mach dann ein kleines Beispiel. Das sagt bekanntlich mehr als 1000 Worte.

      Zur SPI.
      Auf Software-SPI musst du nicht umsteigen.
      Die Befehle, die Bascom dazu bereit stellt verwenden einen Buffer. Und der ist deine Variable oder Array. Und wenn du schreibst SendSPI Array(1),4 dann sendet Bascom 4 Bytes in dem maximalen Tempo und zwar ohne Unterbrechung.
      Sollen die Bytes aber z.B. alle 500 ms eines übertragen werden, darfst du logisch nur alle 500ms 1 Byte senden. Also z.B. mit SendSPI Array(1),1 dann folgt die Pause, dann SendSPI Array(2),1 usw.

      Wenn du allerdings die Wait 20µs meinst, die dich stören, wäre die Statemachine nicht der richtige Weg.

      The post was edited 1 time, last by Mitch64 ().

    • Aber warum schreibst du die ganzen Routinen selber, um das Display zu bedienen?
      Es geht auch anders.

      Du musst eigentlich nur die Standard-Routinen, die Bascom zur Ausgabe von Datenbytes und ControlBytes verwendet, auf eigene Routinen "umbiegen".

      Das bedeutet, dass dann die normalen LCD-Befehle in gewohnter Weise verwendet werden können. Also InitLCD, CLS, Locate, Print etc.

      Schau dir mal die beiden Direktiven an:
      $LCDPUTCTRL und
      $LCDPUTDATA

      Damit kannst du die internen Ausgabe-Routinen für Datenbytes und Steuerbytes auf eigene Routinen umlenken.

      Du must dann nur diese beiden Routinen schreiben, in denen du das Byte auf SPI schreibst und zuvor die Steuerleitungen setzt.

      Übrigens kann man nach der Masche auch jedes I2C-Display bedienen. Man muss dann eben auf den I2C-Bus schreiben.
    • Pluto25 wrote:

      Ob dann das Init noch klappt? Die in den DOG-libs sind völlig anders als das von Dago1
      Die interne InitLcd wird aufgerufen. Sollte das Display damit nicht funktionieren, kann man die Init-Commands von Dago einfach hinterherschicken mit dem Befehl

      LCDCmd

      (Der Befehl für Datenbytes wäre LcdData.)

      Und diese rufen dann wieder die Routinen auf, die man mit
      $LcdPutCtrl und
      $LcdPutData

      definiert hat.

      Damit sollte das klappen.

      Soweit ich gesehen habe, unterstützt Bascom von Haus aus keine 8x1 DOGM Displays. Zumindest habe ich nichts in der Hilfe gefunden.

      Aber mit der Initialisierung von Dago sollte es trotzdem gehen, wenn man die mit LcdCmd abschickt (nach InitLCD).
    • Das ist die falsche Frage.:

      Pluto25 wrote:

      Wo wäre der Vorteil von LcdCmd zu seinem Dogm_init?

      Wenn man die $LCDPutDATA und $LCDPutCtrl verwendet, werden ja alle Daten ans Display über die dort angegebenen Routinen geleitet. - Auch die von der Display-Initialisierung, die ja intern automatisch aufgerufen wird.

      Also gibt es 2 Möglichkeiten. Zuerst die interne (vielleicht unwirksame) InitLCD ausführen lassen und danach die von Dago aufrufen, die ja eigene Initialisierungs-Commands fürs Display bereit hält. Ist dann zwar 2x initialisiert, aber damit kann man glaube ich leben.

      Wenn es aber jemand stört wie dich z.B., dann kann man auch eine eigene LCD-Lib schreiben, in der man die InitLCD auch nach Basic umleitet und dort die von Dago verwendet.
      Das macht aber alles komplizierter.

      Der Vorteil ist eben, dass man alle LCD-Befehle von Bascom verwenden kann.
      Er muss also nicht Strings vorhalten, was auf dem Display anzuzeigen ist und dann byteweise per eigener Routine Zeichen für Zeichen aus dem String auslesen, in ein Byte kopieren, und das dann per SPIOut verschicken. Sondern er kann einfach Print verwenden.

      Ich denke die Vorteile überwiegen und den Nachteil, dass das Display vielleicht 2x initialisiert wird (ist ja nur einmalig), kann man verschmerzen.

      Ach ja,
      Das soll nur ein Vorschlag sein. Diesen Weg würde ich gehen, weils am wenigsten Programmieraufwand bedeutet.

      Aber jeder kann ja für sich entscheiden, wie er es macht.
    • @Mitch64

      Danke für deine Mühe.
      ja, das mit der Abfrage des Temp-Sensors hat sich ja erledigt.
      Mit dem Temp-Sensor war nur ein Test zum Ansteuern des Displays per SPi und "formatieren" der Daten.
      Mir geht es um die 20µs wait bei der SPi-Ausgabe.

      Das mit der Statemaschine hab ich mal überflogen, interessant, aber für dieses Projekt wohl weniger geeignet,
      Auch die Sache mit $LCDPUTCTRL und $LCDPUTDATA hab ich mir angeschaut.
      OK, könnte die Bascom LCD Befehle nutzen. Vorteil.
      Aber, die 2 Daten für die Anzeige im Endeffekt (Spannung oder Strom und die Einheit dazu V oder A)...
      Die Frage wäre halt auch dabei, ob die 20µs wait dann wegfallen würden und ob über diesen Weg 4 Displays angesteuert werden könnten.


      @Pluto25

      Mit Soft-SPi, Shiftout und Delay, das Delay im Endeffekt auch "nur" ein Wait ist, hab ich mir fast gedacht.
      SPi Schnittstelle vom Display-Chip läuft im Nano-Sekunden Bereich.
      Ich hab mal die Clockrate auf 64 gesetzt und diese Konstellation funktioniert ohne Wait. Danke für den Tipp.

      Gruß
      Dagobert
    • Dago1 wrote:

      Mir geht es um die 20µs wait bei der SPi-Ausgabe.
      Nach Datenblatt musst du nach Übertragung eines Bytes 27µs Zeit lassen, das Byte zu verarbeiten.
      Ausnahmen sind Cls (CMD = 1) und Home (CMD = 2), die brauchen 2ms und 1,5ms ca.

      Du kommst also um die 20µs, was ja 27µs sein müssen nicht herum.

      27µs sind ja nicht die Welt sag ich mal. Es kommt aber immer drauf an, wie Zeitkritisch etwas ist.
      Wenn dich die 27µs nach jedem Byte stören, dann musst du in dieser Zeit etwas anderes machen.

      Auf der anderen Seite hast du ja auch Laufzeiten im Programm zwischen den SPIOut Aufrufen.
      Es bietet sich an, mal ein Testprogramm zu machen, das per Schleife immer ein Byte sendet.
      Mit dem Oszi kann man das dann anschauen, wie lange die Zeiten zwischen den Bytes (immer Anfang zu Anfang gerechnet) ist.

      Da kannst du dann bestimmt die eingestellten Waitus 27 noch reduzieren, so dass dann real die 27µs eingehalten werden.
      Man muss ja auch bedenken, dass die SPI bei einem Byte-Strom von hause aus eine Lücke zwischen den Bytes hat.
      Das liegt daran, dass das nächste Byte erst dann in das SPDR geschrieben werden kann, wenn das vorherige vollstündig ausgegeben wurde.
      Und genau dazwischen entsteht durch Laufzeit eine Lücke.

      Wenn du jetzt hin gehst und den SPI-Takt auf '/64' einstellst, sparst du dir vielleicht die Waitus, aber das Byte wird auch langsamer übertragen.
      Wenn man nachrechnet braucht dann ein Byte reine Übertragungsdauer 42us. Bei Takt '/4' sind es 2,7µs. Beidemale kommt noch die Programmlaufzeit dazu.


      Dago1 wrote:

      Die Frage wäre halt auch dabei, ob die 20µs wait dann wegfallen würden und ob über diesen Weg 4 Displays angesteuert werden könnten.

      Wenn du nun mehrere Displays betreiben möchtest, musst du im Prinzip genauso die 27µs einhalten je Display und Byte.
      Wenn du also dem Display 1 ein Byte sendest, und es nach 2.7µs von der SPI rausgeschoben wurde, kannst du noch nicht dem Display 2 ein Byte schicken,
      Du musst warten, bis das Display das Byte verarbeitet hat (27µs oder länger). Denn sonst könnte es sein, dass die RS-Leitung für Display 2 geändert wird
      und das Byte für Display 1 nicht da landet, wo es ankommen soll. Das müsste man mal ausprobieren. Vielleicht geht's ja doch.
      Dabei gehe ich davon aus, dass die RS-Leitung für alle Displays gemeinsam genutzt wird.

      Man könnte per Statemachine eine quasi simultane Ausgabe auf alle Display realisieren.
      Aber ich denke der Aufwand lohnt nicht. Die 8 Zeichen sind schnell geschrieben.
      D.h. wenn alle 4 Displays mit 8 Zeichen zu beschreiben sind, wären das 4x8 Zeichen * 27µs = 0,86ms, bis alle Displays beschrieben sind.

      Auf der anderen Seite könnte man aber im Hauptprogramm weiter machen, Sensoren abfragen, Taster abfragen uvm, während die 27µs für das ausgegebene Byte verstreichen.
      Ganz über Borad würde ich die Statemachine nicht werfen! Man kann das auch im Hauptprogramm für andere Zwecke gut einsetzen.

      Was ich dir aber empfehle ist, die Display-Ausgaben nur dann zu machen, wenn auch tatsächlich was auszugeben ist (geänderter Wert). Das bremst dann das System weniger aus.

      Im übrigen ist es auch möglich, per 4-Bit Mode mehrere Displays zu betreiben, sofern die WR-Leitung der Displays alle auf GND sind. So ist es zumindest einfacher.
      Die RS-Leitung wäre dann mit allen Displays verbunden und die Enable-Leitung bräuchte man dann 1x je Display. Datenleitungen sind wieder zusammen gefasst.

      Und noch was zum Schluss.

      Ich habe mich gestern mal hingesetzt und eine Lib geschrieben, die die Umsetzung der Display-Ausgaben nach SPI für deine Display's macht.
      Dazu gibt es eine Demo, vorbereitet für 2 Display's mir geremmten Zeilen für Erweiterung auf 4 Displays. Der Code ist allerdings nur im Simulator getestet.

      Es wird die Display-Initialisierung aus dem Datenblatt verwendet, die deinem bis auf den Kontrast entspricht. Kannst ja anpassen!
      Damit kannst du alle LCD-Befehle für alphanumerische Displays verwenden.

      Was auch noch wichtig ist, dass die Lib nur die RS-Leitung setzt, nicht aber die CS-Leitungen für die Displays. Das muss der Programmer von Hand machen.
      Das ist dann aber in der Demo nochmal erwähnt.

      Wenn du oder jemand anderer hier im Forum Interesse hast, einfach melden.
    • @Mitch64

      recht vielen Dank für deine ausführlichen Erläuterungen.
      Es soll aber von mir nicht so rüber kommen, daß andere die Arbeit erledigen und Code für mich erstellen sollen.
      Ineressant finde ich Möglichkeit im 4-Bit-Mode mehrere Displays betreiben zu können. Wusste ich nicht.

      Also, so zeitkritisch ist die ganze Geschichte nun auch wieder nicht.
      Die Display-Aktualisierungen sollten aber schon zügig passieren, also nicht im 5-Sek-Takt.
      Gerade bei der Anzeige des Stroms ist das wichtig für mich, da die einzelnen 230V-Phasen bis max. 16A belastet werden können und werden (z.B. Heizung Nebelmaschine).
      Da ich aber mich auf die Displays festgelegt habe, werde ich nun mal die restlichen bestellen, bevor es keine mehr gibt.
      Mit 2 Displays kann ich erstmal weiter testen, eins hab ich noch da, muss mal suchen...
      Ich fange halt diesmal mit der Datenausgabe an, Dateneingabe erfolgt ja final per Funk und RS232 mit den HC-12 Modulen.

      Ja, das Datenblatt von dem Chip habe ich auch von vorne nach hinten und wieder zurück gelesen.
      Die SPi-Schnittstelle vom Chip kann so schnell sein wie sie will, die 20-30 µs Verarbeitungszeit pro Display sind in Stein gemeiselt.
      Bei 12Mhz Quarz-Frequenz und SPi-Clockrate von 4 lief das Ganze noch bei einem Waitus von 20.
      Das bei Erhöhung des Werts der SPi-Clockrate der SPi-Bus langsamer wird ist mir bewusst. Die Programmlaufzeit wird sich noch erhöhen.

      Die RS-Leitung wird für alle Displays identisch geändert. Es gibt nur 2 Ansteuerungen: Initialiseren oder Daten schreiben.
      Nach der Initialisierung liegt RS für alle Displays permanent auf High.
      Aber Du hast recht, nach jeder SPi-Ausgabe muss dann gewartet werden.

      Zum letzten Punkt:
      natürlich habe ich Interesse an der Lib.
      Würde die gerne erstmal mit 2 Displays testen.
      Also melde ich mich mal für die Lib.

      Gruß Dagobert
    • Dago1 wrote:

      recht vielen Dank für deine ausführlichen Erläuterungen.
      Es soll aber von mir nicht so rüber kommen, daß andere die Arbeit erledigen und Code für mich erstellen sollen.
      Gern geschehen.
      Tut es nicht.


      Dago1 wrote:

      Bei 12Mhz Quarz-Frequenz und SPi-Clockrate von 4 lief das Ganze noch bei einem Waitus von 20.
      Ja weil du da mit 20µs + Laufzeit über die 26.8µs, die im Datenblatt angegeben sind, kommst.

      In den Bascom-Libs, wenn du dir die mal anschaust, wirst du immer solche "Waits" finden, damit das Timing passt.

      Zur Lib.
      Ich habe die als Zip angehängt.
      Darin findest du ein Lib-Verzeichnis, da sind die Libs drin. Die ins Lib-Verzeichnis kopieren.
      Dann in Bascom das Prokejt-File öffnen (*.prj).
      Das ist ne Demo mit Hinweisen und zeigt wie die Ausgabe auf die verschiedenen Display erfolgt.
      Das erkennt man in der Main.bas ganz gut (Hauptschleife).

      Die Initialisierung (SPI und Display) wird automatisch vorgenommen in den Modulen.
      SPI muss zuerst vollständig initialisiert sein, bevor man die Display's initialisiert.
      Heißt also, einfach zuerst SPI.inc und danach Display.inc einbinden.

      So wie in der Demo.

      Eine Rückmeldung, obs klappt wäre nett.

      Hier die Zip.

      Gruß Mitch
      Files
    • Tja, was soll ich sagen... a_57_04ef5ee8 a_14_3ef964b0 Ich ziehe mein Kapperl

      Also, ein Port musste ich ändern.
      Die Einstellungen Kontrast und Cursor blinken habe ich noch eingestellt.
      Alles problemlos.
      Dein Demo-Programm funktioniert auf Anhieb und problemlos.
      Ist schon eine feine Sache, wie das so funktioniert.
      Werde das weiter testen und bei mir in den Code einbauen.

      Gruß
      Dagobert
    • So, habe auch mit 2 Displays getestet, läuft ohne Probleme.
      Läuft so ca. 6 Stunden permanent durch.
      Auf einem Display Spannung anzeigen, auf dem anderen Temperatur anzeigen, kein Problem.
      Man muss halt darauf achten, die CS-Leitungen richtig zu setzen.
      Der Aufwand in der Hauptschleife für die Anzeigen-Ausgabe reduziert sich eben auf die LCD-Befehle, das ist schon komfortabel.
      Danke nochmals.

      Gruß
      Dago
    • @Dago1

      Hallo und danke für deine erweiterte Rückmeldung.
      Ich denke das wird nun auch mit den 4 Displays klappen.
      Theoretisch kannst du so viele hin hängen, wie du Pins hast.

      Aber wie du festgestellt hast, ist es wichtig, dass nur ein Display per CS-Leitung selektiert wird.

      Um das im Hauptprogramm zu vereinfachen könnte man eine Routine schreiben, wie

      BASCOM Source Code

      1. Sub Select_Display(Byval DisplayNr as Byte)
      2. Select Case DisplayNr
      3. Case 0 ' 1. Display
      4. Call Display_Deselect() ' letztes Display deselectieren
      5. Reset Display_CS_0
      6. Case 1 ' 2. Display
      7. Call Display_Deselect() ' letztes Display deselectieren
      8. Reset Display_CS_1
      9. ' ...
      10. End Select
      11. ' Display-Nr zwischenspeichern in Variable für Aufruf Deselect_Display()
      12. End Sub
      Display All


      und darin per select case den entsprechenden CS setzen.

      Eine weitere Routine, z.B.

      BASCOM Source Code

      1. Sub Deselect_Display()
      2. End Sub

      würde den letzten CS wieder aufheben.
      Das würde im Hauptprogramm nochmal viel übersichtlicher und eleganter zugleich.

      BASCOM Source Code: Beispiel

      1. ' Hauptschleife
      2. Do
      3. Call Select_Display(0)
      4. Lcd "Displ. 1"
      5. Call Select_Display(1)
      6. Lcd "Displ. 1"
      7. ' usw.
      8. Call Deselect_Display()
      9. Loop
      Display All