Author Topic: SD Card Performance  (Read 14090 times)

Offline justin@uc

  • Newbie
  • *
  • Posts: 5
  • Inspector Butters
    • View Profile
SD Card Performance
« on: June 28, 2012, 01:51:43 AM »
Hi Mark,

I'm currently using a 16GB SD card hooked up via SPI to my M52259DEMO board to log incoming CAN data (and also send the data to a server program on the PC). The CAN is set to 1 Mb/s, and each message has an 8byte payload. I use a temporary 1KB buffer in RAM to store the data (since I know that SD cards like larger data sets).
The data can come in at either 100, 1000, or 2000 messages/second.

The system can keep up with saving 100 and 1000 messages/sec, but at 2000 it can't. I only get about 1500/second, even after I tried to streamline my application. If I disable SD logging, my system can keep up with 2000 (as I can see from my server program).

I've traced through the SD write routines (through utFAT, mass_storage.c, etc), and I don't see any use of DMA. Is there a way I can easily enable it? Or do I have to manually implement it?

Also, does uTasker support other high-speed "tricks", such as 4-bit mode or setting the card to use "burst mode"?

In short, is there anything I can do to improve performance?

Thank you!
Justin

Offline aersek

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: SD Card Performance
« Reply #1 on: June 28, 2012, 11:06:34 AM »
Writing performance can be enhanced with additional code for caching of FAT table in RAM. Mine colleague have developed these function, with an old 256MB card speedup was 3-4 times, from 4kB/s to 15kB/s. New cards are 5 times faster. With new high capacity, high speed speed cards speedup is not so drastically because bigger cluster size, but you can get at least twice of speedup. We were developed this using CF cards on parallel bus, but I believe that same thing is possible with SD cards.

Trick is that uTasker after every data write in file on card also write FAT sector and update file size. If you keep FAT sector temporary in RAM and update just RAM image, and keep file size also in RAM, you save much of time. Just save FAT on end of file or when you need to change FAT sector, file size save just on end of file, in closeFile routine. Problem is when you turn off power while file is open, and FAT is in RAM, we solved this with saving FAT image and size in NVRAM, so on power up is checked state of NVRAM FAT sector, and saved on card if necessary.

This is our proprietary code, and I can't share it, but idea is simple and it works great.

Best regards

Andrija
« Last Edit: June 28, 2012, 11:08:34 AM by aersek »

Offline justin@uc

  • Newbie
  • *
  • Posts: 5
  • Inspector Butters
    • View Profile
Re: SD Card Performance
« Reply #2 on: June 29, 2012, 02:29:38 AM »
Thanks aersek! That's a very good idea! I moved the FAT updating to utCloseFile() and it worked! My system can now keep up with 2000 messages/sec!

I'm not too worried about power being cut before the FAT updating at the moment, maybe if I have time later I'll implement it. Thanks for the heads up though!

For the record, I commented out this line in mass_storage.c from the function utWriteFile():

Code: [Select]
//while (utCommitSector(ptr_utDisk, ptr_utFile->private_disk_location.directory_location.ulSector) == CARD_BUSY_WAIT) {} // force writeback to finalise the operation
And my utCloseFile() now looks like:

Code: [Select]
extern void utCloseFile(UTFILE *ptr_utFile)
{
// Update FAT at close of file instead of every write.
UTDISK *ptr_utDisk = &utDisks[ptr_utFile->ucDrive];
DIR_ENTRY_STRUCTURE_FAT32 *ptrFileEntry = (DIR_ENTRY_STRUCTURE_FAT32 *)ptr_utDisk->ptrSectorData; // the directory entry in the sector buffer
while (utCommitSector(ptr_utDisk, ptr_utFile->private_disk_location.directory_location.ulSector) == CARD_BUSY_WAIT) {} // force writeback to finalise the operation
// End of changes.
...
}

Hope that helps someone!

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3238
    • View Profile
    • uTasker
Re: SD Card Performance
« Reply #3 on: June 29, 2012, 03:12:58 PM »
Hi All

