stm32专题十九:FatFs文件系统简单读写

首先,我们需要向FatFs来提供一些硬件接口,包括储存设备的初始化,读 / 写函数,硬件参数等,这些在diskio.c中实现:

diskio.c

​
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2014        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

#include "diskio.h"		/* FatFs lower layer API */
#include "./flash/bsp_spi_flash.h"
//#include "usbdisk.h"	/* Example: Header file of existing USB MSD control module */
//#include "atadrive.h"	/* Example: Header file of existing ATA harddisk control module */
//#include "sdcard.h"		/* Example: Header file of existing MMC/SDC contorl module */

/* Definitions of physical drive number for each drive */
#define ATA		0	/* Example: Map ATA harddisk to physical drive 0 */
#define MMC		1	/* Example: Map MMC/SD card to physical drive 1 */
#define USB		2	/* Example: Map USB MSD to physical drive 2 */

#define SD_CARD			0
#define SPI_FLASH		1

/*-----------------------------------------------------------------------*/
/* Get Drive Status    读取驱动状态                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
	DSTATUS stat;
//	int result;

	switch (pdrv) {
	case SD_CARD :
//		result = ATA_disk_status();

		// translate the reslut code here

		return stat;

	case SPI_FLASH :
		
		
		if (SPI_FLASH_ReadID() == sFLASH_ID)
		{
			// 状态正常
			stat = 0;
		}
		else
		{
			// 状态异常
			stat = STA_NOINIT;
		}

		// translate the reslut code here

		return 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 SD_CARD :
//		result = ATA_disk_initialize();

		// translate the reslut code here

		return stat;

	case SPI_FLASH :
		
		SPI_FLASH_Init();		// 这里只是初始化引脚和硬件SPI
		SPI_Flash_WAKEUP();	// 确保FLASH不处在低功耗状态
	
		return disk_status(SPI_FLASH);

	}
	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,	/* Sector address in LBA */
	UINT count		/* Number of sectors to read */
)
{
	DRESULT res;
//	int result;

	switch (pdrv) {
	case SD_CARD :
		// translate the arguments here

//		result = ATA_disk_read(buff, sector, count);

		// translate the reslut code here

		return res;

	case SPI_FLASH :
		
		// 输入的是扇区号,这里要转换成地址
		// W25Q64的每个扇区为4KB = 4096 字节
		SPI_FLASH_BufferRead(buff, sector * 4096, count * 4096);
	
		res = RES_OK;		// 默认就认为读取正常

		return res;

	}

	return RES_PARERR;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if _USE_WRITE
DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written */
	DWORD sector,		/* Sector address in LBA */
	UINT count			/* Number of sectors to write */
)
{
	DRESULT res;
//	int result;

	switch (pdrv) {
	case SD_CARD :
		// translate the arguments here

//		result = ATA_disk_write(buff, sector, count);

		// translate the reslut code here

		return res;

	case SPI_FLASH :
		// 一定要先擦除再写入
		SPI_FLASH_SectorErase(sector * 4096);	
		SPI_FLASH_BufferWrite((u8 *)buff, sector * 4096, count * 4096);

		res = RES_OK;	
	
		return res;
	}

	return RES_PARERR;
}
#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/
/* 杂项功能函数,用于传递存储器硬件相关的参数,以便于格式化文件系统 ------------*/

#if _USE_IOCTL
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 SD_CARD :

		// Process of the command for the ATA drive

		return res;

	case SPI_FLASH :

		switch (cmd)
		{
			/* 
			case CTRL_SYNC:		
				// 用于实现缓存,把要写入的文件,先保存在内存(缓存)中,然后再一次性写入到存储介质
			break;
			*/
			// 返回扇区个数
			case GET_SECTOR_COUNT:
				// buff是一个void*空指针,我们根据命令格式,要转换成 DWORD* 类型的指针
				*(DWORD *)buff = 2048;				
			break;
			// 返回扇区大小
			case GET_SECTOR_SIZE:
				*(WORD *)buff = 4096;	
			break;
			// 返回擦除扇区的最小个数
			case GET_BLOCK_SIZE:
				*(DWORD *)buff = 1;	
			break;	
		}
			
		res = RES_OK;	
		return res;
	}

	return RES_PARERR;
}
#endif

// 返回时间
DWORD get_fattime (void)
{
	return 0;
}

​

其中包括了读取设备状态(通过读取SPI设备号来实现),存储设备初始化(stm32引脚配置和硬件SPI),读写操作(调用SPI读写函数),以及传递硬件参数的杂项函数。

然后,要在ffconf.h中进行一些配置(说明:这个主要用于裁剪,通过配置宏定义,可以实现 / 屏蔽相应功能):

// 格式化文件系统
#define	_USE_MKFS		1
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */

// 配置扇区的大小(有多少个字节),特别值得注意的是,两个值不要相等
#define	_MIN_SS		512
#define	_MAX_SS		4096

接下来就是在主函数中进行测试:

#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./flash/bsp_spi_flash.h"
#include "ff.h"

FATFS fsObject;
FIL fp;
UINT bw;
UINT br;

const char wData[] = "FatFs文件系统测试成功!";
char rData[4096] = "";

/*
 * 函数名:main
 * 描述  :主函数
 * 输入  :无
 * 输出  :无
 */
int main(void)
{ 	
	FRESULT res;
	
	LED_GPIO_Config();
	LED_BLUE;
	
	/* 配置串口为:115200 8-N-1 */
	USART_Config();
	printf("\r\n 这是一个8Mbyte串行flash(W25Q64)实验 \r\n");
	
	/* 挂载文件系统,就是初始化硬件GPIO接口和SPI,使能
	   第一个参数为文件系统句柄,第二个参数为路径,第三个参数1表示立即挂载 */
	res = f_mount(&fsObject, "1:", 1);	
	printf("\tf_mount res = %d\n", res);
	
	// 只有当存储介质不存在文件系统时,才进行格式化
	if (res == FR_NO_FILESYSTEM)
	{
		res = f_mkfs("1:", 0, 0);		// 格式化存储介质
		printf("\tf_mkfs res = %d\n", res);
		// 格式化后要取消挂载,然后再重新挂载文件系统
		res = f_mount(NULL, "1:", 1);	
		res = f_mount(&fsObject, "1:", 1);	
		
		printf("\tsecond f_mount res = %d\n", res);
	}
	
	/* 开始测试 */
	
	// 以可读可写权限打开一个文件
	res = f_open(&fp, "1:abcd.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
	printf("\tf_open res = %d\n", res);
	
	// 如果打开文件成功,就可以写入数据
	if (res == FR_OK)
	{
		res = f_write(&fp, wData, sizeof(wData), &bw);
		printf("\tbw = %d\n", bw);
		
		if (res == FR_OK)
		{
			f_lseek(&fp, 0);		// 把文件的光标移到最开头处
			res = f_read(&fp, rData, f_size(&fp), &br);
			if (res == FR_OK)
			{
				printf("\t文件内容: %s, br = %d\n", rData, br);
			}
		}
		f_close(&fp);					// 关闭文件
	}
	
	while(1);  
}

串口打印结果如下:

stm32专题十九:FatFs文件系统简单读写_第1张图片

 

你可能感兴趣的:(stm32专栏)