STM32 QSPI接口驱动GD/W25Qxx配置简要

STM32 QSPI接口GD/W25Qxx配置简要


  • 📝本篇会具体涉及介绍Winbond(华邦)和GD(兆易创新) NOR flash相关型号指令差异。由于网络上可以搜索到很多相关QSPI相关知识内容,不对QSPI通讯协议做深度解析。
  • 🔖首先确保所使用的STM32型号,硬件上是否支持QSPI功能。
  • 由于GD25QXX和对应的W25Qxx 芯片型号较多,芯片出厂,默认状态寄存器关键位存在差异,在没有进行状态寄存器关键位做配置的情况下。两者的驱动代码不能互为通用,代码上可以通过型号辨别,以及对状态寄存器关键位的使能配置,可以整合为一套通用的驱动代码。
  • 🌿QSPI支持三种工作模式:间接模式、状态轮询模式和内存映射模式:
  • 间接模式:使用QSPI寄存器执行全部操作。
  • 状态轮询模式:周期性读取外部FLASH状态寄存器,当标志位置1时会产生中断(如擦除或烧写完成,产生中断)。
  • 内存映射模式:外部FLASH映射到微控制器地址空间,从而系统将其视作内部存储器进行访问。

在间接模式下也可以切换为内存映射模式进行访问,切换过程需要重新对QSPI外设进行复位和重新初始化QSPI操作,代码操作比较麻烦,好处就是提升了读取访问速度。如果需要进行擦除或编程操作,还需要切换为间接模式下进行。

  • QUADSPI 功能框图(见STM32H750参考手册)
    在这里插入图片描述
    在这里插入图片描述

图中BK2只有在双闪存模式下才需要。

  • 4线SPI结构框图
    在这里插入图片描述

  • 🧲QSPI通讯序列
    QUADSPI 通过命令与 FLASH 通信 每条命令包括指令、地址、交替字节、空指令和数据这 五个阶段 任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。
    nCS 在每条指令开始前下降,在每条指令完成后再次上升
    在这里插入图片描述

对于通讯的整个过程,只需要留意3个状态:WIP(BUSY)用于查看擦除/编程操作是否正在进行、QE用于使能4线模式(Quad)和WREN写使能位其实和WIP位对应,该位决定接下来是否可以进行编程、擦写操作。

  • 📜GD25Q64读写测试:
    在这里插入图片描述
  • 📜W25Q64读写测试:
    在这里插入图片描述
  • 基于QSPI片外flash下载算法实现的片外启动APP程序:
    在这里插入图片描述

📗 NOR FLASH 存储器介绍

  • 🍁Winbond(华邦)W25Q64存储器功能控制结构图
    在这里插入图片描述
  • GD(兆易创新)GD25Q64
    在这里插入图片描述
  • 内存空间结构: 一页(Page)256字节,4K(4096 字节)为一个扇区(Sector),16个扇区为1块(Block),容量为8M字节,共有128个块,2048 个扇区。
  • 支持页编程。每页大小由256字节组成,每页的256字节用一次页编程指令即可完成。
  • 擦除指令通用: 16页(1个扇区4K)、32K、64K、全片擦除操作。

两者常规操作指令互为通用。在QE位都配置为使能状态情况下,除了在读取厂商ID有差异外,读取数据功能函数通用。测试了基于W25QXX制作的片外QSPI下载算法文件都可以兼容GD25XX使用。(前提是下载算法中没有对应闪存厂商ID校验,芯片相关状态寄存器位没有写保护)

🌼Nor Flash操作流程
  • 写入操作时:

写入操作前,必须先进行写使能位.
每个数据位只能由1改写为0,不能由0改写为1
写入数据前必须先擦除,擦除后,所有数据位变为1。.(删除目录实际上是填充0xff)
擦除必须按最小擦除单元进行(一个扇区:4kb)
连续写入多字节时,最多写入一页(256字节)的数据,超过页尾位置的数据,会回到页首覆盖写入
写入操作结束后,芯片进入忙状态,不响应新的读写操作

  • 读取操作时:

直接调用读取时序,快速读取(Fast Read Quad I/O (EBh)),需要QE=1,可以不需要使能Write Enable (WREN) (06H),没有页的限制,读取操作结束后不会进入忙状态,但不能在忙状态时读取.

