基于stm32f407 spi flash 移植 fatfs0.15文件系统

1、fatfs文件系统描述

1.1 fatfs文件结构图

在这里插入图片描述

1.2 fatfs移植方式

首先从这个系统结构图中了解到fatfs是独立于硬件层的,通过ff.c中的相关 api 接口去调用不同硬件驱动底层,只需要用户去根据硬件的不同,实现相关的底层驱动接口即可。

2、 移植准备步骤

2.1 下载fatfs0.15资源包 [下载地址](http://elm-chan.org/fsw/ff/00index_e.html)
2.2 stm32f407ZGT6工程模板(正点原子)
2.3 W25Q128驱动、spi驱动

3、工程源文件添加

3.1 添加工程文件

在这里插入图片描述

3.2 工程文件描述

fatfs源文件:
	diskio.c/.h: IO层的实现。
	ff.c/.h: FatFs核心文件,文件管理的实现方法。该文件独立于底层介质操作文件的函数,利用这些函数实现文件的读写。
	ffconf.h: 这个头文件包含了对FatFs功能配置的宏定义,通过修改这些宏定义就可以裁剪FatFs的功能。
	ffsystem.c: 操作系统相关。
	ffunicode.c: unicode编码相关。FF_USE_LFN != 0 时必须包含此文件。

w25q128驱动文件
	w25qxx.c
	w25qxx.h
	spi.c
	spi.h

4、代码添加

4.1 实现底层驱动接口

	DSTATUS disk_initialize (BYTE pdrv);
	DSTATUS disk_status (BYTE pdrv);
	DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
	DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
	DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);

4.1.1 disk_initialize

此函数在文件系统开始挂载的时候被调用,用于初始化磁盘硬件驱动
	/* Physical drive nmuber to identify the drive */
	DSTATUS disk_initialize (BYTE pdrv)
	{
		uint8_t res=0;
	    switch (pdrv)
	    {
	        case EX_FLASH:
	        {
	            W25QXX_Init();
				FLASH_SECTOR_COUNT = 2048*12;
	            break;
	        }
	        default:
	            res=1; 
		}		 
		if(res)return  STA_NOINIT;
		else return 0; //初始化成功
	}

4.1.2 disk_status

获取当前磁盘的状态
	/* Physical drive nmuber to identify the drive */
	DSTATUS disk_status (BYTE pdrv)
	{
		return 0;
	}

4.1.3 disk_read

在 f_read 被调用的时候,调用 disk_read 到指定的磁盘指定的簇中读取数据
	DRESULT disk_read (
		BYTE pdrv,		/* Physical drive nmuber to identify the drive */
		BYTE *buff,		/* Data buffer to store read data */
		LBA_t sector,	/* Start sector in LBA */
		UINT count		/* Number of sectors to read */
	)
	{
		DRESULT res;
	    switch(pdrv)
	    {
	        case EX_FLASH:
	        {
				for(;count>0;count--)
				{
					W25QXX_Read(buff, sector*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE);
					sector++;
					buff+=FLASH_SECTOR_SIZE;
				}
				res = RES_OK;
	            break;
	        }
			default:
				res = RES_ERROR;         
	    }
		return res;
	}

4.1.4 disk_write

在f_write被调用时,调用disk_write到指定的磁盘指定的簇中写入数据
	DRESULT disk_write (
		BYTE pdrv,			/* Physical drive nmuber to identify the drive */
		const BYTE *buff,	/* Data to be written */
		LBA_t sector,		/* Start sector in LBA */
		UINT count			/* Number of sectors to write */
	)
	{
		DRESULT res = RES_OK;
	    switch(pdrv)
	    {
			case EX_FLASH://外部flash
				for(;count>0;count--)
				{										    
					W25QXX_Write((uint8_t*)buff, sector*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE);
					sector++;
					buff+=FLASH_SECTOR_SIZE;
				}
				res = RES_OK;
				break;
			default:
				res = RES_ERROR; 
	    }
	    return res;	
	}

4.1.5 disk_ioctl

	DRESULT disk_ioctl (
		BYTE pdrv,		/* Physical drive nmuber (0..) */
		BYTE cmd,		/* Control code */
		void *buff		/* Buffer to send/receive control data */
	)
	{
		DRESULT res = RES_OK;
	    if(pdrv==EX_FLASH)	//外部FLASH  
	        {
	            switch(cmd)
	            {
	                case CTRL_SYNC:
	                    res = RES_OK; 
	                    break;	 
	                case GET_SECTOR_SIZE:
	                    *(WORD*)buff = FLASH_SECTOR_SIZE;
	                    res = RES_OK;
	                    break;	 
	                case GET_BLOCK_SIZE:
	                    *(WORD*)buff = FLASH_BLOCK_SIZE;
	                    res = RES_OK;
	                    break;	 
	                case GET_SECTOR_COUNT:
	                    *(DWORD*)buff = FLASH_SECTOR_COUNT;
	                    res = RES_OK;
	                    break;
	                default:
	                    res = RES_PARERR;
	                    break;
	            }
	        }else 
	            res=RES_ERROR;//其他的不支持
	        return res;
	}

4.2 修改配置文件

	//配置fatfs系统有多少个逻辑驱动卷使用
	#define FF_VOLUMES		2		
	/* Number of volumes (logical drives) to be used. (1-10) */

