Forum: Mikrocontroller und Digitale Elektronik USART wird langsamer und verliert Daten


von Max M. (maxx2k15)


Angehängte Dateien:

Lesenswert?

Hallo ihr Meister der uC,

ich lese schon lange mit und habe hier schon viel gelernt.
Nun habe ich allerdings selber mal eine Frage.

Im Rahmen meines Elektrotechnik Studiums habe ich ein Praxissemester.

In diesem soll ich eine Datenübertragung via Funk realisieren.

Ziel: RS232 <-> Funkchip <-> Funkchip <-> RS232

Die Geschwindigkeit muss nicht sehr hoch sein, da sowieso schon auf die 
115,2 kBit begrenzt.
Diese sollten aber schon erreicht werden.

Wir haben nun den Atmega128RFA1 ausgesucht und gekauft.
Dazu noch 2x STK600.

Bei dem STK ist noch je ein ATMEGA2560 dabei, mit welchem ich nun seit 
einigen Wochen experimentiere.

Für die RS232 Schnittstelle benötige ich ja nun eine USART.
Diese zu initialisieren und zu verwenden klappt.

Die Daten sollen in einem FIFO (Ringpuffer) zwischengespeichert werden, 
bevor der Funkchip diese an seine Gegenseite weiterreicht.

Auch dieser ist im Programm.
Noch nicht fertig und perfekt, aber er funktioniert...

Für meine ersten Tests verwende ich folgenden Aufbau:
uC1 sendet ohne Rücksicht mit 115,2kBit/s via USART an uC2.
Dieser nimmt die Daten, legt sie in den FIFO und überprüft immer, ob 
dort schon Daten sind.
Sollten Daten vorhanden sein, nimmt er sie aus dem FIFO raus und sendet 
sie über eine andere USART (RS232) an meinen PC, wo ich diese auf dem 
Hyperterminal zur Kontrolle sehen kann.

Wenn ich nun 'wenige' Daten sende, so kommen alle ohne Probleme an.
z.B. 65535 mal ein 'A'.
Wenn ich dies aber 5x ohne Pause wiederhole, fehlen mir am Ende immer 
einige Hundert Pakete.

Inzischen habe ich mit einem Oszi herausgefunden, dass die while 
Schleife in der putc FKT mit langer Laufzeit des Programms wächst.
Und ich verstehe nicht, warum....

Ich sitze nun seit mehreren Wochen daran und verzweifle sehr, weil ich 
nicht weiß, wonach ich suchen muss.... :(

Ich hänge das Programm mal mit an.

Mir ist bewusst, dass es noch nicht perfekt ist und leider durch das 
viele herumdoktoren auch absolut nicht mehr schön ist.
Allerdings werde ich, sobald ich den Funkchip nehme, sowieso nochmal bei 
0 Anfangen und nur bestimmte Passagen übernehmen.

Der 'Fehler' Zähler stimmt auch nicht, dies ist mir aber bewusst.

Ich hoffe, ihr könnt mir helfen

LG, Max

von Stefan F. (Gast)


Lesenswert?

Rücke den Code mal richtig ein, damit er lesbar wird. Vor allem die 
while Schleife!

Bist du sicher, dass der Buffer groß genug ist?

Was soll das sein?: "leer;"

Innerhalb der ISR hast du eine Wiederholschleife, die ca 65 tausend mal 
durchlaufen wird.

Dieser Code tut sicher nicht das, was du erwartest:
1
    zaehl++;
2
    if (zaehl==65535)
3
    {
4
      zaehl=0;
5
      zaehl2++;
6
    }
So hast du den Überlauf alle 65535 mal, wolltest es aber sicher bei 
65536 haben. Das geht so:
1
    zaehl++;
2
    if (zaehl==0)
3
    {
4
      zaehl2++;
5
    }

Aber statt zaehl und zaehl2 kannst du auch einfach einen 32Bit oder gar 
einen 64Bit Integer verwenden.

Du inkludierst die setbaud.h aber berechnest die Baudrate selbst. 
Verwende besser die Berechnungsmakros aus der Library, die haben sich 
bewährt.

von Stefan F. (Gast)


Lesenswert?

> Innerhalb der ISR hast du eine Wiederholschleife, die ca 65 tausend
> mal durchlaufen wird.

Streiche den Satz, ich hatte mich verguckt.

von Max M. (maxx2k15)


Lesenswert?

Hallo Stefan,

danke erstmal fürs anschauen :)

Einen 32 Bit Zähler hatte ich bereits probiert, allerdings hat er 
dennoch nur bis 65535 gezählt....
Daher dachte ich dann, dass 16 Bit das maximale sind, was der AVR kann.

leer; habe ich oben definiert, ist nur ein Leerzeichen in der Ausgabe.
War vorher noch mehr drin...
Dies sollte nur für Übersichtlichkeit sorgen.
Hat es am Anfang auch. Nur inzwischen benötige es nicht mehr ;)

Warum wiederholt er die so oft?
Ist doch ein if

Ablauf:
Kopierer UDR1 in FIFO.
Ist das im FIFO ein A?
Ja -> Zaehl++
Nein -> Nix

Ist zaehl = 65535?
Ja -> zaehl=0; zaehl2++;
Nein -> Nix

EDIT 1

Stefan Us schrieb:
>> Innerhalb der ISR hast du eine Wiederholschleife, die ca 65 tausend
>> mal durchlaufen wird.
>
> Streiche den Satz, ich hatte mich verguckt.

ok^^

EDIT 2

Bei mir im AtmelStudio ist das eingerückt.
Hier in der Codeansicht nicht.
Was kann ich denn dagegen tun?

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

