Forum: Mikrocontroller und Digitale Elektronik Formatieren mit ElmChan FatFS


von Holger K. (holgerkraehe)


Angehängte Dateien:

Lesenswert?

Hallo zusammen

Ich verwende ElmChans FatFS (die vollständige Version)

Mit dieser möchte ich mein FlashSpeicher welcher in Form eines ICs 
vorhanden ist, ansprechen.
Ich habe die DiskIO inzwischen korrekt angepasst.

Nun geht es darum, den Flash zu formatieren.

Das IC ist intern in Pages zu je 256Bytes aufgeteilt.
Diese kann ich Schreiben und Lesen (in 256Byte Blöcken)

Meine DiskIO Konvertiert die vom FatFS kommenden Anfragen, welche für 
einen Sector 512Bytes vorsehen, so dass es diese richtig aus dem Flash 
liest.

Nun fehlt bei meinem Flash jedoch eine FAT und auch ein MBR.
Könnte mir jemand helfen, diese beiden zu erstellen?

FatFS bietet zwei Funktionen an:

f_fdisk und f_mkfs

f_mkfs - Create an FAT volume on the logical drive
f_fdisk - Create logical drives on the physical drive

http://elm-chan.org/fsw/ff/00index_e.html


Ich vermute, dass ich zuerst f_fdisk und dann f_mkfs ausführen muss.
Wobei f_fdisk einen MBR voraussetzt.

Bisher habe ich noch keinen MBR selbst gestrickt.
Nach dem Einlesen in Wikipedia, hätte ich den MBR an Adresse 0x00 des 
Flashs gelegt. Also aus sicht des FatFS auf Sektor 0

Diesen hätte ich wie im Bild im Anhang erstellt.
Die Partitionstabelle wird ja nach meinem Verständnis mit f_fdisk von 
FatFS erstellt.

Müsste das so funktionieren?
Danke

von Falk B. (falk)


Lesenswert?

@Holger Krähenbühl (holgerkraehe)

>Ich vermute, dass ich zuerst f_fdisk und dann f_mkfs ausführen muss.
>Wobei f_fdisk einen MBR voraussetzt.

Ja.

>Bisher habe ich noch keinen MBR selbst gestrickt.
>Nach dem Einlesen in Wikipedia, hätte ich den MBR an Adresse 0x00 des
>Flashs gelegt. Also aus sicht des FatFS auf Sektor 0

Ja.

>Die Partitionstabelle wird ja nach meinem Verständnis mit f_fdisk von
>FatFS erstellt.

Scheint so.

>Müsste das so funktionieren?

Ja.

von Holger K. (holgerkraehe)


Lesenswert?

Danke für die Antwort.
Tut es jedoch leider nicht.


Habe mir den Code von ElmChan genauer angeschaut.
Das erste wass man nach seinem Tutorial machen soll ist:

/* Register work area (do not care about error) */
f_mount(&fs, "", 0);

/* Create FAT volume with default cluster size */
res = f_mkfs("", 0, 0);
if (res) ...


f_mkfs macht folgendes:
1
  if (_MULTI_PARTITION && part) {
2
    /* Get partition information from partition table in the MBR */
3
    if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR;
4
    if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED;
5
    tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
6
    if (!tbl[4]) return FR_MKFS_ABORTED;  /* No partition? */
7
    b_vol = LD_DWORD(tbl + 8);  /* Volume start sector */
8
    n_vol = LD_DWORD(tbl + 12);  /* Volume size */
9
  } else {
10
    /* Create a partition in this function */
11
    if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
12
      return FR_DISK_ERR;
13
    b_vol = (sfd) ? 0 : 63;    /* Volume start sector */
14
    n_vol -= b_vol;        /* Volume size */
15
  }

Er prüft zuerst ob man mehrere Partitionen in den Defines aktiviert hat.
Dies ist standardmässig nicht der Fall und wird auch nicht benötigt.

Falls dies nicht der Fall ist,
geht der Code hier hin:
1
else {
2
    /* Create a partition in this function */
3
    if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
4
      return FR_DISK_ERR;
5
    b_vol = (sfd) ? 0 : 63;    /* Volume start sector */
6
    n_vol -= b_vol;        /* Volume size */
7
  }

Hier wird die VolumeSize aus n_vol gebildet.
n_vol ist bei mir: 16755320
Dies bereits nach dem ersten Sprung in f_mkfs

f_mkfs kennt noch einen Übergabeparameter "au"
Dieser definiert die Anzahl Sektoren.
Jedoch können diese nur im Bereich von 0..128 gewählt werden.
Sehr merkwürdig wie ich finde. Denn mein Flash hat 2048 Sektoren a 
512Byte

Soll ich nun einfach n_vol manuell setzen?

Was meint ihr?

: Bearbeitet durch User
von Holger K. (holgerkraehe)


Lesenswert?

