#include "Winbond.h"

/*
*
*
* 板子上只有SPI5(SSI2)
*/

SSI_InitTypeDef SPI5;
extern unsigned char Flash_type;


u8  W25Q256 = 0; 	 //256 NorFlash的标志 ，用于识别到256的时候开启4Byte 地址

//void (*CS_FLash_RESET)(void);
//void (*CS_FLash_SET)(void);

//void CS0_NorFLash_RESET(void)
//{
//	(*(volatile unsigned char *)(0x4002e000+0x05)) &= ~(1<<0);	
//}

//void CS0_NorFLash_SET(void)
//{
//	(*(volatile unsigned char *)(0x4002e000+0x05)) |= (1<<0);	
//}

//void CS1_NandFLash_RESET(void)
//{
//	EPORT2->EPDR &=~(1<<0);	
//}

//void CS1_NandFLash_SET(void)
//{
//	EPORT2->EPDR |= (1<<0);	
//}

void CS_FLash_RESET(void)
{
	if(Flash_type == 0)	(*(volatile unsigned char *)(0x4002e000+0x05)) &= ~(1<<0);
	else				EPORT2->EPDR &=~(1<<0);
}

void CS_FLash_SET(void)
{
	if(Flash_type == 0)	(*(volatile unsigned char *)(0x4002e000+0x05)) |= (1<<0);
	else				EPORT2->EPDR |= (1<<0);
}

void Check_SSI2_Busy(void)
{
	int timeout = 0xFFFF;
	while(timeout)
	{
		if((SSI2->SR & 0x01) == 0x00)
			break;
		timeout--;
	}
}

void SPI5_Set_DataNum(u16 num)
{
	DRV_SSI_Cmd(SSI2,DISABLE);//关闭SSI2
	SSI2->CTRLR1 = num-1;
	DRV_SSI_Cmd(SSI2,ENABLE);//使能SSI2
}

void SSI2_DMA_RX(unsigned char * p,unsigned char cmd,unsigned int addr,unsigned short num,unsigned Byte_depth,unsigned char mode,unsigned char addrtype)
{
	DMAC_HandleTypeDef hdma;
	
	hdma.instance = DMAC2;
	hdma.init.channel_num = 0;
	/*复位DMAC*/
	HAL_DMAC_Deinit(&hdma);
	hdma.init.dst_msize = HAL_DMAC_MSIZE_1;
	hdma.init.src_msize = HAL_DMAC_MSIZE_1;
	hdma.init.dst_inc = HAL_DMAC_SINC_INC ;
	hdma.init.src_inc = HAL_DMAC_DINC_NO_CHANGE;
	
	if(Byte_depth  == 8)
	{
		hdma.init.dst_tr_width = HAL_DMAC_TR_WIDTH_8BITS;
		hdma.init.src_tr_width = HAL_DMAC_TR_WIDTH_8BITS;
	}
	else if(Byte_depth ==  16)
	{
		hdma.init.dst_tr_width = HAL_DMAC_TR_WIDTH_16BITS;
		hdma.init.src_tr_width = HAL_DMAC_TR_WIDTH_16BITS;
	}		
	else if(Byte_depth ==  32)
	{
		hdma.init.dst_tr_width = HAL_DMAC_TR_WIDTH_32BITS;
		hdma.init.src_tr_width = HAL_DMAC_TR_WIDTH_32BITS;
	}
	
	hdma.init.transfer_type = HAL_DMAC_TRANSFERTYPE_P2M_CONTROLLER_DMA;
	hdma.init.peripheral_type = HAL_DMAC2_PERIPHERAL_SSI2_RX;
	hdma.init.transfer_lli = HAL_DMAC_LLP_DIS;
	hdma.init.src_addr = (uint32_t)(&SSI2->DR);
	hdma.init.dst_addr = (uint32_t)p;
	hdma.init.transfer_size = num;

	/*初始化DMAC*/
	HAL_DMAC_Init(&hdma);

	/*开启非中断模式DMAC传输*/
	HAL_DMAC_StartPolling(&hdma);
	
	if(mode == STD_mode)
	{
		SSI2->DR=cmd;
		if(addrtype ==32)
		SSI2->DR=(addr>>24)&0xff;
		SSI2->DR=(addr>>16)&0xff;
		SSI2->DR=(addr>>8)&0xff;
		SSI2->DR=(addr>>0)&0xff;
		SSI2->DMACR=DMACR_RDMAE;
	}
	else if(mode == DUAL_mode)
	{
		SSI2->DR=cmd;
		SSI2->DR=addr;	
		SSI2->DMACR=DMACR_RDMAE;
	}
	else if(mode == QUAD_mode)
	{
		SSI2->DR=cmd;
		SSI2->DR=addr;		
		SSI2->DMACR=DMACR_RDMAE;
	}
	/*轮询传输完成*/
	HAL_DMAC_PollForTransfer(&hdma, 0, HAL_MAX_DELAY); 
	_dmac_dis(hdma.instance);
	SSI2->DMACR= 0;
}

void SSI2_DMA_RX_Continue(unsigned char * p,unsigned char cmd,unsigned int addr,unsigned short num,unsigned Byte_depth,unsigned char mode,unsigned char addrtype)
{
	DMAC_HandleTypeDef hdma;
	
	hdma.instance = DMAC2;
	hdma.init.channel_num = 0;
	/*复位DMAC*/
	HAL_DMAC_Deinit(&hdma);
	hdma.init.dst_msize = HAL_DMAC_MSIZE_1;
	hdma.init.src_msize = HAL_DMAC_MSIZE_1;
	hdma.init.dst_inc = HAL_DMAC_SINC_INC ;
	hdma.init.src_inc = HAL_DMAC_DINC_NO_CHANGE;
	
	if(Byte_depth  == 8)
	{
		hdma.init.dst_tr_width = HAL_DMAC_TR_WIDTH_8BITS;
		hdma.init.src_tr_width = HAL_DMAC_TR_WIDTH_8BITS;
	}
	else if(Byte_depth ==  16)
	{
		hdma.init.dst_tr_width = HAL_DMAC_TR_WIDTH_16BITS;
		hdma.init.src_tr_width = HAL_DMAC_TR_WIDTH_16BITS;
	}		
	else if(Byte_depth ==  32)
	{
		hdma.init.dst_tr_width = HAL_DMAC_TR_WIDTH_32BITS;
		hdma.init.src_tr_width = HAL_DMAC_TR_WIDTH_32BITS;
	}
	
	hdma.init.transfer_type = HAL_DMAC_TRANSFERTYPE_P2M_CONTROLLER_DMA;
	hdma.init.peripheral_type = HAL_DMAC2_PERIPHERAL_SSI2_RX;
	hdma.init.transfer_lli = HAL_DMAC_LLP_DIS;
	hdma.init.src_addr = (uint32_t)(&SSI2->DR);
	hdma.init.dst_addr = (uint32_t)p;
	hdma.init.transfer_size = num;

	/*初始化DMAC*/
	HAL_DMAC_Init(&hdma);

	/*开启非中断模式DMAC传输*/
	HAL_DMAC_StartPolling(&hdma);
	
	if(mode == STD_mode)
	{
		SSI2->DR=cmd;
		if(addrtype ==32)
		SSI2->DR=(addr>>24)&0xff;
		SSI2->DR=(addr>>16)&0xff;
		SSI2->DR=(addr>>8)&0xff;
		SSI2->DR=(addr>>0)&0xff;
		SSI2->DMACR=DMACR_RDMAE;
	}
	else if(mode == DUAL_mode)
	{
		SSI2->DR=cmd;
		SSI2->DR=addr;	
		SSI2->DMACR=DMACR_RDMAE;
	}
	else if(mode == QUAD_mode)
	{
		SSI2->DMACR=DMACR_RDMAE;
		SSI2->DR=0x00;		
//		SSI2->DR=cmd;
//		SSI2->DR=addr;			
		
	}
	/*轮询传输完成*/
	HAL_DMAC_PollForTransfer(&hdma, 0, HAL_MAX_DELAY); 
	_dmac_dis(hdma.instance);
	SSI2->DMACR= 0;
}

