You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

489 lines
16 KiB

2 days ago
/*
* bsp_quadspi_W25Q128.c
*
* Created on: Apr 25, 2021
* Author: Administrator
*
*
*
*
*
*/
#include <bsp_qspi_w25q128.h>
#include "quadspi.h"
/* 仅限本文件使用的函数 */
static void QSPI_W25Qx_Write_Enable(QSPI_HandleTypeDef *hqspi);
static uint8_t QSPI_W25Qx_AutoPollingMemRead(uint32_t Timeout);
static void QSPI_W25Qx_Enter(QSPI_HandleTypeDef *hqspi);
static void QSPI_W25Qx_Exit(QSPI_HandleTypeDef *hqspi);
/**
* : Flash状态并等待操作结束
* : Timeout
*
* : Flash的状态
* :
*
*
*/
static uint8_t QSPI_W25Qx_AutoPollingMemRead(uint32_t Timeout)
{
QSPI_CommandTypeDef s_command={0};
QSPI_AutoPollingTypeDef s_config={0};
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; //1线方式发送指令
s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/* 配置自动轮询模式 */
s_command.Instruction = READ_STATUS_REG1_CMD; //读取状态寄存器
s_command.AddressMode = QSPI_ADDRESS_NONE; //没有地址
s_command.DataMode = QSPI_DATA_1_LINE; //1线数据
s_command.DummyCycles = 0; //无空周期
/* 配置自动轮询寄存器(不断查询状态寄存器bit0,等待其为0) */
s_config.Match = 0x00; //等待其为0
s_config.Mask = W25Q128FV_FSR_BUSY; //状态寄存器bit0
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(&hqspi,&s_command,&s_config,Timeout) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
return FLASH_OK;
}
/**
* : FLASH的ID
* :
*
* : uint32_t
* :
* 1使SPI模式的指令
*
*/
uint32_t QSPI_W25Qx_ReadID(void)
{
uint32_t uiID;
QSPI_CommandTypeDef s_command = {0};
uint8_t buf[3];
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; //1线方式发送指令
s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/* 读取JEDEC ID */
s_command.Instruction = READ_JEDEC_ID_CMD; //读取ID命令: 0x9F
s_command.AddressMode = QSPI_ADDRESS_NONE; //没有地址
s_command.DataMode = QSPI_DATA_1_LINE; //1线数据
s_command.DummyCycles = 0; //无空周期
s_command.NbData = 3; //读取三个数据
/* 发送指令 */
if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 启动接收 */
if(HAL_QSPI_Receive(&hqspi,buf,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
uiID = (buf[0] << 16) | (buf[1] << 8) | buf[2];
return uiID;
}
/**
* : FLASH写使能
* : hqspi QSPI_HandleTypeDef句柄
*
* :
* :
* 1使SPI模式的指令
*
*/
static void QSPI_W25Qx_Write_Enable(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command = {0};
QSPI_AutoPollingTypeDef s_config={0};
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; //1线方式发送指令
//s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/* 写入使能配置 */
s_command.Instruction = WRITE_ENABLE_CMD; //写使能命令
s_command.AddressMode = QSPI_ADDRESS_NONE; //没有地址
s_command.DataMode = QSPI_DATA_NONE; //没有数据
s_command.DummyCycles = 0; //无空周期
s_command.NbData = 0; //空数据
/* 发送指令 */
if(HAL_QSPI_Command(hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 配置自动轮询模式等待操作完成 */
s_config.Match = W25Q128FV_FSR_WREN;
s_config.Mask = W25Q128FV_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(hqspi,&s_command,&s_config,HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
}
/**
* : FLASH的扇区4KB)
* : _uiSectorAddr: 4KB为单位的地址040968192
*
* :
* :
* 1
*
*/
void QSPI_W25Qx_EraseSector(uint32_t _SectorAddr)
{
QSPI_CommandTypeDef s_command = {0};
/* 写使能 */
QSPI_W25Qx_Write_Enable(&hqspi);
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; //1线方式发送指令
s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/* 擦除扇区配置 */
s_command.Instruction = SECTOR_ERASE_CMD; //扇区擦除指令
s_command.AddressMode = QSPI_ADDRESS_1_LINE; //1线地址方式
s_command.DataMode = QSPI_DATA_NONE; //没有数据
s_command.Address = _SectorAddr; //扇区的首地址,保证是4KB整数倍
s_command.DummyCycles = 0; //无空周期
/* 发送指令 */
if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 自动轮询模式等待编程结束 */
if(QSPI_W25Qx_AutoPollingMemRead(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
}
/**
* : QSPI将数据写入外部FALSH
* : _pBuf:
* _write_Addr: 0256512
* _write_Size: 1 ~ 256
* :
* :
* 1W25Q128FV仅仅支持SPI模式写入
*/
uint8_t QSPI_W25Qx_Write_Buffer(uint8_t *_pBuf,uint32_t _write_Addr,uint16_t _write_Size)
{
QSPI_CommandTypeDef s_command = {0};
/* 防止写入的大小超过256字节 */
if(_write_Size > W25Q128FV_PAGE_SIZE)
{
/* 进入断言,提示错误 */
user_Assert(__FILE__,__LINE__);
}
QSPI_W25Qx_Write_Enable(&hqspi); //写使能
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; //1线方式发送指令
s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/*写入序列配置 */
s_command.Instruction = QUAD_INPUT_PAGE_PROG_CMD; //24位四线快速写入指令
s_command.AddressMode = QSPI_ADDRESS_1_LINE; //1线地址方式
s_command.DataMode = QSPI_DATA_4_LINES; //4线数据方式
s_command.Address = _write_Addr; //写入数据的地址
s_command.NbData = _write_Size; //写入数据的大小
s_command.DummyCycles = 0; //无空周期
/* 发送指令 */
if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 启动传输 */
if(HAL_QSPI_Transmit(&hqspi,_pBuf,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 自动轮询模式等待编程结束 */
if(QSPI_W25Qx_AutoPollingMemRead(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
return 1;
}
/**
* : FLASH芯片进入QSPI模式
* : *hqspi: qspi句柄
*
* :
* :
*
*/
static void QSPI_W25Qx_Enter(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command = {0};
/* 配置FLASH进入QPSI模式 */
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; //1线方式发送指令
s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/* 写入序列配置 */
s_command.Instruction = ENTER_QPI_MODE_CMD; //进入QSPI模式
s_command.AddressMode = QSPI_ADDRESS_NONE; //无地址方式
s_command.DataMode = QSPI_DATA_NONE; //无数据方式
s_command.DummyCycles = 0; //0空闲状态周期
/* 发送指令 */
if(HAL_QSPI_Command(hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
}
/**
* : FLASH芯片退出QSPI模式
* : *hqspi: qspi句柄
*
* :
* :
*
*/
static void QSPI_W25Qx_Exit(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef s_command = {0};
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; //4线方式发送指令
s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/* 写入序列配置 */
s_command.Instruction = EXIT_QPI_MODE_CMD; //进入QSPI模式
s_command.AddressMode = QSPI_ADDRESS_NONE; //无地址方式
s_command.DataMode = QSPI_DATA_NONE; //无数据方式
s_command.DummyCycles = 0; //0空闲状态周期
/* 发送指令 */
if(HAL_QSPI_Command(hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
}
/**
* :
* : _pBuf:
* _read_Addr:
* _read_Size: W25Q128FV_PAGE_SIZE,
* :
* :
* 1SPI模式切换到QSPI模式SPI模式SPI模式
*/
void QSPI_W25Qx_Read_Buffer(uint8_t *_pBuf,uint32_t _read_Addr,uint32_t _read_Size)
{
QSPI_CommandTypeDef s_command = {0};
/* 进入QSPI模式 */
QSPI_W25Qx_Enter(&hqspi);
/* 开始从FLASH读取数据 */
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; //1线方式发送指令
s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/*读取序列配置 */
s_command.Instruction = QUAD_INOUT_FAST_READ_CMD; //24位四线快速写入指令
s_command.AddressMode = QSPI_ADDRESS_4_LINES; //4线地址方式
s_command.DataMode = QSPI_DATA_4_LINES; //4线数据方式
s_command.Address = _read_Addr; //写入数据的地址
s_command.NbData = _read_Size; //写入数据的大小
s_command.DummyCycles = 2; //两个空闲状态周期(4个时钟周期),结合时序理解
/* 发送指令 */
if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 读取数据 */
if(HAL_QSPI_Receive(&hqspi,_pBuf,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 退出QSPI模式 */
QSPI_W25Qx_Exit(&hqspi);
}
/**
* : Flash
* :
*
* : void
* :
*
*/
void QSPI_W25Qx_Reset_Memory()
{
QSPI_CommandTypeDef s_command = {0};
/* 基本配置 */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; //1线方式发送指令
s_command.AddressSize = QSPI_ADDRESS_24_BITS; //24位地址
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //无交替字节
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //W25Q128FV不支持DDR模式
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; //DDR模式,数据输出延迟
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //每次传输都发指令
/* 复位使能W25x */
s_command.Instruction = RESET_ENABLE_CMD; //复位使能命令
s_command.AddressMode = QSPI_ADDRESS_NONE; //没有地址
s_command.DataMode = QSPI_DATA_NONE; //没有数据
s_command.DummyCycles = 0; //无空周期
/* 发送复位使能命令 */
if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 发送复位命令 */
s_command.Instruction = RESET_MEMORY_CMD; //复位命令
/* 发送复位使能命令 */
if(HAL_QSPI_Command(&hqspi,&s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
/* 自动轮询模式等待等待完成 */
if(QSPI_W25Qx_AutoPollingMemRead(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
user_Assert(__FILE__,__LINE__);
}
}
/**
* :
* : file: __FILE__表示源代码文件名
* line: __LINE__表示源代码行号
* void
* :
* 1user_Assert(__FILE__,__LINE__);
*/
void user_Assert(char *file,uint32_t line)
{
printf("Wrong parameters value: file %s on line %d\r\n",file, (unsigned int)line);
/* 这是一个死循环,断言失败时程序会卡此处死机,以便于用户差错 */
if(line == 0)
{
return;
}
while(1)
{
}
}
/**
* : Flash状态并等待操作结束
* : Timeout
*
* : Flash的状态
* :
*
*
*/
void QSPI_W25Qx_EraseDownLoadFlash()
{
int i =0;
int count=CODE_FLASH_STORAGE_SIZE/4/1024;
for(i=0;i<=count;i++)
{
QSPI_W25Qx_EraseSector(i*4*1024);
// HAL_Delay(10);
}
i=10;
}