Hallo miteinander,
ich versuche seit gestern interruptgetriebene Routinen für den USART0
des ATmega2560 zum Laufen zu bringen. Beim Empfang eines Zeichens wird
URXC0 ausgelöst und in der zugehörigen Interrupt-Routine wird das
Zeichen aus UDR0 ausgelesen und in einen Empfangspuffer geschrieben. Zu
sendende Zeichen werden in einen Sendepuffer übertragen und von dort per
UDRE0-Interruptroutine ins UDR0 übertragen.
Ich habe unter http://avrbeginners.net/architecture/uart/uart.html ein
schönes Code-Beispiel gefunden und dieses entsprechend für den 2560
angepasst (Registernamen!). Als "Gegenstation" benutze ich TeraTerm auf
einem PC. Leider funktionierte zunächst weder Senden noch Empfangen.
Durch Betreiben der USART0 im Pollingbetrieb wollte ich dann zunächst
verifizieren, dass meine Parametrierung (Baudrate, Länge, Parity,
Stopbist) der USART0 überhaupt korrekt funktioniert. Eine Simulation der
Init-Routine im AVR-Studio (Vers. 4.18 Build 716) brachte den ersten
Stolperstein zutage: beim Beschreiben von UCSR0C wird auch das Register
UBRR0H wieder überschrieben. Ein Bug der CPU, wie ich nach einigem
Googeln herausfinden konnte, aber einer der tödlich sein kann, wenn man
ihn nicht kennt. Dieser lässt sich jedoch leicht dadurch beheben, dass
man zunächst UCSR0C beschreibt und erst anschließend UBRR0H. Ein Glück
war, dass der Simulator im AVR-Studio diesen Bug auch simuliert, sonst
wäre ich da nie drauf gekommen!
Im Pollingbetrieb konnte ich nun problemlos Daten zwischen ATmega2560
und TeraTerm austauschen. Interruptgetrieben funktionierte aber nach wie
vor überhaupt nichts. Durch "Debug-Ausgaben" (LED einschalten ;-)
stellte ich fest, dass weder die URXC0- noch die UDRE0-Interruptroutine
überhaupt aufgerufen werden. Und jetzt kommt der Hammer:
Um dem Problem zu Leibe zu rücken, warf ich wieder den Simulator des
AVR-Studios und stellte nach längerem Debugggen fest, dass beim Auslösen
eines UDRE0-Interrupts (Adresse des Vektors = 0x34) versucht wird, den
Interrupt-Vektor an der Stelle des UDRE2-Vektors (Adresse des Vektors =
0x68) aufzurufen, wobei ich dort natürlich ein 'reti' stehen hatte, da
ich diesen ja nicht verwendete. Kaum trug ich dort einen 'jmp' auf meine
Interrupt-Routine für die Behandlung des Sendepuffers ein, schon
funktionierte das interruptgetriebene Senden einwandfrei. Ich wusste
zwar noch nicht, warum sich das so verhielt, aber ich abstrahierte und
trug einfach den Sprung auf meine Routine zur Behandlung des
Empfangspuffers ebenfalls statt unter URXC0 (Adresse des Vektors = 0x32)
nun unter URXC2 (Adresse des Vektors = 0x66) ein und siehe da, das
interruptgetrieben Empfangen funktionierte IMMER NOCH NICHT!
Ein nochmaliges Betrachen der Vektortabelle ergab, dass ich bei der
Senderoutine den Vektor statt an der Adresse 0x34 an der Adresse 0x68
eintragen musste, was genau der doppelte Wert ist. Folglich testete ich
nun den Eintrag des Vektors für den Interrupt URXC0 statt an der Adresse
0x32 an der Adresse 0x64 und SO FUNKTIONIERT ES!
Und nun meine staunende Frage:
Was habe ich nicht verstanden oder wo muss ich nochmals nachlesen, um
diesen Sachverhalt zu kapieren? Die include-Datei zum ATmega2560
(m2560def.inc) im AVR-Studio sagt eindeutig:
.equ URXC0addr = 0x0032
.equ UDRE0addr = 0x0034
und so steht das auch im Atmel datasheet zum ATmega 2560 (ist zwar
preliminary, hab' aber nichts Neueres gefunden).
MfG UWF
UWF schrieb:> Ein Bug der CPU, wie ich nach einigem> Googeln herausfinden konnte,
Quelle?
> Dieser lässt sich jedoch leicht dadurch beheben, dass> man zunächst UCSR0C beschreibt und erst anschließend UBRR0H.
Wenn du nur das übliche "8N1" haben willst, geht das noch einfacher:
UCSR0C gar nicht erst anfassen. 8N1 ist die Voreinstellung, und
die garantiert dir das Datenblatt.
> Ein nochmaliges Betrachen der Vektortabelle ergab, dass ich bei der> Senderoutine den Vektor statt an der Adresse 0x34 an der Adresse 0x68> eintragen musste, was genau der doppelte Wert ist.
Willkommen in der wundervollen Verwechslungswelt zwischen Byte- und
Wortadressen. AVR-Datenblätter zeigen 16-bit-basierte Wortadressen
für alle Angelegenheiten, die sich um Codezugriffe kümmern. Wenn
du den Flash jedoch mit LPM ansprichst, dann arbeitet er sehr wohl
byteweise.
>0x32 an der Adresse 0x64
fällt dir was ins Auge? :-)
Das tritt bei allen AVR auf, bei denen rjmp nicht ausreicht, den
gesamten Programmspeicher zu erreichen. Statt rjmp muss man dann jmp
verwenden. Und dieser Befehl passt nicht in 2 Byte.
Danke für Eure schnellen Hinweise. Ich muss zugeben, dass ich in Sachen
AVRs ganz neu unterwegs bin. Hatte vor einigen Jahrzehnten mal mit dem
KIM1 angefangen (CPU: 6502) und mich seither außer einigen
Kleinversuchen mit 80535 (und Derivaten) nur mit PC-Programmierung
beschäftigt. Im Moment geht es ein wenig "Back to the roots" (weil's
einfach Spaß macht).
Zu meiner Entlastung muss ich sagen, dass das mit den Wortadressen zwar
logisch ist (jetz, im Nachinein!), aber man bei den vielen Neuigkeiten,
die am Anfang auf einen zukommen (CPU, Assembler, Entwicklungssystem,
AVR-Studio, Programmer, ...) einfach nicht an alles denkt, weil man
höchstens EINblicke hat, aber noch keinen ÜBERblick ;-)
Auch ist bei der entsprechenden Tabelle im datasheet mit keiner Silbe
erwähnt, dass es sich dabei um Wortadressen handelt. Aufgrund der
include-Datei (m2560def.inc) im AVR-Studio hätte man VIELLEICHT drauf
kommen können, da entdeckte ich jetzt nämlich unterhalb der Definition
der Vektor-Adressen:
.equ INT_VECTORS_SIZE = 114 ; size in words (AHA!)
Also, danke nochmals und speziell an dl8dtl:
73 de Uwe, DL8UF
Das Ganze ist letzten Endes aber auch eine Frage der SChreibweise. Wie
hast du das Ganze denn ursprünglich geschrieben? Ich geh sowieso davon
aus, dass du Assembler programmierst, aber auch dort ist das mit der
richtigen Schreibweise kein Thema, um das man sich Gedanken machen muss.
Mit
.org URXC0addr
jmp ReceiveHandler
.org UDRE0addr
jmp EmptyHandler
macht der Assembler automatisch das richtige, ohne dass man sich um
Zahlenwerte Gedanken machen muss. Wichtig: Vor jedem jmp oder rjmp immer
mit .org und dem Namen aus dem Inc-File neu positionieren, selbst wenn
die Vektoren laut Datenblatt unmittelbar aufeinander folgen.
@ Karl Heinz:
Danke, dein Vorschlag ist nicht nur richtig, sondern auch konsequent.
Den hab' ich inzwischen so umgesetzt.
@ Jörg / alle:
Hier noch die Quelle mit der Angabe zum Bug des ATmega2560:
http://support.atmel.no/knowledgebase/avrstudiohelp/mergedProjects/Simulator/Known_Issues/Notes_for_ATmega2560_2561.htm
<Zitat>
Notes for ATmega2560/2561
* When writing to UCSRnC, the value will be copied to UBRRnH unless
UMSELn1 is set. This behaviour should not happen on devices that have
separate locations for these registers. A workaround is to write UBRRnH
after UCSRnC.
* The JTD bit in the MCUCR register must be set to the desired value
twice within four cycles to change its value. In the simulator the JTD
bit can be written directly.
* The ADC noise reduction function is not supported. Setting the ADIF
flag will not wake the CPU from sleep mode.
* Timer/Counter2
* Output compare pins and FOC does not work.
* Prescaler reset does not work correctly.
* OCR2A/B registers are not buffered correctly in PWM mode.
<Zitat Ende>
Viele Grüße, UWF
UWF schrieb:> Hier noch die Quelle mit der Angabe zum Bug des ATmega2560:
Das ist die Beschreibung eines Simulator-Fehlers. Und wo steht jetzt,
dass auch der Chip diesen Fehler haben soll?
Du könntest Recht haben...
Auch hier kann man's sich erst wieder zusammenreimen, wenn man auf die
(recht lange) URL schaut, aus dem Text ansich geht nicht hervor, dass es
nicht um die CPU, sondern um den Simulator geht (s.o.).
Muss man sich bei Atmel wohl erst dran gewöhnen ;-)
Obwohl, es gibt noch größere Unternehmen mit wesentlich schlechterer
Doku, ansich scheint mir Atmel da ganz gut.
Gruß UWF
UWF schrieb:> Auch hier kann man's sich erst wieder zusammenreimen, wenn man auf die> (recht lange) URL schaut, aus dem Text ansich geht nicht hervor, dass es> nicht um die CPU, sondern um den Simulator geht (s.o.).
Naja, das sollte da gestanden haben, wo der Link auf diese Seite
steht.
> Obwohl, es gibt noch größere Unternehmen mit wesentlich schlechterer> Doku, ansich scheint mir Atmel da ganz gut.
Wenigstens haben die CPUs nicht so viele Bugs. ;-)
Neuere Controller (der ATmega2560 ist von der Entwicklung her schon
ziemlich alt) sind auch im Simulator besser. Das Ganze nennt sich
irgendwie "Simulator V2" oder so, und dort wird der Code der
Simulation direkt aus der Hardwarebeschreibung des ICs abgeleitet,
da können derartige Fehler nicht mehr auftreten.
Ansonsten: traue keiner Simulation, die du nicht selbst gebaut hast. ;-)
Kriterium ist immer das reale Leben, nicht die Simulation.