Forum: Mikrocontroller und Digitale Elektronik Hilfe! AVR spinnt / macht was er will.


von gast (Gast)


Lesenswert?

Hallo.

Ich habe eine Atmega32 mit einem S65 LCD und einer SD karte am laufen.
Die SD karte läuft mit dem Code von Ulrich R.
Leider habe ich seit ein paar Wochen sehr komische Probleme mit der 
Schaltung.
Mein Code ist mit der zeit am wachsen. logisch.
aber jetzt das komische verhalten vom avr.
Es ist so, das wenn ich eine neue Funktion "hinzufügen" in der lib fürs 
LCD, funktionier mein gesamtes Programm nicht mehr sauber. das LCD zeigt 
nur noch schrott an. Und das, obwohl die Funktion gar nicht aufgerufen 
wird?
Wenn ich in der Main Funktion hinter der LCD Ausgabe etwas auf der uart 
ausgeben möchte, habe ich ähnliche Fehler verhalten. nehme ich die uart 
Geschichte wieder raus, läuft es.
Achso, das Bild wird auf der SD karte gefunden, und auch geladen.
Kann es sein, das mein RAM im AVR defekt ist vom (vielen) programmieren?
Oder kann es am AVR Studio liegen? Habe die Version 4.14.
Achso, sobald ich den compiler aus eine andere optimierung einstelle, 
bekomme ich auch ein ähnliches verhalten, das das LCD nur noch mist 
anzeigt, bzw. er den Bild bereich ändert.
vieleicht hat jemand eine lösung für mich.
ich weiß nicht wirklich, wo ich anfangen soll zu suchen.

von holger (Gast)


Lesenswert?

Ich vermute mal das dein RAM am Ende ist.
Stacküberlauf.

von gast (Gast)


Lesenswert?

Klingt nach einer möglichen ursache.
Bedeutet das ein Programmier fehler?
Oder defekter RAM?
Wie kann ich es überprüfen, und falls es der fall sein sollte, beheben?

von Moritz E. (devmo)


Lesenswert?

laut ockhams razor wirds an deinem code liegen ;).. hast du keine 
simulationsmöglichkeit? oder hardware debugger? in der software 
irgendwelche debug-ausgabe möglichkeit? ich habe für debug ziemlich viel 
code investiert, damit ich per uart alles mögliche an internen zuständen 
ausgeben kann, sowie umfangreiche exception try-catch konstrukte 
(allerdings in asm).. ohne alles das wäre ich nie weitergekommen, und 
auch mit diesen möglichkeiten hilft manchmal nur das simulieren. wenn 
fehler sich eingrenzen lassen, in dem du bestimmte programmteile 
rausnimmst, weißt du ja schon wo du anfangen musst. weiter eingrenzen 
lässt sich es in dem du zu debugzwecken den code weiter veränderst, und 
die auswirkung auf das fehlerbild analysierst. oft zeigt sich z.b. am 
zeitpunkt des auftretens was der auslöser sein könnte. wenn dein 
programm sofort beim einschalten abschmiert kommt man mit dem simulator 
schnell weiter, da man nicht viele taktzyklen warten muss.

wie immer gilt, ohne weitere infos, quellcode, kann man kaum mehr als 
das orakel befragen...

von holger (Gast)


Lesenswert?

>Bedeutet das ein Programmier fehler?

In gewisser Weise schon ;)

>Oder defekter RAM?

Nein.

>Wie kann ich es überprüfen, und falls es der fall sein sollte, beheben?

Man kann durch exzessive Nutzung von z.B. printf()
ganz schön viel RAM verbrauchen. Da liegen die auszugebenden
Strings im RAM. Wenn man printf_P() nimmt liegen sie im Flash.
Ist aber nur ein Beispiel. Wo du RAM vernichtest kann uns
nur dein Code verraten.

von gast (Gast)


Lesenswert?

