Forum: Compiler & IDEs uC stürzt beu Zugriff auf MMC ab


von Guenter B. (gbl)


Angehängte Dateien:

Lesenswert?

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:
1
#include <avr/io.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <lcd-routines.h>
5
#define F_CPU 3686400
6
#include <util/delay.h>
7
#include <D:\mikrocontroller\Projekte\SD_Test\mmc.h>
8
#define takt 3686400UL
9
char Buffer[512];
10
long addr = 0;
11
12
13
 //Initialisierung der MMC/SD-Karte
14
 void init_mmc(void)
15
 {
16
  char Timeout = 0;
17
  char a = 1;  
18
  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
int main(void)
38
{
39
  char tmp;
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
  return 1;
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

von Guenter B. (gbl)


Lesenswert?

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

von Alexander D. (zebprophet)


Lesenswert?

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.

von Guenter B. (gbl)


Lesenswert?

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.

von Alexander D. (zebprophet)


Lesenswert?

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.

von Alexander D. (zebprophet)


Lesenswert?

unsigned char mmc_write_sector (unsigned long addr,unsigned char 
*Buffer)

von Guenter B. (gbl)


Lesenswert?

Aber dann müsste er doch einen Datenspeicherbedarf von > 1024 Bytes 
anzeigen

von Benedikt K. (benedikt)


Lesenswert?

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.

von Guenter B. (gbl)


Lesenswert?

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 ?

von dummy (Gast)


Lesenswert?

>Nein, da das zweite Array nur lokal verwendet wird.

Welches zweite Array? Da wird ein Pointer auf das Array übergeben.

von Alexander D. (zebprophet)


Lesenswert?

>Nein, da das zweite Array nur lokal verwendet wird.

die betonunung liegt hier auf "verwendet". array wird als argument 
übergeben -> doppelter speicher.

von dummy (Gast)


Lesenswert?

>array wird als argument übergeben -> doppelter speicher.

Quark!

Buffer kann man auch so schreiben &Buffer[0].
Das ist nur die Adresse von Buffer.

von Benedikt K. (benedikt)


Lesenswert?

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.

von Guenter B. (gbl)


Lesenswert?

Fat usw nutze ich nicht.
Nur die MMC

von Alexander D. (zebprophet)


Lesenswert?

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.

von Benedikt K. (benedikt)


Lesenswert?

Wo brauchst du dann soviel RAM?
Die mmc Routinen brauchten knapp über 512Bytes. Deine Software braucht 
840Bytes. Über 300Bytes für die LCD Routinen?

von holger (Gast)


Lesenswert?

>lcd_string("Datenausgabe        " );

Das sind schon mal 20 Bytes RAM.
Gibts da nicht ein lcd_string_P() ?

von Guenter B. (gbl)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

>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.

von Guenter B (Gast)


Lesenswert?

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 ?

von Benedikt K. (benedikt)


Lesenswert?

Guenter B wrote:
>>Da könnte man einiges optimieren.
>
> Wie optimiert man die LCD-Ausgaben ?

Die ganzen Strings in den Flash anstelle vom RAM.

von Guenter B. (gbl)


Lesenswert?

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 ?

von Benedikt K. (benedikt)


Lesenswert?

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

von Werner B. (werner-b)


Lesenswert?

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.

von Guenter B. (gbl)


Lesenswert?

>>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.

von Benedikt K. (benedikt)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Ersetz dochmal den ATmega8 durch nen ATmega328P, der hat 2kB SRAM.


Peter

von Guenter B (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Guenter B. (gbl)


Lesenswert?

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

von Elizar (Gast)


Lesenswert?

@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 ,-)

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.