Getting started with FreeRTOS+ FAT SL

andheu wrote on Thursday, August 01, 2013:

Hi there

I’m hoping someone can give me some pointers with regards to setting up a FreeRTOS+ FAT SL file system. I’ve run the example that runs in the windows simulator and creates a volume in RAM. I’ve gone through all the code and understand the basics of whats going on with the port layer functions and the structures they use.

My problem is this. I want to set up a file system in flash memory (either on the on board flash in a mcu or a sd card) but I can’t see what I would change in the example to do this (i.e change from RAM to flash). It also seems that I will need to do more than just provide the port layer functions and config files as described here: http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT_SL/Download_FreeRTOS_Plus_FAT_SL.shtml. Or am I wrong?

Obviously I have no experience in this type of thing so even just being pointed to a resource on this topic would help.

Thanks

rtel wrote on Thursday, August 01, 2013:

As far as an interface to the file system is concerned, you do just have to provide the functions specified on the link you reference in your post.  How those functions are implemented depends on the media you are writing to (RAM, NAND flash, NOR flash, SD card, etc.) - so I think your question is related to media drivers rather than the file system itself?

The file system is provided with a RAM disk driver because it is extremely portable, and can be executed on anything that has sufficient RAM.  As soon as you move this to any other media it starts to get more application specific.

Taking an SD card as an example media, and F_WRITESECTOR() as an example function:

The RAM disk has a block of memory that is, in fact, just an array of RAM.  An SD card has a virtual block of memory that is on the SD card itself.

If you look at the RAM disk F_WRITESECTOR() function you will see that it calculates the address of the start of the sector to be written to simply by offsetting it from the start address, and then writes to that address byte for byte (in effect doing a memcpy() from source to destination).

The SD card equivalent can calculate the address in a similar manner, but writing to the SD card is not just a matter of performing a memcpy().  It will require a peripheral (MMC/SPI) to actually write the bytes, and software to control the write protocol.  The write protocol is the sequence necessary to write to the card, set the chip select, reset the card, put the card into the mode required (if SPI mode), wait for the SD card to be idle, address the card, write the bytes, get acks/nacks back, CRC, etc, etc.

How to write to an SD card is specified in the SD specification, and you can find lots of references (e.g. http://www.cs.ucr.edu/~amitra/sdcard/Additional/sdcard_appnote_foust.pdf) and examples by Googling for “SD card software interfacing”.  Wikipedia has more references than possible to read in a lifetime.  https://en.wikipedia.org/wiki/Secure_Digital

You can of course purchase drivers too.

If you were to use some other flash technology, then you would have to write a media driver for that in the same way.

Does this go some  way to answering your question.

Regards.

andheu wrote on Friday, August 02, 2013:

Yes thank you

The only thing I’m still not sure about is where the demo code gets the address of the RAM. In the ramdrv_f.c file, the following is declared globally:

char  ramdrv0[MDRIVER_RAM_VOLUME0_SIZE];
typedef struct
{
  char         * ramdrv;
  unsigned long  maxsector;
  int            use;
  F_DRIVER     * driver;
} t_RamDrv;
static F_DRIVER  t_drivers[1];
static t_RamDrv  RamDrv[1] =
{
  { ramdrv0, ( MDRIVER_RAM_VOLUME0_SIZE / MDRIVER_RAM_SECTOR_SIZE ), 0, &t_drivers[0] }
};

and the initialisation function contains

t_RamDrv    * p;
  p = RamDrv + driver_param;
(void)psp_memset( p->driver, 0, sizeof( F_DRIVER ) );

So to me it looks like the code uses the fact that t_drivers is created in RAM, and therefore pointing to it points to RAM? And then psp_memset clears some RAM for use by the file system?

If that’s correct then I imagine &t_drivers is what I should replace with the peripheral/flash address?

Thanks in advance!

rtel wrote on Friday, August 02, 2013:

So in the RAM drive the media is just RAM, which is allocated as an array.  The address of the array is then placed into the t_RamDrv structure. 

How you modify this to swap the RAM for flash depends on how the Flash is interfaced.

If your flash is memory mapped then you can replace the start of the RAM array with the address of the start of your flash - which you will know from the memory map and/or linker script.  Reading from the flash will most probably be comparable to reading from RAM and you will not have to update the F_READSECTOR function will not change much if at all.  Writing to the Flash will definitely not be like writing to RAM though, so the F_WRITESECTOR function will need updating to do whatever is necessary to erase and re-write flash sectors.

If you have a serial interface to your flash then the memory map of the flash is completely separate to that of your microcontroller, and the start of the flash is in effect address 0 inside the flash.  Then both your read and write sector functions will be quite different to those used by the RAM driver.

Regards.

andheu wrote on Tuesday, August 06, 2013:

That makes sense but if that is how I point to the flash memory, how do turn something like (using the EFM32 gecko):

FLASH_SIZE - 16 * MDRIVER_OBFLASH_SECTOR_SIZE

into a pointer to a F_DRIVER structure as is required when declaring a t_RamDrv structure?

davedoors wrote on Tuesday, August 06, 2013:

I don’t think the F_DRIVER strcuture needs to be in the flash, or pointed to by anything, it is just a RAM variable like any other. It looks like the t_RamDrv structure in the code you posted is just grouping information about a single drive into one place for convenience, maybe because the driver is also used in systems that have more than one drive at a time.

You just need to know the address of the first byte of flash that is part of the file system, then sector addresses are just offset from there. In the RAM drive the base address happens to be the start of the array used to hold the drive structure. Inside the t_RamDrv it is pointed to by ramdrv, but I think this is adding a level of indirection that you don’t need. You could just refer to the same memory as ramdrv0 (the start of the ramdrv0 array), and have the F_DRIVER structure as a file scope variable, and forget about the t_RamDrv structure all together as it seems to have no purpose for a system with one drive.