Forum: Mikrocontroller und Digitale Elektronik Atmega128 USART Interrupt


von Peter D. (pdiener) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe gerade ein Problem mit dem Uart vom Atmega128 (avr-gcc). Und 
zwar habe ich ein Programm geschrieben, das einen 256 byte langen TX und 
einen 256 byte langen RX Puffer verwendet.

Damit das Senden halbwegs im Hintergrund passiert, soll jedes mal, wenn 
das Senderegister leer ist, im Interrupt ein neues Byte aus dem Puffer 
hineingeschrieben werden.

Um nun beim aller ersten Byte, das gesendet werden soll, einen Interrupt 
zu generieren, habe ich gedacht, ich kann einfach das Interruptflag 
setzen und der Interrupt wird dann angesprungen. Das ist aber nicht so. 
Offenbar kann man das TXC0 Bit in UCSR0A nicht setzen.

Ich habe schon einiges probiert, z.B.
cli();
UCSR0A =  (1<<TXC0);    //Set TxComplete Interrupt flag
led_green(1);
//if ((UCSR0A & 0x40) == 0x40) led_yellow(1);  //Check if TXC0 is set
sei();

Man würde hier erwarten, dass das bit gesetzt wird und zumindest gesetzt 
bleibt, bis die Interrupts freigegeben werden. Ist aber nicht so. 
led_yellow(1) wird nicht ausgeführt.

Das Problem ist, dass der Interrupt auch nicht angesprungen wird.

Das Assembler listing habe ich schon angeschaut und meiner Meinung nach 
verhält sich der Compiler korrekt.
1
300 0172 80E4          ldi r24,lo8(64)
2
 301 0174 8BB9          out 43-0x20,r24
3
 302                 .LM42:
4
 303 0176 81E0          ldi r24,lo8(1)
5
 304 0178 0E94 0000     call led_green
6
 305                 .LVL9:
7
 306                 .LM43:
8
 307 017c 5E9B          sbis 43-0x20,6
9
 308 017e 00C0          rjmp .L38
10
 309 0180 81E0          ldi r24,lo8(1)
11
 310 0182 0E94 0000     call led_yellow

Ich habe testweise alle Interrupts definiert, aber keiner wird 
angesprungen.

Was mache ich denn da falsch?

Das angehängte Programm sollte einfach immer Test\n senden, es passiert 
aber nichts.

Ich muss dazusagen, dass der Puffercode auf einem MSP430 läuft, das ist 
also nur ein Thema der Interrupts beim Atmega128.

Grüße,

Peter

von STK500-Besitzer (Gast)


Lesenswert?

>Offenbar kann man das TXC0 Bit in UCSR0A nicht setzen.

Genaueres sollte man in Datenblatt finden. Manche Register/Flags sind 
nur lesbar.

Sobald du ein Zeichen in den Puffer geschoben hast, solltest du das 
UDRIE setzen. Dann springt der Controller von alleine in die ISR.
Da fragst du dann ab, ob der Puffer leer ist, und setzt es zurück.

Das TXC-Flag braucht man eigentlich nur bei Übertragungen, die 
halbduplex sind, wie RS485-2wire, wo sich mehrere Sender und Empfänger 
die Datenübertragungsleitung teilen.

Für die Datenübertragung musst du die UDR-ISR nehmen.

von Michael K. (mmike)


Lesenswert?

Hi,

das Datenblatt sagt:
Writing this bit to one enables interrupt on the TXCn flag. A USARTn 
Transmit Complete interrupt will be generated only if the TXCIEn bit is 
written to one, the global interrupt flag in SREG is written to one and 
the TXCn bit in UCSRnA is set.

Also der Interrupt wird nur ausgelöst wenn das TXCIEn bit UND im SREG 
die Interrupts global aktiviert sind (sei) UND das TXCn bit gesetzt ist.

Grüße,
Michael

von Peter D. (pdiener) Benutzerseite


Lesenswert?

@Michael:
Genau das habe ich gemacht (siehe initialisierungsroutine des uart 
USART0_Init).
Uart konfiguriert, TXCIE0 gesetzt
und dann per Software TXC0 gesetzt.

Aber der Interrupt wird nicht angesprungen. Das Bit lässt sich nicht mal 
schreiben, laut Datenblatt ist es aber schreibbar. Ich habe sogar extra 
das ganze Register gesetzt und nicht nur das Bit, genau so wie es im 
Datenblatt geschrieben ist (dass man alle anderen Bits auf 0 setzen 
soll, wenn man auf UCSR0A zugreift).

Mit dem Data Register empty Flag ist es ganz genauso, nur mit dem 
Unterschied, dass sogar im Datenblatt steht, dass man es nicht in 
Software setzen kann.

Wie löse ich also in Software einer der folgenden Interrupts aus:

TX Complete Interrupt
USART Data Register Empty Interrupt
?

Grüße,

Peter

von Michael U. (amiga)


Lesenswert?

Hallo,

Du kannst ein Interruptflag nicht setzen, das wird nur von der 
jeweiligen Hardware gesetzt. Mit Schreiben einer 1 in die Position wird 
ein gesetztes Interruptflag gelöscht, beim Schreiben einer 0 passiert 
garnichts.

Gruß aus Berlin
Michael

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Beim MSP430 geht das. Wie löst man einen Interrupt dann am AVR in 
Software aus, wenn das nicht geht?

Grüße,

Peter

von Peter D. (pdiener) Benutzerseite


Lesenswert?

@ STK500-Besitzer:
Jetzt verstehe ich, was du meinst. Das Data register empty Flag ist ja 
automatisch beim Reset gesetzt...

Ich probier das mal eben, wie du es beschrieben hast.

Peter

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Vielen Dank, es funktioniert.

Grüße,

Peter

von Ralf K. (ralf82k)


Lesenswert?

@ Peter Diener
Was hast du denn jetzt genau geändert das es läuft?
Habe ähnliches mit ATMega64 vor.

von Peter D. (pdiener) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo Ralf,

ich häng das einfach nochmal als kompletten Quellcode an.
Wichtig ist scheinbar, dass man das Bit TXCIE0 mit dem Befehl cbi 
zurücksetzt. Ich hatte das vorher in C reinundiert in das Register 
UCSR0B, nur das funktioniert nicht, weil es ein Read-Modify-Write war. 
Ich hab das jetzt einfach unkompliziert mit einem Stück Inlineassembler 
erledigt:

asm volatile ("cbi 10, 5");    //clear bit UDRIE0 in register UCSR0B

Wenn jemand zufällig noch weiß, wie man im Inlineassembler unkompliziert 
die Registernamen und Bitnamen anstatt der Adressen verwenden kann, 
würde ich mich über einen kurzen Tip freuen. Ich habe im Moment nur 
nicht die Zeit, das noch zu bereinigen, wichtig ist gerade nur, dass es 
so läuft wie es soll.


Grüße,

Peter

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.