Wenn "au" grösser als _MIN_SS ist, dann repräsentiert es die Anzahl 
Bytes.
Somit 2048 * 512.

Leider kommt dann diese Zeile:
1
if (au > 128) au = 128;

und n_Vol ist immernoch 16755320

von W.S. (Gast)


Lesenswert?

Du hast da ein bissel schlechte Karten. Der Grund ist, daß Chan's FF 
eigentlich zuviel erledigen möchte.
Normalerweise würde man beim Erkennen eines Speichermediums einen 
Handler aktivieren, der dieses Medium als solches behandelt, also MBR 
ausliest (falls nicht BigFloppy) und dann für jede der 4 möglichen 
Partitionen ein dazu passendes Filesystem installiert, welches 
wohlgemerkt NUR SEINE Partition behandelt. Bei einer erweiterten 
Partition dann wiederum einen Handler, der die log.LW innerhalb dieser 
Partition mit passenden Filesystemen verbindet.

Aber:
Chan's FF will das alles selber machen und hat natürlich damit Probleme. 
Bedenke mal, was es für Restriktionen auf einer normalen Festplatte 
gibt, WO eine Partition losgehen darf. Normalerweise hat man zwischen 
MBR und 1. Partition eine Lücke, die bei dir womöglich so groß ist wie 
dein Flash. Also kein HD-Layout verwenden, sondern ne große Floppy 
emulieren - ohne MBR.

Nochwas:
Chan ist einer der Leute, die unangenehmerweise voraussetzen, daß aller 
Speicher im RAM ja grundsätzlich ausgenullt sein muß, weil irgend ein 
C-Papst sowas mal vor ... Jahren gelallt hat. Konsequenterweise geht bei 
Medienwechsel oder System-Restart oder (vermutlich) beim Umformatieren 
und anschließendem Mounten sein FF in den Crash. Ich hatte das mal 
behoben durch konsequentes Ablöschen der benötigten RAM-Variablen beim 
Mounten, aber die Quellen sind in der Firma..

W.S.

von Holger K. (holgerkraehe)


Lesenswert?

Guten Morgen zusammen

Ich möchte mitteilen, dass ElmChans FatFS erfolgreich für ein FlashChip 
angepasst wurde.

Für diejenigen die es interessiert, hier kurz die ToDo Liste:

- Funktionen schreiben, um Pages (Blöcke von Bytes in der Grösse von 512 
/ 1024 2048 oder 4096) vom Flash Lesen und Schreiben zu können ab einer 
definierten Adresse.

- Dikio.c anpassen.
- FlashChip von FatFS formatieren lassen. mittels f_mkfs


Nun die Details:

Für FatFS ist die kleinste Speichereinheit ein Sektor.
Wie gross ein Sektor ist, wird in ffconf.h definiert.

Standardmässig ist dieser 512Byte. Dies bietet sich bei mir an, 
beibehalten zu werden.

1. Niedrigerer Ram verbrauch
2. Meine kleinste physikalisch schreibbare Einheit (auf dem Flash) ist 
256Bytes

Nun muss man sich zwei funktionen schreiben, welche vom flash ab einer 
bestimmten Addresse Daten lesen und schreiben.

Meine sieht wie folgt aus:
1
void pageWrite(uint8_t *Buffer, uint32_t Address, uint16_t Count)
2
{
3
  uint16_t i = 0;
4
5
  set_WriteEN();
6
  //Warten bis Schreibvorgang beendet ist!
7
  while(readStatus() & WIP_MASK);
8
9
  CS_0;
10
  SPI_TRX(0x0A);
11
  SPI_TRX((Address & 0xFF0000) >> 16);
12
  SPI_TRX((Address & 0x00FF00) >> 8);
13
  SPI_TRX((Address & 0x0000FF));
14
  while( i != Count )
15
  {
16
    SPI_TRX(Buffer[i]);
17
    i++;
18
  }
19
  CS_1;
20
}

Dies ist die notwendige Grundlage, um in Diskio.c elegant die restlichen 
Funktionen zu ergänzen.

In Diskio.c gibt es Read und ein Write.

Diese sehen bei mir so aus:
1
DRESULT disk_write (
2
  BYTE pdrv,      /* Physical drive nmuber to identify the drive */
3
  const BYTE *buff,  /* Data to be written */
4
  DWORD sector,    /* Sector address in LBA */
5
  UINT count      /* Number of sectors to write */
6
)
7
{
8
9
10
11
  uint32_t    Address = 0;
12
13
  //Sektoren addresse,
14
  //Sektor wurde mit 512 Byte definiert.
15
16
  //Startaddresse berechnen
17
18
19
  Address = ((sector + 1) * 512) - 512;
20
21
  if(count == 1)
22
  {
23
    pageWrite(buff,Address,256);
24
    buff += 256;
25
26
    pageWrite(buff,Address+256,256);
27
  }
28
  else
29
  {
30
    do
31
    {
32
      //Start Addresse berechnen
33
      Address = ((sector + 1) * 512) - 512;
34
35
      pageWrite(buff,Address,256);
36
      buff += 256;
37
38
      pageWrite(buff,Address+256,256);
39
      buff+=256;
40
      sector++;
41
    }while(count--);
42
  }
43
44
  //Warte bis der Schreibvorgang beendet wurde vom Flash
45
  while(readStatus() & WIP_MASK);
46
  return RES_OK;
47
48
}


