STM32H750XB_RT-THREAD/0-Bootloader/H750-TWIN-QSPI-BOOTLOADER/User/flash/bsp_qspi_flash.c
2025-07-21 14:34:29 +08:00

336 lines
9.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
******************************************************************************
* @file bsp_qspi_flash.c
* @author fire
* @version V1.0
* @date 2019-xx-xx
* @brief qspi flash 底层应用函数bsp
******************************************************************************
* @attention
*
* 实验平台:野火STM32 H750 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :http://firestm32.taobao.com
*
******************************************************************************
*/
#include "./flash/bsp_qspi_flash.h"
QSPI_HandleTypeDef QSPIHandle;
/**
* @brief QSPI_FLASH引脚初始化
* @param 无
* @retval 无
*/
void QSPI_FLASH_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 使能 QSPI 及 GPIO 时钟 */
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();
//设置引脚
/*!< 配置 QSPI_FLASH 引脚: 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);
/*!< 配置 QSPI_FLASH 引脚: 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);
/*!< 配置 QSPI_FLASH 引脚: 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);
/*!< 配置 QSPI_FLASH 引脚: 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);
/*!< 配置 QSPI_FLASH 引脚: 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);
/*!< 配置 SPI_FLASH_SPI 引脚: 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 模式配置 */
QSPIHandle.Instance = QUADSPI;
/*二分频时钟为240/(1+1)=120MHz */
QSPIHandle.Init.ClockPrescaler = 1;
/*FIFO 阈值为 4 个字节*/
QSPIHandle.Init.FifoThreshold = 1;
/*采样移位半个周期*/
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
/*Flash大小32M字节2^25所以取权值25-1=24*/
QSPIHandle.Init.FlashSize = 24;
/*片选高电平保持时间至少50ns对应周期数6*9.2ns =55.2ns*/
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;
/*时钟模式选择模式0nCS为高电平片选释放CLK必须保持低电平*/
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
/*根据硬件连接选择第一片Flash*/
QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1;
/*使能双闪存模式*/
QSPIHandle.Init.DualFlash= QSPI_DUALFLASH_DISABLE;
HAL_QSPI_Init(&QSPIHandle);
/*初始化QSPI接口*/
BSP_QSPI_Init();
}
/**
* @brief 配置QSPI为内存映射模式
* @retval QSPI内存状态
*/
static uint32_t QSPI_EnableMemoryMappedMode(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* 配置读指令 */
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;
/* 配置内存映射模式 */
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;
/* 使能写操作 */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 初始化复位使能命令 */
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;
/* 发送复位flash命令 */
if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 轮询等待flash就绪 */
if (QSPI_AutoPollingMemReady() != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 初始化QSPI存储器
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Init(void)
{
QSPI_CommandTypeDef s_command;
uint8_t value = 0X06;
/* 使能写操作 */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 设置四路使能的状态寄存器使能四通道IO2和IO3引脚 */
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;
/* 配置命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 传输数据 */
if (HAL_QSPI_Transmit(&QSPIHandle, &value,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 自动轮询模式等待存储器就绪 */
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 设置QSPI存储器为4-byte地址模式
* @param 无
* @retval 返回状态
*/
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;
/* 使能写操作 */
QSPI_WriteEnable();
/* 传输命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 自动轮询模式等待存储器就绪 */
if (QSPI_AutoPollingMemReady() != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 发送写入使能,等待它有效.
* @param QSPIHandle: QSPI句柄
* @retval 无
*/
static uint8_t QSPI_WriteEnable()
{
QSPI_CommandTypeDef sCommand;
QSPI_AutoPollingTypeDef s_config;
/* 启用写操作 */
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;
}
/* 配置自动轮询模式等待写启用 */
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 读取存储器的SR并等待EOP
* @param 无
* @retval 无
*/
static uint8_t QSPI_AutoPollingMemReady(void)
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* 配置自动轮询模式等待存储器准备就绪 */
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**********************/