OK, hier meine "main"
1
int main(void){
2
3
  usart_init(38400);
4
  DDRD |= (1 << PD7); // PD0 als Ausgang festlegen
5
6
  display_init();
7
  init_sd();
8
9
//____________________________________
10
  // Drehgeber Anschluß 
11
  DDRC  &= ~(_BV(PC1) | _BV(PC0)); // Pin's als Eingang
12
  PORTC  =  (_BV(PC1) | _BV(PC0)); // PullUp's ein
13
  DDRB   = 0xFF;                   // Port  als Ausgang
14
15
  // Timer0 einstellen                
16
//  TCCR0 = 1<<CS01 | 1<<CS00;   // Teilung durch 256 *  64 Int. alle   2ms bei 8MHz CLK
17
  TCCR0 = 1<<CS02;             // Teilung durch 256 * 256 Int. alle 8,2ms bei 8MHz CLK
18
  TIMSK  = 1<<TOIE0;            // enable timer interrupt
19
  sei();
20
//______________________________________________
21
22
23
  unsigned int Clustervar;
24
  unsigned char Dir_Attrib = 0;
25
  unsigned long Size = 0;
26
27
  //Ausgabe des Root Directory
28
  usart_write("\n\nDirectory\n\n");
29
  for (char a = 1;a < 240;a++)
30
  {
31
    Clustervar = fat_read_dir_ent(0,a,&Size,&Dir_Attrib,Buffer);
32
      if (Clustervar == 0xffff)
33
      {
34
        break;
35
      }
36
    tmp = (Size & 0x0000FFFF);
37
    usart_write("Cluster = %4x DirA = %2x FileName = ",Clustervar,Dir_Attrib);
38
    usart_write(&Buffer);
39
    usart_write("\n");
40
  }
41
  usart_write("\nDirectory Ende\n\n");*/
42
43
44
45
////////////////////////////////
46
  char picname[20];
47
  char npicnamen3[20] = "conf.txt";
48
49
50
  strcpy(picname, "16.bmp");
51
  S65_PutBmpFromSD(0,0, &picname[0]);
52
  _delay_ms(1000);
53
54
55
  S65_Fillscreen(0000);
56
  s65_mainsplit();
57
58
59
  S65_SetTextColor(0x07E0);
60
  char e[20] = {'U','h','r',0};
61
  S65_PutStr(30,108, &e[0]);
62
  
63
  _delay_ms(2000);
64
  strcpy(picname, "door_o.bmp");
65
  S65_PutBmpFromSD(0,20, &picname[0]);
66
  _delay_ms(1000);
67
68
69
  while (1) {
70
  
71
    //__________________________________________
72
    //Ausgabe  = richtung;
73
    //cls(1);
74
    //S65_PutByte(80,40, richtung);
75
      Ausgabe  = ~richtung;         // Nur beim STK500
76
      //usart_write(richtung);
77
      usart_write("Drehrichtung: %i \n",richtung);
78
      usart_write("\n");
79
    //____________________________________________
80
81
82
    PORTD |= (1 << PD7); // PD0 aktivieren
83
        _delay_ms(500);
84
        PORTD &= ~(1 << PD7); // PD0 deaktivieren
85
        _delay_ms(500); 
86
    
87
  }
88
}

Und hier die andere funktion:
1
int S65_lese_konfig(char *picname3)
2
{
3
  uint8_t tmp3;
4
  unsigned int Clustervar3;
5
  unsigned char Dir_Attrib3 = 0;
6
  unsigned char Buffa3[512];
7
  unsigned long Size3 = 0;
8
  //char picname3[20];
9
  // --------------------------------------------------------------------------
10
  // Konfig datei lesen:
11
  usart_write("------------------------------------------\n\n");
12
  usart_write("\n\nlese konfig file\n\n");
13
  mmc_read_csd (Buffa3);
14
  usart_write_str (picname3);
15
16
17
  /*Clustervar3 = 0;
18
  if (fat_search_file(picname3,&Clustervar3,&Size3,&Dir_Attrib3,Buffa3) == 1)
19
    {
20
    usart_write("\n--------------------------------\n\n");
21
    usart_write("\nKonfig File Found!!\n\n");
22
    usart_write("Size = %i \n",&Size3);
23
    //char filefound[20] = {'F','i','l','e',' ','f','o',' ',0};
24
    //S65_PutStr(10,50, &filefound[0]);
25
    //Lese File und gibt es auf der seriellen Schnittstelle aus
26
27
    fat_read_file (Clustervar3,Buffa3,0);
28
    _delay_ms(400);
29
30
    for (tmp3 = 0;tmp3<160;tmp3++)
31
    {
32
      usart_write("Buffer: %x ",Buffa3[tmp3]);
33
  //  char e[20] = {'B','u','f',0};
34
  //  S65_PutStr(10,30, &e[0]);
35
    };
36
37
    usart_write("\n--------------------------------\n\n");
38
    }
39
40
    else
41
    {
42
      usart_write("File Not Found - conf.txt");
43
    }*/
44
  // ------------------------------------------------------------------------
45
  usart_write("\n\nende lese konfig file\n\n");
46
  usart_write("------------------------------------------\n\n");
47
  return(1);    // Alles klar, keine Fehler
48
}
Sobald ich das kommentar bei "if (fat_search_file" raus werfe spinnt 
mein programm rum.

von holger (Gast)


Lesenswert?

Schmeiss doch mal alle

  usart_write("------------------------------------------\n\n");

raus. Funktioniert es dann ?

von Albrecht H. (alieninside)


Lesenswert?

gast wrote:
> Klingt nach einer möglichen ursache.
> Bedeutet das ein Programmier fehler?
> Oder defekter RAM?

Nein, das bedeutet, dass dein Programm mehr RAM-Speicher benötigt als 
der Baustein zur Verfügung stellt, der ATmega32 hat "nur" 2-Kbyte SRAM 
dein Programm bräuchte aber möglicherweise 3KB, 4KB oder noch mehr SRAM.

> Wie kann ich es überprüfen,

