STM32CbueMX之SPI_FLASH + FATFS + USB MSC + 虚拟扩容

前言:

做一个在spi flash 上挂一个文件系统,然后板子用USB线连接电脑能识别读出spi flash上的文件。

背景:

因为spi flash容量比较小,我使用的是32MB的,插上电脑,感觉不好看,显示容量太小了。

所以我打算虚拟扩容一下变成1GB,但是实际可用的还是32MB。把电脑的写权限取消,只读。

fatfs调用写函数

FRESULT f_write (
    FIL* fp,            /* Pointer to the file object */
    const void* buff,    /* Pointer to the data to be written */
    UINT btw,            /* Number of bytes to write */
    UINT* bw            /* Pointer to number of bytes written */
)

返回值正常,然后*bw = 0;表示无空间写入。

主要是我下面实现了在MCU的fatfs文件系统分配超过32MB的空间都会提示已满,不再写入数据。

毕竟真实物理空间是32MB.这样不会破坏文件系统的文件表,导致文件系统出错。

为什么取消电脑写权限呢?是因为电脑写入fatfs文件系统的数据超过32MB的时候会破坏文件系统的文件表。

或者可以再改进一下,可以自我尝试。

STM32CbueMX配置图

 USB pack 大小 =  4096;包越大速度越快。

heap大小:比我们设置的USB pack大512字节就够了。

代码

spi flash 驱动以前文章有写。

user_diskio.c

DSTATUS USER_initialize (
    BYTE pdrv           /* Physical drive nmuber to identify the drive */
)
{
    Stat = BSP_W25Q256_Init();
    return Stat;
}

DSTATUS USER_status (
    BYTE pdrv       /* Physical drive number to identify the drive */
)
{
    return Stat;
}

DRESULT USER_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 */
)
{
    if(BSP_W25Q256_Read(buff, sector << 12, count << 12) != W25Q256_OK)
        return RES_ERROR;

}


DRESULT USER_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 */
)
{

    if(BSP_W25Q256_Erase_Sector(sector << 12) != W25Q256_OK)
        return RES_ERROR;

    if(BSP_W25Q256_Write((uint8_t*)buff, sector << 12, count << 12) != W25Q256_OK)
        return RES_ERROR;

    return RES_OK;
}


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

    if(pdrv != 0)   return RES_PARERR;

    switch(cmd)
    {
        case CTRL_SYNC:
            res = RES_OK;
            break;

        case GET_SECTOR_COUNT:
            *(DWORD*)buff = (W25Q256FV_FLASH_SIZE / W25Q256FV_SECTOR_SIZE);
            res = RES_OK;
            break;

        case GET_SECTOR_SIZE:
            *(WORD*)buff = W25Q256FV_SECTOR_SIZE;
            res = RES_OK;
            break;

        case GET_BLOCK_SIZE:
            *(DWORD*)buff = 1;
            res = RES_OK;
            break;

        default:
            res = RES_PARERR;
            break;

    }

    return res;
}

usbd_storage_if.c

#define MYSTORAGE_LUN_NBR                  1
#define MYSTORAGE_BLK_NBR                  (W25Q256FV_FLASH_SIZE / W25Q256FV_SECTOR_SIZE);
#define MYSTORAGE_BLK_SIZ                  W25Q256FV_SECTOR_SIZE


int8_t STORAGE_Init_FS(uint8_t lun)
{
    return (USBD_OK);
}


int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
    *block_num  = MYSTORAGE_BLK_NBR;
    *block_size = MYSTORAGE_BLK_SIZ;
    return (USBD_OK);
}

int8_t STORAGE_IsReady_FS(uint8_t lun)
{
    return (USBD_OK);
}

int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
    return (USBD_OK);
}

int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    if(BSP_W25Q256_Read(buf, blk_addr << 12, blk_len << 12) != W25Q256_OK)
        return USBD_FAIL;

    return (USBD_OK);
}

int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
    if(BSP_W25Q256_Erase_Sector(blk_addr << 12) != W25Q256_OK)
        return USBD_FAIL;

    if(BSP_W25Q256_Write(buf, blk_addr << 12, blk_len << 12) != W25Q256_OK)
        return USBD_FAIL;

    return (USBD_OK);
}