> Einen 32 Bit Zähler hatte ich bereits probiert, allerdings hat er
> dennoch nur bis 65535 gezählt....
> Daher dachte ich dann, dass 16 Bit das maximale sind, was der AVR kann.

Nee, das geht schon. Vermutlich hattest du irgendwo ungewollt eine 
Umwandlung auf 16bit drin gehabt. C neigt dazu - leider.

> Was kann ich denn dagegen tun?

Mit Leerzeichen einrücken, nicht mit Tabulatoren. Und schon gar nicht 
Tabulatoren und Leerzeichen mischen. Du kannst den Editor irgendwo 
konfigurieren, dass die Tab Taste Leerzeichen erzeugt.

Was ist denn jetzt mit dem Puffer? Bist du sicher, dass er groß genug 
ist?

von Max M. (maxx2k15)


Lesenswert?

Ok, versuche den Code mal übersichtlicher zu machen.

Der Puffer ist wohl nie groß genug, da ich zumindest davon ausgehen 
muss, dass eine Endlosübertragung stattfindet.
Mit dem größeren Puffer würde ich das Problem nur nach hinten schieben.

von Peter D. (peda)


Lesenswert?

Max M. schrieb:
> Die Geschwindigkeit muss nicht sehr hoch sein, da sowieso schon auf die
> 115,2 kBit begrenzt.

Das ist sehr hoch, mehr kann eine PC-UART nicht.
Geh mal runter auf 9600 oder 1200 Baud.
Erst sollte ein Programm grundsätzlich laufen, danach kann man 
optimieren.

Bei Anfängern liegen UART-Probleme oft an dem völligen Fehlen eines 
Übertragungsprotokolls (Paketsynchronisation, Fehlererkennung, 
Datenflußsteuerung).


Wenn Du schon nichts kommentieren willst, dann beschreibe mal in 
verständlichen Sätzen, was das Programm überhaupt machen soll.
Auf Reverse-Engineering hat keiner große Lust.

von Max M. (maxx2k15)


Lesenswert?

Peter Dannegger schrieb:
> Max M. schrieb:
>> Die Geschwindigkeit muss nicht sehr hoch sein, da sowieso schon auf die
>> 115,2 kBit begrenzt.
>
> Das ist sehr hoch, mehr kann eine PC-UART nicht.
> Geh mal runter auf 9600 oder 1200 Baud.
> Erst sollte ein Programm grundsätzlich laufen, danach kann man
> optimieren.

Das ist mir bewusst. Dann werde ich es gleich mal langsamer probieren.
Der vergleich langsam war auch eher auf andere Schnittstellen bezogen ;)

> Wenn Du schon nichts kommentieren willst, dann beschreibe mal in
> verständlichen Sätzen, was das Programm überhaupt machen soll.
> Auf Reverse-Engineering hat keiner große Lust.

Das Programm macht nichts, außer auf Daten zu warten, diese zu speichern 
und anschließend über RS232 weiterzugeben.

Sollten welche über die ISR empfangen werden, nimmt es diese und legt 
sie in den FIFO.
In der main wird immer abgefragt, ob bereits Daten im Puffer sind.
Sollten welche vorhanden sein, werden diese aus dem Puffer genommen und 
über die zweite Schnittstelle an den PC gegeben.
Und das wars auch schon. Mehr macht es nicht.

