Hallo! Nach langer Fehlersuche habe ich mich entschieden die Frage ans Forum zu stellen. Ich habe ein Crumb644 mit einem ATmega644PA und 14.7456 MHz Quarz. Auf der Platine ist USART0 mit dem USB-Seriell-Wandler verbunden und USART1 an einem RS485 Konverterchip. Der USART1 empfängt froh Daten vom RS485 die auch richtig ankommen. Konfiguration: 9600 8N2 (ja, 8N zwei) Mein Problem ist, dass nachvollziehbar immer nach ca. 2 Minuten auf USART1 in der RX ISR nur noch Bytes mit "0" in UDR1 ankommen - obwohl auf dem Scope am Pin des Controllers eindeutig die richtigen Daten anliegen. Erratas scheint es für den 644PA nicht zu geben, Datenblatt habe ich schon durchforstet, Code aufs notwendigste ausgedünnt, alles kein Erfolg. Im Fehlerfall steht in UCSR1A der Wert 0x30 (UDRE1 und FE1 gesetzt) und in UCSR1B der Wert 0x98 FE1 kommt daher weil auf dem Bus einige Geräte anstelle 2 Stop-Bits nur eines senden. IMHO kann das ignoriert werden. Habt Ihr mal ähnliche Erfahrungen gemacht, ist das vielleicht irgendein Bug in Hardware oder muss ich den Fehler in der Software suchen? Bin gerade etwas ratlos. Grüße, Bernhard
Bernhard schrieb: > in der RX ISR nur noch Bytes mit "0" in UDR1 ankommen Wie hast du das kontrolliert? Die ISR wird aber noch zuverlässig pro Zeichen 1 mal aufgerufen? > ist das vielleicht irgendein Bug in Hardware Die RX-ISR wird ja nur dann angesprungen, wenn die Hardware ein Byte tatsächlich (merh oder weniger) empfangen hat. Prüfst du auch die Fehlerflags des UART? > oder muss ich den Fehler in der Software suchen? Wenn auf der Hardware die Signale tatsächlich am Pin ankommen, dann würde ich sagen: Ja, such den Fehler in der Software.
:
Bearbeitet durch Moderator
> FE1 kommt daher weil auf dem Bus einige Geräte anstelle > 2 Stop-Bits nur eines senden. Das glaube ich nicht, aus dem Datenblatt zu FEn: "This bit is set if the next character in the receive buffer had a Frame Error when received. I.e., when the first stop bit of the next character in the receive buffer is zero." > IMHO kann das ignoriert werden. M.E. ist das FE1 ein wichtiger Fingerzeig.
Für den Empfang von Daten ist es nicht erforderlich, zwei Stopbits zu konfigurieren. Ändere das mal auf ein Stopbit und beobachte weiterhin das "framing error"-Bit. Mit den Stopbits kann es dann nichts mehr zu tun haben.
Das UART wertet nur das erste Stopbit aus. Die 2 Stopbits sind nur beim Senden relevant und sollen der Gegenseite mehr Zeit für die Reaktion geben bzw bei vielen unmittelbar aufeinander folgenden Bytes eine schnellere Synchronisation ermöglichen.
Zunächst Danke für Eure Antworten! @Lothar: So wird das kontrolliert:
1 | uint8_t data, stat; |
2 | |
3 | stat = UCSR1A; |
4 | data = UDR1; |
5 | |
6 | UDR0 = data; |
7 | |
8 | // hier werte ich die Fehlerflags aus
|
9 | // aktuell nur DOR1
|
USART0 läuft mit 115200bps, USART1 mit 9600 Von daher ist "UDR0 = data" so machbar ohne groß zu warten. Am PC lasse ich mir die empfangenen Daten als Hex ausgeben. @S. Landoldt: Beim letzten Test habe ich vor dem Fehlerfall auf dem RS485 1247 Telegramme (alle mit korrekter Prüfsumme usw.) erhalten. Darunter auch viele einzelne Bytes mit nur einem Stop-Bit. Bisher hatte ich auf allen meinen Geräten den RS485 auf USART0 und nie ein ähnliches Problem gehabt. Den Code habe ich portiert und mehrfach im Editor und per grep auf der Konsole sichergestellt dass überall die richtigen Register verwendet werden.
Bernhard schrieb: > USART0 läuft mit 115200bps, USART1 mit 9600 > Von daher ist "UDR0 = data" so machbar ohne groß zu warten. Du könntest ja trotzdem mal UDRE0 vorher abfragen, nicht, daß da doch was klemmt. Oliver
FEn heißt, dass der Empfänger auf dem ersten (!) Stopbit eine Null
sieht.
Lothar Miller schrieb:
> Wenn auf der Hardware die Signale tatsächlich am Pin ankommen
Die Betonung liegt auf 'am Pin'.
Guten Morgen, auch ist zu überprüfen, ob man senden über Uart0 darf. UCSR0A – USART Control and Status Register A Bits: RXC0 TXC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0 while ( (UCSR0A & (1<<UDRE0)) == 0 ) { } Das zeigt dieses Codestück nicht.
1 | uint8_t data, stat; |
2 | stat = UCSR1A; |
3 | data = UDR1; |
4 | UDR0 = data; |
Man könnte nun entgegen, dass die beiden Uart mit unterschiedlicher Baudrate arbeiten, aber man weis halt nicht wirklich, ob der Senderegister von Uart0 bereit ist neue Daten aufzunehmen ! Erst dachte ich es werden sauber Sende- und Empfangspuffer (Fifo) für beide Uart genutzt, aber nein, das UartN-Handling ist unsauber in meinen Augen.
@Oliver:
UDRE0 könnte man abfragen, ja. Trotzdem kommt die ISR von USART1 knapp
jede mS und dann hat USART0 schon längst alles im Hintergrund
verschickt.
Es kommen ja auch alle 1247 Telegramme korrekt am PC an, nur dann nur
noch Nuller.
@S. Landoldt:
FEn auf erstem Stopbit, richtig (gerade nachgelesen).
Die Ursache ist ein Gerät auf dem Bus was keine 2 Stopbits kann und das
dann per 9-Bit Übertragung emuliert. Firmware ist nicht von mir und den
Fehler kenne ich.
Gerät vom Bus abgeklemmt und siehe da - kein FE1 mehr.
Fehlerbild ist immernoch das gleiche. Gerade nach 700 Telegrammen.
> Die Betonung liegt auf 'am Pin'.
Nun, ich gehe davon aus dass die Lötstellen von der vorgefertigten
Platine in Ordnung sind und eine Messung ausreicht um sicherzustellen
dass die Bits aus Tatsächlich am Pin ankommen.
Nehmen wir den unwahrscheinlichen Fall dass die Verbindung nicht in
Ordnung ist, dann kommen entweder zufällige Daten an oder gar nichts.
Im Rhythmus der der Telegramme wird die ISR von USART1 aufgerufen und 0
aus UDR1 ausgelesen. Ohne dass überhaupt ein Takt am RXD1 anliegt würde
das doch nicht passieren, oder?
Nachtrag:
Auf mehrfachen Wunsch und trotz meines besseren Wissens habe ich nun den
Code wie folgt "sauber" abgeändert:
1 | uint8_t data, stat; |
2 | stat = UCSR1A; |
3 | data = UDR1; |
4 | loop_until_bit_is_set(UCSR0A, UDRE0); |
5 | UDR0 = data; |
Ergebnis: Bringt nix, gleiches Ergebnis - immernoch Nullen
Hallo Bernhard, für mich, bzw. die Fehlersuche, machst Du noch zu viele Annahmen. Ich habe gelernt noch nichts als gegeben aus zu gehen und selbst alle Verbindungen zu überprüfen und auch selbst für einen korrekten Code zu sorgen. Kannst Du bitte eine abgespecktes Programm, das einen mögl. Fehler immer noch zeigt, bitte komplett einstellen ? Mit komplett ist gemeint, dass unserer AVR Gcc diesen Quelltest auch übersetzt.
@Karl: Danke für Deine Unterstützung. In einer ISR mache ich ungern while Loops. Davor hatte ich ausgiebige Tests mit ner FIFO-Loop für USART0. Um das Thema nicht allzu aufzublähen habe ich das weggelassen. Vielleicht war das ein Fehler, ist aber jetzt nicht wichtig. Beispielcode: Ja, das ist das Ulitimo-Ratio - bisher will ich mir den Aufwand sparen. Hat denn irgendjemand schonmal ein ähnliches Problem gehabt? Das wäre spannend zu wissen. Wenn nicht dann muss ich einfach weiter in der Software nach einer möglichen Ursache suchen.
Hallo Bernhard , ich will nicht überheblich klingen, Probleme sollte man immer im Code suchen. Bei mir läuft Uart0 etc. immer problemlos. Ich verwende immer für den Hardware-Uart eine RX-/TX-Fifo gestützte Implementierung. Diese muss man nur einmalig richtig programmieren und kann sie dann als kleine Lib immer über ein Makefile und einer Inlcudedatei mit einbinden. Und so könnte das für Uart0 aussehen: Beitrag "AVR-GCC: UART mit FIFO"
Karl M. schrieb: > ich will nicht überheblich klingen, Probleme sollte man immer im Code > suchen. Klingt aber falsch. Was ist, wenn der Fehler in der HW steckt. Nicht notwendigerweise im µC aber im sonstigen Azfbau?
Null-Byte + Frame-Error deutet auf eine viel zu hohe Baudrate hin (Startbit wird als Byte abgetatet). Du solltest dann auch viel mehr Bytes empfangen (jede 1-0 Flanke). Irgendeine Task schaltet nach 2min die Baudrate um. Debugge mal das Baudratenregister.
@Peter: Vielen Dank für den Tipp! Das ist nämlich genau die Ursache für die Null-Bytes! Das UBRR1L Register wird auf 0 gesetzt und damit wird das Start-Bit als Byte abgetastet! Der Fehler lag natürlich auch in der Software - ein Copy-Paste Fehler in einem Array von verschiedenen Bus-Geschwindigkeiten war
1 | { .high = BAUD1_UBRR1H, .low = BAUD1_UBRR1H} |
... sollte eigentlich heißen:
1 | { .high = BAUD1_UBRR1H, .low = BAUD1_UBRR1L} |
Danke an alle für Eure Hilfe!
Das ist mir nicht klar, da sollte doch ein Frame-Error kommen. Wie passt das zu: Bernhard schrieb: > ... Firmware ist nicht von mir und den Fehler kenne ich. > Gerät vom Bus abgeklemmt und siehe da - kein FE1 mehr.
Was fuer einen Oszillator verwendest du, den internen RC, der mit der Temperatur weglaeuft ? Ja, ich hab vom Quarz gelesen, aber wurde der auch konfiguriert ? Ich wuerd einfach periodisch ein paar Bytes raussenden, und diesen dann mit einem Oszilloskop vermessen, und/oder mit dem PC empfangen.
@ S. Landoldt: FE1 bei normaler Funktion - hatte ich möglichereweise missverständlich formuliert. @ Oder Doch: Zuerst 20MHz Quarz, während Fehlersuche gegen 14.7456MHz getauscht. Daran lags sicher nicht :) Wie gesagt - Problem ist jetzt gelöst - danke nochmal!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.