[En-Nut-Discussion] Improvement for faster mounting of large SD cards

Malte Marwedel m.marwedel at onlinehome.de
Sat Jan 16 17:52:50 CET 2010

I am using a 4GB SD card together with Nut/OS. Unfortunately, mounting a 
volume took several minutes. So I looked into the source and found, that 
nearly all of the time is needed determining which of the nearly 1000000 
clusters is free (PhatCountFreeClusters()). For every cluster the code 
made three function calls (Phat32GetClusterLink(), PhatTableLoc(), 
PhatSectorLoad()), some pointer arithmetic and uint32_t by uint16_t 
division. Together with a stack on a slow external RAM, this took some time.
So I put Phat32GetClusterLink(), PhatTableLoc() together into one 
function, avoided the division and reduced the pointer calculations and 
PhatSectorLoad() calls.
The downside is of course, that the functional separation of phat32.c 
and phatvol.c is mixed together and with the old functions still around, 
code is somewhat duplicated. So I have my doubt if it would be good to 
add it to the Nut/OS distribution. But if someone has the same problem, 
he might be happy about the code here.

Measured mount speeds (ATMega128 with 16MHz and some other interrupts 
and threads consuming a few percent of CPU):

cluster size: 4K:
   original code: 217 sec
   optimized code: 29 sec

As I still was not satisfied with 29 seconds, I simply formatted the 
card with a larger cluster size.
cluster size 16K:
   original code: 54 sec
   optimized code: 8 sec


  * \brief Counts the number of free clusters in a fat32 volume, fast 
  * \param dev Specifies the file system device.
  * \return The number of free clusters.
static uint32_t PhatFastPhat32FreeClusters(NUTDEVICE * dev) {
     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
     uint32_t rc = 0;
     uint32_t clust = 0;
     uint32_t clustlast = vol->vol_last_clust;
     /* Do not seek beyond the end of the chain. */
     if (clustlast >= (PHATEOC & PHAT32CMASK)) {
         clustlast = (PHATEOC & PHAT32CMASK) -1;
     uint32_t pos = -4;
     uint32_t sect = vol->vol_tab_sect[0];
     int sbn = PhatSectorLoad(dev, sect);
     uint8_t * sdata = vol->vol_buf[sbn].sect_data;
     while (clust < clustlast) {
         pos += 4;
         /* Load the sector that contains the table entry. */
         if (pos >= vol->vol_sectsz) {
             pos = 0;
             sbn = PhatSectorLoad(dev, sect);
             if (sbn  < 0) {
             sdata = vol->vol_buf[sbn].sect_data;
         /* Check if the 32 bit link value is zero */
         uint8_t link = sdata[pos];
         link |= sdata[pos + 1];
         link |= sdata[pos + 2];
         link |= sdata[pos + 3];
         if (link == 0) {
     return rc;

More information about the En-Nut-Discussion mailing list