Forum: Mikrocontroller und Digitale Elektronik RN Software UART und das Geheimnis der verlorenen Zeichen


von stinke (Gast)


Lesenswert?

Hallo!

Ich habe hier auf einem Atmega64 @ 16Mhz den Roboternetz
Software UART [1] zwar zum laufen bekommen, aber
wir haben das Problem, dass etwa 5-10% der Zeichen verloren
gehen und zwar unabhängig von der Baurdrate
(4800, 9600, 19200, 32k, 56k).
Das Kommunikationsprotokoll wurde zwar Fehlertollerant
gemacht (musste eh gemacht werden) was wieder so eigene
Probleme mit bringt => Herumdoktorn an Symthomen.

Das Problem tritt nicht auf wenn Zeichen rechnerseitig mit 1ms Delay
gesendet werden.

Ich habe alle tests mit einem AVR seitigen echo gemacht,
um ausschließen um andere Störquellen auszuschließen.

Hat jemand vieleicht eine Idee?

Zur Schaltung: Der Quarz ist auf der Rückseite der Platine
aufgebracht (Vias). Könnte dies, bei einer sonst Störungsfreien
Platine die Fehlerquelle sein? Ich kann es leider nur sehr sehr
schwer umbauen/testen.


MfG stinke

[1] http://www.roboternetz.de/wissen/index.php/Software-UART_mit_avr-gcc

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

stinke wrote:
> Hallo!
>
> Ich habe hier auf einem Atmega64 @ 16Mhz den Roboternetz
> Software UART [1] zwar zum laufen bekommen, aber
> wir haben das Problem, dass etwa 5-10% der Zeichen verloren
> gehen und zwar unabhängig von der Baurdrate
> (4800, 9600, 19200, 32k, 56k).

Die angegebene Info ist - vorsichtig ausgedrückt - etwas spärlich.

-- Werden die Zeichen in einer FIFO gepuffert?
-- Ist sicgergestellt, daß die FIFO nicht überläuft (ohne FIFO) hat 
diese effektiv eine Länge von 1 Zeichen)
-- Gibe es andere IRQs, welche die IRQ-Latenz in die Höhe schrauben?

Johann

von stinke (Gast)


Lesenswert?

Hallo Johann

Nein es gibt keine weiteren Interrupts.
Die FIFO (von RN) haben wir mal ausprobiert, aber diese lief
definitiv nicht über. Der Fehler hat sich nur dahingehend verändert,
dass mehr Zeichen verschluckt werden.

Ich denke also der Interrupt wird einfach zu langsam abgearbeitet,
aber kann das sein?
1
  suart_init(SUART_BAUD_SELECT(19200, F_CPU));
2
3
  sei();
4
5
  suart_puts("Ready...\n");
6
7
  int i = 0;
8
  while(1) {
9
    unsigned int sc = suart_getc_nowait();
10
    if(sc != QUEUE_EMPTY) {
11
      //uart_putc(sc);
12
      ++i;
13
      suart_putc(sc);
14
      if(sc == 'b') {
15
        suart_putc(i);
16
        i=0;
17
      }
18
    }
19
  }

Das ist im Prinzip das Programm. Bis eben noch auf den
gelinkten code in einer Datei. Magic byte für "Kein Zeichen"
und die Funktionsnamen wurden geändert. Es funktioniert,
nur die Details der Implementation
verstehe ich nicht ganz, zumindest nicht so, dass ich den
"Fehler" (dort oder bei mir) finden könnte.

Der Atmega64 ist mit den fuses
lfuse = 0xBE
hfuse = 0xC9
efuse = 0xFF

konfiguriert. Also externer Resonator, CKOPT, brown-out, kein JTAG
..?

MfG stinke

von stinke (Gast)


Lesenswert?

Achso,

suart_getc_nowait() oder suart_getc_wait() macht hier
keinen Unterschied.

Hier Ein- und Ausgaben:

Gesendet:
012345678901234567890123456789012345678901234567890123456789b

Empfangen:
01234567890123456789023456789023456789013456789013456789b9

