Forum: Compiler & IDEs UART Problem (Assembler zu C) III


von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

Hallo,
ich habe jetzt mal ein Programm geschrieben, was nur das Sendet, was es 
Empfängt. Und es kommt wieder zum gleichen Phänomen. Wenn ich 1 sende 
bekomme ich F1 zurück bei 2 F2 usw. Bei 15 D5 aber wieso zum teufel wird 
dann die erste gesendete 15 vom Rechner korrekt erkannt? Im Anhang die 
aktuelle Komplettversion.

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

und hier das Testprogramm:

von Flo S. (tuxianer)


Lesenswert?

es kann ja nur sein, das der UART falsch initialisiert wird. Im ASM 
gehts ja korrekt. Ist der restliche Code ok? Ich habe versucht mit der 
statemachine weiter zu arbeiten.

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

ich hab die UART1 Auswertung mal erweiter also auf stand der 0 gemacht 
und die Auswertung kommentiert.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

An eine falsche Initialisierung vom UART glaube ich nicht. Ich hatte ja 
deinen Code bzw. die Initialisierung auf einem Atmega32 und angepasstem 
F_CPU laufen lassen und das funktionierte mit einem PC auf der 
Gegenseite. Ich habe aber keinen Atmega162 zum testen, vielleicht jemand 
anderes?

Du könntest aber nachsehen, ob der ASM-Code aus der LSS-Datei die 
UART-Register genauso initialisiert wie der disassemblierte Code (Suche 
im Forum µC & Elektronik nach Disassemb*) des funktionsfähigen Programms 
aus den ASM-Quellen.

Warum schlage ich so was kompliziertes wie ein Disassemblieren vor? Bist 
du 1000% sicher, dass das lauffähige Programm aus bereits gezeigten 
ASM-Quellen entstanden ist?

Vorherige Threads:
Beitrag "UART Programm (Umwandlung von Assembler zu C)"
Beitrag "UART Problem (Assembler zu C) II"

von Flo S. (tuxianer)


Lesenswert?

Also das ASM Programm läuft sowohl mit dem Rechner als auch am PC( es 
sendet die korrekten Werte). Ich werde mich mal über das disassemblieren 
belesen. Danke für den Tipp.

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

ich habs mal mit revava disassembliert aber ich weis nicht, ob ichs
korrekt gemacht habe:

ich habe den syntax benutzt: revava -o /ziel.txt /source.hex

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das sieht nicht so gut aus. Vielleicht ist der falsche AVR eingestellt 
(siehe erste Zeile #arch AT90S8515) oder dieser Disassembler ist hierfür 
untauglich oder das Hex-file ist tatsächlich ganz was anderes als dein 
bisheriges ASM-Listing. Ich würde als ersten disassemblierten ASM-Befehl 
ein rjmp erwarten.

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

hmmm...es kann auch sein es funktioniert nicht mit dem Programm ich 
bekomme sowohl beim C als auch beim ASM Programm die falsche #arch)
Kann mal bitte jemand der nen anderen hat die Hex mal durch jagen?

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

Ich habs mal ins AVR-Studio geladen:

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ein Unterschied ist bei der Initialisierung beim C-Code im Vergleich zum 
ASM-Code:

Im C-Code werden UCSRxC und UCSRxB verODERt gesetzt, während sie im 
ASM-Code direkte Werte bekommen.

Der neue C-Code sähe so aus:
1
  //Baudrate 9k6 UART0
2
  UBRR0H = UBRR_VAL >> 8;   // ASM: 0
3
  UBRR0L = UBRR_VAL & 0xFF; // ASM: 0x2F = 47 dito in C
4
  
5
  //Baudrate 9k6 UART1
6
  UBRR1H = UBRR_VAL >> 8;
7
  UBRR1L = UBRR_VAL & 0xFF;
8
9
  //Uebertragungsart  8N2
10
  UCSR1C = (1<<URSEL1)|(1<<USBS1)|(1<<UCSZ11)|(1<<UCSZ01); 
11
  // ASM: -0x72 = 0x8E = 10001110 = Bits 7,3,2,1
12
  // in C OK      
13
  UCSR0C = (1<<URSEL0)|(1<<USBS0)|(1<<UCSZ10)|(1<<UCSZ00);
14
15
  //Interrupts, Senden und Empfangen aktivieren
16
  UCSR1B = (1<<RXCIE1)|(1<<RXEN1)|(1<<TXEN1); 
17
  // ASM: Bits 7,4,3
18
  // in C OK
19
  UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0);

