STM32H750XB_RT-THREAD/37-SDMMC—FatFs移植与读写测试/User/FATFS/drivers/fatfs_flash_qspi.c

818 lines
25 KiB
C
Raw Permalink Normal View History

2025-07-21 06:34:29 +00:00
/**
******************************************************************************
* @file bsp_xxx.c
* @author STMicroelectronics
* @version V1.0
* @date 2013-xx-xx
* @brief QSPI flash <EFBFBD>ײ<EFBFBD>Ӧ<EFBFBD>ú<EFBFBD><EFBFBD><EFBFBD>bsp
******************************************************************************
* @attention
*
* ʵ<EFBFBD><EFBFBD>ƽ̨:Ұ<EFBFBD><EFBFBD>STM32H743 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD>̳ :http://www.firebbs.cn
* <EFBFBD>Ա<EFBFBD> :http://firestm32.taobao.com
*
******************************************************************************
*/
#include "./fatfs/drivers/fatfs_flash_qspi.h"
#include "ff_gen_drv.h"
static volatile DSTATUS TM_FATFS_FLASH_SPI_Stat = STA_NOINIT; /* Physical drive status */
static uint8_t QSPI_Addr_Mode_Init(void);
QSPI_HandleTypeDef hqspi;
#define QSPIHandle hqspi
const Diskio_drvTypeDef QSPI_Driver =
{
TM_FATFS_FLASH_SPI_disk_initialize,
TM_FATFS_FLASH_SPI_disk_status,
TM_FATFS_FLASH_SPI_disk_read,
#if _USE_WRITE == 1
TM_FATFS_FLASH_SPI_disk_write,
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
TM_FATFS_FLASH_SPI_disk_ioctl,
#endif /* _USE_IOCTL == 1 */
};
/*******************************************************************************
* Function Name : SPI_FLASH_Init
* Description : Initializes the peripherals used by the SPI FLASH driver.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
DSTATUS TM_FATFS_FLASH_SPI_disk_initialize(BYTE lun)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/* ʹ<><CAB9> QSPI <20><> GPIO ʱ<><CAB1> */
QSPI_FLASH_CLK_ENABLE();
QSPI_FLASH_CLK_GPIO_ENABLE();
QSPI_FLASH_BK1_IO0_CLK_ENABLE();
QSPI_FLASH_BK1_IO1_CLK_ENABLE();
QSPI_FLASH_BK1_IO2_CLK_ENABLE();
QSPI_FLASH_BK1_IO3_CLK_ENABLE();
QSPI_FLASH_CS_GPIO_CLK_ENABLE();
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/*!< <20><><EFBFBD><EFBFBD> QSPI_FLASH <20><><EFBFBD><EFBFBD>: CLK */
GPIO_InitStruct.Pin = QSPI_FLASH_CLK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = QSPI_FLASH_CLK_GPIO_AF;
HAL_GPIO_Init(QSPI_FLASH_CLK_GPIO_PORT, &GPIO_InitStruct);
/*!< <20><><EFBFBD><EFBFBD> QSPI_FLASH <20><><EFBFBD><EFBFBD>: IO0 */
GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO0_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO0_AF;
HAL_GPIO_Init(QSPI_FLASH_BK1_IO0_PORT, &GPIO_InitStruct);
/*!< <20><><EFBFBD><EFBFBD> QSPI_FLASH <20><><EFBFBD><EFBFBD>: IO1 */
GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO1_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO1_AF;
HAL_GPIO_Init(QSPI_FLASH_BK1_IO1_PORT, &GPIO_InitStruct);
/*!< <20><><EFBFBD><EFBFBD> QSPI_FLASH <20><><EFBFBD><EFBFBD>: IO2 */
GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO2_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO2_AF;
HAL_GPIO_Init(QSPI_FLASH_BK1_IO2_PORT, &GPIO_InitStruct);
/*!< <20><><EFBFBD><EFBFBD> QSPI_FLASH <20><><EFBFBD><EFBFBD>: IO3 */
GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO3_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO3_AF;
HAL_GPIO_Init(QSPI_FLASH_BK1_IO3_PORT, &GPIO_InitStruct);
/*!< <20><><EFBFBD><EFBFBD> SPI_FLASH_SPI <20><><EFBFBD><EFBFBD>: NCS */
GPIO_InitStruct.Pin = QSPI_FLASH_CS_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_CS_GPIO_AF;
HAL_GPIO_Init(QSPI_FLASH_CS_GPIO_PORT, &GPIO_InitStruct);
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_QSPI;
PeriphClkInitStruct.PLL2.PLL2M = 5;
PeriphClkInitStruct.PLL2.PLL2N = 120;
PeriphClkInitStruct.PLL2.PLL2P = 1;
PeriphClkInitStruct.PLL2.PLL2Q = 1;
PeriphClkInitStruct.PLL2.PLL2R = 3;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_0;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_PLL2;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
/* QSPI_FLASH ģʽ<C4A3><CABD><EFBFBD><EFBFBD> */
QSPIHandle.Instance = QUADSPI;
/*<2A><><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>ʱ<EFBFBD><CAB1>Ϊ216/(1+1)=108MHz */
QSPIHandle.Init.ClockPrescaler = 1;
/*FIFO <20><>ֵΪ 4 <20><><EFBFBD>ֽ<EFBFBD>*/
QSPIHandle.Init.FifoThreshold = 4;
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
/*Flash<73><68>СΪ16M<36>ֽڣ<D6BD>2^25<32><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡȨֵ24-1=24*/
QSPIHandle.Init.FlashSize = 24;
/*Ƭѡ<C6AC>ߵ<EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><E4A3AC><EFBFBD><EFBFBD>50ns<6E><73><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>6*9.2ns =55.2ns*/
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;
/*ʱ<><CAB1>ģʽѡ<CABD><D1A1>ģʽ0<CABD><30>nCSΪ<53>ߵ<EFBFBD>ƽ<EFBFBD><C6BD>Ƭѡ<C6AC>ͷţ<CDB7>ʱ<EFBFBD><CAB1>CLK<4C><4B><EFBFBD><EFBFBD>ֵ͵<D6B5>ƽ*/
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
/*<2A><><EFBFBD><EFBFBD>Ӳ<EFBFBD><D3B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD>һƬFlash*/
QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1;
HAL_QSPI_Init(&QSPIHandle);
/*<2A><>ʼ<EFBFBD><CABC>QSPI<50>ӿ<EFBFBD>*/
BSP_QSPI_Init();
return TM_FATFS_FLASH_SPI_disk_status(NULL);
}
/**
* @brief Initializes the QSPI interface.
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_Init(void)
{
QSPI_CommandTypeDef s_command;
uint8_t value = W25Q256JV_FSR_QE;
/* QSPI memory reset */
if (QSPI_ResetMemory() != QSPI_OK)
{
return QSPI_NOT_SUPPORTED;
}
/* Enable write operations */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* Set status register for Quad Enable,the Quad IO2 and IO3 pins are enable */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = WRITE_STATUS_REG2_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 1;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Transmit the data */
if (HAL_QSPI_Transmit(&hqspi, &value, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* automatic polling mode to wait for memory ready */
if (QSPI_AutoPollingMemReady(W25Q256JV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
/* <20><><EFBFBD>õ<EFBFBD>ַģʽΪ 4 <20>ֽ<EFBFBD> */
if (QSPI_Addr_Mode_Init() != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>4<EFBFBD>ֽڵ<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ4<EFBFBD>ֽ<EFBFBD>
* @retval QSPI<EFBFBD><EFBFBD><EFBFBD>״̬
*/
static uint8_t QSPI_Addr_Mode_Init(void)
{
QSPI_CommandTypeDef s_command;
uint8_t reg;
/* <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>ȡ״̬<D7B4>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_STATUS_REG3_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 1;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
if (HAL_QSPI_Receive(&QSPIHandle, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* <20><><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD>ֵ */
if((reg & W25Q256FV_FSR_4ByteAddrMode) == 1) // 4<>ֽ<EFBFBD>ģʽ
{
return QSPI_OK;
}
else // 3<>ֽ<EFBFBD>ģʽ
{
/* <20><><EFBFBD>ý<EFBFBD><C3BD><EFBFBD> 4 <20>ֽڵ<D6BD>ַģʽ<C4A3><CABD><EFBFBD><EFBFBD> */
s_command.Instruction = Enter_4Byte_Addr_Mode_CMD;
s_command.DataMode = QSPI_DATA_NONE;
/* <20><><EFBFBD>ò<EFBFBD><C3B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* <20>Զ<EFBFBD><D4B6><EFBFBD>ѯģʽ<C4A3>ȴ<EFBFBD><C8B4><EFBFBD><E6B4A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
if (QSPI_AutoPollingMemReady(W25Q256JV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
}
/**
* @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
*/
uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
QSPI_CommandTypeDef s_command;
/* Initialize the read command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.Address = ReadAddr;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = Size;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Reception of the data */
if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_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
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
{
QSPI_CommandTypeDef s_command;
uint32_t end_addr, current_size, current_addr;
/* Calculation of the size between the write address and the end of the page */
current_addr = 0;
while (current_addr <= WriteAddr)
{
current_addr += W25Q256JV_PAGE_SIZE;
}
current_size = current_addr - WriteAddr;
/* Check if the size of the data is less than the remaining place in the page */
if (current_size > Size)
{
current_size = Size;
}
/* Initialize the adress variables */
current_addr = WriteAddr;
end_addr = WriteAddr + Size;
/* Initialize the program command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Perform the write page by page */
do
{
s_command.Address = current_addr;
s_command.NbData = current_size;
/* Enable write operations */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Transmission of the data */
if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait for end of program */
if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
{
return QSPI_ERROR;
}
/* Update the address and size variables for next page programming */
current_addr += current_size;
pData += current_size;
current_size = ((current_addr + W25Q256JV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q256JV_PAGE_SIZE;
} while (current_addr < end_addr);
return QSPI_OK;
}
/**
* @brief Erases the specified block of the QSPI memory.
* @param BlockAddress: Block address to erase
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress)
{
QSPI_CommandTypeDef s_command;
/* Initialize the erase command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = SECTOR_ERASE_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.Address = BlockAddress;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Enable write operations */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* Send the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait for end of erase */
if (QSPI_AutoPollingMemReady(W25Q256JV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief Erases the entire QSPI memory.
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_Erase_Chip(void)
{
QSPI_CommandTypeDef s_command;
/* Initialize the erase command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = CHIP_ERASE_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Enable write operations */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* Send the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait for end of erase */
if (QSPI_AutoPollingMemReady(W25Q256JV_BULK_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief Reads current status of the QSPI memory.
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_GetStatus(void)
{
QSPI_CommandTypeDef s_command;
uint8_t reg;
/* Initialize the read flag status register command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_STATUS_REG1_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 1;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Reception of the data */
if (HAL_QSPI_Receive(&QSPIHandle, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Check the value of the register */
if((reg & W25Q256JV_FSR_BUSY) != 0)
{
return QSPI_BUSY;
}
else
{
return QSPI_OK;
}
}
/**
* @brief Return the configuration of the QSPI memory.
* @param pInfo: pointer on the configuration structure
* @retval QSPI memory status
*/
uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo)
{
/* Configure the structure with the memory configuration */
pInfo->FlashSize = W25Q256JV_FLASH_SIZE;
pInfo->EraseSectorSize = W25Q256JV_SUBSECTOR_SIZE;
pInfo->EraseSectorsNumber = (W25Q256JV_FLASH_SIZE/W25Q256JV_SUBSECTOR_SIZE);
pInfo->ProgPageSize = W25Q256JV_PAGE_SIZE;
pInfo->ProgPagesNumber = (W25Q256JV_FLASH_SIZE/W25Q256JV_PAGE_SIZE);
return QSPI_OK;
}
///**
// * @brief Configure the QSPI in memory-mapped mode
// * @retval QSPI memory status
// */
//uint8_t BSP_QSPI_MemoryMappedMode(void)
//{
// QSPI_CommandTypeDef s_command;
// QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
// /* Configure the command for the read instruction */
// s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
// s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
// s_command.AddressMode = QSPI_ADDRESS_4_LINES;
// s_command.AddressSize = QSPI_ADDRESS_32_BITS;
// s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
// s_command.DataMode = QSPI_DATA_4_LINES;
// s_command.DummyCycles = W25Q256JV_DUMMY_CYCLES_READ_QUAD;
// s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
// s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
// s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
//
// /* Configure the memory mapped mode */
// s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_ENABLE;
// s_mem_mapped_cfg.TimeOutPeriod = 1;
//
// if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
// {
// return QSPI_ERROR;
// }
// return QSPI_OK;
//}
/**
* @brief This function reset the QSPI memory.
* @param hqspi: QSPI handle
* @retval None
*/
static uint8_t QSPI_ResetMemory()
{
QSPI_CommandTypeDef s_command;
/* Initialize the reset enable command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = RESET_ENABLE_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Send the command */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Send the reset memory command */
s_command.Instruction = RESET_MEMORY_CMD;
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait the memory is ready */
if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief This function send a Write Enable and wait it is effective.
* @param hqspi: QSPI handle
* @retval None
*/
static uint8_t QSPI_WriteEnable()
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* Enable write operations */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = WRITE_ENABLE_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* Configure automatic polling mode to wait for write enabling */
s_config.Match = W25Q256JV_FSR_WREN;
s_config.Mask = W25Q256JV_FSR_WREN;
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 1;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
s_command.Instruction = READ_STATUS_REG1_CMD;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.NbData = 1;
if (HAL_QSPI_AutoPolling(&QSPIHandle, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief This function read the SR of the memory and wait the EOP.
* @param hqspi: QSPI handle
* @param Timeout
* @retval None
*/
static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* Configure automatic polling mode to wait for memory ready */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_STATUS_REG1_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
s_config.Match = 0x00;
s_config.Mask = W25Q256JV_FSR_BUSY;
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 1;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_QSPI_AutoPolling(&QSPIHandle, &s_command, &s_config, Timeout) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief <EFBFBD><EFBFBD>ȡFLASH ID
* @param <EFBFBD><EFBFBD>
* @retval FLASH ID
*/
uint32_t QSPI_FLASH_ReadID(void)
{
QSPI_CommandTypeDef s_command;
uint32_t Temp = 0;
uint8_t pData[3];
/* Read JEDEC ID */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_JEDEC_ID_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 3;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* User may add here some code to deal with this error */
while(1)
{
}
}
if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* User may add here some code to deal with this error */
while(1)
{
}
}
Temp = pData[2] |( pData[1]<<8 )| ( pData[0]<<16 );
return Temp;
}
/**
* @brief <EFBFBD><EFBFBD>ȡFLASH Device ID
* @param <EFBFBD><EFBFBD>
* @retval FLASH Device ID
*/
uint32_t QSPI_FLASH_ReadDeviceID(void)
{
QSPI_CommandTypeDef s_command;
uint32_t Temp = 0;
uint8_t pData[3];
/*##-2-Read Device ID Test ###########################################*/
/* Read Manufacture/Device ID */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_ID_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = 0x000000;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 2;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* User may add here some code to deal with this error */
while(1)
{
}
}
if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* User may add here some code to deal with this error */
while(1)
{
}
}
Temp = pData[1] |( pData[0]<<8 ) ;
return Temp;
}
DSTATUS TM_FATFS_FLASH_SPI_disk_status(BYTE lun)
{
FLASH_DEBUG_FUNC();
if(1) /*<2A><><EFBFBD><EFBFBD>FLASH<53>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
{
return TM_FATFS_FLASH_SPI_Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */
}
else
{
return TM_FATFS_FLASH_SPI_Stat |= STA_NOINIT;
}
}
DRESULT TM_FATFS_FLASH_SPI_disk_ioctl(BYTE lun,BYTE cmd, void *buff)
{
FLASH_DEBUG_FUNC();
switch (cmd) {
case GET_SECTOR_COUNT:
*(DWORD * )buff = 4096; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2560*4096/1024/1024=10(MB) */
break;
case GET_SECTOR_SIZE : /*<2A><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>Ĵ<EFBFBD>С<EFBFBD><D0A1><EFBFBD>֣<EFBFBD>*/
*(WORD * )buff = 4096; /*flash<73><68>Сд<D0A1><D0B4>ԪΪҳ<CEAA><D2B3>256<35>ֽڣ<D6BD><DAA3>˴<EFBFBD>ȡ2ҳΪһ<CEAA><D2BB><EFBFBD><EFBFBD>д<EFBFBD><D0B4>λ*/
break;
case GET_BLOCK_SIZE : /* ͬʱ<CDAC><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˫<EFBFBD>֣<EFBFBD> */
*(DWORD * )buff = 1; /*flash<73><68>1<EFBFBD><31>sectorΪ<72><CEAA>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ*/
break;
case CTRL_TRIM:
break;
case CTRL_SYNC :
break;
}
return RES_OK;
}
DRESULT TM_FATFS_FLASH_SPI_disk_read(
BYTE lun,//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>豸ʱ<E8B1B8>õ<EFBFBD>(0...)
BYTE *buff,//<2F><><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD>
DWORD sector, //<2F><><EFBFBD><EFBFBD><EFBFBD>׵<EFBFBD>ַ
UINT count)//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(1..128)
{
FLASH_DEBUG_FUNC();
if ((TM_FATFS_FLASH_SPI_Stat & STA_NOINIT))
{
return RES_NOTRDY;
}
sector+=4096;//<2F><><EFBFBD><EFBFBD>ƫ<EFBFBD>ƣ<EFBFBD><C6A3>ⲿFlash<73>ļ<EFBFBD>ϵͳ<CFB5>ռ<EFBFBD><D5BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ⲿFlash<73><68><EFBFBD><EFBFBD>6M<36>ռ<EFBFBD>
BSP_QSPI_Read(buff, sector <<12, count<<12);
return RES_OK;
}
DRESULT TM_FATFS_FLASH_SPI_disk_write(
BYTE lun,//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>豸ʱ<E8B1B8>õ<EFBFBD>(0...)
const BYTE *buff,//<2F><><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD>
DWORD sector, //<2F><><EFBFBD><EFBFBD><EFBFBD>׵<EFBFBD>ַ
UINT count)//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(1..128)
{
uint32_t write_addr;
FLASH_DEBUG_FUNC();
sector+=4096;//<2F><><EFBFBD><EFBFBD>ƫ<EFBFBD>ƣ<EFBFBD><C6A3>ⲿFlash<73>ļ<EFBFBD>ϵͳ<CFB5>ռ<EFBFBD><D5BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ⲿFlash<73><68><EFBFBD><EFBFBD>4M<34>ռ<EFBFBD>
write_addr = sector<<12;
BSP_QSPI_Erase_Block(write_addr);
BSP_QSPI_Write((uint8_t*)buff,write_addr,4096);
return RES_OK;
}
/*********************************************END OF FILE**********************/