Und noch nicht mal das klappt richtig :((


Hier nochmal etwas ausführlicher:

Hier wird die USART Schnittstelle initialisiert.
1
cli();
2
usart_init();
3
sei();

Dies ist nur, damit ich am PC sehe, dass der uC soweit ist, Sachen zu 
empfangen etc.
1
uart_puts(" Bereit ");

Dies ist für NACH der Übertragung, um die Zähler am PC auszugeben.
Dies sieht dann z.B. so aus:
Eingang: 0 + (0 x 65535) Ausgang: 0 + (0 x 65535) Fehler: 0
1
if (PINA == 0xFE)
2
    {
3
      ..... Siehe ausführlichen Code .....
4
    }

In der while Schleife wir immer geprüft, ob Daten im FIFO liegen.
Die pruef() Funktion vergleicht dafür den Lese- und den Schreibezeiger.
1
pru = pruef();

Falls ja:
BufferOUT() nimmt anschließend ein Byte aus dem FIFO und übergibt ihn an 
die Ausgabefunktion (uart_putc(...))
1
if (pru != 0)  //Siehe pruef(); 0->keine Daten, 1->Daten vorhanden
2
  {
3
    BufferOut();
4
  }

EDIT: Ich glaube, ich mag das Wort "Dies"^^ :P

: Bearbeitet durch User
von Pandur S. (jetztnicht)


Lesenswert?

Es geht also nur ums Durchreichen ? Bei gleicher Baudrate ? Dann braucht 
man nicht mal ein FIFO, sondern nur ein Register.

von Stefan F. (Gast)


Lesenswert?

Den Puffer braucht er, weil er in der while Schleife immer abwechselnd 
eine gewisse Menge Daten sendet und empfängt.

Daher meine Frage nach der Puffergröße. Ist der Puffer groß genug, um 
die Daten eines Schleifendurchlaufes aufzunehmen?

von Max M. (maxx2k15)


Lesenswert?

Sogar mehr.
65535 A's in voller Geschwindigkeit kommen ohne Probleme beim PC an.
Mache ich jedoch die doppelte Menge, fangen die Probleme an.

Ich füge mal noch einen Teil vom anderen uC an, der die Daten sendet:
1
int main(void)
2
{
3
  cli();
4
  usart_init();  //USART wie beim anderen uC initialisieren
5
  sei();
6
  unsigned char daten='A';
7
  
8
  for (int i=0; i<5; i++)
9
  {
10
    for (uint16_t j=0; j < 65535; j++)
11
    {
12
      uart_putc1(daten);
13
      _delay_ms(40);
14
    }  
15
  }
16
   while(1)
17
   {
18
        
19
   }
20
}

In dem Fall 5 x 65535.

von Karl H. (kbuchegg)


Lesenswert?

Max M. schrieb:
> Hallo Stefan,
>
> danke erstmal fürs anschauen :)
>
> Einen 32 Bit Zähler hatte ich bereits probiert, allerdings hat er
> dennoch nur bis 65535 gezählt....

der hat schon weiter gezählt.
Aber du wirst halt die falsche Ausgabefunktion genommen haben.
utoa geht nun mal nur mit 16 Bit Werten.

> leer; habe ich oben definiert, ist nur ein Leerzeichen in der Ausgabe.
> War vorher noch mehr drin...
> Dies sollte nur für Übersichtlichkeit sorgen.

Das ist nicht wirklich übersichtlich. Das verwirrt eher mehr.
Wenn du Überischtlichkeit haben willst, dann schreib  dir eine Funktion, 
die dir einen uint16_t ausgibt (oder eine die uint32_t) ausgibt. Dieses 
Gewurstel mit expliziten utoa in jeweils ein char Array und uart_puts 
Orgie danach ist nicht wirklich übersichtlich. Man kann sich ja auch 
eine Funktion machen, die einen Text zusammen mit einer Zahl ausgibt.
1
void uart_putl( uint32_t value )(
2
{
3
  char tmp[20];
4
5
  ultoa( value, tmp, 10 );
6
  uart_puts( tmp );
7
}
8
9
void uart_putValue( const char* label, uint32_t value )
10
{
11
  uart_puts( label );
12
  uart_putl( value );
13
}
Dann steht da am Anfang deiner Kontrollausgabe (und benenn deine 
Variablen ordentlich. Was soll das sein, eine Variable die 'zahl' 
heisst? Wenn das die Anzahl der Bytes ist, die reingekommen sind, dann 
benenn die Variable auch genau so!)
1
....
2
    if (PINA == 0xFE)
3
    {
4
      uart_putValue( " Eingang: ", inCount );
5
      uart_putValue( " Ausgang: ", outCount );
6
      uart_putValue( " Fehler:  ", nrErrors );
7
      uart_puts( "\n" );
8
9
      inCount = outCount = nrErrors = 0;
10
    }

Huch!
Und auf einmal ist das übersichtlich und verständlich und nicht so ein 
Wust an Programmcode, der sich seitenweise dahinzieht und in dem man 
ständig hin und her scrollen muss, um Zusammenhänge zu sehen.

Hmm.
Deine FIFO sieht nicht so schlecht aus.
Ich hätt trotzdem die Fleury Funktionen genommen.

: Bearbeitet durch User
von Max M. (maxx2k15)


Lesenswert?

Karl Heinz schrieb:
> Max M. schrieb:
>> Hallo Stefan,
>>
>> danke erstmal fürs anschauen :)
>>
>> Einen 32 Bit Zähler hatte ich bereits probiert, allerdings hat er
>> dennoch nur bis 65535 gezählt....
>
> der hat schon weiter gezählt.
> Aber du wirst halt die falsche Ausgabefunktion genommen haben.
> utoa geht nun mal nur mit 16 Bit Werten.

Das war mir nicht bewusst.
Fehler Nummer 1 ist damit geklärt :)


> Huch!
> Und auf einmal ist das übersichtlich und verständlich und nicht so ein
> Wust an Programmcode, der sich seitenweise dahinzieht und in dem man
> ständig hin und her scrollen muss, um Zusammenhänge zu sehen.

Da hast du absolut Recht. Das ist ja mega schön.
Dann werde ich wohl jetzt schon mal von vorne anfangen.

> Hmm.
> Deine FIFO sieht nicht so schlecht aus.
> Ich hätt trotzdem die Fleury Funktionen genommen.

Du meinst die Library?
Ich dachte mir halt, wenn ich hier in einer Firma etwas für die 
entwickeln soll, wäre es besser, wenn ich es selber mache.
Man weiß ja nie....

: Bearbeitet durch User
von Pandur S. (jetztnicht)


Lesenswert?

Falls man denn einen Buffer verwenden will, nimmt man einen ringbuffer, 
der eine Groesse von 2^N, zB 32 byte. Die Adressierung wird dann zu zB

(MyPtr++) && 0x1F , dh die hintersten 5 bit. Keine Bereichsabfrage indem 
Sinne.

von Karl H. (kbuchegg)


Lesenswert?

Max M. schrieb:

> Da hast du absolut Recht. Das ist ja mega schön.

Und das verblüffende ist:
Interessanterweise ist der scheuslichste Code auch meist der mit den 
blödesten Fehlern.
Daraus könnte man folgern, dass es sich lohnt, von Anfang an auf einen 
ordentlichen und gut lesbaren Code zu achten.

> Ich dachte mir halt, wenn ich hier in einer Firma etwas für die
> entwickeln soll, wäre es besser, wenn ich es selber mache.
> Man weiß ja nie....

Niemand hindert dich, die Fleury Funktionen im Detail zu studieren.

von Max M. (maxx2k15)


Lesenswert?

Jetzt Nicht schrieb:
> Falls man denn einen Buffer verwenden will, nimmt man einen ringbuffer,
> der eine Groesse von 2^N, zB 32 byte. Die Adressierung wird dann zu zB
>
> (MyPtr++) && 0x1F , dh die hintersten 5 bit. Keine Bereichsabfrage indem
> Sinne.

Naja der Buffer ist ein Ringbuffer wie in meinem Eingangspost 
geschrieben.

Die Groesse ist 1024 byte, also auch das ist erfüllt.