von Flo S. (tuxianer)


Lesenswert?

immer noch das selbe. Ich hab echt keinen Plan woran das liegen könnte.

von Flo S. (tuxianer)


Lesenswert?

das Problem kann aber anscheinend nur bei der übergabe in die Sende 
Funktion liegen! Das 0x15 wird ja anscheinen Korrekt erkannt.

von Flo S. (tuxianer)


Lesenswert?

kann es daran liegen, das ich verschiedene Typen benutze?

Also
UCUDR: unsigned int
c: uint8_t
send: int

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

hier nochmal das makefile:

von Flo S. (tuxianer)


Lesenswert?

Ok ich glaub ich habs irgendwie sind die Databytes falsch eingestellt. 
Wenn ich si am PC auf 7 stelle kommt das Richtige an! Kann da bitte 
nochmal jemand mit schauen?

von Jörg X. (Gast)


Lesenswert?

Ein Blick in's 'Register Summary' sagt, dass du da Bit namen 
verwechselt, bzw einen Zahlendreher hast:
1
//Uebertragungsart  8N2
2
  UCSR1C = (1<<URSEL1)|(1<<USBS1)|(1<<UCSZ11)|(1<<UCSZ01);
3
                                                      ^^
4
                                                  UCSZ10 
5
  // ASM: -0x72 = 0x8E = 10001110 = Bits 7,3,2,1
6
  // in C OK      
7
  UCSR0C = (1<<URSEL0)|(1<<USBS0)|(1<<UCSZ10)|(1<<UCSZ00);
8
                                          ^^
9
                                      UCSZ01
hth. Jörg

ps.: Ich weiß das, weil ich den Fehler schon mal behoben hab, nicht weil 
ich das datenblatt auswendig kann ;)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das ist's, Jörg. Genial! Ist mir bei jeder Kontrolle durchgeflutscht.

von Flo S. (tuxianer)


Lesenswert?

Ja echt spitze!!! Ich wusste doch daran muss es liegen aber was falsch 
ist habe ich nie bemerkt! Ich werd mich jetzt mal drann machen kleine 
Fehler zu beseitigen!

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

komisch...jetzt sendet es wenn ich 15 sende die 13 aber die 06 nicht 
mehr nach den 50 zeichen. ohne die Korrektur ging es, nur das die 
falschen werte ankamen...

von Flo S. (tuxianer)


Lesenswert?

ok liegt wahrscheinlich doch an was anderem!

von Flo S. (tuxianer)


Lesenswert?


von Flo S. (tuxianer)


Lesenswert?

diese Variante Funktioniert auch nach der Änderung mit der UART.

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

so ich habe meinen aktuellen mal reduziert aber immer noch das gleiche.

auffällig ist bei dem alten, der geht ist nachdem ich 15 sende
headercounter0 0 beim neuen aber 1.

von Flo S. (tuxianer)


Lesenswert?

so ich hab mal alles nach und nach gelöscht und es scheint daran zu 
liegen:
1
uint8_t SendHeader [] = {0x3a,'V', 'A', 'L', 0x00, 'V','M', 0x00,0x01,0x00,0x01,'A', 0xff,0xff,0xff,0xff,0xff,0xff,0xff,'V','a', 'r', 'i', 'a', 'b', 'l', 'e', 'R', 0x0A,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd0};
2
uint8_t SendEheader [] = {0x3A,0x45,0x4E,0x44,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x56};

