Forum: Mikrocontroller und Digitale Elektronik Fehler bei UART unter ASM, nicht bei C-Programm


von Meiermann (Gast)


Lesenswert?

Hallo allerseits,

ich nutze hier einen ATmega16 mit externem Quarz (14.7456 MHz).
Für UART habe ich einen USB-Serial-Wandler aus dem nur noch RX und TX 
raus/reinführen.

Nach dem Löten prüfe ich den UART immer mit einem C-Programm, welches 
die empfangenen Bytes wieder zurücksendet. Das funktioniert hier, die 
Einstellungen sind: 115200 Baud, 1 Stop, keine Parity.

Nun wollte ich ein Programm in Assembler schreiben, und damit ich da 
halbwegs debuggen kann, wollte ich von dort den UART nutzen, um Daten 
zurückzusenden.

Da keine Daten zurückkamen, habe ich mein C-Programm auf ASM übersetzt 
und das eingespielt. Nun kommen zwar Bytes zurück, aber nie genau die 
die man sendet. Sende ich 0 kommt 0xFF, sende ich 0xAA kommt 0xAB 
(manchmal kommt auch was ganz anderes, weswegen ich glaube, dass es 
irgendwie mit dem UART-Timing zusammenhängt).

Die beiden Programm sind hier: (C-Programm, funktioniert)
1
#include <avr/io.h>
2
#include <inttypes.h>
3
#include <avr/interrupt.h>
4
5
// Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!
6
7
#define FR_CPU 14745600L
8
#define BAUD 115200L
9
10
// Berechnungen
11
// clever runden
12
#define UBRR_VAL  ((FR_CPU+BAUD*8)/(BAUD*16)-1)  
13
// Reale Baudrate
14
#define BAUD_REAL (FR_CPU/(16*(UBRR_VAL+1)))  
15
// Fehler in Promille 
16
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) 
17
 
18
#if ((BAUD_ERROR > 10) || (BAUD_ERROR < -10))
19
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
20
#endif
21
22
23
int main (void) {
24
25
UCSRB |= (1<<RXEN)|(1<<TXEN);               // UART RX/TX einschalten
26
UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // Asynchron 8N1 
27
UBRRH = UBRR_VAL >> 8;
28
UBRRL = UBRR_VAL & 0xFF;
29
30
while(1) { // endloses while(1) -- Hauptschleife
31
32
if (UCSRA & (1<<RXC))   // prüfen ob Zeichen verfuegbar
33
  {// USART - Eingang verarbeiten
34
  uint8_t x = UDR;
35
  UDR = x;  // Rücksendung als Echo
36
  }
37
38
}// endloses while(1)
39
// Ende
40
return 0;
41
}
und (ASM-Programm, gibt Unerwartetes zurück)
1
.include "m16def.inc"
2
3
.equ XTAL = 14745600
4
5
.def var1    = r16    ; temp-var für Hauptprogramm
6
.def var2    = r17    ; temp-var für Hauptprogramm
7
8
9
10
; USART
11
.equ F_CPU = 14745600                           ; Systemtakt in Hz
12
.equ BAUD  = 115200                             ; Baudrate
13
14
; USART  Berechnungen
15
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
16
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
17
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
18
 
19
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
20
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
21
.endif
22
23
24
; ########################################################################################
25
.org 0x0000
26
        rjmp    Programmstart    ; Reset Handler
27
; ########################################################################################
28
29
30
31
Programmstart:
32
    ; Stackpointer initialisieren
33
        ldi     r17      , LOW(RAMEND)
34
        out     SPL      , r17
35
        ldi     r17      , HIGH(RAMEND)
36
        out     SPH      , r17
37
  
38
39
    ; Enable USART (Baudrate einstellen)
40
    ldi     var1    , HIGH(UBRR_VAL)
41
    sts     UBRRH    , var1
42
    ldi     var1    , LOW(UBRR_VAL)
43
    sts     UBRRL    , var1
44
    ; USART (Frame-Format: 8 Bit)
45
    ldi     var1    , (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)
46
    out     UCSRC    , var1
47
    ; RX und TX erlauben
48
    ldi     var1    , (1<<TXEN)|(1<<RXEN)
49
    out     UCSRB    , var1
50
51
Hauptprogramm:  
52
    ;USART prüfen / lesen
53
    sbis  UCSRA    , RXC
54
    rjmp  Hauptprogramm
55
56
    in    var1    , UDR
57
WaitUDRE:
58
    sbis  UCSRA    , UDRE
59
    rjmp  WaitUDRE
60
    
61
    out    UDR      , var1
62
    
63
    rjmp  Hauptprogramm
Kann es sein, dass der Fehler über die Baud-Ratenformel kommt?

Gruß,
Meiermann

von spess53 (Gast)


Lesenswert?

Hi

Eigentlich ist die Initialisierung im C-Programm falsch. Siehe 
Datenblatt:

'Accessing UBRRH/ UCSRC Registers'.

MfG Spess

von Meiermann (Gast)


Lesenswert?

Hm, das stimmt wohl, aber unter 'USART Initialization' im gleichen 
Datenblatt steht das Codebeispiel (fast genau) wie bei mir.

Sehr sonderbar alles, zumal das C-Programm ja funktioniert.

Die Reihenfolge der Register-Eintragungen habe ich mal im ASM der des 
C-Programms angegleichen, das Verhalten ändert sich aber trotzdem nicht.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Meiermann schrieb:
> Kann es sein, dass der Fehler über die Baud-Ratenformel kommt?
Hast du einfach mal nachgerechnet?
Was kommt raus, wenn du die Werte "hart" einträgst?

von spess53 (Gast)


Lesenswert?

Hi

In deinem ASM-Pprogramm ist ein gravierender Fehler:

>    ldi     var1    , HIGH(UBRR_VAL)
>    sts     UBRRH    , var1
>    ldi     var1    , LOW(UBRR_VAL)
>    sts     UBRRL    , var1

Die Adressen von UBRRH und UBRRL sind für IO-Adressen. Die kannst du 
nicht mit sts/lds verwenden.

MfG Spess

von Meiermann (Gast)


Lesenswert?

Tatsache, out statt sts und schon geht alles :).

Wäre mir im Leben nicht aufgefallen, da viele Programmbeispiele von out 
auf sts geändert werden müssen, wegen der Reichweite...

Danke!
Ich hab sonst schon jede Zeite 3 mal neu 
geschrieben/geändert/umgruppiert.

von Klaus2m5 (Gast)


Lesenswert?

spess53 schrieb:
> Die Adressen von UBRRH und UBRRL sind für IO-Adressen. Die kannst du
> nicht mit sts/lds verwenden.

Vermutlich ursprünglich für einen der neueren AVRs unsauber 
programmiert.

In jedem Fall richtig wäre es so:
1
.macro output
2
  .if @0 < 0x40
3
    out  @0, @1
4
  .else
5
    sts  @0, @1
6
  .endif
7
.endm 
8
...
9
    ldi     var1    , HIGH(UBRR_VAL)
10
    output  UBRRH    , var1
11
    ldi     var1    , LOW(UBRR_VAL)
12
    output  UBRRL    , var1
13
...

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.