Hallo,
ich habe hier ein unerklärliches Problem und hoffe, es hinreichend genau
zu beschreiben, vielleicht hat einer der mitlesenden Experten einen
Tipp.
Ausgangssituation:
ATXmega agiert als Kommunikationsprozessor, an einem UART kommen Daten
mit 500kBaud an, diese werden in ein FIFO geschrieben, analysiert,
bearbeitet und weiter auf einem anderen UART wieder abgesendet. Die
Daten kommen paketweise, Pakete beginnen mit einem Längenfeld und sind
mit CRC gesichert.
Die UART Routine ist als ISR mit Priority high implementiert, des
weiteren gibt es noch andere Interrupts, teilweise auch mit High
Priority. Alles ist in C geschrieben, Compiler ist der AVRGCC aus dem
aktuellen Studio6.
Fehlerbild: Sporadisch (so mit 0,01%) ist das Längenfeld des Paketes
0xA0 anstatt der korrekten Länge. Zur Kontrolle habe ich Scope an den
RX-Pin des Prozessors gehängt, dort sehe ich den Datenstrom, der
reingeht. In der ISR habe ich nach der Zeile rec = UART.DATA eine
Kontrollausgabe auf einen Port reingehängt:
1 | rec = UART.DATA;
|
2 | if (rec == 0xA0) { PORT_AN(); _delay_us(1) PORT_AUS();}
|
Und wie auf dem Bild zu sehen ist, feuert das nach einiger Zeit und zig
normalen Übertragungen. Zusammen mit dem Fehler stelle ich fest, dass
die Interruptroutine etwas verzögert ist, d.h. ein anderer Interrupt war
dazwischen. (Wenn ich die Kontrolle auf (rec == 0x06) umstelle, dann
feuert das etwas früher und immer).
Ich habe darauf alle anderen Interrupts im System von HI auf MED
zurückgestuft - und siehe da, der Fehler ist weg. Konkret hängt es an
einem Interrupt, dessen ISR ich hier mal einhänge:
1 | TCF0.INTCTRLB = TC_CCDINTLVL_MED_gc | TC_CCCINTLVL_HI_gc | TC_CCBINTLVL_MED_gc | TC_CCAINTLVL_MED_gc;
|
2 |
|
3 | ISR(TCF0_CCC_vect)
|
4 | {
|
5 | PORTE.OUTSET = (1<<my_pin_p);
|
6 | TCF0.INTCTRLB = (TCF0.INTCTRLB & ~TC0_CCCINTLVL_gm) | TC_CCCINTLVL_OFF_gc; // disable Interrupt
|
7 |
|
8 | // timer von event abkoppeln
|
9 |
|
10 | TCF0.CTRLD = TC_EVACT_RESTART_gc | TC_EVSEL_OFF_gc;
|
11 | }
|
Wenn ich den TC_CCCINTLVL_HI_gc auf TC_CCCINTLVL_MED_gc ändere, tritt
der Fehler nicht auf. Aber eigentlich ist die ISR vollkommen harmlos und
hat nichts mit dem UART zu tun - weder der gleich Port noch irgendwelche
Variablen.
Was ist jetzt nicht verstehe - warum ist das so? Warum wird das Byte
verändert, welches ich vom UART lese?