Forum: Compiler & IDEs Unterschied zwischen Code für Arduino und normalem Code


von Benni K. (benjamin_k)


Lesenswert?

Hallo,

ich hab ein Programm für den Arduino geschrieben, welches ich jetzt noch 
einmal in "normalem" C schreiben will.
Im Grunde gibt es nur eine Codestelle, die nicht funktionieren will, der 
folgende Code ist vom Arduino und funktioniert tadellos:
1
void EineFunktion()
2
{
3
  unsigned char buf[512];
4
  mmc_read_sector(0,buf);
5
}
(Zum Auslesen der SD Karte wir diese Library verwendet:
http://www.mikrocontroller.net/articles/AVR_FAT32)

Wenn ich diesen Code jetzt in C kompiliere, kompiliert dies wunderbar, 
nur leider hängt sich das Programm dann beim Aufruf der Funktion
1
mmc_read_sector(0,buf);
auf.

Wenn ich nun hingegen statt
1
unsigned char buf[512];
1
unsigned char* buf;
verwende, läuft das Programm, hängt sich dann aber bei einer späteren 
Leseoperation auf. Ansonsten läuft das Programm ordentlich durch, nur 
wenn es zum Auslesen und Speichern in einem Array kommt, geht nichts 
mehr.

Vielen herzlichen Dank im Voraus und einen schönen Sonntag noch.

von Krapao (Gast)


Lesenswert?

> Wenn ich nun hingegen statt
>
> unsigned char buf[512];
>
> unsigned char* buf;
>
> verwende, läuft das Programm, hängt sich dann aber bei einer späteren
> Leseoperation auf.

Logisch, weil du im 2. Fall mit buf einen nicht initialisierten Zeiger 
hast. Der GCC sollte dafür auch eine Warnung gebracht haben. Die 
Schreiboperation in mmc_read_sector(0,buf) zerschreibt im 
Speicherbereich ab buf halt was...

von Benni K. (benjamin_k)


Lesenswert?

Vielen Dank für die Antwort.

Aber es funktioniert ja zwei mal, wenn ich
1
unsigned char* buf;
 verwende, ich springe dann aus der Funktion raus (dann müsste der 
Speicher ja wieder freigegeben werden) und versuche dann das gleiche 
nochmal zu tun und ab diesem Punkt geschieht dann nichts mehr.

Gehe ich richtig in der Annahme, dass ich den Zeiger richtig mit
1
unsigned char* buf = {0};
initialisiere? Wenn ja, dass hab ich auch schon versucht.

Grüße und Danke

von Karl H. (kbuchegg)


Lesenswert?

Benni K. schrieb:
> Vielen Dank für die Antwort.
>
> Aber es funktioniert ja zwei mal,

Nein.
Es funktioniert garantiert nicht. Es mag für dich so aussehen als ob, 
aber das tut es nicht.

> wenn ich
>
1
unsigned char* buf;
 verwende, ich springe dann aus der Funktion
> raus (dann müsste der Speicher ja wieder freigegeben werden

Es wurde überhaupt kein Speicher reserviert!
Deine Empfangsroutine schreibt irgendwo in den Speicher und zerschiesst 
dir alles. Was genau hängt von den Details ab. Da das aber sowieso 
falsch ist, ist es auch unsinnig dem jetzt nachzugehen. Mach es richtig 
und du hast das Problem in erster Linie erst gar nicht.

> Gehe ich richtig in der Annahme, dass ich den Zeiger richtig mit
>
1
unsigned char* buf = {0};
> initialisiere? Wenn ja, dass hab ich auch schon versucht.

Es geht nicht um den Zeiger.
Du hast in erster Linie keine SPeicherfläche, in die die Daten 
geschrieben werden könnten! Egal ob du dann noch einen Zeiger darauf 
einrichtest oder nicht.

Das hier
1
void EineFunktion()
2
{
3
  unsigned char buf[512];
4
  mmc_read_sector(0,buf);
5
}
ist dir richtige Variante. Mit buf hast du dir eine Speicherfläche 
erzeugt und die Funktion mmc_read_sector kann da reinschreiben. Wenn man 
jetzt rausfinden will, warum mmc_read_sector bei dir abkratzt, muss man 
sich diese Funktion näher ansehen, ob die zb irgendwelche Vorbedingungen 
benötigt.

Unter Umständen liegt das Problem noch nicht mal in dieser Funktion, 
sondern ganz woanders. Was du siehst sind die Symptome. Die müssen aber 
nicht unbedingt offensichtlich mit den Ursachen korrelieren.

von Krapao (Gast)


Lesenswert?

> unsigned char* buf = {0};

Definiert den Zeiger buf und initialisiert ihn mit der Adresse eines 
Speicherbereichs in dem für 1 Byte Platz ist. Der Speicherbereich selbsr 
wird mit dem Wert 0 initialisiert.

Wenn mmc_read_sector in einen 512 Bytes großen Speicherbereich schreiben 
will, musst du den auch angelegt haben. Wenn du ihn zur Laufzeit lokal 
anlegst, d.h. auf dem Stack, dann siehst du ggf. auch erst zur Laufzeit 
Probleme.

Leg den Buffer testweise global an und achte darauf, ob der BSS/DATA 
Bereich im RAM noch ausreichend ist.

von Karl H. (kbuchegg)


Lesenswert?

Krapao schrieb:
>> unsigned char* buf = {0};
>
> Definiert den Zeiger buf und initialisiert ihn mit der Adresse eines
> Speicherbereichs in dem für 1 Byte Platz ist. Der Speicherbereich selbsr
> wird mit dem Wert 0 initialisiert.


Äh. nein.

von Benni K. (benjamin_k)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Nein.
> Es funktioniert garantiert nicht. Es mag für dich so aussehen als ob,
> aber das tut es nicht.

Ich kann mit dem Ergebnis arbeiten und bekomme alle Werte aufs Bit genau 
ausgelesen, ich dachte mir aber schon, dass das der falsche Weg ist.

Nur im Unterschied zu der vollständigen Reservierung des Feldes 
funktioniert diese oben genannte erst Methode mit dem Zeiger.

Wie kann es überhaupt sein, dass ein mit dem Arduino Kompilierter Code 
funktioniert und exakt derselbe Code, den ich von Hand durch den avr-gcc 
jage nicht?

Vielen Dank schonmal für die Hilfe.

von Roland H. (batchman)


Lesenswert?

> Wie kann es überhaupt sein, dass ein mit dem Arduino Kompilierter Code
> funktioniert und exakt derselbe Code, den ich von Hand durch den avr-gcc
> jage nicht?

Von welchem Arduino sprechen wir eigentlich? Wieviel RAM hat der?

von Benni K. (benjamin_k)


Lesenswert?

Roland H. schrieb:
> Von welchem Arduino sprechen wir eigentlich? Wieviel RAM hat der?

Arduino Uno, Atmega328p, also 2kByte SRAM.

Auf den gleichen Chip lade ich dann auch mein Programm mit dem ISP. Der 
Speicher sollte also locker ausreichen.

von Karl H. (kbuchegg)


Lesenswert?

Benni K. schrieb:


> Wie kann es überhaupt sein, dass ein mit dem Arduino Kompilierter Code
> funktioniert und exakt derselbe Code, den ich von Hand durch den avr-gcc
> jage nicht?

Dann wird er nicht genau 100% identisch sein.

von Roland H. (batchman)


Lesenswert?

>> Wie kann es überhaupt sein, dass ein mit dem Arduino Kompilierter Code
>> funktioniert und exakt derselbe Code, den ich von Hand durch den avr-gcc
>> jage nicht?

Es wäre an der Zeit, beide Quelltexte + Makefile etc. komplett zu 
zeigen.

Ich bin auch mal gespannt, wie "gleich" die Quelltexte wirklich sind :-)

von Benni K. (benjamin_k)


Lesenswert?

Hallo,

hier der Arduino Code:
1
#include "mmc.h"
2
3
void setup()
4
{
5
  Serial.begin(115200);
6
  while (mmc_init() == 0)
7
  {
8
    
9
  }
10
  Serial.print("\n");
11
  Serial.println("Initialisierung fertig!");
12
  TestLesen(); //geht
13
}
14
15
void TestLesen()
16
{
17
  unsigned char buf[512];
18
  mmc_read_sector(0,buf);
19
  for (int i = 0; i< 512; i++)
20
  {
21
    Serial.print(buf[i]);
22
    Serial.print('\n');
23
    if (i%8)
24
    {
25
        Serial.print('\n');
26
    }
27
  } 
28
}
29
30
31
void loop()
32
{
33
  
34
}

und hier der C-Code
1
#include <avr/io.h>
2
#include "mmc.h"
3
#include "uart.h"
4
5
void setup()
6
{
7
  uinit();
8
  while (mmc_init() == 0)
9
  {
10
    
11
  }
12
  uputs((unsigned char*)"\n");
13
  uputs((unsigned char*)"Initialisierung fertig!");
14
  //bis hierhin läuft alles wie erwartet
15
  TestLesen(); //geht nicht
16
}
17
18
void TestLesen()
19
{
20
  unsigned char buf[512]; //geht nicht
21
  //unsigned char* buf;   //geht, aber nur 1-2 mal
22
  mmc_read_sector(0,buf); //hängt dann
23
24
  for (int i = 0; i< 512; i++)
25
  {
26
    uputhex(buf[i], HEX);
27
    uputc('\n');
28
    if (i%8)
29
    {
30
       uputc('\n');
31
    }
32
  } 
33
}

Der Code wird mit dem folgenden Optionen erstellt (codeblocks):
Für den Compiler:
-mmcu=atmega328p -Wall -g

Für den Linker:
-mmcu=atmega328p
-Wl,-Map=$(TARGET_OUTPUT_FILE).map,--cref

Danach wird folgendes ausgeführt:
avr-size $(TARGET_OUTPUT_FILE)
avr-objcopy -O ihex -R .eeprom -R .eesafe $(TARGET_OUTPUT_FILE) 
$(TARGET_OUTPUT_FILE).hex
avr-objcopy --no-change-warnings -j .eeprom --change-section-lma 
.eeprom=0 -O ihex $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE).eep.hex
avr-objdump -h -S $(TARGET_OUTPUT_FILE) > $(TARGET_OUTPUT_FILE).lss

