H750下W25QXX下载算法(stlder)制作(1)

代码地址

夕阳武士/H750_W25QXXhttps://gitee.com/wangchief/H750_W25QXX

1、为什么要制作stlder算法

        我们使用的是正点原子的H750核心板进行开发,H750的内部flash只有128k,无法满足比较大型程序的开发。H750提供了QSPI接口,我们可以通过QSPI接口访问外部的FLASH来扩展芯片的FLASH内容。在程序下载及调试过程中需要使用到stldr算法的实现。

2、实现步骤

  1. 实现在128kb内部flash基础上进行QSPI接口访问FLASH的程序开发和验证。
  2. 打包制作stlder算法,实现对外部flash的访问。
  3. 实现整体程序在外部flash的运行
  4. 通过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




根据引用和引用的内容,可以总结出STM32h750 QSPI W25Q64驱动的一些关键信息。 首先,W25Q64是一种SPI NOR Flash芯片,它被连接到STM32h750的QSPI(Quad SPI)接口上。W25Q64的引脚连接为PB2、PB6、PF6、PF7、PF8和PF9。 在设置QSPI时,一些关键的配置参数需要注意。首先是时钟预分频器(clock prescaler),根据W25Q256的最高时钟频率为104MHz,因此需要将分频设置为2。其次是闪存大小(FLASH SIZE),W25Q64的大小为8MB,所以需要将设置为2的(22-1)次方。时钟模式(Clock Mode)应设置为Low,表示CLK空闲时为低电平。芯片选择(Chip Select)需要设置为High Time为5,以确保高电平持续时间大于50ns。 另外,为了保证正常的工作,所有的QSPI引脚都应该设置为very high,而NCS脚(PB6)必须设置为PULL-UP。关于为什么要设置为PULL-UP,具体原因在引用中没有提及。 最后,需要注意W25Q64与W25Q256之间的一些区别。首先是地址位数,W25Q64只支持24位地址,而W25Q256支持24位和32位地址。其次是读写状态寄存器的不同,W25Q64的读状态寄存器为05h和35h,而W25Q256的为05h、35h和15h。写状态寄存器也有所不同,W25Q64的为01h,而W25Q256的为01h、31h和11h。 综上所述,STM32h750的QSPI可以通过相应的配置来驱动W25Q64芯片。需要注意的是,具体的配置参数和引脚连接可能还取决于具体的硬件设计和应用需求。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [STM32H750 QSPI间接模式 W25Q64](https://blog.csdn.net/smallerlang/article/details/127921384)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [STM32H753 STM32H743 STM32H750 QSPI W25Q256 下载算法](https://blog.csdn.net/c101028/article/details/132073746)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值