Hallo,
ich benütze Debian (10/buster) mit avr-gcc um meinen ATMEGA16 am STK500
zu programmieren.
Soweit so gut, meine Programme compilieren und werden richtig
programmiert und ausgefuehrt.
Jeoch habe ich jetzt ein Problem mit einer eigentlich simplen Schleife
1
voidloopFunction(void)
2
{
3
char*mystring="ABCDEF";
4
inti=0;
5
for(i=0;i<3;i++){
6
LCD_Write(mystring[i]);
7
}
8
}
Diese funktioniert, und (schlussendlich wird ABC am LCD Display
angezeigt). Wenn ich jedoch die Abbruchbedingung erhoehe:
1
voidloopFunction(void)
2
{
3
char*mystring="ABCDEF";
4
inti=0;
5
for(i=0;i<4;i++){
6
LCD_Write(mystring[i]);
7
}
8
}
werden am LCD Display zwar 4 Zeichen ausgegeben, aber nur Mist, bzw. das
Symbol zum Wert 0xFF.
Da der Code mMn eigentlich richtig aussieht, hab ich ins generierte
Assembler reingeschaut, via
mrleop schrieb:> da scheint, als ob die Werte gar nicht mehr geladen werden:
Aber nur, weil du offensichtlich keine wirkliche Idee vom AVR-Assembler
hast.
Selbstverständlich werden die Werte geladen. Bis zu drei Zeichen hat der
Compiler nur die Schleife entrollt, weil das nach seiner Berechnung die
sparsamere Variante war.
Jörg W. schrieb:> Allerdings wäre es wohl "netter", wenn du nicht nur einen Zeiger> auf ein> anonymes Array baust, sondern lieber das Array selbst referenzierst:> char mystring[6] = "ABCDEF";
Damit habe ich leider das selbe problem.
> Noch besser wäre es am Ende, das auch noch in den Flash zu packen:> char __flash mystring[6] = "ABCDEF";
Dazu muss ich das array aber noch statisch und const definieren, oder?
Anosten bekomme ich compiler errors.
mrleop schrieb:> Dazu muss ich das array aber noch statisch und const definieren, oder?
Ja. Ist ja irgendwie logisch: Flash ist halt dauerhaft (static) und
konstant (nicht zur Laufzeit änderbar, zumindest nicht direkt).
> Aber wo ist dann der Fehler wenn ich einfach>
1
>charmystring[6]="ABCDEF";
2
>
> verwende?
Weiß ich nicht – jedenfalls liegt er nicht in den paar Zeilen
Assemblercode, die du oben gepostet hast. Die sind OK. Es wird halt ein
Indirektzugriff über das Y-Register benutzt statt der Direktoperanden,
die die entrollte Schleife benutzt hat.
Irgendwas wird wohl mit deiner Linkerei nicht hinhauen, sodass die Daten
deines Arrays nicht da gelandet sind, wo sie eigentlich sein müssten.
Um das aber debuggen zu können, müsstest du ein komplettes
(einschließlich Makefile oder Linkerscripts etc.) minimales Beispiel
posten statt der paar Zeilen Code.
Hm... mystring liegt ja im RAM. Für mich sieht es so aus, als ob bei
Startup der Code fehlt oder fehlerhaft ist, der String Literale aus dem
Flash ins RAM kopiert.
Der Kode in Ausgangsposting ist schon korrekt und sollte funktionieren.
Folgendes fällt mir ein, warum es schief gehen könnte:
1) LCD_Write ist handgestrickter Assemblercode, der das
Y-Register(R28/R29) vermanscht.
2) Interrupt-Routinen vermanschen das Y-Register.
3) Der Stack ist zu klein und läuft in den RAM-Bereich rein, in dem der
String steht.
4) Das Datensegment ist zu groß und keiner hat's gemerkt.
5) Der Linker erzeugt Mist (falsches Script? Selbst gebastelt?).
2^5 schrieb:> Für mich sieht es so aus, als ob bei Startup der Code fehlt oder> fehlerhaft ist, der String Literale aus dem Flash ins RAM kopiert.
Das wäre jetzt auch meine erste Vermutung, daher die Frage nach einem
komplette Minimalprojekt.
Hi,
vielen Dank für die Antworten!
Ich hab mal versucht, mein Programm sehr minimal zu machen, um weitere
Einfluesse zu eliminieren. Dazu hab ich auch das ganze LCD ansteuern
rausgeschmissen, und lass stattdessen meine LEDs blinken.
1
#define F_CPU 1000000UL /* Clock Frequency = 1Mhz */
mrleop schrieb:> rom.hex : lcd.out> $(OBJCOPY) -j .text -O ihex lcd.out rom.hex
Da liegt der Hase im Pfeffer: du kopierst nur .text, damit gehen dir die
Initialwerte für das Datensegment verloren, die stehen nämlich in .data.
Richtig wäre also -j .text -j .data.
Aber Empfehlung: lass den ganzen Zirkus mit der Hexdatei weg, und flashe
direkt die ELF-Datei (die bei dir lcd.out heißt).
> $(PROGRAMMER) $(PFLAGS) -e
Würde ich ganz weglassen, vorheriges Löschen ist beim Schreiben des
Flashs implizit.
> $(PROGRAMMER) $(PFLAGS) -U flash:w:rom.hex
Ersetze das beides durch:
Jörg W. schrieb:> Da liegt der Hase im Pfeffer: du kopierst nur .text, damit gehen dir die> Initialwerte für das Datensegment verloren, die stehen nämlich in .data.>> Richtig wäre also -j .text -j .data.
Mhm, also ein klassisches Layer8 Problem.
> Ersetze das beides durch:> $(PROGRAMMER) $(PFLAGS) -U lcd.out
Damit funktioniert es einwandfrei :) Vielen Dank an alle die mir
geholfen haben!
Walter T. schrieb:> Kein Platz für den Terminator.
Da er die Schleife anderweitig terminieren lassen will, ist das egal.
Wenn man den Terminator haben will, schreibt man einfach
Jörg W. schrieb:> Da er die Schleife anderweitig terminieren lassen will, ist das egal.
Hoppla. Tatsache. Ich hätte eine Compiler-Warnung erwartet, wenn ein
6-Zeichen-Array mit einem 7-Zeichen Literal initialisiert wird.
Warum ist "ABCDEF" manchmal ein Literal mit 6 oder 7 Zeichen?
Nach welcher Regel ist ersteres nicht mit dem zweiten identisch (und
wird vom Compiler mit "excess element" bemängelt) ?
(Wenn das hier zu Off-Topic ist, stelle ich die Frage an anderer Stelle
nochmal.)
Walter T. schrieb:> Jörg W. schrieb:>> Da er die Schleife anderweitig terminieren lassen will, ist das egal.>> Hoppla. Tatsache. Ich hätte eine Compiler-Warnung erwartet, wenn ein> 6-Zeichen-Array mit einem 7-Zeichen Literal initialisiert wird.>
> Warum ist "ABCDEF" manchmal ein Literal mit 6 oder 7 Zeichen?> Nach welcher Regel ist ersteres nicht mit dem zweiten identisch (und> wird vom Compiler mit "excess element" bemängelt) ?>> (Wenn das hier zu Off-Topic ist, stelle ich die Frage an anderer Stelle> nochmal.)
C-Compiler denken einfach: hätte der eine String gewollt, hätte er keine
Länge angegeben.