Letztes Zeichen ist der Zähler i = 0x39 = 57 statt 61 (zzgl. 'b')

von stinke (Gast)


Lesenswert?

Achso,
der Fehler tritt immer bei den selben Zeichen, an der gleichen
Stelle auf. Ich kann das 100 mal wiederholen und es kommt
immer das gleiche Ergebnis heraus o_0

von stinke (Gast)


Lesenswert?

Sorry, nicht ganz exact

01234567890123456789023456789023456789013456789013456789b9
01234567890123456789023456789023456789013456789013456789b9
01234567890123456789023456789023456789013456789013456789b9
01234567890123456789023456789023456789023456789013456789b9
01234567890123456789023456789023456789013456789013456789b9
01234567890123456789023456789023456789023456789013456789b9
01234567890123456789023456789023456789013456789013456789b9
01234567890123456789123456789023456789023456789013456789b9
01234567890123456789023456789023456789013456789013456789b9
01234567890123456789123456789023456789023456789023456789b9
01234567890123456789023456789023456789013456789013456789b9

MfG Stinke

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ich würd mal testen, ob die Zeichen überhaupt ankommen, oder ob sie zu 
schnell gesendet werden. In dem Beispiel weiß man ja, was auf dem AVR zu 
erwarten ist.

Möglicherweise reicht die Bandbreite nicht für Full Duplex aus, schon 
mal Half Duplex versucht?

Ausserdem wird nicht atomar auf sc zugegriffen. Das ist ein Fehler - 
wenn auch in diesem Zusammenhang nicht ausschlaggebend, aber dennoch...

Johann

von stinke (Gast)


Lesenswert?

Dein schuss ins blaue war richtig.

Senden und empfangen wirft wohl das timing übern' Haufen.
Ohne Echo hab jetzt fast einen 100k block gesendet und die
Zeichen wurden alle samt richtig gezählt.

In unserer Anwendung tritt jedoch der Fehler natürlich weiterhin
auf weil wir natürlich senden müssen.

Gibt es hier überhaupt eine pratikable Lösung?

MfG stinke

von Peter D. (peda)


Lesenswert?

Ist natürlich schwer, was zu sagen, ohne den Code zu sehen.

Bei SW-UART sollte man generell ne FIFO nehmen, da man sonst nicht mal 
den 3-Byte Puffer der HW-UART hat. Es können also sehr leicht Zeichen 
verloren gehen.

Ein Beispielcode ist hier:

Beitrag "Software UART mit FIFO"

Ich hab damit bisher keine Probleme gehabt.

Längere Zeichenfolgen sollte man nicht mit Echo zurücksenden. Ist die 
Baudrate des AVR ein bischen langsamer als die des PC, fehlt irgendwann 
die Zeit.
Dieser Effekt kann ohne FIFO schnell auftreten (<100 Byte), mit FIFO 
nach >1000 Byte.


Peter

von Peter D. (peda)


Lesenswert?

Ich hab mal in den RN-Code geschaut, da sind 2 Probleme:

1.
1
    // OutputCompare für gewünschte Timer1 Frequenz 
2
    OCR1A = (uint16_t) ((uint32_t) F_CPU/BAUDRATE);

Damit sendest Du immer einen Takt zu langsam.

2.
Das Senden ist ohne FIFO, damit hast Du zusätzlich zwischen 2 Bytes eine 
Bitzeit Pause.


Peter

von stinke (Gast)


Lesenswert?

Hallo Peter,

Die Roboternetz SW-UART ist oben im link zu finden. Leider
sind die Kommentare nicht so aufschlussreich wie die
aus deiner alten SW-UART.
Ich habe schon festgestlelt  das TX anders gelöst wurde;
gerade lese ich mich in Timer ein. Neuland für mich.