void SSI2_DMA_TX(unsigned char * p,unsigned char cmd,unsigned int addr,unsigned short num,unsigned Byte_depth,unsigned char mode,unsigned char addrtype)
{
	DMAC_HandleTypeDef hdma;
	
	hdma.instance = DMAC2;
	hdma.init.channel_num = 0;
	/*复位DMAC*/
	HAL_DMAC_Deinit(&hdma);
	hdma.init.dst_msize = HAL_DMAC_MSIZE_1;
	hdma.init.src_msize = HAL_DMAC_MSIZE_1;
	hdma.init.dst_inc = HAL_DMAC_SINC_NO_CHANGE ;
	hdma.init.src_inc = HAL_DMAC_DINC_INC;
	
	if(Byte_depth  == 8)
	{
		hdma.init.dst_tr_width = HAL_DMAC_TR_WIDTH_8BITS;
		hdma.init.src_tr_width = HAL_DMAC_TR_WIDTH_8BITS;
	}
	else if(Byte_depth ==  32)
	{
		hdma.init.dst_tr_width = HAL_DMAC_TR_WIDTH_32BITS;
		hdma.init.src_tr_width = HAL_DMAC_TR_WIDTH_32BITS;
	}
	hdma.init.transfer_type = HAL_DMAC_TRANSFERTYPE_M2P_CONTROLLER_DMA;
	hdma.init.peripheral_type = HAL_DMAC2_PERIPHERAL_SSI2_TX;
	hdma.init.transfer_lli = HAL_DMAC_LLP_DIS;
	hdma.init.src_addr = (uint32_t)p;
	hdma.init.dst_addr = (uint32_t)(&SSI2->DR);
	hdma.init.transfer_size = num;

	/*初始化DMAC*/
	HAL_DMAC_Init(&hdma);

	/*开启非中断模式DMAC传输*/
	HAL_DMAC_StartPolling(&hdma);
	
	if(mode == STD_mode)
	{
		SSI2->DR=cmd;
		if(addrtype ==32)
		SSI2->DR=(addr>>24)&0xff;
		SSI2->DR=(addr>>16)&0xff;
		SSI2->DR=(addr>>8)&0xff;
		SSI2->DR=(addr>>0)&0xff;

		SSI2->DMACR=DMACR_TDMAE;
	}
	else if(mode == DUAL_mode)
	{
		SSI2->DR=cmd;
		SSI2->DR=addr;
		
		SSI2->DMACR=DMACR_TDMAE;
	}
	else if(mode == QUAD_mode)
	{
		SSI2->DR=cmd;
		SSI2->DR=addr;
		
		SSI2->DMACR=DMACR_TDMAE;
	}	
	
	/*轮询传输完成*/
	HAL_DMAC_PollForTransfer(&hdma, 0, HAL_MAX_DELAY); 
	_dmac_dis(hdma.instance);
	SSI2->DMACR= 0;
}

//======================================================== NOR FLASH ===================================================================================//
/****************************************************   STD   **********************************************************/
void SPI5_STD_Init(void) //单线初始化
{
	
	SPI5.Format = STD_mode;
	SPI5.DFS   = DFS_08_BIT;      		//数据帧位数格式
	SPI5.FRF   = FRF_SPI;				//
	SPI5.SCPH  = SCPH_MIDDLE_BIT; 		//
	SPI5.SCPOL = INACTIVE_HIGH;   		//
	SPI5.TMOD  = TX_AND_RX;				//SPI 工作模式  发送和接受
	SPI5.SRL   = NORMAL_MODE;			//正常模式
	SPI5.SSTE  = TOGGLE_DISABLE;
	SPI5.CFS   = CFS_01_BIT;      		//控制帧位数格式
	SPI5.NDF   = 0;
	
	if(Flash_type == 0)	SPI5.SSI_STD_BaudRatePrescaler = SSI2_STD_BaudRatePrescaler; //最低2分频，200M SysCLK下，100 Max。
	if(Flash_type == 1)	SPI5.SSI_STD_BaudRatePrescaler = SSI2_Quad_BaudRatePrescaler_for_NandFlash; //最低2分频，200M SysCLK下，100 Max。	
	
	SPI5.Transfer_start_FIFO_level = 0;
	SPI5.Transmit_FIFO_Threshold = 0;
	SPI5.Receive_FIFO_Threshold = 0;

	SPI5.Rx_Sample_Delay =  SAMPLE_DELAY_2_0;

	SPI5.Trans_Type = TT0;      //TTO:指令和地址使用单线; TT1:指令使用单线，地址按配置输出;TT2:指令和地址都使用配置输出
	SPI5.Address_Length = ADDR_L24;
	SPI5.Instruction_length = INST_L8;
	SPI5.WAIT_CYCLES = 0x0;
	SPI5.CLK_STRETCH_EN = CLK_STRETCH_DISABLE;
	
	DRV_SSI_Init(SSI2,&SPI5,0xFFFFFF);
	
}

u16 SSI2_ReadWriteByte(u16 TxData)
{		
	while((SSI2->SR&0x04) == 0)		//等待TX FIFO空	
	{
	}			  
	SSI2->DR=TxData;	 	  		//发送一个byte 
	while((SSI2->SR&0x08) == 0) 	//等RX FIFO非空，待接收完一个byte  
	{
	}	
	return SSI2->DR;          		//返回收到的数据					    
}

u8 W25QXX_ReadSR_1_STD(void)   //读取W25QXX的状态寄存器
{  
	u8 byte=0;   
	CS_FLash_RESET();                            	//使能器件   
	SSI2_ReadWriteByte(0x05); 	                //发送读取状态寄存器命令    
	byte=SSI2_ReadWriteByte(0Xff);          	//读取一个字节  
	CS_FLash_SET();                            	//取消片选     
	return byte;   
} 

	
//将WEL置位   
void W25QXX_Write_Enable_STD(void)   //W25QXX写使能
{
	CS_FLash_RESET();                          			//使能器件   
    SSI2_ReadWriteByte(0x06); 	//发送写使能  
	CS_FLash_SET();                           		//取消片选     	      
} 
	
//将WEL清零  
void W25QXX_Write_Disable_STD(void)   //W25QXX写禁止
{  
	CS_FLash_RESET();                            		//使能器件   
    SSI2_ReadWriteByte(0x04); 	//发送写禁止指令    
	CS_FLash_SET();                            		//取消片选     	      
} 		


void W25QXX_Wait_Busy_STD(void)   		//等待空闲
{   
	volatile signed int time;
	while((W25QXX_ReadSR_1_STD()&0x01)==0x01) // 等待BUSY位清空
	{
		int time = 5000;
		while(time)
		{
			__nop();
			time--;
		};
	}  		
}  

void W25QXX_Enter_4Byte_AddressMode_STD(void)
{
	CS_FLash_RESET();  
	SSI2_ReadWriteByte(0xB7);
	CS_FLash_SET(); 
}

