Tweepy February 2016

External file ressource on embedded system (C language with FAT)

My application/device is running on an ARM Cortex M3 (STM32), without OS but with a FatFs) and needs to access many resources files (audio, image, etc..)

  • The code runs from internal flash (ROM, 256Kb).
  • The resources files are stored on external flash (SD card, 4Gb).
  • There is not much RAM (32Kb), so malloc a complete file from package is not an option.

As the user has access to the resources folder for atomic update, I would like to package all theses resources files in a single (.dat, .rom, .whatever) So the user doesn't mishandle theses data.

Can someone point me to a nice solution to do so?

I don't mind remapping fopen, fread, fseek and fclose in my application, but I would not like starting from scratch (coding the serializer, table of content, parser, etc...). My system is quite limited (no malloc, no framework, just stdlib and FatFs)

Thanks for any input you can give me.

note: I'm not looking for a solution where the resources are embedded IN the code (ROM) as obviously they are way too big for that.

Answers


Brian McFarland February 2016

To expand on what Joachim said above:

Popular choices of uncompressed (sometimes) archive formats are cpio, tar, and zip. Any of the 3 would work just fine.

Here are a few more in-depth comments on using TAR or CPIO.

TAR

I've used tar before for the exact purpose, on an stm32 with FatFS, so can tell you it works. I chose it over cpio or zip because of its familiarity (most developers have seen it), ease of use, and rich command line tools.

GNU Tar gives you fine-grained control over order in which the files are placed in the archive and regexes to manipulate file names (--xform) or --exclude paths. You can pretty much guarantee you can get exactly the archive you're after with nothing more than GNU Tar and a makefile. I'm not sure the same can be said for cpio or zip.

This means it worked well for my build environment, but your requirements may vary.

CPIO

The cpio has a much worse/harder to use set of command line tools than tar in my opinion. Which is why I steer clear of it when I can. However, its file format is a little lighter-weight and might be even simpler to parse (not that tar is hard).

The Linux kernel project uses cpio for initramfs images, so that's probably the best / most mature example on the internet that you'll find on using it for this sort of purpose.

If you grab any kernel source tree, the tool usr/gen_init_cpio.c can used to generate a cpio from a cpio listing file format described in that source file.

The extraction code is in init/initramfs.c.

ZIP

I've never used the zip format for this sort of purpose. So no real comment there.


berendi February 2016

It should be possible to use fatfs recursively.

Drive 0 would be your real device, and drive 1 would be a file on drive 0. You can implement the disk_* functions like this

#define BLOCKSIZE 512
FIL imagefile;
DSTATUS disk_initialize(BYTE drv) {
  UINT r;
  if(drv == 0)
    return SD_initialize();
  else if(drv == 1) {
    r = f_open(&image, "0:/RESOURCE.DAT", FA_READ);
    if(r == FR_OK)
      return 0;
  }
  return STA_NOINIT;
}
DRESULT disk_read(BYTE drv, BYTE *buff, DWORD sector, DWORD count) {
  UINT br, r;
  if(drv == 0)
    return SD_read_blocks(buff, sector, count);
  else if(drv == 1) {
    r = f_seek(&imagefile, sector*BLOCKSIZE);
    if(r != FR_OK)
      return RES_ERROR;
    r = f_read(&imagefile, buff, count*BLOCKSIZE, &br);
    if((r == FR_OK) && (br == count*BLOCKSIZE))
      return RES_OK;
  }
  return RES_ERROR;
}

To create the filesystem image on Linux or other similar systems you'd need mkfs.msdos and the mtools package. See this SO post on how to do it. Might work on Windows with Cygwin, too.


Tweepy February 2016

Berendi found a very clever solution: use the existing fat library to access it recursively!

The implementation is quite simple, and after extensive testing, I'd like to post the code to use FatFs recursively and the commands used for single file fat generation.

  1. First, lets generate a 100Mb FAT32 file:

dd if=/dev/zero of=fat.fs bs=1024 count=102400

mkfs.vfat -F 32 -r 112 -S 512 -v fatfile.fs

  1. Create/push content into it:

echo HelloWorld on Virtual FAT >> helloworld.txt

mcopy -i fatfile.fs helloworld.txt ::/

  1. Change the diskio.c file, to add Berendi's code but also:
DSTATUS disk_status ()
{
  DSTATUS status = STA_NOINIT;
  switch (pdrv)
  {
  case FATFS_DRIVE_VIRTUAL:
      printf("disk_status: FATFS_DRIVE_VIRTUAL\r\n" );
  case FATFS_DRIVE_ATA:    /* SD CARD */
      status = FATFS_SD_SDIO_disk_status();
  }
}
  1. Dont forget to add the enum for the drive name, and the number of volumes:

#define _VOLUMES 2

  1. Then mount the virtual FAT, and access it:
f_mount(&VirtualFAT, (TCHAR const*)"1:/", 1);
f_open(&file, "1:/test.txt", FA_READ);

Thanks a lot for your help.

Post Status

Asked in February 2016
Viewed 3,915 times
Voted 8
Answered 3 times

Search




Leave an answer