Die Maskierung habe ich nicht im Programm.
Allerdings ist das Problem auch nicht, dass der Buffer zu langsam ist, 
oder?

Der uC läuft mit 14,75 MHz.
Alle 86,xx us kommen 8 Bit an.
Das muss der doch locker schaffen?

von Karl H. (kbuchegg)


Lesenswert?

Jetzt Nicht schrieb:
> Falls man denn einen Buffer verwenden will, nimmt man einen ringbuffer,
> der eine Groesse von 2^N, zB 32 byte. Die Adressierung wird dann zu zB
>
> (MyPtr++) && 0x1F , dh die hintersten 5 bit. Keine Bereichsabfrage indem
> Sinne.

Wenn du dann auch noch ein & anstelle eines && nimmst, dann würde das 
sogar stimmen.

Aber ein
1
  counter++;
2
  if( counter == MAX )
3
    counter = 0;

kostet nicht viel und fängt zunächst mal blöde Fehler, wie nicht 2-er 
Potenzen der Buffergröße, ab.

Daran liegts in seinem Fall bestimmt nicht. Wenn er das bischen Zeit 
nicht mehr hat, dann hat er ein viel mächtigeres Problem.

: Bearbeitet durch User
von Pandur S. (jetztnicht)


Lesenswert?

Erst mal verifiziert man die Funktionalitaet mit durchreichen ohne 
Buffer, und dann mit. Dann wird es moeglicherweise am buffer liegen. 
Also auf den Simulator mit dem Buffer und jeden Step ueberlegen, ob die 
Ausfuehrung dem Gedachten entspricht.

Zur Verfeinerung wuerd ich anstelle von "A","A" .. 0,1,2,3,4,5.. 
verwenden und erhaelt so etwas mehr Aufschluss.

: Bearbeitet durch User
von Max M. (maxx2k15)


Lesenswert?

Jetzt Nicht schrieb:
> Erst mal verifiziert man die Funktionalitaet mit durchreichen ohne
> Buffer, und dann mit. Dann wird es moeglicherweise am buffer liegen.
> Also auf den Simulator mit dem Buffer und jeden Step ueberlegen, ob die
> Ausfuehrung dem Gedachten entspricht.
>
> Zur Verfeinerung wuerd ich anstelle von "A","A" .. 0,1,2,3,4,5..
> verwenden und erhaelt so etwas mehr Aufschluss.


An sich sollte dieser doch funktionieren?
Das Problem, was ich mit dem Oszi gemessen habe, ist, dass die while 
Schleife, welche auf das leere UDR wartet, schleichend immer länger 
wird.
Zu Beginn wenige us, später plöztlich 70 us und mehr.
1
void uart_putc(unsigned char c)
2
{
3
  //von dieser while rede ich:
4
  while (!(UCSR0A & (1<<UDRE0)));  /* warten bis Senden moeglich */
5
6
  UDR0 = (uint8_t)c;        // sende Zeichen
7
}

Die Verfeinerung mit verschiedenen Zeichen steht auch schon auf meinem 
Plan :)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Max M. schrieb:
> In diesem soll ich eine Datenübertragung via Funk realisieren.
>
> Ziel: RS232 <-> Funkchip <-> Funkchip <-> RS232
>
> Die Geschwindigkeit muss nicht sehr hoch sein, da sowieso schon auf die
> 115,2 kBit begrenzt.
> Diese sollten aber schon erreicht werden.

Mich würde mal interessieren, welchen "Funkchip" Du Dir ausgesucht hast, 
der diese doch ziemlich hohe Geschwindigkeit von 115,2 kBit überhaupt 
kann...

P.S.
Es gibt etwas, was Du Dir evtl. mal anschauen solltest:

   Beitrag "bidirektionale RS232 Funkbrücke mit RFM12"

Soviel ich weiß, sind damit aber höchstens 19200 Baud möglich, ohne dass 
die Fehlerrate ins unermessliche steigt.

: Bearbeitet durch Moderator
von Max M. (maxx2k15)


Lesenswert?

> Mich würde mal interessieren, welchen "Funkchip" Du Dir ausgesucht hast,
> der diese doch ziemlich hohe Geschwindigkeit von 115,2 kBit überhaupt
> kann...
>
> P.S.
> Es gibt etwas, was Du Dir evtl. mal anschauen solltest:
>
>    Beitrag "bidirektionale RS232 Funkbrücke mit RFM12"
>
> Soviel ich weiß, sind damit aber höchstens 9600 Baud möglich - auf jeden
> Fall erheblich weniger.

Naja, steht 2 Zeilen weiter unten :P

atmega128RFA1
Da ist ein uC und ein Funkmodul mit drauf.
Dieser kann laut Datenblatt 2 MBit.


9600 Baud ist wesentlich zu langsam.

Das Ziel sind die 115,2kBaud

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Max M. schrieb:
> atmega128RFA1
> Da ist ein uC und ein Funkmodul mit drauf.
> Dieser kann laut Datenblatt 2 MBit.

Ah, okay, habe ich überlesen. Sorry.

von Pandur S. (jetztnicht)


Lesenswert?

Dann mach doch mal einen freien Pin in die Schleife rein :


void uart_putc(unsigned char c)
{
 portc,3=1; // **
 while (!(UCSR0A & (1<<UDRE0)));  /* warten bis Senden moeglich */
 portc,3=0;  // **
 UDR0 = (uint8_t)c;        // sende Zeichen
}

Und schau mit dem scope zu. Ich wuerd aber eh mit Interupts arbeiten, 
und dort wird nicht gewartet. Aber zuschauen muss man immer koennen.

von Max M. (maxx2k15)


Lesenswert?