void W25QXX_Enter_QPI_STD(void)
{
	CS_FLash_RESET();  
	SSI2_ReadWriteByte(0x38);
	CS_FLash_SET(); 
}
void W25QXX_Open_QUAD(void)
{
	unsigned char temp = 0;
	
	CS_FLash_RESET();  
	SSI2_ReadWriteByte(0x35);
	temp = SSI2_ReadWriteByte(0xFF);
	CS_FLash_SET(); 
	
	W25QXX_Write_Enable_STD();
	
	CS_FLash_RESET(); 
	SSI2_ReadWriteByte(0x31);
	temp = SSI2_ReadWriteByte(temp|0x02);
	CS_FLash_SET(); 
	
	W25QXX_Wait_Busy_STD();
}

//读取芯片ID
u16 W25QXX_ReadID_STD(void)
{
	u16 Temp = 0;
	
	CS_FLash_RESET();				    
	SSI2_ReadWriteByte(0x90);
	SSI2_ReadWriteByte(0x00);
	SSI2_ReadWriteByte(0x00);
	SSI2_ReadWriteByte(0x00);
	Temp = SSI2_ReadWriteByte(0xFF)<<8;
	Temp |=SSI2_ReadWriteByte(0xFF);
	CS_FLash_SET();				    
	return Temp;
}   
UINT32 W25QXX_ReadID_STD_9F(void)
{
	UINT32 Temp = 0;
	CS_FLash_RESET();
	SSI2_ReadWriteByte(0x9F);//发送读取ID命令
//	SPIWR(0x00);
//	SPIWR(0x00);
//	SPIWR(0x00);
	Temp|=SSI2_ReadWriteByte(0xFF)<<16;
	Temp|=SSI2_ReadWriteByte(0xFF)<<8;
	Temp|=SSI2_ReadWriteByte(0xFF);
	CS_FLash_SET();
	return Temp;
}
//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read_STD(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{ 
 	u16 i;   										    
	CS_FLash_RESET();                            		//使能器件   
    SSI2_ReadWriteByte(0x03);         				//发送读取命令   
    
	if (W25Q256)
	SSI2_ReadWriteByte((uint8_t)((ReadAddr)>>24));  //256Flash发送32bit地址
	
	SSI2_ReadWriteByte((u8)((ReadAddr)>>16));  		//发送24bit地址    
    SSI2_ReadWriteByte((u8)((ReadAddr)>>8));   
    SSI2_ReadWriteByte((u8)ReadAddr);   
    for(i=0;i<NumByteToRead;i++)
	{ 
        pBuffer[i]=SSI2_ReadWriteByte(0XFF);   		//循环读数  
    }
	CS_FLash_SET();  				    	      
} 

