STM32F767 QSPI W25Q256 单线读写 Single Lines模式 24位地址模式

/* Private variables ---------------------------------------------------------*/

QSPI_HandleTypeDef hqspi;

/* USER CODE BEGIN PV */


/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_QUADSPI_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

#define DATA_SIZE 10000
#define DATA_ADDR 320

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_QUADSPI_Init();
  /* USER CODE BEGIN 2 */
	
	HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET);
	
	delay_init(216);
	delay_ms(500);
	
	static uint16_t W25qxx_Id;
	W25qxx_Id = W25qxx_Read_Id(hqspi);
	
	W25qxx_Erase_Sector(hqspi, 0);
	
	static uint8_t pData_wr[DATA_SIZE] = {22,33,44};
	uint32_t i;
	for(i = 0; i < DATA_SIZE; i++)
	{
		pData_wr[i] = i;
	}
	W25QXX_Write(hqspi, pData_wr, DATA_ADDR, DATA_SIZE);
	
	static uint8_t pData_rd[DATA_SIZE];
	W25qxx_Read_Data(hqspi, DATA_ADDR, (uint8_t*)pData_rd, DATA_SIZE);
	
	
	for(i = 0; i < DATA_SIZE; i++)
	{
		if((pData_wr[i] & 0xff) != (pData_rd[i] & 0xff)) break;
	}
	if(i < DATA_SIZE)
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
	}
	else
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
	}
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
}
/**
  * @brief QUADSPI Initialization Function
  * @param None
  * @retval None
  */
static 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 */
  /* QUADSPI parameter configuration*/
  hqspi.Instance = QUADSPI;
  hqspi.Init.ClockPrescaler = 2;
  hqspi.Init.FifoThreshold = 4;
  hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
  hqspi.Init.FlashSize = 24;
  hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_5_CYCLE;
  hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
  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 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);

  /*Configure GPIO pins : PF6 PF7 */
  GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  /*Configure GPIO pin : PB1 */
  GPIO_InitStruct.Pin = GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}
#ifndef __BSP_W25QXX_H
#define __BSP_W25QXX_H

#include "main.h"

//W25X系列/Q系列芯片列表	   
//W25Q80  ID  0XEF13
//W25Q16  ID  0XEF14
//W25Q32  ID  0XEF15
//W25Q64  ID  0XEF16	
//W25Q128 ID  0XEF17	
//W25Q256 ID  0XEF18
#define W25Q80 	0XEF13 	
#define W25Q16 	0XEF14
#define W25Q32 	0XEF15
#define W25Q64 	0XEF16
#define W25Q128	0XEF17
#define W25Q256 0XEF18

extern uint16_t W25QXX_TYPE;					//定义W25QXX芯片型号	

// 
//指令表
#define W25X_WriteEnable		0x06 
#define W25X_WriteDisable		0x04 
#define W25X_ReadStatusReg1		0x05 
#define W25X_ReadStatusReg2		0x35 
#define W25X_ReadStatusReg3		0x15 
#define W25X_WriteStatusReg1    0x01 
#define W25X_WriteStatusReg2    0x31 
#define W25X_WriteStatusReg3    0x11 
#define W25X_ReadData			0x03 
#define W25X_FastReadData		0x0B 
#define W25X_FastReadDual		0x3B 
#define W25X_PageProgram		0x02 
#define W25X_BlockErase			0xD8 
#define W25X_SectorErase		0x20 
#define W25X_ChipErase			0xC7 
#define W25X_PowerDown			0xB9 
#define W25X_ReleasePowerDown	0xAB 
#define W25X_DeviceID			0xAB 
#define W25X_ManufactDeviceID	0x90 
#define W25X_JedecDeviceID		0x9F 
#define W25X_Enable4ByteAddr    0xB7
#define W25X_Exit4ByteAddr      0xE9
#define W25X_SetReadParam		0xC0 
#define W25X_EnterQPIMode       0x38
#define W25X_ExitQPIMode        0xFF

/** 
  * @brief  HAL Status structures definition  
  */  
typedef enum 
{
  Status_Busy       = 0x00U,
  Status_Free    = 0x01U
} Busy_StatusTypeDef;


