STM32H7B0VB OSPI 操作 25QXX FLASH

这篇博客详细介绍了如何在STM32H7B0微控制器上使用OSPI接口操作W25QXX系列闪存,包括初始化配置、读写操作、擦除命令和错误处理。在实践中发现使用CubeMX生成的OSPILibrary存在读取ID错误的问题,并提供了相应的解决步骤和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STM32H7B0VB OSPI 操作 25QXX FLASH

实测使用CUBE MX生成 的 osp 库会有问题,读到的ID 是错的。


#include "w25qxx.h"
#include "octospi.h"
#include "stm32h7xx_hal_ospi.h"
/**
 * @brief  初始化OSPI存储器
 * @retval OSPI存储器状态
 */

uint8_t W25Qxx_OSPI_Init(uint16_t ClockPrescaler)
{
	OSPI_RegularCmdTypeDef s_command;
	uint16_t w25qxx_id;
	uint8_t value = W25QxJV_FSR_QE;
	GPIO_InitTypeDef GPIO_InitStruct;

    /**OCTOSPI1 GPIO Configuration
    PE2     ------> OCTOSPIM_P1_IO2
    PD11     ------> OCTOSPIM_P1_IO0
    PD12     ------> OCTOSPIM_P1_IO1
    PD13     ------> OCTOSPIM_P1_IO3
    PB6     ------> OCTOSPIM_P1_NCS
    */
	RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
	PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_OSPI;
	PeriphClkInitStruct.PLL2.PLL2M = 5;
	PeriphClkInitStruct.PLL2.PLL2N = 50;
	PeriphClkInitStruct.PLL2.PLL2P = 5;
	PeriphClkInitStruct.PLL2.PLL2Q = 100;
	PeriphClkInitStruct.PLL2.PLL2R = 50;
	PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
	PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
	PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
	PeriphClkInitStruct.OspiClockSelection = RCC_OSPICLKSOURCE_PLL2;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_GPIOD_CLK_ENABLE();
	__HAL_RCC_GPIOE_CLK_ENABLE();
	__HAL_RCC_OCTOSPIM_CLK_ENABLE();
	__HAL_RCC_OSPI1_CLK_ENABLE();
	
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF10_OCTOSPIM_P1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	hospi1.Instance = OCTOSPI1;
	hospi1.Init.FifoThreshold = 24;
	hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
	hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_MACRONIX;
	hospi1.Init.DeviceSize = OSPI_FLASH_SIZE;
	hospi1.Init.ChipSelectHighTime =6;
	hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
	hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;
	hospi1.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED;
	hospi1.Init.ClockPrescaler =ClockPrescaler;
	hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_HALFCYCLE;
	hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_DISABLE;
	hospi1.Init.ChipSelectBoundary = 8;
	hospi1.Init.ClkChipSelectHighTime = 0;
	hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;
	hospi1.Init.MaxTran = 0;
	hospi1.Init.Refresh = 0;
	HAL_OSPI_Init(&hospi1);

	/* OSPI存储器复位 */
	if (W25Qxx_OSPI_ResetMemory() != OSPI_OK)
	{
		return OSPI_NOT_SUPPORTED;
	}
	/* 使能写操作 */
	if (W25Qxx_OSPI_WriteEnable() != OSPI_OK)
	{
		return OSPI_ERROR;
	}
	/* 设置四路使能的状态寄存器,使能四通道IO2和IO3引脚 */

	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
	s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
	s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = WRITE_STATUS_REG2_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_NONE;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_1_LINE;
	s_command.DummyCycles        = 0; 
	s_command.NbData = 1;
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
	s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
	s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
	s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
	s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
	/* 配置命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
	!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	/* 传输数据 */
	if (HAL_OSPI_Transmit(&hospi1, &value, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
	!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	/* 自动轮询模式等待存储器就绪 */
	if (W25Qxx_OSPI_AutoPollingMemReady(W25QxJV_SUBSECTOR_ERASE_MAX_TIME) != OSPI_OK)
	{
		return OSPI_ERROR;
	}
	w25qxx_id=W25Qxx_OSPI_FLASH_ReadDeviceID();
	/* 配置地址模式为 4 字节 , 非W25Q256直接跳过*/
	if ( w25qxx_id!= W25Qxx_ID)
		return OSPI_OK;

	if (W25Qxx_OSPI_Addr_Mode_Init() != OSPI_OK)
	{
		return OSPI_ERROR;
	}

	return OSPI_OK;
}
 
/**
 * @brief  检查地址模式不是4字节地址,配置为4字节
 * @retval OSPI存储器状态
 */
uint8_t W25Qxx_OSPI_Addr_Mode_Init(void)
{
	OSPI_RegularCmdTypeDef s_command;
	uint8_t reg;
	
	/* 初始化读取状态寄存器命令 */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = WRITE_STATUS_REG3_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_NONE;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_1_LINE;
	s_command.DummyCycles        = 0; 
	s_command.NbData = 1;
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
	
 
	/* 配置命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	/* 接收数据 */
	if (HAL_OSPI_Receive(&hospi1, &reg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
 
	/* 检查寄存器的值 */
	if ((reg & W25Q256FV_FSR_4ByteAddrMode) == 1)    // 4字节模式
	{
		return OSPI_OK;
	}
	else    // 3字节模式
	{
		/* 配置进入 4 字节地址模式命令 */
		s_command.Instruction = Enter_4Byte_Addr_Mode_CMD;
		s_command.DataMode = HAL_OSPI_DATA_NONE;
 
		/* 配置并发送命令 */
		if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
				!= HAL_OK)
		{
			return OSPI_ERROR;
		}
 
		/* 自动轮询模式等待存储器就绪 */
		if (W25Qxx_OSPI_AutoPollingMemReady(
				W25QxJV_SUBSECTOR_ERASE_MAX_TIME) != OSPI_OK)
		{
			return OSPI_ERROR;
		}
 
		return OSPI_OK;
	}
}
 
/**
 * @brief  从OSPI存储器中读取大量数据.
 * @param  pData: 指向要读取的数据的指针
 * @param  ReadAddr: 读取起始地址
 * @param  Size: 要读取的数据大小
 * @retval OSPI存储器状态
 */
uint8_t W25Qxx_OSPI_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
{
	OSPI_RegularCmdTypeDef s_command;
 
	if(Size == 0)	return OSPI_OK;
 
	/* 初始化读命令 */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = QUAD_INOUT_FAST_READ_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_4_LINES;
	#if W25Qxx_ID==W25Q256
		s_command.AddressSize        = HAL_OSPI_ADDRESS_32_BITS;
	#else
		s_command.AddressSize        = HAL_OSPI_ADDRESS_24_BITS;
	#endif
	s_command.Address            = ReadAddr;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_4_LINES;
	s_command.DummyCycles        = 6; 
	s_command.NbData = Size;
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
 
	/* 配置命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
 
	/* 接收数据 */
	if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	
	return OSPI_OK;
}

/**
 * @brief  将大量数据写入OSPI存储器
 * @param  pData: 指向要写入数据的指针
 * @param  WriteAddr: 写起始地址
 * @param  Size: 要写入的数据大小
 * @retval OSPI存储器状态
 */
uint8_t W25Qxx_OSPI_WritePage(uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
{
	OSPI_RegularCmdTypeDef s_command;
	
		/* 启用写操作 */
	if (W25Qxx_OSPI_WriteEnable() != OSPI_OK)
	{
		return OSPI_ERROR;
	}
 
	/* 初始化程序命令 */	
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = QUAD_INPUT_PAGE_PROG_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_1_LINE;
	#if W25Qxx_ID==W25Q256
		s_command.AddressSize        = HAL_OSPI_ADDRESS_32_BITS;
	#else
		s_command.AddressSize        = HAL_OSPI_ADDRESS_24_BITS;
	#endif
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_4_LINES;
	s_command.DummyCycles        = 0; 
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_ONLY_FIRST_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
	s_command.Address = WriteAddr;
	s_command.NbData = Size;

	/* 配置命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}

	/* 传输数据 */
	if (HAL_OSPI_Transmit(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
		
		/* 配置自动轮询模式等待程序结束 */
		if (W25Qxx_OSPI_AutoPollingMemReady(HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != OSPI_OK)
		{
			return OSPI_ERROR;
		}
 
	return OSPI_OK;
}

//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//CHECK OK
void W25Qxx_OSPI_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite)   
{ 			 		 
	uint32_t pageremain;	   
	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
	if(NumByteToWrite<=pageremain)
	{
		pageremain=NumByteToWrite;//不大于256个字节
	}
	while(1)
	{	   
		W25Qxx_OSPI_WritePage(pBuffer,WriteAddr,pageremain);
		if(NumByteToWrite==pageremain)
		{
			break;//写入结束了
		}
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;	

			NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
			if(NumByteToWrite>256)
			{
				pageremain=256; //一次可以写入256个字节
			}
			else
			{
				pageremain=NumByteToWrite; 	  //不够256个字节了
			}
		}
	}    
} 

//写SPI FLASH  
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)						
uint8_t W25QXX_BUFFER[4096];		 
void W25Qxx_OSPI_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t Size)
{
	uint32_t secpos;
	uint32_t secoff;
	uint32_t secremain;	   
	uint32_t i;    
	uint8_t *W25QXX_BUF;	  
	W25QXX_BUF=W25QXX_BUFFER;	     
	secpos=WriteAddr/4096;//扇区地址  
	secoff=WriteAddr%4096;//在扇区内的偏移
	secremain=4096-secoff;//扇区剩余空间大小   
	if(Size<=secremain)
	{
		secremain=Size;//不大于4096个字节
	}
	while(1) 
	{	
		W25Qxx_OSPI_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
		for(i=0;i<secremain;i++)//校验数据
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)
			{
				break;//需要擦除 
			}				
		}
		if(i<secremain)//需要擦除
		{
			W25Qxx_OSPI_Erase_Block(secpos);		//擦除这个扇区
			for(i=0;i<secremain;i++)	   		//复制
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];	  
			}
			W25Qxx_OSPI_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  
		}
		else
		{
			W25Qxx_OSPI_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. 
		}			
		if(Size==secremain)
		{
			break;//写入结束了
		}
		else//写入未结束
		{
			secpos++;//扇区地址增1
			secoff=0;//偏移位置为0 	 
			pBuffer+=secremain;  				//指针偏移
			WriteAddr+=secremain;				//写地址偏移	   
			Size-=secremain;			//字节数递减
			if(Size > 4096)
			{
				secremain = 4096;//下一个扇区还是写不完
			}
			else
			{
				secremain = Size;		//下一个扇区可以写完了
			}
		}	 
	} 
}
 