//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!	 
void W25QXX_Write_Page_STD(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
 	u16 i;  
    W25QXX_Write_Enable_STD();                  					//SET WEL 
    CS_FLash_RESET();                            						//使能器件  
	 
    SSI2_ReadWriteByte(0x02);      									//发送写页命令  
	if (W25Q256)
	SSI2_ReadWriteByte((uint8_t)((WriteAddr)>>24));  				//256Flash发送32bit地址
	
	SSI2_ReadWriteByte((uint8_t)((WriteAddr)>>16)); 				//发送24bit地址    
    SSI2_ReadWriteByte((uint8_t)((WriteAddr)>> 8));   
    SSI2_ReadWriteByte((uint8_t)((WriteAddr)>> 0));   
    for(i=0;i<NumByteToWrite;i++)SSI2_ReadWriteByte(pBuffer[i]);	//循环写数  
	
	CS_FLash_SET(); 													//取消片选						 
	W25QXX_Wait_Busy_STD();					   						//等待写入结束
} 
//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck_STD(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 			 		 
	u16 pageremain;	   
	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
	while(1)
	{	   
		W25QXX_Write_Page_STD(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_Erase_Chip_STD(void)   
{                                   
  W25QXX_Write_Enable_STD();                 	  //SET WEL 
  W25QXX_Wait_Busy_STD();   
  CS_FLash_RESET();                            	  //使能器件   
  SSI2_ReadWriteByte(0xC7);   //发送片擦除命令  
  CS_FLash_RESET();                             //取消片选     
  W25QXX_Wait_Busy_STD();   				   	  //等待芯片擦除结束
} 


void W25QXX_BlockErase64KB_STD(u32 addr)
{
	addr*=(64*1024);
	W25QXX_Write_Enable_STD();                 	//SET WEL
	W25QXX_Wait_Busy_STD();
	CS_FLash_RESET();                            	  	//使能器件
	SSI2_ReadWriteByte(0xD8);   			//发送片擦除命令

    if (W25Q256)
    SSI2_ReadWriteByte((uint8_t)((addr)>>24));  	//256Flash发送32bit地址	
	
	SSI2_ReadWriteByte((uint8_t)((addr)>>16)); 			//发送24bit地址
	SSI2_ReadWriteByte((uint8_t)((addr)>>8));
	SSI2_ReadWriteByte((uint8_t)addr);
	CS_FLash_SET();                           	//取消片选
	W25QXX_Wait_Busy_STD();   				   	//等待芯片擦除结束
}

void W25QXX_SectorErase4KB_STD(u32 addr)
{
	addr*=4096;
	W25QXX_Write_Enable_STD();                 	//SET WEL
	W25QXX_Wait_Busy_STD();
	CS_FLash_RESET();                           	  	//使能器件
	SSI2_ReadWriteByte(0x20);   			//发送片擦除命令
	
	if (W25Q256)
	SSI2_ReadWriteByte((uint8_t)((addr)>>24));  	//256Flash发送32bit地址	

	
	SSI2_ReadWriteByte((uint8_t)((addr)>>16)); 			//发送24bit地址
	SSI2_ReadWriteByte((uint8_t)((addr)>>8));
	SSI2_ReadWriteByte((uint8_t)addr);
	CS_FLash_SET();                            	//取消片选
	W25QXX_Wait_Busy_STD();   				   	//等待芯片擦除结束
}

/****************************************************   STD   **********************************************************/
//===========================================================================================================================================//

/****************************************************   Dual  **********************************************************/

void SPI5_Dual_Read_Init(void)
{

	SPI5.Format = DUAL_mode;
	SPI5.DFS   = DFS_08_BIT;      		//数据帧位数格式
	SPI5.FRF   = FRF_SPI;				//
	SPI5.SCPH  = SCPH_MIDDLE_BIT; 		//
	SPI5.SCPOL = INACTIVE_HIGH;   		//
	SPI5.TMOD  = RX_ONLY;				//SPI 工作模式  发送和接受
	SPI5.SRL   = NORMAL_MODE;			//正常模式
	SPI5.SSTE  = TOGGLE_DISABLE;
	SPI5.CFS   = CFS_01_BIT;      		//控制帧位数格式
	SPI5.NDF   = 0;
	SPI5.SSI_DUAL_BaudRatePrescaler = SSI2_Dual_BaudRatePrescaler;//最低2分频，200M SysCLK下，100 Max。
	
	SPI5.Transfer_start_FIFO_level = 1;
	SPI5.Transmit_FIFO_Threshold = 0;
	SPI5.Receive_FIFO_Threshold = 7;

	SPI5.Rx_Sample_Delay = SAMPLE_DELAY_2_0;

	SPI5.Trans_Type = TT0;      //TTO:指令和地址使用单线; TT1:指令使用单线，地址按配置输出;TT2:指令和地址都使用配置输出
	SPI5.Instruction_length = INST_L8;
	SPI5.WAIT_CYCLES = 8;
	SPI5.CLK_STRETCH_EN = CLK_STRETCH_ENABLE;
	
	
	DRV_SSI_Init(SSI2,&SPI5,0xFFFFFF);	
}

void SPI5_Dual_Read_Init_test(void)
{
	SPI5.Format = DUAL_mode;
	SPI5.DFS   = DFS_08_BIT;      		//数据帧位数格式
	SPI5.FRF   = FRF_SPI;				//
	SPI5.SCPH  = SCPH_MIDDLE_BIT; 		//
	SPI5.SCPOL = INACTIVE_HIGH;   		//
	SPI5.TMOD  = RX_ONLY;				//SPI 工作模式  发送和接受
	SPI5.SRL   = NORMAL_MODE;			//正常模式
	SPI5.SSTE  = TOGGLE_DISABLE;
	SPI5.CFS   = CFS_01_BIT;      		//控制帧位数格式
	SPI5.NDF   = 0;
	SPI5.SSI_DUAL_BaudRatePrescaler = SSI2_Dual_BaudRatePrescaler;//最低2分频，200M SysCLK下，100 Max。
	
	SPI5.Transfer_start_FIFO_level = 1;
	SPI5.Transmit_FIFO_Threshold = 0;
	SPI5.Receive_FIFO_Threshold = 7;

	SPI5.Rx_Sample_Delay = SAMPLE_DELAY_2_0;

	SPI5.Trans_Type = TT0;      //TTO:指令和地址使用单线; TT1:指令使用单线，地址按配置输出;TT2:指令和地址都使用配置输出
//	SPI5.Instruction_length = INST_L0;
//	SPI5.WAIT_CYCLES = 0;
	SPI5.CLK_STRETCH_EN = CLK_STRETCH_ENABLE;
	
	
	DRV_SSI_Init(SSI2,&SPI5,0xFFFFFF);	
}

//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read_DUAL(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{   										       
	if(W25Q256)
		SPI5.Address_Length = ADDR_L32;
	else
		SPI5.Address_Length = ADDR_L24;
	
	SPI5_Dual_Read_Init();
	SPI5_Set_DataNum(NumByteToRead);
	__nop();__nop();__nop();
	
#if !SSI2_DMA
	SSI2->DR = 0x3B;
	SSI2->DR = ReadAddr;
	while((SSI2->SR&0x04) == 0)//TXFIFO空 等待命令和地址发送完毕
	{
		__nop();
	}
    for(i=0;i<NumByteToRead;i++)
	{ 
		while((SSI2->SR&0x08) == 0)__nop();
        ((unsigned char *)pBuffer)[i] = SSI2->DR;  		//循环读数  
    }
#else
	SSI2_DMA_RX(pBuffer,0x3B,ReadAddr,NumByteToRead,8,DUAL_mode,0);
#endif
	
	Check_SSI2_Busy();
	SPI5_STD_Init(); 				//切回单线	
} 

/****************************************************   Dual   **********************************************************/
//===========================================================================================================================================//

/****************************************************   Quad   **********************************************************/
void SPI5_Quad_Write_Init(void)
{
	DRV_SSI_Cmd(SSI2,DISABLE);//关闭SSI2
	
	SPI5.Format = QUAD_mode;
	SPI5.FRF   = FRF_SPI;				//
	SPI5.SCPH  = SCPH_MIDDLE_BIT; 		//
	SPI5.SCPOL = INACTIVE_HIGH;   		//
	SPI5.TMOD  = TX_ONLY;				//SPI 工作模式  发送和接受
	SPI5.SRL   = NORMAL_MODE;			//正常模式
	SPI5.SSTE  = TOGGLE_DISABLE;
	SPI5.CFS   = CFS_01_BIT;      		//控制帧位数格式
	
	SPI5.Transfer_start_FIFO_level = 1 ;
	SPI5.Transmit_FIFO_Threshold = 0;
	SPI5.Receive_FIFO_Threshold = 0;

	SPI5.Rx_Sample_Delay =  SAMPLE_DELAY_2_0;

	SPI5.Trans_Type = TT0;      //TTO:指令和地址使用单线; TT1:指令使用单线，地址按配置输出;TT2:指令和地址都使用配置输出
	SPI5.Instruction_length = INST_L8;
	SPI5.CLK_STRETCH_EN = CLK_STRETCH_ENABLE;
	
	DRV_SSI_Init(SSI2,&SPI5,0xFFFFFF);	
}
void SPI5_Quad_Read_Init(void)
{
	SPI5.Format = QUAD_mode;
	SPI5.FRF   = FRF_SPI;				//
	SPI5.SCPH  = SCPH_MIDDLE_BIT; 		//
	SPI5.SCPOL = INACTIVE_HIGH;   		//
	SPI5.TMOD  = RX_ONLY;				//SPI 工作模式  发送和接受
	SPI5.SRL   = NORMAL_MODE;			//正常模式
	SPI5.SSTE  = TOGGLE_DISABLE;
	SPI5.CFS   = CFS_01_BIT;      		//控制帧位数格式

	SPI5.Transfer_start_FIFO_level = 1;
	SPI5.Transmit_FIFO_Threshold = 0;
	SPI5.Receive_FIFO_Threshold = 7;

	SPI5.Rx_Sample_Delay = SAMPLE_DELAY_2_0;

	SPI5.Trans_Type = TT0;      //TTO:指令和地址使用单线; TT1:指令使用单线，地址按配置输出;TT2:指令和地址都使用配置输出
//	SPI5.Instruction_length = INST_L8;

	SPI5.CLK_STRETCH_EN = CLK_STRETCH_ENABLE;
	
	DRV_SSI_Init(SSI2,&SPI5,0xFFFFFF);	
}


//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read_QUAD(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{ 
	u16 num = 0;
	if(W25Q256)
		SPI5.Address_Length = ADDR_L32;
	else
		SPI5.Address_Length = ADDR_L24;

#if !SSI2_DMA
	
	SPI5.NDF = NumByteToRead-1;
	SPI5.SSI_QUAD_BaudRatePrescaler = 6;        
	SPI5.WAIT_CYCLES = 8;     
	SPI5_Quad_Read_Init();
	
	SSI2->DR = 0x6B;
	SSI2->DR = ReadAddr;
	__nop();__nop();__nop();
	while(((SSI2->SR&0x04) == 0) && ((SSI2->SR&0x08) == 0))// 等待 TXFIFO发送完毕，并且RXFIFO收到数据
	{
		__nop();
	}
    for(i=0;i<NumByteToRead;i++)
	{ 
		while((SSI2->SR&0x08) == 0)__nop();
        ((unsigned char *)pBuffer)[i] = SSI2->DR;  		//循环读数
    }
	
#else
	if(NumByteToRead%4 == 0)
	{
		SPI5.DFS = DFS_32_BIT;      				//数据帧位数格式
		num = (NumByteToRead/4)-1;
	}
	else
	{
		SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
		num = NumByteToRead - 1 ;
	}	
	SPI5.NDF = num;
	SPI5.SSI_QUAD_BaudRatePrescaler = SSI2_Quad_BaudRatePrescaler;        
	SPI5.Instruction_length = INST_L8;
	SPI5.WAIT_CYCLES = 8;    
	SPI5_Quad_Read_Init();
	if(NumByteToRead%4 == 0)
		SSI2_DMA_RX(pBuffer,0x6B,ReadAddr,num + 1,32,QUAD_mode,0);
	else
		SSI2_DMA_RX(pBuffer,0x6B,ReadAddr,num + 1,8,QUAD_mode,0);
#endif
	Check_SSI2_Busy();
	SPI5_STD_Init(); 				//切回单线	
} 
void W25QXX_Read_QUAD_DMA(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   //读取数目为4byte 倍数
{ 
// 	u16 i;  
	if(W25Q256)
		SPI5.Address_Length = ADDR_L32;
	else
		SPI5.Address_Length = ADDR_L24;
	
	SPI5.DFS = DFS_32_BIT;      				//数据帧位数格式
	SPI5.Instruction_length = INST_L8;
	SPI5.WAIT_CYCLES = 8;	
	SPI5_Quad_Read_Init();
	SPI5_Set_DataNum(NumByteToRead/4);
	SSI2_DMA_RX(pBuffer,0x6B,ReadAddr,NumByteToRead/4,32,QUAD_mode,0);
	Check_SSI2_Busy();
} 
//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!	 
void W25QXX_Write_Page_QUAD(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
	u16 num  = 0;
	
	SPI5_STD_Init();	
    W25QXX_Write_Enable_STD();                  					//SET WEL 

	if(W25Q256)
		SPI5.Address_Length = ADDR_L32;
	else
		SPI5.Address_Length = ADDR_L24;
	
	
#if !SSI2_DMA
	
	SPI5.NDF = NumByteToWrite-1;
	SPI5.SSI_QUAD_BaudRatePrescaler = 6;        
	SPI5.WAIT_CYCLES = 0;     
	SPI5_Quad_Write_Init();
	
	SSI2->DR = 0x32;
	SSI2->DR = WriteAddr;
	__nop();__nop();__nop();
    for(i=0;i<NumByteToWrite;i++) //循环写数据 
	{ 
		if((SSI2->SR&0x02) == 0x02)			                //TX FIFO 没满，继续写满
			SSI2->DR = ((unsigned char*)pBuffer)[i];  		//循环写数据
		else
		{
			while((SSI2->SR&0x04) == 0){}   //TX FIFO 已满，等待FIFO空
			SSI2->DR = ((unsigned char*)pBuffer)[i];
		} 		
    }
	Check_SSI2_Busy();
#else
	if(NumByteToWrite%4 == 0)
	{
		SPI5.DFS = DFS_32_BIT;      				//数据帧位数格式 
		num = (NumByteToWrite/4)-1;
	}
	else
	{
		SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
		num = NumByteToWrite - 1 ;
	}
	SPI5.NDF = num;
	SPI5.SSI_QUAD_BaudRatePrescaler = SSI2_Quad_BaudRatePrescaler;        
	SPI5.WAIT_CYCLES = 0;     
	SPI5_Quad_Write_Init();
	if(NumByteToWrite%4 == 0)
		SSI2_DMA_TX(pBuffer,0x32,WriteAddr,num + 1,32,QUAD_mode,0);
	else
		SSI2_DMA_TX(pBuffer,0x32,WriteAddr,num + 1,8,QUAD_mode,0);
#endif
	SPI5_STD_Init(); 
	W25QXX_Wait_Busy_STD();					   						//等待写入结束
	 
}
//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck_QUAD(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 			 		 
	u16 pageremain;	   
	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
	while(1)
	{	   
		W25QXX_Write_Page_QUAD(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个字节了
		}
	}
} 
/****************************************************   Quad   **********************************************************/
//===========================================================================================================================================//
/****************************************************    QPI   **********************************************************/

