win32移植FATFS,使用windows API读取磁盘镜像文件

首先使用DiskGenius 建立一个.img格式的磁盘映像文件,我虚拟了一个256MB的SD卡,如下

并格式化为FAT32文件系统,可以使用DiskGenius打开并拷贝数据。

win32移植FATFS,使用windows API读取磁盘镜像文件_第1张图片

使用windows API实现底层虚拟SD卡的读写操作。

 //代码如下

/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2016        */
/*-----------------------------------------------------------------------*/
/* 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.       */
/*-----------------------------------------------------------------------*/
/*************************************************************************************************************
 * 文件名			:	diskio.c
 * 功能				:	文件系统底层接口
 * 作者				:	[email protected]
 * 创建时间			:	2019-10-31
 * 最后修改时间		:	2019-10-31
 * 详细				:	修复了读写接口的1个扇区与多个扇区颠倒问题,并且限制多个扇区读写操作是,一次操作为100个扇区
*************************************************************************************************************/

#include "diskio.h"		/* FatFs lower layer API */
#include "system.h"


#define	SECTOR_SIZE_			512		//扇区大小定义
static HFILE sg_fpImg = NULL;		//文件指针


/* Definitions of physical drive number for each drive */
#define DEV_SD		0	//默认为SD卡
#define DEV_MMC		1	/* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB		2	/* Example: Map USB MSD to physical drive 2 */


/*-----------------------------------------------------------------------*/
/* Get Drive Status     读取状态寄存器                            */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{
	
	switch (pdrv) 
	{
		case DEV_SD :	//SD卡
		{
			if(sg_fpImg != NULL) return RES_OK;			
		}
		default:break;
	}
	
	return STA_NOINIT;
}


/*-----------------------------------------------------------------------*/
/* Inidialize a Drive       初始化                                             */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{
	static bool InitStatus[1];	//记录初始化状态,防止重复初始化
	
	switch (pdrv) 
	{
		case DEV_SD :	//初始化SD卡
		{
			if (sg_fpImg == NULL)	//防止重复打开
			{
				char pPath[MAX_PATH + 1];
				char ImgFilePath[MAX_PATH + 1];
				char ext[32];

				GetModuleFileName(NULL, pPath, MAX_PATH);		//获取当前可执行文件的路径
				_splitpath(pPath, NULL, ImgFilePath, NULL, ext);	//处理路径,去掉后面的程序名称
				strcat(ImgFilePath, "system\\SDCARD.img");
				//sg_fpImg = (HFILE)OpenFile(ImgFilePath, GENERIC_ALL, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); //读写打开文件,允许其他软件只读方式打开
				sg_fpImg = CreateFile(ImgFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);		//打开文件-如不不存在返回失败
				if (sg_fpImg == NULL)
				{
					DEBUG("初始化SD卡错误,SD卡错误:%d\r\n", GetLastError());
					return STA_NOINIT;
				}
                    
			}
			return RES_OK;
		}
		default:break;
	}
	
	return STA_NOINIT;
}


//#include "StopWatch.h"
//STOP_WATCH_HANDLE g_StopWatchHandle1;
/*-----------------------------------------------------------------------*/
/* 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 */
)
{
	u32 cnt;

	switch (pdrv) 
	{
		case DEV_SD :
		{
			if (sg_fpImg == NULL) return RES_ERROR;

            //设置文件偏移
            if (SetFilePointer(sg_fpImg, SECTOR_SIZE_ * sector, NULL, FILE_BEGIN) == HFILE_ERROR)
            {
                DEBUG("移动写文件指针错误:%d\r\n", GetLastError());
                break;
            }
			//Sleep(1);	//模拟延时
			Sleep(4 + count / 20);

            if (ReadFile(sg_fpImg, buff, SECTOR_SIZE_*count, &cnt, NULL) == FALSE)//最后一个参数必须为NULL,否则不会自动移动文件读写指针,SetFilePointer也会无效
            {
                DEBUG("读文件错误:%d\r\n", GetLastError());
                break;
            }

			return RES_OK;
		}
		default:break;
	}

	return RES_PARERR;
}



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

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 */
)
{
    u32 cnt;

	switch (pdrv) 
	{
		case DEV_SD :
		{
            if (sg_fpImg == NULL) return RES_ERROR;

			//设置文件偏移
            if (SetFilePointer(sg_fpImg, SECTOR_SIZE_ * sector, NULL, FILE_BEGIN) == HFILE_ERROR)
            {
                DEBUG("移动写文件指针错误:%d\r\n", GetLastError());
                break;
            }

            Sleep(1);	//模拟延时
            Sleep(1 + count / 20);
            if (WriteFile(buff, buff, SECTOR_SIZE_ * count, &cnt, NULL) == FALSE)	//最后一个参数必须为NULL,否则不会自动移动文件读写指针,SetFilePointer也会无效
            {
                DEBUG("串口发送失败,错误:%d\r\n", GetLastError());
            }

			return RES_OK;
		}
		default:break;
	}

	return RES_PARERR;
}



/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions  杂项功能                                           */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{



	switch (pdrv) 
	{
		case DEV_SD :
		{
			switch(cmd)
			{
				case GET_SECTOR_SIZE:	//获取扇区大小
				{
					*((WORD *)buff) = SECTOR_SIZE_;
					uart_printf("FATFS获取SD卡块大小:%dB\r\n", SECTOR_SIZE_);
				}break;
				default: return RES_PARERR;
			}
			return RES_OK;
		}
		default:break;
	}
	
	return RES_PARERR;
}

 需要注意的是windows API读写文件时,最后一个参数必须为NULL,否则SetFilePointer()函数将无法设置偏移,应为最后一个参数也是用于设置偏移的。

if (WriteFile(buff, buff, SECTOR_SIZE_ * count, &cnt, NULL) == FALSE)	//最后一个参数必须为NULL,否则不会自动移动文件读写指针,SetFilePointer也会无效

这样就可以在PC端虚拟STM32上面的文件系统,使用FATFS了。

win32移植FATFS,使用windows API读取磁盘镜像文件_第2张图片

读取的虚拟SD卡中的字库与编码文件,实现与开发板上同样的操作。 

你可能感兴趣的:(CortexM3(STM32),VC++,.NET)