/**
 * @brief  擦除OSPI存储器的指定块
 * @param  BlockAddress: 需要擦除的块地址
 * @retval OSPI存储器状态
 */
uint8_t W25Qxx_OSPI_Erase_Block(uint32_t BlockAddress)
{
	OSPI_RegularCmdTypeDef s_command;
	
	/* 初始化擦除命令 */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = SECTOR_ERASE_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_1_LINE;
	#if W25Qxx_ID==W25Q256
		s_command.AddressSize        = HAL_OSPI_ADDRESS_32_BITS;
	#else
		s_command.AddressSize        = HAL_OSPI_ADDRESS_24_BITS;
	#endif
	s_command.Address            = BlockAddress*4096;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_NONE;
	s_command.DummyCycles        = 0; 
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
 
	/* 启用写操作 */
	if (W25Qxx_OSPI_WriteEnable() != OSPI_OK)
	{
		return OSPI_ERROR;
	}
 
	/* 发送命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}

	/* 配置自动轮询模式等待擦除结束 */
	if (W25Qxx_OSPI_AutoPollingMemReady(W25QxJV_SUBSECTOR_ERASE_MAX_TIME) != OSPI_OK)
	{
		return OSPI_ERROR;
	}
	return OSPI_OK;
}
 
/**
 * @brief  擦除整个OSPI存储器
 * @retval OSPI存储器状态
 */
