硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1778|回复: 9
收起左侧

[SPI/QSPI] 请教:用实验例程,QSPI读写W25Q256错误。

[复制链接]

26

主题

136

回帖

214

积分

高级会员

积分
214
发表于 2024-8-27 23:51:07 | 显示全部楼层 |阅读模式
今天打算试一下QSPI读写Flash,用硬汉哥的例程,在开发板上做实验,顺利完成。
但当把这个程序下载到另一个板子上跑时,读写数据就总是不对了。



另一个板子的QSPI引脚用得不一样,是使用了以下连接:
[C] 纯文本查看 复制代码
    /**QUADSPI GPIO Configuration
    PE2     ------> QUADSPI_BK1_IO2
    PB2     ------> QUADSPI_CLK
    PB10     ------> QUADSPI_BK1_NCS
    PD11     ------> QUADSPI_BK1_IO0
    PD12     ------> QUADSPI_BK1_IO1
    PD13     ------> QUADSPI_BK1_IO3
    */

将bsp_qspi_w25q256.c中的IO配置改了,如下。
[C] 纯文本查看 复制代码
#define QSPI_CS_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOB_CLK_ENABLE()
#define QSPI_CS_PIN                     GPIO_PIN_10
#define QSPI_CS_GPIO_PORT               GPIOB
#define QSPI_CS_GPIO_AF                 GPIO_AF9_QUADSPI

#define QSPI_CLK_GPIO_CLK_ENABLE()     __HAL_RCC_GPIOB_CLK_ENABLE()
#define QSPI_CLK_PIN                    GPIO_PIN_2
#define QSPI_CLK_GPIO_PORT              GPIOB
#define QSPI_CLK_GPIO_AF                GPIO_AF9_QUADSPI

#define QSPI_BK1_D0_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D0_PIN                 GPIO_PIN_11
#define QSPI_BK1_D0_GPIO_PORT           GPIOD
#define QSPI_BK1_D0_GPIO_AF             GPIO_AF9_QUADSPI

#define QSPI_BK1_D1_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D1_PIN                 GPIO_PIN_12
#define QSPI_BK1_D1_GPIO_PORT           GPIOD
#define QSPI_BK1_D1_GPIO_AF             GPIO_AF9_QUADSPI

#define QSPI_BK1_D2_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOE_CLK_ENABLE()
#define QSPI_BK1_D2_PIN                 GPIO_PIN_2
#define QSPI_BK1_D2_GPIO_PORT           GPIOE
#define QSPI_BK1_D2_GPIO_AF             GPIO_AF9_QUADSPI

#define QSPI_BK1_D3_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D3_PIN                 GPIO_PIN_13
#define QSPI_BK1_D3_GPIO_PORT           GPIOD
#define QSPI_BK1_D3_GPIO_AF             GPIO_AF9_QUADSPI


实验结果:
[C] 纯文本查看 复制代码
检测到串行Flash, ID = 00EF4019, 型号: WM25Q256JV
 容量 : 32M字节, 扇区大小 : 4096字节, 页大小:256字节

*******************************************
请选择操作命令:
【1 - 读QSPI Flash, 地址:0x0,长度:1024字节】
【2 - 写QSPI Flash, 地址:0x0,长度:1024字节】
【3 - 写QSPI Flash前10KB空间, 全0x55】
【4 - 读整个串行Flash, 测试读速度】
【Z - 读取前1K,地址自动减少】
【X - 读取后1K,地址自动增加】
【Y - 擦除整个串行Flash,整片32MB擦除大概300秒左右】
其他任意键 - 显示命令提示


【1 - 读QSPI Flash, 地址:0x0 ,长度:1024字节】
读取第1个字节,数据如下
 FF 
读取前10个字节,数据如下
 FF FF FF FF FF FF FF FF FF FF
读串行Flash成功,数据如下
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
……

 【3 - 写QSPI Flash前10KB空间, 全0x55】
........................................
数据长度: 10240字节, 写耗时: 1ms, 写速度: 10240KB/s

