/** * @brief Reads current status of the W25Q128FV. * @retval W25Q128FV memory status */ uint8_tW25Qxx_GetStatus(void) { uint8_t cmd[] = {READ_STATUS_REG1_CMD}; uint8_t status;
W25Qxx_CS_Enable(); /* Send the read status command */ W25Qxx_WriteByte(cmd, 1); /* Reception of the data */ W25Qxx_ReadByte(&status, 1); W25Qxx_CS_Disable();
/* Check the value of the register */ if((status & W25QXX_FSR_BUSY) != 0) { return W25QXX_BUSY; } else { return W25QXX_OK; } }
/** * @brief This function send a Write Enable and wait it is effective. * @retval None */ uint8_tW25Qxx_WriteEnable(void) { uint8_t cmd[] = {WRITE_ENABLE_CMD}; uint32_t tickstart = W25Qxx_GetTick();
/*Select the FLASH: Chip Select low */ W25Qxx_CS_Enable(); /* Send the read ID command */ W25Qxx_WriteByte(cmd, 1); /*Deselect the FLASH: Chip Select high */ W25Qxx_CS_Disable();
/* Wait the end of Flash writing */ while(W25Qxx_GetStatus() == W25QXX_BUSY) { /* Check for the Timeout */ if((W25Qxx_GetTick() - tickstart) > W25QXX_TIMEOUT_VALUE) { return W25QXX_TIMEOUT; } }
W25Qxx_CS_Enable(); /* Send the read ID command */ W25Qxx_WriteByte(cmd, 1); /* Reception of the data */ W25Qxx_ReadByte(ID, 3); W25Qxx_CS_Disable(); }
/** * @brief Reads an amount of data from the QSPI memory. * @param pData: Pointer to data to be read * @param ReadAddr: Read start address * @param Size: Size of data to read * @retval QSPI memory status */ // TODO uint8_t W25Qxx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) { uint8_t cmd[4];
W25Qxx_CS_Enable(); /* Send the read ID command */ W25Qxx_WriteByte(cmd, 4); /* Reception of the data */ if(W25Qxx_ReadByte(pData, Size) == 0) { return W25QXX_ERROR; } W25Qxx_CS_Disable(); return W25QXX_OK; }
/** * @brief Writes an amount of data to the QSPI memory. * @param pData: Pointer to data to be written * @param WriteAddr: Write start address * @param Size: Size of data to write,No more than 256byte. * @retval QSPI memory status */ uint8_tW25Qxx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) { uint8_t cmd[4]; uint32_t end_addr, current_size, current_addr; uint32_t tickstart = W25Qxx_GetTick();
/* Calculation of the size between the write address and the end of the page */ current_addr = 0;
/*Select the FLASH: Chip Select low */ W25Qxx_CS_Enable(); /* Send the read ID command */ W25Qxx_WriteByte(cmd, 4); /*Deselect the FLASH: Chip Select high */ W25Qxx_CS_Disable();
/* Wait the end of Flash writing */ while(W25Qxx_GetStatus() == W25QXX_BUSY) { /* Check for the Timeout */ if((W25Qxx_GetTick() - tickstart) > W25QXX_SECTOR_ERASE_MAX_TIME) { return W25QXX_TIMEOUT; } } return W25QXX_OK; }
/** * @brief Erases the entire QSPI memory.This function will take a very long time. * @retval QSPI memory status */ uint8_tW25Qxx_Erase_Chip(void) { uint8_t cmd[4]; uint32_t tickstart = W25Qxx_GetTick(); cmd[0] = CHIP_ERASE_CMD;
/*Select the FLASH: Chip Select low */ W25Qxx_CS_Enable(); /* Send the read ID command */ W25Qxx_WriteByte(cmd, 1); /*Deselect the FLASH: Chip Select high */ W25Qxx_CS_Disable();
/* Wait the end of Flash writing */ while(W25Qxx_GetStatus() != W25QXX_BUSY) { /* Check for the Timeout */ if((W25Qxx_GetTick() - tickstart) > W25QXX_BULK_ERASE_MAX_TIME) { return W25QXX_TIMEOUT; } } return W25QXX_OK; }
/*-----------------------------------------------------------------------*/ /* 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 DEV_SPIFLASH 0
/*-----------------------------------------------------------------------*/ /* Get Drive Status */ /*-----------------------------------------------------------------------*/
DSTATUS disk_status( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { DSTATUS stat; uint8_t result;
switch(pdrv) { case DEV_SPIFLASH : result = W25Qxx_GetStatus();
// translate the reslut code here switch(result) { case W25QXX_OK: stat = STA_NOINIT & (~STA_NOINIT); break;
case W25QXX_ERROR: stat = STA_NOINIT; break;
case W25QXX_BUSY: stat = STA_NOINIT; break;
case W25QXX_TIMEOUT: stat = STA_NOINIT; break; } return stat;
} return STA_NOINIT; }
/*-----------------------------------------------------------------------*/ /* Inidialize a Drive */ /*-----------------------------------------------------------------------*/
DSTATUS disk_initialize( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { DSTATUS stat; uint8_t result;
switch(pdrv) { case DEV_SPIFLASH : result = W25Qxx_Init(); W25Qxx_IC_Check();
// translate the reslut code here switch(result) { case W25QXX_OK: stat = STA_NOINIT & (~STA_NOINIT); break;
case W25QXX_ERROR: stat = STA_NOINIT; break;
case W25QXX_BUSY: stat = STA_NOINIT; break;
case W25QXX_TIMEOUT: stat = STA_NOINIT; break; } return stat;
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; uint8_t result;
switch(pdrv) { case DEV_SPIFLASH : // translate the arguments here
result = W25Qxx_Read(buff, sector * W25Qxx_Info.Flash_Sector_Size, count * W25Qxx_Info.Flash_Sector_Size);
// translate the reslut code here switch(result) { case W25QXX_OK: res = RES_OK; break;
case W25QXX_ERROR: res = RES_ERROR; break;
case W25QXX_BUSY: res = RES_NOTRDY; break;
case W25QXX_TIMEOUT: res = RES_ERROR; break; } return res;
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_SPIFLASH : // translate the arguments here for(UINT i = 0; i < count; i++) { W25Qxx_Erase_Block((sector + i) * W25Qxx_Info.Flash_Sector_Size); } result = W25Qxx_Write((uint8_t*)buff, sector * W25Qxx_Info.Flash_Sector_Size, count * W25Qxx_Info.Flash_Sector_Size);
// translate the reslut code here switch(result) { case W25QXX_OK: res = RES_OK; break;
case W25QXX_ERROR: res = RES_ERROR; break;
case W25QXX_BUSY: res = RES_NOTRDY; break;
case W25QXX_TIMEOUT: res = RES_ERROR; break; } return res;
DRESULT disk_ioctl( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void* buff /* Buffer to send/receive control data */ ) { DRESULT res = RES_OK;
switch(pdrv) { case DEV_SPIFLASH : switch(cmd) { case GET_SECTOR_COUNT://将驱动器上可用扇区的数目返回到buff指向的DWORD变量中 { *(DWORD*)buff = W25Qxx_Info.Flash_Sector_Count; break; } case GET_SECTOR_SIZE://将媒体的扇区大小返回到buff指向的WORD变量中 { *(WORD*)buff = W25Qxx_Info.Flash_Sector_Size; //类型是WORD的类型,每个扇区是4096的大小,这里同时还需要修改MAX_SS的值 break; } case GET_BLOCK_SIZE://将闪存介质的擦除块大小(以扇区为单位)返回到buff指向的DWORD变量中 { *(DWORD*)buff = 1; //每次擦除的大小是1个扇区,因为单位是扇区 break; } } // Process of the command for the RAM drive