📘Nor flash状态寄存器介绍

  • 🌿winbond(华邦)W25QXX状态寄存器访问指令
    在这里插入图片描述
  • 📄具体状态寄存器位说明
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
📘 GD25QXX状态寄存器
  • 🌿GD(兆易创新)GD25QXX状态寄存器总表:

在这里插入图片描述

🔰状态寄存器差异化说明

  • 🌿QE位:该位属于非易失性(non-volatile),数据在断电后仍然能够保持的特性。一旦该位配置位1,将一直保持其状态,不会断电丢失。
  • 🔖winbond(华邦)W25QXX,该位出厂默认状态是根据芯片具体型号决定该位默认状态是否为1
  • When the QE bit is set to a 0 state (factory default for part numbers with ordering options “IM”&“JM”).
  • When the QE bit is set to a 1 (factory fixed default for part numbers with ordering options “IQ” & “JQ”),
  • 🔖GD(兆易创新)GD25Qxx,该位出厂默认状态是0,如需要使用QSPI 模式,必须先将该位配置为1才行。
  • ✨QE位的使能,对于QSPI 4线Quad访问方式尤为重要。

📘指令介绍

  • 🌿winbond(华邦)W25Q64指令:
    在这里插入图片描述
    在这里插入图片描述

  • 🌿GD(兆易创新)GD25Q64指令集

在这里插入图片描述

在这里插入图片描述

🛠状态寄存器配置

  • 🌿状态寄存器1,QE位配置流程说明