int8_t STORAGE_GetMaxLun_FS(void)
{
    return (MYSTORAGE_LUN_NBR - 1);
}

main.c

#include <stdio.h>
#include "w25q256.h"

FIL fil;
FATFS spi_fs;
unsigned char work[4096] = {0};
unsigned char read_buf[50] = {0};
unsigned char write_buf[4096] = "hello sudaroot\r\n";

static void USB_GPIO_Init(void);


int main(void)
{
    /* USER CODE BEGIN 1 */
    unsigned int res = 0;
    unsigned int count = 0;
    /* USER CODE END 1 */


    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */
    USB_GPIO_Init();
    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USB_DEVICE_Init();
    MX_SPI5_Init();
    MX_FATFS_Init();
    /* USER CODE BEGIN 2 */
    printf("sudaroot usb and fatfs msc\r\n");
    res = f_mount(&spi_fs, "0:", 1);

    if(res != FR_OK)
    {
        printf("文件系统挂载失败,f_mount = %d\r\n", res);
        res = f_mkfs("0:", FM_ANY, 0, (void*)&work, 4096);

        if(res != FR_OK)
        {
            printf("文件系统格式化失败,f_mkfs = %d\r\n", res);
        }
        else
        {
            printf("重新挂载文件系统\r\n");
            res = f_mount(&spi_fs, "0:", 1);

            if(res != FR_OK)
            {
                printf("文件系统挂载失败,f_mount = %d\r\n", res);
            }
            else
            {
                printf("文件系统挂载成功\r\n");
            }
        }
    }
    else printf("文件系统挂载成功\r\n");

    /*----------------------- 文件系统测试:写测试 -----------------------------*/
    printf("\r\n****** 即将进行文件写入测试... ******\r\n");

    res = f_open(&fil, "0:sudaroot.txt", FA_OPEN_APPEND | FA_WRITE);

    if(res == FR_OK)
    {
        res = f_write(&fil, write_buf, 4096, &count);

        if(res != FR_OK)
        {
            printf("f_write 发生错误,err = %d, count = %d\r\n", res, count);
            printf("关闭打开的sudaroot.txt文件\r\n");
            count = 0;
            f_close(&fil);
        }
        else
        {
            if(count == 0)
            {
                printf("没有空间写入数据了\r\n");
            }

            count = 0;
            f_close(&fil);
        }
    }
    else
    {
        printf("打开/创建sudaroot.txt文件失败,err = %d\r\n", res);
    }

    printf("\r\n****** 结束进行文件写入测试... ******\r\n");

    /*------------------- 文件系统测试:读测试 ------------------------------------*/
    printf("****** 即将进行文件读取测试... ******\r\n");
    res = f_open(&fil, "0:sudaroot.txt", FA_OPEN_EXISTING | FA_READ);

    if(res == FR_OK)
    {
        printf("打开sudaroot.txt文件成功\r\n");
        res = f_read(&fil, read_buf, sizeof(read_buf), &count);

        if(res != FR_OK)
        {
            printf("f_read 发生错误,err = %d\r\n", res);
            printf("关闭打开的sudaroot.txt文件\r\n");
            f_close(&fil);
        }
        else
        {
            printf("文件读取成功,读取字节数据:%d\n", count);
            printf("向文件读取的数据为:\r\n%s\r\n", read_buf);
            printf("关闭打开的sudaroot.txt文件\r\n");
            f_close(&fil);
        }
    }
    else printf("打开sudaroot.txt文件失败,err = %d\r\n", res);



    /*------------------- 不再使用文件系统,取消挂载文件系统 ------------------------------------*/
    printf("不再使用文件系统,取消挂载文件系统\r\n");
    res = f_mount(NULL, "0:", 1);

    if(res == FR_OK) printf("取消挂载文件系统成功\r\n");
    else    printf("取消挂载文件系统失败,err = %d\r\n", res);

    printf("文件系统测试结束\r\n");

    printf("csize = 0x%X = %d\r\n", spi_fs.csize, spi_fs.csize);
    printf("ssize = 0x%X = %d\r\n", spi_fs.ssize, spi_fs.ssize);
    printf("n_fatent = 0x%lX = %lu\r\n", spi_fs.n_fatent, spi_fs.n_fatent);
    printf("database = 0x%lX = %lu\r\n", spi_fs.database, spi_fs.database);
    printf("fsize = 0x%lX = %lu\r\n", spi_fs.fsize, spi_fs.fsize);
    printf("last_clst = 0x%lX = %lu\r\n", spi_fs.last_clst, spi_fs.last_clst);
    printf("free_clst = 0x%lX = %lu\r\n", spi_fs.free_clst, spi_fs.free_clst);
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        HAL_GPIO_TogglePin(RUN_LED_GPIO_Port, RUN_LED_Pin);
        HAL_Delay(500);
    }

    /* USER CODE END 3 */
}

