#include "gd32f10x.h"
#include "spi.h"
#include "w25q32.h"

/*-------------------------------------------------*/
/*函数名:初始化W25Q32                             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void W25Q32_Init(void)
{
	rcu_periph_clock_enable(RCU_GPIOA);                                      //打开GPIOA时钟
	gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_4);          //设置PA4,PP输出,控制CS引脚
	CS_DISENABLE;                                                            //关闭CS
	SPI0_Init();	                                                         //初始化SPI0
}
/*-------------------------------------------------*/
/*函数名:等待W25Q32空闲                           */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void W25Q32_WaitBusy(void)
{
	uint8_t res;                           //保存返回值
	
	do{                                    //循环等待
		CS_ENABLE;                         //打开CS
		SPI0_ReadWriteByte(0x05);          //发送命令0x05
		res = SPI0_ReadWriteByte(0xff);    //发送一个字节,从而才能读取一个字节,也就是W25Q32状态寄存器1的数据
		CS_DISENABLE;                      //关闭CS
	}while((res&0x01)==0x01);              //等到BIT0成0,退出while循环,说明W25Q32空闲了
}
/*-------------------------------------------------*/
/*函数名:W25Q32写使能                             */
/*参  数:无                                       */
/*返回值:无                                       */
/*-------------------------------------------------*/
void W25Q32_Enable(void)
{
	W25Q32_WaitBusy();              //等待W25Q32空闲
	CS_ENABLE;                      //打开CS
	SPI0_ReadWriteByte(0x06);       //发送命令0x06
	CS_DISENABLE;                   //关闭CS
}
/*-------------------------------------------------*/
/*函数名:W25Q32擦除一个64K大小的块                */
/*参  数:blockNB:块编号从0开始                   */
/*返回值:无                                       */
/*-------------------------------------------------*/
void W25Q32_Erase64K(uint8_t blockNB)
{
	uint8_t wdata[4];                    //保存命令和地址
	
	wdata[0] = 0xD8;                     //擦除指令0xD8
	wdata[1] = (blockNB*64*1024)>>16;    //需要擦除的块的地址
	wdata[2] = (blockNB*64*1024)>>8;     //需要擦除的块的地址
	wdata[3] = (blockNB*64*1024)>>0;     //需要擦除的块的地址
	
	W25Q32_WaitBusy();     //等待W25Q32空闲
	W25Q32_Enable();       //使能
	CS_ENABLE;             //打开CS
	SPI0_Write(wdata,4);   //把wdata发送给W25Q32
	CS_DISENABLE;          //关闭CS
	W25Q32_WaitBusy();     //等待W25Q32空闲吗,确保擦除完毕后再退出W25Q32_Erase64K子函数
}
/*--------------------------------------------------------*/
/*函数名:W25Q32写入一页数据(256字节)                   */
/*参  数:wbuff:写入数据指针  pageNB:页编号从0开始      */
/*返回值:无                                              */
/*--------------------------------------------------------*/
void W25Q32_PageWrite(uint8_t *wbuff, uint16_t pageNB)
{
	uint8_t wdata[4];                  //保存命令和地址
	
	wdata[0] = 0x02;                   //页写入数据指令0x02
	wdata[1] = (pageNB*256)>>16;       //需要写入数据的页地址
	wdata[2] = (pageNB*256)>>8;        //需要写入数据的页地址
	wdata[3] = (pageNB*256)>>0;        //需要写入数据的页地址
	
	W25Q32_WaitBusy();                 //等待W25Q32空闲
	W25Q32_Enable();                   //使能
	CS_ENABLE;                         //打开CS
	SPI0_Write(wdata,4);               //把wdata发送给W25Q32
	SPI0_Write(wbuff,256);             //接着发送256字节(一页)的数据
	CS_DISENABLE;                      //关闭CS
}
/*-----------------------------------------------------------------*/
/*函数名:W25Q32读取数据                                           */
/*参  数:rbuff:接收缓冲区  addr:读取地址  datalen:读取长度     */
/*返回值:无                                                       */
/*-----------------------------------------------------------------*/
void W25Q32_Read(uint8_t *rbuff, uint32_t addr, uint32_t datalen)
{
	uint8_t wdata[4];          //保存命令和地址
	
	wdata[0] = 0x03;           //读取数据指令0x03
	wdata[1] = (addr)>>16;     //读取数据的地址
	wdata[2] = (addr)>>8;      //读取数据的地址
	wdata[3] = (addr)>>0;      //读取数据的地址
	
	W25Q32_WaitBusy();         //等待W25Q32空闲
	CS_ENABLE;                 //打开CS
	SPI0_Write(wdata,4);       //把wdata发送给W25Q32
	SPI0_Read(rbuff,datalen);  //读取datalen个字节数据
	CS_DISENABLE;              //关闭CS
}