HAL_StatusTypeDef W25qxx_Cmd(QSPI_HandleTypeDef hqspi, uint32_t Instruction);
uint16_t W25qxx_Read_Id(QSPI_HandleTypeDef hqspi);
HAL_StatusTypeDef W25qxx_Read_Data(QSPI_HandleTypeDef hqspi, uint32_t Addr, uint8_t *pData, uint32_t Data_Count);
HAL_StatusTypeDef W25qxx_Erase_Sector(QSPI_HandleTypeDef hqspi, uint32_t Sector);
Busy_StatusTypeDef W25qxx_Is_Busy(QSPI_HandleTypeDef hqspi);
void W25QXX_Write_Page(QSPI_HandleTypeDef hqspi, uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
void W25QXX_Write_NoCheck(QSPI_HandleTypeDef hqspi, uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)  ;
void W25QXX_Write(QSPI_HandleTypeDef hqspi, uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);


#endif	//__BSP_W25QXX_H


#include "bsp_w25qxx.h"


uint16_t W25QXX_TYPE;					//定义W25QXX芯片型号	

HAL_StatusTypeDef W25qxx_Cmd(QSPI_HandleTypeDef hqspi, uint32_t Instruction)
{
	QSPI_CommandTypeDef cmd;
	HAL_StatusTypeDef status;
	
	cmd.Instruction = Instruction;
	cmd.Address = 0;
	cmd.AlternateBytes = 0;
	cmd.AddressSize = 0;
	cmd.AlternateBytesSize = 0;
	cmd.DummyCycles = 0;
	cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	cmd.AddressMode = QSPI_ADDRESS_NONE;
	cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	cmd.DataMode = QSPI_DATA_NONE;
	cmd.NbData = 0;
	cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
	cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
	
	status = HAL_QSPI_Command(&hqspi, &cmd, 1000);
	return status;
}

uint16_t W25qxx_Read_Id(QSPI_HandleTypeDef hqspi) 
{
	uint16_t id;
	QSPI_CommandTypeDef cmd;
	HAL_StatusTypeDef status;
	uint8_t pData[2];
	
	W25qxx_Cmd(hqspi, W25X_WriteEnable);
	
	cmd.Instruction = W25X_ManufactDeviceID;
	cmd.Address = 0;
	cmd.AlternateBytes = 0;
	cmd.AddressSize = QSPI_ADDRESS_24_BITS;
	cmd.AlternateBytesSize = 0;
	cmd.DummyCycles = 0;
	cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	cmd.AddressMode = QSPI_ADDRESS_1_LINE;
	cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	cmd.DataMode = QSPI_DATA_1_LINE;
	cmd.NbData = 2;
	cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
	cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
	
	status = HAL_QSPI_Command(&hqspi, &cmd, 1000);
	
	status = HAL_QSPI_Receive(&hqspi, pData, 1000);
	
	id = (pData[0] << 8) | pData[1];
	
	while(W25qxx_Is_Busy(hqspi) == Status_Busy)
	{
		
	}
	
	return id;
}

void W25QXX_Write_Page(QSPI_HandleTypeDef hqspi, uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
	QSPI_CommandTypeDef cmd;
	
	W25qxx_Cmd(hqspi, W25X_WriteEnable);
	
	cmd.Instruction = W25X_PageProgram;
	cmd.Address = WriteAddr;
	cmd.AlternateBytes = 0;
	cmd.AddressSize = QSPI_ADDRESS_24_BITS;
	cmd.AlternateBytesSize = 0;
	cmd.DummyCycles = 0;
	cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	cmd.AddressMode = QSPI_ADDRESS_1_LINE;
	cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	cmd.DataMode = QSPI_DATA_1_LINE;
	cmd.NbData = NumByteToWrite;
	cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
	cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
	
	HAL_QSPI_Command(&hqspi, &cmd, 1000);
	HAL_QSPI_Transmit(&hqspi, pBuffer, 1000);
	
	while(W25qxx_Is_Busy(hqspi) == Status_Busy)
	{
		
	}
} 

void W25QXX_Write_NoCheck(QSPI_HandleTypeDef hqspi, uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 			 		 
	uint16_t pageremain;	   
	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
	while(1)
	{	   
		W25QXX_Write_Page(hqspi, 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个字节了
		}
	}   
}

	 
void W25QXX_Write(QSPI_HandleTypeDef hqspi, uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 
	uint32_t secpos;
	uint16_t secoff;
	uint16_t secremain;	   
 	uint16_t i;    
	uint8_t * W25QXX_BUF;	 
	static uint8_t W25QXX_BUFFER[4096];	
	
	W25QXX_BUF=W25QXX_BUFFER;	     
	secpos=WriteAddr/4096;//扇区地址  
	secoff=WriteAddr%4096;//在扇区内的偏移
	secremain=4096-secoff;//扇区剩余空间大小   

 	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
	while(1) 
	{	
		W25qxx_Read_Data(hqspi, secpos*4096, W25QXX_BUF, 4096);//读出整个扇区的内容
		while(W25qxx_Is_Busy(hqspi) == Status_Busy)
		{
			
		}
		
		for(i=0;i<secremain;i++)//校验数据
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除  	  
		}
		if(i<secremain)//需要擦除
		{
			W25qxx_Erase_Sector(hqspi, secpos);//擦除这个扇区
			while(W25qxx_Is_Busy(hqspi) == Status_Busy)
			{
				
			}
			for(i=0;i<secremain;i++)	   //复制
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];	  
			}
			
			W25QXX_Write_NoCheck(hqspi, W25QXX_BUF,secpos*4096,4096);//写入整个扇区  
			
		}else W25QXX_Write_NoCheck(hqspi, pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. 		

		while(W25qxx_Is_Busy(hqspi) == Status_Busy)
		{
			
		}
		
		if(NumByteToWrite==secremain)break;//写入结束了
		else//写入未结束
		{
			secpos++;//扇区地址增1
			secoff=0;//偏移位置为0 	 

		   	pBuffer+=secremain;  //指针偏移
			WriteAddr+=secremain;//写地址偏移	   
		   	NumByteToWrite-=secremain;				//字节数递减
			if(NumByteToWrite>4096)secremain=4096;	//下一个扇区还是写不完
			else secremain=NumByteToWrite;			//下一个扇区可以写完了
		}	 
	};	 
}