uint8_t W25Qxx_OSPI_Erase_Chip(void)
{
	OSPI_RegularCmdTypeDef s_command;
	
	/* 初始化擦除命令 */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = CHIP_ERASE_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_NONE;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_NONE;
	s_command.DummyCycles        = 0; 
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
 
	/* 启用写操作 */
	if (W25Qxx_OSPI_WriteEnable() != OSPI_OK)
	{
		return OSPI_ERROR;
	}
	/* 发送命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	/* 配置自动轮询模式等待擦除结束 */
	if (W25Qxx_OSPI_AutoPollingMemReady(W25QxJV_BULK_ERASE_MAX_TIME) != OSPI_OK)
	{
		return OSPI_ERROR;
	}
	return OSPI_OK;
}
 
/**
 * @brief  读取OSPI存储器的当前状态
 * @retval OSPI存储器状态
 */
uint8_t W25Qxx_OSPI_GetStatus(void)
{
	OSPI_RegularCmdTypeDef s_command;
	uint8_t reg;
	/* 初始化读取状态寄存器命令 */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = READ_STATUS_REG1_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_NONE;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_1_LINE;
	s_command.DummyCycles        = 0; 
	s_command.NbData             = 1;
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
 
	/* 配置命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	/* 接收数据 */
	if (HAL_OSPI_Receive(&hospi1, &reg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	/* 检查寄存器的值 */
	if ((reg & W25QxJV_FSR_BUSY) != 0)
	{
		return OSPI_BUSY;
	}
	else
	{
		return OSPI_OK;
	}
}
 
/**
 * @brief  复位OSPI存储器。
 * @param  hOSPI: OSPI句柄
 * @retval 无
 */
uint8_t W25Qxx_OSPI_ResetMemory(void)
{
	OSPI_RegularCmdTypeDef s_command;
	
	/* 初始化复位使能命令 */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = RESET_ENABLE_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_NONE;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_NONE;
	s_command.DummyCycles        = 0; 
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
	/* 发送命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return OSPI_ERROR;
	}
 
	/* 发送复位存储器命令 */
	s_command.Instruction = RESET_MEMORY_CMD;
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return OSPI_ERROR;
	}
 
	s_command.InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES;
	s_command.Instruction = RESET_ENABLE_CMD;
	s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
 
	/* 发送命令 */
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return OSPI_ERROR;
	}
 
	/* 发送复位存储器命令 */
	s_command.Instruction = RESET_MEMORY_CMD;
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return OSPI_ERROR;
	}
	/* 配置自动轮询模式等待存储器就绪 */
	if (W25Qxx_OSPI_AutoPollingMemReady(HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != OSPI_OK)
	{
		return OSPI_ERROR;
	}
	return OSPI_OK;
}
 