👉针对GD(兆易创新)GD25Q64,经测试,如需修改QE位,可以通过使用写状态寄存器1(0x01)命令,读取2个字节数据(S0-S7、S8-S16),再进行修改。

  • 🔖个人测试时,如果单独写状态寄存器2的QE位,会写入不成功。
  • QE位是否配置成功,可以通过读状态寄存器(0x35),进行查询。
  • Write Status Register (WRSR) (01H or 31H or 11H)
    The Write Status Register (WRSR) command allows new values to be written to the Status Register. Before it can be accepted, a Write Enable (WREN) command must previously have been executed. After the Write Enable (WREN)
    command has been decoded and executed, the device sets the Write Enable Latch (WEL).
    The Write Status Register (WRSR) command has no effect on S15, S10, S1 and S0 of the Status Register. For command code of “01H” / “31H” / “11H”, the Status Register bits S7~S0 / S15~S8 / S23~S16 would be written. CS# must be driven high after the eighth bit of the data byte has been latched in. Otherwise, the Write Status Register (WRSR) command is not executed. As soon as CS# is driven high, the self-timed Write Status Register cycle (whose duration is tW) is initiated. While the Write Status Register cycle is in progress, the Status Register may still be read to check the value of the Write In Progress (WIP) bit. The Write In Progress (WIP) bit is 1 during the self-timed Write Status Register cycle, and is 0 when it is completed. When the cycle is completed, the Write Enable Latch (WEL) is reset.
    The Write Status Register (WRSR) command allows the user to change the values of the Block Protect (BP4, BP3, BP2, BP1, and BP0) bits, to define the size of the area that is to be treated as read-only. The Write Status Register (WRSR) command also allows the user to set or reset the Status Register Protect (SRP1 and SRP0) bits in accordance with the Write Protect (WP#) signal. The Status Register Protect (SRP1 and SRP0) bits and Write Protect (WP#) signal allow the device to be put in the Hardware Protected Mode. The Write Status Register (WRSR) command is not executed once the Hardware Protected Mode is entered

  • 🧬 时序图:
    在这里插入图片描述

  • 🌿读状态寄存器代码实现:

int qspi_flash_read_status1(uint8_t *status) {//读状态寄存器1QSPI_CommandTypeDef command;command.InstructionMode = QSPI_INSTRUCTION_1_LINE;command.AddressSize = QSPI_ADDRESS_24_BITS;command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;command.DdrMode = QSPI_DDR_MODE_DISABLE;command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;command.Instruction = READ_STATUS_REG_CMD; //0x05,读取:S7-S0command.AddressMode = QSPI_ADDRESS_NONE;command.DataMode = QSPI_DATA_1_LINE;command.DummyCycles = 0;command.NbData = 1;//1个字节if (HAL_QSPI_Command(&hqspi, &command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=HAL_OK) {return HAL_ERROR;}if (HAL_QSPI_Receive(&hqspi, status, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=HAL_OK) {return HAL_ERROR;}return HAL_OK;
}int qspi_flash_read_status2(uint8_t *status) {读状态寄存器2QSPI_CommandTypeDef command= {0};command.InstructionMode = QSPI_INSTRUCTION_1_LINE;command.AddressSize = QSPI_ADDRESS_24_BITS;command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;command.DdrMode = QSPI_DDR_MODE_DISABLE;command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;command.Instruction = READ_STATUS2_REG_CMD;//0x35读取:S15-S8command.AddressMode = QSPI_ADDRESS_NONE;command.DataMode = QSPI_DATA_1_LINE;command.DummyCycles = 0;command.NbData = 1;if (HAL_QSPI_Command(&hqspi, &command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=HAL_OK) {return HAL_ERROR;}if (HAL_QSPI_Receive(&hqspi, status, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=HAL_OK) {return HAL_ERROR;}return HAL_OK;
}
  • 🌿写状态寄存器代码实现:
int qspi_flash_write_status(uint8_t status1_val, uint8_t status2_val) {写状态寄存器1-2QSPI_CommandTypeDef command = {0};uint8_t buf[2];TxCplt = 0;qspi_flash_write_enable();command.InstructionMode = QSPI_INSTRUCTION_1_LINE;command.AddressSize = QSPI_ADDRESS_24_BITS;command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;command.DdrMode = QSPI_DDR_MODE_DISABLE;command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;command.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD;command.Instruction = WRITE_STATUS_REG_CMD;command.DummyCycles = 0;command.AddressMode = QSPI_ADDRESS_NONE;command.DataMode = QSPI_DATA_1_LINE;command.NbData = 2;//2个字节(S0-S7,S7-S16)buf[0] = status1_val;buf[1] = status2_val;if (HAL_QSPI_Command(&hqspi, &command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=HAL_OK) {return HAL_ERROR;}if (HAL_QSPI_Transmit(&hqspi, buf, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=HAL_OK) {return HAL_ERROR;}if (qspi_flash_atuo_polling_mem_ready() != HAL_OK) {return HAL_ERROR;}return HAL_OK;
}

📘读数据操作

  • 主要介绍4线QUAD操作指令。
  • 🌿Quad I/O Fast Read (EBH)
    Quad I/O快速读取命令可以通过在输入3字节地址(A23-A0)之后设置“连续读取模式”位(M7-0),从而进一步降低命令开销。如果“连续读模式”位(M5-4)=(1,0),则下一个四I/O快速读命令(在CS#升降之后)不需要EBH命令代码。如果“连续读模式”位(M5-4)=(1,0),下一个命令需要该命令代码,从而恢复正常操作。重置命令之前也可以用来在发出正常命令前重置(M7-0)。

在这里插入图片描述
在这里插入图片描述

⏰Dummy Cycle空指令周期
  • 🌿在STM32H7参考手册上,QUADSPI 通信配置寄存器 (QUADSPI_CCR),指定 CLK 周期数范围一般: 0 - 31。

对于stm32H7一般在快速读取数据时,默认设定的是6个Dummy Cycle,适用的最大工作频率是104MHz.验证这个参数是否设定合理,验证方法,读写数据页内容多次进行查看,验证数据是否正确即可。如果该参数设置不对,读取的数据和写入的数据对应不上,或者会出全部是0、或者是一个其他的uint8_t类型任意的固定或不固定的数值,也可能出现读取出来的数据和写入的数据和对应的地址错位的情况。

  • Winbond(华邦)W25Q64:没有找到相关描述
  • GD(兆易创新)GD25Q64
    在这里插入图片描述
  • 🌿读数据实现
/*** @brief   读NOR Flash* @note    从指定地址开始读取指定长度的数据* @param   pbuf   : 读取到数据保存的地址* @param   pbuf   : 指定开始读取的地址* @param   datalen: 指定读取数据的字节数* @retval  无*/
void norflash_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{QSPI_CommandTypeDef qspi_command_struct = {0};qspi_flash_write_enable();//使能QE位qspi_command_struct.InstructionMode = QSPI_INSTRUCTION_1_LINE;qspi_command_struct.Instruction = QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD;//Quad I/O Fast Read EBHqspi_command_struct.AddressMode = QSPI_ADDRESS_4_LINES;qspi_command_struct.AddressSize = QSPI_ADDRESS_24_BITS;qspi_command_struct.Address = addr;qspi_command_struct.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;qspi_command_struct.DummyCycles = 6; //此处必须要有空闲等待时间,否则数据和地址会出现错位qspi_command_struct.DataMode = QSPI_DATA_4_LINES;qspi_command_struct.NbData = datalen;qspi_command_struct.DdrMode = QSPI_DDR_MODE_DISABLE;qspi_command_struct.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;qspi_command_struct.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD;HAL_QSPI_Command(&hqspi, &qspi_command_struct, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);HAL_QSPI_Receive(&hqspi, pbuf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
}

📗擦除和写入操作

之所以将擦除和写入放在一起说明,是因为nor flash写操作前,需要先对当前要写入数据的地址扇区进行擦除操作,目的是为了将要写入的区域,保证为空(0xff),才能保证写入的数据的准确性。需要注意的是,最小擦除大小为扇区单位(4K)。

  • 📝扇区擦除操作:
int qspi_flash_erase_sector(uint32_t address) {uint32_t EraseStartAddress =  address;EraseStartAddress &=0x0FFFFFFF; //最大可寻址范围EraseStartAddress = EraseStartAddress -  EraseStartAddress % 0x1000;//起始地址-扇区地址QSPI_CommandTypeDef command = {0};qspi_flash_write_enable();//写使能QE=1command.InstructionMode = QSPI_INSTRUCTION_1_LINE;command.AddressSize = QSPI_ADDRESS_24_BITS;//24位地址,可寻址范围小于或等于16MBcommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;command.DdrMode = QSPI_DDR_MODE_DISABLE;command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;command.Instruction = SUBSECTOR_ERASE_4_BYTE_ADDR_CMD;//擦除指令0x20command.AddressMode = QSPI_ADDRESS_1_LINE;command.Address = EraseStartAddress;command.DataMode = QSPI_DATA_NONE;command.DummyCycles = 0;if (HAL_QSPI_Command(&hqspi, &command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=HAL_OK) {return HAL_ERROR;}if (qspi_flash_atuo_polling_mem_ready() != HAL_OK) {return HAL_ERROR;}return HAL_OK;
}
  • 📑写操作
/* 扇区缓存 */
static uint8_t g_norflash_buf[4096];/*** @brief   写NOR Flash* @note    在指定地址开始写入指定长度的数据,该函数带擦除操作*          NOR Flash一般是:256个字节为一个Page,4096个字节为一个Sector,16个Sector为1个Block*          擦除的最小单位为Sector* @param   pbuf   : 待写入数据的起始地址* @param   addr   : 指定开始写入数据的地址* @param   datalen: 指定写入数据的字节数* @retval  无*/
void norflash_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{uint32_t secpos;uint16_t secoff;uint16_t secremain;uint16_t i;uint8_t *norflash_buf;norflash_buf = g_norflash_buf;                                      /* 扇区缓存 */secpos = addr / 4096;                                               /* 扇区索引 */secoff = addr % 4096;                                               /* 写入起始地址在当前扇区的偏移量 */secremain = 4096 - secoff;                                          /* 计算当扇区剩余的字节数 */if (datalen <= secremain)                                           /* 不大于4096个字节 */{secremain = datalen;}while (1){norflash_read(norflash_buf, secpos * 4096, 4096);               /* 读出当前整个扇区的内容,用于擦除扇区后恢复非写入区域的数据 */for (i=0; i<secremain; i++)                                     /* 校验数据 */{if (norflash_buf[secoff + i] != 0xFF)                       /* 写入区域中有非0xFF的数据,就需要擦除 */{break;}}if (i < secremain)                                              /* 需要擦除 */{
//                            /* 擦除整个扇区 */qspi_flash_erase_sector(secpos) ;for (i=0; i<secremain; i++)                                 /* 将待写入的数据,先写入扇区缓存 */{norflash_buf[i + secoff] = pbuf[i];}norflash_write_nocheck(norflash_buf, secpos * 4096, 4096);  /* 写入整个扇区 */}else                                                            /* 不需要擦除,可以直接写入 */{norflash_write_nocheck(pbuf, addr, secremain);              /* 直接写扇区剩余的空间 */}if (datalen == secremain)                                       /* 写入结束 */{break;}else                                                            /* 写入未结束 */{secpos++;                                                   /* 扇区索引增1 */secoff = 0;                                                 /* 扇区偏移位置为0 */pbuf += secremain;                                          /* 偏移pbuf指针地址secremain个已写入的字节数 */addr += secremain;                                          /* 偏移写入地址secremain个已写入的字节数 */datalen -= secremain;                                       /* 计算剩余写入的字节数 */if (datalen > 4096)                                         /* 剩余数据量超过4096,只能先写入一个扇区数据 */{secremain = 4096;}else                                                        /* 剩余数据量不超过4096,可一次性写入 */{secremain = datalen;}}}
}

📓复位nor flash操作

  • GD25Q64复位使能和复位指令:Enable Reset (66H) and Reset (99H)
  • 复位内容:Volatile settings:易失性设置,包括易失性状态寄存器位、写使能锁存状态(WEL)、编程/擦除暂停状态、读取参数设置(P7-P0)、连续读取模式位设置(M7-M0)和环绕位设置(W6-W4).
  • 复位流程:执行复位命令序列包括:先发送使能复位命令(66H),然后将CS#拉高,再发送复位命令(99H),最后将CS#拉高。设备在接受复位命令后会花费大约tRST / tRST_E的时间来完成复位,在此期间不会接受任何其他命令。

在这里插入图片描述

  • 🌿High-Z时间:

在这里插入图片描述

  • STM32H750 ,时钟配置为400MHz,执行一个__NOP( )控制指令时间:1/400MHz=2.5ns,
  • 🌿复位命令发出之后,到nor flash 执行完内部复位所需的时间:12ms
    在这里插入图片描述

  • 来自:https://doc.embedfire.com/mcu/stm32/h743prov/hal/zh/latest/book/QSPI.html#qspi-7

**
* @brief  复位QSPI存储器。
* @param  QSPIHandle: QSPI句柄
* @retval 无
*/
static uint8_t QSPI_ResetMemory()
{QSPI_CommandTypeDef s_command;/* 初始化复位使能命令 */s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;s_command.Instruction       = RESET_ENABLE_CMD;//0x66s_command.AddressMode       = QSPI_ADDRESS_NONE;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 (HAL_QSPI_Command(&QSPIHandle, &s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {return QSPI_ERROR;}/* 发送复位存储器命令 0x99*/s_command.Instruction = RESET_MEMORY_CMD;if (HAL_QSPI_Command(&QSPIHandle, &s_command,HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {return QSPI_ERROR;}/* 配置自动轮询模式等待存储器就绪 */if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) !=QSPI_OK) {return QSPI_ERROR;}return QSPI_OK;
}

📗QSPI外设引脚配置

  • 🔖QSPI外设引脚配置不是固定的,可以根据实际使用情况,可以映射到任意支持的引脚上。

在这里插入图片描述

  • 🔨QSPI引脚配置:需要将外设引脚的速度设置为非常高(Very HIGH)。
    在这里插入图片描述
  • 🔖需要注意CS引脚配置,不能使能Fast Mode.
void MX_QUADSPI_Init(void)
{/* USER CODE BEGIN QUADSPI_Init 0 *//* USER CODE END QUADSPI_Init 0 *//* USER CODE BEGIN QUADSPI_Init 1 *//* USER CODE END QUADSPI_Init 1 */hqspi.Instance = QUADSPI;hqspi.Init.ClockPrescaler = 1; //200MHz/(1+1)=100MHzhqspi.Init.FifoThreshold = 32; //最大支持32hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;hqspi.Init.FlashSize = 22;//8MB= 2^[FSIZE+1] =1<<23hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;//信号(CS)的高电平持续时间hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;/*时钟模式选择模式0,nCS为高电平(片选释放),传输数据CLK保持低电平*/hqspi.Init.FlashID = QSPI_FLASH_ID_1;hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;if (HAL_QSPI_Init(&hqspi) != HAL_OK){Error_Handler();}/* USER CODE BEGIN QUADSPI_Init 2 *//* USER CODE END QUADSPI_Init 2 */}
  • 有关信号时间参数信息:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 📝QSPI初始化配置:(参考野火内容介绍:https://doc.embedfire.com/mcu/stm32/h743prov/hal/zh/latest/book/QSPI.html#qspi-7

/**
* @brief  初始化QSPI存储器
* @retval QSPI存储器状态
*/
uint8_t BSP_QSPI_Init(void)
{QSPI_CommandTypeDef s_command;uint8_t value = W25Q256JV_FSR_QE;//0X02/* QSPI存储器复位 */if (QSPI_ResetMemory() != QSPI_OK) {return QSPI_NOT_SUPPORTED;}/* 使能写操作 */if (QSPI_WriteEnable() != QSPI_OK) {return QSPI_ERROR;}/* 设置四路使能的状态寄存器,使能四通道IO2和IO3引脚 */s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;s_command.Instruction       = WRITE_STATUS_REG2_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.NbData            = 1;s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;/* 配置命令 */if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {return QSPI_ERROR;}/* 传输数据 */if (HAL_QSPI_Transmit(&QSPIHandle, &value, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {return QSPI_ERROR;}/* 自动轮询模式等待存储器就绪 */if (QSPI_AutoPollingMemReady(W25Q256JV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) {return QSPI_ERROR;}/* 配置地址模式为 4 字节 */if (QSPI_Addr_Mode_Init() != QSPI_OK) {return QSPI_ERROR;}return QSPI_OK;
}
  • 🍕相关参考和资料推荐
  • 📌安富莱_STM32-V7:https://www.armbbs.cn/forum.php?mod=viewthread&tid=91590&highlight=STM32-V7
  • 📍QSPI驱动例程可以参考:正点原子STM32H750中的相关例程:http://47.111.11.73/docs/boards/stm32/zdyz_stm32h750_polaris.html
  • 🎈或者参考野火版的开发板资料:https://gitee.com/Embedfire-stm32h7-pro/ebf_stm32h743_pro_code_v
  • 🥕间接模式切换内存映射模式项目参考:https://github.com/ziancube/GD25Qxx-Stm32h747

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/445460.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VScode 自定义代码配色方案

vscode是一款高度自定义配置的编辑器, 我们来看看如何使用它自定义配色吧 首先自定义代码配色是什么呢? 看看我的代码界面 简而言之, 就是给你的代码的不同语义(类名, 函数名, 关键字, 变量)等设置不同的颜色, 使得代码的可读性变强. 其实很多主题已经给出了定制好的配色方案…

闯关leetcode——88. Merge Sorted Array

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/merge-sorted-array/description/ 内容 You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, and two integers m and n, representing the number of elements …

为什么人工智能用 Python?

人工智能领域倾向于使用Python&#xff0c;主要归因于Python的多个显著优势&#xff1a; 简洁性与可读性&#xff1a;Python的语法设计简洁明了&#xff0c;代码易于阅读和理解&#xff0c;这对于涉及复杂算法和逻辑的人工智能项目尤为重要。它降低了编程门槛&#xff0c;使得…

Unity3D 单例模式

Unity3D 泛型单例 单例模式 单例模式是一种创建型设计模式&#xff0c;能够保证一个类只有一个实例&#xff0c;提供访问实例的全局节点。 通常会把一些管理类设置成单例&#xff0c;例如 GameManager、UIManager 等&#xff0c;可以很方便地使用这些管理类单例&#xff0c;…

DGX的优势

NVIDIA DGX 的 AI 领导力 文章目录 前言一、概述推动跨行业的 AI 创新二、优势客户体验到哪些好处?1. 利用生成式 AI 释放研究人员的潜力2. 加快现代应用程序的上市时间3. 利用 AI 改善客户体验三、性能性能很重要1. 为世界上最先进的超级计算机提供动力2. 打破世界纪录3. 提高…

Go编译为可执行文件

在window下打包成其他系统可运行的文件 1.在window下打包成window下可执行文件 在项目main.go同级目录下&#xff0c;逐条执行以下命令 set CGO_ENABLED0 set GOOSwindows set GOARCHamd64 go build -o main-windows.exe main.go 2.在window下打包成linux 在项目main.go同级目…

Python从入门到高手6.3节-字符串操作方法

目录 6.3.1 字符串常用操作方法 6.3.2 获取字符串长度 6.3.3 字符串的大小写操作 6.3.4 删除字符串中的指定字符 6.3.5 字符串的子串查找 6.3.6 字符串的子串统计 6.3.7 字符串的子串替换 6.3.8 字符串的拆分函数 6.3.9 字符串的前缀与后缀 6.3.10 你一定要成为高手 …

FLINK内存管理解析,taskmanager、jobmanager

1、在 Flink 中设置内存的方法是配置以下两个选项之一&#xff1a; 1&#xff09;Total Flink memory&#xff1a;taskmanager.memory.flink.sizejobmanager.memory.flink.size 2&#xff09;Total process memory&#xff1a;taskmanager.memory.process.sizejobmanager.mem…

Linux驱动开发(速记版)--设备模型

第八十章 设备模型基本框架-kobject 和 kset 80.1 什么是设备模型 设备模型使Linux内核处理复杂设备更高效。 字符设备驱动适用于简单设备&#xff0c;但对于电源管理和热插拔&#xff0c;不够灵活。 设备模型允许开发人员以高级方式描述硬件及关系&#xff0c;提供API处理设备…

vue3学习之插槽slot

关于slot web组件内部的占位符&#xff0c;可以使用自己的标记填充这个占位符 &#xff0c;具名插槽就是在slot标签上添加name属性&#xff08;https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/slot&#xff09; vue3官方文档&#xff1a;https://cn.vuejs.org/gui…

论文阅读 BLIP-2

Bootstrapping Language-Image Pre-training with Frozen Image Encoders and Large Language Models 使用冻结的图像编码器和大型语言模型进行语言-图像预训练的引导 BLIP-2 通过一个轻量级的查询变换器弥合了模态之间的差距。 Querying Transformer 第一阶段通过冻结的图像编…

构建流媒体管道:利用 Docker 部署 Nginx-RTMP 从 FFmpeg RTMP 推流到 HLS 播放的完整流程

最近要实现一个类似导播台的功能&#xff0c;于是我先用 FFmpeg 实现一个参考对照的 Demo&#xff0c;我将其整理为一篇文章&#xff0c;方便后续大家或者和自己参考&#xff01; 1、软件工具介绍 本次部署相关软件 / 工具如下&#xff1a; FFmpeg&#xff1a;全称是 Fast Fo…

YOLO11改进 | 注意力机制| 对小目标友好的BiFormer【CVPR2023】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 本文介绍了一种新颖的动态稀疏注意力机制…

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表&#xff08;重点掌握&#xff09;】 可以使用类&#xff1a;“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁&#xff0c;就是直接给put&#xff0c;get等方法加上synch…

LLM | Tokenization 从原理与代码了解GPT的分词器

声明&#xff1a;以上内容全是学习Andrej Karpathy油管教学视频的总结。 --------------------------------------------------------------------------------------------------------------------------------- 大家好。在今天我们学习llm中的Tokenization&#xff0c;即分…

【Golang】关于Go语言中的IO操作

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

day01-Qt5入门

day01-Qt5入门 1.下载Qtcreate 官网地址&#xff1a;http://qt-project.org/downloads 2.配置环境变量 将类似于 D:\Qt\Qt5.1.1\5.1.1\mingw48_32\bin 的目录添加到环境变量中 3.创建一个新项目 输入自己的项目名称&#xff0c;后面默认下一部 4.运行第一个项目 在窗口…

[红队apt]自解压文件攻击

免责声明:本文用于了解攻击者攻击手法使用&#xff0c;请勿用于非法用途 前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理黑客利用自解压文件进行攻击的流程原理 自解压文件概念 后缀格式:exe 用途: 早期windows系统有些时候没有安装压缩程序&#xf…

GitLab Runner 通过 Pipeline 流水线实现持续集成 CI

文章目录 1、基础环境2、安装 Docker3、安装 GitLab4、安装 JDK5、安装 Maven6、安装 GitLab Runner7、注册 GitLab Runner8、上传 GitLab9、配置 Pipeline 1、基础环境 本次演示搭建&#xff0c;我使用的是阿里云服务器&#xff0c;配置如下&#xff1a; 服务器1&#xff1a;…

微服务swagger解析部署使用全流程

1、介绍 swagger是一个在线接口说明文档&#xff0c;在代码中通过注解的方式将说明问题集成到项目&#xff0c;代码发生修改&#xff0c;说明文档同步修改&#xff0c;前后台联调可以快速同步数据。 2、应用 1、引入依赖 <dependency><groupId>io.springfox<…