使用W25Q16要知道的

1、FLASH擦除后值为1;FLASH只能写0

2、W25QX在进行各种操作时,不能进行其他操作,此时BUSY置1;当BUSY时,只能接受两种命令:1、读状态位 2、停止擦除

3、对FLASH进行擦除或写入前,需要进行**写使能**。写使能后,进行除了读取状态位以外的操作,都会自动关闭写使能;也就是每次写入或擦除之前都要重新写使能,不需要手动关闭

4、W25QX每页256字节。扇区4K,块64K。擦除最小也要擦除一个扇区。写入按页写入【需要计算,一页写完了要去下一页写,否则覆盖之前的】,不过写入可以在页中间或者头部写,不限制写入位置。

5、HOLD引脚会让SPI引脚进入高阻态,用来让多个SPI设备使用。但不清楚为什么不直接用一个CS

#define FLASH_CSN_LOW		SPI2_CS1_GPIO_Port->BSRR|=SPI2_CS1_Pin<<16
#define FLASH_CSN_HIGH	SPI2_CS1_GPIO_Port->BSRR|=SPI2_CS1_Pin
#define FLASH_HOLD_LOW	HOLD2_GPIO_Port->BSRR|=HOLD2_Pin<<16
#define FLASH_HOLD_HIGH	HOLD2_GPIO_Port->BSRR|=HOLD2_Pin

#define   Write_Enable   0x06  //写使能
#define   Write_Disable  0x04  //写失能
#define   Read_Status_1  0x05  //读状态寄存器1
#define   Sector_Erase   0x20  //扇区擦除指令
#define   Block_Erase    0xD8  //块(64k)擦除指令
#define   Page_Problem   0x02  //写页指令
#define   Read_Data      0x03  //读指令
/**
* @brief  SPI2发送或接受1byte数据
  *
  * @note   SPI2发送或接受1byte数据
  *
  * @param  TxData: 发送数据
	*					    
  * @retval Rxdata:读到的数据
  */
uint8_t W25X_ReadWrite_Byte(uint8_t TxData)
{
	uint8_t Rxdata;
  HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000);       
  return Rxdata;  
}

/**
* @brief  使能W25Q16的写功能
  *
  * @note   使能W25Q16的写功能
  *
  * @param  null
	*					    
  * @retval null
  */
void W25X_WriteEnable()
{
  FLASH_CSN_LOW;//CS拉低使能芯片
  W25X_ReadWrite_Byte(Write_Enable);//写入指令
  FLASH_CSN_HIGH;
}

/**
* @brief  失能W25Q16的写功能
  *
  * @note   失能W25Q16的写功能
  *
  * @param  null
	*					    
  * @retval null
  */
void W25X_WriteDisable()
{
  FLASH_CSN_LOW;//CS拉低使能芯片
  W25X_ReadWrite_Byte(Write_Disable);//写入指令
  FLASH_CSN_HIGH;
}


uint8_t W25X_ReadStatusRegister(void)
{
//		W25X_WaitBusy();
    FLASH_CSN_LOW;
    W25X_ReadWrite_Byte(0x05); // 读取状态寄存器命令
    uint8_t status = W25X_ReadWrite_Byte(0xFF);
    FLASH_CSN_HIGH;
		printk("状态寄存器值:0x%02x\r\n",status);
    return status;
}


/**
* @brief  等待W25Q16可以工作
  *
  * @note   W25Q16的状态位S0为BUSY,当忙时只能收停止擦除和读取状态位的命令
	*					等待busy结束。
	*					未实现超时报错。
  *
  * @param  null
	*					    
  * @retval null
  */
void W25X_WaitBusy()
{
	uint8_t tmp;
	while(1)
	{
		FLASH_CSN_LOW;
		W25X_ReadWrite_Byte(Read_Status_1);
		tmp = W25X_ReadWrite_Byte(0xff);
		FLASH_CSN_HIGH;
		if((tmp&0x01) == 0)return;
	}
}

/**
* @brief  W25X块擦除(64KB)
  *
  * @note   擦除给定地址的块
  *
	* @param  addr:擦除地址
	*					    
  * @retval null
  */
void W25X_BlockErase(uint32_t addr)
{
	W25X_WaitBusy();
	FLASH_CSN_LOW;
	W25X_ReadWrite_Byte(Block_Erase);
	W25X_ReadWrite_Byte((addr>>16)&0xff);
	W25X_ReadWrite_Byte((addr>>8)&0xff);
	W25X_ReadWrite_Byte((addr)&0xff);
	FLASH_CSN_HIGH;
}


/**
* @brief  W25X扇区擦除(4KB)
  *
  * @note   擦除给定地址的扇区
  *
	* @param  addr:擦除地址
	*					    
  * @retval null
  */
void W25X_SectorErase(uint32_t addr)
{
	W25X_WaitBusy();
	FLASH_CSN_LOW;
	W25X_ReadWrite_Byte(Sector_Erase);
	W25X_ReadWrite_Byte((addr>>16)&0xff);
	W25X_ReadWrite_Byte((addr>>8)&0xff);
	W25X_ReadWrite_Byte((addr)&0xff);
	FLASH_CSN_HIGH;
}

/**
* @brief  W25X页写入
  *
  * @note   W25X页写入
  *
	* @param  addr	:写入页地址
	*		
	* @param  pbuf	:写入数组
	*	
	* @param  len		:写入长度
	*	
  * @retval null
  */
void W25X_WritePage(uint32_t addr,uint8_t* pbuf,uint16_t len)
{
	W25X_WaitBusy();
	FLASH_CSN_LOW;
	W25X_ReadWrite_Byte(Page_Problem);
	W25X_ReadWrite_Byte((addr>>16)&0xff);
	W25X_ReadWrite_Byte((addr>>8)&0xff);
	W25X_ReadWrite_Byte((addr)&0xff);
	for(uint16_t i = 0; i<len; i++)
	{
		W25X_ReadWrite_Byte(pbuf[i]);
	}
	FLASH_CSN_HIGH;
	
}

/**
* @brief  W25X页读取
  *
  * @note   W25X页读取
  *
	* @param  addr	:读取地址
	*		
	* @param  pbuf	:读取数组
	*	
	* @param  len		:读取长度
	*	
  * @retval null
  */
void W25X_ReadData(uint32_t addr,uint8_t* pbuf,uint16_t len)
{
	W25X_WaitBusy();
	FLASH_CSN_LOW;
	W25X_ReadWrite_Byte(Read_Data);
	W25X_ReadWrite_Byte((addr>>16)&0xff);
	W25X_ReadWrite_Byte((addr>>8)&0xff);
	W25X_ReadWrite_Byte((addr)&0xff);
	for(uint16_t i = 0; i<len; i++)
	{
		pbuf[i] = W25X_ReadWrite_Byte(0xff);
	}
	FLASH_CSN_HIGH;
	
}


/**
* @brief  W25X测试
  *
  * @note   W25X读取制造商ID并打印
	*	
  * @retval null
  */
void W25X_Test()
{
	uint8_t test_buf[3];
	W25X_WaitBusy();
	FLASH_CSN_LOW;
	W25X_ReadWrite_Byte(0x9f);
	test_buf[0] = W25X_ReadWrite_Byte(0xff);
	test_buf[1] = W25X_ReadWrite_Byte(0xff);
	test_buf[2] = W25X_ReadWrite_Byte(0xff);
	printk("读取W25X地址0x%02x%02x%02x\r\n",test_buf[0],test_buf[1],test_buf[2]);
}