Also es läuft endlich :)))

Danke für eure vielen Hinweise :)

Habe nun ein neues leeres Projekt begonnen.

Zum testen habe ich 4 Mio Datenpakete übertragen
(Noch nur A's, später noch Zeichenfolgen.)

LG, Max

von Stefan F. (Gast)


Lesenswert?

Wo genau war jetzt der Fehler?

von Max M. (maxx2k15)


Lesenswert?

Wenn ich das nur genau wüsste.

Ich habe das leere Programm angefangen mit richtiger Benennung der 
Variablen, alles unnötige raus, die eine oder andere Kleinigkeit 
verändert und schwups ging es.

Hätte ich doch nur mal früher hier geschrieben...

Habe jetzt die Zeichenfolge ABC gesendet, kommt auch korrekt an.

von Jim M. (turboj)


Lesenswert?

Max M. schrieb:
> Die Groesse ist 1024 byte

Nein. Dein Puffer ist maximal 256 Byte groß, weil Du nur uint8_t als 
Indexvariablen hast (jedenfalls im geposteten Code). Mit -Wall sollte 
das eigentlich auch entsprechende Warnings geben (Vergleich niemals true 
u.ä).

Größere Indexvariablen würden dann wegen der nicht atomaren 
Schreibzugriffe andere Probleme machen.

: Bearbeitet durch User
von Max M. (maxx2k15)


Lesenswert?

Jim Meba schrieb:
> Max M. schrieb:
>> Die Groesse ist 1024 byte
>
> Nein. Dein Puffer ist maximal 256 Byte groß, weil Du nur uint8_t als
> Indexvariablen hast (jedenfalls im geposteten Code). Mit -Wall sollte
> das eigentlich auch entsprechende Warnings geben (Vergleich niemals true
> u.ä).
>
> Größere Indexvariablen würden dann wegen der nicht atomaren
> Schreibzugriffe andere Probleme machen.

Warum?
Eine Stelle in meinem Array hat 8 Bit.
Ich habe 1024 Stellen.
-> 1024 Byte
Oder habe ich jetzt einen Denkfehler?

Der Speicher im neuen Programm hat sogar nur 128 Byte.
Oder halt Bit, sollte ich da wirklich gerade was verdrehen ;)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Max M. schrieb:
> -> 1024 Byte

Aber wenn der Index darauf ein uint8_t ist, kannst Du nur die Stellen 
0...255 in Deinem Array überhaupt adressieren.

von Max M. (maxx2k15)


Lesenswert?

Also weil read und write nur so weit zählen können?

Stimmt, das ist wohl ein Fehler^^

Aber wie gesagt, sind jetzt eh nur noch 128 Byte.
Die kann ich mit meiner 8 Bit Adresse auch alle ansprechen ;)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Max M. schrieb:
> Aber wie gesagt, sind jetzt eh nur noch 128 Byte.
> Die kann ich mit meiner 8 Bit Adresse auch alle ansprechen ;)

Ja.

von Max M. (maxx2k15)


Lesenswert?

Doofe Frage:

Kann ich jetzt dem Titel irgendwie ein [Gelöst] anhängen oder ist das 
unüblich?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Soviel ich weiß, kann der Thread-Ersteller den Betreff ändern - genau 
für diesen Zweck. Wie das geht, weiß ich allerdings nicht.

von Peter D. (peda)


Lesenswert?

Max M. schrieb:
> Kann ich jetzt dem Titel irgendwie ein [Gelöst] anhängen oder ist das
> unüblich?

Schön wäre es, macht aber leider kaum einer. In anderen Foren ist das 
öfter zu sehen.
Hier hab ich das mal gemacht:
Beitrag "USB 3.0 nicht abwärts kompatibel: Problem gelöst"

Wenn Du auf Deinen Beitrag gehst und da steht "Bearbeiten", einfach 
draufklicken.

von Max M. (maxx2k15)


Lesenswert?

Heute kam ich aus dem Wochenende und es geht nicht mehr :/

Da ich damals keinen direkten Fehler finden konnte, weiß ich nun nicht 
mehr weiter...

Als weiteres Experiment habe ich es nun mal komplett ohne FIFO probiert.
Sogar das klappt nicht.

Also der "einfachere" Ablauf ist:

ISR wird aufgerufen -> Register1 (UDR1) wird gelesen und in 
Zwischenvariable gepackt
-> Register2 (UDR0) wird mit dieser Variable beschrieben

Das sollte dann so aussehen:
1
ISR (USART1_RX_vect)  //Empfangen der Daten
2
{  
3
  uint8_t data;
4
  
5
  PORTB |= (1<<DDB0);
6
  data = UDR1;      //Empfangsregister auslesen
7
  
8
  while (!(UCSR0A & (1<<UDRE0)));  //warten bis Senden moeglich
9
  UDR0 = data;
10
  
11
  PORTB &= ~(1<<DDB0);
12
}

Die Zeichen lasse ich vom Hyperterminal in eine Textdatei mitschreiben, 
wo ich sie anschließend zum Buchstaben-zählen in Word packe.
Es sind zu wenige...

Dass man so eine lange ISR vermeiden sollte weiß ich, aber wenn ich mit 
ca 115 kbit/s empfange muss ich doch auch mit der selben Geschwindigkeit 
schreiben können.

Das sofortige rausschreiben in der ISR soll eventuelle Verzögerungen 
vermeiden.

Allerdings bin ich doch verwundert, da es letztes mal ging.
Ich habe heute morgen nix am Code geändert oder an der Hardware etwas 
gemacht.
Lag nur das Wochenende rum....

Lg, Max

von Max M. (maxx2k15)


Lesenswert?

Niemand eine Idee/Hinweis?

von Peter D. (peda)