HAL_StatusTypeDef W25qxx_Read_Data(QSPI_HandleTypeDef hqspi, uint32_t Addr, uint8_t *pData, uint32_t Data_Count)
{
	QSPI_CommandTypeDef cmd;
	HAL_StatusTypeDef status;
	
	W25qxx_Cmd(hqspi, W25X_WriteEnable);
	
	cmd.Instruction = W25X_ReadData;
	cmd.Address = Addr;
	cmd.AlternateBytes = 0;
	cmd.AddressSize = QSPI_ADDRESS_24_BITS;
	cmd.AlternateBytesSize = 0;
	cmd.DummyCycles = 0;
	cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	cmd.AddressMode = QSPI_ADDRESS_1_LINE;
	cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	cmd.DataMode = QSPI_DATA_1_LINE;
	cmd.NbData = Data_Count;
	cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
	cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
	
	status = HAL_QSPI_Command(&hqspi, &cmd, 1000);
	status = HAL_QSPI_Receive(&hqspi, pData, 1000);
	
	while(W25qxx_Is_Busy(hqspi) == Status_Busy)
	{
		
	}
	
	return status;
}

HAL_StatusTypeDef W25qxx_Erase_Sector(QSPI_HandleTypeDef hqspi, uint32_t Sector)
{
	QSPI_CommandTypeDef cmd;
	HAL_StatusTypeDef status;
	
	W25qxx_Cmd(hqspi, W25X_WriteEnable);
	
	cmd.Instruction = W25X_SectorErase;
	cmd.Address = Sector * 4096;
	cmd.AlternateBytes = 0;
	cmd.AddressSize = QSPI_ADDRESS_24_BITS;
	cmd.AlternateBytesSize = 0;
	cmd.DummyCycles = 0;
	cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	cmd.AddressMode = QSPI_ADDRESS_1_LINE;
	cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	cmd.DataMode = QSPI_DATA_NONE;
	cmd.NbData = 0;
	cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
	cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
	
	status = HAL_QSPI_Command(&hqspi, &cmd, 1000);
	
	while(W25qxx_Is_Busy(hqspi) == Status_Busy)
	{
		
	}
	
	return status;
}

Busy_StatusTypeDef W25qxx_Is_Busy(QSPI_HandleTypeDef hqspi)
{
	QSPI_CommandTypeDef cmd;
	HAL_StatusTypeDef status;
	uint8_t Data;
	
	cmd.Instruction = W25X_ReadStatusReg1;
	cmd.Address = 0;
	cmd.AlternateBytes = 0;
	cmd.AddressSize = QSPI_ADDRESS_24_BITS;
	cmd.AlternateBytesSize = 0;
	cmd.DummyCycles = 0;
	cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	cmd.AddressMode = QSPI_ADDRESS_1_LINE;
	cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	cmd.DataMode = QSPI_DATA_1_LINE;
	cmd.NbData = 1;
	cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
	cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
	
	status = HAL_QSPI_Command(&hqspi, &cmd, 1000);
	status = HAL_QSPI_Receive(&hqspi, &Data, 1000);
	
	if(Data & 0x01) return Status_Busy;
	else return Status_Free;
} 



总结:
1、从地址DATA_ADDR开始写DATA_SIZE个字节数据,然后从地址DATA_ADDR开始读DATA_SIZE个字节数据,并进行比较,结果均相同
2、此程序指令、地址、数据等都采用单线SPI通信
3、
在这里插入图片描述
4、W25Q256最高104MHz时钟,所以分频设置为2,采用时钟216MHz/(2+1);
5、FLASH SIZE设为24,W25Q256为32MB大小,2的(24+1)次方
6、Clock Mode为Low,CLK空闲时为低电平
7、Chip Select High Time设为5,最低50ns,13.8ns*5 > 50ns
在这里插入图片描述

8、每条W25Q256指令发送前都要使能W25qxx_Cmd(hqspi, W25X_WriteEnable);发送后都要等待忙标志复位while(W25qxx_Is_Busy(hqspi) == Status_Busy)
9、将QuadSPI Mode改为Quad SPI lines,屏蔽//HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET);因为这两个引脚已复用,程序一样正确执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值