Ich denke es würde helfen wenn TX _vect ist. Ich probiere das gleich mal
aus.
Habe auch gerade festgestellt das du das auch machst.
Danke für den Hinweis auf die neue Version/den neuen Thread.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Die uart_putc ist blockiered: Sie wartet so lange, bis das Byte gesendet 
werden kann. Hier mal ne nicht-blockierende Lösung versuchen. Durch das 
Blockeren verliert men evtl. empfangene Zeichen.

Eigentlich sollte das bei niedrigen Baudraten im Full Duplex gangbar 
sein; daher sicherstellen, daß die Blockierung nicht der Bösewicht ist.

Auch mal die Timer-Werte nachrechnen, welche Fehler sich durch Rundung 
wegen den 16 MHz ergeben. diese Frequemz ist nicht so schmackig für den 
UART wie zB 14.7456 MHz oder 18.432 MHz.

Die Hardware ist wie ich verstanden habe schon fertig? Da das Zeug aber 
noch nie (richtig) funktioniert hat, nehme ich mal an, es handelt sich 
dabei um nen Prototypen oder ne Nullserie.

Bei anderer Handware würd ich ne (Hardware-)Flußsteuerung vorsehen, 
damit der recht langsame Software-UART sich net verschluckt.

Ansonstend dünkt mich, daß da ein etwas seltsames Konzept am Werke ist. 
Der µC hat doch UART, sogar mehrere, wenn ich mich recht entsinne...

Johann

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Ich hab mal in den RN-Code geschaut, da sind 2 Probleme:
>
> 1.
>
1
>     // OutputCompare für gewünschte Timer1 Frequenz
2
>     OCR1A = (uint16_t) ((uint32_t) F_CPU/BAUDRATE);
3
>
>
> Damit sendest Du immer einen Takt zu langsam.
>

Sollten doch Peanuts sein, ob man einen Tick (bzw. ca 10 Ticks beim 
letzten Bit) zu langsam oder zu schnell ist. Oder? Zudem wird ohenhin 
abgerundet.

Viel drastischer wirkt sich ein Jitter aus, der durch eine andere 
IRQ/ISR ausgelöst wird und sich im Bereich von mindestens 50 Ticks 
bewegen dürfte.

Johann

von stinke (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab ein sende FIFO eingebaut und konnte das Problem so lösen.


Wir werden in der praxis natürlich nicht jeden Character echo'n,
aber wir haben seitens des AVR Befehle im Befehlssatz die auch "mal
zu Wort kommen wollen". Das hat die Probleme verursacht.

Danke für eure Hilfe. Auch an Peter für deine Implementation
(die ich erst später entdeckt habe).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

stinke wrote:
> Ich hab ein sende FIFO eingebaut und konnte das Problem so lösen.

Ohne im Detail auf die FIFO-Implementierung geschaut zu haben würd ich 
was drauf wetten, daß dort noch mindestens ein Hund in einer 
Race-Condition begraben ist.

Johann

von Peter D. (peda)


Lesenswert?

Johann L. wrote:
> Ohne im Detail auf die FIFO-Implementierung geschaut zu haben würd ich
> was drauf wetten, daß dort noch mindestens ein Hund in einer
> Race-Condition begraben ist.

Da wirst Du wohl recht haben.

Der RN-Code liegt leider nicht als compilierbares Programm vor, daher 
kann man das auch nicht prüfen.
Deshalb fragte ich ja auch nach dem Code (nicht nach Schnipselchen).

Der Fehler wird wohl in den unbekannten FIFO-Macros liegen.
Macros sind ja schön und gut, aber manchmal ist eine angepaßte FIFO doch 
besser und sicherer.

Ich hab auch ne Weile überlegen müssen, damit mein Code interruptfest 
ist.
Die Hauptbedingung dafür war, daß der Index 8-Bittig ist, somit konnte 
auf Interruptsperre verzichtet werden.


@stinke

Dein Code sieht sehr seltsam, aus, da dürften noch einige Fallgruben 
drin sein.
Der Empfang ist ohne FIFO, da könnts schnell mal klemmen.
Und der Sende-FIFO macht keinen Sprung an den Anfang, sondern schmeißt 
alle Bytes nach dem 64-sten weg.


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.