//#define QPI_BaudRatePrescaler 6

void Flash_Enter_QPI(void) //Flash进入QPI模式
{
	SPI5_STD_Init();       	//单线模式下使Flash进入QPI模式
	W25QXX_Enter_QPI_STD();	//Flash 进入QPI模式
	W25QXX_Wait_Busy_STD(); //等待Flash空闲
}





void SPI5_QPI_Set_DataNum(u16 num)
{
	DRV_SSI_Cmd(SSI2,DISABLE);//关闭SSI2
	SSI2->CTRLR1 = num;
	DRV_SSI_Cmd(SSI2,ENABLE);//使能SSI2
}


/****************************************************    QPI   **********************************************************/
//======================================================== NOR FLASH ===================================================================================//





//======================================================== NAND FLASH (1,2,4 Buffer Mode)===================================================================================//
uint8_t W25NXX_ReadSR(uint8_t reg)                    //读取W25NXX的状态寄存器
{  
	uint8_t byte = 0;   
	CS_FLash_RESET();                                    //使能器件 
	SSI2_ReadWriteByte(0x0F);   					  //发送读取状态寄存器命令 
	SSI2_ReadWriteByte(reg);                          //寄存器地址 
	byte = SSI2_ReadWriteByte(0x00);                  //读取一个字节 
	CS_FLash_SET();                                 	  //取消片选  	
	
	return byte;  
} 

//将WEL置位   
void W25NXX_Write_Enable(void)   //W25QXX写使能
{
	CS_FLash_RESET();                         			//使能器件   
    SSI2_ReadWriteByte(0x06); 	//发送写使能  
	CS_FLash_SET();                          		//取消片选     	      
} 
	
//将WEL清零  
void W25NXX_Write_Disable(void)   				//W25QXX写禁止
{  
	CS_FLash_RESET();                          	//使能器件   
    SSI2_ReadWriteByte(0x04); 					//发送写禁止指令    
	CS_FLash_SET();                            	//取消片选     	      
} 	

// 3个状态寄存器
// 保护寄存器1：地址0xA0
// 配置寄存器2: 地址0xB0
// 状态寄存器3: 地址0xC0  (只读寄存器)
void W25NXX_Write_SR(uint8_t reg, uint8_t val)   
{   
	W25NXX_Write_Enable();	
	CS_FLash_RESET(); 							//使能器件
       
	SSI2_ReadWriteByte(0x1F);          		//发送写取状态寄存器命令    
	SSI2_ReadWriteByte(reg);                //寄存器地址 
	SSI2_ReadWriteByte(val);               	//写入一个字节      	      
	
	CS_FLash_SET();                            //取消片选 
	W25NXX_Write_Disable();
} 

void W25NXX_Wait_Busy(void)   		        //等待空闲
{   
	while((W25NXX_ReadSR(0xC0)&0x01)==0x01);  		// 等待BUSY位清空
} 

void W25NXX_ContinuousRead_Mode(void)
{
	u8 statut = 0;
	statut = W25NXX_ReadSR(0xb0);
//	statut &= cClrb3;
//	statut &= cClrb4;
	statut &= ~0x08;
//	statut &= ~0x10;
	
	W25NXX_Write_SR(0xb0,statut);
}

//配置BUF=0：页读模式
void W25N01GV_PageRead_Mode(void)
{
	u8 statut = 0;
	statut = W25NXX_ReadSR(0xb0);
//	statut |= cSetb3;
//	statut |= cSetb4;
	statut |= 0x08;
	W25NXX_Write_SR(0xb0,statut);
}

void Write_Page(u32 page)
{
	CS_FLash_RESET();                            	    
	SSI2_ReadWriteByte(0x13);
	SSI2_ReadWriteByte((u8)(page>>16));
	SSI2_ReadWriteByte((u8)(page>>8));
	SSI2_ReadWriteByte((u8)page);
	CS_FLash_SET();
	W25NXX_Wait_Busy();
}

//读取芯片ID
//返回值如下:				   
//0xEFAA21,表示芯片型号为W25N01
//0xEFAA22,表示芯片型号为W25N02  
//0xEFAA23,表示芯片型号为W25N04  
uint32_t W25NXX_ReadID(void)
{
	uint8_t Mfr_id = 0;
	uint16_t Device_id = 0;
	uint32_t id = 0;
	
	CS_FLash_RESET();
//	SSI2_SS_RESET;	
	SSI2_ReadWriteByte(0x9f);
	SSI2_ReadWriteByte(0x00);
	Mfr_id = SSI2_ReadWriteByte(0xff);
	Device_id = SSI2_ReadWriteByte(0xff);
	Device_id = Device_id<<8 | SSI2_ReadWriteByte(0xff);
//	SSI2_SS_SET;
	CS_FLash_SET();
	
	id = Mfr_id;
	id = (id<<16)+Device_id;
	return id;
}  
/**********************擦除**********************/
//擦除128KB Block

