Hallo,
Wir setzen diesen Controller ein und haben mit dem UART Probleme. Alle
paar Stunden empfängt dieser Müll. Also SEHR sporadisch. EMV Störungen
können ausgeschlossen werden, es sind nur sehr kurze Leitungen.
Das zeigt sich so als ob er irgendwie auf die Idee kommt auf 9 Bit
Übertragung umzuschalten und kommt dann mit dem Empfang komplett
durcheinander und empfängt falsche Zeichen.
Auch habe ich schon einen anderen Quarz eingebaut, damit 0,0% Abweichung
da sind.
Die Empfangsroutine über Interrupt habe ich auch schon neu programmiert
und es läuft nichts anderes mehr.
Im UART Interrupt habe ich folgenden Code hinterlegt:
1
__interrupt void USART1_RX_interrupt( void )
2
{
3
4
// *DEBUG Test Echo auf COM 0 ausgeben
5
unsigned char udr1;
6
unsigned char ucsr1a, ucsr1a2;
7
unsigned char ucsr1b, ucsr1b2;
8
unsigned char ucsr1c, ucsr1c2;
9
10
ucsr1a2 = UCSR1A; // Register merken
11
ucsr1b2 = UCSR1B;
12
ucsr1c2 = UCSR1C;
13
14
udr1 = UDR1; // Daten empfangen
15
16
if (udr1 == 255) // Fehler erkannt, nochmals merken
17
{
18
ucsr1a = UCSR1A;
19
ucsr1b = UCSR1B;
20
ucsr1c = UCSR1C;
21
udr1--;
22
}
23
24
UDR0 = udr1; // Test-Ausgabe auf anderen UART
25
26
if (udr1 == 254)
27
{
28
ucsr1a++; // hier Breakpoint setzen im Register anzuschauen
29
ucsr1b++;
30
ucsr1c++;
31
ucsr1a2++;
32
ucsr1b2++;
33
ucsr1c2++;
34
}
35
}
Also wenn die 255 empfangen werden, dann ist es zu spät und sind schon
einige Fehler passiert. Uns wundert es, dass die Register der Anzahl
Datenbits während diesem ändert (Protokolliert mit diesen
zwischenvariablen) !!?!?
Die Daten über den seriellen Bus sind in jedem Fall korrekt verschickt
worden (mit separatem USB-Datenspion und BinTerm protokolliert)
Baudrate ist nur 9600 Baud.
Der Atmel Support möchte jetzt so viele Zusatzmessungen haben, wo wir
vor der Entscheidung stehen ob wir nicht gleich den Atmel raus schmeißen
und durch einen anderen ersetzen. Wir haben schon sehr viel Zeit in das
Problem gesteckt und sind der Meinung es muss der Prozessor selbst sein.
Was meint Ihr?
Kurzes Kabel ist keine Garantie gegen Störungen, denn die können auch
auf der Platine ausgelöst werden. Empfang von 0xFF ist ein ziemlich
starkes Indiz für ein falsch erkanntes Startbit, ausgelöst durch ein
kurzen negativen Puls.
Verifizierung: Mal irgendwas an Rx-Pin vom Controller hängen, was auf
negative Flanke triggert. Ob nun DSO, Logikanalysator oder einfaches
D-Flipflop. Dessen GND möglichst direkt an GND-Pin vom Controller
hängen.
Und ggf. auch Vcc/GND auf Glitches kontrollieren.
Wenn das selten auftritt und auf Rx nicht getriggert werden kann weil
immer was los ist: In der Interrupt-Routine im Fehlerfall einen
unbenutzten Ausgang setzen und auf den ein DSO triggern (one shot). Und
dann mal nachsehen was auf der Leitung los war.
Dass Atmel hier Messungen sehen will kann ich sehr gut verstehen. Was
hast du dir erwartet? Dass eine Horde Atmel-Techniker einrückt und
selber nachmisst? Wenn's ein dort bekannter Fehler wäre, hätten die
anders reagiert. Und sowas wäre wahrscheinlich schon früher aufgeflogen,
so neu ist der AT90CAN128 nun auch nicht.
Wäre es eine Möglichkeit einen anderen AVR (mega128) mit externem
CAN-Controller zu nehmen? Funktion und Programm könnten weitgehend
erhalten bleiben.
Dazu den Datenverkehr mit diesem anderen AVR mitlesen und sehen, ob der
zuverlässig arbeitet und ob das Problem damit erledigt ist.
Manchmal ließt man ja die eigenartigsten Fehlerbeschreibungen im
'errata'; wenn man Pech hat stößt man selber drauf.
Den Datenverkehr am Rx-Pin kann mit mit jeden x-beliebigen Controller
mit UART zur Kontrolle mitlesen, oder auch mit einem Laptop. Man sollte
nur darauf achten, dass der die gleiche Situation vorfindet, d.h. dessen
GND sollte dem GND des Controllers entsprechen um mögliche Fehler im
GND-Signal mit zu erfassen. Und der sollte möglichst auf CMOS-Pegel bei
gleicher VCC reagieren, und nicht wie der MAX232 auf TTL-Pegel (das wäre
beispielsweise bei Laptop mit zwischengeschaltetem MAXe ein Problem).
Hallo Markus,
diese Art Problem deutet nach meiner Erfahrung auf einen Softwarefehler
hin.
Die üblichen Verdächtigen zu diesem Thema sind - bereits nach
Wahrscheinlichkeit geordnet -
1. Ein Problem in Deinem Code (z. B. Reentrancy , 1-off, ....).
2. Ein Problem in Deinem Code (z. B. Reentrancy , 1-off, ....).
3. Ein Problem in Deinem Code (z. B. Reentrancy , 1-off, ....).
.
.
.
n. Ein Fehler im Compiler
.
.
.
z. Ein Hardware-Fehler im benutzten Processor
!!!
Der übliche Weg beim Debuggen:
1. gründlicher eigener Schreibtischtest (der gesamten Anwendung!!!)
incl. Analyse des erzeugten Assembler-Codes
2. gründlicher Schreibtischtest durch erfahrene aber unvoreingenommene
Kollegen
3. Kompilation und Test mit anderen (möglichst ohne) Optimierungen
.
.
.
Das sind alles Dinge, die Zeit brauchen. Diese Zeit hat man
üblicherweise nicht, man nimmt sie sich!
Ich wünsche Dir viel Erfog (und das nötige Qentchen Glück)!
Bernhard
Markus wrote:
> Also wenn die 255 empfangen werden, dann ist es zu spät und sind schon> einige Fehler passiert. Uns wundert es, dass die Register der Anzahl> Datenbits während diesem ändert (Protokolliert mit diesen> zwischenvariablen) !!?!?
Variablen können durch nen wildgewordenen Pointer leicht überschrieben
werden.
Dein bischen Codeschnipsel nützt daher kaum was.
Ich bin zu 99,99% sicher, es ist ein Fehler in Deiner Software.
Die UART verwendet doch fast jeder, da müßte der Fehler schon längst
aufgefallen sein.
Poste dochmal nen kompletten Testcode, der den Fehler zeigt. Und da Du
nicht den AVR-GCC benutzt, auch das erzeugte Assemblerlisting (mit den
Codezeilen).
Peter
Hallo Markus,
ich nutze auch CAN auf dem AT90CAN128 und habe die von Dir beschriebenen
Probleme nicht gesehen. Was sagt der Support dazu? Am besten Du schickst
denen Deine Messungen (so wie oben von A.K. beschrieben) weil es könnte
auch an Deinem Schaltplan liegen.
Um 100% Fehler im Schaltplan auszuschließen, probier es auf dem EK
aus...
Hast Du eine abgespeckte Version Deines Codes?
Kannst Du wirklich ein Überschreiben der UART Register ausschließen? Wie
schließt Du das aus? -> Am besten Stack checken!! Stichwort:
Rekursivität.
Eventuell hast Du wirklich ein Problem im Schaltplan (schwankende
Spannungsversorgung...), und Dein uC macht ein Reset (je nachdem wie Du
POR programmierst) -> Registerwerte anders.
Also am besten wie A.K. geschrieben hat, Messungen machen, Schaltplan
rein etc.
MfG
Joe
Ich bin schon der zweite Kollege, der erste hat es auch nicht gefunden.
Und ich habe diese gesammt UART Routine sogar auch neu geschrieben.
HW haben auch schon mehrere Kollegen angeschaut und überprüft, mitsamt
EMV und Temperaturtests.
HW ist definitiv in Ordnung. Software auch. Wir kämpfen schon seit
Wochen! mit dem Problem.
Atmel mein, die Initialisierung ist in Ordnung. Anbei der RX-Interrupt
und der Main-Loop.
1
#ifdef __IAR_SYSTEMS_ICC__
2
#pragma vector=USART1_RX_vect
3
__interruptvoidUSART1_RX_interrupt(void)
4
#else
5
ISR(USART1_RX_vect)
6
#endif
7
{
8
9
// *DEBUG Test Echo auf COM 0 ausgeben
10
unsignedcharudr1;
11
unsignedcharucsr1a,ucsr1a2;
12
unsignedcharucsr1b,ucsr1b2;
13
unsignedcharucsr1c,ucsr1c2;
14
15
ucsr1a2=UCSR1A;
16
ucsr1b2=UCSR1B;
17
ucsr1c2=UCSR1C;
18
19
udr1=UDR1;
20
21
if(udr1==255)
22
{
23
ucsr1a=UCSR1A;
24
ucsr1b=UCSR1B;
25
ucsr1c=UCSR1C;
26
udr1--;
27
}
28
29
//while(!Uart_tx_ready());
30
UDR0=udr1;
31
32
if(udr1==4)
33
IsrUSART1_RxHead=0;// Start Zeichen Protokoll
34
else{
35
IsrUSART1_RxHead++;
36
if(IsrUSART1_RxHead>=USART1_RX_BUFFER_SIZE)
37
IsrUSART1_RxHead=0;
38
}
39
40
USART1_RxBuf[IsrUSART1_RxHead]=udr1;// Store received data in buffer, clear Status(!)
if(USART1_RxBuf[IsrUSART1_RxHead]!=0x0A)// LF - Ende Zeichen
20
return;
21
22
bOK=1;
23
for(i=0;i<L_CT;i++)
24
if(USART1_RxBuf[i]!=cT1[i])
25
{
26
bOK=0;
27
break;
28
}
29
if(!bOK)
30
{
31
bOK=2;
32
for(i=0;i<L_CT;i++)
33
if(USART1_RxBuf[i]!=cT2[i])
34
{
35
bOK=0;
36
break;
37
}
38
}
39
if(!bOK)
40
{
41
bOK=3;
42
for(i=0;i<L_CT;i++)
43
if(USART1_RxBuf[i]!=cT3[i])
44
{
45
bOK=0;
46
break;
47
}
48
}
49
IsrUSART1_RxHead=0;
50
switch(bOK)
51
{
52
case1:
53
WriteToCommPath(1,L_CA,(UCHAR*)cA1);
54
break;
55
case2:
56
WriteToCommPath(1,L_CA,(UCHAR*)cA2);
57
break;
58
case3:
59
WriteToCommPath(1,L_CA,(UCHAR*)cA3);
60
break;
61
}
62
}
63
}
Es gibt immer drei Unterschirdliche Telegramme vom PC (cTx[]). Die
werden erkannt dann gibt es dazu die entsprechenden Dummy-Antworten
(cAx[]).
Diese Funktion "Test_Mm" wird in der Main while(1) - Schleife endlos
aufgerufen. Mehr gibt es nicht.
"WriteToCommPath" sendet den Buffer nur noch raus, mit dem Senden hab
ich keine Probleme, das tut.
Der UART-Interrupt zeigt folgende Register:
:: Interrupt Start
UCSR1A = 0x03
UCSR1B = 0x00
UCSR1C = 0x26
RDAT = 0xFF
UCSR1A = 0xB8
UCSR1B = 0xB8
UCSR1C = 0x6F
:: Pause mit Breakpoint.
Woher sollen diese komische Zahlen kommen? Ich meine warum Ändert der
Prozessor so die Bits in diesen Registern? z.B. 9-Bit-Übertragung
aktiviert?
Der Code ist genau so wie oben gepostet, es gibt nur noch den
TX-Interrupt sonst nichts mehr, kein anderer Interrupt ist aktiv, der in
diesen Interrupt reinspucken könnte.
Und: ZEIT haben wir schon mehrere WOCHEN und mehrere PERSONEN
reingesteckt!
Hallo UART-Freunde,
die Fehler sind normal ! Jeder, der etwas gegen diese
Frickelschnittstelle hat, kennt dieses Problem. Oft steht es auch im
Handbuch und nennt sich Fehlerrate. Versuch doch mal den Prozessor bzw.
externen Quarz mit Eisspray zu Ärgern.
Grüße,
UART-Hasser.
Rekapituliert:
- Controller ist ok (sagt Atmel),
- Hardware ist ok (sagst du),
- Programm ist ok (sagst du),
also hast du entweder kein Problem oder mindestens eine der Aussagen ist
falsch. Nimm's mir also nicht übel, wenn ich die Aussagen in Frage
stelle (und ebenso Atmel).
Hast du den Code auch mal ohne Optimierung übersetzt? Wenn du die
Variablen mit den Debugger ansiehst, dann kann dabei alles mögliche
passieren, denn diese ucsr1* Variablen sind lokal und werden aus Sicht
des Compilers nicht wirklich verwendet, sind also komplett überflüssig
und werden möglicherweise wegoptimiert. Was der Debugger vielleicht
nicht weiss. Mach die mal global und "volatile".
Markus wrote:
> Anbei der RX-Interrupt> und der Main-Loop.
Was soll denn das wieder, diese Schnipselchen?
Und wozu denkst Du, ist der Dateianhang da?
Da ist nirgends das Main.
Und alle Initialisierungen fehlen auch.
Wenn Du Hilfe willst, dann ist ein kompilierbares Programm das absolute
Minimum.
> Der UART-Interrupt zeigt folgende Register:> :: Interrupt Start> UCSR1A = 0x03> UCSR1B = 0x00> UCSR1C = 0x26> RDAT = 0xFF> UCSR1A = 0xB8> UCSR1B = 0xB8> UCSR1C = 0x6F
Das ergibt überhaupt keinen Sinn, d.h. Du solltest die Fehlersuche
ausweiten und woanders suchen.
Denke mal über Murphys Gesetz nach:
Der Fehler ist nie da, wo man ihn sucht, sondern in genau dem
Programmteil, den man als 100%-ig funktionierend von der Fehlersuche
ausgeschlossen hat.
Frage andere Programmierer, jeder kann Dir mindestens einen Fall nennen,
wo dieses Gesetzt gestimmt hat.
Meistens sinds Kleinigkeiten (fehlende oder falsche Defines, Includes,
ein ";" zuviel, "{}" zu wenig, "=" statt "==" usw.).
Peter
Wie wird die UART initialisiert?
Welche Übertragungsparameter?
Kann es sein, dass es zu Paritätsfehlern kommt, und Deine Interrupt
Routine das nicht auswertet?
Kannst Du das ganze Programm posten, mit main() usw?
Ich musste weg, ich kann andere Einstellungen/Tests erst wieder am
Montag machen...
Wie schon oben beschrieben, es gibt nur noch die Main mit der While(1)
zu Test_Mm. Wofür soll ich das posten?.
Das Projekt ist natütlich wesentlich umfangreicher, aber alles komplett
auskommentiert.
Die Initialisierung des UARTs ist richtig, das hat Atmel bestätigt.
Die Variabeln
1
unsignedcharucsr1a,ucsr1a2;
2
unsignedcharucsr1b,ucsr1b2;
3
unsignedcharucsr1c,ucsr1c2;
Legt der Compiller auf interne Register und werden nicht "wegoptimiert",
im Breakpoint kann ich die dann sehen!
Hallo Markus,
mach uns doch trotzdem bitte den Quellcode rein, wenn alles
auskommentiert ist dann lösch das alles weg so daß wir einen lauffähigen
Code bekommen nur mit der Main, der Init, der ISR und Deiner Testroutine
nix mehr. Wenn der Code so umfangreich ist, dann kann auch Atmel etwas
übersehen haben, erst recht wenn das ein fremder Code ist (nutzt Du
Macros? Da übersieht man immer mal was). Wenn Du schreibst dass vorher
schon jem. anders da dran gearbeitet hat, jetzt Du das übernommen hast
dann weißt Du bestimmt dass es nicht einfach ist sich im fremden Code
zurechtzufinden.
Du tust auch Dir einen gefallen wenn Du eine simple Testroutine hast und
nicht ständig zwischen den Kommentaren lesen mußt. Also am besten alles
in 2-3 Dateien packen, kompilieren (ohne Optimierungen) und nochmal
testen. Dann uns das kompilierfähige Projekt posten (dann mußt Du keine
Angst haben dass die jem. den Code klaut ;-) es ist dann ja nur ne
simple UART Ansteuerung und wir sehen den "auskommentierten" Code
nicht).
Wenn Du es schaffst das doch noch heute zu machen, können wir am
Wochenende mal nen Blick drauf werfen :)
Viele Grüße
Joe
Markus wrote:
> Wie schon oben beschrieben, es gibt nur noch die Main mit der While(1)> zu Test_Mm. Wofür soll ich das posten?.
Wie schon gesagt, weil alles den Fehler beinhalten kann.
Man weiß erst dann, wo wirklich der Fehler steckt, wenn man ihn
beseitigt hat.
Vorher sind alles nur vage Vermutungen, z.B. das mit der UART.
> Das Projekt ist natütlich wesentlich umfangreicher, aber alles komplett> auskommentiert.
Dann kommentier nicht aus, sondern lösche es.
Und ja, das kann ein Unterschied sein.
> Die Initialisierung des UARTs ist richtig, das hat Atmel bestätigt.
Warum dann diese Geheimniskrämerei?
Woher sollen wir wissen, ob Deine Registerausgaben dazu passen?
Peter
Hast Du vielleicht die Möglichkeit, USART0 anstatt USART1 zu verwenden?
9600Bd sind eigentlich kein Thema. Kann es dennoch sein, daß irgendwo
der Interrupt zu lange blockiert wird?
Den kompletten Code hier einzustellen, wird nicht viel bringen. Den
verwendeten IAR-Compiler benutzen wohl kaum welche; das sind nämlich die
Bösen :-)
Ich hab diesen bösen Compiler ;-)
Wenn man einen Code von jem. übernimmt und eine Peripherie funktioniert
nicht, dann macht man erstmal saubere Sache. Alles weg, ganz weg aus den
Augen den vor lauter Zeichen sieht man den Code nicht mehr. Einfach nur
die Routine drin die Fehler macht, nix anderes. Wenn dann soweit ist,
kann man diesen "sauberen" Code mit anderen Teilen. Dann vermeidet man
auch die Diskussion "poste noch das" und "poste dann das hier". Es ist
einfach alles verfügbar und es gibt eine Basis. Dann kann man
weitersehen.
Also nochmal, alles aufräumen, kompilierfähiges Projekt posten. Je
weniger Dateien, je kürzer der Code desto besser für uns welche den Code
erstmal verstehen müssen. Also wenn ich mir schon die Arbeit machen
will, dann will ich nicht erstmal betteln müssen dies und das zu
bekommen und mich rechtfertigen warum ich das trotzdem sehen will (wie
A.K. und Peter das machen) denn ich möchte doch für den Markus den Code
debuggen da kann ich 100000 Zeilen auskommentierten Code einfach nicht
brauchen....
> Alles weg, ganz weg aus den Augen den vor lauter Zeichen sieht> man den Code nicht mehr. Einfach nur die Routine drin die> Fehler macht, nix anderes.
Bei diesen Gelegenheiten macht sich ein Versionsverwaltungssystem wie
CVS bezahlt. Man kann einfach einen Ast anlegen, den zu testenden Code
putzen, manche Teile ganz löschen und trotzdem bleibt alles erhalten.
Außerdem kann man besser und schlechter funktionierende Versionen
einfach vergleichen.
Sorry, aber wenn ich schon Wochen an etwas rumteste, dann habe ich schon
laengst eine minimalisierte Testversion, die sich auf genau das
konzentriert, was getestet werden soll.
Das erste, was ich hier schreiben wuerde, waere ein Sender, der ein
festes Muster schickt und ein Empfaenger, der genau dieses Muster
erwartet und ueberprueft.
Btw, wer i als Variablennamen benutzt, hat's nicht anders verdient.
Der Fehler tritt eben nur alle paar Stunden auf, daher wurde immer mehr
abgespeckt und und und... Tausende Abfragen (jede Sekunde 3 Stück)
funktionieren, und dann auf einmal nicht mehr. Manchmal kommt der Fehler
erst nach 6 Stunden!
>Btw, wer i als Variablennamen benutzt, hat's nicht anders verdient.
Was soll das?? In einer kleinen For-Schleife nutze ich immer i, zumal
die Variable nicht mehr als 5 Codezeilen ihre Gültigkeit hat!
Andere Variablen, je nach Gültigkeitsdauer erhalten auch
aussagekräftigere Bezeichnungen.
Markus,
ich warte auf den Code und die Messungen beim Fehlerfall.
@all:
Den Programmierstil eines einzelnen müssen wir hier nicht diskutieren.
Konzentrieren wir uns doch einfach auf den Fehler.
2 allgemeine Debughilfen:
- installiere einen Bad-ISR-Handler (freigegebene ISRs ohne Handler).
- installiere eine Routine zur Ausgabe der Stackbelastung (ist
compilerabhängig).
Peter
Hallo,
@Peter Da.
Inwiefern kann es einen Unterschied machen ob ich einen Code
auskommentiere oder lösche? Oder denkst du eher daran das man etwas
vergessen hat auszukommentieren?
Gruß
Peter
UCSR1A = 0x03 0b00000011 U2X1 = 1 MPCM1 = 1
UCSR1B = 0x00 keine Interrupts an, nichts
UCSR1C = 0x26 0b00100110, even parity, 1 stop bit, character size = 8
MPCM Protocol 17.10.1
"If 5- to 8-bit character frames are used, the Transmitter must be set
to use two stop bit (USBSn = 1) since the first stop bit is used for
indicating the frame type."
Wenn du den Code rauslöschst musst du dir (und vor allem wir uns) keine
Gedanken darüber machen, ob beim Auskommentieren etwas schiefgegangen
sein könnte. Geschachtelte Kommentare entstehen schnell und bei vielen
IDEs ist das Syntax-Highlighting nicht perfekt.
Nimm's einfach raus, geht schnell, hat keine Nachteile, erhöht die
Lesbarkeit und entfernt eine potenzielle Fehlerquelle und ist ein
Standardarbeitsschritt, wenn man nicht mehr weiter weiß...
Markus wrote:
>>Btw, wer i als Variablennamen benutzt, hat's nicht anders verdient.> Was soll das??
Was soll ein ordentlicher, uebersichtlicher Code? Jede Variable hat eine
Bedeutung und der Code ist wesentlich leichter lesbar, wenn sich diese
Bedeutung im Namen widerspiegelt. Bei i hoert es ja nicht auf, Namen wie
L_CT, cT2 versteht auf Anhieb kein Mensch - und du auch nicht, wenn du
irgendwann mal den Code nach laengerer Pause wieder warten musst.
Klammern sparen faellt in das gleiche Muster - das geht 99 mal gut und
beim 100ten mal uebersiehst du halt doch, dass die for-Schleife nicht da
endet, wo du glaubst.
Dass du nach so vielen Wochen immer noch kein explizites Testprogramm
hast, sondern eine teilweise auskommentierte Codewueste, wundert mich da
nicht. So wirst du dem Problem nicht auf die Spur kommen und bei Atmel
investiert ganz sicher auch niemand viel Zeit fuer dich, wenn du das
Problem nicht wirklich bis auf das Minimum runterbrichst.
Sorry, aber es sind immer die "coolen"
"Ich-weiss-was-ich-tue"-Entwickler die sich die ueblen und peinlichen
Bugs einfangen und beim Review nachher so klein mit Hut sind. 90% der
Softwareentwicklung ist eine Frage von Stil und Disziplin.
@Peter Stegemann
Wie ich schon oben geschrieben habe, ich bin der zweite programmierer,
der hier das Problem versucht zu lößen. Die Routine "Test_Mm" dient nur
zum Test und ist ein Mini-Programm, so auch die Variabeln drumherum.
Wiso soll ich in solch einen Code einen ordentlichen Aufwand stecken,
wenn der sowiso wieder gelöscht wird und nur zu einem schnellen Test
dient?
Nur weil ich den Variablen bessere Namen gebe funktioniert das ganze
trozdem nicht besser. Und: Ich nutze den IAR, wenn der tatsächlich Code
als Auskommentiert darstellt und trozdem erzeugt, dann würde wohl IAR
schon lange vom Markt verschwunden sein.
@All:
Die Frage ist viel mehr:
Wenn ich alles für Atmel Mundgerecht aufbereite dann ist das mindestens
eine bis zwei Wochen Arbeit, mit dem ganzen
Schriftverkehr/Besprechungen. Wenn das programm dann immer noch nicht
geht bleiben wir auf der Ar...-Karte sitzen.
Wenn ich gleich einen anderen Prozessor einsetze, z.B. einen
ordentlichen Cortex, dann habe ich auch Aufwand, der zwar größer ist,
aber dafür ist der Prozessor um 50% günstiger und für das ganze
funktioniert! (>> preiserspanrins in der Serie)
Wenn hier jemand solch ein exotisches Problem schon mal hatte und dann
z.B. sowas wie "Telegrammsicherheit" und "Resend des Telegramms"
einbauen musste, dann ist das auch ein Hinweis auf das oben beschriebene
Problem. (Unser eigentlicher Schnittstellen-Protokollkonverter ist
Fehlertollerant, aber der Kunde möchte den Ab- und Zu Fehler nicht mehr
sehen. Tatsächlich kam der Fehler ca. 1 mal die Woche im Anlagenbetrieb
vor.)
Ja, es ist mit unterschiedlichen HW-Modulen / Umgebungsbedingungen
reproduzierbar.
@Markus
>>Wie ich schon oben geschrieben habe, ich bin der zweite programmierer,>>der hier das Problem versucht zu lößen. Die Routine "Test_Mm" dient nur>>zum Test und ist ein Mini-Programm, so auch die Variabeln drumherum.>>Wiso soll ich in solch einen Code einen ordentlichen Aufwand stecken,>>wenn der sowiso wieder gelöscht wird und nur zu einem schnellen Test>>dient?
Nach Deinen bisherigen Schilderungen dreht es sich um ein ernsthaftes
schwer zu debuggendes Problem, nicht um eine Kleinigkeit, die man - um
Dich zu zitieren - mit einem "schnellen Test" mal eben so nebenbei
findet!
Du widersprichst Dir hier also massiv und führst damit den Aufwand der
übrigen Poster ad absurdum!
Wie sieht denn der generierte Assembler-Code aus? Hast Du den schon mal
angesehen?
Dieser Assemblercode gehört übrigens ebenfalls zu den am Montag
abzuliefernden Dateien.
Bernhard
Markus wrote:
> Wenn ich gleich einen anderen Prozessor einsetze, z.B. einen> ordentlichen Cortex, dann habe ich auch Aufwand, der zwar größer ist,> aber dafür ist der Prozessor um 50% günstiger und für das ganze> funktioniert! (>> preiserspanrins in der Serie)
Und woher nimmst Du die Gewißheit, daß der Fehler auf nem anderen
Prozessor wie von Geisterhand plötzlich verschwunden sein soll?
Software richtet sich aber nicht nach dem Wunschdenken des Entwicklers.
Der Fehler ist erst weg, wenn man ihn gefunden hat.
Das Register plötzlich unsinnige Werte haben sollen, riecht 10 Meilen
gegen den Wind nach Software.
> Wenn hier jemand solch ein exotisches Problem schon mal hatte
Ich wüßte nicht.
Ein Protokoll und ne CRC kann aber nichts schaden. Die Teilnehmer können
ja zu unterschiedlichen Zeiten eingeschaltet worden sein oder das Kabel
gesteckt worden sein.
Eine galvanische Trennung ist auch zu empfehlen bei größeren
Entfernungen, um Erdschleifen aufzutrennen.
Wir benutzen z.B. CAN-Bus und der ist an jedem Gerät optisch entkoppelt.
Peter
Der UART ist mit Optokoppler, galvanischer Trennung und RS485
ausgestattet.
(Ich hatte das auch schon weg und einen TTL-V24 Wandler (MAX232) dran um
ein HW Problem auszuschließen)
Ich frage mich mittlerweile was du mit dem Thread eigentlich bezweckst.
Wenn du damit herausfinden wolltest, ob andere das Problem schon kennen:
offensichtlich nicht. Und UART Kommunikation wird ja mit AVRs nicht erst
sei gestern durchgeführt.
Atmel wiederum kann nur dann eine schnelle Antwort ohne allzu viele
Rückfragen geben, wenn ein derartiges Problem bereits bekannt ist.
Wonach es also nicht aussieht. Und eine Fehlersuche ist nun einmal ein
gründliches Unterfangen in dem nicht nach Treu und Glauben vorgegangen
wird, sondern Annahmen und Behauptungen wenig zählen. Dass dies nicht in
2 Wochen über die Bühne gehen kann sollte klar sein. Sich darüber zu
beschweren, dass Atmel solides Material haben will, erscheint mir etwas
befremdlich. Was erwartest du von Atmel denn eigentlich? Wunder?
Jede hier präsentierte Ansatz, dem Problem zu Leibe zu rücken, wird von
dir mit der Begründung abgelehnt, es hätten sich schon mehrere Leute
wochenlang damit befasst. Ohne darauf weiter einzugehen oder gar
irgendwelche Details zu nennen. Auf dieser Basis sind Diskussionen wenig
sinnvoll.
Also: Was willst du eigentlich? Dass du frustriert bist verstehe ich.
Aber einer Lösung kommst du so nicht näher.
Montag kann ich den Code verkleinern und dann posten. Vieleicht findet
jemand dann doch ein Problem in der SW. Dann wäre mir geholfen. Sorry,
dass ich den Code heute nicht mehr schicken kann, was wohl alle die mir
hier helfen wollen ausbremst.
Hast du mal versucht das Programm auf einem ähnlichen Chip auszuführen
(z.B. ATmega16A, ATmega162)? Der USART-Kram sollte darauf ja auch
problemlos laufen. Verschwindet das Problem dadurch, so wird ein Bug im
Controller zumindest wahrscheinlicher.
Alternativ würde ich vielleicht mal einen Code hier aus dem Forum
ausprobieren (AVR-Tutorial: UART) - die haben sich schon x-mal
bewährt. Damit sollte sich ein etwaiges Software-Problem eingrenzen
lassen.
Happy hunting - das Mistvieh kriegen wir ;)
Anbei wie versprochen das Projekt. Im ZIP:
- IAR Projekt
- Test-EXE (Bedienung selbsterklärend)
- RTF-Datei, die einen Fehler zeigt.
Bitte keine Kommentare abgeben, bezüglich wie ich die zig Dateien klein
bekommen habe. Alle möglichen Defines waren in Dateien Verteilt, die hab
ich in wenige Dateien zusammengelegt. OK?
Danke für eure Unterstützung.
>Dazu den Datenverkehr mit einem anderen AVR mitlesen und sehen, ob der>zuverlässig arbeitet und ob das Problem damit erledigt ist.>Hast Du vielleicht die Möglichkeit, USART0 anstatt USART1 zu verwenden?>9600Bd sind eigentlich kein Thema. Kann es dennoch sein, daß irgendwo>der Interrupt zu lange blockiert wird?>Hast du mal versucht das Programm auf einem ähnlichen Chip auszuführen>(z.B. ATmega16A, ATmega162)?
Jemals etwas davon gemacht?
Das ist doch immer noch keine vernuenftige, minimale Testimplementation.
Die Testroutine ist voellig kommentarfrei, vom Rest viel auf Deutsch
kommentiert, die Files immer noch mit irgendwelchem Zeug vermuellt, das
offensichtlich aus irgendeiner groesseren Geschichte stammt - schick das
so zu Atmel, das landet direkt im Muelleimer.
Also, da ist wirklich zu hoffen, dass die Anlage in der das läuft nicht
ein Kernkraftwerk ist ...
Trotzdem:
1) Im Prinzip empfängt Dein Testprogramm nur 3 verschiedene Telegramme.
Was ist so schwierig daran, in der ISR einen Vergleich mit den
Sollwerten einzubauen und bei einer Abweichung ein Pin zu setzen das ein
Oszi triggert?
2) Du verwendest Parity even. Im ganzen Programm ist keine
Fehlerbehandlung für einen Paritätsfehler vorgesehen.
3) Das Programm schaut danach aus, als ob die serielle Leitung selbst
mit Half-Duplex läuft, da Du die Richtung umschaltest. Kann dort
irgendwo der Fehler liegen?
@Gast (Gast): Dazu habe ich im derzeit leider keine Möglichkeit
@Peter Stegemann (pst): Siehe mein Post vom 03.11.2008 11:15, 3.
Abschnitt.
@Klaus Falser (kfalser):
1) hab ich schon, in Form der Echo-Ausgabe auch den anderen COM Port.
Dann nämlich tut der auch keine Antwort schicken.
2) normal läuft das ohne Parity. Habs nur so zum Test mal umgestellt.
3) RS485, hab's mit Oszi geprüft, Umschaltung funktioniert immer sauber.
Ein Oszi kann ich hier nicht anschließen, das Telegramm wird vom
Prozessor immer am Ende ausgewertet. Dann sind die "Falschen Zeichen"
schon vorbei.
Ich habe den Datenstrom mit einem extra Terminalprogramm aufgezeichnet,
daran sehe ich dass die Daten korrekt über die Datenleitungen gehen,
ansonsten würde der ja auch das falsche aufzeichnen.
Hat schon mal jemand die Software in einen Atmel eingespielt und mit
meinem Programm geprüft?
> Ein Oszi kann ich hier nicht anschließen, das Telegramm wird vom> Prozessor immer am Ende ausgewertet. Dann sind die "Falschen Zeichen"> schon vorbei.
Da haben wir uns nicht verstanden.
Wen Du die Auswertung in der ISR machst (was leicht möglich ist, da Du
nur 3 verschiedene Telegramme empfängst, die sich kaum unterscheiden),
kannst Du in der ISR ein Pin setzen.
Ein besseres Speicheroszi kann dann sofort triggern und die letzen
Millisekunden anzeigen.
> Ein Oszi kann ich hier nicht anschließen, das Telegramm wird vom
Prozessor immer am Ende ausgewertet. Dann sind die "Falschen Zeichen"
schon vorbei.
Ja und? Dafür gibt's Speicheroszis (digitale Oszis) oder Logikanalyzer.
(Aber vermutlich hat er den Fehler schon gefunden und schämt sich..)
Ich hab diesen Thread erst jetzt gerade gefunden und wundere mich schon
darüber, dass die Variablen im ISR nicht als volatile gekennzeichnet
sind.
Wenn man separate Register dafür haben will, sollte man sich nicht auf
den Compiler verlassen, sondern register uint8_t oder ähnliches
verwenden, damit das auch alles so ist, wie man es will und nicht hoffen
muss.
Wenigstens wurde das volatile im übermittelten Code schon mal
eingepflegt.
Dann fällt auf, dass MCPM bei 8-Bit gewählt wurde. Soll das so? Warum
MCPM bei nur zwei Teilnehmern?
Des weiteren fällt auf, dass der TXC Interrupt, der immer dann ausgelöst
wird, wenn das letzte Stop-Bit aus dem TX-FiFo versendet wurde, einges
tut, was dort meines Erachtens nichts zu suchen hat. Ich habe jetzt
nicht im Kopf alle Varianten einer möglichen Race-Condition ausgetüftelt
und habe auch keine AT90CAN zur Verfügung, aber meine RS485
Tranceiver-Routinen sehen erheblich einfacher aus.
Es gibt im AVR zwei für das Senden wichtige Flags, die separate
Interrupts auslösen, wenn man Software-geschaltete RS485 Interfaces
verwendet:
Gegenüber einem voll-duplex RS232/RS422 muss dabei die übliche Software
für einen UDRE-Interrupt nach dem letzten Zeichen den TXC Interrupt
einschalten.
Der TXC-Interrupt wiederum schaltet lediglich den RS485-Tranceiver
wieder auf RX um und deaktiviert sich selbst.
Also sieht meine RS485 folgendermaßen aus:
putc_485(c) schaltet auf RS485TX_Enable, Zeichen in die Queue,
UDRE-Interrupt aktivieren.
Da das UDR Register leer ist, ist UDRE gesetzt und ein aktivieren des
Interrupts löst diesen auch gleich aus.
Wurde der UDRE-Interrupt durch das letzte Zeichen aus der Queue
aktiviert, ist dieses ja bereits im FIFO, hier deaktiviert sich der
UDRE-Interrupt also selbst, aktiviert aber noch den TXC Interrupt.
Der TXC-Interrupt schaltet dann lediglich RS485TX_Disable() und sich
selbst aus.
++++++++++*Achtung*++++++++
Die vorhandene Implementation führt zu einem seltsamen Verhalten in
exakt dem Fall, dass nach Ablauf des UDRE Interrupt und Aktivierung des
TXC-Interrupts ein weiteres Zeichen in die Queue geschrieben wird.
Dieses Zeichen kann nach Lust und Laune entweder durch den neu
aktivierten UDRE-Interrupt oder den gerade angesprungenen TXC Interrupt
behandelt werden.
Wurde der TXC ein oder zwei Cycles vorher ausgelöst, kann der UDRE
Interrupt nicht mehr dazwischen kommen und das Zeichen wird durch den
TXC Interrupt behandelt. Damit löst der TXC-Interrupt sich selbst gleich
noch einmal aus. Da das UDRE nun aber ebenfalls kommt, der UDRE aber
kein Zeichen mehr vorfindet, schaltet er TXC wieder frei. Damit kann es
leicht passieren, dass unendlich auf eine weitere TXC Situation gewartet
wird. Dadurch wird der TXC Interrupt nach dem ersten Zeichen des
folgenden Blockes ausgelöst, was dann wiederum zu jede Menge 0xFF führt,
weil
der Treiber des RS485 bereits wieder auf Empfang steht.
Dadurch, dass der TXC-Irq Zeichen selbst behandeln kann und die Richtung
des RS485 Treibers nicht immer umstellt, ist letztere also vom Zufall
abhängig.
++++++++++++++++++
Grundsätzlich sollten ISRs immer so kurz wie möglich sein, also bitte
bei der Aktivierung von RS485RX/TX nicht immer noch die DDRx mit
umschalten.
Das Auslesen der UCSRx Register habe ich nicht verstanden, weil diese
Register einmal als Puffer für den Status / das Setup genutzt werden,
dann wiederum werden sie inkrementiert...
Wahrscheinlich habe ich hier jetzt allgemein Bekanntes geschrieben, aber
vielleicht hilft es ja, die Sache mal systematisch zu betrachten. Ich
weiß, dass es nach 2 Wochen Suchen auch bei den offensichtlichsten
Fehlern kaum Hoffnung gibt, man sieht sie einfach nicht. Das ist
menschlich.
Gruß, Ulrich
@Ulrich P.
Vielen Dank für die Ausführliche Antwort. Ich werde es mit meinem
Kollege durcharbeiten.
>Das Auslesen der UCSRx Register habe ich nicht verstanden, weil diese>Register einmal als Puffer für den Status / das Setup genutzt werden,>dann wiederum werden sie inkrementiert...
Das hab ich nur zum Debuggen einprogrammiert, das Inkrementiert sind
einfach nur Zeilen um einen Breakpoint zu setzen.
PS: Ich war im Urlaub, daher die Funkstille.