野火STM32F103——Fat文件系统及Flash芯片W25Q64学习记录

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

        本文章为个人学习记录,主要内容为在stm32使用FatFs文件系统访问W25Q64


提示:以下是本篇文章正文内容,下面案例可供参考

一、Fatfs是什么?

FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统。它完全是由 ANSI C 语言编写并且完
全独立于底层的 I/O 介质。因此它可以很容易地不加修改地移植到其他的处理器当中。
基于 F103 系列开发板
PIC AVR SH Z80 H8 ARM 等。 FatFs 支持 FAT12 FAT16 FAT32 等格式,所以我们利用
前面写好的 SPI Flash 芯片驱动,把 FatFs 文件系统代码移植到工程之中,就可以利用文件系统的
各种函数,对 SPI Flash 芯片以“文件”格式进行读写操作了。
FatFs 文件系统的源码可以从 fatfs 官网下载 :
http://elm-chan.org/fsw/ff/00index_e.html

二、W25Q64是什么

W25Q64是一直Flash存储设备,使用SPI通讯,具有32768可编程页,每页256字节,用“页编程”每次可编程256个字节,每次写入内容都需要进行擦除工作,可以使用“扇区擦除”、“块擦除”、“整片擦除”擦除,擦除其实是给芯片里的储存单元都置1,因为写入数据时芯片只能把储存单元上的1置为0,不能把0置1........(略)

 

                              8MB=128块(64KB) 1=16扇区(4KB 1扇区=16页(256B

三、使用步骤

1.引入库

先把下载的Fatfs的文件导入工程中:

 

2.移植文件系统

我们重点需要关注的几个文件:

diskio.c:主要用于与底层设备通讯(底层驱动函数(Flash的通信函数)需要自己实现)

ffconf.h:此文件为Fat功能配置的宏定义,可以剪裁Fat的功能. 
/=======================================================================/
媒体接口层
diskio.c代码解析:

此文件有几个宏

可根据你挂载再stm32修改

这里#define SPI_FLASH    就是W25Q64的宏定义

//挂载设备
#define DEV_SD		0
#define SPI_FLASH	1

这里需要根据挂载的设备数量,修改ffconf.h里的FF_VOLUMES宏 ,这里表示设备有2台

/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations存储设备数
/---------------------------------------------------------------------------*/

#define FF_VOLUMES		2
/* Number of volumes (logical drives) to be used. (1-10) */

设备初始化函数(输入参数为挂在设备宏)


/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive *//*输入设备号*/
)
{
	DSTATUS stat;
	
	
	switch (pdrv) 
	{
		case DEV_SD :

			return stat;

		case SPI_FLASH :
				SPI_Flash_Init();					//初始化
				/*唤醒略*/
				
				return disk_status(SPI_FLASH);		/*获取设备状态,初始化成功则返回RES_OK*/
		default:
			break;
	}
	return STA_NOINIT;
}

只需要switch里的选项修改成你的挂载设备,然后在选项里添加响应的函数或代码即可

这里添加为        Flash的GPIO 及SPI初始化函数

/********************************************************
    函数名        :SPI_Flash_Init
    函数功能    :SPI的初始化配置
    函数参数    :
                    
    函数返回    :无
*********************************************************/    
void SPI_Flash_Init(void)

获取设备状态

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


	switch (pdrv) 
		{
			case DEV_SD :
		
						return stat;

			case SPI_FLASH :								
				if(Flash_Read_ID()==Flash_ID)										//如果获取的设备ID是对的
				{
						stat=RES_OK;																//返回一个RES_OK表示成功
						return stat;
				}
				break;
			default:
				break;
	}
	return STA_NOINIT;
}

引用函数:

/********************************************************
    函数名        :Flash_Read_ID
    函数功能    :返回Flash的设备ID
    函数参数    :
                    
    函数返回    :读取从机的数据
*********************************************************/    
uint32_t Flash_Read_ID(void)


读取数据

/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

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 DEV_SD :


		return res;

	case SPI_FLASH :
		Flash_Read_Data(buff,sector*4096,count*4096);		/*1个扇区4K(4096)byte  
											每个扇区地址相隔4096byte所以需要*4096 		*/
		return RES_OK;
	}

	return RES_PARERR;
}

调用函数

