STM32H750XB_RT-THREAD/24-QSPI—读写串行FLASH(W25Q256)/双片FLASH读写(间接模式)/User/flash/bsp_qspi_flash.c
2025-07-21 14:34:29 +08:00

911 lines
26 KiB
C
Raw 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 H743 开发板
* 论坛 :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;
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/* 使能 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 BANK2时钟 */
QSPI_FLASH_BK2_IO0_CLK_ENABLE();
QSPI_FLASH_BK2_IO1_CLK_ENABLE();
QSPI_FLASH_BK2_IO2_CLK_ENABLE();
QSPI_FLASH_BK2_IO3_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);
HAL_QSPI_DeInit(&QSPIHandle);
/*!< 配置 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_BK2 引脚: IO0 */
GPIO_InitStruct.Pin = QSPI_FLASH_BK2_IO0_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_BK2_IO0_AF;
HAL_GPIO_Init(QSPI_FLASH_BK2_IO0_PORT, &GPIO_InitStruct);
/*!< 配置 QSPI_FLASH_BK2 引脚: IO1 */
GPIO_InitStruct.Pin = QSPI_FLASH_BK2_IO1_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_BK2_IO1_AF;
HAL_GPIO_Init(QSPI_FLASH_BK2_IO1_PORT, &GPIO_InitStruct);
/*!< 配置 QSPI_FLASH_BK2 引脚: IO2 */
GPIO_InitStruct.Pin = QSPI_FLASH_BK2_IO2_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_BK2_IO2_AF;
HAL_GPIO_Init(QSPI_FLASH_BK2_IO2_PORT, &GPIO_InitStruct);
/*!< 配置 QSPI_FLASH_BK2 引脚: IO3 */
GPIO_InitStruct.Pin = QSPI_FLASH_BK2_IO3_PIN;
GPIO_InitStruct.Alternate = QSPI_FLASH_BK2_IO3_AF;
HAL_GPIO_Init(QSPI_FLASH_BK2_IO3_PORT, &GPIO_InitStruct);
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_QSPI;
//QSPI freq = osc/PLL2M*PLL2N/PLL2R/ClockPrescaler+1
PeriphClkInitStruct.PLL2.PLL2M = 5;
PeriphClkInitStruct.PLL2.PLL2N = 144;
PeriphClkInitStruct.PLL2.PLL2P = 2;
PeriphClkInitStruct.PLL2.PLL2Q = 2;
PeriphClkInitStruct.PLL2.PLL2R = 3;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_2;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_PLL2;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
/* QSPI_FLASH 模式配置 */
QSPIHandle.Instance = QUADSPI;
/*二分频时钟为216/(1+1)=108MHz */
QSPIHandle.Init.ClockPrescaler = 1;
/*FIFO 阈值为 4 个字节*/
QSPIHandle.Init.FifoThreshold = 24;
/*采样移位半个周期*/
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
/*Flash大小为64M字节2^26所以取权值26-1=25*/
QSPIHandle.Init.FlashSize = 25;
/*片选高电平保持时间至少50ns对应周期数6*9.2ns =55.2ns*/
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE;
/*时钟模式选择模式0nCS为高电平片选释放CLK必须保持低电平*/
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
/*根据硬件连接选择第一片Flash*/
QSPIHandle.Init.FlashID = QSPI_FLASH_ID_2;
QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_ENABLE;
HAL_QSPI_Init(&QSPIHandle);
/*初始化QSPI接口*/
BSP_QSPI_Init();
}
/**
* @brief 初始化QSPI存储器
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Init(void)
{
QSPI_CommandTypeDef s_command;
uint8_t value = 0x06;
/* QSPI存储器复位 */
if (QSPI_ResetMemory() != QSPI_OK)
{
return QSPI_NOT_SUPPORTED;
}
//进入四字节模式(**
QSPI_EnterFourBytesAddress();
/* 使能写操作 */
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(W25Q256JV_SUBSECTOR_ERASE_MAX_TIME) != 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(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK)
{
return QSPI_ERROR;
}
return QSPI_OK;
}
/**
* @brief 从QSPI存储器中读取大量数据.
* @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;
if(Size == 0)
{
printf("BSP_QSPI_Read Size = 0");
return QSPI_OK;
}
/* 初始化读命令 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_CMD_4BYTE;
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 ReadAddr: 读取起始地址
* @param Size: 要读取的数据大小
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_FastRead(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
QSPI_CommandTypeDef s_command;
if(Size == 0)
{
printf("BSP_QSPI_FastRead Size = 0");
return QSPI_OK;
}
/* 初始化读命令 */
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存储器
* @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;
if(Size == 0)
{
printf("BSP_QSPI_Write Size = 0");
return QSPI_OK;
}
/* 计算写入地址和页面末尾之间的大小 */
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 = QUAD_INPUT_PAGE_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;
if(current_size == 0)
{
printf("BSP_QSPI_Write current_size = 0");
return QSPI_OK;
}
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 BlockAddress: 需要擦除的块地址
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress)
{
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 = 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;
}
//QSPI_FLASH_Wait_Busy();
/* 发送命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return QSPI_ERROR;
}
//QSPI_FLASH_Wait_Busy();
/* 配置自动轮询模式等待擦除结束 */
if (QSPI_AutoPollingMemReady(W25Q256JV_SUBSECTOR_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_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 复位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 = 2;
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 = 0x0000;
s_config.Mask = W25Q256JV_FSR_BUSY + (W25Q256JV_FSR_BUSY <<8);
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, 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_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.AddressMode = QSPI_ADDRESS_NONE;
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_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 = 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,GPIO_PIN_SET);
}
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**********************/