基于HC32F460petb芯片给FLASH安装fat文件系统

FAT(File Allocation Table)文件系统是一种用于磁盘驱动器、USB闪存驱动器、软盘等存储设备的文件系统。FAT文件系统主要有两种变体:FAT12和FAT16,它们后来被FAT32所取代。FAT32文件系统是对FAT16的扩展,支持更大的文件和磁盘分区。

FAT文件系统的核心是其文件分配表(FAT),这是一个表格,它记录了磁盘上每个簇的使用情况。簇是磁盘上的一组连续扇区,用于存储文件数据。在FAT文件系统中,每个文件和目录都占用一个或多个簇,并且FAT表记录了这些簇的使用情况。

以下是FAT文件系统的一些关键特点:

  1. **簇分配**:FAT文件系统通过簇来管理文件数据。文件和目录信息存储在簇中,并且FAT表记录了哪些簇被文件和目录占用。

  2. **文件分配表(FAT)**:FAT是一个表,它列出了每个簇的使用情况。FAT表中有两种类型的簇:空簇(未使用的簇)和已分配簇(被文件或目录占用的簇)。

  3. **根目录**:FAT文件系统中的每个磁盘分区都有一个根目录,其中包含文件和目录的目录项。每个目录项都包含文件或目录的名称、大小、起始簇号等信息。

  4. **文件大小限制**:FAT文件系统的文件大小受限于簇的大小。例如,FAT12和FAT16支持的最大文件大小为2GB,而FAT32支持的最大文件大小为2TB。

  5. **兼容性**:FAT文件系统与不同的操作系统兼容,包括Windows、Linux和macOS。这使得FAT文件系统成为跨平台文件共享的理想选择。

  6. **简单性**:FAT文件系统相对简单,易于实现和维护。这使得它成为许多嵌入式系统、旧计算机和便携式存储设备的首选文件系统。

  7. **性能**:FAT文件系统具有较好的性能,因为它不需要复杂的索引结构来访问文件。文件数据直接存储在磁盘上的簇中,这使得文件访问速度较快。

FAT文件系统在历史上非常流行,但随着技术的发展,更高级的文件系统如NTFS(用于Windows)、EXT4(用于Linux)和APFS(用于macOS)等逐渐取代了FAT文件系统。然而,由于其简单性和广泛的兼容性,FAT文件系统仍然在一些旧设备和特殊应用中得到使用。

目前单片机中用的最多的文件系统就是fat32,得益于正点原子和野火的大量资料,让我们很快的就能开发出来相关的功能,本篇用来记录一次fat32的移植过程,芯片采用的是华大的PETB,flash才采用的是GD25Q40,虽然是GD系列的存储芯片,但是命令上基本兼容W25Q系列。

fat32源码的下载,可以从github下载:strawberryhacker/fat32: Tiny FAT32 file system implementation. (github.com)

也可以从官网下载,(不知道为什么我在家的电脑打不开fat官网,有遇到类似情况的小伙伴告诉我解决方案!

可以配置ffconf.h的修改,可以参考其他博文。

这里只看diskio的移植:

cpp 复制代码
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* 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 "ff.h"			/* Obtains integer types */
#include "diskio.h"		/* Declarations of disk functions */

#include "ev_hc32f460_lqfp100_v2_w25qxx.h"
/* Definitions of physical drive number for each drive */
#define DEV_RAM		0	/* Example: Map Ramdisk to physical drive 0 */
#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 */

// jinyuhang 本篇移植,只考虑了外部falsh,后续考虑SD卡
/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

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

	// switch (pdrv) {
	// case DEV_RAM :
	// 	result = RAM_disk_status();

	// 	// translate the reslut code here

	// 	return stat;

	// case DEV_MMC :
	// 	result = MMC_disk_status();

	// 	// translate the reslut code here

	// 	return stat;

	// case DEV_USB :
	// 	result = USB_disk_status();

	// 	// 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 DEV_RAM :
	// 	result = RAM_disk_initialize();

	// 	// translate the reslut code here

	// 	return stat;

	// case DEV_MMC :
	// 	result = MMC_disk_initialize();

	// 	// translate the reslut code here

	// 	return stat;

	// case DEV_USB :
	// 	result = USB_disk_initialize();

	// 	// translate the reslut code here

	// 	return stat;
	// }
	// return STA_NOINIT;
	DSTATUS stat=RES_OK;
		BSP_W25QXX_Init();
	return stat;
}