I had some communication with Andrija last year concerning his project and some optimisations that were made. He has done some great work (not just concerning the FAT interface part) and I still have a collection of ideas from then.

I am presently a little wary about the FAT sectors caching since I could imagine that this will fail if more than one user were to be writing files at the same time but it will cut down on unnecessary SD card writes, which can obviously slow things down.

Another related, but not identical, problem is that seeks in files can also become slow when the files get large - see http://www.utasker.com/forum/index.php?topic=1729.0
This is due to the fact that a seek in a backward direction requires the FAT file cluster to be searched through starting from the beginning. Even when rewinding a few bytes in the file (eg. to repeat HTTP content that is being taken from the card) means that the seek has to be performed. A technique used to accelate this involves keeping a backup of the previous file location at the application layer. In addition to holding the present location in the file the struct also holds physical access information (which cluster, for example) and by simply overwriting the file struct after data has been read by a copy of it before the data was read immediately sets the file pointer back to the previous location without the need to do any cluster chain searching (requiring reading sectors from the card a number of times).

Generally it becomes obvious that there can be advantages when the application itself can hold some file system information (presently ignoring the fact that these backups could becoming invalid if another user manipulates the same file - but there are already mechanisms - see MANAGED_FILES - that can resynchronise such things), as we have seen also here; either for temporary FAT content or file structs. Such techniques are already in operation in certain projects where they are important due to speed requirements.

I am thinking that it may be useful for the application to optionally pass some storage space to the utFAT so that it can be used on an individual bases so that multiple users will not be able to disturb each other (i.e. multiple writes to the same card could be in operation at the same time to different open files and more than one application could be reading from a single file - usually from different locations of course). I could imaging this to be a safe generic method for allowing acceleration to be enabled specifically where it is most useful in a project, also allowing a tradeoff between memory requirements and speed, whereby we all known that by allowing more RAM to be used (for buffering) it is often possible to reduce the need for slower external accesses.

I will be considering these possibilities for future releases so all ideas are very welcome ;-)

Regards

Mark


Offline aersek

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: SD Card Performance
« Reply #4 on: July 03, 2012, 11:33:57 AM »
There is no problem with multiple user accesses. FAT cache is allocated in mass_storage.c file, and all accesses to disk are made trough same FAT image in RAM. It's implemented in all functions that access FAT table (fnAllocateCluster, deleteClusterChain, fnNextSector...) reading it or writing to it. Good thing is that uTasker is round-robin approach OS, so only one task is running in moment, no other tasks are stored on stack, and because of that functions from mass_storage.c can't be called at same time from different tasks.

Best regards

Andrija

Offline justin@uc

  • Newbie
  • *
  • Posts: 5
  • Inspector Butters
    • View Profile
Re: SD Card Performance
« Reply #5 on: July 04, 2012, 03:00:41 AM »
Thanks for the information Mark and Andrija!

I've "solved" my next problem of keeping up with 3000 messages/second by increasing the SPI baud rate to 20MHz from 8MHz. Seems to work well!

I've also solved the problem of the dangers of holding the FAT information in RAM too long--I write back the FAT cache every time 128 new sectors/clusters are created.

One more question though: If the file is fresh I can get 3000 messages/sec just fine for as long as I want (the files typically get to about 5-10MBs in size before I manually stop the logging). But once I close then reopen the file (and re-start the logging) the performance starts to drop, with each consecutive open/close further slowing the logging performance down (to about 2400 messages/sec). My solution now is to delete the file and start fresh, but obviously this isn't sustainable. Does anyone have any ideas as to why this is happening? Is it the increased seek times because the file gets too large?

Thanks!
Justin

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3238
    • View Profile
    • uTasker
Re: SD Card Performance
« Reply #6 on: July 09, 2012, 04:14:33 PM »
Justin

The size of a file shouldn't affect the reading time.
A seek delay is only relevant when moving the file pointer in the file - reading blocks of data doesn't require a seek.

Regards

Mark