void W25NXX_Erase_Block(uint16_t block)   
{               
	uint32_t addr = 0; 	
	addr = 64 * block;  				  //输入的是Page地址，一个块有64页。

	W25NXX_Write_SR(0xA0, 0x00);          // 关flash保护功能
	
    W25NXX_Write_Enable();                //SET WEL 
    W25NXX_Wait_Busy();   
	
    CS_FLash_RESET();  						    //使能器件
    SSI2_ReadWriteByte(0xD8);        	//发送片擦除命令  
	SSI2_ReadWriteByte((uint8_t)(addr>>16));
	SSI2_ReadWriteByte((uint8_t)(addr>>8)); 
	SSI2_ReadWriteByte((uint8_t)(addr));
	CS_FLash_SET();                         //取消片选     	
	
	W25NXX_Wait_Busy();   				        //等待芯片擦除结束
	W25NXX_Write_SR(0xA0,0x7C);                 // 开flash保护功能

}

void W25NXX_EraseFlash(unsigned short block_num)           // 
{
	unsigned short block = 0;
 
	printf("Block_num:%d \r\n",block_num);
	for(;block < block_num ; block++)
	{
		W25NXX_Erase_Block(block);
	}
	printf("擦除结束\r\n");
}

/**********************页模式**********************/

//单页写函数
//SPI在一页内写入不大于2048个字节的数据
//在指定地址开始写入最大2048字节的数据
//pBuffer:数据存储区
//ColumnAddr:开始写入的页内地址(0-2047)
//PageAddr:页地址
//NumByteToWrite:要写入的字节数(最大2048),该数不应该超过该页的剩余字节数!!!
void W25NXX_WritePageAddr_Data_STD(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToWrite)   //不能写入超过2048 Byte（一页2048个Byte，后面的64 Byte非数据位）
{
 	uint16_t i;
//	W25NXX_Write_SR(0xB0,W25NXX_ReadSR(0xB0)|0x08); //NandFlash 都切换到 buffer mode
	W25N01GV_PageRead_Mode();	
	
	W25NXX_Write_SR(0xA0, 0x00);                // 关flash保护功能

	//------写BUFF------
    W25NXX_Write_Enable();                  	//SET WEL 
    CS_FLash_RESET();                              //使能器件   
    SSI2_ReadWriteByte(0x02);      	            //发送写BUFF命令   
    SSI2_ReadWriteByte(ColumnAddr>>8); 	        //BUFF地址   
    SSI2_ReadWriteByte(ColumnAddr);
	
	for(i=0;i<NumByteToWrite;i++)SSI2_ReadWriteByte(pBuffer[i]);//循环写数 
	CS_FLash_SET();                                //取消片选 
	W25NXX_Wait_Busy();					    	//等待写入结束
	
	//-------BUFF数据写入flash--------
	CS_FLash_RESET();                          	//使能器件   
	SSI2_ReadWriteByte(0x10);					//发送写页命令   
	SSI2_ReadWriteByte(PageAddr>>16); 			//发送16it地址    
	SSI2_ReadWriteByte(PageAddr>>8); 			//发送16it地址    
	SSI2_ReadWriteByte(PageAddr);   
	CS_FLash_SET();   
	W25NXX_Wait_Busy();					        //等待写入结束 
		
	W25NXX_Write_SR(0xA0,0x7C);                 // 开flash保护功能	 
} 


void W25NXX_WritePageAddr_Data_QUAD(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToWrite)   //不能写入超过2048 Byte（一页2048个Byte，后面的64 Byte非数据位）
{
	uint16_t num = 0;
	W25NXX_Write_SR(0xA0, 0x00);          // 关flash保护功能

	//------写BUFF------
    W25NXX_Write_Enable();                  	//SET WEL 
	
#if !SSI2_DMA
	
	SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
	SPI5.SSI_QUAD_BaudRatePrescaler = 8;        //NandFlash 最高支持104MHz时钟， 250MHz下最低4分频 62.5MHz
	SPI5.Address_Length = ADDR_L16;
	SPI5.WAIT_CYCLES = 0;     
	SPI5.NDF = NumByteToWrite - 1 ;
	SPI5_Quad_Write_Init();
	
	SSI2->DR = 0x32;
	SSI2->DR = ColumnAddr;

    for(i=0;i<NumByteToWrite;i++) //循环写数据 
	{ 
		if((SSI2->SR&0x02) == 0x02)			                //TX FIFO 没满，继续写满
			SSI2->DR = ((unsigned char*)pBuffer)[i];  		//循环写数据
		else
		{
			while((SSI2->SR&0x04) == 0){}   				//TX FIFO 已满，等待FIFO空
			SSI2->DR = ((unsigned char*)pBuffer)[i];
		} 		
    }
	
#else
	if(NumByteToWrite%4 == 0)
	{
		SPI5.DFS = DFS_32_BIT;      				//数据帧位数格式
		num = (NumByteToWrite/4)-1;
	}
	else
	{
		SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
		num = NumByteToWrite - 1 ;
	}	
	SPI5.NDF = num;
	SPI5.SSI_QUAD_BaudRatePrescaler = SSI2_Quad_BaudRatePrescaler_for_NandFlash;
	SPI5.Address_Length = ADDR_L16;
	SPI5.WAIT_CYCLES = 0;
	SPI5_Quad_Write_Init();
	
	if(NumByteToWrite%4 == 0)	
		SSI2_DMA_TX(pBuffer,0x32,ColumnAddr,num + 1,32,QUAD_mode,0);	
	else
		SSI2_DMA_TX(pBuffer,0x32,ColumnAddr,num + 1,8,QUAD_mode,0);	
	
#endif	
	Check_SSI2_Busy();
	SPI5_STD_Init();
	W25NXX_Wait_Busy();					    	//等待写入结束
	
	
	
	//-------BUFF数据写入flash--------
	W25NXX_Write_Enable();
	CS_FLash_RESET();                          	//使能器件   
	SSI2_ReadWriteByte(0x10);      	    		//发送写页命令   
	SSI2_ReadWriteByte(PageAddr>>16); 			//发送高8位地址    
	SSI2_ReadWriteByte(PageAddr>>8); 		    //发送中8位地址    
	SSI2_ReadWriteByte(PageAddr);   			//发送低8位地址
	CS_FLash_SET();   
	W25NXX_Wait_Busy();					        //等待写入结束 
		
	W25NXX_Write_SR(0xA0,0x7C);                 // 开flash保护功能	 
} 

//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界! 
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(32bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25NXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite ,unsigned char mode)   //函数内部自动将32位地址转换为对应的页地址和页内地址
{             
	uint16_t WriteNum = 0;         //写入每一页的数据量
	uint16_t ColumnAddr;           //页内地址
	uint32_t PageAddr;             //页地址
//	printf("NumByteToWrite:%d\r\n",NumByteToWrite);
//判断第一次写入时，对应的页内地址，页地址，写入的数据量。
	ColumnAddr = (WriteAddr%2048);
	PageAddr = WriteAddr/2048;
	
	if(NumByteToWrite<(2048-ColumnAddr)) WriteNum = NumByteToWrite;         
	else WriteNum = 2048-ColumnAddr;	
	
	while(1)
	{
		if(mode==1)
			W25NXX_WritePageAddr_Data_STD(pBuffer,ColumnAddr,PageAddr,WriteNum);
		else if(mode==4)
			W25NXX_WritePageAddr_Data_QUAD(pBuffer,ColumnAddr,PageAddr,WriteNum);
		if(NumByteToWrite == WriteNum)break;    //如果已经写入的数据达到要求，则写入完毕，退出。因为NumByteToWrite是不断减少的，当减到最后一次的时候，要写入的数据必定等于剩余的数据。
		
		pBuffer += WriteNum;                    //数组头跟着移动
		ColumnAddr = 0;           				//下一次写入操作必定从页内0地址写起。		
		PageAddr++;								//下一次写入操作必定从新页开始写。
		NumByteToWrite -= WriteNum;				//总写入数据量根据已经写入的量进行减少。
		
		if(NumByteToWrite<2048)                //下一次不需要写满一页
		{
			 WriteNum =NumByteToWrite;
		}
		else WriteNum = 2048;                  //下一次要写满一页
	}
} 