int fputc(int ch, FILE *FILE)
{
    HAL_UART_Transmit(&huart1, (unsigned char *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

static void USB_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11 | GPIO_PIN_12, GPIO_PIN_RESET);

    /*Configure GPIO pin : W25Q256_CS_Pin */
    GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_Delay(2);
}

效果:

扩容:

先算一下1GB转换成4KB一个扇区的话一共有几个扇区。

1GB = 1024MB =1024 * 1024KB

总扇区数 = 1024 * 1024KB / 4 KB = 262144

修改 user_diskio.c

DRESULT USER_ioctl (
	BYTE pdrv,      /* Physical drive nmuber (0..) */
	BYTE cmd,       /* Control code */
	void *buff      /* Buffer to send/receive control data */
)
{
...
        case GET_SECTOR_COUNT:
            *(DWORD*)buff = 262144;
            res = RES_OK;
            break;
...
}

修改usbd_storage_if.c

#define MYSTORAGE_BLK_NBR                 262144


int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
//    if(BSP_W25Q256_Erase_Sector(blk_addr << 12) != W25Q256_OK)
//        return USBD_FAIL;

//    if(BSP_W25Q256_Write(buf, blk_addr << 12, blk_len << 12) != W25Q256_OK)
//        return USBD_FAIL;

    return (USBD_OK);
}

main.c

#include <stdio.h>
#include "w25q256.h"

FIL fil;
FATFS spi_fs;
unsigned char work[4096] = {0};
unsigned char read_buf[50] = {0};
unsigned char write_buf[4096] = "hello sudaroot\r\n";

static void USB_GPIO_Init(void);


int main(void)
{
    /* USER CODE BEGIN 1 */
    unsigned int res = 0;
    unsigned int count = 0;
    /* USER CODE END 1 */


    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */
    USB_GPIO_Init();
    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USB_DEVICE_Init();
    MX_SPI5_Init();
    MX_FATFS_Init();
    /* USER CODE BEGIN 2 */
    printf("sudaroot usb and fatfs msc\r\n");
    res = f_mount(&spi_fs, "0:", 1);

    if(res != FR_OK)
    {
        printf("文件系统挂载失败,f_mount = %d\r\n", res);
        res = f_mkfs("0:", FM_ANY, 0, (void*)&work, 4096);

        if(res != FR_OK)
        {
            printf("文件系统格式化失败,f_mkfs = %d\r\n", res);
        }
        else
        {
            printf("重新挂载文件系统\r\n");
            res = f_mount(&spi_fs, "0:", 1);

            if(res != FR_OK)
            {
                printf("文件系统挂载失败,f_mount = %d\r\n", res);
            }
            else
            {
                printf("文件系统挂载成功\r\n");
            }
        }
    }
    else printf("文件系统挂载成功\r\n");

    printf("csize = 0x%X = %d\r\n", spi_fs.csize, spi_fs.csize);
    printf("ssize = 0x%X = %d\r\n", spi_fs.ssize, spi_fs.ssize);
    printf("n_fatent = 0x%lX = %lu\r\n", spi_fs.n_fatent, spi_fs.n_fatent);
    printf("database = 0x%lX = %lu\r\n", spi_fs.database, spi_fs.database);
    printf("fsize = 0x%lX = %lu\r\n", spi_fs.fsize, spi_fs.fsize);
    printf("last_clst = 0x%lX = %lu\r\n", spi_fs.last_clst, spi_fs.last_clst);
    printf("free_clst = 0x%lX = %lu\r\n", spi_fs.free_clst, spi_fs.free_clst);
    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        HAL_GPIO_TogglePin(RUN_LED_GPIO_Port, RUN_LED_Pin);
        HAL_Delay(500);
    }

    /* USER CODE END 3 */
}