Lesenswert?

Max M. schrieb:
> Heute kam ich aus dem Wochenende und es geht nicht mehr :/

Funkverbindungen können Fehler und Aussetzer haben, das ist völlig 
normal.
Ohne ein Protokoll wirst Du da nicht weiter kommen.

von Max M. (maxx2k15)


Lesenswert?

Das stimmt, allerdings Funke ich ja noch nicht.

Noch ist es uC1 -> USART -> uC2 -> USART (RS232) -> PC

von Stefan E. (sternst)


Lesenswert?

1
  UCSR0C &= ~(1<<UMSEL01) | (1<<UMSEL00);  //Asynchrone Operation
2
...
3
  UCSR1C &= ~(1<<UMSEL11) | (1<<UMSEL10);  //Asynchrone Operation
Da fehlt jeweils noch eine Klammer, ist aber nicht die Ursache deines 
Problems.

1
  UCSR0B |= ((1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0));  //...
Und wo ist die ISR dazu?
Wenn dann noch der entsprechende RX-Pin in der Luft hängen sollte, ist 
es kein Wunder, dass es mal zu funktionieren scheint, und mal nicht.

von Karl M. (Gast)


Lesenswert?

Hallo Max M.,

vor Tage habe diesen Thread mal gelesen und irgendwie kommst Du nicht 
weiter.
Verwende doch einfach mal die FIFO Uart Routinen von Peter Dannegger 
(PeDa), diese laufen bei mir sehr gut.
Und schreibe dann ein einfachen Testprogramm, das Du uns hier zeigst.

# Beitrag "AVR-GCC: UART mit FIFO"

# Beitrag "Software UART mit FIFO"

von Max M. (maxx2k15)


Lesenswert?

Stefan Ernst schrieb:

>
1
  UCSR0B |= ((1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0));  //...
> Und wo ist die ISR dazu?
> Wenn dann noch der entsprechende RX-Pin in der Luft hängen sollte, ist
> es kein Wunder, dass es mal zu funktionieren scheint, und mal nicht.

Im Programm gibt es nur eine ISR.
Es ist die für den Empfang.
Im oberen Code wird nur 1. RX aktiviert, 2. TX aktiviert und 3. RX 
Interrupt enabled
Da hängt doch dann noch nix in der Luft.
Nachdem ich in der ISR UDR auslese, wird das zuständige Bit 
zurückgesetzt.
-> Interrupt wird erst bei neuem Empfang ausgelöst

Karl M. schrieb:
> Verwende doch einfach mal die FIFO Uart Routinen von Peter Dannegger
> (PeDa), diese laufen bei mir sehr gut.
> Und schreibe dann ein einfachen Testprogramm, das Du uns hier zeigst.

Ich schaue mir heute Nachmittag mal die beiden Links an :)

Danke euch schon mal. Bin über jede Hilfe dankbar

: Bearbeitet durch User
von Stefan E. (sternst)


Lesenswert?

Max M. schrieb:
> Im Programm gibt es nur eine ISR.

Eben. Du aktivierst aber zwei Interruptquellen.

Max M. schrieb:
> Da hängt doch dann noch nix in der Luft.

In der Hardware! Was genau hängt an dem RX-Pin, dessen Interrupt du 
aktivierst, ohne eine ISR dafür zu haben?

von Nosnibor (Gast)


Lesenswert?

Kann es denn überhaupt gut gehen, ohne Pause durch so eine UART-Kette zu 
senden?
Wenn z.B. der erste Sender eine etwas (sagen wir 0,1%) höhere Baudrate 
hat als der nächste Prozessor in der Kette, dann steht der Mittelsmann 
da und hat nach je 1000 Byte, die er durchgereicht hat, ein Byte übrig, 
das er nicht losgeworden ist, weil sein Sender geringfügig langsamer ist 
als sein Empfänger. Da hilft (bei einem Dauertest) auch keine FIFO.

Das einzige, was da hilft, ist ein Protokoll, das auf 
Baudratenabweichungen zwischen den Kommunikationspartnern Rücksicht 
nimmt, z.B. durch gelegentliche Pausen. Die Leitung bis zum Überquellen 
vollzustopfen ist jedenfalls kein solches Protokoll.

von Falk B. (falk)


Lesenswert?

@ Nosnibor (Gast)

>Kann es denn überhaupt gut gehen, ohne Pause durch so eine UART-Kette zu
>senden?

Nein.

>als sein Empfänger. Da hilft (bei einem Dauertest) auch keine FIFO.

Eben.

von Max M. (maxx2k15)


Lesenswert?

Stefan Ernst schrieb:
> Max M. schrieb:
>> Im Programm gibt es nur eine ISR.
>
> Eben. Du aktivierst aber zwei Interruptquellen.
>
> Max M. schrieb:
>> Da hängt doch dann noch nix in der Luft.
>
> In der Hardware! Was genau hängt an dem RX-Pin, dessen Interrupt du
> aktivierst, ohne eine ISR dafür zu haben?

Ich habe den RX Interrupt (USART1_RX_vect).
Dieser wird auch ausgelöst.
(1<<RXEN0) und (1<<TXEN0) aktivieren noch keinen Interrupt, das tut erst 
(1<<RXCIE0).
Die beiden anderen aktivieren nur die Sende- und Empfangseinheit.
Daher habe ich nur 1 USART Interrupt aktiv, welchen ich auch verwende.

EDIT:
Es ist
uC1 RX <-> uC2 TX
uC1 TX <-> uC2 RX

uC2 <-> RS232 genauso

EDIT ENDE

