/******************************************************************************
;  *   	@MCU				 : MC51F003A4
;  *   	@Create Date         : 2021.10.11
;  *   	@Author/Corporation  : Martin/SinoMCU
;  *   	@晟矽微技术支持QQ 	 : 2048615934
;  *    @晟矽微官网		     : http://www.sinomcu.com/
;  *   	@Copyright           : 2020 SINOMCU Corporation,All Rights Reserved.
;  *----------------------Abstract Description---------------------------------
;  *			          W25Q64函数                              		
******************************************************************************/

#include "w25qxx.h"
#include "SPI.h"

//4Kbytes为一个Sector
//16个扇区为1个Block
//W25Q128
//容量为16M字节,共有128个Block,4096个Sector

/************************************************
;  *    @Function Name       : W25QXX_Init
;  *    @Description         : 初始化flash
;  *    @IN_Parameter        :
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Init(void)
{
	W25QXX_CS = 1;   //SPI FLASH不选中
	SPI_User_Init(); //初始化SPI
}
/************************************************
;  *    @Function Name       : W25QXX_ReadSR
;  *    @Description         : 读取W25QXX的状态寄存器
;  *    @IN_Parameter        :	
;  *    @Return parameter    :	BIT7  6   5   4   3   2   1   0
								SPR   RV  TB BP2 BP1 BP0 WEL BUSY
								SPR:默认0,状态寄存器保护位,配合WP使用
								TB,BP2,BP1,BP0:FLASH区域写保护设置
								WEL:写使能锁定
								BUSY:忙标记位(1,忙;0,空闲)
								默认:0x00
;  ***********************************************/
uint8_t W25QXX_ReadSR(void)
{
	uint8_t byte = 0;
	W25QXX_CS = 0;							//使能器件
	SPI1_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令
	byte = SPI1_ReadWriteByte(0Xff);		//读取一个字节
	W25QXX_CS = 1;							//取消片选
	return byte;
}
/************************************************
;  *    @Function Name       : W25QXX_Write_SR
;  *    @Description         : 	写W25QXX状态寄存器					
;  *    @IN_Parameter        :  只有SPR,TB,BP2,BP1,BP0
								(bit 7,5,4,3,2)可以写!!!
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Write_SR(uint8_t sr)
{
	W25QXX_CS = 0;							 //使能器件
	SPI1_ReadWriteByte(W25X_WriteStatusReg); //发送写取状态寄存器命令
	SPI1_ReadWriteByte(sr);					 //写入一个字节
	W25QXX_CS = 1;							 //取消片选
}
/************************************************
;  *    @Function Name       : W25QXX_Write_Enable
;  *    @Description         : W25QXX写使能  将WEL置位
;  *    @IN_Parameter        :
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Write_Enable(void)
{
	W25QXX_CS = 0;						  //使能器件
	SPI1_ReadWriteByte(W25X_WriteEnable); //发送写使能
	W25QXX_CS = 1;						  //取消片选
}
/************************************************
;  *    @Function Name       : W25QXX_Write_Disable
;  *    @Description         : W25QXX写禁止  将WEL清零
;  *    @IN_Parameter        :
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Write_Disable(void)
{
	W25QXX_CS = 0;						   //使能器件
	SPI1_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令
	W25QXX_CS = 1;						   //取消片选
}
/************************************************
;  *    @Function Name       : W25QXX_ReadID
;  *    @Description         : 读取芯片ID
;  *    @IN_Parameter        :
;  *    @Return parameter    :	0XEF13,表示芯片型号为W25Q80
								0XEF14,表示芯片型号为W25Q16
								0XEF15,表示芯片型号为W25Q32
								0XEF16,表示芯片型号为W25Q64
								0XEF17,表示芯片型号为W25Q128
;  ***********************************************/
uint16_t W25QXX_ReadID(void)
{
	uint16_t temp = 0;
	W25QXX_CS = 0;
	SPI1_ReadWriteByte(0x90); //发送读取ID命令
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	temp |= SPI1_ReadWriteByte(0xFF) << 8;
	temp |= SPI1_ReadWriteByte(0xFF);
	W25QXX_CS = 1;
	return temp;
}
/************************************************
;  *    @Function Name       : W25QXX_Read
;  *    @Description         : 读取SPI FLASH
;  *    @IN_Parameter        :	pBuffer:数据存储区
								ReadAddr:开始读取的地址(24bit)
								NumByteToRead:要读取的字节数(最大65535)
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Read(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
	uint16_t i;
	W25QXX_CS = 0;									 //使能器件
	SPI1_ReadWriteByte(W25X_ReadData);				 //发送读取命令
	SPI1_ReadWriteByte((uint8_t)((ReadAddr) >> 16)); //发送24bit地址
	SPI1_ReadWriteByte((uint8_t)((ReadAddr) >> 8));
	SPI1_ReadWriteByte((uint8_t)ReadAddr);
	for (i = 0; i < NumByteToRead; i++)
	{
		pBuffer[i] = SPI1_ReadWriteByte(0XFF); //循环读数
	}
	W25QXX_CS = 1;
}
/************************************************
;  *    @Function Name       : W25QXX_Write_Page
;  *    @Description         : 写页
;  *    @IN_Parameter        :	pBuffer:数据存储区
								WriteAddr:开始写入的地址(24bit)
								NumByteToWrite:要写入的字节数(最大256),
								该数不应该超过该页的剩余字节数!!!
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
	uint16_t i;
	W25QXX_Write_Enable();							  //SET WEL
	W25QXX_CS = 0;									  //使能器件
	SPI1_ReadWriteByte(W25X_PageProgram);			  //发送写页命令
	SPI1_ReadWriteByte((uint8_t)((WriteAddr) >> 16)); //发送24bit地址
	SPI1_ReadWriteByte((uint8_t)((WriteAddr) >> 8));
	SPI1_ReadWriteByte((uint8_t)WriteAddr);
	for (i = 0; i < NumByteToWrite; i++)
		SPI1_ReadWriteByte(pBuffer[i]); //循环写数
	W25QXX_CS = 1;						//取消片选
	W25QXX_Wait_Busy();					//等待写入结束
}
/************************************************
;  *    @Function Name       : W25QXX_Write_NoCheck
;  *    @Description         : 无检验写SPI FLASH
								必须确保所写的地址范围内的数据全部为0XFF,
								否则在非0XFF处写入的数据将失败!
								具有自动换页功能；
								在指定地址开始写入指定长度的数据,但是要确保地址不越界!
;  *    @IN_Parameter        :	pBuffer:数据存储区
								WriteAddr:开始写入的地址(24bit)
								NumByteToWrite:要写入的字节数(最大65535)
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Write_NoCheck(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(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个字节了
		}
	}
}
/************************************************
;  *    @Function Name       : W25QXX_Erase_Chip
;  *    @Description         : 擦除整个芯片
;  *    @IN_Parameter        :
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Erase_Chip(void)
{
	W25QXX_Write_Enable(); //SET WEL
	W25QXX_Wait_Busy();
	W25QXX_CS = 0;						//使能器件
	SPI1_ReadWriteByte(W25X_ChipErase); //发送片擦除命令
	W25QXX_CS = 1;						//取消片选
	W25QXX_Wait_Busy();					//等待芯片擦除结束
}
/************************************************
;  *    @Function Name       : W25QXX_Erase_Sector
;  *    @Description         : 擦除一个扇区
;  *    @IN_Parameter        :
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Erase_Sector(uint32_t Dst_Addr)
{
	//监视falsh擦除情况,测试用
	//	printf("fe:%x\r\n", Dst_Addr);
	Dst_Addr *= 4096;
	W25QXX_Write_Enable(); //SET WEL
	W25QXX_Wait_Busy();
	W25QXX_CS = 0;									 //使能器件
	SPI1_ReadWriteByte(W25X_SectorErase);			 //发送扇区擦除指令
	SPI1_ReadWriteByte((uint8_t)((Dst_Addr) >> 16)); //发送24bit地址
	SPI1_ReadWriteByte((uint8_t)((Dst_Addr) >> 8));
	SPI1_ReadWriteByte((uint8_t)Dst_Addr);
	W25QXX_CS = 1;		//取消片选
	W25QXX_Wait_Busy(); //等待擦除完成
}
/************************************************
;  *    @Function Name       : W25QXX_Wait_Busy
;  *    @Description         : 等待空闲
;  *    @IN_Parameter        :
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_Wait_Busy(void)
{
	while ((W25QXX_ReadSR() & 0x01) == 0x01); // 等待BUSY位清空
}
/************************************************
;  *    @Function Name       : W25QXX_PowerDown
;  *    @Description         : 掉电模式
;  *    @IN_Parameter        :
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_PowerDown(void)
{
	W25QXX_CS = 0;						//使能器件
	SPI1_ReadWriteByte(W25X_PowerDown); //发送掉电命令
	W25QXX_CS = 1;						//取消片选
	NOP(20);							//等待TPD
}
/************************************************
;  *    @Function Name       : W25QXX_WAKEUP
;  *    @Description         : 唤醒
;  *    @IN_Parameter        :
;  *    @Return parameter    :
;  ***********************************************/
void W25QXX_WAKEUP(void)
{
	W25QXX_CS = 0;							   //使能器件
	SPI1_ReadWriteByte(W25X_ReleasePowerDown); //  send W25X_PowerDown command 0xAB
	W25QXX_CS = 1;							   //取消片选
	NOP(20);								   //等待TRES1
}

/**************************** end of file *********************************************/