5、调用方式

5.1 相关变量定义

	BYTE readBuffer[1024]={0};        				/* 读缓冲区 */        
	BYTE writeBuffer[] = "I can do all things !";   /* 写缓冲区 */
	FATFS myFs[1];          //逻辑磁盘工作区 
	FIL myFile;	  		    //文件
	UINT br,bw;		        //读写变量
	FRESULT res = FR_OK;

5.2 文件系统挂载

	/* Mount/Unmount a logical drive */
	//FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt);			
	f_mount(&myFs[0],"1:",1);  

5.3 打开、写、关闭

	f_open (&myFile, (const TCHAR*)"1:/yyy.txt", FA_CREATE_ALWAYS | FA_WRITE);
	f_write(&myFile,writeBuffer,sizeof(writeBuffer),&bw);
	f_close(&myFile);

5.4 打开、读、关闭

	f_open (&myFile, (const TCHAR*)"1:/yyy.txt", FA_OPEN_EXISTING | FA_READ);
    f_read(&myFile, readBuffer, sizeof(readBuffer), &br);
    f_close(&myFile);

6、遇到的问题

6.1 文件系统挂载失败

	注意观察逻辑磁盘工作区以及磁盘卷标ID需要与 diskio 中的 pdrv 相对应。

6.2 文件第一次写成功,但直接读取失败

	需要调用 f_close 关闭文件后以不同的模式重新打开文件

6.3 为什么定义 FLASH_SECTOR_SIZE 为512Bytes

	fatfs 中的 sector 与 w25q128 中的 sector 含义不一样
    fatfs 中的 sector 是逻辑上的扇区,规定读写操作的最小基本单元
    w25q128 中的sector是物理意义上的扇区,256个 block ,每个block有16个 sector ,每个 sector 有4K Bytes
    fatfs文件系统规定的每个 sector 大小为 512/1024/2048/4096 字节
    
    并且可以看到 disk_read 是以 sector 大小进行读取数据的
    DRESULT disk_read (
                        BYTE pdrv,		// Physical drive nmuber to identify the drive 
                        BYTE *buff,		//Data buffer to store read data 
                        LBA_t sector,	// Start sector in LBA 
                        UINT count		// Number of sectors to read )
	所以在 disk_read 中调用 W25QXX_Read 函数去读取数据的时候也是按照文件系统规定的扇区大小去读写数据
    W25QXX_Read(buff, sector*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE);
    
    至于下面这几个变量的定义,则是为了满足文件系统的格式需要设定的,但同时满足芯片内存的大小所规定的,当然也可以改成其它形式
    #define FLASH_SECTOR_SIZE 	512			  
    #define FLASH_BLOCK_SIZE   	8     	    
    uint16_t FLASH_SECTOR_COUNT=2048*16;	
    // 2048*16*512 = 16,777,216 = 16M Byte
    
    例如当调用 W25QXX_Read(buff, sector*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE)读取数据时
    传入 sector*FLASH_SECTOR_SIZE 的大小为所操作的 fs 文件中维护的sector所对应物理内存中的地址,
    并且以 FLASH_SECTOR_SIZE 字节大小去读取数据,看下面这几条程序
    void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);
	    --> for(i=0;i<NumByteToRead;i++)
	        	 pBuffer[i]=SPI1_ReadWriteByte(0XFF);   //循环读数 

    当然也会存在当你所需要读取的数据字节大小小于一个 fatfs 中每个 sector 对应的字节大小的情况,
    这时就会直接读取整个 sector(512字节)的数据返回到缓冲区中,
    然后再按照你所需要的数据长度裁剪,再拷到用户空间 fp->buf中。
    f_read()
        --> memcpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt);

7. 源文件分享

Gitee下载工程源文件


有空再写~~

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在STM32F407移植FATFS文件系统,首先需要了解FATFS是一个开源的文件系统,它可以在嵌入式设备上实现存储器的文件读写操作。 在移植FATFS之前,需要准备一些基本的材料,如软件开发环境、相关的文档和资料。可以从FATFS的官方网站下载最新版本的库文件和相关的示例代码。 首先,创建一个新的工程,并在工程中添加所需的库文件和头文件。将fatfs.c和diskio.c两个源文件添加到工程,并在工程设置中包含相关的头文件目录。 接下来,在工程中添加适配底层硬件的代码,在这里是针对STM32F407的。需要编写适配FATFS的底层I/O读写操作的代码,包括初始化SD卡、读取扇区数据和写入扇区数据。 然后,根据具体需求配置FATFS的参数。可以在fatfs_conf.h文件中修改相关的参数,如簇大小、扇区大小和最大文件数等。这些参数根据实际应用需求进行调整。 最后,编写应用程序代码。可以利用FATFS提供的API来实现文件的打开、读取和写入等操作。需要注意的是在使用FATFS API之前,需要先调用f_mount函数挂载文件系统。 完成以上步骤后,就可以进行编译和烧录操作,将程序下载到STM32F407上进行测试。可以通过读取和写入文件来验证FATFS的正常工作。 总结来说,STM32F407移植FATFS文件系统需要准备相关的材料,包括库文件和文档。然后添加相关的源文件和头文件到工程中,并编写适配底层硬件的代码。之后根据需求配置FATFS参数,并编写应用程序代码。最后进行编译和烧录操作,进行测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值