Hallo, ich habe ein Problem mit der Übertragungüber die serielle Schnittstelle. Im Einsatz habe ich eine ATMega32 und 14.7456 MHz. Meine Verbindung zum PC geht über eine FT232(FTDI) auf USB. Angestrebt sind 115200 Baud bei asynchronen Betrieb. Hier erstmal meine Einstellungen im Programm: USART_Init: ;Set baud rate LDI temp, 0x00 OUT UBRRH, temp LDI temp, 0x0F ;Asynchron, 14.7456 MHz, 115200Baud ;LDI temp, 0x07 ;Synchron, 14.7456 MHz, 115200Baud OUT UBRRL, temp ;Set to asynchonius mode LDI temp, 0x00 LDI temp, (1<<U2X) OUT UCSRA, temp ;Enable receiver and transmitter LDI temp, 0x00 LDI temp, (1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN) OUT UCSRB, temp ;Protocol: 8,N,1 LDI temp, 0x00 LDI temp, (1<<URSEL)|(1<<USBS)|(1<<UCSZ1)|(1<<UCSZ0) OUT UCSRC, temp Empfangen will ich via Interrupt, hier die Routine: USART_RX_Complete: PUSH temp ;Save temporary Variable IN temp, SREG PUSH temp ;Save Status-Register IN received, UDR ;Byte from USART OUT PORTC, received POP temp ;Restore Status-Register OUT SREG, temp POP temp ;Restore temporary Variable RETI Soweit tut das auch, aber nicht immer. Wenn ich größere Blöcke zum µC sende, werden die Daten anscheinend nicht richtig empfangen. Schicke ich bspw. 2048 Bytes mit dem Wert 12, so sehe ich das andere Werte an den Port angelegt werden. Jedes 3-5 Mal liegt dann zum Ende ein Wert am Port C den ich gar nicht gesendet habe, bspw. 136 anstelle von 12. Ich gehe mal davon aus, das meine Comport-Einstellungen im µC falsch sind, aber so habe ich das aus der Dokumentations von Atmel gelesen. Am PC sind die Einstellungen korrekt, das habe ich mit einer Hardware kontrolliert. Ich hoffe Ihr könnt mir weiterhelfen. -- Gruß Karsten
Im gezeigten Code sehe ich kein Problem (was nicht heißt, dass es keines gibt). Mit fehlt jedoch der ganze Code, z.B. um zu prüfen, dass PORTC nirgendwo anders auftaucht, das Register „received“ bzw. ein Alias davon nirgendwo anders verwendet wird und dass ein Interrupt-Handler für den Tx-Interrupt vorhanden ist.
Klaus 2m5 schrieb: > Dein Kommentar sagt 8n1, Du setzt aber 8n2. Hallo Klaus, habe jetzt LDI temp, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0) OUT UCSRC, temp gesetzt, dadurch ist das Problem aber nicht behoben, eher schlimmer geworden. Meine Einstellungen auf der PC Seite stehen defintiv auf 8, N, 1. -- Gruß Karsten
Hc Zimmerer schrieb: > Im gezeigten Code sehe ich kein Problem (was nicht heißt, dass es keines > gibt). Mit fehlt jedoch der ganze Code, z.B. um zu prüfen, dass PORTC > nirgendwo anders auftaucht, Hallo, nein PortC wird nur dort verwendet. > das Register „received“ bzw. ein Alias davon > nirgendwo anders verwendet wird .def temp = R16 .def received = R18 die werden auch nicht anderweitig benutzt. Die Anwendung soll lediglich nur ein paar Bytes einlesen. > und dass ein Interrupt-Handler für den > Tx-Interrupt vorhanden ist. Ist er nicht, aber sollte doch eigentlich kein Problem sein? -- Gruß Karsten
Zu den 2 Stopbits: Da ist auch keine Änderung zu erwarten. Der Empfänger ignoriert ein zweites Stopbit, auch wenn es eingestellt ist. Es wirkt sich nur auf den Sender aus.
Karsten Sosna schrieb: > Klaus 2m5 schrieb: >> Dein Kommentar sagt 8n1, Du setzt aber 8n2. > > Hallo Klaus, > habe jetzt > > LDI temp, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0) > OUT UCSRC, temp > > gesetzt, dadurch ist das Problem aber nicht behoben, eher schlimmer > geworden. Meine Einstellungen auf der PC Seite stehen defintiv auf 8, N, > 1. Geh da mal auf 8 N 2 Der Sender darf immer mehr Stoppbits benutzen. Mehr Stoppbits bedeutet einfach nur, dass der Sender dem Empfänger ein bischen mehr Zeit einräumt um mit dem empfangenen Byte etwas zu tun. Dem Empfänger ist die Anzahl der Stoppbits normalerweise sowieso egal. Kannst du senderseitig mal nach jedem Byte (oder x Bytes) eine Pause einlegen? Kurz und gut: Wenn du die Übertragungsgeschwindigkeit mal runterdrossest, bleiben dann die Fehler oder verschwinden sie?
Hc Zimmerer schrieb: > Dann wäre noch die Standard-Frage bei PORT C: JTAG abgeschaltet (Fuse, > MCUCSR)? Fuse Bits High 0xD9 Low 0xFF Damit sollte JTAGEN abgeschaltet sein. -- Gruß Scotty
Karsten Sosna schrieb: >> und dass ein Interrupt-Handler für den >> Tx-Interrupt vorhanden ist. > > Ist er nicht, aber sollte doch eigentlich kein Problem sein? Nur solange Du sicher nicht nach UDR schreibst und selbst dann ist es kein besonders guter Stil, dem AVR einen Interrupt zu erlauben, für den es keine Routine gibt. Das schreit nach späteren Problemen.
Erstmal vielleicht eine niedrigere Baudrate versuchen. Ungewöhnlich: UBRRL=0x0F, UX2=1 Besser: UBRRL=0x07, UX2=0 Double-Speed verringert das Bit-Sampling von 16 auf 8 Samples, allerdings nur bei einer schlechten RS232-Verbindung ein Problem.
> Geh da mal auf 8 N 2 > Der Sender darf immer mehr Stoppbits benutzen. Mehr Stoppbits bedeutet > einfach nur, dass der Sender dem Empfänger ein bischen mehr Zeit > einräumt um mit dem empfangenen Byte etwas zu tun. Dem Empfänger ist die > Anzahl der Stoppbits normalerweise sowieso egal. > > Kannst du senderseitig mal nach jedem Byte (oder x Bytes) eine Pause > einlegen? Kurz und gut: Wenn du die Übertragungsgeschwindigkeit mal > runterdrossest, bleiben dann die Fehler oder verschwinden sie? Hallo Karl, habe ich ich beides ausprobiert, es ändert sich nichts. ganz im Gegenteil, damit bekomme ich gar keine vernünftige Übertragung mehr hin. Bin jetzt bei 38400, 8, N, 2 -- Gruß Karsten
Karsten Sosna schrieb: habe ich ich beides ausprobiert, es ändert sich nichts. ganz im > Gegenteil, damit bekomme ich gar keine vernünftige Übertragung mehr hin. Das schreit aber dann nach einem Timingproblem. Runter mit der Baudrate auf 300, im Sender nach jedem Byte eine Pause einlegen (und den Bytewert hochzählen). Auf dem AVR das empfangene Byte auf einen Port ausgeben (oder sonst irgendwo wo man den Wert sieht) und beobachten: Ist die Anzahl der korrekt empfangenen Bytes immer gleich? Wieviele Bytes sind hintereinander fehlerhaft? Gibt es da Zusammenhänge?
Klaus 2m5 schrieb: > Erstmal vielleicht eine niedrigere Baudrate versuchen. > > Ungewöhnlich: UBRRL=0x0F, UX2=1 > Besser: UBRRL=0x07, UX2=0 Hallo Klaus, die zweite Einstellung habe ich auch schon durch gehabt, brachte aber keine Änderung. Ich gehe jetzt mal auf 9600, 8, N, 2 Synchron Absolute Katastrophe, jetzt kann ich sehen wie unregelmäßig sich der Port ändert. Ich sende einfach 2048 Bytes a Wert 12, das Ergenis ist ein Zufallszahlengenerator. -- Gruß Scotty
Ich habe zwar Zweifel, ob das der wirkliche Grund ist. Aber für einen externen Quarz von 14.7456 MHz müsste die CKOPT-Fuse 0 sein, nach Deinen Fuse-Angaben ist sie aber 1. Meistens tut's trotzdem.
> Das schreit aber dann nach einem Timingproblem.
So, ich habe jetzt auf 9600 gekürzt, die Anzahl der empfangenen Bytes
stimmt nie. Ich sende einfach 255 Bytes. Beim ersten Durchlauf sagt er
0, beim zweiten 67 oder mal 11 oder mal 165. Da haut irgendwas nicht
hin. Stimmen denn meine Fuse-Bits für externer Quartz 14.7465MHz?
--
Gruß Karsten
Hc Zimmerer schrieb: > Ich habe zwar Zweifel, ob das der wirkliche Grund ist. Aber für einen > externen Quarz von 14.7456 MHz müsste die CKOPT-Fuse 0 sein, nach Deinen > Fuse-Angaben ist sie aber 1. Meistens tut's trotzdem. Laut AVR-Studio ist sie 0. -- Gruß Karsten
Äm. Schriebst Du nicht oben Karsten Sosna schrieb: > Fuse Bits > > High 0xD9 > Low 0xFF Und CKOPT ist Bit 4 in der High Fuse? Edit: Du hast schon den ATmega32 eingestellt? Edit2: Und berücksichtigt, dass programmierte Fuses auf 0 sind?
>> High 0xD9 >> Low 0xFF > > Und CKOPT ist Bit 4 in der High Fuse? > > Edit: Du hast schon den ATmega32 eingestellt? So habe jetzt CKOPT "angehakt", damit ändert sich High von 0xD9 auf 0xC9. Ich habe aber noch was gemacht. Ich habe die Baudrate auf 57600 festgelegt. Wenn ich mir dieser Rate sende, kommen unterschiedlich viel Bytes an. Gehe ich jetzt mit dem Sender runter auf bspw. 38400 oder 19200 dann kommen exakt soviel Bytes an wie ich gesendet habe. Der µC steht aber weiterhin auf 57600. Desweiteren funktioniert das erst nach dem ersten Datenblock. -- Gruß Karsten
Das wird immer ominöser, und den vollen Code haben wir auch nicht. Dass bei abweichender Baudrate genau soviel Zeichen kommen wie gesendet wurden, ist doch seeeehr unwahrscheinlich. Und das sogar bei verschiedenen Baudrates. Lass' mal den Empfang Empfang sein. Mache das Erlauben des Sendeinterrupts weg und danach im Hauptprogramm eine Sendeschleife. Also ganz einfach immer dann, wenn TxC gesetzt ist, z.B. 0x31 nach UDR schreiben, dann eine Warteschleife (damit der Empfänger nicht fehlsynchronisiert, also z.B. verschachtelt 2 Register runterzählen), und das in einer ewigen Schleife. Dann schaust Du, ob bei übereinstimmenden Baudrates „11111111...“ empfangen wird. Erst wenn das der Fall ist, nimmst Du die Arbeit am Empfänger wieder auf.
> Das wird immer ominöser, und den vollen Code haben wir auch nicht. Dass > bei abweichender Baudrate genau soviel Zeichen kommen wie gesendet > wurden, ist doch seeeehr unwahrscheinlich. Und das sogar bei > verschiedenen Baudrates. Hallo, das ist mir ja auch schleierhaft. > Lass' mal den Empfang Empfang sein. Mache das Erlauben des > Sendeinterrupts weg und danach im Hauptprogramm eine Sendeschleife. > Also ganz einfach immer dann, wenn TxC gesetzt ist, z.B. 0x31 nach UDR > schreiben, dann eine Warteschleife (damit der Empfänger nicht > fehlsynchronisiert, also z.B. verschachtelt 2 Register runterzählen), > und das in einer ewigen Schleife. > > Dann schaust Du, ob bei übereinstimmenden Baudrates „11111111...“ > empfangen wird. Erst wenn das der Fall ist, nimmst Du die Arbeit am > Empfänger wieder auf. Dein Rat bin ich gefolgt, das Senden vom µC zum PC funktioniert einwandfrei, dabei ist es egal ob ich das mit 9600 Baud oder 115200 Baud probiere. Werde jetzt mal probieren was passiert wenn ich beim Empfang nicht via Interrupt sondern Polling gehe. Hänge jetzt mal bestehenden Code an. Einige Passagen habe ich aus kommentiert, das es ja der Test für das Senden war. \\\ .include "m32def.inc" ;Binding Definitionsfile for Processortype .equ F_CPU = 14745600 ;Systemclock in Hz .equ BAUD = 115200 ;Baudrate ; Calculation .equ UBRR_VAL = ((F_CPU+BAUD*8)/(BAUD*16)-1) .equ BAUD_REAL = (F_CPU/(16*(UBRR_VAL+1))) .equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000) .if ((BAUD_ERROR>10) || (BAUD_ERROR<-10)) ; max. +/-10 Promille error .error "SystemError: Baudrate-Error greater 1 Percent, thats to high!" .endif .def temp = R16 .def received = R18 .def counter1 = R20 .def counter2 = R21 .def counter3 = R22 .def count = R23 .org 0x00 RJMP Initialize ;Reset .org URXCaddr RJMP USART_RX_Complete ;USART Receive Complete Interrupt Vector Address RJMP mainloop Initialize: ;Stack LDI temp, LOW(RAMEND) OUT SPL, temp LDI temp, HIGH(RAMEND) OUT SPH, temp USART_Init: ; Set baud rate LDI temp, HIGH(UBRR_VAL) OUT UBRRH, temp ; LDI temp, 0x0F ;Asynchron, 14.7456 MHz, 115200Baud LDI temp, LOW(UBRR_VAL) OUT UBRRL, temp LDI temp, 0x00 ; LDI temp, (1<<U2X) ;Set to asynchonius mode OUT UCSRA, temp ;Enable receiver and transmitter LDI temp, 0x00 ; LDI temp, (1<<RXCIE)|(1<<TXCIE)|(1<<RXEN)|(1<<TXEN) LDI temp, (1<<RXCIE)|(1<<RXEN)|(1<<TXEN) ; OUT UCSRB, temp SBI UCSRB,TXEN ;Protocol: 8,N,1 LDI temp, 0x00 LDI temp, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0) OUT UCSRC, temp LDI temp, 0b11111111 OUT DDRC, temp ;Port C for Output ; SEI ;Enable Interupts RET MainLoop: RCALL Sync RCALL SerOut OUT PORTC, count INC count RJMP MainLoop USART_RX_Complete: PUSH temp ;Save temporary Variable IN temp, SREG PUSH temp ;Save Status-Register IN received, UDR ;Byte from USART OUT PORTC, received POP temp ;Restore Status-Register OUT SREG, temp POP temp ;Retore temporary Variable RETI SerOut: LDI Temp, 31 SBIS UCSRA,UDRE RJMP SerOut OUT UDR, temp RET Sync: LDI counter1,0 Sync_1: LDI counter2,0 Sync_2: LDI counter3,0 ;Sync_3: ; DEC counter3 ; BRNE Sync_3 DEC counter2 BRNE Sync_2 DEC counter1 BRNE Sync_1 RET /// Wie Du siehst, ist da wirklich nichts hinter, Die Empfangsroutine habe ich seit Gestern nicht geändert. Ich habe nur den Interrupt disabled und die Senderoutine eingebaut. -- Gruß Karsten
Hardwareproblem? Pegelwandler? Mit dem Oszi schonmal die Flanken angeschaut?
Fhutdhb Ufzjjuz schrieb: > Hardwareproblem? Pegelwandler? Mit dem Oszi schonmal die Flanken > angeschaut? Hallo, der FT232RL funktioniert einwandfrei(den habe ich in einer anderen Anwendung getestet), auch der µC scheint nicht defekt zu sein(Schon ausgetauscht). -- Gruß Karsten
Welches Zeichen erscheint denn? Was mich stutzig macht: Du machst
1 | ldi temp, 31 |
2 | [...] |
3 | OUT UDR, temp |
Damit sendest Du aber keine '1' (0x31), sondern das Kontrollzeichen 0x1f. Keine Ahnung, wie Dein Terminalprogramm das darstellt. Bei abweichender Baudrate oder sonstigen Fehlern auf der Übertragungsstrecke kann aber durchaus ein Zeichen ankommen (oder auch mehrere, wenn die Sendebaudrate deutlich unter der Empfangsbaudrate liegt). Wichtig ist also in diesem Fall, dass das richtige Zeichen ankommt. Kommt denn wirklich 0x1f an?
Karsten Sosna schrieb: > Interrupt sondern Polling gehe. Hänge jetzt mal bestehenden Code an. > .org 0x00 > RJMP Initialize ;Reset > Initialize: > > ;Stack > LDI temp, LOW(RAMEND) > OUT SPL, temp > LDI temp, HIGH(RAMEND) > OUT SPH, temp > > USART_Init: > ; Set baud rate .... > RET Ich frage mich wie das da überhaupt funktionieren kann. Vom Reset vector springst du in Initialize, danach fällst du in USART_Init durch und dann machst du ein RET. Wohin soll es denn RETurnen?
> Welches Zeichen erscheint denn? Was mich stutzig macht: Du machst >
1 | > ldi temp, 31 |
2 | > [...] |
3 | > OUT UDR, temp |
4 | > |
> Damit sendest Du aber keine '1' (0x31), sondern das Kontrollzeichen > 0x1f. Keine Ahnung, wie Dein Terminalprogramm das darstellt. Hallo, das ist mir schon klar und war auch so gewollt, übertragen werden grunsätzlich binäre Daten. Daher ist es egal, wenn ich 31 sende muss auf der PC-Seite 31(oder 0x1F) abkommen und das tat es. Nichts desto trotz lief der µC auch dann im Empfang mit Interrupt. 2-3 mal und dann war wieder Schluß, nur noch Schrott. Also dachte ich es liegt vielleicht an der CKOPT-Fuse, also wieder umgesetzt, danach ging gar nichts mehr, also wieder zurückgesetzt. Gleiches Ergebnis. :=( Also habe ich etwas Forschung betrieben und festgestellt, das der µC zeitweilig resetet wurde, ergo habe ich ihn mal ausgetauscht, gleiches Ergebnis. Also konnte es nur am Programm liegen. Dann kam die Erleuchtung, bei dem Reset handelt es sich ja nicht um ein Hardware-Reset sondern um ein Software-Reset und damit standen meine Register im Nirwana. Jetzt habe ich die Register sauber initialisiert und siehe da alles funktioniert bestens. Ich habe jetzt meine Übertragung auf 230400, 8, N, 1, Asynchron und keine Probleme. Also hier sind zwei Dinge zusammen gefallen. Das eine war die falsch eingestellte Fuse und das andere die falsch initialisierten Register womit ich dann eine falsche Anzeige hatte. So nun läuft er wie ich mir das vorstelle. Ich bedanke mich daher ganz besonders bei Dir und natürlich auch bei allen anderen für die Unterstützung. -- Gruß Karsten
> Ich frage mich wie das da überhaupt funktionieren kann. > Vom Reset vector springst du in Initialize, danach fällst du in > USART_Init durch und dann machst du ein RET. Wohin soll es denn > RETurnen? Hallo Michael, da ist was beim Formartieren schief gegangen. Wenn ch den Code aus dem AVR-Studio hierher kopiere kann das kein Mensch mehr lesen. Das RET steht da nicht im Orignal, weiß nicht wie es da hin gekommen ist. -- Gruß Karsten
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.