/**
 * @brief  发送写入使能,等待它有效.
 * @param  hOSPI: OSPI句柄
 * @retval 无
 */
uint8_t W25Qxx_OSPI_WriteEnable(void)
{
	OSPI_RegularCmdTypeDef s_command;
	OSPI_AutoPollingTypeDef s_config;
	/* 启用写操作 */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = WRITE_ENABLE_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_NONE;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_NONE;
	s_command.DummyCycles        = 0; 
	s_command.DataDtrMode        = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;

	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
 
	s_command.Instruction = READ_STATUS_REG1_CMD;
	s_command.DataMode = HAL_OSPI_DATA_1_LINE;
	s_command.NbData = 1;
	
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	/* 配置自动轮询模式等待写启用 */
	s_config.Match = W25QxJV_FSR_WREN;;
	s_config.Mask = W25QxJV_FSR_WREN;;
	s_config.MatchMode = HAL_OSPI_MATCH_MODE_AND;
	s_config.Interval = 0x10;
	s_config.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;

	if (HAL_OSPI_AutoPolling(&hospi1, &s_config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return OSPI_ERROR;
	}
	return OSPI_OK;
}
 
/**
 * @brief  读取存储器的SR并等待EOP
 * @param  hOSPI: OSPI句柄
 * @param  Timeout 超时
 * @retval 无
 */
uint8_t W25Qxx_OSPI_AutoPollingMemReady(uint32_t Timeout)
{
	OSPI_RegularCmdTypeDef s_command;
	OSPI_AutoPollingTypeDef s_config;
	/* 配置自动轮询模式等待存储器准备就绪 */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = READ_STATUS_REG1_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_NONE;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_1_LINE;
	s_command.DummyCycles        = 0; 
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
	
	if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK)
	{
		return OSPI_ERROR;
	}
	
	s_config.Match = 0x00;
	s_config.Mask = W25QxJV_FSR_BUSY;
	s_config.MatchMode = HAL_OSPI_MATCH_MODE_AND;
	s_config.Interval = 0x10;
	s_config.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;
 
	if (HAL_OSPI_AutoPolling(&hospi1, &s_config, Timeout) != HAL_OK)
	{
		return OSPI_ERROR;
	}
	return OSPI_OK;
}
 
