Forum: Mikrocontroller und Digitale Elektronik USART-EEPROM asm: begrenzte Zeichenanzahl?


von Fritzl W. (friz)


Lesenswert?

Hy,
Ich habe hier einen Atmega8L ohne Quarz mit FTDI232 Kabel an meinem 
Laptop.
Ich sende Strings an die USART des m8 welche er im EEPROM speichert
und mir über Int0 dann wieder am USART ausgeben soll. Das funktioniert 
auch, bis ich mit der BaudRate hochgehe bis (die erforderlichen) 57600!
Je höher die BaudRate wird umso weniger Zeichen bekomme ich zurück, oder 
vertauschte Zeichen.

So sieht die Ausgabe im Terminal (Termite3.1) aus :

1Gesendet: 1200=Baudrate/Test:1234567890123456789012345678901234567890
1Bekommen: 1200=Baudrate/Test:1234567890123456789012345678901234567890
Soweit OK
2Gesendet: 2400=Baudrate/Test:1234567890123456789012345678901234567890
2Bekommen: 2400=Bart/et13579135791357913579
Schlecht
3Gesendet: 4800=Baudrate/Test:1234567890123456789012345678901234567890
3Bekommen: 4800=r/t3715937159
Schlechter
4Gesendet: 57600=Baudrate/Test:1234567890123456789012345678901234567890
4Bekommen: 57600
Depremierendes Ergebniss! Im HTerm siehts genauso aus!

Hab schon einiges probiert, aber immer mit dem gleichen Ergebniss!
*1 Am fehlenden Quarz oder der Baudratenabweichung von 3,6% sollte es 
nicht liegen weil ich grössere ZeichenStrings ohne Probleme schicken 
kann, nur nicht im EEPROM speichern.
*2 Die Interrupts kommen sich auch nicht in die quere. "Glaubichhaltso"
*3 Kann es sein das "usartrxc"-ISR zu langsam ist und sich nach ein paar 
Zeichen verhaschpelt?

Hier der Quellcode:

[avrasm]
 .include "m8def.inc"
;
 .equ  f_cpu      = 8000000    ;Prozessortakt
 .equ  baud       = 57600    ;Gewünschte Baudrate
 ;
 .equ  ubrr_val   = ((f_cpu+baud*8)/(baud*16)-1);Clever runden
 .equ  baud_real  = (f_cpu/(16*(ubrr_val+1)));Reale Baudrate
 .equ  baud_error  =((baud_real*1000)/baud-1000)  ;Fehler in Promille
 ;
 .if  ((baud_error>36) || (baud_error<-36))
  .error "Baudrate Error"
 .endif
;
 intx0:;;;;;;;;;;;;;;;Insert Interrupt Routine bei Tastendruck
;
eeprom_read:
    sbic  eecr,    eewe
    rjmp  eeprom_read
    out   eearh,   zh         ;EEPROM Adresse bekantgeben
    out   eearl,   zl
    sbi   eecr,    eere
    in    zeichen, eedr
 ;
  serout:
    sbis  ucsra,  udre
    rjmp  serout
    out   udr,    zeichen    ;Zeichen senden
 ;
    adiw  Zl,      1          ; Zeiger erhöhen
    cpi   zeichen, '\r'       ; auf CR warten
    brne  eeprom_read         ;ungleich, springen
    ldi   ZL,      low(Daten)
    ldi   ZH,      high(Daten)
lange_pause
    reti
 usartrxc:;;;;;;;;;;;Insert Interrupt Routine
;
    in    zeichen, udr       ;Zeichen holen
;
  eeprom_write:
    sbic  eecr,    eewe
    rjmp  eeprom_write
    out   eearh,   zh        ;EEPROM Adresse bekantgeben
    out   eearl,   zl
    out   eedr,    zeichen   ;Zeichen laden
    sbi   eecr,    eemwe
    sbi   eecr,    eewe      ;Zeichen absenden an EEPROM
 ;
    adiw  Zl,      1          ; Zeiger erhöhen
    cpi   zeichen, '\r'       ; auf CR warten
    brne  eeprom_write1       ; wenn ungleich, springen
    ldi   ZL,      low(Daten) ; zurücksetzen
    ldi   ZH,      high(Daten)
  eeprom_write1:
    reti
 ;;;;;;;;;;;;;;PROGRAMM START;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 reset:
    ldi   ssr,  high(RAMEND)       ;Stack
    out   sph,  ssr
    ldi   ssr,  low(RAMEND)
    out   spl,  ssr
;
    ldi   ZL,   low(daten)
    ldi   ZH,   high(daten)
;
    sbi  ucsrb,  txen               ;USART senden aktiviert
    sbi  ucsrb,  rxen               ;USART empfangen aktiviert
    sbi  ucsrb,  rxcie              ;Interrupt bei USART Empfang
    ldi  ssr,    (1<<ursel | 1<<ucsz1 | 1<<ucsz0)
    out  ucsrc,  ssr                ;8 Datenbits, kein Parity, 1 Stop
    ldi  ssr,    HIGH(ubrr_val)
    out  ubrrh,  ssr
    ldi  ssr,    LOW(ubrr_val)
    out  ubrrl,  ssr
;
    sei
 loop:
          rjmp  loop
.ESEG
      Daten:
             .db     0
[avrasm]

: Bearbeitet durch User
von HalbTroll (Gast)


Lesenswert?

Serout() ist ja blockierend. Das geht so natuerlich nicht. Mach das per 
interrupt.

von Jim M. (turboj)


Lesenswert?

Schau mal im Datenblatt nach, wie lange das Schreiben eines EEPROM Bytes 
dauert. Das darf bei Dir nur eine Byte-Zeit beim UART lang sein, was 
vermutlich nur für 1200 Baud zutrifft.

Abhilfe für schnellere Baudraten: String puffern und erst am Ende der 
Übertragung ins EEPROM schreiben.

von Klaus 2. (klaus2m5)


Lesenswert?

Jim Meba schrieb:
> Schau mal im Datenblatt nach, wie lange das Schreiben eines EEPROM Bytes
> dauert. Das darf bei Dir nur eine Byte-Zeit beim UART lang sein, was
> vermutlich nur für 1200 Baud zutrifft.

Im Datenblatt steht 8,5ms/Byte abhängig von der Genauigkeit des internen 
RC-Oscillators (1MHz und unabhängig von der tatsächlichen CPU clock).

Das ergibt 117,6 Bytes pro Sekunde und ist für 1200 Baud eigentlich 
schon zu knapp.

: Bearbeitet durch User
von Fritzl W. (friz)


Lesenswert?

Jim Meba schrieb:
> Schau mal im Datenblatt nach, wie lange das Schreiben eines EEPROM Bytes
> dauert. Das darf bei Dir nur eine Byte-Zeit beim UART lang sein, was
> vermutlich nur für 1200 Baud zutrifft.
>
> Abhilfe für schnellere Baudraten: String puffern und erst am Ende der
> Übertragung ins EEPROM schreiben.


Klaus 2m5 schrieb:
> Im Datenblatt steht 8,5ms/Byte abhängig von der Genauigkeit des internen
> RC-Oscillators (1MHz und unabhängig von der tatsächlichen CPU clock).
>
> Das ergibt 117,6 Bytes pro Sekunde und ist für 1200 Baud eigentlich
> schon zu knapp.

Genau das habe ich auch gerade gelesen. Das wird wohl der Fehler sein! 
:-)
Wenn ich fertig bin mit lesen und programmieren werd ich mal posten wies 
ausgegangen ist.
Vielen Dank erstmal.

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.