3/29/2014

Petit FAT for NUC122

FAT 是檔案系統簡稱
以前的MCU要PO FAT可說是個大工程
但現在很多原廠都有提供FAT lib


使用都很少需要在自已去了解FAT的部份
但如果真的有問題時
就只能等待原廠的回應嗎?

FATFS 這個網站的作者
提供了FAT系統
符合ANSI C 的標準
所以在移植上非常的容易
而且所有sourde code都是開放的
可用於商業行為

FATFS 對RAM的需求比較高,但功能較完整
能Mount SDC/CF/HD/USB.....等裝置

Petit FAT 是簡易版,對RAM和ROM的要求較小
但在寫檔方面的限制是
只能取代原檔案內的內容
不能開新檔案

Petit FAT移植範例:
在原文件中提到移植Petit FAT
需使用者完成三個API
1. disk_initialze
2. disk_readp
3. disk_writep

另integer.h也是需要注意的地方
但基本上是不需要做修改的

PFF.h是功能定義的設定檔

首先了解SD/MMC是使用SPI方式做溝通
SPI Mode0 /Mode3 二種都可

在來就是實作需要的三個API

1. disk_initialze
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive                                                 */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (void)
{
 BYTE n, cmd, ty, ocr[4];
 UINT tmr;

#if _USE_WRITE
 if(CardType && MMC_SEL)
        disk_writep(0, 0); /* Finalize write process if it is in progress */
#endif
 init_spi();  /* Initialize ports to control MMC */

 DESELECT();    //SPI CS = H

 for(n = 10; n; n--)
        spi_wr(0xFF); /* 80 dummy clocks with CS=H */

 ty = 0;
 if(send_cmd(CMD0, 0) == 1)    /* Enter Idle state */
    {   
  if(send_cmd(CMD8, 0x1AA) == 1)   /* SDv2 */
        { 
   for(n = 0; n < 4; n++)
                ocr[n] = spi_wr(0xFF);  /* Get trailing return value of R7 resp */

   if(ocr[2] == 0x01 && ocr[3] == 0xAA) /* The card can work at vdd range of 2.7-3.6V */
            {   
    for(tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--)    /* Wait for leaving idle state (ACMD41 with HCS bit) */
                    DELAY_100u();

    if(tmr && send_cmd(CMD58, 0) == 0)  /* Check CCS bit in the OCR */
                {  
     for(n = 0; n < 4; n++)
                        ocr[n] = spi_wr(0xFF);

     ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */
    }
   }
  }
        else
        {       /* SDv1 or MMCv3 */
   if (send_cmd(ACMD41, 0) <= 1)
            {
    ty = CT_SD1;
                cmd = ACMD41; /* SDv1 */
   }
            else
            {
    ty = CT_MMC;
                cmd = CMD1; /* MMCv3 */
   }

   for (tmr = 10000; tmr && send_cmd(cmd, 0); tmr--)
                DELAY_100u(); /* Wait for leaving idle state */

   if (!tmr || send_cmd(CMD16, 512) != 0)   /* Set R/W block length to 512 */
    ty = 0;
  }
 }
 CardType = ty;
 DESELECT();
 spi_wr(0xFF);

 return ty ? 0 : STA_NOINIT;
}
2. disk_readp
/*-----------------------------------------------------------------------*/
/* Read partial sector                                                   */
/*-----------------------------------------------------------------------*/

/* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
/* Sector number (LBA) */
/* Byte offset to read from (0..511) */
/* Number of bytes to read (ofs + cnt mus be <= 512) */

DRESULT disk_readp(BYTE *buff,DWORD lba,WORD ofs,WORD cnt)
{
 DRESULT res;
 BYTE rc;
 WORD bc;

 if(!(CardType & CT_BLOCK))
        lba *= 512;  /* Convert to byte address if needed */

 res = RES_ERROR;
 if(send_cmd(CMD17, lba) == 0)  /* READ_SINGLE_BLOCK */
    {
  bc = 40000;

  do{       /* Wait for data packet */
   rc = spi_wr(0xFF);
  } while (rc == 0xFF && --bc);

  if(rc == 0xFE)        /* A data packet arrived */
        {
   bc = 514 - ofs - cnt;

   /* Skip leading bytes */
   if(ofs)
            {
    do spi_wr(0xFF); while (--ofs);
   }

   /* Receive a part of the sector */
   if(buff)
            { /* Store data to the memory */
    do{
     *buff++ = spi_wr(0xFF);
    } while (--cnt);
   }
            else
            { /* Forward data to the outgoing stream (depends on the project) */
   // do{
   //  FORWARD(spi_read());
   // } while (--cnt);
   }

   /* Skip trailing bytes and CRC */
   do spi_wr(0xFF); while (--bc);

   res = RES_OK;
  }
 }

 DESELECT();
 spi_wr(0xFF);

 return res;
}

3. disk_writep
/*-----------------------------------------------------------------------*/
/* Write partial sector                                                  */
/*-----------------------------------------------------------------------*/
/* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
/* Number of bytes to send, Sector number (LBA) or zero */

#if _USE_WRITE
DRESULT disk_writep (const BYTE *buff,DWORD sa)
{
 DRESULT res;
 WORD bc;
 static WORD wc;

 res = RES_ERROR;

 if(buff)
    {  /* Send data bytes */
  bc = (WORD)sa;
  while (bc && wc)
        {  /* Send data bytes to the card */
   spi_wr(*buff++);
   wc--; bc--;
  }
  res = RES_OK;
 }
    else
    {
  if(sa)
        { /* Initiate sector write process */
   if(!(CardType & CT_BLOCK))
                sa *= 512; /* Convert to byte address if needed */

   if(send_cmd(CMD24, sa) == 0)
            {   /* WRITE_SINGLE_BLOCK */
    spi_wr(0xFF);
                spi_wr(0xFE);  /* Data block header */
    wc = 512;       /* Set byte counter */
    res = RES_OK;
   }
  }
        else
        { /* Finalize sector write process */
   bc = wc + 2;
   while (bc--)
                spi_wr(0); /* Fill left bytes and CRC with zeros */

   if((spi_wr(0xFF) & 0x1F) == 0x05)   /* Receive data resp and wait for end of write process in timeout of 500ms */
            { 
    for(bc = 5000; spi_wr(0xFF) != 0xFF && bc; bc--)
                    DELAY_100u(); /* Wait ready */

    if(bc)
                    res = RES_OK;
   }
   DESELECT();
   spi_wr(0xFF);
  }
 }
 return res;
}
#endif

一樣提供source code 有IAR和KEIL二種IDE
Petit FAT for NCU122

沒有留言: