Hallo,
mein Programm stürzt beim Zugriff auf die mmc.h bzw die MMC-Karte ab.
ATMega8
mmc.h von U.Radig
WINAVR 20080610
AVR Studio 4.13 SP2
Minimalbeispiel:
while(a!=0)//ist der Rückgabewert ungleich NULL ist ein Fehler aufgetreten MMC/SD-Karte wird dann neu Initialisiert
19
{
20
a=mmc_init();
21
Timeout++;
22
if(Timeout==200)
23
{
24
lcd_string("no MMC");
25
break;
26
}
27
}
28
}
29
//Initialisierung der MMC/SD-Karte ENDE!
30
31
32
33
34
35
36
37
intmain(void)
38
{
39
chartmp;
40
lcd_init();
41
init_mmc();
42
set_cursor(0,1);
43
lcd_string("Schreibtest");
44
45
while(1)
46
{
47
lcd_home();
48
set_cursor(0,2);
49
lcd_string("Speichern");
50
_delay_ms(500);
51
tmp=mmc_write_sector(addr,Buffer);
52
set_cursor(0,2);
53
lcd_string("Fertig ");
54
_delay_ms(500);
55
}
56
57
return1;
58
}
Das Minimalbeispiel funktioniert. Das eigentliche Programm funktioniert
seit einiger Zeit plötzlich nicht mehr. Ich habe den Mega8 getauscht.
Danach ging es einmal und danach wieder nicht.
Nachvollziehbar nach dem Aufruf:
tmp = mmc_read_sector (addr,Buffer);
oder
tmp = mmc_write_sector (addr,Buffer);
macht das Programm nichts mehr.
mmc_init funktioniert
Beim Kompilieren bekomme ich eine Fehlermeldung:
../M8Timer1.c:356: warning: pointer targets in passing argument 2 of
'mmc_read_sector' differ in signedness
Kann diese mit dem Absturz zusammenhängen ?
Gruß
Günter
Wie ich jezt festgestellt habe, stürzt der Mega 8 nicht komplett ab.
Die Interruptroutine läuft noch.
Direkt vor dem Aufruf "tmp = mmc_read_sector (addr,Buffer);"
kann ich noch eine Meldung ausgeben. Wenn ich in der
mmc_read_sector-Funktion direkt am Anfang ein Printf einfüge, so wird
dieses nicht mehr ausgeführt. Kann es sein, dass das Programm zu tief
verschachtelt
ist und ins Nirwana springt ?
Tritt vielleicht ein Stacküberlauf oder so etwas auf ?
Günter
Hi,
ich habe auch diese Routinen eingesetzt und muss sagen, dass sie für den
m8 einfach zu viel Speicher brauchen. Versuch es mal mit einem m32.
zum anderen braucht die mmc eine vernünftige spannungsversorgung. gerne
mit kondensator oder spule.
AVR-Studio zeigt folgende Werte an:
Program: 7892 bytes (96.3% Full)
(.text + .data + .bootloader)
Data: 840 bytes (82.0% Full)
(.data + .bss + .noinit)
sollte doch eigentlich reichen oder sollte man Reserven lassen ?
Für die MMC habe ich einem LM317 eingesetzt.
Das Minimalprogramm läuft, deshalb vermute ich einen Programmfehler
meinerseits.
Kann ein AVR eventuell verschleissen ?
Ich habe ihn schon sehr oft programmiert.
Allerdings zeigt mir PonyProg beim Verify ein OK.
Die Karte scheint auch noch zu funktionieren.
INIT geht und mit dem PC funktioniert sie auch.
Hi,
da sollten auf jeden Fall noch Reserven bleiben. C braucht immer etwas
speicher für sich, die ganzen Funktionsaufrufe etc...
Wenn Du nicht gerade 342 Jahre alt bist oder jeden Tag im Jahr 50x
programmierst, dann funktioniert der AVR auch. Nur kurzschluss und
falsche polung zerschiessen ihn sofort.
wenn ich mich nicht irre, dupliziert C bei mmc_write_sector
(addr,Buffer) den Buffer, und du benutzt plötzlich 2x512 byte und noch
ein bisschen was dazu. Hier sollten dann nur zeiger übergeben werden.
Nein, da das zweite Array nur lokal verwendet wird. Das taucht dann
nicht bei der RAM Anzeige auf. Keine Ahnung wieso Ulrich dieses unschöne
"Feature" eingebaut hat. In der alten Version hat er das globale 512Byte
Array verwendet, daher lief diese Version auch auf einem mega8
problemlos.
Ein Stackviewer für den gcc, das wäre echt mal ein geniales Tool. Dann
könnte man sich schön den worst case Stackverbrauch anzeigen lassen.
Ich habe Buffer global definiert.
Demnach könnte ich doch alle *Buffer in der mmc.c durch Buffer ersetzen,
oder ?
bzw
Wo gibt es die alte Version der mmc.h ?
>Nein, da das zweite Array nur lokal verwendet wird.
die betonunung liegt hier auf "verwendet". array wird als argument
übergeben -> doppelter speicher.
Ich hatte mich von Alexander verleiten lassen, denn in den FAT Routinen
von Radig hat er tatsächlich ein unnötiges, lokales Array mit 512Bytes
drin:
unsigned char Buffer[BlockSize];
steht in der fat_init.
ok,ich habe mich geirrt. nur die referenz wird übergeben.
dennoch ist es bei dem code bei mir zu den selben problemen gekommen und
ein m32 schaffte abhilfe.
Keine Ahnung wo das RAM verbraucht wird.
Allerdings ist das Programm dann ja trotzdem deutlich unter 1024 Bytes .
Das Merkwürdige: Das Programm lief ja schon.
Ich weiß nicht mehr was ich seit dem verändert habe.
>Keine Ahnung wo das RAM verbraucht wird.
Bei deinen LCD Ausgaben geht ne Menge drauf.
Da könnte man einiges optimieren.
>Allerdings ist das Programm dann ja trotzdem deutlich unter 1024 Bytes .
Auf den ersten Blick stimmt das schon. 184 Bytes auf dem Stack sind
aber auch manchmal ganz schnell erreicht. Versuch doch einfach mal
ein paar von deinen LCD Ausgaben auszukommentieren, und teste dann
nochmal.
>Das Merkwürdige: Das Programm lief ja schon.
Du benutzt da ne ganze Menge Variablen in der ISR
und im restlichen Teil deines Programmes. Die werden
z.B. lustig an itoa() übergeben. Da sollte man ganz
vorsichtig mit sein. Dein Timer kann jederzeit zuschlagen
und den Wert ändern.
Der AVR bleibt immer beim Aufruf mmc_read/write_sector hängen.
Kann es sein das hier beim Aufruf doch noch weitere Variablen Speicher
verbraucht werden ?
Das Problem lief eigentlich wochenlang (während der Entwicklungsphase)
stabil. Vielleicht habe ich eine wirklich eine Speichergrenze
überschritten.
Man bastelt ja immer wieder etwas dazu.
>Bei deinen LCD Ausgaben geht ne Menge drauf.
Ich werde sie mal testweise rausnehmen.
>Da könnte man einiges optimieren.
Wie optimiert man die LCD-Ausgaben ?
Program: 5796 bytes (70.8% Full)
(.text + .data + .bootloader)
Data: 666 bytes (65.0% Full)
(.data + .bss + .noinit)
Habe jetzt nur noch die Sekundenanzeige als LCD-String stehen lassen.
Momentan funktioniert es. Verstehen kann ich es allerdings nicht.
LCD_string gibt doch nur den im Flash stehenden String aus. Dieser
String wird doch nur an eine Variable übergeben und dann durch
LCD_string ausgegeben.
Macht vielleicht:
LCD_buffer="Hallo Test";
lcd_string(LCD_buffer);
oder
lcd_string("Hallo Test");
einen Unterschied ?
Guenter B. wrote:
> LCD_string gibt doch nur den im Flash stehenden String aus.
Keine Ahnung, du hast die Funktion geschrieben. Aber ich würde mal sagen
nein. Ohne spezielle Anweisung an den Compiler den String in den Flash
zu packen, landet dieser im RAM.
> Macht vielleicht:> LCD_buffer="Hallo Test";> lcd_string(LCD_buffer);> oder> lcd_string("Hallo Test");>> einen Unterschied ?
Nein. Beidesmal dürfte der String im RAM landen. Das kann anfangs
ziemlich verwirrend, such mal hier im Forum, oder schau mal in die
Anleitung von WinAVR, da ist das alles beschrieben. Oder auch hier:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Array_aus_Zeichenketten_im_Flash-Speicher
Auszug aus AVR-GCC-Tutorial#Programmspeicher_.28Flash.29
...
Die Harvard-Architektur des AVR weist getrennte Adressräume für
Programm(Flash)- und Datenspeicher(RAM) auf. Der C-Standard und der
gcc-Compiler sehen keine unterschiedlichen Adressräume vor.
...
Das heisst, der Text liegt im Flash und wird beim Programmstart in das
RAM kopiert und belegt somit doppelt Speicher.
Ließ dir das AVR-GCC-Tutorial durch, spziell den Bereich über den
Flash Speicher.
>>Keine Ahnung, du hast die Funktion geschrieben.
Nein. Habe ich aus dem Tutorial.
>>Das heisst, der Text liegt im Flash und wird beim Programmstart in das>>RAM kopiert und belegt somit doppelt Speicher.
Ja einmal doppelt. Aber der nächste Text wird doch wieder der gleichen
Variablen zugewiesen.
LCD_buffer="Hallo Test1"; 11 Bytes Flash
lcd_string(LCD_buffer); 11 Bytes Ram
LCD_buffer="Hallo Test2"; nochmal 11 Bytes Flash
lcd_string(LCD_buffer); 11 Bytes Ram von vorher werden überschrieben
LCD_buffer="Hallo Test3"; nochmal 11 Bytes Flash
lcd_string(LCD_buffer); 11 Bytes Ram von vorher werden überschrieben
Benötigt nur einmal den Speicher der Variablen lcd_string und wird
jedesmal wieder überschrieben.
Guenter B. wrote:
> LCD_buffer="Hallo Test1"; 11 Bytes Flash> lcd_string(LCD_buffer); 11 Bytes Ram> LCD_buffer="Hallo Test2"; nochmal 11 Bytes Flash> lcd_string(LCD_buffer); 11 Bytes Ram von vorher werden überschrieben> LCD_buffer="Hallo Test3"; nochmal 11 Bytes Flash> lcd_string(LCD_buffer); 11 Bytes Ram von vorher werden überschrieben>> Benötigt nur einmal den Speicher der Variablen lcd_string und wird> jedesmal wieder überschrieben.
Wenn der Compiler das so übersetzen würde, hättest du recht. Nur kann
man so keine Strings zuweisen. Das geht höchstens mit Pointer. Aber
trotzdem ist jeder Text der rechts steht immer noch ein String im RAM
und belegt auch ram.
strcpy_P(LCD_buffer,PSTR("Hallo Test3")); sollte genau das machen, was
du beschreibst. Die beste Lösung wäre aber, die LCD Routinen so
umzubauen, dass sie direkt aus dem Flash lesen.
Ja, ich denke ich werde mir mal einen größeren AVR zulegen.
Das würde auch das Problem mit den zuwenigen IO Ports lösen.
Ich habe bislang nur mit Tiny.und dem Mega8 gearbeitet und dachte mit
meinen bescheidenen Programmierkenntnissen reize ich diese nie aus.
Ich danke euch für die zahlreichen Antworten und Hilfestellungen.
Gruß
Günter
Guenter B wrote:
> Ja, ich denke ich werde mir mal einen größeren AVR zulegen.> Das würde auch das Problem mit den zuwenigen IO Ports lösen.
Der ATmega328P (CSD: 3,79€) ist pinkompatibel zum ATmega8, kannst ihn
also leicht austauschen.
Einige Register sind aber anders belegt.
Peter
Danke für den Hinweis. Den 328P kannte ich noch gar nicht.
Ich habe die Platine nämlich schon fertig geätzt und bestückt.
Das spart mir das Neuätzen.
Gruß
Günter
@benedikt:
Den Stackviewer kannst du dir notfalls selbst bauen, indem du dir die
Adresse der ersten Stackvariablen irgendwo global merkst und gann
gelegentlich mal ein Unterprogramm aufrufst, das ein weiteres Byte auf
dem Stack deklariert und dessen Adress-Distanz zur gemerkten Adresse
bestimmst.
In einer zweiten globalen Variablen kannst du dir das gefundene Maximum
sogar noch abspeichern; dann reicht es, gelegentlich mal nachzusehen, ob
man noch im grünen Bereich ist ,-)