uC stürzt beu Zugriff auf MMC ab

OP #1051860
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
Angehängte Dateien:
OP #1055591
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
OP #1055657
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.
#1055675
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.
#1055701
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.
Gast #1055798
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.
Gast #1055869
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 ?
OP #1056444
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 ?
#1056462
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
#1056473
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.
OP #1056521
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.
#1056530
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.
Gast #1056760
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
#1057815
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
Gast #1058842
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 ,-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren