STM32H7B0VB OSPI 操作 25QXX FLASH

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

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_ */

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
### 回答1: STM32 HAL库提供了对W25Qxx系列SPI Flash的驱动程序。W25Qxx是一种常见的SPI Flash存储器,在嵌入式系统中被广泛使用。以下是一个简单的示例代码来说明如何使用STM32 HAL库驱动W25Qxx SPI Flash。 首先,我们需要在STM32 CubeMX中配置SPI外设和引脚。选择正确的SPI接口,并将其配置为主模式。然后,选择适当的引脚作为SPI的时钟线、MISO线和MOSI线。在配置完成后,生成代码并导出到STM32Cube HAL库中。 生成代码后,我们需要在应用程序中包含必要的头文件,例如"stm32fxxx_hal.h"和"w25qxx.h"。接下来,我们需要初始化SPI和W25Qxx。通过调用相应的初始化函数来完成这些操作。例如,使用HAL_SPI_Init()函数来初始化SPI外设,使用W25QXX_Init()函数来初始化W25Qxx。 初始化完成后,我们可以使用W25Qxx提供的函数来完成读写操作。例如,使用W25Qxx_ReadData()函数来从Flash中读取数据,使用W25Qxx_WriteData()函数写入数据。这些函数通常需要传递参数,如读写地址和数据缓冲区。 除了读写操作外,W25Qxx还提供了其他一些有用的函数,如擦除某个扇区、块或整个芯片的函数。在使用这些函数之前,我们需要确保已正确初始化W25Qxx。 最后,在应用程序结束时,我们应该调用HAL_SPI_DeInit()和W25Qxx_DeInit()函数来释放资源并关闭SPI和W25Qxx外设。 总结一下,通过使用STM32 HAL库和W25Qxx SPI Flash驱动程序,我们可以方便地在STM32微控制器上实现SPI Flash存储器的读写操作。希望以上内容对你有帮助! ### 回答2: stm32 HAL库是针对STMicroelectronics公司的STM32系列MCU(微控制器)而提供的一套硬件抽象层,旨在简化嵌入式代码的开发过程。W25Qxx是一种串行外部存储器,通过SPI接口与STM32 MCU通信。在使用W25Qxx SPI Flash时,可以使用stm32 HAL库来轻松地编写驱动程序。 首先,需要在代码中包含stm32 HAL库的相关头文件以及SPI驱动程序的头文件。然后,要定义所需的SPI外设和引脚,并初始化SPI外设。 在初始化完成后,可以通过函数HAL_SPI_Transmit来发送命令给W25Qxx SPI Flash进行读取或写入操作。例如,可以使用“读取数据”命令来从存储器中读取数据。使用函数HAL_SPI_Transmit发送命令字节,然后使用函数HAL_SPI_Receive接收返回的数据。类似地,可以使用“写入数据”命令来向W25Qxx SPI Flash写入数据。 另外,还可以使用“擦除扇区”命令来擦除存储器的一个扇区。使用函数HAL_SPI_Transmit发送擦除命令,接着发送擦除地址以确定要擦除的扇区的位置。 需要注意的是,为了与W25Qxx SPI Flash正确通信,还需要了解W25Qxx芯片的寄存器和命令格式。可以参考W25Qxx的数据手册来获取相关信息。 总之,使用STM32 HAL库来驱动W25Qxx SPI Flash是一个简单而有效的方法。通过初始化SPI外设并使用HAL库的函数来发送命令和接收数据,可以轻松地实现对W25Qxx SPI Flash的控制和读写操作。 ### 回答3: STM32 HAL库是ST公司为STM32系列微控制器提供的一套高级应用程序编程接口(API),它提供了一系列的函数和工具,方便开发者在STM32上进行硬件驱动和应用程序的开发。 W25Qxx是一种SPI Flash存储器,广泛应用于嵌入式系统中,具有高速度、大容量和低功耗等优点。为了在STM32上使用W25Qxx SPI Flash,需要编写相应的驱动程序。 首先,需要通过HAL库提供的函数,对SPI总线进行初始化设置。可以通过配置STM32的GPIO引脚和SPI相关寄存器,设置传输速度、数据位宽等参数,实现SPI总线的初始化。 接下来,需要编写读取和写入数据的函数。在读取数据时,首先通过发送读取指令的命令字,将数据从W25Qxx中读入缓冲区,然后通过SPI总线传输数据。在写入数据时,首先发送写使能命令,然后发送写入指令的命令字,将数据写入W25Qxx中。需要注意的是,写入操作需要先擦除对应的扇区或页,再进行写入。 在编写驱动程序时,还需要考虑到错误处理和异常情况。通过判断SPI总线是否正常工作、W25Qxx是否擦除、写入是否成功等,可以对错误进行处理,并给出相应的提示和解决方案。 最后,在整个驱动程序中,可以根据实际需求,添加其他功能。例如,可以编写擦除整片Flash的函数、快速读取数据的函数等,以满足具体的应用需求。 综上所述,编写STM32 HAL库的W25Qxx SPI Flash驱动程序,需要对SPI总线进行初始化设置,编写读取和写入数据的函数,考虑错误处理和异常情况,并根据实际需求添加其他功能。这样可以方便地在STM32上使用W25Qxx SPI Flash,实现数据存储和读取等功能。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

fpd_led

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

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

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

打赏作者

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

抵扣说明:

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

余额充值