Also hier habe ich mal den Schaltplan, hoffe er ist nicht allzu chaotisch. Dass an PortC nichts angeschlossen ist, liegt an der Pinbeschränkung in meinem Target!, ist ja aber genau das Selbe wie obendrüber. Was Noch fehlt ist hier lediglich der 100n Kondi am 74HC237 zwischen GND und VCC. Hatte bei meinen Programmierversuchen diese beiden ICs auch garnicht in ihren Sockeln, nur den Mega. Kann das ursächlich sein? Ist an der Außenbeschaltung was bedenklich in Hinblick auf ISP? Würde mich über Hinweise freuen.
Viele Grüße und schöne Ostern:)
ben
Projekt: RGB Matrix 8x8
-
-
Haben die Basisvorwiderstände wirklich nur 62 Ohm...? - da kann's schon ein Problem geben, dass hier dann der IPS beeinflusst wird...
ich würde die entweder mal größer machen (wenn der Strom dann noch reicht, LED-Strom/Verstärkungsfaktor), oder da (so empfiehlt Atmel das auch) Steckbrücken rein, die Du dann öffnest, wenn Du den ISP benutzt...
-
Tatsache!
Habe mal die Widerstände ausgelötet, nachdem ich überlegt hab den Mega einfach immer ausserhalb der Schaltung zu flashen, das dann aber wieder verworfen wegen des Quarzes der genutzt werden soll. Widerstände vergrößern wollte ich ungern, da ich dann erstens gleich 24 hätte tauschen können wegen gleicher Helligkeit, außerdem erinnere ich mich dass es schon recht knapp war mit dem Strom...
Und tatsächlich: ohne die gings beim ersten Anlauf. Habe jetzt nur den Resetwiderstand und die Portpinwiderstände (alle 3) steckbar, kann aber sagen dass es nicht am Resetwiderstand (14,7k) lag. Also ist mindestens einer der anderen Schuld. Was mich nur wundert ist, dass die Außenbeschaltung des Ports eigentlich nicht anders ist als bei der ersten Version wenn mich nicht alles täuscht, also 62Ohm -> Transistor mit Widerstand für LED. Lediglich die Leiterbahnlängen sind ein bisschen kürzer. Mega ist der Selbe, Sockel ist ein anderer. Kann ich davon ausgehen dass es in der alten Version immer grade so noch ging, und hier wegen den kürzeren Wege eben grad nicht mehr? Kann mir das jemand erklären? Würde mich interessieren.
So dann da dies Problem gelöst ist vielen vielen Dank, es kommen sicher hundert neue. Danke für die Hilfe!
Viele Grüße,
ben. -
Hallo!
Nach "ausgiebigem" Testen der Hardware kann ich nun mit Freude verkünden dass diese soweit funktioniert. Jetzt habe ich mich mal an die SW gewagt. Fertig ist noch nichts, nur der Plan in meinem Kopf. Glaube auch, dass wenn das irgendwann mal fertig werden sollte, ein ganz schöner Brocken gewesen sein wird...
Was ich habe ist eine Matrix die Spaltenweise gemultiplext werden kann, alle Farben auf einmal. Jede Spalte kann also 1/8 der Zeit aktiv sein, wobei die Zeilen den RGB Anoden entsprechen, und die Spalte jeweils zusammengefasst die Kathoden der betr. Spalte.Was ich gerne schaffen möchte wenns fertig sein sollte ist eine Matrix die vorerst gespeicherte Animationen abspielen kann, mit verschiedenen Helligkeiten (und somit Farben/Pixel). Dazu brauche ich wie ich von Pesi erfahren habe die Funktion des Z-Pointer. Komplette Zukunftsmusik ist vermutlich dann noch die Verwirklichung vom DMX Empfang (somit die Nutzung der hier geläufigen Matrixsoftwares), auch deswegen hab ich ja alles nochmal neu gebaut.
Habe mir die Möglichkeit Bilder zu speichern mit dem Z-Pointer angesehen und denke ich soweit verstanden. Wie so eine PWM funktioniert weiß ich vom Prinzip her auch, habe mir einiges dazu durchgelesen, als denke ich für mich passendstes Beispiel das AVR Tutorial zur Software-PWM auserkoren. Das macht ja schon so ziemlich genau was ich will, also verschiedene Helligkeiten an verschiedenen Pins. Müsste ich halt noch entsprechend erweitern.
Mein Problem ist jetzt einwenig wie ich diese doch (für mich) recht komplexen Softwareschritte in ein ganzes Programm stecke, so dass alles ineinander schlüssig funktionert. Da habe ich vermutlich einfach zu wenig Erfahrung.
Vorgestellt hab ich mir die Funktionsweise so: Es gibt einen großen Hauptteil im Programm der das Multiplexing erledigt, in etwa so:Code
Alles anzeigenSpalte 1: Spalte 8 ausschalten Zeilenwerte zurücksetzen Zeilen für RGB aktivieren Spalte 1 am 74HC237 aktivieren Spalte 2: Spalte 1 ausschalten Zeilenwerte zurücksetzen Zeilen für RGB aktivieren Spalte 2 am 74HC237 aktivieren . . . Spalte 8: Spalte 7 ausschalten Zeilen für RGB aktivieren Spalte 8 am 74HC237 aktivieren
Habe mir auch Pesis "Schneeflocke" schon desöfteren zu Gemüt geführt, leider verstehe ich dadurch nicht unbedingt mehr, wie ich die Software zusammenbauen kann. Das einleuchtendste ist noch die Geschichte mit dem Z-Pointer.
In der Hauptschleife wie ich sie oben beschrieben habe, müsste ja dann irgendwie die PWM für "Zeilen für RGB aktivieren" integriert werden, also für den Fall dass die LED gedimmt werden sollen. Wie kriege ich Diese Hauptschleife, die Daten des Z-Pointer und die PWM zusammen? Würde das nach dem Prinzip überhaupt irgendwie hinzubekommen sein?
Habt ihr einen Rat für mich? Ist das schaffbar für einen Laien? Oder soll ichs lieber dabei belassen, und nur die SW ohne PWM geschweige denn DMX versuchen?
Bin echt in einer Zwickmühle, hab jetzt schon so viel Arbeit (und ja auch bisschen Geld) reingesteckt, und hätte gerne dass es dann auch perfekt funktioniert, nur wenn ich dann mal wieder davor sitz, so wie jetzt, dann ists einfach ein riesen Berg an Information der irgendwie zusammengebracht werden will...mh. Habt ihr einen Rat?Viele Grüße
ben -
In der Hauptschleife wie ich sie oben beschrieben habe, müsste ja dann irgendwie die PWM für "Zeilen für RGB aktivieren" integriert werden, also für den Fall dass die LED gedimmt werden sollen.
Nee, genau andersrum - das ganze PWM/Multiplexing-Gedöns kommt in einen Timerinterrupt, wird also reglemäßig aufgerufen, unabhängig davon, was die SW sonst so macht...
dsa läuft also "automatisch", "immer nebenbei", liest die Werte aus dem RAM und steuert die LEDs entsprechend an.
in der Hauptschleife kannst Du dann machen was Du willst, Bilder per Algorithmus erzeugen oder aus dem Flash lesen, oder per DMX empfangen - die Bilder schreibst Du einfach in den Ausgabepuffer (also den RAM-Bereich, wo die Multiplex-ISR rausliest), dann werden die angezeigt.
Fang am Besten klein an, mach' erst mal ne Multiplex-Routine ohne PWM - weiter nix, im RAM sind nach dem Rest zufällige Werte, das gibt bunte Farben.
also Hautpschleife nur
main: rjmp main
und die Multiplex-Routine - wenn dann Deine Matrix irgendwelche Farben anzeigt, statisch, ohne dass sich was ändert, und immer die selben nach jedem Reset, dann funktioniert die schon mal - dann kannst Du ja in der Hauptschleife (bzw. das kannst Du auch vorher schon machen) einfach nur bestimmte Farben in den Ausgabepuffer schreiben, z.B. alles blau oder alles rot o.ä.
und dann halt Schritt für Schritt erweitern...
-
Hallo!
Danke für die Richtigstellung und Erklärung! Habe mich nun nochmal rangesetzt und konnte einen kleinen Teilerfolg verbuchen. Habe jetzt also das Programm was ich bisher hatte, ohne Timer, an die neue Hardware angepasst (hauptsächlich den 74HC, und das gleichzeitige Farbmultiplexing) und dann versucht in einen Timer zu packen, mit Hilfe des AVR-Tutorial "Timer". Es scheint auch teilweise zu funktionieren. Jedenfalls wird der Overflow mindestens einmal ausgelöst.
Ich wollte zuerst einmal die Matrix einfarbig komplett leuchten lassen. Dazu folgendes Programm, noch ohne Bilder im Speicher oder ähnliches, nur das Multiplexing.Code
Alles anzeigen.include "m16def.inc" .def vollregister=R16 .def nullregister=R17 .def arbeitsregister=R18 .def rot=R19 .def gruen=R20 .def blau=R21 .org 0x0000 rjmp main ; Reset Handler .org OVF0addr rjmp timer0_overflow ; Timer Overflow Handler main: ldi vollregister, 0xFF ldi nullregister, 0x00 out DDRA, vollregister ; Ports als Ausgänge Deklarieren out DDRB, vollregister out DDRC, vollregister out DDRD, vollregister out PortA, vollregister ; Alle Portpins High, damit LED sicher aus sind out PortB, vollregister out PortC, vollregister out PortD, vollregister ldi arbeitsregister, HIGH(RAMEND) ; Stackpointer initialisieren out SPH, arbeitsregister ldi arbeitsregister, LOW(RAMEND) out SPL, arbeitsregister ldi rot, 0xFF ; Werte für die Zeilen laden ldi gruen, 0xFF ; kommen später aus dem Speicher?! ldi blau, 0x00 ldi arbeitsregister, (1<<CS00) ; CS00 setzen: Teiler 1 out TCCR0, arbeitsregister ldi arbeitsregister, (1<<CS01) out TCCR0, arbeitsregister ; CS01 setzen: Teiler 64?! ldi arbeitsregister, (1<<TOIE0) ; TOIE0: Interrupt bei Timer Overflow out TIMSK, arbeitsregister sei loop: rjmp loop timer0_overflow: //Spalte1: ldi arbeitsregister, 0b0000010 ; Werte für 74HC laden out PortA, gruen out PortB, rot out PortC, blau out PortD, arbeitsregister ; Spalte 1 am 74HC aktivieren //Spalte2: ldi arbeitsregister, 0b01000010 out PortA, gruen out PortB, rot out PortC, blau out PortD, arbeitsregister . . . //Spalte8: ldi arbeitsregister, 0b01110010 out PortA, gruen out PortB, rot out PortC, blau out PortD, arbeitsregister reti
Habe das mal testweise geflasht, und siehe da, das Display macht sogar was: Die erste Spalte leuchtet blau, in voller Helligkeit, so wie gewünscht. Die anderen glimmen aber nur ganz leicht. Woran kann das liegen? Habe den Code mehrmals durchgesehen, aber nichts erkannt. Habe ich irgendwo Tomaten auf den Augen? Weiterhin war ich mir nicht ganz sicher bei der Prescalereinstellung. Habe im DB des Mega16 geschaut, da aber nichts wirklich hilfreiches gefunden (S81) jedenfalls verstehe ich es nicht umzusetzen. Habe es jetzt vom Tutorial abgeleitet, anhand der Tabelle für den Mega8. Passt das so? Woran kann das verschiedentliche leuchten liegen?
Ich hoffe der Code ist einigermaßen durchschaubar und nicht komplett am Prinzip vorbei. Würde mich freuen, wenn mal jemand drüber sieht und mir evtl. einen Tip geben könnte.
lg, ben:)
Edit: nach nochmaligem Überlegen: liegt es evtl. tatsächlich dran, dass die Prescaler Einstellung so Murks ist, und er immer noch bei 1 steht? Der Mega läuft momentan auf internen 8MHz. Dann könnte ich mir vorstellen dass sowas passiert.? -
Hallo!
Also hab eben nochmal etwas rumprobiert mit dem Vorteiler, und die oben beschriebene Erscheinung hängt tatsächlich damit zusammen. Folgende Veränderungen konnte ich feststellen:
Prescaler 1 : Spalte1-100%, Rest ca. 40%
Prescaler 8 : Spalte1-100%, Rest ca. 5%
Prescaler 64 : Spalte1-100%, Rest ca. 5% aber flimmernd
Prescaler256: Spalte1-100%, Rest ca. 5%, flackernd objektiv langsamer als bei 64
Bei 1024 dann wie gehabt, aber das flackern ist fast nicht mehr zu erkennen.Was mich aber irritiert ist, dass die Takteinstellungen des Käfers komplett egal sind. Habe es jeweils mit dem internen Oszillator auf 1MHz, 4MHz, und 8MHz getestet. Ich vermute dass das, was im Interrupt steht einfach zu lang ist. Kann das sein? Der µC schafft es evtl. nicht zwischen 2 Interrupts die Sachen komplett abzuarbeiten? Dann würde es doch aber genau umgekehrt sein, also je kleiner der Prescaler, desto dunkler? Ich kanns nicht ganz nachvollziehen. Kann mir da jemand einen Denkanstoß verpassen?
Lg, ben:) -
Überleg' Dir doch einfach mal, was da passiert (das ist das wichtigste beim Programmieren, verstehen, was der Code eigentlich macht):
Die ISR wird regelmäßig aufgerufen - da macht sie "in einem Rustch" alle Spalten durch - es kommt also jede nur ein paar Takte dran.
bei der letzten Spalte bleibt es dann, bis die ISR das nächste mal aufgerufen wird - die ist also wesentlich länger an als alle anderen, damit auch deutlich heller...
so geht das also nicht - Du must bei jedem Aufruf die Spalte eins weiter zählen, damit alle gleich lang an sind.
also noch ein Register als Zähler für die Spalte - das wird bei jedem ISR-Aufruf erst mal hoch gezählt - ist es 8, dann wieder auf 0 setzen. Dann alle Zeilen (also Port A-C) aus, die Zeilen-Daten für die neue Spalte aus dem RAM holen (*da*, in der ISR, *nicht* in der Hauptschleife) und an PortA-C ausgeben, dann die neue Spalte aktivieren - welche, steht ja eben in dem Zähler.
nicht falsch verstehen, aber was soll das mit dem "nullregister" und "vollregister", wo ist der Quatsch denn her...? - das ist völlige Verschwendung, zwei wertvolle Register die ganze Zeit nur mit 2 festen Werten zu belegen...
normal reserviert man sich ne Anzahl Arbeitsregister (bei mir heissen die z.B. temp0, temp1, ...), und wenn man nun z.B. an nen Port 0x00 ausgeben will, dann macht man halt
ganz wichtig: in ner ISR immer die verwendeten Register sichern, sonst kann's Dir in der Hauptschleife was "verhunzen", wenn in der ISR an nem Register was geändert wird, das Du in der Hauptschleife auch brauchst - inkl. Statusregister!
also, Beispiel, Du benutzt in der ISR die Register temp0 und temp1, dann beginnt die ISR mit:
und endet mitRegister, die nur in der Routine verwendet werden, sozusagen "reserviert" sind (wie hier dann z.B. der Zähler für die Spalte), brauchst Du natürlich nicht sichern.
-
Hallo!
Nach nun wieder einiger vergangener Zeit und einigen Stunden an überlegen und Tüfteln und vielen Tagen in der Ecke liegen, wel man ja auch andere Sachen machen muss...bin ich nun ein wenig weiter und präsentiere stolz meinen Fortschritt...
Das zuletz beschriebene Problem mit der einen hellen und den vielen flackernden Zeilen lag tatsächlich, wie ich es mir fast dachte und was Pesi ja bestätigte an der Art wie die Software arbeitete. Habe das Problem nun behoben und das Lesen eines Bildes aus dem Speicher eingebaut. Momentan sieht es also so aus:Code
Alles anzeigen/* * RGBMatrix_74_HC.asm * * Created: 12.04.2012 15:47:52 * Author: Ben */ .include "m16def.inc" .def temp0=R16 .def temp1=R17 .def temp2=R18 .def rot=R19 .def gruen=R20 .def blau=R21 .def ccount=R22 .def warten=R23 .org 0x0000 rjmp main ; Reset Handler .org OVF0addr rjmp timer0_overflow ; Timer Overflow Handler main: ldi temp0, 0xFF out DDRA, temp0 ; Ports als Ausgänge Deklarieren out DDRB, temp0 out DDRC, temp0 out DDRD, temp0 out PortA, temp0 ; Alle Portpins High, damit LED sicher aus sind out PortB, temp0 out PortC, temp0 out PortD, temp0 ldi ccount, 0xFF ; Spaltenzähler nullen ; Stackpointer initialisieren ldi temp0, HIGH(RAMEND) out SPH, temp0 ldi temp0, LOW(RAMEND) out SPL, temp0 ldi temp0, 0b00000001 ; Prescaler 1 out TCCR0, temp0 ldi temp0, (1<<TOIE0) ; TOIE0: Interrupt bei Timer Overflow out TIMSK, temp0 sei loop: rjmp loop timer0_overflow: push ZH ; Register sichern push ZL push R0 ldi ZL, LOW(daten*2) //Zeilendaten in Z-Pointer laden ldi ZH, HIGH(daten*2) //lpm Ausgabe: inc ccount // Spaltenzähler erhöhen cpi ccount, 1 // Vergleich mit 1 breq Spalte1 // wenn 1 dann Spalte1 aufrufen cpi ccount, 2 // analog mit den anderen Spalten . . . cpi ccount, 8 breq Spalte8 clr ccount // Spaltenzähler zurücksetzen reti pop R0 // Register zurück pop ZL pop ZH Spalte1: ldi temp1, 0b0000010 ; Werte für 74HC laden lpm gruen, Z+ out PortA, gruen //out PortB, rot //out PortC, blau out PortD, temp1 ; Spalte 1 am 74HC aktivieren ldi warten, 0xFF // Warteschleife für Zeilentransistoren warte1: dec warten brne warte1 rjmp Ausgabe . . . Spalte8: ldi temp1, 0b01110010 lpm gruen, Z+ out PortA, gruen //out PortB, rot //out PortC, blau out PortD, temp1 ldi warten, 0xFF warte8: dec warten brne warte8 rjmp Ausgabe daten: .db 0b11100111,0b11100111,0b11100111,0b00011000,0b00011000,0b11100111,0b11100111,0b11100111
Also das Ganze funktioniert soweit, allerdings weiß ich nicht, inwieweit man hier noch optimieren könnte. Da hab ich einfach nicht genug Erfahrung. Die Warteschleife nach jeder Zeilenausgabe muss sein, da die Transistoren sonst nicht nachkommen. Geht auch nicht kürzer, das hab ich versucht.
Habe das oben alles nur mit einer Farbe gemacht, um erstmal zu sehen ob es so überhaupt gehen würde. Das geht ja dann für die anderen analog.
Was ich mich jetzt noch Frage ist, wie ich es hinbekomme mehrere Bilder nacheinander/in versch. Farben parallel anzuzeigen. Ich müsste ja eine neue Speicheradresse anlegen, also Beispielsweise Bild1, Bild2, usw. und die dann mit Daten füllen, wie ich es bei "daten" oben schon gemacht hab. Wie kriegt die ISR jetzt mit, dass sie nicht Daten, sondern Bild1/2/... ausgeben soll? Habe mir Pesis "Schneeflocke" schon oft angesehen, ist ja das Prinzip, steige aber zum Großteil noch nicht durch.
Wenn ich das hinbekommen haben sollte würde ich mich gerne noch der PWM widmen, so dass ich dann theoretisch beliebige Farben mischen könnte. Sollte dass dann tatsächlich geschafft sein, wäre für mich DMX Empfang der letzte Wunsch.Ich würde mich freuen wenn mir jemand einen Tip geben würde, wie ich das mit den verschiedenen Bildern hinbekommen kann.
Werde mir das Programm von Pesi auch wieder und wieder anschauen, das hilft tatsächlich. Wieder und wieder, wieder und wieder, ...
Langsam nimmt es ja Form an, das hätte ich ohne das Forum wohl nie geschafft.:) Danke an dieser Stelle! -
Hallo miteinander!
Habe mich in der inzwischen vergangenen Zeit recht lange und oft mit der Software rumgeschlagen, so richtig vorwärts gehts aber leider nicht. Optimiert habe ich die Warteschleife nach jeder Zeilenausgabe, indem ich sie in ein Macro gepackt habe. Das wars aber im Groben auch schon. Ich hänge im Prinzip momentan an 2 Problemen, die sich vermutlich gegenseitig bedingen bzw. den gleichen Grund haben, nämlich meine nur rudimentären Kenntnisse von ASM. Ich hoffe ihr könnt mir hier helfen.Das erste Problem ist, wie ich es schaffe, die Bilddaten für R/G/B jeweils zusammenhängend im Speicher ablegen zu können, und dann natürlich auch wieder auszulesen. Nach der bisherigen Software (s. letzter Beitrag) müsste ich die Daten nämlich pro Zeile im Speicher ablegen, also nach diesem Schema: Zeile1_R, Zeile2_G, Zeile3_B, usw.
Das wird schon bei einem Bild in RGB ein rechtes Chaos, wenn man das händisch, oder auch vom Matrixeditor erstellt, einfügen will. Also habe ich überlegt wie man das umgehen kann. Meine erste Idee war, dass ich ja die Multiplexroutine umstricken könnte, so dass immer erst Zeile 1-8 jeder Farbe ausgelesen und angezeigt werden, dann 1-8 der nächsten Farbe, usw, anstelle der jetztigen Routine, in der ja wie oben genannt erst jede erste, dann jede zweite Zeile gelesen und angezeigt wird. Denn dann könnte ich einfach mit dem Z-Pointer und lpm farbregister, Z+ nacheinander auslesen.
Vom Prinzip her ging das gut, jedenfalls mit 2 Farben. (das hatte ich zum Testen, ob es evtl. flackert o.ä.) Problematisch finde ich aber den ellenlangen und somit Speicherfressenden Quelltext, außerdem funktioniert das bei drei Farben nicht mehr richtig, da ab dem Befehl "cpi ccount, 17" syntax error, unexpected INTEGER gemeldet wird. Bin mir auch relativ sicher, dass fähigere ASM Menschen hierbei die Hände über dem Kopf zusammenschlagen (nur der für die Ausgabe wichtige Teil, Rest bleibt ja wie oben). Die Zusätze R, G und B stehen jeweils für die Farbe...Code
Alles anzeigenAusgabe: inc ccount // Spaltenzähler erhöhen cpi ccount, 1 // Vergleich mit 1 breq Spalte1R // wenn 1 dann Spalte1 aufrufen cpi ccount, 2 // analog mit den anderen Spalten breq Spalte2R cpi ccount, 3 breq Spalte3R cpi ccount, 4 breq Spalte4R_sprung // ab hier meldet der Assembler schon relative branch out of reach, da der Code zwischen dieser Zeile und dem Label Spalte4R zu // lang ist. Das wird mit rjmp umgangen, weil dieser Befehl weiter springen kann [...] cpi ccount, 9 // das gleiche in Grün breq Spalte1G_sprung [...] breq Spalte8G_sprung cpi ccount 17 //und nochmal in Blau breq Spalte1B_sprung [...] breq Spalte8B_sprung clr ccount // Spaltenzähler zurücksetzen reti Spalte4R_sprung: //hier die o.g. Sprungmarken rjmp Spalte4R [...] rjmp Spalte8G .macro wartengeneral ldi warten, 0xFF // Warteschleife für Zeilentransistoren warte1: dec warten brne warte1 .endm pop R0 // Register zurück pop ZL pop ZH // und jetzt die eigentliche Ausgabe Spalte1R: ldi temp1, 0b0000010 ; Werte für 74HC laden lpm rot, Z+ out PortB, rot out PortD, temp1 ; Spalte 1 am 74HC aktivieren wartengeneral // Warteschleife für Zeilentransistoren rjmp Ausgabe [...] Spalte8B: ldi temp1, 0b01110010 lpm blau, Z+ out PortC, gruen out PortD, temp1 wartengeneral // Warteschleife für Zeilentransistoren rjmp Ausgabe
Wie eben schon erwähnt, ist das glaube ich das Beispiel, wie ich es nicht machen sollte. Habe den Code massiv gekürzt, damit es überhaupt zumutbar ist, erkennbar an den [...].
Das Problem der strukturierten Speichernutzung (also immer erst ein Bild in einer Farbe, dann die nächste, ...) konnte ich also damit nicht lösen. Ich vermute dass der Z-Pointer oder eine andere Funktion von ASM mir hier anderweitig helfen könnte. Leider hab ich nach stundenlangem Lesen immer noch keinen richtigen Durchblick. Rein vom Gefühl her würde ich die Bilddaten in den Speicher einfach unter verschiedenen Adressen (z.B. Bild_1R: .db[Bilddaten], Bild1_G: .db[Bilddaten], usw. im Speicher ablegen. Aber wie bringe ich dem µC dann bei, wann er welches Byte aus welcher Adresse holen soll? Geht das so überhaupt?Damit bin ich auch "schon" beim zweiten Problem, und beim Schreiben fällt mir auf, dass es genau auf das Selbe herausläuft. Ich möchte ja verschiedene Bilder anzeigen können, die aus dem Speicher kommen, nacheinander. Dann müsste ich halt nur noch Bild_1 in Bild2_... ändern, wenn das so geht wie ich mir das vorstelle.
Ich hoffe ich konnte mein Problem halbwegs verständlich erklären, und noch mehr hoffe ich, dass mir jemand dazu einen Tip/Link/Hinweis/Schlag auf den Hinterkopf in die richtige Richtung geben kann, das würde mich freuen.
Viele Grüße, ben. -
Habe nochmal die letzten Posts gelesen und insbesondere diesen Beitrag als schon wieder komplett vergessen erkannt:
Nee, genau andersrum - das ganze PWM/Multiplexing-Gedöns kommt in einen Timerinterrupt, wird also reglemäßig aufgerufen, unabhängig davon, was die SW sonst so macht...
dsa läuft also "automatisch", "immer nebenbei", liest die Werte aus dem RAM und steuert die LEDs entsprechend an.
in der Hauptschleife kannst Du dann machen was Du willst, Bilder per Algorithmus erzeugen oder aus dem Flash lesen, oder per DMX empfangen - die Bilder schreibst Du einfach in den Ausgabepuffer (also den RAM-Bereich, wo die Multiplex-ISR rausliest), dann werden die angezeigt.
Dabei ist das glaube ich elementar. Habe nun versucht das Programm dementsprechend zu gestalten, sprich "nur" die Multiplexroutine ist im Timerinterrupt, dort werden die in der Hauptschleife aus dem Speicher gelesenen Bilddaten übernommen. So ist theoretisch auch das Problem mit der Bildspeicherung pro Farbe gelöst, s. Code. Im Hauptprogramm wird momentan immer wieder eine Schleife durchlaufen, welche die Bilder aus dem Flash liest und in den SRAM schreibt, von wo aus sich die ISR sie dann holt. Das macht mit den drei Bildern wenig Sinn, aber für spätere Animationen/mehrere Bilder denke ich schon.
Der Part im Quelltext der die Bilder liest und umsetzt ist trotzdem noch recht lang, aber schon kürzer als bei der gestrigen Variante.
Problem ist aber, dass der Code nicht das macht was er soll. Momentan ist im Flash für jede Zeile jeder Farbe ein Byte mit dem Wert 0xFF, es dürfte also nichts leuchten. Das tut es aber trotzdem, und das recht durcheinander, ca. alle 0,5s ein neues "Bild".Offenbar funktioniert also bei der Übergabe Speicher/RAM/Routine irgendetwas nicht. Ich habe den Quelltext hoffentlich ausreichend kommentiert und hoffe, dass hier jemand einmal drüber schauen könnte, woran das liegen könnte. Bin schon recht erfreut dass es jetzt in allen Farben blinkt, meine erste Animation, hey!...
Code
Alles anzeigen.def temp0=R16 .def temp1=R17 .def temp2=R18 .def rot=R19 .def gruen=R20 .def blau=R21 .def ccount=R22 .def warten=R23 .org 0x0000 rjmp main //Reset Handler .org OVF0addr rjmp timer0_overflow //Timer Overflow Handler main: ldi temp0, 0xFF out DDRA, temp0 //Ports als Ausgänge Deklarieren out DDRB, temp0 out DDRC, temp0 out DDRD, temp0 out PortA, temp0 //Alle Portpins High, damit LED sicher aus sind out PortB, temp0 out PortC, temp0 out PortD, temp0 ldi ccount, 0xFF //Spaltenzähler nullen ldi temp0, HIGH(RAMEND) //Stackpointer initialisieren out SPH, temp0 ldi temp0, LOW(RAMEND) out SPL, temp0 ldi temp0, 0b00000001 // Prescaler 1 out TCCR0, temp0 ldi temp0, (1<<TOIE0) //TOIE0: Interrupt bei Timer Overflow out TIMSK, temp0 sei auslesen: //Bilddaten für rotes Standbild auslesen ldi ZL, LOW(Bild1_R*2) //dazu Z-Pointer an die entsprechende Adresse setzen ldi ZH, HIGH(Bild1_R*2) ld temp2, Z+ //temp2 mit dem ersten Byte des Bildes füllen sts Rot1, temp2 //Inhalt von temp2 in Rot1 im Ram schreiben ld temp2, Z+ //analog mit Rot2-Rot8 sts Rot2, temp2 [...] sts Rot8, temp2 ldi ZL, LOW(Bild1_G*2) //Bilddaten für grünes Standbild auslesen ldi ZH, HIGH(Bild1_G*2) //dazu Z-Pointer an die entsprechende Adresse setzen ld temp2, Z+ //temp2 mit dem ersten Byte des Bildes füllen sts Gruen1, temp2 //Inhalt von temp2 in Gruen1 im Ram schreiben ld temp2, Z+ //analog mit Gruen2-Gruen8 sts Gruen2, temp2 [...] sts Gruen8, temp2 ldi ZL, LOW(Bild1_B*2) //Bilddaten für blaues Standbild auslesen ldi ZH, HIGH(Bild1_B*2) //dazu Z-Pointer an die entsprechende Adresse setzen ld temp2, Z+ //temp2 mit dem ersten Byte des Bildes füllen sts Blau1, temp2 //Inhalt von temp2 in Blau1 im Ram schreiben ld temp2, Z+ //analog mit Blau2-Blau8 sts Blau2, temp2 [...] sts Blau8, temp2 rjmp auslesen //wieder von vorne timer0_overflow: push ZH //Register sichern push ZL push R0 .macro warteschleife //Warteschleifen für Multiplexroutine ldi warten, 0xFF //damit Transistoren hinterherkommen warteschleife: dec warten brne warteschleife .endm Ausgabe: //Routine zum Aufruf der einzelnen Anzeigelabels für die Zeilen inc ccount // Spaltenzähler erhöhen cpi ccount, 1 // Vergleich mit 1 breq Spalte1 // wenn 1 dann Spalte1 aufrufen cpi ccount, 2 // analog mit den anderen Spalten [...] breq Spalte5_sprung //ab hier wieder das Problem mit der Sprungweite cpi ccount, 6 breq Spalte6_sprung cpi ccount, 7 breq Spalte7_sprung cpi ccount, 8 breq Spalte8_sprung clr ccount // Spaltenzähler zurücksetzen reti Spalte5_sprung: rjmp Spalte5 Spalte6_sprung: rjmp Spalte6 Spalte7_sprung: rjmp Spalte7 Spalte8_sprung: rjmp Spalte8 pop R0 // Register zurück pop ZL pop ZH Spalte1: ldi temp1, 0b0000010 ; Werte für 74HC laden lds gruen, Gruen1 //Register gruen mit Gruen1 füllen out PortA, gruen //an PortA gruen ausgeben lds rot, Rot1 //Register rot mit Rot1 füllen out PortB, rot //an PortB rot ausgeben lds blau, Blau1 //Register blau mit Blau1 füllen out PortC, blau //an PortC blau ausgeben out PortD, temp1 ; Spalte 1 am 74HC aktivieren warteschleife // Warteschleife für Zeilentransistoren rjmp Ausgabe Spalte2: ldi temp1, 0b01000010 //analog zu Spalte1 [...] rjmp Ausgabe Bild1_R: .db 0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111 Bild1_G: .db 0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111 Bild1_B: .db 0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111,0b11111111 .DSEG //Speicherreservierung entsprechend der Farbzeilen im SRAM Rot1: .BYTE 1 Rot2: .BYTE 1 Rot3: .BYTE 1 Rot4: .BYTE 1 Rot5: .BYTE 1 Rot6: .BYTE 1 Rot7: .BYTE 1 Rot8: .BYTE 1 Gruen1: .BYTE 1 Gruen2: .BYTE 1 Gruen3: .BYTE 1 Gruen4: .BYTE 1 Gruen5: .BYTE 1 Gruen6: .BYTE 1 Gruen7: .BYTE 1 Gruen8: .BYTE 1 Blau1: .BYTE 1 Blau2: .BYTE 1 Blau3: .BYTE 1 Blau4: .BYTE 1 Blau5: .BYTE 1 Blau6: .BYTE 1 Blau7: .BYTE 1 Blau8: .BYTE 1
Habe an den sich wiederholenden Stellen gekürzt, der Übersicht halber. Ich würde mich wirklich freuen, wenn hier jemand einen Funke des Anstoßes parat hätte.
lg, benEDIT: Habe nochmal herumprobiert und das ganze Ausgelese aus dem Flash rausgelassen, etwa so:
Also einfach ein willkürliches Muster an alle 3 Farbports in den Ram geschrieben. Jetzt passiert was interessantes. Direkt nach dem Einschalten für ca 1/2s ist dieses dann auch zu sehen. Dann geht es im gleichen Takt (vielleicht sind es auch nur 0.25s oder irgendwas dazwischen, jedenfalls erkennbar) so weiter, dass immer 3-spaltenweise von links nach rechts irgendeine "wirre" Musterfolge (allerdings immer die gleiche) ausgegeben wird. Also vermute ich den Fehler irgendwo im Ablegen im Ram. Da bin ich allerdings ein wenig überfragt. Wo ist mein Fehler? ich hänge gleich noch ein Video an, was das Verhalten zeigt.
Edit: hier das Video, bei Sekunde 2 das anfängliche, korrekte Anzeigen, dann wieder das wirre Durchlaufen. Am Anfang sieht man das schonmal, da ich die Aufnahme gestartet hab als die Matrix an war.Externer Inhalt www.youtube.comInhalte von externen Seiten werden ohne Ihre Zustimmung nicht automatisch geladen und angezeigt.Durch die Aktivierung der externen Inhalte erklären Sie sich damit einverstanden, dass personenbezogene Daten an Drittplattformen übermittelt werden. Mehr Informationen dazu haben wir in unserer Datenschutzerklärung zur Verfügung gestellt.
Hoffe das ist irgendwie hilfreich.
lg, ben:) -
Hallo!
Habe noch ein wenig herumprobiert, mit der Schreiberei in den Ram. Habe das ganze vereinfacht, so dass nur noch eine Adresse im Ram pro Farbe genutzt wird, einfach um dem Problem auf die Schliche zu kommen. So richtig nutzt das aber nichts, bzw. kann ich es nicht interpretieren. Das Verhalten hat sich jetzt ein wenig geändert, und zwar in sofern, dass jetzt nicht mehr einzelne Pixel in verschiedenen Kombinationen blinken, sondern ganze Spalten. (Obwohl bei korrekter Funktion eigentlich alles dunkel sein sollte)Was ich (denke ich) als Ursache ausschließen kann:
- die Zeilentransistoren, da diese bereits in vorherigen Versionen (seit der Warteschleife) hinterherkommen
- den 74HC, der die Spalten durchschaltet, da auch das schon ordnungsgemäß gearbeitet hat, vor der Ram-Sache--> Deshalb vermute ich dass ich irgendwas bei der Speicherung im Ram oder dem Auslesen verramsche. (Was für ein Wortspiel) Also ein Softwareproblem. Habe mir den Artikel zum Ram von microcontroller.net mehrfach durchgelesen, aber ich komm nicht auf den richtigen Trichter. Langsam machts keinen Spaß mehr. Fühl mich auch schon rech blöde, immer wieder ohne Erfolg hier was neues zu posten.
Ich weiß dass der Code sehr lang ist, der oben steht, aber vielleicht könnte doch mal jemand drüber schauen...so richtig weiter weiß ich nicht mehr.Viele Grüße
ben -
Hallo, mal ein Status.
Hab mir den Code nochmal in aller Ruhe vorgenommen und solange zurückgebaut, bis was funktionierte. D.h.:
Zuerst den ganzen Z-Pointer Kram rausgelöscht, und von Hand drei Bytes (pro Farbe eins) reingetippt, und in den Ram geschrieben. Da hat es immer noch fröhlich geblunken, immer im selben Muster, egal was ich in die Bytes reinschrieb. Nur am Anfang 1x kurz das bekannte Aufleuchten des richtigen Musters.
Dann hab ich die 24 Ram-Adressen auf 3 reduziert, entsprechend in der Ausgabeschleife geändert. Außerdem noch die pop und push Befehle für die Z-Pointer Register entfernt, wurden ja nicht mehr gebraucht.Und, man soll es kaum glauben, was ich in der Hauptschleife in die 3Bytes für die Farben reinschrieb, wurde tatsächlich in den Ram übernommen und auch dauerhaft angezeigt. Hurra!
Also die ganze Sache wieder zurück, Speicheradressen hinzugefügt, Z-Pointer wieder mit dazu, die Ausgabeschleife wieder angepasst, und das Ding läuft tatsächlich immer noch. Den "Bildspeicher" im Flash habe ich noch angepasst, jetzt reicht eine Adresse "Bild_1" für die Daten R,G und B anstelle von "Bild_1_R" usw.
Woran es letztendlich lag, dass es anfangs nicht wollte kann ich nicht sagen, vermutlich hing es an irgendeiner kleinen mistigen Zeile. Hänge die SW so wie sie momentan ist mal mit ran. Der nächste große Meilenstein ist dann eine PWM. Hier muss ich mir aber noch überlegen, wie das ganze vom Prinzip genau aussehen soll. Cool wäre das.
Das also nur als Lebenszeichen. Ich bin sicher der Code ist sowas von nicht optimiert und ließe sich mit etwas know-how noch beachtlich schrumpfen, aber ich bin erstmal froh dass es so läuft. Für Hinweise bin ich natürlich immer gerne hoffen:) Genug gelabert, hier der Code (wieder an den wiederholenden Stellen gekürzt)Code
Alles anzeigen.include "m16def.inc" .def temp0=R16 .def temp1=R17 .def temp2=R18 .def rot=R19 .def gruen=R20 .def blau=R21 .def ccount=R22 .def warten=R23 .def temp3=R24 .org 0x0000 rjmp main //Reset Handler .org OVF0addr rjmp timer0_overflow //Timer Overflow Handler main: ldi temp0, 0xFF out DDRA, temp0 //Ports als Ausgänge Deklarieren out DDRB, temp0 out DDRC, temp0 out DDRD, temp0 out PortA, temp0 //Alle Portpins High, damit LED sicher aus sind out PortB, temp0 out PortC, temp0 out PortD, temp0 ldi ccount, 0xFF //Spaltenzähler nullen ldi temp0, HIGH(RAMEND) //Stackpointer initialisieren out SPH, temp0 ldi temp0, LOW(RAMEND) out SPL, temp0 ldi temp0, 0b00000001 // Prescaler 1 out TCCR0, temp0 ldi temp0, (1<<TOIE0) //TOIE0: Interrupt bei Timer Overflow out TIMSK, temp0 sei /*Bild1: //Bilddaten für rotes Standbild auslesen ldi ZL, Low(Bild_1*2) ldi ZH, High(Bild_1*2) rjmp laden*/ Bild2: ldi ZL, Low(Bild_2*2) ldi ZH, High(Bild_2*2) //rjmp laden //laden: lpm temp3, Z+ sts Rot1, temp3 [...] lpm temp3, Z+ sts Rot8, temp3 lpm temp3, Z+ sts Gruen1, temp3 [...] lpm temp3, Z+ sts Gruen8, temp3 lpm temp3, Z+ sts Blau1, temp3 [...] lpm temp3, Z+ sts Blau8, temp3 rjmp Bild_2 //wieder von vorne .macro warteschleife //Warteschleifen für Multiplexroutine ldi warten, 0xFF //damit Transistoren hinterherkommen warteschleife: dec warten brne warteschleife .endm timer0_overflow: Ausgabe: //Routine zum Aufruf der einzelnen Anzeigelabels für die Zeilen inc ccount // Spaltenzähler erhöhen cpi ccount, 1 // Vergleich mit 1 breq Spalte1 // wenn 1 dann Spalte1 aufrufen cpi ccount, 2 // analog mit den anderen Spalten breq Spalte2 cpi ccount, 3 breq Spalte3 cpi ccount, 4 breq Spalte4 cpi ccount, 5 breq Spalte5_sprung //ab hier wieder das Problem mit der Sprungweite cpi ccount, 6 breq Spalte6_sprung cpi ccount, 7 breq Spalte7_sprung cpi ccount, 8 breq Spalte8_sprung clr ccount // Spaltenzähler zurücksetzen reti Spalte5_sprung: rjmp Spalte5 Spalte6_sprung: rjmp Spalte6 Spalte7_sprung: rjmp Spalte7 Spalte8_sprung: rjmp Spalte8 ldi temp2, 0b01010101 Spalte1: ldi temp1, 0b0000010 ; Werte für 74HC laden lds gruen, Gruen1 //Register gruen mit Gruen1 füllen out PortA, gruen //an PortA gruen ausgeben lds rot, Rot1 //Register rot mit Rot1 füllen out PortB, rot //an PortB rot ausgeben lds blau, Blau1 //Register blau mit Blau1 füllen out PortC, blau //an PortC blau ausgeben out PortD, temp1 ; Spalte 1 am 74HC aktivieren warteschleife // Warteschleife für Zeilentransistoren rjmp Ausgabe Spalte2: ldi temp1, 0b01000010 //analog zu Spalte1 [...] Spalte8: ldi temp1, 0b01110010 lds gruen, Gruen8 //Register gruen mit Gruen1 füllen out PortA, gruen //an PortA gruen ausgeben lds rot, Rot8 //Register rot mit Rot1 füllen out PortB, rot //an PortB rot ausgeben lds blau, Blau8 //Register blau mit Blau1 füllen out PortC, blau //an PortC blau ausgeben out PortD, temp1 warteschleife rjmp Ausgabe Bild_1: .db 0b11111110,0b11111101,0b11111011,0b11110111,0b11110111,0b11110111,0b11111011,0b11111011 .db 0b01111111,0b10111111,0b11011111,0b11101111,0b11110111,0b11111011,0b11111101,0b11111110 .db 0b11100111,0b11100111,0b11100111,0b11100111,0b11100111,0b11100111,0b11100111,0b11100111 Bild_2: .db 0b11111000,0b11111000,0b11111000,0b11111000,0b11111000,0b11111000,0b11111000,0b11111000 .db 0b11100011,0b11100011,0b11100011,0b11100011,0b11100011,0b11100011,0b11100011,0b11100011 .db 0b00011111,0b00011111,0b00011111,0b00011111,0b00011111,0b00011111,0b00011111,0b00011111 .DSEG //Speicherreservierung entsprechend der Farbzeilen im SRAM Rot1: .BYTE 1 [...] Blau8: .BYTE 1
Ganz schön viel Platz, ich hoffe es ist einigermaßen übersichtlich.
Fröhliche Grüße, Ben.:)