当前遇到的问题是,直接调用低层函数读写数据是正常的,由于读写无法共存,所有读数据,我采用了复制的方式,没有采用直接指针. 我使用fatfs文件系统后,格式化正常,读正常,就是只要一新建文件,保存,当时是没有报错,但是重启板子后,挂载falsh时,就会提示没有文件系统,就是写文件时,把文件系统给写坏了,找了很久原因,希望能得到华大官方的帮助,谢谢,关键代码如下
#ifndef W25QXX_H
#define W25QXX_H
#include "qspi.h"
/**
*******************************************************************************
** \defgroup W25QXXGroup W25Q64 SPI NOR Flash driver
**
******************************************************************************/
//@{
/*******************************************************************************
* Global type definitions ('typedef')
******************************************************************************/
/*****************************************************************************/
/* Global pre-processor symbols/macros ('define') */
/*****************************************************************************/
/* W25QXX Flash ID */
#define W25Q80 0XEF13u
#define W25Q16 0XEF14u
#define W25Q32 0XEF15u
#define W25Q64 0XEF16u
#define W25Q128 0XEF17u
/* W25QXX Command list */
#define W25X_WriteEnable 0x06u
#define W25X_WriteDisable 0x04u
#define W25X_ReadStatusReg 0x05u
#define W25X_WriteStatusReg 0x01u
#define W25X_ReadData 0x03u
#define W25X_FastReadData 0x0Bu
#define W25X_FastReadDual 0x3Bu
#define W25X_PageProgram 0x02u
#define W25X_BlockErase 0xD8u
#define W25X_SectorErase 0x20u
#define W25X_ChipErase 0xC7u
#define W25X_PowerDown 0xB9u
#define W25X_ReleasePowerDown 0xABu
#define W25X_DeviceID 0xABu
#define W25X_ManufactDeviceID 0x90u
#define W25X_JedecDeviceID 0x9Fu
/*******************************************************************************
* Global variable definitions ('extern')
******************************************************************************/
extern uint16_t W25QXX_TYPE;
/*******************************************************************************
* Global function prototypes (definition in C source)
******************************************************************************/
int W25QXX_Init(void);
int W25QXX_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
int W25QXX_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
#endif
#include "w25qxx.h"
#include "string.h"
uint16_t W25QXX_TYPE = W25Q64;
uint8_t W25QXX_BUFFER[4096];
/**
*******************************************************************************
** \brief W25QXX IO initialize
**
** \param None
**
** \retval int
**
******************************************************************************/
int W25QXX_Init(void)
{
int result = QspiFlash_Init();
if (result == 0) {
// W25QXX_TYPE = W25QXX_ReadID();
}
return result;
}
/**
*******************************************************************************
** \brief W25QXX read flash content
**
** \param [in] ReadAddr Address to be read
** \param [in] NumByteToRead Number to be read, (MAX. 65535)
** \param [out] pBuffer Read data buffer
**
** \retval Read result
**
******************************************************************************/
int W25QXX_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
while(flashnoreading){};
stc_qspi_comm_protocol_t stcQspiCommProtocol;
MEM_ZERO_STRUCT(stcQspiCommProtocol);
/* Switch to standard read mode */
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresIO;
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
/* Pointer to flash address map */
// pBuffer = (uint8_t *)((uint32_t)QSPI_BUS_ADDRESS + ReadAddr);
uint8_t * pFlashReadAddr = (uint8_t *)((uint32_t)QSPI_BUS_ADDRESS + ReadAddr);
memcpy(pBuffer, pFlashReadAddr, (uint32_t)NumByteToRead);
return 0 ;
}
/**
*******************************************************************************
** \brief W25QXX flash write
**
** \param [in] pBuffer data buffer to be written
** \param [in] WriteAddr Address to be written
** \param [in] NumByteToWrite Number to be written, (MAX. 65535)
**
** \retval None
**
******************************************************************************/
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;
}
while (1)
{
QspiFlash_WritePage(WriteAddr,pBuffer , pageremain); //pBuffer
if (NumByteToWrite == pageremain)
{
break;
}
else //NumByteToWrite>pageremain
{
pBuffer += pageremain;
WriteAddr += pageremain;
NumByteToWrite -= pageremain;
if (NumByteToWrite > 256u)
{
pageremain = 256u;
}
else
{
pageremain = NumByteToWrite;
}
}
}
flashnoreading = 0 ;
}
/**
*******************************************************************************
** \brief W25QXX flash write API for MSC
**
** \param [in] pBuffer data buffer to be written
** \param [in] WriteAddr Address to be written
** \param [in] NumByteToWrite Number to be written, (MAX. 65535)
**
** \retval Write result
**
******************************************************************************/
int W25QXX_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
if(WriteAddr + NumByteToWrite -1 > (uint32_t)FLASH_MAX_ADDR){
return 1 ;
}
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t * W25QXX_BUF;
W25QXX_BUF = W25QXX_BUFFER;
secpos = WriteAddr / 4096u;
secoff = (uint16_t)(WriteAddr % 4096u);
secremain = 4096u - secoff;
// DDL_Printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite); // for test
if (NumByteToWrite <= secremain)
{
secremain = NumByteToWrite; // less than 4K
}
while (1)
{
W25QXX_Read(W25QXX_BUF, secpos * 4096u, 4096u); // read one sector content
stc_qspi_comm_protocol_t stcQspiCommProtocol;
MEM_ZERO_STRUCT(stcQspiCommProtocol);
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
for (i = 0u; i < secremain; i++) // check if blank sector
{
if (W25QXX_BUF[secoff + i] != (uint8_t)0XFF)
{
break;
}
}
if (i < secremain)
{
QspiFlash_Erase4KbSector(secpos); // not blank, need erase
for (i = 0u; i < secremain; i++) // backup first
{
W25QXX_BUF[i + secoff] = pBuffer[i];
}
W25QXX_Write_NoCheck( W25QXX_BUF , secpos * 4096u,4096u); // write back after erase
}
else
{
W25QXX_Write_NoCheck(pBuffer , WriteAddr, secremain);
}
if (NumByteToWrite == secremain)
{
break;
}
else
{
secpos++; // next sector
secoff = 0u;
pBuffer += secremain;
WriteAddr += secremain;
NumByteToWrite -= secremain;
if (NumByteToWrite > 4096u)
{
secremain = 4096u;
}
else
{
secremain = NumByteToWrite;
}
}
}
;
return 0 ;
}
/*-----------------------------------------------------------------------*/
/* 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 "w25qxx.h"
/* Definitions of physical drive number for each drive */
#define W25QXX 0 /* Example: Map Ramdisk to physical drive 0 */
#define FATFS_SECTOR_SIZE 512
#define FATFS_SECTOR_COUNT 8 * 1024 * 2 //一共8M空间
#define FATFS_BLOCK_SIZE 8 //每个BLOCK有8个扇区
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = 0;
switch (pdrv) {
case W25QXX :
// 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;
switch (pdrv) {
case W25QXX :
stat = W25QXX_Init();
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* 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 W25QXX :
// translate the arguments here
// result = flashfatfsread(buff, sector * FATFS_SECTOR_SIZE, count * FATFS_SECTOR_SIZE);
// result = W25QXX_Read(buff, sector * FATFS_SECTOR_SIZE, count * FATFS_SECTOR_SIZE);
for(;count>0;count--)
{
result = W25QXX_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
// translate the reslut code here
return (DRESULT)result;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#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 W25QXX :
// result = flashfatfswrite((uint8_t *)buff,sector * FATFS_SECTOR_SIZE,count * FATFS_SECTOR_SIZE);
// result = W25QXX_Write((uint8_t *)&buff, sector * FATFS_SECTOR_SIZE, count * FATFS_SECTOR_SIZE);
for(;count>0;count--)
{
result = W25QXX_Write((uint8_t*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
return (DRESULT)result; //RES_PARERR
}
return RES_PARERR;
}
#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;
switch (pdrv) {
case W25QXX :
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = FATFS_SECTOR_SIZE;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = FATFS_BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = FATFS_SECTOR_COUNT;
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
return res;
}
return RES_PARERR;
}
DWORD get_fattime (void)
{
return 0;
}
#include "qspi.h"
uint8_t flashnoreading = 1 ;
/**
*******************************************************************************
** \brief QSPI flash init function
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
int QspiFlash_Init(void)
{
stc_qspi_init_t stcQspiInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcQspiInit);
/* Configuration peripheral clock */
PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_QSPI, Enable);
/* Configuration QSPI pin */
PORT_SetFunc(QSPCK_PORT, QSPCK_PIN, Func_Qspi, Disable);
PORT_SetFunc(QSNSS_PORT, QSNSS_PIN, Func_Qspi, Disable);
PORT_SetFunc(QSIO0_PORT, QSIO0_PIN, Func_Qspi, Disable);
PORT_SetFunc(QSIO1_PORT, QSIO1_PIN, Func_Qspi, Disable);
PORT_SetFunc(QSIO2_PORT, QSIO2_PIN, Func_Qspi, Disable);
PORT_SetFunc(QSIO3_PORT, QSIO3_PIN, Func_Qspi, Disable);
/* Configuration QSPI structure */
stcQspiInit.enClkDiv = QspiHclkDiv3;
stcQspiInit.enSpiMode = QspiSpiMode3;
stcQspiInit.enBusCommMode = QspiBusModeRomAccess;
stcQspiInit.enPrefetchMode = QspiPrefetchStopComplete;
stcQspiInit.enPrefetchFuncEn = Disable;
stcQspiInit.enQssnValidExtendTime = QspiQssnValidExtendSck32;
stcQspiInit.enQssnIntervalTime = QspiQssnIntervalQsck8;
stcQspiInit.enQsckDutyCorr = QspiQsckDutyCorrHalfHclk;
stcQspiInit.enVirtualPeriod = QspiVirtualPeriodQsck6;
stcQspiInit.enWpPinLevel = QspiWpPinOutputHigh;
stcQspiInit.enQssnSetupDelayTime = QspiQssnSetupDelay1Dot5Qsck;
stcQspiInit.enQssnHoldDelayTime = QspiQssnHoldDelay1Dot5Qsck;
stcQspiInit.enFourByteAddrReadEn = Disable;
stcQspiInit.enAddrWidth = QspiAddressByteThree;
stcQspiInit.stcCommProtocol.enReadMode = QspiReadModeFourWiresIO;
stcQspiInit.stcCommProtocol.enTransInstrProtocol = QspiProtocolExtendSpi;
stcQspiInit.stcCommProtocol.enTransAddrProtocol = QspiProtocolExtendSpi;
stcQspiInit.stcCommProtocol.enReceProtocol = QspiProtocolExtendSpi;
stcQspiInit.u8RomAccessInstr = QSPI_3BINSTR_FOUR_WIRES_IO_READ;
int result = QSPI_Init(&stcQspiInit);
flashnoreading = 0; //允许读取falsh
return result;
}
/**
*******************************************************************************
** \brief QSPI flash write enable function
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
void QspiFlash_WriteEnable(void)
{
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_WRITE_ENABLE);
QSPI_ExitDirectCommMode();
}
/**
*******************************************************************************
** \brief QSPI flash wait for write operation end function
**
** \param [in] None
**
** \retval Ok Flash internal operation finish
** \retval ErrorTimeout Flash internal operation timeout
**
******************************************************************************/
en_result_t QspiFlash_WaitForWriteEnd(void)
{
en_result_t enRet = Ok;
uint8_t u8Status = 0u;
uint32_t u32Timeout;
stc_clk_freq_t stcClkFreq;
CLK_GetClockFreq(&stcClkFreq);
u32Timeout = stcClkFreq.sysclkFreq / 1000u;
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_READ_SR1);
do
{
u8Status = QSPI_ReadDirectCommValue();
u32Timeout--;
} while ((u32Timeout != 0u) &&
((u8Status & FLASH_BUSY_BIT_MASK) == FLASH_BUSY_BIT_MASK));
if (FLASH_BUSY_BIT_MASK == u8Status)
{
enRet = ErrorTimeout;
}
QSPI_ExitDirectCommMode();
return enRet;
}
/**
*******************************************************************************
** \brief QSPI flash page write program function
**
** \param [in] u32Addr Valid flash address
**
** \param [in] pData Pointer to send data buffer
**
** \param [in] len Send data length
**
** \retval Error Page write program failed
** \retval Ok Page write program success
**
******************************************************************************/
en_result_t QspiFlash_WritePage(uint32_t u32Addr, uint8_t * pData, uint16_t len)
{
en_result_t enRet = Ok;
uint16_t u16Index = 0u;
if ((u32Addr > FLASH_MAX_ADDR) || (NULL == pData) || (len > FLASH_PAGE_SIZE))
{
enRet = Error;
}
else
{
QspiFlash_WriteEnable();
/* Send data to flash */
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_PAGE_PROGRAM);
QSPI_WriteDirectCommValue((uint8_t)((u32Addr & 0xFF0000ul) >> 16));
QSPI_WriteDirectCommValue((uint8_t)((u32Addr & 0xFF00u) >> 8));
QSPI_WriteDirectCommValue((uint8_t)(u32Addr & 0xFFu));
while (len--)
{
QSPI_WriteDirectCommValue(pData[u16Index]);
u16Index++;
}
QSPI_ExitDirectCommMode();
/* Wait for flash idle */
enRet = QspiFlash_WaitForWriteEnd();
}
return enRet;
}
/**
*******************************************************************************
** \brief QSPI flash erase 4Kb sector function
**
** \param [in] u32Addr Valid flash address
**
** \retval Error Sector erase failed
** \retval Ok Sector erase success
**
******************************************************************************/
en_result_t QspiFlash_Erase4KbSector(uint32_t u32Addr)
{
en_result_t enRet = Ok;
if (u32Addr >= FLASH_MAX_ADDR)
{
enRet = Error;
}
else
{
QspiFlash_WriteEnable();
/* Send instruction to flash */
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_ERASE_4KB_SECTOR);
QSPI_WriteDirectCommValue((uint8_t)((u32Addr & 0xFF0000ul) >> 16));
QSPI_WriteDirectCommValue((uint8_t)((u32Addr & 0xFF00u) >> 8));
QSPI_WriteDirectCommValue((uint8_t)(u32Addr & 0xFFu));
QSPI_ExitDirectCommMode();
/* Wait for flash idle */
enRet = QspiFlash_WaitForWriteEnd();
}
return enRet;
}
/**
*******************************************************************************
** \brief QSPI flash erase chip function
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
void QspiFlash_EraseChip(void)
{
QspiFlash_WriteEnable();
/* Send instruction to flash */
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_ERASE_CHIP);
QSPI_ExitDirectCommMode();
/* Wait for flash idle */
QspiFlash_WaitForWriteEnd();
}
/**
*******************************************************************************
** \brief QSPI flash read status register function
**
** \param [in] u8Reg Need to get status register
** \arg FLASH_INSTR_READ_SR1 Status register 1
** \arg FLASH_INSTR_READ_SR2 Status register 2
** \arg FLASH_INSTR_READ_SR3 Status register 3
**
** \retval uint8_t Current register value
**
******************************************************************************/
uint8_t QspiFlash_ReadStatusRegister(uint8_t u8Reg)
{
uint8_t regSta = 0u;
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(u8Reg);
regSta = QSPI_ReadDirectCommValue();
QSPI_ExitDirectCommMode();
return regSta;
}
|