STM32 QSPI双闪存操作

@STM32 QSPI双闪存操作

使用CubeMX或者CubeIDE生成框架

使用野火的开发板,MCU型号为stm32h750/743,他们家核心板上使用了QSPI挂了2片FLASH,型号为W25Q256,但是提供的例程里只有单个FLASH的QSPI操作例程。根据了解,他们本来计划在核心板上只保留1片FLASH的,只是我买的比较早了 。
原理图
在开发板上的原理图接线如上,其中PB2为时钟,PG6为片选,两片FLASH共用。
QSPI配置界面
QSPI双FLASH模式的配置注意把片选设置为1个片选选中2片FLASH就可以了,其他引脚设置按照原理图中进行设置即可。在CubeIDE中,点击保存后会自动弹框,询问是否生成代码,非常的方便。

双闪存需要注意的地方

开发板厂家提供了该flash的底层驱动,bsp_qspi_flash.c bsp_qspi_flash.h,在驱动里提供了擦除、写入、读取等函数接口,在擦除和写入的函数中都调用了一个轮询等待的子函数。因为FLASH进行擦除和写入都需要耗费一定时间,在这段时间内无法进行其他操作,比如读取,因此在FLASH内部有许多状态寄存器。轮询等待的实现就是去查询相应的寄存器,只有当表示空闲的那一位数据为1时,表示可以进行读取操作,为0则表示繁忙。

/**
  * @brief  擦除QSPI存储器的指定块
  * @param  BlockAddress: 需要擦除的块地址
  * @retval QSPI存储器状态
  */
uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress)
{
	QSPI_CommandTypeDef s_command;
	/* 初始化擦除命令 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	s_command.Instruction       = SECTOR_ERASE_CMD;
	s_command.AddressMode       = QSPI_ADDRESS_1_LINE;
	s_command.AddressSize       = QSPI_ADDRESS_32_BITS;
	s_command.Address           = BlockAddress;
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode          = QSPI_DATA_NONE;
	s_command.DummyCycles       = 0;
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;

	/* 启用写操作 */
	if (QSPI_WriteEnable() != QSPI_OK)
	{
		return QSPI_ERROR;
	}

	/* 发送命令 */
	if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return QSPI_ERROR;
	}

	/* 配置自动轮询模式等待擦除结束 */
	if (QSPI_AutoPollingMemReady(W25Q256JV_SECTOR_ERASE_MAX_TIME) != QSPI_OK)
	{
		return QSPI_ERROR;
	}
	return QSPI_OK;
}

厂家提供的驱动只有单个FLASH状态寄存器读取的设置,因此需要修改该函数。

首先看一下原来的自动轮询模式等待函数QSPI_AutoPollingMemReady

/**
  * @brief  读取存储器的SR并等待EOP
  * @param  hqspi: QSPI句柄
  * @param  Timeout 超时
  * @retval 无
  */
static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout)
{
	QSPI_CommandTypeDef     s_command;
	QSPI_AutoPollingTypeDef s_config;
	/* 配置自动轮询模式等待存储器准备就绪 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	s_command.Instruction       = READ_STATUS_REG1_CMD;
	s_command.AddressMode       = QSPI_ADDRESS_NONE;
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode          = QSPI_DATA_1_LINE;
	s_command.DummyCycles       = 0;
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;

	s_config.Match           = 0x00;
	s_config.Mask            = W25Q256JV_FSR_BUSY;
	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)
	{
		return QSPI_ERROR;
	}
	return QSPI_OK;
}

该函数是向FLASH发送READ_STATUS_REG1_CMD(05H)命令读取FLASH内部的寄存器,我们只关注这个状态寄存器的第0 位“BUSY”,当这个位为“1”时,表明FLASH 芯片处于忙碌状态,它可能正在对内部的存储矩阵进行“擦除”或“数据写入”的操作。调用HAL_QSPI_AutoPolling 库函数,设定命令参数及自动轮询参数,最后设定超时返回,如果在超时等待时间内确定FLASH 就绪则返回存储器就绪状态,否则返回存储器错误。其实主要就是检查它的W25Q256FV_FSR_BUSY (01H)(即BUSY 位),通过QUADSPI_PSMAR
与**QUADSPI_QUADSPI _PSMKR **作‘与’运算或者是作‘或’运算。如果满足条件才退出本函数,以便继续后面与FLASH 芯片的数据通讯。
单个FLASH需要判断一个字节,而双闪存操作的情况下,有可能一片FLASH已经处于空闲状态,而另一片还在繁忙,若此时进行其他操作则会导致结果异常(亲测只判断一片空闲就写入数据,导致只有一片FLASH中有数据)。由于双闪存模式下HAL库读取为:第一个字节为FLASH1的数据,第二个字节为FLASH2的数据,第三个字节为FLASH1的数据,这样奇偶交替,因此轮询等待读取状态寄存器的函数
修改为:

static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout)
{
	QSPI_CommandTypeDef     s_command;
	QSPI_AutoPollingTypeDef s_config;
	/* 配置自动轮询模式等待存储器准备就绪 */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	s_command.Instruction       = READ_STATUS_REG1_CMD;
	s_command.AddressMode       = QSPI_ADDRESS_NONE;
	s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode          = QSPI_DATA_1_LINE;
	s_command.DummyCycles       = 0;
	s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;
	s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
	s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;

	s_config.Match           = 0x00;
	s_config.Mask            = W25Q256JV_FSR_BUSY + (W25Q256JV_FSR_BUSY <<8);/*双闪存判断两个字节*/
	s_config.MatchMode       = QSPI_MATCH_MODE_AND;
	s_config.StatusBytesSize = 2;/*双闪存判断两个字节*/
	s_config.Interval        = 0x10;
	s_config.AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;

	if (HAL_QSPI_AutoPolling(&hqspi, &s_command, &s_config, Timeout) != HAL_OK)
	{
		return QSPI_ERROR;
	}
	return QSPI_OK;
}

这样就可以判断出两片FLASH都处于就绪状态了

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值