/**
 * @brief  读取FLASH Device ID
 * @param 	无
 * @retval FLASH Device ID
 */
uint32_t W25Qxx_OSPI_FLASH_ReadDeviceID(void)
{
	OSPI_RegularCmdTypeDef s_command;
	uint32_t Temp = 0;
	uint8_t pData[3]={0,0,0};
	/*##-2-读取设备ID测试    ###########################################*/
	/* 读取制造/设备 ID */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = READ_ID_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_1_LINE;
	s_command.AddressSize        = HAL_OSPI_ADDRESS_24_BITS;
	s_command.Address            = 0x000000;
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_1_LINE;
	s_command.DummyCycles        = 0; 
	s_command.NbData = 2;
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
 
	HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

	HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);

 
	Temp = pData[1] | (pData[0] << 8);
 
	return Temp;
}

uint32_t W25Qxx_OSPI_EnableMemoryMappedMode(void)
{
  OSPI_RegularCmdTypeDef      s_command;
  OSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
 
  /* Configure the command for the read instruction */
	s_command.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG;
  s_command.FlashId            = HAL_OSPI_FLASH_ID_1;
  s_command.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE;
	s_command.Instruction        = QUAD_INOUT_FAST_READ_CMD;
	s_command.AddressMode        = HAL_OSPI_ADDRESS_4_LINES;
	#if W25Qxx_ID==W25Q256
		s_command.AddressSize        = HAL_OSPI_ADDRESS_32_BITS;
	#else
		s_command.AddressSize        = HAL_OSPI_ADDRESS_24_BITS;
	#endif
	s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
	s_command.DataMode 					 = HAL_OSPI_DATA_4_LINES;
	s_command.DummyCycles        = 6; 
	s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
	s_command.SIOOMode           = HAL_OSPI_SIOO_INST_EVERY_CMD;
  s_command.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS;
  s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
  s_command.AddressDtrMode     = HAL_OSPI_ADDRESS_DTR_DISABLE;
  s_command.DQSMode            = HAL_OSPI_DQS_DISABLE;
 
  /* Configure the memory mapped mode */
  s_mem_mapped_cfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;
  s_mem_mapped_cfg.TimeOutPeriod     = 0;
 
	HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
	
  return HAL_OSPI_MemoryMapped(&hospi1, &s_mem_mapped_cfg);
}

#ifndef W25QXX_OSPI_H_
#define W25QXX_OSPI_H_
 
#include "stm32h7xx_hal.h"

#define W25Q80 	0XEF13 	
#define W25Q16 	0XEF14
#define W25Q32 	0XEF15
#define W25Q64 	0XEF16
#define W25Q128	0XEF17  
#define W25Q256	0XEF18 

#define W25Qxx_ID W25Q64
 
/* OSPI Error codes */
#define OSPI_OK            ((uint8_t)0x00)
#define OSPI_ERROR         ((uint8_t)0x01)
#define OSPI_BUSY          ((uint8_t)0x02)
#define OSPI_NOT_SUPPORTED ((uint8_t)0x04)
#define OSPI_SUSPENDED     ((uint8_t)0x08)
 
 
/* W25QxJV Micron memory */
/* Size of the flash */
#define OSPI_FLASH_SIZE            23     /* 地址总线宽度访问整个内存空间 */
#define OSPI_PAGE_SIZE             256
 
/* OSPI Info */
typedef struct {
  uint32_t FlashSize;          /*!< 闪存大小 */
  uint32_t EraseSectorSize;    /*!< 擦除操作的扇区大小 */
  uint32_t EraseSectorsNumber; /*!< 擦除操作的扇区数 */
  uint32_t ProgPageSize;       /*!< 编程操作的页面大小 */
  uint32_t ProgPagesNumber;    /*!< 编程操作的页面数 */
} OSPI_Info;
 
/* Private define ------------------------------------------------------------*/
/*命令定义-开头*******************************/
/**
  * @brief  W25QxJV配置
  */