void W25NXX_ReadPageAddr_Data_STD(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToRead)   
{ 
 	uint16_t i; 
	
//	W25NXX_Write_SR(0xB0,W25NXX_ReadSR(0xB0)|0x08);
	W25N01GV_PageRead_Mode();
	
    //------从flash读数据到BUFF-----	
	CS_FLash_RESET();                            //使能器件   
	SSI2_ReadWriteByte(0x13);
	SSI2_ReadWriteByte(PageAddr>>16);             
    SSI2_ReadWriteByte(PageAddr>>8);     //发送16bit页地址，将对应页的数据提取到BUFF中     
    SSI2_ReadWriteByte(PageAddr);   
	CS_FLash_SET(); 	
	W25NXX_Wait_Busy();	
	
	//------再从BUFF读数据到单片机内-----
	
	CS_FLash_RESET();   	
	SSI2_ReadWriteByte(0x03); 
	SSI2_ReadWriteByte(ColumnAddr>>8);  
	SSI2_ReadWriteByte(ColumnAddr); 	
	SSI2_ReadWriteByte(0xFF);	
	for(i=0;i<NumByteToRead;i++)
	{ 
		pBuffer[i]= SSI2_ReadWriteByte(0xFF);   	//循环读数  
	}
	CS_FLash_SET();
	W25NXX_Wait_Busy();
}

void W25NXX_ReadPageAddr_Data_QUAD(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToRead)   
{ 
	uint16_t num = 0;
	
	W25NXX_Write_SR(0xB0,W25NXX_ReadSR(0xB0)|0x08);   //NandFlash 都切换到 buffer mode 
	
    //------从flash读数据到BUFF-----	
	CS_FLash_RESET();                            //使能器件   
	SSI2_ReadWriteByte(0x13);
	SSI2_ReadWriteByte(PageAddr>>16);             
    SSI2_ReadWriteByte(PageAddr>>8);     //发送16bit页地址，将对应页的数据提取到BUFF中     
    SSI2_ReadWriteByte(PageAddr);   
	CS_FLash_SET(); 	
	W25NXX_Wait_Busy();
	//------再从BUFF读数据到单片机内-----

	
//	printf("NumByteToRead:%d\r\n",NumByteToRead);
//	printf("ColumnAddr:%d\r\n",ColumnAddr);
	
#if !SSI2_DMA
	
	SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
	SPI5.SSI_QUAD_BaudRatePrescaler = 8;        //NandFlash 最高支持104MHz时钟， 250MHz下最低4分频 62.5MHz
	SPI5.Address_Length = ADDR_L16;
	SPI5.WAIT_CYCLES = 8;     
	SPI5.NDF = NumByteToRead - 1 ;
	SPI5_Quad_Read_Init();

	SSI2->DR = 0x6B;
	SSI2->DR = ColumnAddr;

	while(((SSI2->SR&0x04) == 0) && ((SSI2->SR&0x08) == 0))// 等待 TXFIFO发送完毕，并且RXFIFO收到数据
	{
		__nop();
	}
    for(i=0;i<NumByteToRead;i++)
	{ 
		while((SSI2->SR&0x08) == 0)__nop();
        ((unsigned char *)pBuffer)[i] = SSI2->DR;  		//循环读数
    }
	
#else
//	if(NumByteToRead%4 == 0)
//	{
//		SPI5.DFS = DFS_32_BIT;      				//数据帧位数格式
//		num = (NumByteToRead/4)-1;
//	}
//	else
//	{
		SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
		num = NumByteToRead - 1;
//	}
	SPI5.NDF = num;
	SPI5.SSI_QUAD_BaudRatePrescaler = SSI2_Quad_BaudRatePrescaler_for_NandFlash;
	SPI5.Address_Length = ADDR_L16;
	SPI5.Instruction_length = INST_L8;
	SPI5.WAIT_CYCLES = 8;
	SPI5_Quad_Read_Init();
	
	CS_FLash_RESET();
//	if(NumByteToRead%4 == 0)		
//		SSI2_DMA_RX(pBuffer,0x6B,ColumnAddr,num + 1,32,QUAD_mode,0);
//	else
		SSI2_DMA_RX(pBuffer,0x6B,ColumnAddr,num + 1,8,QUAD_mode,0);
	CS_FLash_SET();
#endif
	Check_SSI2_Busy();
	SPI5_STD_Init(); 								//切回单线
	W25NXX_Wait_Busy();
}

//void W25NXX_ReadPageAddr_Data_QUAD_16Bits(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToRead)   
//{ 
// 	uint16_t i; 
//	uint16_t num = 0;
//	
//	W25NXX_Write_SR(0xB0,W25NXX_ReadSR(0xB0)|0x08);   //NandFlash 都切换到 buffer mode 
//	
//    //------从flash读数据到BUFF-----	
//	CS_FLash_RESET();                            //使能器件   
//	SSI2_ReadWriteByte(0x13);
//	SSI2_ReadWriteByte(PageAddr>>16);             
//    SSI2_ReadWriteByte(PageAddr>>8);     //发送16bit页地址，将对应页的数据提取到BUFF中     
//    SSI2_ReadWriteByte(PageAddr);   
//	CS_FLash_SET(); 	
//	W25NXX_Wait_Busy();
//	//------再从BUFF读数据到单片机内-----

//	
////	printf("NumByteToRead:%d\r\n",NumByteToRead);
////	printf("ColumnAddr:%d\r\n",ColumnAddr);
//	
//#if !SSI2_DMA
//	
//	SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
//	SPI5.SSI_QUAD_BaudRatePrescaler = 8;        //NandFlash 最高支持104MHz时钟， 250MHz下最低4分频 62.5MHz
//	SPI5.Address_Length = ADDR_L16;
//	SPI5.WAIT_CYCLES = 8;     
//	SPI5.NDF = NumByteToRead - 1 ;
//	SPI5_Quad_Read_Init();

//	SSI2->DR = 0x6B;
//	SSI2->DR = ColumnAddr;

//	while(((SSI2->SR&0x04) == 0) && ((SSI2->SR&0x08) == 0))// 等待 TXFIFO发送完毕，并且RXFIFO收到数据
//	{
//		__nop();
//	}
//    for(i=0;i<NumByteToRead;i++)
//	{ 
//		while((SSI2->SR&0x08) == 0)__nop();
//        ((unsigned char *)pBuffer)[i] = SSI2->DR;  		//循环读数
//    }
//	
//#else
//	if(NumByteToRead%2 == 0)
//	{
//		SPI5.DFS = DFS_16_BIT;      				//数据帧位数格式
//		num = (NumByteToRead/2)-1;
//	}
//	else
//	{
//		SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
//		num = NumByteToRead - 1;
//	}
//	SPI5.NDF = num;
//	SPI5.SSI_QUAD_BaudRatePrescaler = SSI2_Quad_BaudRatePrescaler_for_NandFlash;
//	SPI5.Address_Length = ADDR_L16;
//	SPI5.WAIT_CYCLES = 8;
//	SPI5_Quad_Read_Init();
//	
//	if(NumByteToRead%2 == 0)		
//		SSI2_DMA_RX(pBuffer,0x6B,ColumnAddr,num + 1,16,QUAD_mode,0);
//	else
//		SSI2_DMA_RX(pBuffer,0x6B,ColumnAddr,num + 1,8,QUAD_mode,0);

