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.
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.
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"
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.
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.
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?
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:
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?
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!
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...
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.
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.
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!
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.
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?
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?
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)...
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.
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.
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.
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.
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.