STM32F FREERTOS SPI-FLASH FATFS可以写文件,无法打开文件或者无法读文件的问题

这两天终于把SPI FLASH的FATFS文件系统搞好了。总结这一过程,得出以下经验:

1.  先将SPI FALSH底层驱动调好,并好好做测试。自己写一个程序,写入然后读出进行校验,确认数据是OK,并且确认整片FLASH是可用的。 之前驱动没写好,PAGE和SECTOR搞错了,导致部分文件只能写入一部分,后面部分不正确,一开始还以为是内存异常,找了好久。

2. user_diskio.c文件里的USER_initialize、USER_status、USER_read、USER_write这4大函数,一定要写好。前面2个函数没什么,主要是后面两个函数容易出错,或者容易让人大意出问题。因为USER_read和USER_write这两个函数传递进来的sector就是扇区(@param  sector: Sector address (LBA)),而不是扇区地址。而底层驱动(我从网上下载的)采用的是扇区所在的物理地址,两种要做好对应关系。否则,可能出现可以绑定、但是无法读写的情况。

3. USER_ioctl函数中,获取命令为GET_BLOCK_SIZE是,根据字面理解返回的是块的长度尺寸,例如64K,但是应该返回的是块里面扇区的数量。


4. 第一次使用FLASH或上电需要格式化文件系统,这个是常识了,当然过后就不再需要了,除非FLASH出现异常。发现网上有人提出问题无法保存数据的问题,结果是每次上电都格式化了。res = f_mkfs(USERPath, 1, 4096);


注意以上问题后,FATFS就可以用了。

相关代码:

/**
 ******************************************************************************
  * @file    user_diskio.c
  * @brief   This file includes a diskio driver skeleton to be completed by the user.
  ******************************************************************************
  * This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * Copyright (c) 2018 STMicroelectronics International N.V. 
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without 
  * modification, are permitted, provided that the following conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice, 
  *    this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
  * 3. Neither the name of STMicroelectronics nor the names of other 
  *    contributors to this software may be used to endorse or promote products 
  *    derived from this software without specific written permission.
  * 4. This software, including modifications and/or derivative works of this 
  *    software, must execute solely and exclusively on microcontroller or
  *    microprocessor devices manufactured by or for STMicroelectronics.
  * 5. Redistribution and use of this software other than as permitted under 
  *    this license is void and will automatically terminate your rights under 
  *    this license. 
  *
  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 
  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 
  * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

#ifdef USE_OBSOLETE_USER_CODE_SECTION_0
/* 
 * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0)
 * To be suppressed in the future. 
 * Kept to ensure backward compatibility with previous CubeMx versions when 
 * migrating projects. 
 * User code previously added there should be copied in the new user sections before 
 * the section contents can be deleted.
 */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
#endif

/* USER CODE BEGIN DECL */

/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "ff_gen_drv.h"
#include "w25qx.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
/* Disk status */
static volatile DSTATUS Stat = STA_NOINIT;
extern void MX_SPI1_Init(void);
/* USER CODE END DECL */

/* Private function prototypes -----------------------------------------------*/
DSTATUS USER_initialize (BYTE pdrv);
DSTATUS USER_status (BYTE pdrv);
DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1
  DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);  
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
  DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff);
#endif /* _USE_IOCTL == 1 */

Diskio_drvTypeDef  USER_Driver =
{
  USER_initialize,
  USER_status,
  USER_read, 
#if  _USE_WRITE
  USER_write,
#endif  /* _USE_WRITE == 1 */  
#if  _USE_IOCTL == 1
  USER_ioctl,
#endif /* _USE_IOCTL == 1 */
};

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Initializes a Drive
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_initialize (
	BYTE pdrv           /* Physical drive nmuber to identify the drive */
)
{
	switch (pdrv)
	{
		case 0 :
		MX_SPI1_Init();				//初始化SPI FLASH
		return RES_OK;			
		case 1 :
		return RES_OK;         
		case 2 :
		return RES_OK;         
		case 3 :
		return RES_OK;
		default:
		return STA_NOINIT;
	}
}
 
/**
  * @brief  Gets Disk Status 
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_status (
	BYTE pdrv       /* Physical drive number to identify the drive */
)
{
	switch (pdrv)
	{
		case 0 :
		return RES_OK;
		case 1 :
		return RES_OK;         
		case 2 :
		return RES_OK;         
		default:
		return STA_NOINIT;
	}
}

/**
  * @brief  Reads Sector(s) 
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
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 */
)
{
 /* USER CODE HERE */							//HUANGDADAO
  UINT i = 0;
  for(i = 0; i < count; i ++)
  {
    BSP_W25Qx_Read_Sector(buff, sector*SECTOR_SIZE);
    sector++;
    buff+=SECTOR_SIZE;
  }
  return RES_OK;
}

/**
  * @brief  Writes Sector(s)  
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
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 */
)
{ 
/* USER CODE HERE */
  UINT i = 0;
  for(i = 0; i < count; i ++)
  {
    BSP_W25Qx_Write_Sector((uint8_t*)buff,sector*SECTOR_SIZE);
    sector ++;
    buff += SECTOR_SIZE;
  }
  return RES_OK;
}
#endif /* _USE_WRITE == 1 */

/**
  * @brief  I/O control operation  
  * @param  pdrv: Physical drive number (0..)
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
	BYTE pdrv,      /* Physical drive nmuber (0..) */
	BYTE cmd,       /* Control code */
	void *buff      /* Buffer to send/receive control data */
)
{
 DRESULT res = RES_OK;
  
  switch(cmd)
  {
    case CTRL_SYNC :
        break;	

    case CTRL_TRIM:
        break;
		
    case GET_BLOCK_SIZE:
				*(DWORD*)buff = BLOCK_SIZE;
				break;
		
    case GET_SECTOR_SIZE:
				*(DWORD*)buff = SECTOR_SIZE;
        break;
		
    case GET_SECTOR_COUNT:
				*(DWORD*)buff = SECTOR_COUNT;
				break;
			
    default:
	res = RES_PARERR;
	break;
    }
  
  return res;
}
#endif /* _USE_IOCTL == 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
相关文章
相关标签/搜索