【1 - 读QSPI Flash, 地址:0x0 ,长度:1024字节】
读取第1个字节,数据如下
 FF 
读取前10个字节,数据如下
 FF FF FF FF FF FF FF FF FF FF
读串行Flash成功,数据如下
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF -  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF



芯片ID应该是正确读出来了。
但是读写,打印信息说成功了,实际上却总是读到的FF,不对劲。
我仔细比较了芯片信号,和开发板上是一样的芯片,这样读写命令就不需要修改了吧。

整个文件如下:
[C] 纯文本查看 复制代码
/*
#include "bsp.h"

/* 
    STM32-V7开发板接线

	PG6/QUADSPI_BK1_NCS AF10
	PF10/QUADSPI_CLK	AF9
	PF8/QUADSPI_BK1_IO0 AF10
	PF9/QUADSPI_BK1_IO1 AF10
	PF7/QUADSPI_BK1_IO2 AF9
	PF6/QUADSPI_BK1_IO3 AF9

	W25Q256JV有512块,每块有16个扇区,每个扇区Sector有16页,每页有256字节,共计32MB
*/

/* QSPI引脚和时钟相关配置宏定义 */
#define QSPI_CLK_ENABLE()              __HAL_RCC_QSPI_CLK_ENABLE()
#define QSPI_CLK_DISABLE()             __HAL_RCC_QSPI_CLK_DISABLE()

#define QSPI_MDMA_CLK_ENABLE()         __HAL_RCC_MDMA_CLK_ENABLE()
#define QSPI_FORCE_RESET()             __HAL_RCC_QSPI_FORCE_RESET()
#define QSPI_RELEASE_RESET()           __HAL_RCC_QSPI_RELEASE_RESET()

//#define QSPI_CS_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOG_CLK_ENABLE()
//#define QSPI_CS_PIN                    GPIO_PIN_6
//#define QSPI_CS_GPIO_PORT              GPIOG
//#define QSPI_CS_GPIO_AF                GPIO_AF10_QUADSPI

//#define QSPI_CLK_GPIO_CLK_ENABLE()     __HAL_RCC_GPIOF_CLK_ENABLE()
//#define QSPI_CLK_PIN                   GPIO_PIN_10
//#define QSPI_CLK_GPIO_PORT             GPIOF
//#define QSPI_CLK_GPIO_AF               GPIO_AF9_QUADSPI

//#define QSPI_BK1_D0_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOF_CLK_ENABLE()
//#define QSPI_BK1_D0_PIN                GPIO_PIN_8
//#define QSPI_BK1_D0_GPIO_PORT          GPIOF
//#define QSPI_BK1_D0_GPIO_AF            GPIO_AF10_QUADSPI

//#define QSPI_BK1_D1_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOF_CLK_ENABLE()
//#define QSPI_BK1_D1_PIN                GPIO_PIN_9
//#define QSPI_BK1_D1_GPIO_PORT          GPIOF
//#define QSPI_BK1_D1_GPIO_AF            GPIO_AF10_QUADSPI

//#define QSPI_BK1_D2_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOF_CLK_ENABLE()
//#define QSPI_BK1_D2_PIN                GPIO_PIN_7
//#define QSPI_BK1_D2_GPIO_PORT          GPIOF
//#define QSPI_BK1_D2_GPIO_AF            GPIO_AF9_QUADSPI

//#define QSPI_BK1_D3_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOF_CLK_ENABLE()
//#define QSPI_BK1_D3_PIN                GPIO_PIN_6
//#define QSPI_BK1_D3_GPIO_PORT          GPIOF
//#define QSPI_BK1_D3_GPIO_AF            GPIO_AF9_QUADSPI

#define QSPI_CS_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOB_CLK_ENABLE()
#define QSPI_CS_PIN                     GPIO_PIN_10
#define QSPI_CS_GPIO_PORT               GPIOB
#define QSPI_CS_GPIO_AF                 GPIO_AF9_QUADSPI

