Forum: Mikrocontroller und Digitale Elektronik AT90CAN128 UART Bug? Atmel rausschmeißen?


von Markus (Gast)


Lesenswert?

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?

von (prx) A. K. (prx)


Lesenswert?

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.

von Gast (Gast)


Lesenswert?

>Alle paar Stunden empfängt dieser Müll.

Zunächst würde ich ausschließen, daß kein Müll gesendet wird. Hast Du 
den Datenstrom extern überprüft?

von Gast (Gast)


Lesenswert?

Ich bin blöd! Hast Du ja geschrieben.

von (prx) A. K. (prx)


Lesenswert?

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.

von Gast (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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

von Bernhard R. (barnyhh)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Joe (Gast)


Lesenswert?

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

von Joe (Gast)


Lesenswert?

nochmal was vergessen: Eventuell kann auch der Compiler was falsch 
machen (sehr sehr selten) deshalb: alle Optimierungen aus.

MfG
Joe

von Markus (Gast)


Lesenswert?

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
  __interrupt void USART1_RX_interrupt( void )
4
#else
5
  ISR(USART1_RX_vect)
6
#endif
7
{
8
9
  // *DEBUG  Test Echo auf COM 0 ausgeben
10
  unsigned char udr1;
11
  unsigned char ucsr1a, ucsr1a2;
12
  unsigned char ucsr1b, ucsr1b2;
13
  unsigned char ucsr1c, 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(!)
41
  
42
  if (udr1 == 254)      
43
  {
44
    ucsr1a++;
45
    ucsr1b++;
46
    ucsr1c++;
47
    ucsr1a2++;
48
    ucsr1b2++;
49
    ucsr1c2++;
50
  }
51
}
1
const unsigned char cT1[] = {0x04, 0x30, 0x31, 0x31, 0x39, 0x54, 0x31, 0x30, 0x31, 0x30, 0x32, 0x31, 0x34, 0x30, 0x05, 0x0D, 0x0A};
2
const unsigned char cT2[] = {0x04, 0x30, 0x31, 0x31, 0x39, 0x54, 0x31, 0x30, 0x31, 0x30, 0x32, 0x31, 0x34, 0x31, 0x05, 0x0D, 0x0A};
3
const unsigned char cT3[] = {0x04, 0x30, 0x31, 0x31, 0x39, 0x54, 0x31, 0x30, 0x31, 0x30, 0x32, 0x31, 0x34, 0x32, 0x05, 0x0D, 0x0A};
4
5
const unsigned char cA1[] = {0x04, 0x30, 0x31, 0x31, 0x39, 0x54, 0x31, 0x30, 0x31, 0x30, 0x32, 0x30, 0x30, 0x31, 0x34, 0x30, 0x02, 0x3D, 0x30, 0x30, 0x30, 0x30, 0x3B, 0x03, 0x30, 0x34, 0x34, 0x35, 0x0D, 0x0A};
6
const unsigned char cA2[] = {0x04, 0x30, 0x31, 0x31, 0x39, 0x54, 0x31, 0x30, 0x31, 0x30, 0x32, 0x30, 0x30, 0x31, 0x34, 0x31, 0x02, 0x3D, 0x30, 0x30, 0x30, 0x30, 0x3B, 0x03, 0x30, 0x34, 0x34, 0x36, 0x0D, 0x0A};
7
const unsigned char cA3[] = {0x04, 0x30, 0x31, 0x31, 0x39, 0x54, 0x31, 0x30, 0x31, 0x30, 0x32, 0x30, 0x30, 0x31, 0x34, 0x32, 0x02, 0x3D, 0x30, 0x30, 0x30, 0x30, 0x3B, 0x03, 0x30, 0x34, 0x34, 0x37, 0x0D, 0x0A};
8
9
#define L_CT  (sizeof(cT1))
10
#define L_CA  (sizeof(cA1))
11
12
void Test_Mm(void)
13
{                                  
14
  if (IsrUSART1_RxHead >= (L_CT - 1))
15
  {     
16
    int i;                    
17
    unsigned char bOK;
18
    
19
    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
      case 1:               
53
        WriteToCommPath(1, L_CA, (UCHAR *)cA1);
54
        break;
55
      case 2:
56
        WriteToCommPath(1, L_CA, (UCHAR *)cA2);
57
        break;
58
      case 3:                    
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!

von LOL^ (Gast)


Lesenswert?

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.

von Sachich N. (dude) Benutzerseite


Lesenswert?

Was passiert denn wenn du Rx frei laesst?

von (prx) A. K. (prx)


Lesenswert?

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

von Markus (Gast)


Lesenswert?

Ja, und wieso sind vor und nach dem Lesen von UDR1 in dem Regsiter 
UCSR1x die Bits verdreht ?

von Klaus2 (Gast)


Lesenswert?

Gibts da keine Beispielappl von Atmel, die ihr mal testen könnt?

Klaus.

von (prx) A. K. (prx)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Klaus F. (kfalser)


Lesenswert?

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?

von Peter -NL (Gast)


Lesenswert?

- Hardware ist ok (sagst du),

Tritt es auf bei eine einzige HW (Prototyp), oder mehrere identische HW?

von Markus (Gast)


Lesenswert?

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
  unsigned char ucsr1a, ucsr1a2;
2
  unsigned char ucsr1b, ucsr1b2;
3
  unsigned char ucsr1c, ucsr1c2;
Legt der Compiller auf interne Register und werden nicht "wegoptimiert", 
im Breakpoint kann ich die dann sehen!

von Joe (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Gast (Gast)


Lesenswert?

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 :-)

von Joe (Gast)


Lesenswert?

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

von Klaus F. (kfalser)


Lesenswert?

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

von P. S. (Gast)


Lesenswert?

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.

von Markus (Gast)


Lesenswert?

Wie schon geschrieben, erst Montag kann ich den Code schicken...

von Markus (Gast)


Lesenswert?

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.

von Joe (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

2 allgemeine Debughilfen:

- installiere einen Bad-ISR-Handler (freigegebene ISRs ohne Handler).

- installiere eine Routine zur Ausgabe der Stackbelastung (ist 
compilerabhängig).


Peter

von Martin (Gast)


Lesenswert?

Wieviele  AT90CAN128 habt ihr getestet?
Gibt es Unterschiede?

von Peter (Gast)


Lesenswert?

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

von Arc N. (arc)


Lesenswert?

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

von Kai G. (runtimeterror)


Lesenswert?

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

von P. S. (Gast)


Lesenswert?

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.

von Peter -NL (Gast)


Lesenswert?

Ist beeindruckend das Könner, mit viel Geduld, weiterhelfen ...

von Markus (Gast)


Lesenswert?

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

von Bernhard R. (barnyhh)


Lesenswert?

@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

von Peter D. (peda)


Lesenswert?

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

von Markus (Gast)


Lesenswert?

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)

von (prx) A. K. (prx)


Lesenswert?

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.

von Markus (Gast)


Lesenswert?

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.

von Kai G. (runtimeterror)


Lesenswert?

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 ;)

von Markus (Gast)


Angehängte Dateien:

Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Disassembly-Listing fehlt.

von Markus (Gast)


Angehängte Dateien:

Lesenswert?

Anbei die Listings...

von Markus (Gast)


Lesenswert?

Ich kann auch gerne die Test-EXE für Linux kompillieren und posten, nur 
falls jemand Windows nicht benutzen mag...

von Gast (Gast)


Lesenswert?

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

von P. S. (Gast)


Lesenswert?

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.

von Klaus F. (kfalser)


Lesenswert?

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?

von Markus (Gast)


Lesenswert?

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

von Klaus F. (kfalser)


Lesenswert?

> 1) hab ich schon, in Form der Echo-Ausgabe auch den anderen COM Port.
> Dann nämlich tut der auch keine Antwort schicken.

Und, was zeigt das Oszi?

von Markus (Gast)


Lesenswert?

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?

von Klaus Falser (Gast)


Lesenswert?

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

von Sachich N. (dude) Benutzerseite


Lesenswert?

Und? Was ist jetzt?

von Bensch (Gast)


Lesenswert?

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

von Ulrich P. (uprinz)


Lesenswert?

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

von Markus (Gast)


Lesenswert?

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

von Lutz (Gast)


Lesenswert?

Nun solltest Du aber so laaangsam schon wieder drin sein ... Wie ist der 
Stand?

von Dino S. (Gast)


Lesenswert?

Vermutlich hat er jetzt einen anderen µC im Einsatz.
Die Fehler treten aber immer noch auf ;-)

von Martin K. (mkohler)


Lesenswert?

Bensch wrote:
> (Aber vermutlich hat er den Fehler schon gefunden und schämt sich..)
Treffer?

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.