STM32H750XB_RT-THREAD/0-Bootloader/H750-TWIN-QSPI-BOOTLOADER/User/flash/bsp_qspi_flash.c

336 lines
9.9 KiB
C
Raw Normal View History

2025-07-21 06:34:29 +00:00
/**
******************************************************************************
* @file bsp_qspi_flash.c
* @author fire
* @version V1.0
* @date 2019-xx-xx
* @brief qspi flash <EFBFBD>ײ<EFBFBD>Ӧ<EFBFBD>ú<EFBFBD><EFBFBD><EFBFBD>bsp
******************************************************************************
* @attention
*
* ʵ<EFBFBD><EFBFBD>ƽ̨:Ұ<EFBFBD><EFBFBD>STM32 H750 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD>̳ :http://www.firebbs.cn
* <EFBFBD>Ա<EFBFBD> :http://firestm32.taobao.com
*
******************************************************************************
*/
#include "./flash/bsp_qspi_flash.h"
QSPI_HandleTypeDef QSPIHandle;
/**
* @brief QSPI_FLASH<EFBFBD><EFBFBD><EFBFBD>ų<EFBFBD>ʼ<EFBFBD><EFBFBD>
* @param <EFBFBD><EFBFBD>
* @retval <EFBFBD><EFBFBD>
*/
void QSPI_FLASH_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* ʹ<><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);
HAL_QSPI_DeInit(&QSPIHandle);
/* QSPI_FLASH ģʽ<C4A3><CABD><EFBFBD><EFBFBD> */
QSPIHandle.Instance = QUADSPI;
/*<2A><><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>ʱ<EFBFBD><CAB1>Ϊ240/(1+1)=120MHz */
QSPIHandle.Init.ClockPrescaler = 1;
/*FIFO <20><>ֵΪ 4 <20><><EFBFBD>ֽ<EFBFBD>*/
QSPIHandle.Init.FifoThreshold = 1;
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
/*Flash<73><68>С32M<32>ֽڣ<D6BD>2^25<32><35><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡȨֵ25-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;
/*ʹ<><CAB9>˫<EFBFBD><CBAB><EFBFBD><EFBFBD>ģʽ*/
QSPIHandle.Init.DualFlash= QSPI_DUALFLASH_DISABLE;
HAL_QSPI_Init(&QSPIHandle);
/*<2A><>ʼ<EFBFBD><CABC>QSPI<50>ӿ<EFBFBD>*/
BSP_QSPI_Init();
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>QSPIΪ<EFBFBD>ڴ<EFBFBD>ӳ<EFBFBD><EFBFBD>ģʽ
* @retval QSPI<EFBFBD>ڴ<EFBFBD>״̬
*/
static uint32_t QSPI_EnableMemoryMappedMode(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* <20><><EFBFBD>ö<EFBFBD>ָ<EFBFBD><D6B8> */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INOUT_4BYTE_FAST_READ_CMD;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 6;
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><D3B3>ģʽ */
s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
s_mem_mapped_cfg.TimeOutPeriod = 0;
if (HAL_QSPI_MemoryMapped(hqspi, &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 uint32_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
/* ʹ<><CAB9>д<EFBFBD><D0B4><EFBFBD><EFBFBD> */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>λʹ<CEBB><CAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = RESET_MEMORY_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;
/* <20><><EFBFBD>͸<EFBFBD>λflash<73><68><EFBFBD><EFBFBD> */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* <20><>ѯ<EFBFBD>ȴ<EFBFBD>flash<73><68><EFBFBD><EFBFBD> */
if (QSPI_AutoPollingMemReady() != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>QSPI<EFBFBD><EFBFBD><EFBFBD>
* @retval QSPI<EFBFBD><EFBFBD><EFBFBD>״̬
*/
uint8_t BSP_QSPI_Init(void)
{
QSPI_CommandTypeDef s_command;
uint8_t value = 0X06;
/* ʹ<><CAB9>д<EFBFBD><D0B4><EFBFBD><EFBFBD> */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·ʹ<C2B7>ܵ<EFBFBD>״̬<D7B4>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8>IO2<4F><32>IO3<4F><33><EFBFBD><EFBFBD> */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = WRITE_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;
/* <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_Transmit(&QSPIHandle, &value,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() != QSPI_OK)
{
return QSPI_ERROR;
}
/* QSPI memory reset */
if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK)
{
return QSPI_ERROR;
}
QSPI_EnterFourBytesAddress();
/* Enable MemoryMapped mode */
if( QSPI_EnableMemoryMappedMode(&QSPIHandle) != QSPI_OK )
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>QSPI<EFBFBD><EFBFBD><EFBFBD>Ϊ4-byte<EFBFBD><EFBFBD>ַģʽ
* @param <EFBFBD><EFBFBD>
* @retval <EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬
*/
uint8_t QSPI_EnterFourBytesAddress(void)
{
QSPI_CommandTypeDef s_command;
/* Initialize the command */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_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;
/* ʹ<><CAB9>д<EFBFBD><D0B4><EFBFBD><EFBFBD> */
QSPI_WriteEnable();
/* <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><D4B6><EFBFBD>ѯģʽ<C4A3>ȴ<EFBFBD><C8B4><EFBFBD><E6B4A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
if (QSPI_AutoPollingMemReady() != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD>ʹ<EFBFBD>ܣ<EFBFBD><EFBFBD>ȴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч.
* @param QSPIHandle: QSPI<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @retval <EFBFBD><EFBFBD>
*/
static uint8_t QSPI_WriteEnable()
{
QSPI_CommandTypeDef sCommand;
QSPI_AutoPollingTypeDef s_config;
/* <20><><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD> */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = WRITE_ENABLE_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* <20><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD>ѯģʽ<C4A3>ȴ<EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD> */
s_config.Match = W25Q256JV_FSR_WREN;
s_config.Mask = W25Q256JV_FSR_WREN;
s_config.MatchMode = QSPI_MATCH_MODE_AND;
s_config.StatusBytesSize = 2;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sCommand.Instruction = READ_STATUS_REG1_CMD;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.NbData = 1;
if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SR<EFBFBD><EFBFBD><EFBFBD>ȴ<EFBFBD>EOP
* @param <EFBFBD><EFBFBD>
* @retval <EFBFBD><EFBFBD>
*/
static uint8_t QSPI_AutoPollingMemReady(void)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* <20><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD>ѯģʽ<C4A3>ȴ<EFBFBD><C8B4><EFBFBD><E6B4A2>׼<EFBFBD><D7BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
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 = 2;
s_config.Interval = 0x10;
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_QSPI_AutoPolling(&QSPIHandle, &s_command, &s_config,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/*********************************************END OF FILE**********************/