Da ich hier lediglich die Sektoren nummer bekomme, und ein Sektor 
512Byte ist, muss ich dies auf meine Gegebenheiten umrechnen.
Insbesondere die Adresse muss entsprechend umgerechnet werden.


Wichtig ist noch die Funktion ioctl in diskio.c

Diese gibt informationen zum Speichermedium an FatFS zurück.
Unteranderem die Anzahl Sektoren und die anzahl Bytes/Sektor
Wobei letzeres ignoriert wird wenn in der config eine fixe Sektoren 
grösse definiert wurde (was sinnvoll ist)
1
DRESULT disk_ioctl (
2
  BYTE pdrv,    /* Physical drive nmuber (0..) */
3
  BYTE cmd,    /* Control code */
4
  void *buff    /* Buffer to send/receive control data */
5
)
6
{
7
8
9
    if( cmd == GET_SECTOR_COUNT )
10
    {
11
      *(DWORD*)buff = 2048; //2048 sektoren a 512bytes = 8Mb Flash
12
    }
13
14
    if( cmd == GET_SECTOR_SIZE )
15
    {
16
      *(DWORD*)buff = 512;
17
    }
18
19
    if( cmd == GET_BLOCK_SIZE )
20
    {
21
      *(DWORD*)buff = 1;
22
    }
23
24
    return RES_OK;
25
26
  //return RES_PARERR;
27
}

Wenn man dies ersteinmal angepasst hat, dann kann man den Chip 
formatieren.
Dies geschieht mittels dem befehl f_mkfs
1
      f_mount(&fs,"",0);
2
      res = f_mkfs("",1,0);

Parameter zwei gibt ob eine Partitionstabelle in den MBR geschrieben 
wird oder nicht. Da ich auf meinem Speicher keine Partitionen möchte, 
wähle ich hier 1 für SFD.

Damit beginnt die FileAllocationTable (FAT) direkt beim ersten Sektor 
des Flashchips.

Wenn alles geklappt hat ist res = FR_OK.

Dannach kann man beliebig Dateien erstellen, bearbeiten, löschen etc.
Auch Ordner erstellen und den Inhalt auflisten.

War erst einmal klar, wie das ganze funktioniert, war es sehr einfach 
den Code entsprechend anzupassen.
Evtl. hilft es ja jemandem.


Hier noch ein paar Bemerkungen:

- Wearleveling ist nicht vorhanden.
  Wenn also oft Dateien erstellt oder geändert werden, wird die FAT sehr 
häufig geschrieben. dadurch gehen diese Speicherzellen als erstes 
kapput.

Neuere Flashspeicher können mind. 100'000 Schreibzyklen aushalten.
Da kann dann jeder selbst berechnen.

Alternativ könnte man so auch FRAM oder andere Speicher einsetzen.


Viel Spass
Gruss

eure Krähe

von Falk B. (falk)


Lesenswert?

Herzlichen Glückwunsch!

von Holger K. (holgerkraehe)


Lesenswert?

Danke :)

von Thomas S. (df1po)


Lesenswert?

Servus,
ich hab das Ganze auf einem W7500P (Cortex M0) laufen. Es gibt da ein 
Problem nach dem f_mkfs. Die freien Cluster (f_getfree) werden nach dem 
f_mkfs immer konstant angezeigt (max. Größe des NOR Flashs), egal 
wieviel ich schreibe. Starte ich das Programm komplett neu (Reset) 
stimmt wieder alles und die Größe wird entsprechend angezeigt. So mach 
ich das:

FRes = f_getfree ("/", &nclst, &pFatFs);  /* Get number of free clusters 
on the drive */
FRes = f_mkfs ("", 1, 4096);      // sfd filesystem
if (FRes != FR_OK) {
  cmd_error(FRes);
}
FRes = f_mount(0, "", 0);
pFatFs = &FatFs;
FRes = f_mount(&FatFs,"/",0);
FRes = f_getfree ("/", &nclst, &pFatFs);  /* Get number of free clusters 
on the drive */ <-- dieser Wert bleibt konstant bis zum nächsten Rest



Hat jemand eine Idee dazu ?

Gruß
Thomas

von c-hater (Gast)


Lesenswert?

Thomas S. schrieb:

> Hat jemand eine Idee dazu ?

Lerne Programmieren...

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.