自学内容网 自学内容网

基于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的移植:

/*-----------------------------------------------------------------------*/
/* 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_RAM0/* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC1/* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB2/* 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就不应该再发生读写等冲突的操作了。
 


原文地址:https://blog.csdn.net/weixin_41579872/article/details/137786142

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!