#define QSPI_CLK_GPIO_CLK_ENABLE()     __HAL_RCC_GPIOB_CLK_ENABLE()
#define QSPI_CLK_PIN                    GPIO_PIN_2
#define QSPI_CLK_GPIO_PORT              GPIOB
#define QSPI_CLK_GPIO_AF                GPIO_AF9_QUADSPI

#define QSPI_BK1_D0_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D0_PIN                 GPIO_PIN_11
#define QSPI_BK1_D0_GPIO_PORT           GPIOD
#define QSPI_BK1_D0_GPIO_AF             GPIO_AF9_QUADSPI

#define QSPI_BK1_D1_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D1_PIN                 GPIO_PIN_12
#define QSPI_BK1_D1_GPIO_PORT           GPIOD
#define QSPI_BK1_D1_GPIO_AF             GPIO_AF9_QUADSPI

#define QSPI_BK1_D2_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOE_CLK_ENABLE()
#define QSPI_BK1_D2_PIN                 GPIO_PIN_2
#define QSPI_BK1_D2_GPIO_PORT           GPIOE
#define QSPI_BK1_D2_GPIO_AF             GPIO_AF9_QUADSPI

#define QSPI_BK1_D3_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOD_CLK_ENABLE()
#define QSPI_BK1_D3_PIN                 GPIO_PIN_13
#define QSPI_BK1_D3_GPIO_PORT           GPIOD
#define QSPI_BK1_D3_GPIO_AF             GPIO_AF9_QUADSPI

/* 供本文件调用的全局变量 */
static QSPI_HandleTypeDef 	QSPIHandle;

/* 供本文件调用的函数 */
static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi);
static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi);


/*
*********************************************************************************************************
*	函 数 名: bsp_InitQSPI_W25Q256
*	功能说明: QSPI Flash硬件初始化,配置基本参数
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitQSPI_W25Q256(void)
{
	/* 复位QSPI */
	QSPIHandle.Instance = QUADSPI;
	if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
	
	/* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
	QSPIHandle.Init.ClockPrescaler  = 1;  
	
	/* 设置FIFO阀值,范围1 - 32 */
	QSPIHandle.Init.FifoThreshold   = 32; 
	
	/* 
		QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
		在外部信号延迟时,这有利于推迟数据采样。
	*/
	QSPIHandle.Init.SampleShifting  = QSPI_SAMPLE_SHIFTING_HALFCYCLE; 
	
	/*Flash大小是2^(FlashSize + 1) = 2^25 = 32MB */
    //QSPI_FLASH_SIZE - 1; 需要扩大一倍,否则内存映射方位最后1个地址时,会异常。
	QSPIHandle.Init.FlashSize       = QSPI_FLASH_SIZE; 
	
	/* 命令之间的CS片选至少保持2个时钟周期的高电平 */
	QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
	
	/*
	   MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平
	   MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平
	*/
	QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
	
	/* QSPI有两个BANK,这里使用的BANK1 */
	QSPIHandle.Init.FlashID   = QSPI_FLASH_ID_1;
	
	/* V7开发板仅使用了BANK1,这里是禁止双BANK */
	QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

	/* 初始化配置QSPI */
	if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}	
}	

