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
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