int fputc(int ch, FILE *FILE)
{
    HAL_UART_Transmit(&huart1, (unsigned char *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

static void USB_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11 | GPIO_PIN_12, GPIO_PIN_RESET);

    /*Configure GPIO pin : W25Q256_CS_Pin */
    GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_Delay(2);
}

编译烧录重启连接USB到PC

一切正常。

分析:

先分析一下FATFS结构体和容量相关的参数,然再改。

/* File system object structure (FATFS) */

typedef struct {
...
WORD csize; / *簇大小[扇区] * /
WORD ssize; / *扇区大小(512,1024,2048或4096)* /
DWORD last_clst; / *最后分配的簇* /
DWORD free_clst; / *没使用簇数量* /
DWORD n_fatent; / * FAT条目数(簇数+ 2)* /
DWORD fsize; / * FAT的大小[扇区] * /
DWORD volbase; / *卷起始扇区* /
DWORD fatbase; / * FAT起始扇区* /
DWORD dirbase; / *根目录基本扇区* /
DWORD database; / *数据起始扇区* /
...
} FATFS;

簇是文件系统的最小单位,spi_flash的最小擦除单位是扇区。

变量csize表示一个簇由几个扇区组成,ssize表示一个扇区大小。n_fatent表示可用于存数据簇的总数。

还有就是一般小于4GB的文件系统都会格式化成FAT12或者FAT16,这种方式扩容不支持FAT32。

由上面串口打印的信息我们可以看出

簇大小 = csize *  ssize = 8 * 4KB = 32KB

那么1GB可以分成几个32KB的簇

簇总数 = 1GB / 32KB = 1024 * 1024KB  / 32KB = 32768 = 0X‭8000‬

文件表和保留扇区用几个簇 = 簇总数 - n_fatent = 32768 - 32759 = 9

本来是32MB的flash = 8192 * 4KB = 1024 * 32KB

所以我们使用更改n_fatent = 1024 - 9 = 1015

还要注意的是n_fatent会在实际可用簇的基础上+2。

但是直接更改n_fatent是不行的,因为n_fatent会写入分区表,这样子会破坏分区表。

所以换一种方法,看哪里用n_fatent分配空间,在那里把n_fatent修改成常量。

下面这个函数是分配新的簇函数

/*-----------------------------------------------------------------------*/
/* FAT handling - Stretch a chain or Create a new chain                  */
/*-----------------------------------------------------------------------*/
static
DWORD create_chain (	/* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
	_FDID* obj,			/* Corresponding object */
	DWORD clst			/* Cluster# to stretch, 0:Create a new chain */
)
{
	DWORD cs, ncl, scl;
	FRESULT res;
	FATFS *fs = obj->fs;


	if (clst == 0) {	/* Create a new chain */
		scl = fs->last_clst;				/* Get suggested cluster to start from */
		if (scl == 0 || scl >= fs->n_fatent) scl = 1;
	}
	else {				/* Stretch current chain */
		cs = get_fat(obj, clst);			/* Check the cluster status */
		if (cs < 2) return 1;				/* Invalid FAT value */
		if (cs == 0xFFFFFFFF) return cs;	/* A disk error occurred */
		if (cs < fs->n_fatent) return cs;	/* It is already followed by next cluster */
		scl = clst;
	}

#if _FS_EXFAT
	if (fs->fs_type == FS_EXFAT) {	/* On the exFAT volume */
		ncl = find_bitmap(fs, scl, 1);				/* Find a free cluster */
		if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl;	/* No free cluster or hard error? */
		res = change_bitmap(fs, ncl, 1, 1);			/* Mark the cluster 'in use' */
		if (res == FR_INT_ERR) return 1;
		if (res == FR_DISK_ERR) return 0xFFFFFFFF;
		if (clst == 0) {							/* Is it a new chain? */
			obj->stat = 2;							/* Set status 'contiguous' */
		} else {									/* It is a stretched chain */
			if (obj->stat == 2 && ncl != scl + 1) {	/* Is the chain got fragmented? */
				obj->n_cont = scl - obj->sclust;	/* Set size of the contiguous part */
				obj->stat = 3;						/* Change status 'just fragmented' */
			}
		}
		if (obj->stat != 2) {	/* Is the file non-contiguous? */
			if (ncl == clst + 1) {	/* Is the cluster next to previous one? */
				obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2;	/* Increment size of last framgent */
			} else {				/* New fragment */
				if (obj->n_frag == 0) obj->n_frag = 1;
				res = fill_last_frag(obj, clst, ncl);	/* Fill last fragment on the FAT and link it to new one */
				if (res == FR_OK) obj->n_frag = 1;
			}
		}
	} else
#endif
	{	/* On the FAT12/16/32 volume */
		ncl = scl;	/* Start cluster */
		for (;;) {
			ncl++;							/* Next cluster */
			if (ncl >= fs->n_fatent) {		/* Check wrap-around */
				ncl = 2;
				if (ncl > scl) return 0;	/* No free cluster */
			}
			cs = get_fat(obj, ncl);			/* Get the cluster status */
			if (cs == 0) break;				/* Found a free cluster */
			if (cs == 1 || cs == 0xFFFFFFFF) return cs;	/* An error occurred */
			if (ncl == scl) return 0;		/* No free cluster */
		}
		res = put_fat(fs, ncl, 0xFFFFFFFF);	/* Mark the new cluster 'EOC' */
		if (res == FR_OK && clst != 0) {
			res = put_fat(fs, clst, ncl);	/* Link it from the previous one if needed */
		}
	}

	if (res == FR_OK) {			/* Update FSINFO if function succeeded. */
		fs->last_clst = ncl;
		if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--;
		fs->fsi_flag |= 1;
	} else {
		ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;	/* Failed. Generate error status */
	}

	return ncl;		/* Return new cluster number or error status */
}

#endif /* !_FS_READONLY */

修改一下

static
DWORD create_chain (	/* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
	_FDID* obj,			/* Corresponding object */
	DWORD clst			/* Cluster# to stretch, 0:Create a new chain */
)
{

...
	if (clst == 0) {	/* Create a new chain */
		scl = fs->last_clst;				/* Get suggested cluster to start from */
		//if (scl == 0 || scl >= fs->n_fatent) scl = 1;
        if (scl == 0 || scl >= 1015) scl = 1;
	}
...
			//if (ncl >= fs->n_fatent) {		/* Check wrap-around */
            if (ncl >= 1015) {		/* Check wrap-around */
				ncl = 2;
				if (ncl > scl) return 0;	/* No free cluster */
			}
....
}

把注释的两行的fs->n_fatent 换成我们算出来的 1015;

测试程序:

每次调用f_write()往缓存区写入4096个字节数据,统计能写多少次。

f_write(&fil, write_buf, 4096, &count); 函数返回值不等于FR_OK一般是配置出错,或者硬件出错。

而count写入字节统计为0的话才是没用多余的空间写入。

FIL fil;
FATFS spi_fs;
unsigned char read_buf[50] = {0};
unsigned char work[4096] = {0};
unsigned char write_buf[4096] = "\r\nhello sudaroot\r\n";



/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    /* USER CODE BEGIN 1 */
    unsigned int res = 0;
    unsigned int count = 0;
    unsigned int sum = 0;
    /* USER CODE END 1 */


    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* USER CODE BEGIN SysInit */
    USB_GPIO_Init();
    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USB_DEVICE_Init();
    MX_SPI5_Init();
    MX_FATFS_Init();
    /* USER CODE BEGIN 2 */
    HAL_Delay(1000);
    BSP_W25Q256_Erase_Sector(0);
    HAL_Delay(100);
    printf("sudaroot usb and fatfs msc\r\n");
    res = f_mount(&spi_fs, "0:", 1);

    if(res != FR_OK)
    {
        printf("文件系统挂载失败,f_mount = %d\r\n", res);
        res = f_mkfs("0:", FM_ANY, 0, (void*)&work, 4096);

        if(res != FR_OK)
        {
            printf("文件系统格式化失败,f_mkfs = %d\r\n", res);
        }
        else
        {
            printf("重新挂载文件系统\r\n");
            res = f_mount(&spi_fs, "0:", 1);

            if(res != FR_OK)
            {
                printf("文件系统挂载失败,f_mount = %d\r\n", res);
            }
            else
            {
                printf("文件系统挂载成功\r\n");
            }
        }
    }
    else printf("文件系统挂载成功\r\n");

    printf("csize = 0x%X = %d\r\n", spi_fs.csize, spi_fs.csize);
    printf("ssize = 0x%X = %d\r\n", spi_fs.ssize, spi_fs.ssize);
    printf("n_fatent = 0x%lX = %lu\r\n", spi_fs.n_fatent, spi_fs.n_fatent);
    printf("database = 0x%lX = %lu\r\n", spi_fs.database, spi_fs.database);
    printf("fsize = 0x%lX = %lu\r\n", spi_fs.fsize, spi_fs.fsize);
    printf("last_clst = 0x%lX = %lu\r\n", spi_fs.last_clst, spi_fs.last_clst);
    printf("free_clst = 0x%lX = %lu\r\n", spi_fs.free_clst, spi_fs.free_clst);

    /*----------------------- 文件系统测试:写测试 -----------------------------*/
    printf("\r\n****** 即将进行文件写入测试... ******\r\n");
    while(1)
    {
        res = f_open(&fil, "0:sudaroot.txt", FA_OPEN_APPEND | FA_WRITE);

        if(res == FR_OK)
        {
            res = f_write(&fil, write_buf, 4096, &count);

            if(res != FR_OK)
            {
                printf("f_write 发生错误,err = %d, count = %d\r\n", res, count);
                printf("关闭打开的sudaroot.txt文件\r\n");
                count = 0;
                f_close(&fil);
                break;
            }
            else
            {
                if(count == 0)
                {
                    printf("没有空间写入数据了\r\n");
                    break;
                }
                sum++;
                count = 0;
                f_close(&fil);

            }
        }
        else
        {
            printf("打开/创建sudaroot.txt文件失败,err = %d\r\n", res);
            break;
        }
        HAL_GPIO_TogglePin(RUN_LED_GPIO_Port, RUN_LED_Pin);
        HAL_Delay(1);
    }

    printf("总计:sum = %u\r\n", sum);

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        HAL_GPIO_TogglePin(RUN_LED_GPIO_Port, RUN_LED_Pin);
        HAL_Delay(500);
    }

    /* USER CODE END 3 */
}

效果:

电脑也能读取。

上图等值写入了8104次数据。每次写4KB字节。那么共写入了 8104 * 4KB = 32,416KB数据。

计算一下,和上面数据对比。

我们上面计算出n_fatent = 1015;但是n_fatent会多加比实际可用簇多加2个簇。

故实际的簇是n_fatent - 2 = 1015 - 2 = 1013;

因为一簇 = 32KB; 

故32MB实际可用 = 1013 * 32KB = 32416KB;

对比发现,和计算结果和测试效果一致。

扩容成功。

  全篇完。

本人是一个嵌入式未入门小白,博客仅仅代表我个人主观见解,记录成长笔记。
笔记是以最简单的方式,只展示最核心的原理。
若有与 大神大大 见解有歧义,我绝对坚信 大神大大 见解是对的,我的是错的。
若无积分等无法下载源码,可加入QQ群657407920下载交流经验。感谢~!

 

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值