Du könntest dir evt. an bestimmten Stellen den Inhalt des Stackpointers 
ausgeben lassen, also wenn der Stack beim AVR von oben nach unten wächst 
und der Stackpointer plötzlich "ganz unten" ankommt, also z.B. bei 0000 
oder 0002, (läuft das so beim ATmega?), dann spricht vieles dafür, dass 
du zu wenig SRAM hast, dann kann alles durcheinander kommen: Variablen 
werden überschrieben, Unterprogramm und Interruptrücksprungadressen 
gehen verloren, usw. ...

> und falls es der fall sein sollte, beheben?

Einen Prozessor mit mehr SRAM besorgen z.B. den ATmega644 (mit 4KB 
SRAM), oder externes RAM verwenden, (eher unpraktisch). Oder mal dein 
Programm durchschauen: Rekursive oder sehr verschachtelte 
Unterprogrammaufrufe brauchen viel RAM, und, (da hab ich leider noch 
nicht allzu viel Ahnung von Win-AVR-C), möglicherweise kannst du was 
retten wenn du darauf schaust, dass alle Funktionsparameter "By 
Reference" d.h. als Pointer und nicht als Speicherkopie d.h. "By Value" 
übergibst. Umfangreiche Stringmanipulationen sind bei 2KB Ram wohl auch 
nicht drin.
Im Prinzip musst du dir bei jeder Funktion, bei jeder Schleife und bei 
jeder zur Laufzeit angelegten Variable überlegen wieviel RAM dafür wohl 
verbraucht wird.

Nachtrag:
Gerade mal kurz in deinen Code reingeschaut, (wie gesagt, hab da nicht 
viel Ahnung von), aber wenn ich nur 2KB SRAM hätte, würde ich nicht so 
verschwenderisch mit den "char filefound[20]" etc. um mich werfen...
Alle Stringkonstanten müssen ins Flash, (oder optimiert das der 
Compiler?).

Und der "unsigned char Buffa3[512];" da ist ja schon mal von vornerein 
ein Viertel des RAMs auf einen Schlag weg.

von Jadeclaw D. (jadeclaw)


Lesenswert?

> Alle Stringkonstanten müssen ins Flash, (oder optimiert das der
> Compiler?).
Der Compiler optimiert das nicht.
Die Stringkonstanten sind zwar im Flash, werden sie aber nicht auf eine 
spezielle Weise deklariert und über eine Spezialfunktion gelesen, 
sondern einfach nach der Methode 
"usart_write("------------------------------------------\n\n");" 
eingetragen, dann werden diese Konstanten beim Programmstart ins RAM 
umgeladen. Da bleibt dann für den Stack nichts mehr übrig.
Besser man macht es so: 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Array_aus_Zeichenketten_im_Flash-Speicher


Gruß
Jadeclaw.

von gast (Gast)


Lesenswert?

Schade, ich dachte der compiler meldet sich mal, wenn er merkt falls es 
eng wird.
Der hätte ja nun wirklich den überblick.

"Buffa3[512];" wird in einer Funktion deklariert.
Wenn ich diese Funktion jetzt dreimal aufrufe, belegt sie doch nur 
einmal den speicher, oder habe ich da grundsätzlich irgendwas noch nicht 
verstanden?

von Daniel F. (df311)


Lesenswert?

nein, der speicher wird jedesmal reserviert. er wird zwar (im 
normalfall) wieder freigegeben, aber wenn z.b. nur mehr 300 kB ram übrig 
sind, es werden aber 512 benötigt gibts schon probleme.
wie die speicherverwaltung auf dem avr in c funktioniert weiß ich leider 
nicht genau, programmiere in asm...

von Zweiter Gast (Gast)


Lesenswert?

Hmm, hilft da "static unsigned char Buffa3[512];" ?

von Albrecht H. (alieninside)


Lesenswert?

Zweiter Gast wrote:
> Hmm, hilft da "static unsigned char Buffa3[512];" ?

Dann werden die 512 Bytes eben dauerhaft belegt, (könnte aber 
vielleicht, in anderen Situationen, unter gewissen Umständen, wenn man 
das gleich beim Programmstart mit allen dauerhaft benötigten Buffern 
macht, dabei helfen, die  Speicherfragmentierung zu verringern).

Aber das Grundproblem bleibt dasselbe: Nur 2024 Bytes RAM die sich 
Variablen und Stack teilen müssen.

von Simon K. (simon) Benutzerseite


Lesenswert?

Zweiter Gast wrote:
> Hmm, hilft da "static unsigned char Buffa3[512];" ?

Wurde doch schon gepostet:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Array_aus_Zeichenketten_im_Flash-Speicher

von gast (Gast)


Lesenswert?

Erstaunlich.
Durch ein wenig optimierung und ausklammern von "usart_write" 
funktioniert es jetzt.
An einen Stacküberlauf habe ich überhaupt nicht gedacht.

Ein "Danke" an alle beteiligten.

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.