Hallo Zusammen,
ich benötige ein wenig Hilfestellung bei der im Anhang befindlichen
Software.
Die Software selber war ursprünglich für einen MEGA32 und einen 4 x 4 x
4 LED Cube entwickelt. Ich habe die Software für einen ATMEGA8 und einen
3 x 3 x 3 LED Cube angepaßt.
Grundsätzlich funktioniert die Software bis auf zwei Macken einwandfrei.
Die für mich im Augenblick wichtigste Macke, ist die Tatsache, das PINB4
(MISO) nicht dass tut was er soll.
Den Effekt, den ich bei laufenden Würfel festgestellt habe, ist das
PINB4 nicht schaltet bzw. sich sehr mekrwürdig verhält und damit die
Spalte die an diesen Port angschlossen ist ausgeschaltet bleibt.
Ich habe das ganze dann mal im AVRStudio simuliert und konnte den Fehler
nachvollziehen. Nur ist mir leider die Ursache dieses Fehlers nicht
wirklich klar.
Einen Hardwarefehler kann ich ausschliessen, ich habe einen kleines
Testprogramm, dass mir alle Zeilen und Spalten durchschaltet. Hier
funktioniert alles einwandfrei.
Könnte dies mal jemand simulieren und mir noch mit ein paar Ideen unter
die Arme greifen.
[EDIT] ich habe die Software soweit reduziert, dass die zweite Macke ein
Überschreiten der Array-Grenze und damit hängen des Controllers nicht
vorkommen kann[EDIT]
Entwicklungsumgebung:
Eclipse
AVR-Studio 4.16 (zum simulieren)
WinAVR-20090313
ATMEGA8
Gruß
Frank
Problem erkannt und beseitigt, zum einen wahr es nicht PINB4 der
gesponnen hat sondern PINB3.
Für den, den es interessiert.
In der Dokumentation zum ATMEGA8 Seite 58, Abschnitt "Alternate
Functions of Port B" findet man zu PINB3 die folgende Aussage:
Damit war klar, dass durch die Verwendung des ISR(TIMER2_COMP_vect) der
PINB3 zur Verwendung als Output wegfallen oder ein alternativer Ansatz
gesucht werden muss.
1
TCNT2=0x00;
2
TIMSK|=(1<<OCIE2);
3
4
OCR2=15;
5
TCCR2=(0<<WGM21)|(1<<WGM20)// CTC-Mode
6
|(1<<COM21)|(0<<COM20)// Toggle OC2 on Compare Match
7
|(1<<CS21)|(1<<CS20);// Prescaler: 5
Ich habe mich dafür entschieden, einen alternativen Ansatz zu wählen, da
ich keine Lust habe mmeine Hardware zu ändern.
Ich habe das ganze jetzt mit einem ISR(TIMER0_OVF_vect) gelöst und
betreibe diesen mit 100Hz.
ATMEGA8 mit einem 4 MHz Quartz unter Verwendung von Timer0 (8 Bit).
ISR - Initialisierung
Warum nicht gleich so werden einige Fragen, dazu muss ich sagen, dass
die Software ursprünglich von Christian Moen für einen MEGA16
geschrieben wurde. Andreas verwendet den TIMER2_COMP_vect um den Würfel
zu aktualisieren.
Gruß
Frank
>Damit war klar, dass durch die Verwendung des ISR(TIMER2_COMP_vect) der>PINB3 zur Verwendung als Output wegfallen oder ein alternativer Ansatz>gesucht werden muss.
Das wäre für nicht klar, da man beim AVR eigentlich immer die alternate
Portunction explizit ein- und ausschalten kann.
>ISR(TIMER0_OVF_vect)>{> TCNT0 = 217; // 4000000 1024 100Hz = 39,0625 = 39> // 256 - 39 = 217
Na, ob das auch wirklich stimmt?
Möglicherweise sichert der Compiler noch ein paar Register...
Selbstnachladende Timer-Modi sind immer die bessere Wahl, wenn man ein
genaues Timing einhalten will.
Da es nicht wirklich auf die ms ankommt. Braucht es auch nicht so genau
zu sein.
Mittlerweile habe ich die Framerate sogar auf 1KHz erhöht. Weil ich
einfach mal sehen wollte was der ATMEGA8 so leistet. Und das Teil rennt
ohne Ende.
Mittlerweile ist der Speicher mit 98,5% belegt und das Teil rennt jetzt
seit 48 Stunden ununterbrochen.
Wenn alles fertig ist, stelle ich das ganze Projekt in die Codesammlung
und werde einen Artikel dazu verfassen.
Wenn ich es wirklich auf die 100stel Sekunde genau bräuchte, dann
natürlich CTC oder ähnliches. Mein Problem war wie oben beschreiben,
dass der PINB3 durch den CTC belegt war! Ich hatte also keine andere
Wahl wenn ich die Hardware nicht ändern wollte.
Im übrigen, wenn Du mir zeigst, wie man die alternate Portfunction beim
ATMEGA8 abschaltet, bist Du für dieses Wochenende mein absoluter Held!
Ich habe es im Handbuch nicht gefunden, was nicht heisst das es nicht
dort steht...
Gruß
Frank
>Im übrigen, wenn Du mir zeigst, wie man die alternate Portfunction beim>ATMEGA8 abschaltet,
Die sind defaultmäßig immer abgeschaltet, aber du schaltest die ja
selber ein (vermutlich, ohne zu wissen, was du da tust). Mit Interrupts
o.ä. hat das nichts zu tun.
1
(1<<COM21)|(0<<COM20)
Die Rumschieberei der Nullen trägt hier nichts zur besseren Übersicht
bei.
Oliver
>> Die Rumschieberei der Nullen trägt hier nichts zur besseren Übersicht> bei.
Aber definitiv tut es das. Nimm' beispielsweise ein Register wie "TCCR0"
mit den Bits "CS02" "CS01" "CS00".
Wenn im Quelltext folgende Passage auftaucht:
1
(1<<CS02)|(0<<CS01)|(1<<CS00)
Dann sehe ich direkt "aha Clock Select steht auf 101". Ein Blick ins
Datenblatt mit "101" im Hinterkopf und ich sehe "101 => Vorteiler 1024".
Nicht ohne Grund ordnet Atmel in den Datenblättern einzelne Bits, die
eine Funktionalität definieren in eine Tabelle ein (selbst wenn sie
registerübergreifend sind wie teilweise die WGMxx-Bits).
Der einzige Grund warum jemand überhaupt
1
REG=(1<<XXYY)|(0<<ABzz)...
verwendet und nicht gleich
1
REG=0x23
schreibt liegt darin, dem nachfolgenden Programmierer (und sich selbst
in 2-3 Monaten ;-) die Arbeit zu erleichtern. Für Codegröße und Laufzeit
spielt es keine Rolle, da ein Compiler, der tatsächlich anfängt Literale
zur Laufzeit und nicht zur Compilezeit zu shiften ein ganz andeses
Problem hat. Code wird nicht geschrieben um dem Compiler die Arbeit zu
erleichtern, sondern in erster Linie um klar auszudrücken, was man haben
will.
Ist das gleiche Problem wie bei Klammerung in C. Eigentlich sind die
meisten Klammern in arithmetischen Ausdrücken redundant, da die Operator
Precendence in C klar definiert ist. Ich habe beruflich oft mit
Quelltext von Programmierern zu tun, die relativ frisch aus dem
Hochschulumfeld kommen und glauben, sie wären besonders klug, wenn sie
Ausdrücke mit möglichst wenigen Klammern schreiben. Einige davon haben's
auch tatsächlich drauf und alles funktioniert wie es soll. Das Problem
kommt spätestens dann, wenn ein Kollege den Quellcode bekommt. Der
blickt's dann nicht und schwupps ist ein Bug drin ("aber ich habe doch
nur einen weiteren Summanden hinzugefügt..."). Mittlerweile kommt mir
kein Code mehr durch's Review, der mehr als zwei unterschiedliche
Operatoren in einem Ausdruck hat und keine Klammern verwendet - selbst
wenn er tut was er soll.
Gruß,
Bernd
Hallo,
alles klar, wer die Dokumente richtig liest und nicht nur überfliegt,
kommt auch auf die richtigen Einstellungen.
Seite 118, Tabelle 43 Compare Output Mode, Non-PWM Mode
1
COM21COM20Description
2
00Normalportoperation,OC2disconnected.
3
01ToggleOC2onCompareMatch
4
10ClearOC2onCompareMatch
5
11SetOC2onCompareMatch
Also, wenn ich es richtig verstanden habe, ist die korrekt Einstellung:
Das bedeutet, will ich eine Bildwiederholfrequenz von ca. 100 FPS
erreichen, muss ich die folgende Werte zu Grunde legen.
(ich benutze jetzt bewusst die von Oliver angemäkelte schreibweise).
Brechnung:
1
Quartz/Vorteil/OCR2/AnzahlLayer=FrameRate
2
3
4.000.000HZ/256/52sindca.300Hz
4
5
3Ebenenmüssenaktualisiertwerden
6
7
4.000.000/256/52/3sindca.100FPS
Code:
1
TCNT2=0x00;
2
TIMSK|=(1<<OCIE2);
3
4
OCR2=52;
5
TCCR2=(0<<WGM21)|(1<<WGM20)// CTC-Mode
6
|(0<<COM21)|(0<<COM20)// Normal port operation, OC2 disconnected
7
|(1<<CS22)|(1<<CS21)
8
|(0<<CS20);// Prescaler: 256
Da das für meinen Anwendungsfall Näherungswerte vollkommen ausreichen,
sind, sind die Wert hinreichend genau.
Danke für die Hinweise und die großen Zaunpfähle :-))) haben echt
geholfen.
Gruß
Frank
P.S. ich hoffe ich hab mich nicht verrechnet.
P.P.S @STK500-Besitzer: für heute bist Du mein Held...
Bernd O. schrieb:
> Oliver schrieb:> Aber definitiv tut es das. Nimm' beispielsweise ein Register wie "TCCR0"> mit den Bits "CS02" "CS01" "CS00".>> Wenn im Quelltext folgende Passage auftaucht:>
1
(1<<CS02)|(0<<CS01)|(1<<CS00)
>> Dann sehe ich direkt "aha Clock Select steht auf 101". Ein Blick ins> Datenblatt mit "101" im Hinterkopf und ich sehe "101 => Vorteiler 1024".
und was ist, wenn CS01 vorher auf 1 stand?
Justus Skorps schrieb:
> Bernd O. schrieb:>> Oliver schrieb:>>> Aber definitiv tut es das. Nimm' beispielsweise ein Register wie "TCCR0">> mit den Bits "CS02" "CS01" "CS00".>>>> Wenn im Quelltext folgende Passage auftaucht:>>
1
(1<<CS02)|(0<<CS01)|(1<<CS00)
>>>> Dann sehe ich direkt "aha Clock Select steht auf 101". Ein Blick ins>> Datenblatt mit "101" im Hinterkopf und ich sehe "101 => Vorteiler 1024".>> und was ist, wenn CS01 vorher auf 1 stand?
Was soll dann sein?
Dann wird es von:
1
REG=(1<<CS02)|(0<<CS01)|(1<<CS00)
genauso auf 0 gesetzt wie von:
1
REG=(1<<CS02)|(1<<CS00)
Im ersten Fall eben offensichtlich und im zweiten Fall implizit (und
eventuell vom Programmierer nicht beabsichtigt - zumindest hat der
Programmierer nicht dokumentiert, dass er das entsprechende Bit löschen
wollte).
Bei "|=" sind Nullshifts dementsprechend zu unterlassen, da man beim
überfliegen des Codes geneigt ist, davon auszugehen, dass das erwähnte
Bit gelöscht würde.
Zusammenfassend ist es also so:
Bei "=" werden bei fehlendem "Nullshift" Bits implizit gelöscht, die
nicht im Befehl stehen.
Bei "!=" wird bei vorhandenem "Nullshift" suggeriert, dass mit dem
Befehl Bits gelöscht werden, die nicht gelöscht werden.
Beides also schlecht. Zwar nicht falsch, aber fehlerträchtig.
Gegen Programmierfehler hilft ohnehin weder Nullen zu shiften noch sie
nicht zu shiften. Wenn man sich aber an die Regel hält, bei "=" alle
Bits aufzuführen und bei "|=" nur die zu setzenden, senkt man die
Fehlerwahrscheinlichkeit.
Gruß,
Bernd