/*
*********************************************************************************************************
*	函 数 名: HAL_QSPI_MspInit
*	功能说明: QSPI底层初始化,被HAL_QSPI_Init调用的底层函数
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void HAL_QSPI_MspInit(QSPI_HandleTypeDef *hqspi)
{
	GPIO_InitTypeDef GPIO_InitStruct;

	/* 使能QPSI时钟  */
	QSPI_CLK_ENABLE();
	
	/* 复位时钟接口 */
	QSPI_FORCE_RESET();
	QSPI_RELEASE_RESET();
	
	/* 使能GPIO时钟 */
	QSPI_CS_GPIO_CLK_ENABLE();
	QSPI_CLK_GPIO_CLK_ENABLE();
	QSPI_BK1_D0_GPIO_CLK_ENABLE();
	QSPI_BK1_D1_GPIO_CLK_ENABLE();
	QSPI_BK1_D2_GPIO_CLK_ENABLE();
	QSPI_BK1_D3_GPIO_CLK_ENABLE(); 

	/* QSPI CS GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_CS_PIN;
	GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull      = GPIO_PULLUP;
	GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate = QSPI_CS_GPIO_AF;
	HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &GPIO_InitStruct);
	
	/* QSPI CLK GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_CLK_PIN;
	GPIO_InitStruct.Pull      = GPIO_NOPULL;
	GPIO_InitStruct.Alternate = QSPI_CLK_GPIO_AF;
	HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D0 GPIO pin 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK1_D0_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK1_D0_GPIO_AF;
	HAL_GPIO_Init(QSPI_BK1_D0_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D1 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK1_D1_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK1_D1_GPIO_AF;
	HAL_GPIO_Init(QSPI_BK1_D1_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D2 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK1_D2_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK1_D2_GPIO_AF;
	HAL_GPIO_Init(QSPI_BK1_D2_GPIO_PORT, &GPIO_InitStruct);

	/* QSPI D3 GPIO 引脚配置 */
	GPIO_InitStruct.Pin       = QSPI_BK1_D3_PIN;
	GPIO_InitStruct.Alternate = QSPI_BK1_D3_GPIO_AF;
	HAL_GPIO_Init(QSPI_BK1_D3_GPIO_PORT, &GPIO_InitStruct);
}

/*
*********************************************************************************************************
*	函 数 名: HAL_QSPI_MspDeInit
*	功能说明: QSPI底层复位,被HAL_QSPI_Init调用的底层函数
*	形    参: hqspi QSPI_HandleTypeDef类型句柄
*	返 回 值: 无
*********************************************************************************************************
*/
void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi)
{
	/* 复位QSPI引脚 */
	HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN);
	HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN);
	HAL_GPIO_DeInit(QSPI_BK1_D0_GPIO_PORT, QSPI_BK1_D0_PIN);
	HAL_GPIO_DeInit(QSPI_BK1_D1_GPIO_PORT, QSPI_BK1_D1_PIN);
	HAL_GPIO_DeInit(QSPI_BK1_D2_GPIO_PORT, QSPI_BK1_D2_PIN);
	HAL_GPIO_DeInit(QSPI_BK1_D3_GPIO_PORT, QSPI_BK1_D3_PIN);

	/* 复位QSPI */
	QSPI_FORCE_RESET();
	QSPI_RELEASE_RESET();

	/* 关闭QSPI时钟 */
	QSPI_CLK_DISABLE();
}

/*
*********************************************************************************************************
*	函 数 名: QSPI_EraseSector
*	功能说明: 擦除指定的扇区,扇区大小4KB
*	形    参: _uiSectorAddr : 扇区地址,以4KB为单位的地址,比如0,4096, 8192等
*	返 回 值: 无
*********************************************************************************************************
*/
void QSPI_EraseSector(uint32_t _uiSectorAddr)
{
	QSPI_CommandTypeDef sCommand={0};

	/* 写使能 */
	QSPI_WriteEnable(&QSPIHandle);	

	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;	 /* 每次传输都发指令 */	
	
	/* 擦除配置 */
	sCommand.Instruction = SUBSECTOR_ERASE_4_BYTE_ADDR_CMD;   /* 32bit地址方式的扇区擦除命令,扇区大小4KB*/       
	sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 地址发送是1线方式 */       
	sCommand.Address     = _uiSectorAddr;        /* 扇区首地址,保证是4KB整数倍 */    
	sCommand.DataMode    = QSPI_DATA_NONE;       /* 无需发送数据 */  
	sCommand.DummyCycles = 0;                    /* 无需空周期 */  

	if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
	
	QSPI_AutoPollingMemReady(&QSPIHandle);	
}

