Kleines Problem mit meinem Bascom-Code zum Multiplexen von Dot-Matrix-Displays

  • Moin!


    Habe jetzt nach einigen Monaten Pause einige LED-Displays (2 x 40x16, untereinander) aus'm Keller gekramt.


    Die Ansteuerung ist eigentlich recht simpel und orientiert sich an dem Prinzip, einfach die gewünschte Farbe ins Array zu schreiben und das Array dann im Timer auszulesen und an die HC595 Schieberegister zu geben. Als letztes dann noch die Zeile hinterher und gut ist.


    Funktioniert auch alles prima, nur die letzte Zeile, also in meinem Fall die 16. ist immer wesentlich heller als die anderen. Ich denke, dass wird 'nen Timingproblem beim Umschalten der Zeile sein, aber ich bin zu dämlich, dass zu fixen.


    Vielleicht kann sich ja mal einer den Code der Timerroutine ansehen und mir weiterhelfen. Wiegesagt, er sollte einfach zu verstehen sein, sonst fragen.


    Danke und Gruß


    Jan



  • So, hab das jetzt gefixed, allerdings etwas unschön.


    Nutze jetzt zusätzlich den Output Enable des 4094 bzw. den G des HC595. Damit schalte ich die LEDs kurz dunkel. Dadurch ist die letzte Zeile jetzt genauso hell wie die anderen. Warum das nur bei der letzten Zeile passiert, weiß ich noch nicht, aber das wird schon.


    Mit der Routine bekomme ich jetzt eine 64 x 32 BiColor-LED-Matrix angesteuert. Ich wollte damit ne 64x64 ansteuern, aber die Display's sind noch nicht da. Das wird wohl das maximum sein, was der AVR mit 20MHz und mit Bascom hergibt.


    Hat jemand bereits ein Protokoll in Bascom entwickelt, um den AVR entsprechend anzusteuern? Mir schwebt da so I²C vor, allerdings hab ich noch nie 'nen Slave geproggt. Mit SPI hab ich etwas rumprobiert, aber mitunter fehlerhafte Übertragungen erhalten. Ich stelle mir vor, die AVR's damit entsprechend untereinander zu vernetzen, damit ich auch größere Panels bauen kann. Der Host-AVR gibt dann nur entsprechend die LED-Koordinate (x,y) und die Farbe vor und gut ist. Also brauche ich ja wohl 3 Bytes, die ich an das Display senden muss, einmal die x-Koordinate, dann die y-Koordinate und letztlich die Farbe. Ist sowas in I²C machbar und vorallem, ist es auch performant? Hat jemand von Euch sowas schonmal in Bascom gemacht?


    Gruß


    Jan

  • Hast du bei der letzten Zeile vieleicht einen falschen Widerstand am Transistor, ich denke mal du hast gemultiplext.


    #



    Gruß Matze1992

    :led: 0815 - Mit der Lizenz zum Löten :led:
    Wer Rechtschreibfehler findet darf sie behalten oder in Ebay verkaufen.

  • Also ich würde das ungefähr so angehen:
    Der "Master" hat ausreichend RAM, um das gesamte Bild im Speicher zu halten. Den wiederum befüllst du über den PC per RS232 oder sowas...
    Die "Slaves" bekommen/benutzen dann jeweils nur die Daten, die du ihnen sendest und refreshen ihr Segment selbsttätig - dadurch hat der Master genügend Ruhepausen für Kommunikation/Nachladen etc...


    Bei der Verkabelung der Slaves hast du zwei Möglichkeiten:
    1 - Feste Slave-Adressen anhand derer die Slaves sich ihre Datenpakete aus einem großen Strom rausfischen
    2 - Ein Enable-Pin pro Slave - nur wenn der aktiv ist wird auch gelauscht


    Für größere Distanzen solltest du einen Treiberbaustein nutzen - da gibts eine riesen Auswahl - je nach Geschwindigkeit, Leitungslänge und verwendeter Pinzahl.


    Softwareseitig kannst du dann entsprechend darauf aufsetzen - einen Parser (also Protokoll-Interpreter) brauchst du so oder so.
    Per UART würde das dann z.b. so aussehen:
    - Master sendet ein Startbyte um einen einzelnen Slave anzusprechen
    - Alle Slaves empfangen das Byte, aber nur einer reagiert
    - Dann kommt der Segmentinhalt - als die Bildinformationen
    - ggfs. funkt der Slave ein ACK oder sowas. Oder du baust direkt ne CRC mit ein ;)


    UART hätte den Vorteil, dass du in Bascom direkt die Puffer und UART-Interrupts, etc. nutzen kannst.


    Sämtliche anderen Protokolle kann man aber auch easy in einen Interrupt verfrachten - entweder checkt ein Timer regelmäßig einen Pin, oder du klemmst es direkt an nen INTx Pin, oder du nutzt einen Tiny2313 mit PinChangeInterrupt oder, oder, oder...


    Du merkst schon: Der Bus selber ist nicht das Problem, sondern die Auswertung :D


    Die Lösung ist ein Mittel aus Größe/Können des AVRs und dem Preis für zusätzliche Komponenten der Slaves.
    Mit zwei Schieberegistern und einem 8-Pin-Tiny könnte man das machen - oder aber mit einem Tiny2313 und einem SR.
    Oder auch ganz ohne schlaue Slaves - nur mit dedizierten Matrix-Treibern...
    Von Maxim gibts glaubich sogar welche, die 8x8 R/G/Y Segmente selbstständig refreshen können - ob die aber billiger sind als ein Tiny2313 wage ich zu bezweifeln...


    64x64 Pixel sind übrigens nicht wirklich "viel" - nur, wenn man die alle einzeln durchrattern läßt - dann sinkt halt der Dutycycle auf 1/64 - was doof ist.
    Der AVR langweilt sich bei 20MHz trotzdem zu Tode - nimm doch mal alle waitsms raus und lass den 1000x mal das Display refreshen - das kann nicht sehr lange dauern...
    Wichtig ist, dass du eine Art Frambuffer benutzt: das Bild wird vollständig im RAM gepuffert und kann flott angezeigt werden - einfach Array-Element x an Pin y und fertig.
    Änderungen am Buffer kommen dagegen weniger häufig vor - wenn wir mal von 25 fps ausgehen nur alle 1/25 Sekunde - bei 20 MHz sind das immer noch 800.000 Clock-Cycles.


    Um Flackern von vornherein zu vermeiden, solltest du zudem die Anzeige in einen Timer-Interrupt legen. Dann hast du zumindest eine feste Refresh-Rate und wenn der AVR anderweitig beschäftigt ist, bricht die Frame-Rate nicht ein.


    In der ISR darfst du natürlich nix anderes machen, als Spalte ändern, neue Infos in die Reihen und vielleicht ein Flag setzen.


    Zu der letzten Zeile nochmal kurz:
    Setze deine Refresh-Rate mal runter, so dass du mitzählen kannst - das hat mir beim Debuggen immer sehr geholfen.
    Es reicht ja schon, dass er zwischen letzter und erster Zeile etwas macht, dass ein paar Cycles mehr braucht als bei den Reihen vorher - dann leuchtet die eben für einen Tick länger und das summiert sich bei 20 MHz natürlich direkt stark.

  • Wow, was für ne Menge an Input :)


    An den UART habe ich jetzt noch gar nicht gedacht, bin immer davon ausgegangen, dass er zu langsam wäre.


    Prinzipiell hast Du recht, dass ich auch nen Tiny als Slave nehmen könnte. Aber wenn ich Dich richtig verstehe, steuert der dann nur nen 8x8 Display an. Bei mir geht es aber darum, dass ich fertige 16 x 64 bzw. 32 x 64 LED-Panels habe, die alle an nem HC595 hängen und nen HC238 als Zeilentreiber haben. Somit muss ein AVR mindestens mal 16 x 64 LED's treiben.


    Der Timer-Interrupt kommt bei mir aber schon ganz schön ins schwitzen, weil er ja das gesamte array durchlaufen und ausgeben muss. Und dass ist bei 64 x 32 immerhin 2.048 Bytes groß. Oder mache ich grundsätzlich was verkehrt? Den Code von oben kannst Du ja mal in Bascom pasten und den Einzug glattziehen, dann hast Du exakt meine gegenwärtige Timer-Routine. Da es derzeit 2 Displays sind, gibt es je einmal DisplayXred und DisplayXgreen, also jeweils pro Display und Farbe einen SerialIn. Das spart mir etwas Zeit. Würde ich sie alle hintereinander hängen, schafft es der ISR nicht mehr.


    Matze1992: Die Displays sind fix und fertig aufgebaut und komplett identisch, daran liegt es net. Aber nach der letzten Zeile setzt er ja den Counter quasi wieder zurück, ist also mit der Schleife fertig, und das dauert n Tick länger, daran wird's wohl liegen.

  • Und wenn du den Counter noch eins weiter zählen lassen würdest, also praktisch zu einer Zeile die gar nicht existiert? Oder würde es dann flackern?






    Gruß Matze1992

    :led: 0815 - Mit der Lizenz zum Löten :led:
    Wer Rechtschreibfehler findet darf sie behalten oder in Ebay verkaufen.

  • Hmm, peil ich net. Mal ma auf, wie Du das meinst :)


    Annahme ist, dass Du die Daten für die Led's in nem Pixel-Array hast.


    Ich gehe led für led durch, lese die Pixeldaten aus und takte das entsprechende SR mit ner 1 oder eben ner 0. Dann Zeile raus. Dann wieder von vorn, setze aber den Index quasi eine Zeile weiter, bei 40 LEDs pro Zeile also index = index + 40 usw...

  • Oder würdest Du das gar nicht mit nem Pixel-Array machen? Ist an sich ne charmante Sache und mit ner kleinen Umrechen-Funktion kann man easy jede Led per Koordinate ansabbeln. Und da das Array n byte gross ist, kann ich "theoretisch" auch bis zu 255 Farben mitgeben. Bei mir ist eben 1 = rot, 2 = grün und 3 = gelb.


    Wie Du ja am Code siehst, schreibe ich jede Zeile von rechts nach links, also die rechte obere Led ist die erste und die linke untere ist die 1.024 bzw. 2.048te.


    Wenn Du von Spalte laden sprichst, gehe ich davon aus, dass Du mit Spalte 1 quasi die rechte obere LED bis zur rechten unteren LED meinst?! Also Du befüllst sie nicht horizontal, sondern vertikal?

  • Dein Problem ist halt, dass du den Inhalt zur Laufzeit neu "bestimmst" bzw. auswertest - und das in einer ISR.
    Das sollte man halt deutlich "eleganter" machen - schon alleine, dass jede LED ein einzelnes Byte in einem Riesen Array hat macht keinen Sinn.
    Ein Byte kann 256 Zustände beschreiben - davon nutzt du exakt 4 - R/G/Y/AUS.
    Das große Array braucht außerdem schon einen Adressraum von nem WORD - das benötigt dann doppelt soviel CPU-Zeit usw...
    Mach dir lieber vier 40-Byte-Arrays - je eines für Rot und eines für Grün pro Displayhälfte.


    Und keine ewigen Abfragen in ner ISR, das kostet Zeit ohne Ende - nur Speicher auslesen, Bytes rausclocken, nächste Zeile.


    Haste mal nen Schaltplan für das Ding? Wo ist was wie angeschlossen?