代码地址
夕阳武士/H750_W25QXXhttps://gitee.com/wangchief/H750_W25QXX
1、为什么要制作stlder算法
????????我们使用的是正点原子的H750核心板进行开发,H750的内部flash只有128k,无法满足比较大型程序的开发。H750提供了QSPI接口,我们可以通过QSPI接口访问外部的FLASH来扩展芯片的FLASH内容。在程序下载及调试过程中需要使用到stldr算法的实现。
2、实现步骤
- 实现在128kb内部flash基础上进行QSPI接口访问FLASH的程序开发和验证。
- 打包制作stlder算法,实现对外部flash的访问。
- 实现整体程序在外部flash的运行
- 通过bootloader来实现程序的跳转。
3、本章内容
????????本章节实现上述不走 ,验证128k内部flash内QSPI接口对外部W25QXX的访问。
3.1开发硬件环境
- ? ? ? ? 正点原子H750核心板
- ? ? ? ? 正点原子北极星底板
3.2软件开发环境
- STM32CubeIDE 1.90
- STM32CubeMX 6.5
- STM32Cube_FW_H7 V1.10.0
3.2工程创建
3.3?Cubemx配置
?
?3.4?驱动开发
? ? ? ? 设计编写bsp_w25qxx.c和bsp_w25qxx.h两个文件实现对W25QXX系列QSPI访问的支持,目前手头只有W25Q64芯片,后续驱动对其他型号进行支持完善。
? ? ? ? 对外接口
函数? ? ? ? ? ? ?? | 说明 | bsp_w25qxx_Init | 初始化w25qxx | bsp_w25qxx_Read | 读取w25qxx | bsp_w25qxx_EraseSector | 擦除w25qxx的一个扇区(4k) | bsp_w25qxx_EraseBlock | 擦除w25qxx的一个块(64k) | bsp_w25qxx_EraseChip | 擦除整片w25qxx | bsp_w25qxx_Write | 写入w25qxx | bsp_w25qxx_MemoryMapedEnter | 进入内存映射模式 |
?内部接口
函数? | 说明 | bsp_w25qxx_AutoPollingNotBusy | 阻塞方式等待W25QXX不繁忙 | bsp_w25qxx_AutoPollingWriteEnable | 阻塞方式等待W25QXX写使能 | bsp_w25qxx_Reset | 软件复位W25QXX | bsp_w25qxx_GetID | 获取芯片的ID | bsp_w25qxx_GetUID | 获取芯片的UID | bsp_w25qxx_WriteEnable | 写使能 | EndianSwap | 大小端转换 | bsp_w25qxx_WriteStatusReg | 写单个状态寄存器 | bsp_w25qxx_ReadStatusReg | 读取单个状态寄存器 | bsp_w25qxx_GetStatusRegs | 获取3个状态寄存器 |
#ifndef __BSP_W25QXX_H__
#define __BSP_W25QXX_H__
/***********************************************************************************
全局变量
***********************************************************************************/
#include "main.h"
/***********************************************************************************
命令宏定义
***********************************************************************************/
#define CMD_ENABLE_RESET 0x66
#define CMD_RESET 0x99
#define CMD_GET_ID 0x9F
#define CMD_GET_UID 0x4B
#define CMD_WRITE_ENABLE 0x06
#define CMD_READ 0xEB
#define CMD_WRITE 0x32
#define CMD_ERASE_SECTOR 0x20
#define CMD_ERASE_BLOCK 0xD8
#define CMD_ERASE_CHIP 0xC7
#define CMD_GET_REG1 0x05
#define CMD_GET_REG2 0x35
#define CMD_GET_REG3 0x15
#define CMD_SET_REG1 0x01
#define CMD_SET_REG2 0x31
#define CMD_SET_REG3 0x11
/***********************************************************************************
函数声明
***********************************************************************************/
extern uint8_t bsp_w25qxx_Init();
extern uint8_t bsp_w25qxx_Read(uint32_t addr , uint8_t*buff , uint32_t len);
extern uint8_t bsp_w25qxx_EraseSector(uint32_t addr);
extern uint8_t bsp_w25qxx_EraseBlock(uint32_t addr);
extern uint8_t bsp_w25qxx_EraseChip();
extern uint8_t bsp_w25qxx_Write(uint32_t addr , uint8_t*buff , uint32_t len);
extern uint8_t bsp_w25qxx_MemoryMapedEnter();
#endif
/***********************************************************************************
头文件
***********************************************************************************/
#include "bsp_w25qxx.h"
#include "string.h"
/***********************************************************************************
宏定义
***********************************************************************************/
#define DEBUG_ENABLE
/***********************************************************************************
全局变量
***********************************************************************************/
extern QSPI_HandleTypeDef hqspi;
uint32_t ChipID;
uint64_t ChipUID;
uint8_t StatusReg[3] ={0};
/***********************************************************************************
函数声明
***********************************************************************************/
static uint8_t bsp_w25qxx_AutoPollingNotBusy();
static uint8_t bsp_w25qxx_AutoPollingWriteEnable();
static uint8_t bsp_w25qxx_Reset();
static uint8_t bsp_w25qxx_GetID();
static uint8_t bsp_w25qxx_GetUID();
static uint8_t bsp_w25qxx_WriteEnable();
static void EndianSwap(uint8_t* pdata , uint8_t len);
static uint8_t bsp_w25qxx_WriteStatusReg(uint8_t regindex , uint8_t data);
static uint8_t bsp_w25qxx_ReadStatusReg(uint8_t regindex , uint8_t* data);
static int8_t bsp_w25qxx_GetStatusRegs();
/***********************************************************************************
全局函数
***********************************************************************************/
/**
***************************************************
* @brief bsp_w25qxx_Init
* @note 初始化w25qxx芯片
* 进行芯片复位,ID读取,UID读取
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
uint8_t bsp_w25qxx_Init()
{
//复位芯片
if(bsp_w25qxx_Reset() != 0)
return 1;
//获取芯片ID信息
if(bsp_w25qxx_GetID() != 0)
return 1;
//获取芯片UID信息
if(bsp_w25qxx_GetUID() != 0)
return 1;
//使能QSPI模式 STATUS REG2 的QE写为1
if(bsp_w25qxx_WriteStatusReg(2 , 0x02) != 0)
return 1;
//DRV 100% WPS = 0
if(bsp_w25qxx_WriteStatusReg(3 , 0) != 0)
return 1;
//获取状态寄存器
if(bsp_w25qxx_GetStatusRegs() != 0)
return 1;
return 0;
}
/**
***************************************************
* @brief bsp_w25qxx_Read
* @note 读取芯片数据
* @para
* addr 读取地址
* buff 存放缓冲
* len 读取长度
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
uint8_t bsp_w25qxx_Read(uint32_t addr , uint8_t*buff , uint32_t len)
{
QSPI_CommandTypeDef command = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*24位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
command.Instruction = CMD_READ; /*读取数据*/
command.DummyCycles = 6; /*6个空周期*/
command.AddressMode = QSPI_ADDRESS_4_LINES; /*4地址信息*/
command.DataMode = QSPI_DATA_4_LINES; /*4线数据*/
command.NbData = len; /*读取数据大小 */
command.Address = addr; /*读取地址 */
/* 发送读取命令 */
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
/* 等待读取完成 */
if (HAL_QSPI_Receive(&hqspi, buff, HAL_MAX_DELAY) != HAL_OK)
return 1;
return 0;
}
/**
***************************************************
* @brief bsp_w25qxx_EraseSector
* @note 擦除4k数据
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
uint8_t bsp_w25qxx_EraseSector(uint32_t addr)
{
QSPI_CommandTypeDef command = {0};
//WEL使能
if(bsp_w25qxx_WriteEnable() != 0)
return 1;
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*24位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
command.Instruction = CMD_ERASE_SECTOR; /*擦除sector 4k*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_1_LINE; /*1地址信息*/
command.DataMode = QSPI_DATA_NONE; /*0线数据*/
command.NbData = 0; /*数据*/
command.Address = addr; /*地址 */
//发送命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//等待不繁忙,即操作完成
return bsp_w25qxx_AutoPollingNotBusy();
}
/**
***************************************************
* @brief bsp_w25qxx_EraseBlock
* @note 擦除64k数据
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
uint8_t bsp_w25qxx_EraseBlock(uint32_t addr)
{
QSPI_CommandTypeDef command = {0};
//WEL使能
if(bsp_w25qxx_WriteEnable() != 0)
return 1;
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*24位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
command.Instruction = CMD_ERASE_BLOCK; /*擦除block 64k*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_1_LINE; /*1地址信息*/
command.DataMode = QSPI_DATA_NONE; /*0线数据*/
command.NbData = 0; /*数据*/
command.Address = addr; /*地址 */
//发送命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//等待不繁忙,即操作完成
return bsp_w25qxx_AutoPollingNotBusy();
}
/**
***************************************************
* @brief bsp_w25qxx_EraseChip
* @note 正片擦除
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
uint8_t bsp_w25qxx_EraseChip()
{
QSPI_CommandTypeDef command = {0};
//WEL使能
if(bsp_w25qxx_WriteEnable() != 0)
return 1;
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*24位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
command.Instruction = CMD_ERASE_CHIP; /*擦除chip*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_NONE; /*无地址信息*/
command.DataMode = QSPI_DATA_NONE; /*0线数据*/
command.NbData = 0; /*数据*/
//发送命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//等待不繁忙,即操作完成
return bsp_w25qxx_AutoPollingNotBusy();
}
/**
***************************************************
* @brief bsp_w25qxx_Write
* @note 写入芯片数据,最大写入1页256个数据,大于256,从头写
* @para
* addr 写入地址
* buff 写入数据缓冲区
* len 写入长度
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
uint8_t bsp_w25qxx_Write(uint32_t addr , uint8_t*buff , uint32_t len)
{
QSPI_CommandTypeDef command = {0};
//WEL使能
if(bsp_w25qxx_WriteEnable() != 0)
return 1;
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*24位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD; /*只发送一次*/
command.Instruction = CMD_WRITE; /*写入数据*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_1_LINE; /*1地址信息*/
command.DataMode = QSPI_DATA_4_LINES; /*4线数据*/
command.NbData = len; /*数据*/
command.Address = addr; /*地址 */
//发送写命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//写数据
if (HAL_QSPI_Transmit(&hqspi, buff, HAL_MAX_DELAY) != HAL_OK)
return 1;
return bsp_w25qxx_AutoPollingNotBusy();
}
/**
***************************************************
* @brief bsp_w25qxx_MemoryMapedEnter
* @note QSPI进入内存映射模式,地址为0x90000000
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
uint8_t bsp_w25qxx_MemoryMapedEnter()
{
QSPI_CommandTypeDef command = {0};
QSPI_MemoryMappedTypeDef mappedcfg = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /* 32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输都发指令 */
command.Instruction = CMD_READ; /* 快速读取命令 */
command.AddressMode = QSPI_ADDRESS_4_LINES; /* 4个地址线 */
command.DataMode = QSPI_DATA_4_LINES; /* 4个数据线 */
command.DummyCycles = 6; /* 空周期 */
/* 关闭溢出计数 */
mappedcfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
mappedcfg.TimeOutPeriod = 0;
if (HAL_QSPI_MemoryMapped(&hqspi, &command, &mappedcfg) != HAL_OK)
return 1;
return 0;
}
/***********************************************************************************
局部函数
***********************************************************************************/
/**
***************************************************
* @brief EndianSwap
* @note 数据大小端转换
* @para
* padat 指向待转换的数据
* len 数据为几字节
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static void EndianSwap(uint8_t* pdata , uint8_t len)
{
uint8_t temp = 0;
for(uint8_t i=0;i<len/2;i++)
{
temp = pdata[i];
pdata[i] = pdata[len-i-1];
pdata[len-i-1] = temp;
}
}
/**
***************************************************
* @brief bsp_w25qxx_AutoPollingNotBusy
* @note 等待BUSY信号
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static uint8_t bsp_w25qxx_AutoPollingNotBusy()
{
QSPI_CommandTypeDef command = {0};
QSPI_AutoPollingTypeDef config = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /* 32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输都发指令 */
command.Instruction = CMD_GET_REG1; /* 读取状态命令 */
command.AddressMode = QSPI_ADDRESS_NONE; /* 无需地址 */
command.DataMode = QSPI_DATA_1_LINE; /* 1线数据 */
command.DummyCycles = 0; /* 无需空周期 */
/* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
config.Match = 0x00;
config.Mask = 0x01;
config.Interval = 0x10;
config.StatusBytesSize = 1;
config.MatchMode = QSPI_MATCH_MODE_AND;
config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_QSPI_AutoPolling(&hqspi, &command, &config, HAL_MAX_DELAY) != HAL_OK)
return 1;
return 0;
}
/**
***************************************************
* @brief bsp_w25qxx_AutoPollingWriteEnable
* @note 等待WEL信号
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static uint8_t bsp_w25qxx_AutoPollingWriteEnable()
{
QSPI_CommandTypeDef command = {0};
QSPI_AutoPollingTypeDef config = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /* 32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输都发指令 */
command.Instruction = CMD_GET_REG1; /* 读取状态命令 */
command.AddressMode = QSPI_ADDRESS_NONE; /* 无需地址 */
command.DataMode = QSPI_DATA_1_LINE; /* 1线数据 */
command.DummyCycles = 0; /* 无需空周期 */
/* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
config.Mask = 0xFD;
config.Match = 0x01;
config.MatchMode = QSPI_MATCH_MODE_OR;
config.StatusBytesSize = 1;
config.Interval = 0x10;
config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_QSPI_AutoPolling(&hqspi, &command, &config, HAL_MAX_DELAY) != HAL_OK)
return 1;
return 0;
}
/**
***************************************************
* @brief bsp_w25qxx_Reset
* @note 复位芯片,66和99命令必须连续发送,发送完毕后至少需要等待30us
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static uint8_t bsp_w25qxx_Reset()
{
QSPI_CommandTypeDef command = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
command.Instruction = CMD_ENABLE_RESET; /*使能重启*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_NONE; /*无地址信息*/
command.DataMode = QSPI_DATA_NONE; /*无数据信息*/
command.NbData = 0; /*写数据大小 */
command.Address = 0; /*写入地址 */
/*复位使能*/
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
/*复位*/
command.Instruction = CMD_RESET;
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
return 0;
}
/**
***************************************************
* @brief bsp_w25qxx_GetID
* @note 获取芯片的ID信息,识别芯片类型
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static uint8_t bsp_w25qxx_GetID()
{
QSPI_CommandTypeDef command = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
command.Instruction = CMD_GET_ID; /*获取芯片ID*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_NONE; /*无地址信息*/
command.DataMode = QSPI_DATA_1_LINE; /*无数据信息*/
command.NbData = 3; /*写数据大小 */
command.Address = 0; /*写入地址 */
//发送获取ID命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//获取ID
if (HAL_QSPI_Receive(&hqspi, (uint8_t *)&ChipID, HAL_MAX_DELAY) != HAL_OK)
return 1;
//进行大小端转换
EndianSwap((uint8_t *)&ChipID , 3);
return 0;
}
/**
***************************************************
* @brief bsp_w25qxx_GetUID
* @note 识别芯片的UID编码
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static uint8_t bsp_w25qxx_GetUID()
{
QSPI_CommandTypeDef command = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
command.Instruction = CMD_GET_UID; /*获取芯片UID*/
command.DummyCycles = 4; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_NONE; /*无地址信息*/
command.DataMode = QSPI_DATA_1_LINE; /*无数据信息*/
command.NbData = 8; /*写数据大小 */
command.Address = 0; /*写入地址 */
//发送命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//接收UID信息
if (HAL_QSPI_Receive(&hqspi, (uint8_t *)&ChipUID, HAL_MAX_DELAY) != HAL_OK)
return 1;
//大小端抓换
EndianSwap((uint8_t *)&ChipUID , 8);
return 0;
}
/**
***************************************************
* @brief bsp_w25qxx_WriteEnable
* @note 使能W25QXX的写功能,使能状态寄存器的WEL位
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static uint8_t bsp_w25qxx_WriteEnable()
{
QSPI_CommandTypeDef command = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
command.Instruction = CMD_WRITE_ENABLE; /*写使能*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_NONE; /*无地址信息*/
command.DataMode = QSPI_DATA_NONE; /*无数据信息*/
command.NbData = 0; /*写数据大小 */
command.Address = 0; /*写入地址 */
//发送命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//等待WEL位置位
return bsp_w25qxx_AutoPollingWriteEnable();
}
/**
***************************************************
* @brief bsp_w25qxx_WriteStatusReg
* @note 使能W25QXX的QSPI模式
* @para
regindex 写第几个
data 写入内容
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static uint8_t bsp_w25qxx_WriteStatusReg(uint8_t regindex , uint8_t data)
{
//使能WEL
if(bsp_w25qxx_WriteEnable() != 0)
return 1;
QSPI_CommandTypeDef command = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
/* 写序列配置 */
if(regindex == 1)
command.Instruction = CMD_SET_REG1; /*写status reg1*/
else if(regindex == 2)
command.Instruction = CMD_SET_REG2; /*写status reg2*/
else if(regindex == 3)
command.Instruction = CMD_SET_REG3; /*写status reg3*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_NONE; /*无地址信息*/
command.DataMode = QSPI_DATA_1_LINE; /*无数据信息*/
command.NbData = 1; /*写数据大小 */
command.Address = 0; /*写入地址 */
//发送配置命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//发送配置信息
if(HAL_QSPI_Transmit(&hqspi, &data, HAL_MAX_DELAY) != HAL_OK)
return 1;
//等待notbusy
return bsp_w25qxx_AutoPollingNotBusy();
}
/**
***************************************************
* @brief bsp_w25qxx_ReadStatusReg
* @note 读取status寄存器
* @para
* regindex 读第几个
* data 存放读取到的数据
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static uint8_t bsp_w25qxx_ReadStatusReg(uint8_t regindex , uint8_t* data)
{
QSPI_CommandTypeDef command = {0};
command.InstructionMode = QSPI_INSTRUCTION_1_LINE; /*1线方式发送指令 */
command.AddressSize = QSPI_ADDRESS_24_BITS; /*32位地址 */
command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /*无交替字节 */
command.DdrMode = QSPI_DDR_MODE_DISABLE; /*W25Q256JV不支持DDR */
command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /*DDR模式,数据输出延迟 */
command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /*每次发送命令 */
if(regindex == 1)
command.Instruction = CMD_GET_REG1; /*写status reg1*/
else if(regindex == 2)
command.Instruction = CMD_GET_REG2; /*写status reg2*/
else if(regindex == 3)
command.Instruction = CMD_GET_REG3; /*写status reg3*/
command.DummyCycles = 0; /*不需要空周期*/
command.AddressMode = QSPI_ADDRESS_NONE; /*无地址信息*/
command.DataMode = QSPI_DATA_1_LINE; /*无数据信息*/
command.NbData = 1; /*数据大小 */
command.Address = 0; /*入地址 */
//发送读取命令
if (HAL_QSPI_Command(&hqspi, &command, HAL_MAX_DELAY) != HAL_OK)
return 1;
//接收数据
if(HAL_QSPI_Receive(&hqspi, data, HAL_MAX_DELAY) != HAL_OK)
return 1;
return 0;
}
/**
***************************************************
* @brief bsp_w25qxx_GetStatusRegs
* @note 获取三个status register 数据
* @para NONE
* @retval
0:成功
1:失败
* @data 2022.04.28
* @auth WXL
***************************************************
**/
static int8_t bsp_w25qxx_GetStatusRegs()
{
if(bsp_w25qxx_ReadStatusReg(1 , &StatusReg[0]) != 0)
return 1;
if(bsp_w25qxx_ReadStatusReg(2 , &StatusReg[1]) != 0)
return 1;
if(bsp_w25qxx_ReadStatusReg(3 , &StatusReg[2]) != 0)
return 1;
return 0;
}
#ifdef DEBUG_ENABLE
void bsp_w25qxx_test()
{
#define SIZE 100
#define ADDRESS 0
uint8_t buff[SIZE];
uint16_t index = 0;
//初始化驱动。
if(bsp_w25qxx_Init()!=0)
{
printf("Init w25qxx failed\r\n");
}
printf("Init w25qxx success\r\n");
printf("Chip ID is %06x\r\n",ChipID);
printf("Chip UID is %llx\r\n",ChipUID);
printf("Status REG1:%02x REG2:%02x REG3:%02x \r\n",StatusReg[0],StatusReg[1],StatusReg[2]);
//测试sector的擦除功能。
printf("\r\nErase sector test\r\n");
bsp_w25qxx_EraseSector(ADDRESS);
printf("Read data from chip\r\n");
bsp_w25qxx_Read(ADDRESS , buff , SIZE);
for(index = 0;index <SIZE;index++)
{
if((index %15 == 0) && (index!=0))
{
printf("\r\n");
}
printf(" %02x ",buff[index]);
buff[index] = index % SIZE;
}
printf("\r\nWrite data to chip\r\n");
bsp_w25qxx_Write(ADDRESS , buff , SIZE);
memset(buff , 0 , SIZE);
printf("Get data from chip\r\n");
bsp_w25qxx_Read(ADDRESS , buff , SIZE);
for(index = 0;index <SIZE;index++)
{
if((index %15 == 0) && (index!=0))
{
printf("\r\n");
}
printf(" %02x ",buff[index]);
buff[index] = index % SIZE;
}
//测试block的擦除功能。
printf("\r\n\r\nErase block test \r\n");
bsp_w25qxx_EraseBlock(ADDRESS);
printf("Read data from chip\r\n");
bsp_w25qxx_Read(ADDRESS , buff , SIZE);
for(index = 0;index <SIZE;index++)
{
if((index %15 == 0) && (index!=0))
{
printf("\r\n");
}
printf(" %02x ",buff[index]);
buff[index] = index % SIZE;
}
printf("\r\nWrite data to chip\r\n");
bsp_w25qxx_Write(ADDRESS , buff , SIZE);
memset(buff , 0 , SIZE);
printf("Get data from chip\r\n");
bsp_w25qxx_Read(ADDRESS , buff , SIZE);
for(index = 0;index <SIZE;index++)
{
if((index %15 == 0) && (index!=0))
{
printf("\r\n");
}
printf(" %02x ",buff[index]);
buff[index] = index % SIZE;
}
//测试chip的擦除功能。
printf("\r\n\r\nErase chip \r\n");
bsp_w25qxx_EraseChip();
printf("Read data from chip\r\n");
bsp_w25qxx_Read(ADDRESS , buff , SIZE);
for(index = 0;index <SIZE;index++)
{
if((index %15 == 0) && (index!=0))
{
printf("\r\n");
}
printf(" %02x ",buff[index]);
buff[index] = index % SIZE;
}
printf("\r\nWrite data to chip\r\n");
bsp_w25qxx_Write(ADDRESS , buff , SIZE);
memset(buff , 0 , SIZE);
printf("Get data from chip\r\n");
bsp_w25qxx_Read(ADDRESS , buff , SIZE);
for(index = 0;index <SIZE;index++)
{
if((index %15 == 0) && (index!=0))
{
printf("\r\n");
}
printf(" %02x ",buff[index]);
buff[index] = index % SIZE;
}
//进入mapped模式。
printf("\r\n\r\nMaped mode entered\r\n");
bsp_w25qxx_MemoryMapedEnter();
uint32_t add = 0x90000000;
printf("Read data from %x address\r\n",add+ADDRESS);
for(index = 0;index <SIZE;index++)
{
if((index %15 == 0) && (index!=0))
{
printf("\r\n");
}
printf(" %02x ",*((uint8_t*)(add+ADDRESS + index)));
}
}
#endif
|