Forum: Mikrocontroller und Digitale Elektronik ATmega2560 - Zugriff auf falsche Interruptvektoren


von UWF (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von crazy horse (Gast)


Lesenswert?

>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.

von UWF (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von UWF (Gast)


Lesenswert?

@ 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

von Stefan E. (sternst)


Lesenswert?

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?

von UWF (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.