Forum: Mikrocontroller und Digitale Elektronik Problem: zwei Variablen auf selber Adresse(?)


von Stefan A. (aige)


Lesenswert?

Hallo,

ich hab mal wieder mit C meine lieben Probleme...(bezutze AVR Studio)

mein Programm funktioniert nicht richtig, schon in der Simulation nicht, 
Variablen ändern schlagartig ihren Wert obwohl weit und breit nichts 
darauf zugreift. Es ist sicher ein Problem mit static, volatile & 
Co...ich hab die Sachen wohl nicht verstanden...

Ich hab schon einiges probiert, ich weis schon gar nicht mehr wie der 
Urzustand war, aber ich fang jetzt einfach mal an:

Auf jedenfall ist mir aufgefallen das in meinem Programm die Variablen 
buffer[] und timer_adc die selbe Adresse haben was wohl nicht gut ist...

hier ein Ausschnitt vom Program:
1
#include <string.h>
2
#include <avr/io.h>
3
#include <avr/pgmspace.h>
4
#include <avr/interrupt.h>
5
#include "diskio.h"
6
#include "uart.h"
7
8
BYTE read_data(BYTE* buffer, DWORD address);
9
BYTE write_data(BYTE* buffer, DWORD address);
10
11
static BYTE   ReadChannelADC0();
12
static BYTE   BCDto7seg(BYTE bcd);
13
static WORD   BINtoBCD(BYTE bin);
14
static DWORD   BINtoASCII(BYTE bin);
15
static void   ausgabe(WORD);
16
static void   schiebe(BYTE bin);  
17
static void   port_init();
18
19
20
volatile   BYTE  timer_refresh;
21
volatile   BYTE  timer_adc;
22
    
23
24
int main(void)
25
{
26
  timer_refresh = 0;
27
  timer_adc = 0;
28
29
  BYTE  result = 0;
30
31
  BYTE   buffer[512];
32
  WORD   adcbuffer = 0;
33
  WORD  bytecnt = 0;
34
  DWORD  address = 0x00060A00;
35
  DWORD  blockcnt = 0;
36
  DWORD  cache = 0;
37
38
39
  uart_init();
40
  
41
  result = disk_initialize();
42
  if(result == 0) uart_puts("Initialisierung erfolgreich...");
43
  else uart_puts("errer bei Initialisierung...");
44
45
46
  port_init();
47
  sei();
48
    
49
50
  while(1)
51
  {  
52
    if(timer_refresh >= 4)        // MUX/Anzeige Refresh?
53
    {  
54
      timer_refresh = 0;
55
      ausgabe(adcbuffer);        // gibt buffer auf 7 segmentantzeigen
56
    }
57
58
    if(timer_adc >= 50)          // 100ms
59
    {  
60
      BYTE temp = 0;
61
      timer_adc = 0;
62
      temp = ReadChannelADC0();    
63
      adcbuffer = BINtoBCD(temp);
64
65
//      uart_putint(temp);  
66
    
67
68
      if(blockcnt <= 2)
69
      {
70
        cache = BINtoASCII(temp);
71
        
72
//        uart_putint(cache);
73
        buffer[bytecnt] = 0x3D;
74
        bytecnt++;
75
        buffer[bytecnt] = 0x3D;
76
        bytecnt++;
77
        buffer[bytecnt] = (cache >> 24) & 0xFF;
78
        bytecnt++;
79
        buffer[bytecnt] = (cache >> 16) & 0xFF;
80
        bytecnt++;
81
        buffer[bytecnt] = (cache >>  8) & 0xFF;
82
        bytecnt++;
83
        buffer[bytecnt] = (cache >>  0) & 0xFF;
84
        bytecnt++;
85
        buffer[bytecnt] = 0x0D;
86
        bytecnt++;
87
        buffer[bytecnt] = 0x0A;
88
        bytecnt++;
89
90
91
        if(bytecnt >= 512)
92
        {
93
          bytecnt = 0;
94
  //      uart_putint(address);
95
          if(write_data(buffer, address) == 0) uart_puts("Schreiben erfolgreich...");
96
          else uart_puts("Error beim Schreiben...");
97
98
          for(int i = 0; i < 512; i++) buffer[i] = 0;
99
100
          address += 512;
101
          blockcnt++;
102
        }
103
      }
104
    }
105
  }
106
}
107
108
ISR(TIMER2_COMP_vect)      // wird alle 2ms aufgerufen (Takt/64;8MHz)
109
{
110
  timer_refresh++;
111
  timer_adc++;
112
};

von g457 (Gast)


Lesenswert?

> Variablen ändern schlagartig ihren Wert obwohl weit und breit nichts
> darauf zugreift.

Das deutet i.d.R. auf einen Überlauf oder einen fehlgeleiteten Zeiger 
hin. Und auf welchem Controller bist Du unterwegs?

von Peter (Gast)