//#endif
//	Check_SSI2_Busy();
//	SPI5_STD_Init(); 								//切回单线
//	W25NXX_Wait_Busy();
//}

//void W25NXX_ReadPageAddr_Data_QUAD_Con(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToRead)   
//{ 
// 	uint16_t i; 
//	uint16_t num = 0;
//	
//	W25NXX_Write_SR(0xB0,W25NXX_ReadSR(0xB0)|0x08);   //NandFlash 都切换到 buffer mode 
//	
//    //------从flash读数据到BUFF-----	
//	CS_FLash_RESET();                            //使能器件   
//	SSI2_ReadWriteByte(0x13);
//	SSI2_ReadWriteByte(PageAddr>>16);             
//    SSI2_ReadWriteByte(PageAddr>>8);     //发送16bit页地址，将对应页的数据提取到BUFF中     
//    SSI2_ReadWriteByte(PageAddr);   
//	CS_FLash_SET(); 	
//	W25NXX_Wait_Busy();
//	//------再从BUFF读数据到单片机内-----

//	
////	printf("NumByteToRead:%d\r\n",NumByteToRead);
////	printf("ColumnAddr:%d\r\n",ColumnAddr);
//	
//#if !SSI2_DMA
//	
//	SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
//	SPI5.SSI_QUAD_BaudRatePrescaler = 8;        //NandFlash 最高支持104MHz时钟， 250MHz下最低4分频 62.5MHz
//	SPI5.Address_Length = ADDR_L16;
//	SPI5.WAIT_CYCLES = 8;     
//	SPI5.NDF = NumByteToRead - 1 ;
//	SPI5_Quad_Read_Init();

//	SSI2->DR = 0x6B;
//	SSI2->DR = ColumnAddr;

//	while(((SSI2->SR&0x04) == 0) && ((SSI2->SR&0x08) == 0))// 等待 TXFIFO发送完毕，并且RXFIFO收到数据
//	{
//		__nop();
//	}
//    for(i=0;i<NumByteToRead;i++)
//	{ 
//		while((SSI2->SR&0x08) == 0)__nop();
//        ((unsigned char *)pBuffer)[i] = SSI2->DR;  		//循环读数
//    }
//	
//#else
//	if(NumByteToRead%4 == 0)
//	{
//		SPI5.DFS = DFS_32_BIT;      				//数据帧位数格式
//		num = (NumByteToRead/4)-1;
//	}
//	else
//	{
//		SPI5.DFS = DFS_08_BIT;      				//数据帧位数格式
//		num = NumByteToRead - 1;
//	}
//	SPI5.NDF = num;
//	SPI5.SSI_QUAD_BaudRatePrescaler = SSI2_Quad_BaudRatePrescaler_for_NandFlash;
//	SPI5.Address_Length = ADDR_L16;
//	SPI5.WAIT_CYCLES = 8;
//	SPI5_Quad_Read_Init();
//	
//	if(NumByteToRead%4 == 0)		
//		SSI2_DMA_RX(pBuffer,0x6B,ColumnAddr,num + 1,32,QUAD_mode,0);
//	else
//		SSI2_DMA_RX(pBuffer,0x6B,ColumnAddr,num + 1,8,QUAD_mode,0);

//#endif
//	Check_SSI2_Busy();
//	SPI5_STD_Init(); 								//切回单线
//	W25NXX_Wait_Busy();

//}

//无检验读SPI FLASH 
//具有自动换页功能 
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(32bit)
//NumByteToRead:要读取的字节数(最大65535)
//CHECK OK
void W25NXX_Read_NoCheck(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead,unsigned char mode)   //函数内部自动将32位地址转换为对应的页地址和页内地址
{             
	uint16_t ReadNum = 0;         //读取每一页的数据量
	uint16_t ColumnAddr;          //业内地址
	uint32_t PageAddr;
	
//判断第一次读取时，对应的页内地址，页地址，写入的数据量。
	ColumnAddr = (ReadAddr%2048);
	PageAddr = ReadAddr/2048;
	
	if(NumByteToRead<(2048-ColumnAddr)) ReadNum = NumByteToRead;         
	else ReadNum = 2048-ColumnAddr;
	
	while(1)
	{
		if(mode == 1)
			W25NXX_ReadPageAddr_Data_STD(pBuffer,ColumnAddr,PageAddr,ReadNum);
		else if(mode == 4)
			W25NXX_ReadPageAddr_Data_QUAD(pBuffer,ColumnAddr,PageAddr,ReadNum);
		
		if(NumByteToRead == ReadNum)break;    //如果已经写入的数据达到要求，则写入完毕，退出。因为NumByteToWrite是不断减少的，当减到最后一次的时候，要写入的数据必定等于剩余的数据。
		
		pBuffer += ReadNum;                     //数组头跟着移动
		ColumnAddr = 0;           				//下一次读取操作必定从页内0地址写起。		
		PageAddr++;								//下一次读取操作必定从新页开始写。
		NumByteToRead -= ReadNum;				//总读取数据量根据已经读取的量进行减少。
		
		if(NumByteToRead<2048)                //下一次不需要写满一页
		{
			 ReadNum =NumByteToRead;
		}
		else ReadNum = 2048;                  //下一次要写满一页
	}
} 

//void W25NXX_Read_NoCheck_16Bits(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead,unsigned char mode)   //函数内部自动将32位地址转换为对应的页地址和页内地址
//{             
//	uint16_t ReadNum = 0;         //读取每一页的数据量
//	uint16_t ColumnAddr;          //业内地址
//	uint32_t PageAddr;
//	
////判断第一次读取时，对应的页内地址，页地址，写入的数据量。
//	ColumnAddr = (ReadAddr%2048);
//	PageAddr = ReadAddr/2048;
//	
//	if(NumByteToRead<(2048-ColumnAddr)) ReadNum = NumByteToRead;         
//	else ReadNum = 2048-ColumnAddr;
//	
//	while(1)
//	{
//		if(mode == 1)
//			W25NXX_ReadPageAddr_Data_STD(pBuffer,ColumnAddr,PageAddr,ReadNum);
//		else if(mode == 4)
//			W25NXX_ReadPageAddr_Data_QUAD_16Bits(pBuffer,ColumnAddr,PageAddr,ReadNum);
//		
//		if(NumByteToRead == ReadNum)break;    //如果已经写入的数据达到要求，则写入完毕，退出。因为NumByteToWrite是不断减少的，当减到最后一次的时候，要写入的数据必定等于剩余的数据。
//		
//		pBuffer += ReadNum;                     //数组头跟着移动
//		ColumnAddr = 0;           				//下一次读取操作必定从页内0地址写起。		
//		PageAddr++;								//下一次读取操作必定从新页开始写。
//		NumByteToRead -= ReadNum;				//总读取数据量根据已经读取的量进行减少。
//		
//		if(NumByteToRead<2048)                //下一次不需要写满一页
//		{
//			 ReadNum =NumByteToRead;
//		}
//		else ReadNum = 2048;                  //下一次要写满一页
//	}
//}

