基于Xilinx平台MicroBlaze的SPI方式FatFs移植
创始人
2024-02-14 07:50:33
0

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博客

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...