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
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.
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?
> 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?
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.
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.
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
.....SieheausführlichenCode.....
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(...))
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?
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
intmain(void)
2
{
3
cli();
4
usart_init();//USART wie beim anderen uC initialisieren
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
voiduart_putl(uint32_tvalue)(
2
{
3
chartmp[20];
4
5
ultoa(value,tmp,10);
6
uart_puts(tmp);
7
}
8
9
voiduart_putValue(constchar*label,uint32_tvalue)
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.
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....
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.
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.
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?
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.
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.
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
voiduart_putc(unsignedcharc)
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 :)
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.
> 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
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.
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
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.
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.
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 ;)
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 ;)
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.
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_tdata;
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
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.
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.
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"
> 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
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?
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.
@ 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.
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.
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:
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.
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?
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.
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.
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.
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.
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
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. ;-)
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...
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?
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.
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?
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.
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.