/********************************************************
    函数名        :Flash_Read_Data
    函数功能    :读取Flash内部数据
    函数参数    :参数
                        @Read_Buff:用于接收数据的数组
                        @addr:读取哪个位置(地址)的数据                 

                          例:  设备第0个字节地址为0,第1页地址为1*256,第二个扇区地址为2*4096

                                                                                                
                        @Byte_length:读取数据的长度 单位字节

                                读1个扇区需要1*4096
    函数返回    :无
*********************************************************/    
void Flash_Read_Data(uint8_t*Read_Buff,uint32_t addr,uint32_t Byte_length)

写数据函数(需要在ffconf.h把 FF_FS_READONLY设置为0才能使用)

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

#if FF_FS_READONLY == 0			//需要在ffconf.h把 FF_FS_READONLY设置为0才能使用

DRESULT disk_write (
	BYTE pdrv,			/* Physical drive nmuber to identify the drive */
	const BYTE *buff,	/* Data to be written *//*写入Flash的数据*/
	LBA_t sector,		/* Start sector in LBA *//*起始扇区*/
	UINT count			/* Number of sectors to write *//*写扇区的数量*/
)
{
	DRESULT res;
	int result;

	switch (pdrv) {
	case DEV_SD :
		
			return res;

	case SPI_FLASH :
			Flash_Scetor_Erese(sector*4096);//写之前需要擦除扇区4k
			Flash_Write_Buffs((uint8_t*)buff,sector*4096,count*4096);	//向Flash写入数据
			
			return RES_OK;

	}

	return RES_PARERR;
}
#endif

调用函数

/********************************************************
    函数名        :Flash_Scetor_Erese
    函数功能    :扇区擦除(4kbyte)
                        
    函数参数    :addr:擦除的扇区地址 
    函数返回    :无
*********************************************************/    
void Flash_Scetor_Erese(uint32_t addr)


/********************************************************
    函数名        :Flash_Write_Buffs
    函数功能    :自动转页写入
                    

    函数参数    :参数
                        @Write_Buff:用于发送数据的数组
                        @addr:写哪个位置(地址)的数据        
                                    
                        @Byte_length:写数据的长度 
                        
    函数返回    :无
*********************************************************/
void Flash_Write_Buffs(uint8_t*Write_Buff,uint32_t addr,uint32_t Byte_length)

调用disk_ioctl函数以控制设备特定的功能和通用读/写以外的杂项功能

(这玩意好像是告诉我们上层程序一些信息的)

他在diskio.h里定义了一些命令宏

下面为一些标准命令(机翻)

程序

/*-----------------------------------------------------------------------*/
/* 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_SD :

		
			return res;

		case SPI_FLASH :
					switch (cmd)
			{	
				case	GET_SECTOR_COUNT://设备的大小(这里是有多少个扇区)
					*(DWORD*)buff=2048;		//返回类型根据你数据的大小决定好像,详细在ff.h
					break;
				case	GET_SECTOR_SIZE://扇区大小 4096个字节
					*(WORD*)buff=4096;				
					break;
				case	GET_BLOCK_SIZE://擦除块扇区大小	一次擦除一个扇区
					*(WORD*)buff=1;			
					break;
				default:
					break;
			}
	

		// Process of the command for the MMC/SD card

		
	}

	return RES_OK;
}

相关宏设置

 在ffconf.h里把把扇区最大范围FF_MAX_SS 修改成4096

#define FF_MIN_SS		512
#define FF_MAX_SS		4096
/* This set of options configures the range of sector size to be supported. (512,
/  1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/  harddisk, but a larger value may be required for on-board flash memory and some
/  type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/  for variable sector size mode and disk_ioctl() function needs to implement
/  GET_SECTOR_SIZE command. */
/* 这组选项配置要支持的扇区大小范围。 (512,
/ 1024、2048 或 4096) 对于大多数系统、通用存储卡和
/ 硬盘,但板载闪存和一些可能需要更大的值
/ 光学介质类型。 当 FF_MAX_SS 大于 FF_MIN_SS 时,配置 FatFs
/对于可变扇区大小模式和disk_ioctl()函数需要实现
/GET_SECTOR_SIZE 命令。 */

返回时间


DWORD get_fattime (void)
{
	return 0;
	
}

不用直接返回0

使用看官网

媒体接口层好像讲完了。


应用程序接口层

介绍函数