Lesenswert?

> if(bytecnt >= 512)

die Prüfung kommt ein wenig spät wenn du vorher schon 10mal etwas auf 
bytecnt addierst.

von Stefan A. (aige)


Lesenswert?

Ich verwende einen ATmega8, die Compileroptimierung hab ich auch mal 
ausgeschaltet aber ändert nix. Beim Übersetzten kommt, das nur ca 50% 
Speicher belegt sind. Bin ratlos, bei meinen Versuchen bin ich laufend 
auf Probleme der Art: "schreibe was in eine Variable, eine andere nimmt 
einen ganz kuriosen Wert an, oder: Vor einem Unterprogramm Aufruf ist 
die Variable in der main() noch ok, bis zum Rücksprung aus dem UP auch 
noch, nach dem Rücksprung ist der Wert ein anderer

von Karl H. (kbuchegg)


Lesenswert?

Peter schrieb:
>> if(bytecnt >= 512)
>
> die Prüfung kommt ein wenig spät wenn du vorher schon 10mal etwas auf
> bytecnt addierst.

Hab ich zuerst auch gedacht, aber er hat das Glück, dass seine Records 
immer 8 Bytes lang sind und das geht sich ganzzahlig in 512 Bytes aus. 
Schön ist es trotzdem nicht. Fehleranfällig: ja klar.

Sollte man korrigieren, aber dürfte hier nicht das Problem sein.

von Karl H. (kbuchegg)


Lesenswert?

Stefan A. schrieb:
> Ich verwende einen ATmega8, die Compileroptimierung hab ich auch mal
> ausgeschaltet aber ändert nix. Beim Übersetzten kommt, das nur ca 50%
> Speicher belegt sind.

Moment.
Du hast >50% SRAM verbraucht?

Dann überläufst du deinen Speicher.
Denn der 512-Byte Buffer in main() ist als funktionslokale Variable in 
dieser Statistik nicht mit enthalten. Mach den mal als globale Variable 
und erfreue dich an >100% SRAM Auslastung.


> Bin ratlos, bei meinen Versuchen bin ich laufend
> auf Probleme der Art: "schreibe was in eine Variable, eine
> andere nimmt einen ganz kuriosen Wert an, oder: Vor einem
> Unterprogramm Aufruf ist die Variable in der main() noch ok,
> bis zum Rücksprung aus dem UP auch noch, nach dem Rücksprung
> ist der Wert ein anderer

All das sind (unter anderem) klassische Symptome von: Stack durch 
Überlauf zerschossen.

von Stefan A. (aige)


Lesenswert?

Peter schrieb:
>> if(bytecnt >= 512)
>
> die Prüfung kommt ein wenig spät wenn du vorher schon 10mal etwas auf
> bytecnt addierst.

hm ich möchte den buffer mit 512 Byte randvollschreiben -- 512/8 = 64, 
sollte also irgendwann genau eine Punktlandung auf 512 ergeben und 
write_data(buffer, address) wird aufgerufen

von Stefan A. (aige)


Lesenswert?

> Moment.
> Du hast >50% SRAM verbraucht?
>
> Dann überläufst du deinen Speicher.
> Denn der 512-Byte Buffer in main() ist als funktionslokale Variable in
> dieser Statistik nicht mit enthalten. Mach den mal als globale Variable
> und erfreue dich an >100% SRAM Auslastung.
>
> All das sind (unter anderem) klassische Symptome von: Stack durch
> Überlauf zerschossen.

Ei ei, das hört sich aber nicht gut an...In der Tat, wenn ich buffer[] 
global mache, dann hab ich schon 99.8% Auslastung...

kurios ist, es funktioniert etwas besser in der Simulation und auch auf 
Real, aber dann schlägt wieder dieser, ich nen es mal "Fehler" zu:
1
for(int i = 0; i < 512; i++) buffer[i] = 0;
Die Laufvariable kommt bis genau 509 und als nächstes kommt wieder 266 = 
Endlossschleife, aber der Rest ging bis dahin besser...

Naja das ändert aber nichts daran, dass ich ein Problem hab. Wie kann 
ich meinen SRAM "entschlacken"?

>Hab ich zuerst auch gedacht, aber er hat das Glück, dass seine Records
>immer 8 Bytes lang sind und das geht sich ganzzahlig in 512 Bytes aus.
>Schön ist es trotzdem nicht. Fehleranfällig: ja klar.

>Sollte man korrigieren, aber dürfte hier nicht das Problem sein.

Hm wie kann man das besser machen?

von Vlad T. (vlad_tepesch)


Lesenswert?

Stefan A. schrieb:
> kurios ist, es funktioniert etwas besser in der Simulation und auch auf
> Real, aber dann schlägt wieder dieser, ich nen es mal "Fehler" zu:for(int i = 0; 
i < 512; i++) buffer[i] = 0; Die Laufvariable kommt bis genau 509 und als nächstes 
kommt wieder 266 =
> Endlossschleife, aber der Rest ging bis dahin besser...