Vielen Dank für das Interesse und die bisherige Diskussion.


Vielleicht nochmal kurz die Funktion mmc_read_sector():
1
unsigned char mmc_read_sector (unsigned long addr,unsigned char *Buffer){
2
   unsigned short a;
3
   // cmd17 zum lesen eines einzelnen blocks von der karte
4
   unsigned char cmd[] = {0x40+17,0x00,0x00,0x00,0x00,0xFF}; // CMD17 (read_single_block), response R1.
5
   
6
   // addressiertung bei mmc und sd (standart < 2.0) in bytes, also muss sektor auf byte adresse umgerechnet werden.
7
   // sd standart > 2.0, adressierung in sektoren, also 512 byte bloecke
8
   if(card_type==0) addr = addr << 9; //addr = addr * 512
9
10
   cmd[1] = ((addr & 0xFF000000) >>24 );
11
   cmd[2] = ((addr & 0x00FF0000) >>16 );
12
   cmd[3] = ((addr & 0x0000FF00) >>8 );
13
   cmd[4] = (addr &  0x000000FF);
14
15
   MMC_Enable();
16
17
   //Sendet Commando cmd an MMC/SD-Karte
18
   if( 0 != mmc_write_command(cmd) )  return FALSE;
19
20
   //Wartet auf Start Byte von der MMC/SD-Karte (0xFE/Start Byte)
21
   while (mmc_read_byte() != 0xFE){};
22
23
  // mmc/sd in hardware spi, block lesen
24
  #if (MMC_SOFT_SPI==FALSE)
25
     unsigned char tmp;
26
     a=512;
27
     SPDR = 0xff;                // dummy byte
28
    do{                    // 512er block lesen
29
      loop_until_bit_is_set(SPSR,SPIF);
30
      tmp=SPDR;
31
      SPDR = 0xff;            // dummy byte
32
      *Buffer=tmp;
33
      Buffer++;
34
    }while(--a);
35
36
  // mmc/sd in software spi, block lesen
37
  #else
38
    a=512;
39
    do{
40
      *Buffer++ = mmc_read_byte();
41
    }while(--a);
42
  #endif
43
44
   //CRC-Byte auslesen
45
   mmc_read_byte();//CRC - Byte wird nicht ausgewertet
46
   mmc_read_byte();//CRC - Byte wird nicht ausgewertet
47
48
   MMC_Disable();
49
   return TRUE;
50
}