f_mount挂载工作缓冲区

        f_mount 函数有三个形参,第一个参数是 指向 FATFS 变量指针,如果赋值为 NULL 可以取消物理设备挂载。
        第二个参数为逻辑设备编号, 使用设备根路径表示,与物理设备编号挂钩,前面我们定义 SPI Flash 芯片 物理编号为 1 ,所以这里使用“1:”。
        第三个参数可选 0 1 1 表示立即挂载, 0 表示不立即挂
载,延迟挂载。 f_mount 函数会返回一个 FRESULT 类型值,指示运行情况。

FATFS Flash_f;				//需要较大空间所以定义为全局变量,存放在静态区

int main()
{
		
	f_mount(&Flash_f,"1:",1);
}

运行会返回一个 FRESULT 类型值,挂载失败会返回非0的置,

其中返回FR_NO_FILESYSTEM,说明没有 FAT 文件系统,

这时需要我们格式化Flash,往芯片写入文件系统(会清除掉原本芯片上的数据)

初始化媒体设备

f_mkfs

f_mkfs有3个参数

        path:储存设备号   (这里用的是Flash)字符串“x:” x是你宏定义的编号,“1:”

          opt:格式选择     好像0是默认

        work:   指向用于格式化过程的工作缓冲区的指针 

         FF_USE_LFN==3的话会在函数里使用malloc申请空间

len:工作缓冲区大小 *

FF_USE_LFN尽量设置为1申请在静态区否则容易内存溢出

FATFS Flash_f;				//需要较大空间所以定义为全局变量,存放在静态区
FIL WenJian;
BYTE work[FF_MAX_SS];          //工作缓冲区
int main()
{
	
	FRESULT a;																			//保存函数返回状态
	USART1_Config();																//使用串口通信
		
	a=f_mount(&Flash_f,"1:",1);											//挂载设备
	printf("%d\n",a);
	//如果Flash没有写入文件系统,就格式化
	if(a==FR_NO_FILESYSTEM)
	{
		a=f_mkfs("1:",0,work,FF_MAX_SS);												//初始化设备建立文件系统
		printf("f_mkfs=%d\n",a);	
		/*初始化后需要重新挂载*/
		f_mount(NULL,"1:",1);																		//取消挂载
		f_mount(&Flash_f,"1:",1);																//重新挂载
	}


文件简单读写

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include <stdio.h>
#include "bsp_spi.h"
#include	"ff.h"	


FATFS Flash_f;				//需要较大空间所以定义为全局变量,存放在静态区
FIL WenJian;


uint16_t Dt;
uint8_t Buffs[4096]={0};
const uint8_t WrtieBuffs[]={"欢迎使用野火stm32f1开发板"};
void Delay(uint32_t time)
{
		for(;time!=0;time--);
	
}
UINT	bW,bR;
BYTE work[FF_MAX_SS];
int main()
{
	
	FRESULT a;																			//保存函数返回状态
	USART1_Config();																//使用串口通信
		
	a=f_mount(&Flash_f,"1:",1);											//挂载设备
	printf("%d\n",a);
	//如果Flash没有写入文件系统,就格式化
	if(a==FR_NO_FILESYSTEM)
	{
		a=f_mkfs("1:",0,work,FF_MAX_SS);												//初始化设备建立文件系统
		printf("f_mkfs=%d\n",a);	
		/*初始化后需要重新挂载*/
		f_mount(NULL,"1:",1);																		//取消挂载
		f_mount(&Flash_f,"1:",1);																//重新挂载
	}
	
	
	a=f_open(&WenJian,"1:cbd.txt",FA_OPEN_ALWAYS|FA_WRITE|FA_READ);			//打开/创建文件
	printf("f_open=%d\n",a);
	if(a==FR_OK)
	{
		a=f_write (&WenJian,WrtieBuffs,sizeof(WrtieBuffs),&bW);				//写内容		
		printf("f_write=%d bW=%d\n",a,bW);
		
		if(a==FR_OK)
		{
			f_lseek(&WenJian,0);										//设置光标位置
			a=f_read (&WenJian,Buffs,f_size(&WenJian),&bR);											//读取文件内容
				printf("f_read=%d bW=%d\n",a,bR);			
			if(a==FR_OK)
			{
			
				printf("\n内容:%s",Buffs);										//读取成功就打印
			}	
			
		}
		f_close(&WenJian);													//关闭文件
	}
	
	
	while(1)
	{

	}
}


总结

不更了

  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值