Du hast ja nun keinen Platz für den Stack mehr

von Karl H. (kbuchegg)


Lesenswert?

Stefan A. schrieb:

> Naja das ändert aber nichts daran, dass ich ein Problem hab. Wie kann
> ich meinen SRAM "entschlacken"?

Indem du Variablen einsparst.
Wo wird denn der Rest des Speichers verbraucht?

Bei dir reicht ein Byte hier, ein Byte da nicht mehr.
Da muss man schon gröber nachsehen. Also: Alle globalen Variablen 
durchsehen, vor allen Dingen große Arrays und versuchen sie loszuwerden. 
Die SD-Routinen unterhalten nicht zufällig auch noch große Buffer?

> Hm wie kann man das besser machen?

Indem man nach jedem Byte, welches in den Buffer kommt nachsieht, ob man 
den Buffer nicht ausleeren müsste. Zu diesem Zwecke bietet sich dann 
eine Funktion an, die genau das macht:
  1 Byte in den Buffer einfügen
  prüfen ob der Buffer dadurch voll geworden ist und ausgeleert werden
  muss

Deine Schreibsequenz sieht dann so aus:
1
  ....
2
     if(blockcnt <= 2)
3
      {
4
        cache = BINtoASCII(temp);
5
6
        write_byte( 0x3D );
7
        write_byte( 0x3D );
8
        write_byte( (cache >> 24) & 0xFF );
9
        write_byte( (cache >> 16) & 0xFF );
10
        write_byte( (cache >>  8) & 0xFF );
11
        write_byte( (cache >>  0) & 0xFF );
12
        write_byte( 0x0D );
13
        write_byte( 0x0A );
14
      }
15
  ....
16
17
...
18
19
void write_byte( BYTE byte )
20
{
21
  buffer[bytecnt] = byte;
22
  bytecnt++;
23
24
  if(bytecnt >= 512)
25
  {
26
    bytecnt = 0;
27
  //      uart_putint(address);
28
    if(write_data(buffer, address) == 0)
29
      uart_puts("Schreiben erfolgreich...");
30
    else
31
      uart_puts("Error ......
32
  ....

Neben dem defensiven Gedanken zur Fehlervermeidung hat das dann auch 
noch den Vorteil der besseren Übersicht :-) Man sieht sehr viel besser 
was in welcher Reihenfolge geschrieben wird, ohne dass immer wieder 
irgendwelche 'Zwischenanweisungen' den Lesefluss stören.

von Karl H. (kbuchegg)


Lesenswert?

Es ist zwar nicht viel, aber du könntest mal damit anfangen all die 
konstanten Texte ins Flash auszulagern (*)

Das sind schon mal 100 Bytes SRAM, die du ziemlich billig freischaufeln 
kannst. Nur mit den Texten, die du gezeigt hast :-)

(*) eigentlich falsch ausgedrückt. Denn die Texte sind schon im Flash. 
Sie werden beim Programmstart noch zusätzlich ins SRAM kopiert, damit zb 
uart_puts schön darauf zugreifen kann.

von Vlad T. (vlad_tepesch)


Lesenswert?

Karl heinz Buchegger schrieb:
> Das sind schon mal 100 Bytes SRAM, die du ziemlich billig freischaufeln
> kannst. Nur mit den Texten, die du gezeigt hast :-)

Einfach uart_puts durch uart_puts_P ersetzen

von Stefan A. (aige)


Lesenswert?

ich liebe euch :D
hab nun ca 400 Byte rausgeschunden - und alles funktioniert einwandfrei 
nun. Auf den Fehler wäre ich nie im Leben gekommen


>Einfach uart_puts durch uart_puts_P ersetzen

Aber ich weis nicht was damit gemeint ist. Meine uart Routinen hab ich 
selbst geschrieben und sind deshalb recht einfach
Auf die schnelle hab ich nicht rausgefunden wie ich meine Texte auf den 
Flash speichern lassen kann - damit würde ich nochmal 60Byte rausholen 
können

Warum gibt es denn keinen Fehlermeldung oder zumindest ne Warnung wenn 
der SRAM überfüllt ist?

von g457 (Gast)


Lesenswert?

> Auf die schnelle hab ich nicht rausgefunden wie ich meine Texte auf den
> Flash speichern lassen kann

pgm_read_*() zum lesen, PSTR() ums bequem in den Flash zu verbannen. 
Beides in pgmspace.h (avr-libc)

> Warum gibt es denn keinen Fehler oder zumindest ne Warnung wenn der SRAM
> überfüllt ist?

Weil es in der Regel nicht möglich ist, das vorherzusagen(!). Und wenns 
mit ("globalem") Zeugs zugemüllt ist, dann gibts dir avr-objcopy/.. 
hüpsch aus :-)

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.