#define W25QxJV_DUMMY_CYCLES_READ           4
#define W25QxJV_DUMMY_CYCLES_READ_QUAD      10
 
#define W25QxJV_BULK_ERASE_MAX_TIME         250000
#define W25QxJV_SECTOR_ERASE_MAX_TIME       3000
#define W25QxJV_SUBSECTOR_ERASE_MAX_TIME    800
 
/**
  * @brief  W25QxJV 指令
  */
/* 复位操作 */
#define RESET_ENABLE_CMD                     0x66
#define RESET_MEMORY_CMD                     0x99
 
#define ENTER_QPI_MODE_CMD                   0x38
#define EXIT_QPI_MODE_CMD                    0xFF
 
/* 识别操作 */
#define READ_ID_CMD                          0x90
#define DUAL_READ_ID_CMD                     0x92
#define QUAD_READ_ID_CMD                     0x94
#define READ_JEDEC_ID_CMD                    0x9F
 
/* 读操作 */
#define READ_CMD                             0x03
#define FAST_READ_CMD                        0x0B
#define DUAL_OUT_FAST_READ_CMD               0x3B
#define DUAL_INOUT_FAST_READ_CMD             0xBB
#define QUAD_OUT_FAST_READ_CMD               0x6B
#define QUAD_INOUT_FAST_READ_CMD             0xEB
 
/* 写操作 */
#define WRITE_ENABLE_CMD                     0x06
#define WRITE_DISABLE_CMD                    0x04
 
/* 寄存器操作 */
#define READ_STATUS_REG1_CMD                  0x05
#define READ_STATUS_REG2_CMD                  0x35
#define READ_STATUS_REG3_CMD                  0x15
 
#define WRITE_STATUS_REG1_CMD                 0x01
#define WRITE_STATUS_REG2_CMD                 0x31
#define WRITE_STATUS_REG3_CMD                 0x11
 
 
/* 编程操作 */
#define PAGE_PROG_CMD                        0x02
#define QUAD_INPUT_PAGE_PROG_CMD             0x32
#define EXT_QUAD_IN_FAST_PROG_CMD            0x12
#define Enter_4Byte_Addr_Mode_CMD            0xB7
 
/* 擦除操作 */
#define SECTOR_ERASE_CMD                     0x20    //0xD8擦:64K    0x52擦:32K     0x20擦:4K
#define CHIP_ERASE_CMD                       0xC7
 
#define PROG_ERASE_RESUME_CMD                0x7A
#define PROG_ERASE_SUSPEND_CMD               0x75
 
 
/* 状态寄存器标志 */
#define W25QxJV_FSR_BUSY                    ((uint8_t)0x01)    /*!< busy */
#define W25QxJV_FSR_WREN                    ((uint8_t)0x02)    /*!< write enable */
#define W25QxJV_FSR_QE                      ((uint8_t)0x02)    /*!< quad enable */
#define W25Q256FV_FSR_4ByteAddrMode         ((uint8_t)0x01)    /*!< 4字节地址模式 */
 
/*命令定义-结尾*******************************/
uint8_t W25Qxx_OSPI_Init(uint16_t ClockPrescaler);
uint8_t W25Qxx_OSPI_Addr_Mode_Init(void);
uint8_t W25Qxx_OSPI_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size);
uint8_t W25Qxx_OSPI_WritePage(uint8_t *pData, uint32_t WriteAddr, uint32_t Size);
void W25Qxx_OSPI_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t Size);
uint8_t W25Qxx_OSPI_Erase_Block(uint32_t BlockAddress);
uint8_t W25Qxx_OSPI_Erase_Chip(void);
uint8_t W25Qxx_OSPI_GetStatus(void);
uint8_t W25Qxx_OSPI_ResetMemory(void);
uint8_t W25Qxx_OSPI_WriteEnable(void);
uint8_t W25Qxx_OSPI_AutoPollingMemReady(uint32_t Timeout);
uint32_t W25Qxx_OSPI_FLASH_ReadDeviceID(void);
uint32_t W25Qxx_OSPI_EnableMemoryMappedMode(void);
 
#endif /* W25QXX_OSPI_H_ */

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fpd_led

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值