Forum: Compiler & IDEs AVR, memcmp


von Ludwig M. (laludelala)


Lesenswert?

Hallo!

Ich bin dabei, Zugriffsroutinen für eine FAT16 (MMC-Karte) zu schreiben. 
Als Mikrokontroller dient ein ATMega16.

Die Routinen sind fertig, ich kann mit ihnen am PC (x86 Programm unter 
Linux) in einer virtuellen FAT-Partition Dateien anlegen und 
reinschreiben.


Jetzt bin ich dabei, das Ganze auf den Atmel zu portieren, und mir macht 
die Hardvard-Architektur zu schaffen.


Ich möchte nämlich einen ausgelesenen Buffer (Datentyp eines "FAT 
Directory Entries") mit einer Konstanten vergleichen:

dir.Name[0] = 0xff;
while( (memcmp(dir.Name, "DATADIR    ", 11) != 0) && (dir.Name[0] != 
0x00)  )
                getDirEntry(0, c++, &dir, 1);


Debugmeldungen, welche Verzeichnisse er durchlaufen hat, liefern 
"DATADIR    " und "" ...

daraus schliesse ich, daß "memcmp" dir.Name mit einem Wert aus dem 
falschen Speicher vergleicht.


Dumm ist nur, daß ein "memcmp(dir.Name PSTR("DATADIR    "), 11)" keinen 
Effekt hat.


Die avr-libc schweigt sich darüber aus, ob memcmp die Daten aus dem RAM, 
dem Flash oder sonstwoher holt :(




Gibt es eine andere Möglichkeit, als memcmp selbst zu implementieren?






Saluti!

Ludwig

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ludwig M. wrote:

> daraus schliesse ich, daß "memcmp" dir.Name mit einem Wert aus dem
> falschen Speicher vergleicht.

Falsche Schlussfolgerung.  Du musst den Bug woanders suchen.  Mit den
paar Brocken kann meine Kristallkugel aber gerade nichts erraten.

> Dumm ist nur, daß ein "memcmp(dir.Name PSTR("DATADIR    "), 11)" keinen
> Effekt hat.

memcmp_P() ist noch nicht implementiert.

> Die avr-libc schweigt sich darüber aus, ob memcmp die Daten aus dem RAM,
> dem Flash oder sonstwoher holt :(

Immer RAM, sofern nichts anderes angegeben war.  Da dein "DATADIR    "
auch im RAM liegt, muss das memcmp() an sich erst einmal
funktionieren.

von Ludwig M. (laludelala)


Lesenswert?

Hallo!

Vielen Dank für die Antwort. Die "paar Brocken" habe ich jetzt ergänzt, 
hier nun die gesamte Funktion. "Directory" ist ein global definierter 
Datentyp und bildet die Verzeichniseinträge in der FAT ab.

Was sich zum vorigen Auszug geändert hat, sind einige 
Debug-Informationen und eine Auswertung für den entsprechenden Return.


Was über die Serielle kommt ist dann:
  Programm gestartet, FAT initialisiert!
  getDataDir: DATADIR
  getDataDir:
  Gefundene DataDir:



Hier die Funktion:

uint16_t getDataDir(void)
{
Directory dir;
uint16_t c = 0;
        dir.Name[0]     = 0xff;
        while( (memcmp(dir.Name, "DATADIR    ", 11) != 0) && 
(dir.Name[0] != 0x00)  )
{
                getDirEntry(0, c++, &dir, 1);
uart_puts(PSTR("\n\ngetDataDir: "));
uart_puts_R(dir.Name);
}
uart_puts(PSTR("\n\nGefundene DataDir: "));
uart_puts_R(dir.Name);
        c--;
        if(dir.Name[0] != 0x00)
                return(dir.FirstClusterLO);
        else
                return(0);
}





Ich hoffe, daß Deine Kristallkugel jetzt besser erraten kann ...



Saluti!

Ludwig

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Sieht mir so aus, als wäre die Schleife mit der Bedingung
1
dir.Name[0]
abgebrochen worden.

p.s.: bitte benutze [ c ] ... [ /c ] Code-Markierungen.

von Karl H. (kbuchegg)


Lesenswert?

Mach mal folgendes:
In der while Schleife:
1
     ...
2
     getDirEntry(0, c++, &dir, 1);
3
     uart_puts(PSTR("\n\ngetDataDir: \""));
4
     uart_puts_R(dir.Name);
5
     uart_puts(PSTR("\""));
6
   }

Und dann zählst du in der Ausgabe mal wieviele
Leerzeichen hinter dem in dir.Name enthaltenem
String noch drann sind. Leerzeichen in einem
Dateinamen sind meistens keine gute Idee. Vor allen
Dingen dann nicht, wenn ein String mit ihnen
beginnt oder endet.

von Karl H. (kbuchegg)


Lesenswert?

Falls du's nicht gesehen hast.
Mein Vorschlag ist, vor und nach der Ausgabe von dir.Name
noch zusätzliche " auszugeben, damit man in der Ausgabe
sieht wo der String anfängt und wo er aufhört.

Übrigens: Wenn du anscheined sowieso mit C-Strings
arbeitest, wieso benutzt du dann die mem... Funktionen.
Für C-strings gibts die schöne str.. Familie an
Funktionen.

von psavr (Gast)


Lesenswert?

Falls Du Deine Stringkostanten irgendwann doch im FLASH halten willst um 
RAM zu sparen:
1
int memcmp_P(const void *, PGM_VOID_P, size_t); 
2
3
int memcmp_P(const void *s1, PGM_VOID_P s2, size_t n) 
4
{ 
5
  if (n != 0) 
6
  { 
7
    unsigned char *p1 = (unsigned char *)s1; 
8
    PGM_P p2 = (PGM_P)s2; 
9
    unsigned char c; 
10
    do 
11
    { 
12
      c=pgm_read_byte(p2++); 
13
      if (*p1++ != c) 
14
      { 
15
        return (*--p1 - c); 
16
      } 
17
    } 
18
    while (--n != 0); 
19
  } 
20
  return (0); 
21
}

von Ludwig M. (laludelala)


Lesenswert?

Hallo!

Ich wollt emich erstmal entschuldigen, das hier etwas totgestellt zu 
haben, ich war einige Wochen ohne Computer - Grafikkartenspeicher im 
Notebook kaputt.


@Karl-Heinz, die Leerstellen sind schon richtig, denn ich lese die FAT 
aus, und die kennt nur mit Leerzeichen aufgefüllte Zeichenketten.
Die Ausgabe erfolgt jedoch mit KEINEM Leerzeichen.
Übrigens nutze ich aus genau diesem Grund (Leerzeichen aufgefüllte 
zeichenketten) die mem... Funktionen statt der str... Funktionen - 
letztere arbeiten nur mit nullterminierten Strings, die aber die FAT 
nicht akzeptiert

@psavr, dankeschön, werde ich mir merken!



Saluti!

Ludwig

von Ludwig M. (laludelala)


Lesenswert?

Hallo!

Das Problem ist owhl, daß der Atmel von der Flash-karte an dieser einen 
Stelle ein "0x00" statt eines "0x20" ausliest - der Rest wird aber schon 
richtig ausgelesen.

Das treibt mich gerade in den Wahnsinn ...



Saluti!

Ludwig

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.