/*
*********************************************************************************************************
*	函 数 名: QSPI_EraseChip
*	功能说明: 整个芯片擦除
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void QSPI_EraseChip(void)
{
	QSPI_CommandTypeDef sCommand={0};

	/* 写使能 */
	QSPI_WriteEnable(&QSPIHandle);	

	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;	 /* 每次传输都发指令 */	
	
	/* 擦除配置 */
	sCommand.Instruction = BULK_ERASE_CMD;       /* 整个芯片擦除命令*/       
	sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 地址发送是1线方式 */       
	sCommand.Address     = 0;                    /* 地址 */    
	sCommand.DataMode    = QSPI_DATA_NONE;       /* 无需发送数据 */  
	sCommand.DummyCycles = 0;                    /* 无需空周期 */  

	if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
	
	QSPI_AutoPollingMemReady(&QSPIHandle);	
}

/*
*********************************************************************************************************
*	函 数 名: QSPI_WriteBuffer
*	功能说明: 页编程,页大小256字节,任意页都可以写入
*	形    参: _pBuf : 数据源缓冲区;
*			  _uiWriteAddr :目标区域首地址,即页首地址,比如0, 256, 512等。
*			  _usWriteSize :数据个数,不能超过页面大小,范围1 - 256。
*	返 回 值: 1:成功, 0:失败
*********************************************************************************************************
*/
uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
{
	QSPI_CommandTypeDef sCommand={0};

	/* 写使能 */
	QSPI_WriteEnable(&QSPIHandle);	
	
	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_ONLY_FIRST_CMD;	 /* 仅发送一次命令 */	
	
	/* 写序列配置 */
	sCommand.Instruction = QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速写入命令 */
	sCommand.DummyCycles = 0;                    /* 不需要空周期 */
	sCommand.AddressMode = QSPI_ADDRESS_1_LINE;  /* 1线地址方式 */
	sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据方式 */
	sCommand.NbData      = _usWriteSize;         /* 写数据大小 */   
	sCommand.Address     = _uiWriteAddr;         /* 写入地址 */
	
	if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
	{
        //return 0;
		Error_Handler(__FILE__, __LINE__);
	}
	
	/* 启动传输 */
	if (HAL_QSPI_Transmit(&QSPIHandle, _pBuf, 10000) != HAL_OK)
	{
        //return 0;
		Error_Handler(__FILE__, __LINE__);
        
	}
	
	QSPI_AutoPollingMemReady(&QSPIHandle);	
	
	return 1;
}

/*
*********************************************************************************************************
*	函 数 名: QSPI_ReadBuffer
*	功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
*	形    参: _pBuf : 数据源缓冲区。
*			  _uiReadAddr :起始地址。
*			  _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
*	返 回 值: 无
*********************************************************************************************************
*/
void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
{
	
	QSPI_CommandTypeDef sCommand = {0};
	
	
	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    	/* 1线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;      	/* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  	/* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      	/* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  	/* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;		/* 每次传输要发指令 */	
 
	/* 读取数据 */
	sCommand.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 32bit地址的4线快速读取命令 */
	sCommand.DummyCycles = 6;                    /* 空周期 */
	sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
	sCommand.DataMode    = QSPI_DATA_4_LINES;    /* 4线数据 */ 
	sCommand.NbData      = _uiSize;              /* 读取的数据大小 */ 
	sCommand.Address     = _uiReadAddr;          /* 读取数据的起始地址 */ 
	
	if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}

	/* 读取 */
	if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, 10000) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}	
}

/*
*********************************************************************************************************
*	函 数 名: QSPI_WriteEnable
*	功能说明: 写使能
*	形    参: hqspi  QSPI_HandleTypeDef句柄。
*	返 回 值: 无
*********************************************************************************************************
*/
static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
{
	QSPI_CommandTypeDef     sCommand = {0};
	
	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;	 /* 每次传输都发指令 */
	
	/* 写使能 */
	sCommand.Instruction       = WRITE_ENABLE_CMD;  /* 写使能指令 */
	sCommand.AddressMode       = QSPI_ADDRESS_NONE; /* 无需地址 */
	sCommand.DataMode          = QSPI_DATA_NONE;    /* 无需数据 */
	sCommand.DummyCycles       = 0;                 /* 空周期  */

	if (HAL_QSPI_Command(&QSPIHandle, &sCommand, 10000) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}	
}