aber wieso wird HeaderCounter0 nicht erhöht wie hängt denn das zusammen?

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

ich werd verrückt...das gleiche mit dem End_header. Ich hab das 
geschrieben:
1
  while(1) {
2
  
3
  
4
    if(ucUDR_valid0) {
5
    
6
            if(State0 == REC_FOOTER) {
7
      Transmit0(EndCounter0);
8
    }

und wenn ich am Computer so lange gesendet habe, bis ich dort bin 
schickt der µC entweder 35 oder 25 zurück keine Spur von einer Variable, 
die Hochzählt.

von Flo S. (tuxianer)


Lesenswert?

irgendwas scheint mit der Speicherverwaltung oder so nicht zu stimmen. 
Ich habe keine Ahnung, wo dort ne 23 oder 35 herkommt.

von Flo S. (tuxianer)


Lesenswert?

diesmal hilft es, wenn ich

uint8_t Daten0[384];
und
uint8_t Daten1[384];

lösche...ich kann mir nicht erklären, wo das Problem herkommt.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Wenn das Rausnehmen von fetten Feldern die Situation verbessert, ist 
bestimmt die Speicherauslastung an der Grenze. Wie ist denn der 
Speicherfüllgrad?

Bei http://www.mikrocontroller.net/articles/AVR-GCC#Tipps_.26_Tricks 
unter der Beschreibung des Tools avr-size nachsehen, Werte für die 
ELF-Datei ermitteln und mit dem Datenblatt vergleichen.

Das SRAM muss ausserdem noch einen Stack aufnehmen, d.h. data+bss Grösse 
muss entsprechend kleiner als die SRAM Grösse sein.

ADD:
> Atmega162
> Flash (Kbytes)  16
> EEPROM (Kbytes) 0.5
> SRAM (Bytes)    1024

Da bist du mit zwei Feldern zu je 384 Bytes schon anständig am SRAM 
füllen!

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

also bei der Version kommt:

   text    data     bss     dec     hex filename
   1376       0    1023    2399     95f /Test.elf

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

bei der:

   text    data     bss     dec     hex filename
    688     100    1023    1811     713 /New.elf

von Stefan B. (stefan) Benutzerseite


Lesenswert?

1023 Bytes uninitialiserte Variablen (Sektion bss) bekomme ich auch 
raus.

(EDIT: data 0 Problem hat sich erledigt)

Das SRAM ist für die Variablen dieses Programms zu klein. Du musst im 
Programm die Variablen deutlich abspecken.

von Flo S. (tuxianer)


Lesenswert?

naja die einzigen großen Variablen sind doch Daten0/1 aber im ASM 
klappts ja auch mit der Verwaltung das versteh ich noch nicht ganz.

wo sehe ich denn nu wie viel tatsächlich gebraucht werden?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

An der Ausgabe vom avr-size siehst du es. Dein Ziel muss sein:

FLASH-ROM >= text + data
SRAM >= data + bss + stack

Lediglich der Platzbedarf vom Stack (für die Rücksprungadressen beim 
Aufruf von Funktionen und ggf. Funktionsargumente soweit nicht in 
Registern übergeben) fehlt noch in der Berechnung. Den kann man 
abschätzen oder mit Versuchen ermitteln. Bei deinem Programm ist das 
nicht viel; vielleicht 50 Bytes?

Im C-Programm sind die Übergabevariablen aus den UART-ISRs und die 
Verwaltung der state machine hinzugekommen. Die Art und den Platzbedarf 
der Variablen im ASM-Programm kenne ich nicht. Bist du sicher, dass dort 
die gleichen Variablen benutzt werden?

von Flo S. (tuxianer)


Lesenswert?

also im ASM hab ichs so:
1
 .equ var0      = 0x0142
2
3
 .equ var1      = 0x02E2
4
5
 .equ Vartheta    = 0x0482
1
VariablenHeader:
2
3
.db 0x3a,'V', 'A', 'L', 0x00, 'V','M', 0x00,0x01,0x00
4
5
.db 0x01,'A', 0xff,0xff,0xff,0xff,0xff,0xff,0xff,'V' 
6
7
.db 'a', 'r', 'i', 'a', 'b', 'l', 'e', 'R', 0x0A,0xff  
8
9
.db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff  
10
11
.db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd0
12
13
14
15
Endheader:
16
17
.db 0x3A,0x45,0x4E,0x44,0xff,0xff,0xff,0xff,0xff,0xff
18
19
.db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
20
21
.db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
22
23
.db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
24
25
.db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x56

Das sind bei den Variablen sogar jeweils 32 Bytes mehr.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Die Zahlen sind nicht aussagekräftig. Es handelt sich bestimmt um 
Anfangsadressen von Variablen aber nicht um deren Länge. Die Länge aller 
Variablen plus der Stackbedarf bestimmt den benötigten Platz im SRAM.

In einem der Listings hattest du mal dies drin:

0x0100 ist die Startadresse vom internen SRAM in der 
Speicherkonfiguration A beim Atmega162 (Figure 9 im Datenblatt).
1
 ;interner RAM
2
 .equ Header    = 0x0100      ; 50 Bytes
3
 .equ Content   = 0x0132      ; 16 Bytes
4
 .equ var0      = 0x0142      ; 416 Bytes
5
 .equ var1      = 0x02E2      ; 416 Bytes
6
 .equ Vartheta  = 0x0482      ; 16 Bytes
7
 .equ Varr      = 0x0492      ; 16 Bytes
8
 .equ wandeldatalow  = 0x04a2 ; 1 Byte
9
 .equ wandeldatahigh = 0x04a3 ; 1 Byte
10
 .equ wandeltemp  = 0x04a4    ; 1 Byte ?
11
;                             ==========
12
;                               933 Bytes

Wenn man annimmt, dass die Variablen hintereinander stehen, kann man 
z.B. für Header einen Platzbedarf von 0x0132 - 0x0100 = 50 Bytes 
annehmen.

Schwierig wird es, bei der letzten Variablen wandeltemp. Da muss man im 
ASM-Listung nachsehen wie die benutzt wird. Vom Vergleich mit den 
anderen Wandeldingsen her möglicherweise als Byte.

Dann wäre hier der Platzbedarf insgesamt: 0x04a5-0x0100 = 0x03a5 = 933 
Bytes für die Variablen. Der Rest vom SRAM (1024-933 = 91) kann als 
Stack benutzt werden.

Vergleicht man ASM mit C sieht man, dass z.B. oben nur eine Variable für 
den 50-Bytes Header angelegt ist, während du im C Programm 4 Stück 
angelegt hast (Header Uart0, Header Uart1, SendHeader und 
SendEHeader)...

von Flo S. (tuxianer)


Lesenswert?

stimmt jetzt weis ich wie das zustande kommt. im asm kann theoretisch 
immer nur ein uart senden und empfangen im c theoretisch beide. deshalb 
habe ich die im ASM zusammengefasst. Wie es in der Praxis aussieht weis 
ich nicht...ob da beide Rechner zugleich senden können. Auserdem wird 
der Endheader nicht abgespeichert. Da ich den nicht brauche kann ich den 
im C auch löschen. Ich probier mal, was da noch zu optimieren geht.

Edit:

mit den Endheadern weg bin ich jetzt bei:
   text    data     bss     dec     hex filename
    734     100     923    1757     6dd /New.elf

also immer noch zuviel.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Wie Platz im SRAM sparen?

Möglichkeit 1: Platz hast du ja im FLASH_ROM genug. Du könntest z.B. die 
festen Werte von VariablenHeader und Endheader aus dem FLASH-ROM aus 
ausgeben und nicht aus dem SRAM heraus.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29

Möglichkeit 2: Benutze Felder wenn möglich mehrfach. Header und Content 
aus dem ASM-Listing scheinen keine Unterscheidung in Uart0/Uart2 zu 
brauchen. Vielleicht kannst du auch SendHeader und SendEHeader 
vermeiden, indem du deine Arbeitsvariable Header durch eine Funktion mit 
den Werten füllen lässt.

von Flo S. (tuxianer)


Lesenswert?

Naja im ASM brauchen die keine Unterscheidung, da das Programm ja in der 
Interrupt Routine festhängt. Aber im C können ja theoretisch beide 
Rechner zu gleich senden und ausgewertet werden.

wobei das ganze mit 2 Uarts Parallel evtl durch diese Stelle beindert 
werden könnte:
1
    if(ucUDR_valid0) {
2
      
3
      //Interrupts deaktivieren
4
      cli();              
5
      //Byte in c einlesen
6
      c = ucUDR0; //
7
      
8
      //ucUDR_valid0 zurücksetzen
9
      ucUDR_valid0 = 0;
10
      //Interrupts aktivieren
11
      sei();

aber man kann ja eigentlich auch nur das Interrupt für Uart 1/0 
deaktivieren oder?

Das ist eben die Frage wenn es gehen würde, dass man mit Zwei Rechnern 
zugleich kommunizieren kann das könnte man die Festen Daten in den Flash 
laden wenn nicht könnte man Die Daten zusammenfassen. Müsste aber dann 
die 2. Uart blockieren, so das nicht was überschrieben wird.

von Flo S. (tuxianer)


Lesenswert?

kann ich die Interrupts wieder mit:

UCSR1B |= (1<<RXCIE1)
UCSR1B &= (1<<RXCIE1)

aktivieren und deaktivieren im Programm? oder gibst da noch ne 
elegantere Lösung. Denn so könnte ich ja wie gesagt mit beiden Rechnern 
zugleich kommunizieren.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Der nächste Interrupt geht ja nicht verloren, sondern staut sich auf. 
Wenn sei die Interrupts global wieder zulässt, wird der angestaute 
Interrupt ausgelöst.

Ein Interrupt kann verloren gehen, wenn bei gesperrtem Interrupts die 
gleiche Interruptquelle mehrfach einen Interrupt melden will. Das ist 
hier im Fall der UARTs IMHO uninteressant - käme es zu diesem Fall, 
wären sowieso schon Zeichen verloren.

Dazu kommt es aber nicht, denn die Codestelle zwischen cli/sei ist sehr 
kurz im Vergleich zu der Zeit, die ein Zeichen bei 9600 Baud braucht, um 
vollständig im UART zu landen. Zweitens sind beim Atmega162 die UARTs 
für zwei Zeichen gepuffert.

Wenn du unbedingt ohne cli/sei arbeiten willst, kannst du das mit einer 
weiteren Hilfsvariable realisieren, die die ISR beim Schreibzugriff in 
main Däumchen drehen lässt.
1
volatile unsigned char main_ist_aktiv;
2
3
ISR...
4
{
5
   if (!main_ist_aktiv)
6
   {
7
      ucdata0 = UDR0;
8
      ucdata0_valid = 1;
9
   }
10
   else
11
   {
12
      // nix machen, der "gleiche" Interrupt 
13
      // kommt nach dem return gleich wieder
14
      // und hoffentlich hat main_ist_aktiv 
15
      // dann gewechselt
16
   }
17
}
18
19
int main(void)
20
{
21
   while(1)
22
   {
23
      if (ucdata0_valid) 
24
      {
25
         unsigned char c;
26
         main_ist_aktiv = 1;
27
         c = ucdata0;
28
         ucdata0_valid = 0;
29
         main_ist_aktiv = 1;
30
      }
31
   }
32
}

von Marco (Gast)


Lesenswert?

ok alsu durch den puffer dürfte es gehen. Das wäre dann glaube 
unrealistisch, das genau zwischen cli und sei 3x gesendet wird.

von Flo S. (tuxianer)


Lesenswert?

Ok Danke! Dann werde ich mir keine Gedanken über verlorene Zeichen 
machen müssen!

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.