Grüße

von Jim M. (turboj)


Lesenswert?

Deklariere mal den Puffer buf[512] als globale Variable, d.h. so:
1
unsigned char buf[512]; 
2
3
void TestLesen()
4
{
5
  mmc_read_sector(0,buf);

Meckert er dann über freien Speicher? Dann hattest Du einen Stack 
Überlauf. AFAIK kennt der GCC keine Overlays für Daten. Da muss man dann 
vorsichtig sein beim Reservieren von Speicher.

von Roland H. (batchman)


Lesenswert?

Meine Glaskugel ist gerade beim TÜV. Also sehe ich die main() Funktion 
des C-Programmes unscharf, ebenso kann ich uputhex nicht erkennen. F_CPU 
liegt im Dunkeln, ob uinit() auch 115k einstellt, ...

Mit "komplett" meine ich "komplett" :-)

Aaahh ... ich habe eine Vision ... ohne Kugel ... ein zip Attachment, 
mit allem drin ... auspacken, make, ...

von Benni K. (benjamin_k)


Lesenswert?

Hallo, danke für die Antworten,

uputhex kann ich auch genauso gut weglassen, die Funktion wurde noch nie 
aufgerufen =), es hängt ein 16MHZ Quarz dranne und es wird eine 
Symbolrate von 9600 Baud verwendet.
Ich werde versuchen morgen eine Archiv hochzuladen, muss nur erstmal ein 
makefile erstellen.



Grüße

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.