/*
*********************************************************************************************************
*	函 数 名: QSPI_AutoPollingMemReady
*	功能说明: 等待QSPI Flash就绪,主要用于Flash擦除和页编程时使用
*	形    参: hqspi  QSPI_HandleTypeDef句柄
*	返 回 值: 无
*********************************************************************************************************
*/
static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi)
{
	QSPI_CommandTypeDef     sCommand = {0};
	QSPI_AutoPollingTypeDef sConfig = {0};

	
	/* 基本配置 */
	sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;    /* 1线方式发送指令 */
	sCommand.AddressSize       = QSPI_ADDRESS_32_BITS;       /* 32位地址 */
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
	sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
	sCommand.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
	sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;	 /* 每次传输都发指令 */
	
	/* 读取状态*/
	sCommand.Instruction       = READ_STATUS_REG_CMD; /* 读取状态命令 */
	sCommand.AddressMode       = QSPI_ADDRESS_NONE;   /* 无需地址 */
	sCommand.DataMode          = QSPI_DATA_1_LINE;    /* 1线数据 */
	sCommand.DummyCycles       = 0;                   /* 无需空周期 */

	/* 屏蔽位设置的bit0,匹配位等待bit0为0,即不断查询状态寄存器bit0,等待其为0 */
	sConfig.Mask            = 0x01;
	sConfig.Match           = 0x00;
	sConfig.MatchMode       = QSPI_MATCH_MODE_AND;
	sConfig.StatusBytesSize = 1;
	sConfig.Interval        = 0x10;
	sConfig.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;

	if (HAL_QSPI_AutoPolling(&QSPIHandle, &sCommand, &sConfig, 10000) != HAL_OK)
	{
		Error_Handler(__FILE__, __LINE__);
	}
}

/*
*********************************************************************************************************
*    函 数 名: QSPI_MemoryMapped
*    功能说明: QSPI内存映射,地址 0x90000000
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void QSPI_MemoryMapped(void)
{
    QSPI_CommandTypeDef s_command = {0};
    QSPI_MemoryMappedTypeDef s_mem_mapped_cfg = {0};

    /* 基本配置 */
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;      /* 1线方式发送指令 */ 
    s_command.AddressSize = QSPI_ADDRESS_32_BITS;             /* 32位地址 */
    s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
    s_command.DdrMode = QSPI_DDR_MODE_DISABLE;                /* W25Q256JV不支持DDR */
    s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;   /* DDR模式,数据输出延迟 */
    s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次传输都发指令 */
    
    /* 全部采用4线 */
    s_command.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD; /* 快速读取命令 */
    s_command.AddressMode = QSPI_ADDRESS_4_LINES;                 /* 4个地址线 */
    s_command.DataMode = QSPI_DATA_4_LINES;                       /* 4个数据线 */
    s_command.DummyCycles = 6;                                    /* 空周期 */

    /* 关闭溢出计数 */
    s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
    s_mem_mapped_cfg.TimeOutPeriod = 0;

    if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
    {
       Error_Handler(__FILE__, __LINE__);
    }
}

/*
*********************************************************************************************************
*	函 数 名: sf_ReadID
*	功能说明: 读取器件ID
*	形    参: 无
*	返 回 值: 32bit的器件ID (最高8bit填0,有效ID位数为24bit)
*********************************************************************************************************
*/
uint32_t QSPI_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_32_BITS;       /* 32位地址 */
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字节 */
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;      /* W25Q256JV不支持DDR */
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;  /* DDR模式,数据输出延迟 */
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;	  /* 每次传输都发指令 */
	
	/* 读取JEDEC ID */
	s_command.Instruction = READ_ID_CMD2;         /* 读取ID命令 */
	s_command.AddressMode = QSPI_ADDRESS_NONE;    /* 1线地址 */
	s_command.DataMode = QSPI_DATA_1_LINE;        /* 1线地址 */
	s_command.DummyCycles = 0;                    /* 无空周期 */
	s_command.NbData = 3;                         /* 读取三个数据 */

	if (HAL_QSPI_Command(&QSPIHandle, &s_command, 10000) != HAL_OK) 
	{
       Error_Handler(__FILE__, __LINE__);
	}

	if (HAL_QSPI_Receive(&QSPIHandle, buf, 10000) != HAL_OK) 
	{
       Error_Handler(__FILE__, __LINE__);
	}

	uiID = (buf[0] << 16) | (buf[1] << 8 ) | buf[2];

	return uiID;
}