Nosnibor schrieb:
> Kann es denn überhaupt gut gehen, ohne Pause durch so eine
> UART-Kette zu
> senden?
> Wenn z.B. der erste Sender eine etwas (sagen wir 0,1%) höhere Baudrate
> hat als der nächste Prozessor in der Kette, dann steht der Mittelsmann
> da und hat nach je 1000 Byte, die er durchgereicht hat, ein Byte übrig,
> das er nicht losgeworden ist, weil sein Sender geringfügig langsamer ist
> als sein Empfänger. Da hilft (bei einem Dauertest) auch keine FIFO.
>
> Das einzige, was da hilft, ist ein Protokoll, das auf
> Baudratenabweichungen zwischen den Kommunikationspartnern Rücksicht
> nimmt, z.B. durch gelegentliche Pausen. Die Leitung bis zum Überquellen
> vollzustopfen ist jedenfalls kein solches Protokoll.

Diese Befürchtung hatte ich auch schon.

Das Ziel des Projekts war allerdings, auf einer Seite in RS232 rein zu 
schreiben, dann soll die Funkstrecke kommen und dann am Schluss wieder 
das gleiche auf der anderen Seite (auch RS232) rauskommen.
Der "Nutzer" soll also eigentlich gar nicht merken, dass da irgendwas 
dazwischen ist.

Habt ihr vielleicht eine Idee, was ich sonst noch machen könnte?

PS: Mein Chef meinte, dass ein Hardwarehandshake nicht möglich ist.

: Bearbeitet durch User
von Stefan E. (sternst)


Lesenswert?

Max M. schrieb:
> (1<<RXEN0) und (1<<TXEN0) aktivieren noch keinen Interrupt, das tut erst
> (1<<RXCIE0).
> Die beiden anderen aktivieren nur die Sende- und Empfangseinheit.

Und in dem von dir gezeigten Code steht das hier:
1
 UCSR0B |= ((1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0));

von Max M. (maxx2k15)


Lesenswert?

Stefan Ernst schrieb:
> Max M. schrieb:
>> (1<<RXEN0) und (1<<TXEN0) aktivieren noch keinen Interrupt, das tut erst
>> (1<<RXCIE0).
>> Die beiden anderen aktivieren nur die Sende- und Empfangseinheit.
>
> Und in dem von dir gezeigten Code steht das hier:
>
1
 UCSR0B |= ((1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0));

Ich sehe noch immer keinen Fehler.
Aus dem UART Tutorial:

RXCIE (RX Complete Interrupt Enable)

Wenn dieses Bit gesetzt ist, wird ein UART RX Complete Interrupt 
ausgelöst, wenn ein Zeichen vom UART empfangen wurde. Das Global Enable 
Interrupt Flag muss selbstverständlich auch gesetzt sein.

TXCIE (TX Complete Interrupt Enable)

Wenn dieses Bit gesetzt ist, wird ein UART TX Complete Interrupt 
ausgelöst, wenn ein Zeichen vom UART gesendet wurde. Das Global Enable 
Interrupt Flag muss selbstverständlich auch gesetzt sein.

RXEN (Receiver Enable)

Nur wenn dieses Bit gesetzt ist, arbeitet der Empfänger des UART 
überhaupt. Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin 
des AVR als normaler I/O-Pin verwendet werden.

TXEN (Transmitter Enable)

Nur wenn dieses Bit gesetzt ist, arbeitet der Sender des UART überhaupt. 
Wenn das Bit nicht gesetzt ist, kann der entsprechende Pin des AVR als 
normaler I/O-Pin verwendet werden.

von Stefan E. (sternst)


Lesenswert?

Max M. schrieb:
> Ich sehe noch immer keinen Fehler.

Du willst mich veräppeln, oder?
Du willst mir also sagen, dass du davon ausgehst, dass die besagte Zeile 
nur RXEN0 und TXEN0 setzt, aber nicht RXCIE0?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Du willst mich veräppeln, oder?
> Du willst mir also sagen, dass du davon ausgehst, dass die besagte Zeile
> nur RXEN0 und TXEN0 setzt, aber nicht RXCIE0?

Hat er doch oben mehrfach schon gesagt: Ein Interrupt wird aktiviert.

Du redest aber von zwei Interrupts, die hier aktiviert werden. Ich 
wüsste nicht, wie das durch Setzen von RXCIEO0 gehen sollte.

von Max M. (maxx2k15)


Lesenswert?

Stefan Ernst schrieb:
> Max M. schrieb:
>> Ich sehe noch immer keinen Fehler.
>
> Du willst mich veräppeln, oder?
> Du willst mir also sagen, dass du davon ausgehst, dass die besagte Zeile
> nur RXEN0 und TXEN0 setzt, aber nicht RXCIE0?

Nein wirklich nicht...
Doch, dass der gesetzt ist ist klar.
Und der wird ausgelöst und hängt nicht in der Luft.
Bei keinem der Controller.

Kannst du nochmal in anderen Worten sagen, was du meinst?
Ich steh grad wohl auf dem Schlauch.
Es ist kein Pin in der Luft.
Es werden alle Register gelesen -> Interrupt zurückgesetzt.

von Stefan F. (Gast)


Lesenswert?

Mir ist nicht klar, wieso du überhaupt pufferst.

Wenn die Datenübertragung für die Endgräte transparent sein soll, das 
ist die naheliegende Lösung, jedes Byte (in beide Richtungen) sofort 
weiter zu reichen.

von Nosnibor (Gast)


Lesenswert?

Max M. schrieb:
> Das Ziel des Projekts war allerdings, auf einer Seite in RS232 rein zu
> schreiben, dann soll die Funkstrecke kommen und dann am Schluss wieder
> das gleiche auf der anderen Seite (auch RS232) rauskommen.
> Der "Nutzer" soll also eigentlich gar nicht merken, dass da irgendwas
> dazwischen ist.