/*-----------------------------------------------------------------------*/
/* 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;
//	int result;

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

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

	// 	// translate the reslut code here

	// 	return res;

	// case DEV_MMC :
	// 	// translate the arguments here

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

	// 	// translate the reslut code here

	// 	return res;

	// case DEV_USB :
	// 	// translate the arguments here

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

	// 	// translate the reslut code here

	// 	return res;
	// }

//	return RES_PARERR;
	BSP_W25QXX_Read(sector * 512U, buff, (uint32_t)count * 512U);
	return RES_OK;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/
static void W25QXX_Write_NoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t pageremain;
    pageremain = (uint16_t)(256U - WriteAddr % 256U);
    if (NumByteToWrite <= pageremain) {
        pageremain = NumByteToWrite;
    }
    for (;;) {
        (void)BSP_W25QXX_Write(WriteAddr, pBuffer, pageremain);
        if (NumByteToWrite == pageremain) {
            break;
        } else { //NumByteToWrite>pageremain
            pBuffer += pageremain;
            WriteAddr += pageremain;

            NumByteToWrite -= pageremain;
            if (NumByteToWrite > 256U) {
                pageremain = 256U;
            } else {
                pageremain = NumByteToWrite;
            }
        }
    }
}
static uint8_t u8CopybackBuf[W25Q64_SECTOR_SIZE];

static void SpiFlashWrite(uint8_t *pbuf, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;
    uint8_t *pu8CbBuf;
    pu8CbBuf = u8CopybackBuf;
    secpos = WriteAddr / W25Q64_SECTOR_SIZE;
    secoff = (uint16_t)(WriteAddr % W25Q64_SECTOR_SIZE);
    secremain = (uint16_t)(W25Q64_SECTOR_SIZE - secoff);
    if (NumByteToWrite <= secremain) {
        /* less than 4K */
        secremain = NumByteToWrite;
    }
    for (;;) {
        (void)BSP_W25QXX_Read(secpos * W25Q64_SECTOR_SIZE, pu8CbBuf, W25Q64_SECTOR_SIZE);
        /* check if blank sector */
        for (i = 0U; i < secremain; i++) {
            if (pu8CbBuf[secoff + i] != 0XFFU) {
                break;
            }
        }
        if (i < secremain) {
            /* not blank, need erase */
            (void)BSP_W25QXX_EraseSector(secpos * W25Q64_SECTOR_SIZE);
            /* backup first */
            for (i = 0U; i < secremain; i++) {
                pu8CbBuf[i + secoff] = pbuf[i];
            }
            /* write back after erase */
            W25QXX_Write_NoCheck(pu8CbBuf, secpos * W25Q64_SECTOR_SIZE, (uint16_t)W25Q64_SECTOR_SIZE);

        } else {
            W25QXX_Write_NoCheck(pbuf, WriteAddr, secremain);
        }
        if (NumByteToWrite == secremain) {
            break;
        } else {
            /* next sector */
            secpos++;
            secoff = 0U;

            pbuf += secremain;
            WriteAddr += secremain;
            NumByteToWrite -= secremain;
            if (NumByteToWrite > W25Q64_SECTOR_SIZE) {
                secremain = (uint16_t)W25Q64_SECTOR_SIZE;
            } else {
                secremain = NumByteToWrite;
            }
        }
    }
}

#if FF_FS_READONLY == 0

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;
//	int result;

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

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

//	// 	// translate the reslut code here

//	// 	return res;

//	// case DEV_MMC :
//	// 	// translate the arguments here

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

//	// 	// translate the reslut code here

//	// 	return res;

//	// case DEV_USB :
//	// 	// translate the arguments here

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

//	// 	// translate the reslut code here

//	// 	return res;
//	// }

//	return RES_PARERR;

	SpiFlashWrite(( BYTE *)buff, sector * 512U,  (uint32_t)count * 512U);
	return RES_OK;
}

#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_RAM :

		// Process of the command for the RAM drive

		return res;

	case DEV_MMC :

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

		return res;

	case DEV_USB :

		// Process of the command the USB drive

		return res;
	}

	return RES_PARERR;
}

//
DWORD get_fattime (void)
{
	return 0;
}

主要实现初始化,读和写的函数就可以了,如果大家看了关于USB的例程的话,就会发现这里的读写函数就是USB-msc例程中的读写函数,完全可以使用。也得到了一个经验:USB的msc功能需要配置的读写和fat32需要的读写接口都是一样的,想想这个事情也合理,USB读取U盘也是fat32格式。

实测功能正常。需要注意的是,fat32是单片机读写flash的操作,USB的msc操作是通过USB主机如电脑读写flash的操作,这两个操作应该是独立的,否则会有冲突。在实际的项目中,如果接上USB,那么单片机内部的fat32就不应该再发生读写等冲突的操作了。

相关推荐
scan16 小时前
单片机串口接收状态机STM32
stm32·单片机·串口·51·串口接收
Qingniu016 小时前
【青牛科技】应用方案 | RTC实时时钟芯片D8563和D1302
科技·单片机·嵌入式硬件·实时音视频·安防·工控·储能
深圳市青牛科技实业有限公司8 小时前
【青牛科技】应用方案|D2587A高压大电流DC-DC
人工智能·科技·单片机·嵌入式硬件·机器人·安防监控
Mr.谢尔比9 小时前
电赛入门之软件stm32keil+cubemx
stm32·单片机·嵌入式硬件·mcu·信息与通信·信号处理
LightningJie9 小时前
STM32中ARR(自动重装寄存器)为什么要减1
stm32·单片机·嵌入式硬件
西瓜籽@10 小时前
STM32——毕设基于单片机的多功能节能窗控制系统
stm32·单片机·课程设计
远翔调光芯片^1382879887212 小时前
远翔升压恒流芯片FP7209X与FP7209M什么区别?做以下应用市场摄影补光灯、便携灯、智能家居(调光)市场、太阳能、车灯、洗墙灯、舞台灯必看!
科技·单片机·智能家居·能源
极客小张13 小时前
基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
stm32·单片机·嵌入式硬件·mqtt·sqlite·毕业设计·智能充电桩
m0_7393128716 小时前
【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)
stm32·单片机·嵌入式硬件
徐嵌17 小时前
STM32项目---水质水位检测
stm32·单片机·嵌入式硬件