/***************************** 安富莱电子 [url]www.armfly.com[/url] (END OF FILE) *********************************/





请教一下,这可能是哪里的问题呢?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115490
QQ
发表于 2024-8-28 09:14:07 | 显示全部楼层
配置看着没问题,降低下速度试试

  QSPIHandle.Init.ClockPrescaler  = 1;
回复

使用道具 举报

26

主题

136

回帖

214

积分

高级会员

积分
214
 楼主| 发表于 2024-8-28 14:12:45 | 显示全部楼层
降低速度已经试过了。
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115490
QQ
发表于 2024-8-28 18:18:44 | 显示全部楼层
ifree 发表于 2024-8-28 14:12
降低速度已经试过了。

还有一个地方可以试试。
上拉都开启试试
GPIO_InitStruct.Pull      = GPIO_NOPULL;

别的没有要特别注意的了。
回复

使用道具 举报

26

主题

136

回帖

214

积分

高级会员

积分
214
 楼主| 发表于 2024-8-28 23:29:46 | 显示全部楼层
这个qspi的引脚,只要该引脚支持这个功能就可以选择使用吧?和您例程还有一个区别就是这些引脚不一样
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115490
QQ
发表于 2024-8-29 09:18:19 | 显示全部楼层
ifree 发表于 2024-8-28 23:29
这个qspi的引脚,只要该引脚支持这个功能就可以选择使用吧?和您例程还有一个区别就是这些引脚不一样

这个没关系,注意这个GPIO_AF9_QUADSPI的AF9,可能这个引脚是AF其它数值,这个没错就没问题的。
回复

使用道具 举报

26

主题

136

回帖

214

积分

高级会员

积分
214
 楼主| 发表于 2024-8-30 18:38:40 | 显示全部楼层

破案了,芯片可能是“假货”?我用下面这个2块钱一个的芯片,就无法存数据。但为什么能正确读取到ID?
换成上面这个贵一点的芯片,就正常了。

W25Q256.png
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115490
QQ
发表于 2024-8-31 09:01:29 | 显示全部楼层
ifree 发表于 2024-8-30 18:38
破案了,芯片可能是“假货”?我用下面这个2块钱一个的芯片,就无法存数据。但为什么能正确读取到ID?
...



怎么想到可能是这个问题的。
回复

使用道具 举报

26

主题

136

回帖

214

积分

高级会员

积分
214
 楼主| 发表于 2024-8-31 13:31:24 来自手机 | 显示全部楼层
我想死马当活马医。引脚分配检查了N次实在找不出问题来。就想是不是硬件问题,换一个芯片试试。正好有另一个卖家买的芯片,然后把这个可能有问题的芯片,换了一片,以及把这个芯片换到v7开发板上,有问题的芯片都不能正常读写。
回复

使用道具 举报

5

主题

60

回帖

75

积分

初级会员

积分
75
发表于 2024-9-13 14:50:36 | 显示全部楼层
ifree 发表于 2024-8-31 13:31
我想死马当活马医。引脚分配检查了N次实在找不出问题来。就想是不是硬件问题,换一个芯片试试。正好有另一 ...

一分钱一分货呐 ,我最近碰到这种情况 ,DM9000网口总掉线 ,一顿查软硬件 , 结果芯片太老了,15年的 , 换成23年的芯片就好了 ,这种库存芯片和假芯片真是头大
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-4-28 23:09 , Processed in 0.325402 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表