Dann bleibt zu hoffen, daß der Nutzer die Strecke sinnvoll nutzt und 
nicht so extrem "testet"; dann geht das schon gut.

Viele Funkchips arbeiten ja auch mit Betriebsarten und Frequenzen, wo 
sie sowieso nicht 100% der Zeit senden dürfen (eher so 1%), dann kann so 
ein Datenstau erst recht nicht auftreten.

von Stefan E. (sternst)


Lesenswert?

Frank M. schrieb:
> Hat er doch oben mehrfach schon gesagt: Ein Interrupt wird aktiviert.
>
> Du redest aber von zwei Interrupts, die hier aktiviert werden. Ich
> wüsste nicht, wie das durch Setzen von RXCIEO0 gehen sollte.

Ich behaupte nicht, dass er mit RXCIEO0 zwei Interrupts aktiviert, 
sondern einen zweiten (neben dem einen eigentlich benutzten).
1
  UCSR0B |= ((1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0));  //Aktivieren receiver und transmitter, aktiviere RX Interrupt
2
...  
3
  UCSR1B |= ((1<<RXEN1) | (1<<TXEN1) | (1<<RXCIE1));  //Aktivieren receiver und transmitter, aktiviere RX Interrupt

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Ich behaupte nicht, dass er mit RXCIEO0 zwei Interrupts aktiviert,
> sondern einen zweiten (neben dem einen eigentlich benutzten).

Upps. Das stimmt.

Hier fehlt ISR (USART0_RX_vect). Ich glaube, dieser Hinweis ist etwas 
verständlicher. ;-)

von Max M. (maxx2k15)


Lesenswert?

Inzwischen bin ich mir auch nicht mehr sicher mit meiner Lösung.

Allerdings geht es ja noch nicht mal ohne Puffer.
Dann kann ich jetzt Feierabend machen und sagen es geht nicht?^^

Ne im Ernst, ich hab ja jetzt dann ein wirkliches Problem...

Ich tausche jetzt mal die beiden Boards.
Mal sehen ob das was bringt...

von Max M. (maxx2k15)


Lesenswert?

Frank M. schrieb:
> Stefan Ernst schrieb:
>> Ich behaupte nicht, dass er mit RXCIEO0 zwei Interrupts aktiviert,
>> sondern einen zweiten (neben dem einen eigentlich benutzten).
>
> Upps. Das stimmt.
>
> Hier fehlt ISR (USART0_RX_vect). Ich glaube, dieser Hinweis ist etwas
> verständlicher. ;-)

Ah, jetzt ist es klar.
^^
Ich kann mal rausnehmen, dass der ungenutzte Interrupt aktiviert ist.
Aber könnte das wirklich so extreme Störungen verursachen, wenn ich den 
nicht aufrufe?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Max M. schrieb:
> Ich kann mal rausnehmen, dass der ungenutzte Interrupt aktiviert ist.
> Aber könnte das wirklich so extreme Störungen verursachen, wenn ich den
> nicht aufrufe?

Wenn Du einen Interrupt aktivierst, aber keine ISR dazu schreibst, macht 
der µC einen (Soft-)Reset. Grund: Die Interrupt-Vektoren sind 
standardmäßig mit Sprung auf Adresse 0 initialisiert.

von Max M. (maxx2k15)


Lesenswert?

Frank M. schrieb:
> Wenn Du einen Interrupt aktivierst, aber keine ISR dazu schreibst, macht
> der µC einen (Soft-)Reset. Grund: Die Interrupt-Vektoren sind
> standardmäßig mit Sprung auf Adresse 0 initialisiert.

Ist raus.
Danke :)
In dem Praktikum lernt man einfach 10x mehr als in jeder Vorlesung :P

Ich habe nun die beiden Boards getauscht.
Jetzt läuft die Übertragung wieder ohne Datenverlust.
=> das eine Board läuft schneller als des andere.

Da ich keinen Handshake verwenden darf ist das ja nun ein mega Problem.
Ich werde nie 2 gleichschnelle Quarze finden.

Mir kommt aber gerade die Idee, 2 Stopbits zu verwenden.
Könnte mir das etwas Zeit verschaffen, sollte der eine etwas schneller 
sein als der andere?

von Peter D. (peda)


Lesenswert?

Die Quarztoleranz ist nur bei sehr langen Paketen (mehrere MB) ein 
Problem.
Wenn der 2.MC langsamer sendet, läuft irgendwann sein Empfangspuffer 
über.

von Max M. (maxx2k15)


Lesenswert?

Was der Fall ist.
Bei kurzen Übertragungen keine Probleme (z.B. ca 65kB),
bei langen Übertragungen (ca. 3MB+) fehlen Daten/Buffer läuft über.

Bin mir inzwischen recht sicher, dass das das Problem ist.
Der Taktgenerator auf dem STK600 hat eine Genauigkeit von 0.5%.
Das auf jedem Board und ganz schnell geht da was schief.

Besorge mal nen 14.xxx MHz Quarz (hab den genauen Wert gerade nicht im 
Kopf). Der ist dann ja wesentlich genauer.

von Stefan F. (Gast)


Lesenswert?

Exakt gleiche Frequenzen wirst du nicht hinbekommen, es sei denn, du 
taktest alle beteiligten Computer synchron.

Also wirst du wohl dem Sender sagen müssen, dass er etwas langsamer 
machen soll.

Wenn du bei allen Teilen 2 Stopbits einstellst, gewinnst du gar nichts.

Du kannst allerdings NUR beim Sender 2 Stoppbits einstellen und bei 
allen anderen jedoch 1 Stopbit. Bei bidirektionaler Übertragung geht das 
jedoch nicht.

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.