STM32H750XB_RT-THREAD/45-DCMI—OV2640摄像头实验/User/flash/bsp_qspi_flash.c
2025-07-21 14:34:29 +08:00

995 lines
28 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 2015-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;
static uint8_t QSPI_Addr_Mode_Init(void);
/**
* @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);
/* QSPI_FLASH 模式配置 */
QSPIHandle.Instance = QUADSPI;
/*二分频时钟为216/(1+1)=108MHz */
QSPIHandle.Init.ClockPrescaler = 1;
/*FIFO 阈值为 4 个字节*/
QSPIHandle.Init.FifoThreshold = 32;
/*采样移位半个周期*/
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
#if USE_DUAL_ExtFLASH
/*Flash大小为64M字节2^26所以取权值26-1=25*/
QSPIHandle.Init.FlashSize = 25;
#else
/*Flash大小为32M字节2^25所以取权值25-1=24*/
QSPIHandle.Init.FlashSize = 24;
#endif
/*片选高电平保持时间至少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;
HAL_QSPI_Init(&QSPIHandle);
/*初始化QSPI接口*/
BSP_QSPI_Init();
}
/**
* @brief 配置QSPI为内存映射模式
* @retval QSPI内存状态
*/
uint32_t QSPI_EnableMemoryMappedMode(void)
{
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* 配置读指令 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INOUT_FAST_READ_CMD_4BYTE;
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(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 初始化QSPI存储器
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Init(void)
{
QSPI_CommandTypeDef s_command;
uint8_t value = W25Q256JV_FSR_QE;
/* QSPI存储器复位 */
if (QSPI_ResetMemory() != QSPI_OK)
{
return QSPI_NOT_SUPPORTED;
}
/* 使能写操作 */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 设置四路使能的状态寄存器使能四通道IO2和IO3引脚 */
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;
/* 配置命令 */
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(W25Q256JV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
/* 配置地址模式为 4 字节 */
if (QSPI_Addr_Mode_Init() != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 检查地址模式不是4字节地址配置为4字节
* @retval QSPI存储器状态
*/
static uint8_t QSPI_Addr_Mode_Init(void)
{
QSPI_CommandTypeDef s_command;
uint8_t reg;
/* 初始化读取状态寄存器命令 */
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;
/* 配置命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 接收数据 */
if (HAL_QSPI_Receive(&QSPIHandle, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 检查寄存器的值 */
if((reg & W25Q256FV_FSR_4ByteAddrMode) == 1) // 4字节模式
{
return QSPI_OK;
}
else // 3字节模式
{
/* 配置进入 4 字节地址模式命令 */
s_command.Instruction = Enter_4Byte_Addr_Mode_CMD;
s_command.DataMode = QSPI_DATA_NONE;
/* 配置并发送命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 自动轮询模式等待存储器就绪 */
if (QSPI_AutoPollingMemReady(W25Q256JV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
}
/**
* @brief 从QSPI存储器中读取大量数据.
* @param pData: 指向要读取的数据的指针
* @param ReadAddr: 读取起始地址
* @param Size: 要读取的数据大小
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_FastRead(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
QSPI_CommandTypeDef s_command;
/* 初始化读命令 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INOUT_FAST_READ_CMD_4BYTE;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.Address = ReadAddr;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 6;
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;
/* 配置命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 接收数据 */
if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 从QSPI存储器中读取大量数据.
* @note 改指令只能使用在50MHz一下本配置下不好用
* @param pData: 指向要读取的数据的指针
* @param ReadAddr: 读取起始地址
* @param Size: 要读取的数据大小
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
QSPI_CommandTypeDef s_command;
/* 初始化读命令 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_CMD_4BYTE; //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;
/* 配置命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 接收数据 */
if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 将大量数据写入QSPI存储器
* @param pData: 指向要写入数据的指针
* @param WriteAddr: 写起始地址
* @param Size: 要写入的数据大小
* @retval QSPI存储器状态
*/
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;
/* 计算写入地址和页面末尾之间的大小 */
current_addr = 0;
while (current_addr <= WriteAddr)
{
current_addr += W25Q256JV_PAGE_SIZE;
}
current_size = current_addr - WriteAddr;
/* 检查数据的大小是否小于页面中的剩余位置 */
if (current_size > Size)
{
current_size = Size;
}
/* 初始化地址变量 */
current_addr = WriteAddr;
end_addr = WriteAddr + Size;
/* 初始化程序命令 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = EXT_QUAD_IN_FAST_PROG_CMD_4BYTE;
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;
/* 逐页执行写入 */
do
{
s_command.Address = current_addr;
s_command.NbData = current_size;
/* 启用写操作 */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 配置命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 传输数据 */
if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 配置自动轮询模式等待程序结束 */
if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
{
return QSPI_ERROR;
}
/* 更新下一页编程的地址和大小变量 */
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 擦除QSPI存储器的指定扇区
* @param SectorAddress: 需要擦除的扇区地址
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Erase_Sector(uint32_t SectorAddress)
{
QSPI_CommandTypeDef s_command;
/* 初始化擦除命令 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = SECTOR_ERASE_CMD_4BYTE;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.Address = SectorAddress;
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 (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 发送命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 配置自动轮询模式等待擦除结束 */
if (QSPI_AutoPollingMemReady(W25Q256JV_SECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 擦除QSPI存储器的指定块单块大小32k
* @param BlockAddress: 需要擦除的块地址
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Erase_Block32(uint32_t BlockAddress)
{
QSPI_CommandTypeDef s_command;
/* 初始化擦除命令 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = BLOCK32_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;
/* 启用写操作 */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 发送命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 配置自动轮询模式等待擦除结束 */
if (QSPI_AutoPollingMemReady(W25Q256JV_SECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 擦除QSPI存储器的指定块单块大小64k
* @param BlockAddress: 需要擦除的块地址
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Erase_Block64(uint32_t BlockAddress)
{
QSPI_CommandTypeDef s_command;
/* 初始化擦除命令 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = BLOCK64_ERASE_CMD_4BYTE;
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;
/* 启用写操作 */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 发送命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 配置自动轮询模式等待擦除结束 */
if (QSPI_AutoPollingMemReady(W25Q256JV_SECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 擦除整个QSPI存储器
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Erase_Chip(void)
{
QSPI_CommandTypeDef s_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;
/* 启用写操作 */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 发送命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 配置自动轮询模式等待擦除结束 */
if (QSPI_AutoPollingMemReady(W25Q256JV_BULK_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 读取QSPI存储器的当前状态
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_GetStatus(void)
{
QSPI_CommandTypeDef s_command;
uint8_t reg;
/* 初始化读取状态寄存器命令 */
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;
/* 配置命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 接收数据 */
if (HAL_QSPI_Receive(&QSPIHandle, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 检查寄存器的值 */
if((reg & W25Q256JV_FSR_BUSY) != 0)
{
return QSPI_BUSY;
}
else
{
return QSPI_OK;
}
}
/**
* @brief 返回QSPI存储器的配置
* @param pInfo: 在配置结构上的指针
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo)
{
/* 配置存储器配置结构 */
pInfo->FlashSize = W25Q256JV_FLASH_SIZE;
pInfo->EraseSectorSize = W25Q256JV_SECTOR_SIZE;
pInfo->EraseSectorsNumber = (W25Q256JV_FLASH_SIZE/W25Q256JV_SECTOR_SIZE);
pInfo->ProgPageSize = W25Q256JV_PAGE_SIZE;
pInfo->ProgPagesNumber = (W25Q256JV_FLASH_SIZE/W25Q256JV_PAGE_SIZE);
return QSPI_OK;
}
/**
* @brief 复位QSPI存储器。
* @param QSPIHandle: QSPI句柄
* @retval 无
*/
static uint8_t QSPI_ResetMemory()
{
QSPI_CommandTypeDef s_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;
/* 发送命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 发送复位存储器命令 */
s_command.Instruction = RESET_MEMORY_CMD;
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
/* 配置自动轮询模式等待存储器就绪 */
if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 发送写入使能,等待它有效.
* @param QSPIHandle: QSPI句柄
* @retval 无
*/
static uint8_t QSPI_WriteEnable()
{
QSPI_CommandTypeDef s_command;
QSPI_AutoPollingTypeDef s_config;
/* 启用写操作 */
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;
}
/* 配置自动轮询模式等待写启用 */
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 读取存储器的SR并等待EOP
* @param QSPIHandle: QSPI句柄
* @param Timeout 超时
* @retval 无
*/
static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout)
{
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 = 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 读取FLASH ID
* @param 无
* @retval FLASH ID
*/
uint32_t QSPI_FLASH_ReadID(void)
{
QSPI_CommandTypeDef s_command;
uint32_t Temp = 0;
uint8_t pData[3];
/* 读取JEDEC ID */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_JEDEC_ID_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
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(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* 用户可以在这里添加一些代码来处理这个错误 */
while(1)
{
}
}
if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* 用户可以在这里添加一些代码来处理这个错误 */
while(1)
{
}
}
Temp = ( pData[2] | pData[1]<<8 )| ( pData[0]<<16 );
return Temp;
}
/**
* @brief 读取FLASH Device ID
* @param 无
* @retval FLASH Device ID
*/
uint32_t QSPI_FLASH_ReadDeviceID(void)
{
QSPI_CommandTypeDef s_command;
uint32_t Temp = 0;
uint8_t pData[3];
/*##-2-读取设备ID测试 ###########################################*/
/* 读取制造/设备 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(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* 用户可以在这里添加一些代码来处理这个错误 */
while(1)
{
}
}
if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* 用户可以在这里添加一些代码来处理这个错误 */
while(1)
{
}
}
Temp = pData[1] |( pData[0]<<8 ) ;
return Temp;
}
/**
* @brief 读取ReadStatusReg
* @param 无
* @retval ReadStatusReg
*/
uint32_t QSPI_FLASH_ReadStatusReg(uint8_t reg)
{
QSPI_CommandTypeDef s_command;
uint32_t Temp = 0;
uint8_t pData[10];
/* 读取制造/设备 ID */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
if(reg == 1)
s_command.Instruction = READ_STATUS_REG1_CMD;
else if(reg == 2)
s_command.Instruction = READ_STATUS_REG2_CMD;
else if(reg == 3)
s_command.Instruction = READ_STATUS_REG3_CMD;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_32_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 = 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)
{
printf("something wrong ....\r\n");
/* 用户可以在这里添加一些代码来处理这个错误 */
while(1)
{
}
}
if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* 用户可以在这里添加一些代码来处理这个错误 */
while(1)
{
}
}
//单flash时读取的字节数为pData[0]pData[1]
//Temp = pData[0] |( pData[1]<<8 ) ;
//双flash时读取的字节数为pData[0]pData[2]
//Temp = pData[1] |( pData[0]<<8 ) ;
Temp = pData[0] ;
return Temp;
}
/**
* @brief 读取ReadStatusReg
* @param 无
* @retval ReadStatusReg
*/
uint32_t QSPI_FLASH_WriteStatusReg(uint8_t reg,uint8_t regvalue)
{
QSPI_CommandTypeDef s_command;
/* 使能写操作 */
if (QSPI_WriteEnable() != QSPI_OK)
{
return QSPI_ERROR;
}
/* 读取制造/设备 ID */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
if(reg == 1)
s_command.Instruction = WRITE_STATUS_REG1_CMD;
else if(reg == 2)
s_command.Instruction = WRITE_STATUS_REG2_CMD;
else if(reg == 3)
s_command.Instruction = WRITE_STATUS_REG3_CMD;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AddressSize = QSPI_ADDRESS_8_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 = 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)
{
printf("something wrong ....\r\n");
/* 用户可以在这里添加一些代码来处理这个错误 */
while(1)
{
}
}
if (HAL_QSPI_Transmit(&QSPIHandle, &regvalue, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("something wrong ....\r\n");
/* 用户可以在这里添加一些代码来处理这个错误 */
while(1)
{
}
}
/* 自动轮询模式等待存储器就绪 */
if (QSPI_AutoPollingMemReady(W25Q256JV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
void QSPI_Set_WP_High(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStruct;
__GPIOF_CLK_ENABLE();
/*选择要控制的GPIO引脚*/
GPIO_InitStruct.Pin = GPIO_PIN_7;
/*设置引脚的输出类型为推挽输出*/
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
/*设置引脚为上拉模式*/
GPIO_InitStruct.Pull = GPIO_PULLUP;
/*设置引脚速率为高速 */
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
/*调用库函数使用上面配置的GPIO_InitStructure初始化GPIO*/
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOF,GPIO_PIN_7,1);
}
void QSPI_Set_WP_TO_QSPI_IO(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStruct;
QSPI_FLASH_BK1_IO2_CLK_ENABLE();
//设置引脚
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
/*!< 配置 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);
}
/*********************************************END OF FILE**********************/