FatFs是面向小型嵌入式系统的一种通用的FAT文件系统。它完全是由AISI C语言编写并且完全独立于底层的I/O介质。因此它可以很容易地不加修改地移植到其他的处理器当中,如8051、PIC、AVR、SH、Z80、H8、ARM等。FatFs支持FAT12、FAT16、FAT32等格式。
FatFs源码下载FatFs - Generic FAT Filesystem Module
下载下来后,目录结构由帮助文档(doc)和文件系统源码(src)构成:
打开源码我们会看到如下几个文件:
integer.h:文件中包含了一些数值类型定义。
diskio.c:包含底层存储介质的操作函数,这些函数需要用户自己实现,主要添加底层驱动函数。
ff.c:FatFs核心文件,文件管理的实现方法。该文件独立于底层介质操作文件的函数,利用这些函数实现文件的读写。(相当于C语言中的stdio.h)
cc936.c:本文在option目录下,是简体中文支持所需要添加的文件,包含了简体志文的GBK和Unicode相互转换功能函数。
ffconf.h:这个头文件包含了对FatFs功能配置的宏定义,通过修改这些宏定义就可以裁剪FatFs的功能。如需要支持简体中文,需要把ffconf.h中的_CODE_PAGE的宏改成936并把上面的cc936.c文件加入到工程之中。
在Xilinx平台MicroBlaze没有SD卡,所以我们只能以SPI的方式来进行移植。
移植步骤如下:
1.diskio.c中需要修改如下几个函数
1.
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv) {
case DEV_SPI :
result = spi_flash_status();
stat = RES_OK;
return stat;
case DEV_MMC :
return stat;
case DEV_USB :
return stat;
}
return STA_NOINIT;
}
2.
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv) {
case DEV_SPI :
result = spi_flash_init((u32)pdrv);
stat = RES_OK;
return stat;
case DEV_MMC :
return stat;
case DEV_USB :
return stat;
}
return STA_NOINIT;
}
3.
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res;
int result;
switch (pdrv) {
case DEV_SPI :
sector+=1536;
result = spi_flash_read(sector*4096,count*4096,(u8*)buff);
res = RES_OK;
return res;
case DEV_MMC :
return res;
case DEV_USB :
return res;
}
return RES_PARERR;
}
4.
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res;
int result;
switch (pdrv) {
case DEV_SPI :
sector += 1536;
spi_flash_sector_erase(sector*4096);
result = spi_flash_write(sector*4096,count*4096,(u8*)buff);
res = RES_OK;
return res;
case DEV_MMC :
return res;
case DEV_USB :
return res;
}
return RES_PARERR;
}
5.
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
int result;
switch (pdrv) {
case DEV_SPI:
switch(cmd)
{
case GET_SECTOR_COUNT:
*(DWORD *) buff = 512;
break;
case GET_SECTOR_SIZE:
*(DWORD *) buff = 4096;
break;
case GET_BLOCK_SIZE:
*(DWORD *) buff = 1;
break;
}
res = RES_OK;
return res;
case DEV_RAM :
return res;
case DEV_MMC :
return res;
case DEV_USB :
return res;
}
return RES_PARERR;
}
6.
DWORD get_fattime(void)
{
return ((DWORD)(2022 - 1980) << 25) //YEAR
| ((DWORD)12 << 21) //MONTH
| ((DWORD)20 << 16) //DAY
| ((DWORD)7 << 11) //HOUR
| ((DWORD)20 << 5) //MINUTE
| ((DWORD)30 << 1); //SECOND
}
完整代码如下:
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include "spi_flash.h"/* Definitions of physical drive number for each drive */
#define DEV_SPI 0 /* Example: Map Ramdisk to physical drive 0 */
#define DEV_RAM 1 /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_MMC 2 /* Example: Map USB MSD to physical drive 2 */
#define DEV_USB 3 /* Example: Map USB MSD to physical drive 2 *//*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/DSTATUS disk_status (BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{DSTATUS stat;int result;switch (pdrv) {case DEV_SPI ://result = RAM_disk_status();result = spi_flash_status();// translate the reslut code herestat = RES_OK;return stat;case DEV_MMC ://result = MMC_disk_status();// translate the reslut code herereturn stat;case DEV_USB ://result = USB_disk_status();// translate the reslut code herereturn stat;}return STA_NOINIT;
}/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/DSTATUS disk_initialize (BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{DSTATUS stat;int result;switch (pdrv) {case DEV_SPI :result = spi_flash_init((u32)pdrv);// translate the reslut code herestat = RES_OK;return stat;case DEV_MMC ://result = MMC_disk_initialize();// translate the reslut code herereturn stat;case DEV_USB ://result = USB_disk_initialize();// translate the reslut code herereturn stat;}return STA_NOINIT;
}/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/DRESULT disk_read (BYTE pdrv, /* Physical drive nmuber to identify the drive */BYTE *buff, /* Data buffer to store read data */DWORD sector, /* Start sector in LBA */UINT count /* Number of sectors to read */
)
{DRESULT res;int result;switch (pdrv) {case DEV_SPI :// translate the arguments heresector+=1536;result = spi_flash_read(sector*4096,count*4096,(u8*)buff);//result = RAM_disk_read(buff, sector, count);// translate the reslut code hereres = RES_OK;return res;case DEV_MMC :// translate the arguments here//result = MMC_disk_read(buff, sector, count);// translate the reslut code herereturn res;case DEV_USB :// translate the arguments here//result = USB_disk_read(buff, sector, count);// translate the reslut code herereturn res;}return RES_PARERR;
}/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/#if FF_FS_READONLY == 0DRESULT disk_write (BYTE pdrv, /* Physical drive nmuber to identify the drive */const BYTE *buff, /* Data to be written */DWORD sector, /* Start sector in LBA */UINT count /* Number of sectors to write */
)
{DRESULT res;int result;switch (pdrv) {case DEV_SPI :// translate the arguments heresector += 1536;spi_flash_sector_erase(sector*4096);result = spi_flash_write(sector*4096,count*4096,(u8*)buff);// translate the reslut code hereres = RES_OK;return res;case DEV_MMC :// translate the arguments here//result = MMC_disk_write(buff, sector, count);// translate the reslut code herereturn res;case DEV_USB :// translate the arguments here//result = USB_disk_write(buff, sector, count);// translate the reslut code herereturn res;}return RES_PARERR;
}#endif/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/DRESULT disk_ioctl (BYTE pdrv, /* Physical drive nmuber (0..) */BYTE cmd, /* Control code */void *buff /* Buffer to send/receive control data */
)
{DRESULT res;int result;switch (pdrv) {case DEV_SPI:switch(cmd){case GET_SECTOR_COUNT:*(DWORD *) buff = 512;break;case GET_SECTOR_SIZE:*(DWORD *) buff = 4096;break;case GET_BLOCK_SIZE:*(DWORD *) buff = 1;break;}res = RES_OK;return res;case DEV_RAM :// Process of the command for the RAM drivereturn res;case DEV_MMC :// Process of the command for the MMC/SD cardreturn res;case DEV_USB :// Process of the command the USB drivereturn res;}return RES_PARERR;
}DWORD get_fattime(void)
{return ((DWORD)(2022 - 1980) << 25) //YEAR| ((DWORD)12 << 21) //MONTH| ((DWORD)20 << 16) //DAY| ((DWORD)7 << 11) //HOUR| ((DWORD)20 << 5) //MINUTE| ((DWORD)30 << 1); //SECOND
}
#include "spi_flash.h"代码
#ifndef __SPI_FLASH_H_
#define __SPI_FLASH_H_#include "xparameters.h"
#include "xspi.h"
#include "xil_exception.h"#define SPI_DEVICE_ID XPAR_QSPI_FLASH_DEVICE_ID
#define SPI_SELECT 0x01
#define SPI_WRITE 0x02
#define SPI_READ 0x03
#define SPI_RDSR1 0x05
#define SPI_WREN 0x06
#define SPI_SE 0xD8
#define SPI_RDID 0x9F#define READ_WRITE_EXTRA_BYTES 4
#define RDSR1_BYTES 2
#define WREN_BYTES 1
#define SE_BYTES 4
#define FLASH_SR_IS_READY_MASK 0x01
#define PAGE_SIZE 256#define SPI_DATA_REG 0
#define SPI_CTRL_REG 1
#define SPI_STS_REG 2#define SPI_CTRL_RXRST 0x01
#define SPI_CTRL_TXRST 0x02#define SPI_STS_RDV 0x01
#define SPI_STS_WRV 0x02
#define SPI_STS_WRB 0x04#define STAT_OK 0x0A
#define STAT_ERR 0x11
#define CMD_SET_FPWM 0x01
#define CMD_SET_SPWM 0x02
#define CMD_SET_SCDAC 0x03
#define CMD_SET_SVDAC 0x04
#define CMD_RD_V_DCDC 0x05
#define CMD_RD_V_OUT 0x06
#define CMD_RD_I_OUT 0x07
#define CMD_RD_I_SEN 0x08
#define CMD_RD_SW 0x09#define SPI_DRV_CS 0x100
#define SPI_DRV_RD 0x200
#define SPI_FLASH_SS 0x400
#define SPI_IO_SS 0x800int spi_flash_init(u32 dev_id);
int spi_flash_read(u32 addr, u32 count, u8* buf);
int spi_flash_read_l(u32 Addr, u32 ByteCount);
int spi_flash_wait(void);
void spi_flash_sector_erase(u8 sector);
void spi_flash_set_write_enable(void);
int spi_flash_write(u32 spi_addr, u32 count, u8* buf);
int spi_flash_get_id(void);#endif
spi_flash.c代码:
#include "spi_flash.h"
#include "xspi_l.h"static XSpi Spi;
static u8 ReadBuffer[PAGE_SIZE + READ_WRITE_EXTRA_BYTES + 4];
static u8 WriteBuffer[PAGE_SIZE + READ_WRITE_EXTRA_BYTES];int spi_flash_init(u32 dev_id){int Status;XSpi_Config *ConfigPtr;ConfigPtr = XSpi_LookupConfig(dev_id);if (ConfigPtr == NULL)return XST_DEVICE_NOT_FOUND;Status = XSpi_CfgInitialize(&Spi, ConfigPtr, ConfigPtr->BaseAddress);if (Status != XST_SUCCESS)return XST_FAILURE;Status = XSpi_SetOptions(&Spi, XSP_MASTER_OPTION |XSP_MANUAL_SSELECT_OPTION);if(Status != XST_SUCCESS)return XST_FAILURE;Status = XSpi_SetSlaveSelect(&Spi, SPI_SELECT);if(Status != XST_SUCCESS)return XST_FAILURE;XSpi_Start(&Spi);XSpi_IntrGlobalDisable(&Spi); // Pooled modereturn XST_SUCCESS;
}
/******************************************************************************** Read data from SPI Flash* @param u32 Address* @param u32 Count* @param u8* Buffer* @return Operation Status******************************************************************************/
int spi_flash_read(u32 spi_addr, u32 count, u8* buf){u32 i, block_size, page_rem, buf_rem;u32 buf_addr = 0;while(buf_addr < count){page_rem = 0x0100 - (spi_addr & 0x00ff);buf_rem = count - buf_addr;block_size = (buf_rem > page_rem) ? page_rem : buf_rem;if(spi_flash_read_l(spi_addr, block_size) != XST_SUCCESS)return XST_FAILURE;for(i = 0; i < block_size; i++)buf[buf_addr + i] = ReadBuffer[i + READ_WRITE_EXTRA_BYTES];spi_addr += block_size;buf_addr += block_size;}return XST_SUCCESS;
}int spi_flash_read_l(u32 Addr, u32 ByteCount){int Status;Status = spi_flash_wait();if(Status != XST_SUCCESS)return XST_FAILURE;WriteBuffer[0] = SPI_READ;WriteBuffer[1] = (u8) (Addr >> 16);WriteBuffer[2] = (u8) (Addr >> 8);WriteBuffer[3] = (u8) Addr;return XSpi_Transfer(&Spi, WriteBuffer, ReadBuffer,(ByteCount + READ_WRITE_EXTRA_BYTES));
}
/******************************************************************************** Read flash status register* @param Spi Driver Instance* @return Status register contents******************************************************************************/
int spi_flash_status(void){WriteBuffer[0] = SPI_RDSR1;return XSpi_Transfer(&Spi, WriteBuffer, ReadBuffer, RDSR1_BYTES);
}int spi_flash_wait(void){while(1) {if(spi_flash_status() != XST_SUCCESS)return XST_FAILURE;if((ReadBuffer[1] & FLASH_SR_IS_READY_MASK) == 0)break;}return XST_SUCCESS;
}void spi_flash_set_write_enable(void){WriteBuffer[0] = SPI_WREN;XSpi_Transfer(&Spi, WriteBuffer, NULL, WREN_BYTES);
}void spi_flash_sector_erase(u8 sector){spi_flash_set_write_enable();WriteBuffer[0] = SPI_SE;WriteBuffer[1] = sector;WriteBuffer[2] = 0;WriteBuffer[3] = 0;XSpi_Transfer(&Spi, WriteBuffer, ReadBuffer, SE_BYTES);spi_flash_wait();}int spi_flash_write_buf(u32 spi_addr, u32 count, u8* buf){int i;spi_flash_wait();spi_flash_set_write_enable();WriteBuffer[0] = SPI_WRITE;WriteBuffer[1] = (spi_addr >> 16) & 0xFF;WriteBuffer[2] = (spi_addr >> 8) & 0xFF;WriteBuffer[3] = spi_addr & 0xFF;for(i = 0; i < count; i++){WriteBuffer[4 + i] = buf[i];}XSpi_Transfer(&Spi, WriteBuffer, NULL, (count + READ_WRITE_EXTRA_BYTES));return XST_SUCCESS;
}int spi_flash_write(u32 spi_addr, u32 count, u8* buf){u32 cnt = count;u32 pointer = 0;u32 page_rem, block_size;u32 cur_addr = spi_addr;while(cnt){if((cur_addr & 0xFFFF) == 0x0000){spi_flash_sector_erase(cur_addr >> 16);}page_rem = PAGE_SIZE - (cur_addr & 0xFF);block_size = (cnt > page_rem) ? page_rem : cnt;spi_flash_write_buf((cur_addr+pointer), block_size, (buf+pointer));pointer += block_size;cnt -= block_size;}return XST_SUCCESS;
}int spi_flash_get_id(void){u32 id;WriteBuffer[0] = SPI_RDID;XSpi_Transfer(&Spi, WriteBuffer, ReadBuffer, 4);id = (ReadBuffer[1] << 16) | (ReadBuffer[2] << 8) | ReadBuffer[3];return id;
}
2.修改ffconf.h
#define FF_MAX_SS 4096
3.测试FatFs
#include "xparameters.h" /* SDK generated parameters */
#include "FatFs/spi_flash.h"
#include "xil_printf.h"
#include "FatFs/ff.h"
#include "xil_cache.h"
#include "xplatform_info.h"/************************** Constant Definitions *****************************//**************************** Type Definitions *******************************//***************** Macros (Inline Functions) Definitions *********************//************************** Function Prototypes ******************************/
int FfsSdPolledExample(void);/************************** Variable Definitions *****************************/
static FIL fil; /* File object */
static FATFS fatfs;
/** To test logical drive 0, FileName should be "0:/" or* "". For logical drive 1, FileName should be "1:/"*/
static char FileName[32] = "Test.bin";
static char *SD_File;#ifdef __ICCARM__
#pragma data_alignment = 32
u8 DestinationAddress[10*1024];
#pragma data_alignment = 32
u8 SourceAddress[10*1024];
#else
u8 DestinationAddress[10*1024] __attribute__ ((aligned(32)));
u8 SourceAddress[10*1024] __attribute__ ((aligned(32)));
#endif#define TEST 7/*****************************************************************************/
/**
*
* Main function to call the SD example.
*
* @param None
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None
*
******************************************************************************/
int main(void)
{int Status;xil_printf("SD Polled File System Example Test \r\n");Status = FfsSdPolledExample();if (Status != XST_SUCCESS) {xil_printf("SD Polled File System Example Test failed \r\n");return XST_FAILURE;}xil_printf("Successfully ran SD Polled File System Example Test \r\n");return XST_SUCCESS;}/*****************************************************************************/
/**
*
* File system example using SD driver to write to and read from an SD card
* in polled mode. This example creates a new file on an
* SD card (which is previously formatted with FATFS), write data to the file
* and reads the same data back to verify.
*
* @param None
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None
*
******************************************************************************/
int FfsSdPolledExample(void)
{FRESULT Res;UINT NumBytesRead;UINT NumBytesWritten;u32 BuffCnt;BYTE work[FF_MAX_SS];u32 FileSize = (8*1024);/** To test logical drive 0, Path should be "0:/"* For logical drive 1, Path should be "1:/"*/TCHAR *Path = "0:/";for(BuffCnt = 0; BuffCnt < FileSize; BuffCnt++){SourceAddress[BuffCnt] = TEST + BuffCnt;}/** Register volume work area, initialize device*/Res = f_mount(&fatfs, Path, 0);if (Res != FR_OK) {return XST_FAILURE;}/** Path - Path to logical driver, 0 - FDISK format.* 0 - Cluster size is automatically determined based on Vol size.*/Res = f_mkfs(Path, FM_FAT, 0, work, sizeof work);if (Res != FR_OK) {return XST_FAILURE;}/** Open file with required permissions.* Here - Creating new file with read/write permissions. .* To open file with write permissions, file system should not* be in Read Only mode.*/SD_File = (char *)FileName;Res = f_open(&fil, SD_File, FA_CREATE_ALWAYS | FA_WRITE | FA_READ);if (Res) {return XST_FAILURE;}/** Pointer to beginning of file .*/Res = f_lseek(&fil, 0);if (Res) {return XST_FAILURE;}/** Write data to file.*/Res = f_write(&fil, (const void*)SourceAddress, FileSize,&NumBytesWritten);if (Res) {return XST_FAILURE;}/** Pointer to beginning of file .*/Res = f_lseek(&fil, 0);if (Res) {return XST_FAILURE;}/** Read data from file.*/Res = f_read(&fil, (void*)DestinationAddress, FileSize,&NumBytesRead);if (Res) {return XST_FAILURE;}/** Data verification
// */
// for(BuffCnt = 0; BuffCnt < FileSize; BuffCnt++){
// if(SourceAddress[BuffCnt] != DestinationAddress[BuffCnt]){
// return XST_FAILURE;
// }
// }/** Close file.*/Res = f_close(&fil);if (Res) {return XST_FAILURE;}return XST_SUCCESS;
}
测试完成。
具体每个函数的参数和功能介绍参考:STM32F429入门(二十二):SPI-FatFs文件系统_郑烯烃快去学习的博客-CSDN博客