- #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;
- }