#include <string.h>
#include "w25qxx.h"
#include "dmac_drv.h"
#include "delay.h"
#include "ssi_drv.h"
#include "QSPI.h"
#include "trans_port.h"

extern UINT32 g_sys_clk;


UINT8  Flash_Type = 0;	  //Flash_Type = 0, 24bits地址的NorFlash
                          //Flash_Type = 1, 32bits地址的NorFlash W25Q256 NorFlash的标志 ，用于识别到256的时候开启4Byte 地址
                          //Flash_Type = 2, Nand Flash
UINT16  Flash_ID = 0;      					
UINT16  Nand_page = 0;      			//  Nand Flash当前页地址，用于判断是否切换页地址






//读取W25QXX的状态寄存器
//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(unsigned char Reg)   //读取W25QXX的状态寄存器
{  
	uint8_t retVal=0; 

	SSI_TypeDef *SSIx=SSI1;
	
	SSIx->SSI_DR = Reg;
	SSIx->SSI_DR = 0xff;

	__asm("nop");	__asm("nop");	__asm("nop");

	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}
	while(SSIx->SSI_SR&SR_BUSY){;}

	while(SSIx->SSI_SR&SR_RFNE)
	{
		retVal=SSIx->SSI_DR;
	}
	
	return retVal;   
} 

uint8_t W25QXX_WriteSR(unsigned char Reg, unsigned char val)   
{  
	volatile unsigned char retVal;
	
	SSI_TypeDef *SSIx=SSI1;
	
  //W25QXX_Write_Enable();           //enable
	W25QXX_Write_EnableVolatile();
		
	SSIx->SSI_DR=Reg;
	SSIx->SSI_DR=val;
	__asm("nop"); __asm("nop"); __asm("nop");
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}
	while(SSIx->SSI_SR&SR_BUSY){;}
	while(SSIx->SSI_SR&SR_RFNE)
	{
		retVal=SSIx->SSI_DR;
	}
	
	W25QXX_Wait_Busy();
}

//将WEL置位   
void W25QXX_Write_Enable(void)   //W25QXX写使能
{
	volatile unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	SSI1_STD_Init(SSI1);
	
	if((W25QXX_ReadSR(W25X_ReadSR1)&0x02) == 0)
	{
		SSIx->SSI_DR=W25X_WriteEnable;
	
		__asm("nop"); __asm("nop"); __asm("nop");
		
		while((SSIx->SSI_SR&SR_TFE)==0x00){;}
			
		while(SSIx->SSI_SR&SR_BUSY){;}
		
		while(SSIx->SSI_SR&SR_RFNE)
		{
				temp=SSIx->SSI_DR;//清空fifo
		}	
		W25QXX_Wait_Busy();
	}

}

void W25QXX_Write_EnableVolatile(void)   //W25QXX写使能
{
	volatile unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	SSI1_STD_Init(SSI1);
	
		SSIx->SSI_DR=W25X_WriteEnable_VSR;
	
		__asm("nop"); __asm("nop"); __asm("nop");
		
		while((SSIx->SSI_SR&SR_TFE)==0x00){;}
			
		while(SSIx->SSI_SR&SR_BUSY){;}
		
		while(SSIx->SSI_SR&SR_RFNE)
		{
				temp=SSIx->SSI_DR;//清空fifo
		}	
		W25QXX_Wait_Busy();

} 

//将WEL清零  
void W25QXX_Write_Disable(void)   //W25QXX写禁止
{
	volatile unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	if((W25QXX_ReadSR(W25X_ReadSR1)&0x02) == 0x02)
	{
		SSIx->SSI_DR=W25X_WriteDisable;
	
		__asm("nop"); __asm("nop"); __asm("nop");
		
		while((SSIx->SSI_SR&SR_TFE)==0x00){;}
			
		while(SSIx->SSI_SR&SR_BUSY){;}
		
		while(SSIx->SSI_SR&SR_RFNE)
		{
				temp=SSIx->SSI_DR;//清空fifo
		}	
			
		W25QXX_Wait_Busy();
	}
}

void W25QXX_Wait_Busy(void)   		//等待空闲
{
	while((W25QXX_ReadSR(W25X_ReadSR1)&0x01));  		// 等待BUSY位清空
}

 /*进入4Byte地址模式*/
void W25QXX_4ByteAddress_Mode(void)
{
	volatile unsigned char status;
	unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	temp = 0x00;	
	SSIx->SSI_DR = W25X_Enter_4ByteAddr;  //进入
	//SSIx->SSI_DR = W25X_Exit_4ByteAddr;		//退出

	__asm("nop"); __asm("nop"); __asm("nop");	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}
	while(SSIx->SSI_SR&SR_BUSY){;}

	temp=SSIx->SSI_DR;//清空fifo
}

 /* 打开QE*/
UINT8 W25QXX_QE_Enable(void)
{
	UINT8 temp=0;

	//开启双线四线模式
	temp=W25QXX_ReadSR(W25X_ReadSR2);   								//SET QE 
	if(!(temp&0x02))
	{
		
		W25QXX_Write_EnableVolatile();  //W25QXX_Write_Enable();
			
		W25QXX_WriteSR(W25X_WriteSR2,temp|0x02);

		W25QXX_Wait_Busy();
	}
	
	//printf("W25QXX_ReadSR =0x%x  \r\n",W25QXX_ReadSR(W25X_ReadSR2));
}

//读取芯片ID
//返回值如下:				   
//0XEF13,表示芯片型号为W25Q80  
//0XEF14,表示芯片型号为W25Q16    
//0XEF15,表示芯片型号为W25Q32  
//0XEF16,表示芯片型号为W25Q64 
//0XEF17,表示芯片型号为W25Q128 	  
UINT32 W25QXX_ReadID(void)
{
	int i;
	volatile unsigned short Device_ID;
	SSI_TypeDef *SSIx=SSI1;
	
	SSIx->SSI_DR=W25X_ManufactDeviceID;
	SSIx->SSI_DR = 0x00;
	SSIx->SSI_DR = 0x00;
	SSIx->SSI_DR = 0x00;

	SSIx->SSI_DR=DUMMY_BYTE;
	SSIx->SSI_DR=DUMMY_BYTE;	

	__asm("nop");	__asm("nop");	__asm("nop");

	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}
	while(SSIx->SSI_SR&SR_BUSY){;}

	for(i=0; i<4; i++)
	{
		Device_ID = SSIx->SSI_DR;
	}

	Device_ID  = (SSIx->SSI_DR<<8);
	Device_ID |= (SSIx->SSI_DR);
	
	return Device_ID;
}


void W25QXX_Init(void)
{
	SSI_TypeDef *SSIx=SSI1;
	
	if(Flash_ID==0xEF18||Flash_ID==0xC818||Flash_ID==0x0B16)  //256M flash
	{
		Flash_Type=1; 
		W25QXX_4ByteAddress_Mode();
	}

	W25QXX_QE_Enable();       			//QE
	
}

//复位
void LT268_exFlash_soft_reset(void)
{

}

//------------------------------------------------------------------ Write --------------------------------------------------------------------------
void W25QXX_STD_DMA_Send(SSI_TypeDef *SSIx,int dma_ch, UINT8* psend, UINT32 addr, UINT32 length, BOOL binten)
{
    int num;
	
	exFlash_dma_control->DMA_CONFIG = 1;
	//Tx
	exFlash_dma_channel[dma_ch]->DMA_SADDR = (UINT32)psend;
	exFlash_dma_channel[dma_ch]->DMA_DADDR = (UINT32)&SSIx->SSI_DR;
	if(binten == TRUE)
	{
		exFlash_dma_channel[dma_ch]->DMA_CTRL = INTEN|DNOCHG|SIEC|M2P_DMA|DWIDTH_B|SWIDTH_B|SBSIZE_4|DBSIZE_4;
	}
	else
	{
		exFlash_dma_channel[dma_ch]->DMA_CTRL = DNOCHG|SIEC|M2P_DMA|DWIDTH_B|SWIDTH_B|SBSIZE_4|DBSIZE_4;
	}
	exFlash_dma_channel[dma_ch]->DMA_CTRL_HIGH = length&0xFFF;  //最大长度为0x0FFF
	exFlash_dma_channel[dma_ch]->DMA_CFG = (HS_SEL_DST_HARD);
	exFlash_dma_channel[dma_ch]->DMA_CFG_HIGH = exFlash_DST_TX;

	//enable dma channel
	exFlash_dma_control->DMA_CHEN |= (CHANNEL_WRITE_ENABLE(dma_ch)|CHANNEL_ENABLE(dma_ch));
	
//	SSI_STD_DMA_Trig(SSIx, PAGE_PROG_CMD, addr, DMACR_TDMAE);
	
	SSIx->SSI_DR= W25X_PageProgram;   //W25X_PageProgram_4B; 
	if (Flash_Type==1)
		SSIx->SSI_DR = (addr>>24)&0xff;
	SSIx->SSI_DR=(addr>>16)&0xff;
	SSIx->SSI_DR=(addr>>8)&0xff;
	SSIx->SSI_DR=(addr>>0)&0xff;
	SSIx->SSI_DMACR=DMACR_TDMAE;

    while(exFlash_dma_control->DMA_CHEN & CHANNEL_STAT(dma_ch)){}
		exFlash_dma_control->DMA_CHEN &=~(CHANNEL_WRITE_ENABLE(dma_ch)|CHANNEL_ENABLE(dma_ch));
		exFlash_dma_channel[dma_ch]->DMA_CFG &= ~(1<<8);

    SSIx->SSI_DMACR = 0;
}

//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!	 
void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{	
	W25QXX_Write_Enable();
	
	W25QXX_STD_DMA_Send(SSI1,exFlash_CHNUM,pBuffer,WriteAddr,NumByteToWrite,0);
	
	SSI1_STD_Init(SSI1);

	W25QXX_Wait_Busy();
}

//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
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个字节了
		}
	}
} 
//------------------------------------------------------------------ Read --------------------------------------------------------------------------
//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
{
	volatile unsigned char temp;
	int i=0,j=0;
	int txnum;
	SSI_TypeDef *SSIx=SSI1;

	txnum=NumByteToRead;
	if (Flash_Type==1)
	{
		SSIx->SSI_DR = W25X_ReadData;
		SSIx->SSI_DR = (ReadAddr>>24)&0xff;
	}
	else  	SSIx->SSI_DR = W25X_ReadData;

	SSIx->SSI_DR = (ReadAddr>>16)&0xff;
	SSIx->SSI_DR = (ReadAddr>>8)&0xff;
	SSIx->SSI_DR = (ReadAddr>>0)&0xff;
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	if (Flash_Type==1)
	{
		while(NumByteToRead>0)
		{
			if( (SSIx->SSI_SR&SR_TFNF)&&(txnum>0) )
			{
				SSIx->SSI_DR=DUMMY_BYTE;
				txnum--;
			}	 
				 
			if(SSIx->SSI_SR&SR_RFNE)
			{
				if(j < 5)
				{
					temp=SSIx->SSI_DR;
					j++;
				}
				else
				{
					*(pBuffer+i)=SSIx->SSI_DR;
					 i++;
					 NumByteToRead--;
				}
			}
		}
	}
	else
	{
		while(NumByteToRead>0)
		{
			if( (SSIx->SSI_SR&SR_TFNF)&&(txnum>0) )
			{
				SSIx->SSI_DR=DUMMY_BYTE;
				txnum--;
			}	 
				 
			if(SSIx->SSI_SR&SR_RFNE)
			{
				if(j < 4)
				{
					temp=SSIx->SSI_DR;
					j++;
				}
				else
				{
					*(pBuffer+i)=SSIx->SSI_DR;
					 i++;
					 NumByteToRead--;
				}
			}
		}
	}
	
	while(SSIx->SSI_SR&SR_BUSY){;}
} 

//------------------------------------------------------------------ Erase --------------------------------------------------------------------------
void W25QXX_SectorErase4K(uint32_t addr)   
{
	volatile unsigned char status;
	unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	W25QXX_Write_Enable();                 	 	  //SET WEL 

	if (Flash_Type==1)
	{
		SSIx->SSI_DR = W25X_SectorErase;                 //W25X_SectorErase_4B;	  
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送32bit块地址	
	}else SSIx->SSI_DR = W25X_SectorErase;
	
	SSIx->SSI_DR = (addr>>16)&0xFF;
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR = (addr)&0xFF;

	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)==0x00){;}
		
	while(SSIx->SSI_SR&SR_BUSY){;}

	while(SSIx->SSI_SR&SR_RFNE)
	{
		temp=SSIx->SSI_DR;//清空fifo
	}
	
	W25QXX_Wait_Busy();
} 

void W25QXX_BlockErase32KB(uint32_t addr)   
{
	volatile unsigned char status;
	unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	//addr=addr*65536;							
	temp = 0x00;	
	
	W25QXX_Write_Enable();                 	 	  //SET WEL 
	
	SSIx->SSI_DR = W25X_32KBlockErase;
	if (Flash_Type==1)
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送块地址	
	SSIx->SSI_DR = (addr>>16)&0xFF;    
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR =  addr&0xFF;
	
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)==0x00){;}
		
	while(SSIx->SSI_SR&SR_BUSY){;}

	while(SSIx->SSI_SR&SR_RFNE)
	{
		temp=SSIx->SSI_DR;//清空fifo
	}

	W25QXX_Wait_Busy();
}

void W25QXX_BlockErase64KB(UINT32 addr)   
{
	unsigned char temp=0;

	SSI_TypeDef *SSIx=SSI1;
	
	W25QXX_Write_Enable();                 	 	  //SET WEL 
	W25QXX_Wait_Busy();

	SSIx->SSI_DR = W25X_64KBlockErase;   //W25X_64KBlockErase_4B; ----不兼容
	if (Flash_Type==1)
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送块地址
	SSIx->SSI_DR = (addr>>16)&0xFF;    
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR = (addr)&0xFF;		

	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)==0x00){;}
		
	while(SSIx->SSI_SR&SR_BUSY){;}

	while(SSIx->SSI_SR&SR_RFNE)
	{
		temp=SSIx->SSI_DR;//清空fifo
	}
	
	W25QXX_Wait_Busy();
}

//擦除整个芯片		  
//等待时间超长...
void W25QXX_Erase_Chip(void)   
{          
	volatile unsigned char status;
	unsigned char temp=0;
	SSI_TypeDef *SSIx=SSI1;
	
	W25QXX_Write_Enable();                 	//SET WEL 
	
	SSIx->SSI_DR = W25X_ChipErase;
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)==0x00){;}
		
	while(SSIx->SSI_SR&SR_BUSY){;}

	while(SSIx->SSI_SR&SR_RFNE)
	{
		temp=SSIx->SSI_DR;//清空fifo
	}

	W25QXX_Wait_Busy();
} 


/*Dual_Read_Mode*/
void NorFlash_Read_Init(UINT8 CmdLen, UINT8 waitCycles,UINT32 data_len)
{
	SSI_TypeDef *SSIx=SSI1;
	//-----------------DUAL MODE-----------------------
	#if 1
	SSIx->SSI_SSIENR = 0x00;	 
	SSIx->SSI_BAUDR =  QUAD_BAUDR;
	SSIx->SSI_CTRLR1 = ((data_len == 0)?0:(data_len-1));
		
	SSIx->SSI_CTRLR0 = 07;
	SSIx->SSI_SPI_CTRLR0 = 0;
		
	SSIx->SSI_CTRLR0 |= (CTRLR0_SPI_FRF_DUAL|CTRLR0_FRF_MOT|CTRLR0_DFS_VALUE(0x07)|CTRLR0_TMOD_RX_ONLY|
						 CTRLR0_SSTE_MASK(0)|CTRLR0_SCPOL_MASK(0)|CTRLR0_SCPH_MASK(0));
	
	SSIx->SSI_SPI_CTRLR0|= ( CTRLR0_TRANS_TYPE_TT0  |CTRLR0_INST_L_VALUE(CmdLen)               		//CMD_Len: 0=0bit，1=4bit，2=8bit, 3=16bit
													|CTRLR0_WAIT_CYCLES_VALUE(waitCycles)      		//dummy_clock max=31 
													|CTRLR0_CLK_STRETCH_EN_MASK );
	
	if(Flash_Type==1)	SSIx->SSI_SPI_CTRLR0|=CTRLR0_ADDR_L_VALUE(0x08);     // 4 Byte addr
	else   						SSIx->SSI_SPI_CTRLR0|=CTRLR0_ADDR_L_VALUE(0x06);     // 3 Byte addr     //addr_len= n*4 bit ( max_n=15)
	
	SSIx->SSI_TXFTLR = 0x00010000;
	SSIx->SSI_RXFTLR = 0x7;	
	
	if(QUAD_BAUDR==0x02&&g_sys_clk>=80000000)//high speed
	{
	 SSIx->SSI_RX_SAMPLE_DELAY=0x00010001;
	}
	
	SSIx->SSI_IMR = 0x00;
	SSIx->SSI_SSIENR = 0x01;
	//----------------- END -----------------------------------------------------
	#else
	//-----------------QUAL MODE---------------------------
	//----------------- END -----------------------------------------------------
	#endif
}
void NorFlash_Read(unsigned int addr, unsigned char *buf, int num)
{
	int i=0;
	SSI_TypeDef *SSIx=SSI1;
	
	//NorFlash_Read_Init(2,8,num);
	SSIx->SSI_SSIENR = 0x00;	 
	SSIx->SSI_BAUDR =  QUAD_BAUDR;
	SSIx->SSI_CTRLR1 = ((num == 0)?0:(num-1));
	SSIx->SSI_CTRLR0 = 07;
	SSIx->SSI_SPI_CTRLR0 = 0;
	SSIx->SSI_CTRLR0 |= (CTRLR0_SPI_FRF_DUAL|CTRLR0_FRF_MOT|CTRLR0_DFS_VALUE(0x07)|CTRLR0_TMOD_RX_ONLY);
	SSIx->SSI_SPI_CTRLR0|= ( CTRLR0_TRANS_TYPE_TT0  |CTRLR0_INST_L_VALUE(2)               		//CMD_Len: 0=0bit，1=4bit，2=8bit, 3=16bit
													|CTRLR0_WAIT_CYCLES_VALUE(8)      		//dummy_clock max=31 
													|CTRLR0_CLK_STRETCH_EN_MASK );
	if(Flash_Type==1)	SSIx->SSI_SPI_CTRLR0|=CTRLR0_ADDR_L_VALUE(0x08);     // 4 Byte addr
	else   						SSIx->SSI_SPI_CTRLR0|=CTRLR0_ADDR_L_VALUE(0x06);     // 3 Byte addr     //addr_len= n*4 bit ( max_n=15)
	
	SSIx->SSI_TXFTLR = 0x00010000;
	SSIx->SSI_RXFTLR = 0x7;	
	if(QUAD_BAUDR==0x02&&g_sys_clk>=80000000)//high speed
	{
	 SSIx->SSI_RX_SAMPLE_DELAY=0x00010001;
	}
	SSIx->SSI_IMR = 0x00;
	SSIx->SSI_SSIENR = 0x01;
	
	DelayUS(1);
	
  SSIx->SSI_DR = W25X_FastReadDual;
	
	SSIx->SSI_DR = addr;
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}

//	while( ((num>0)&&(SSIx->SSI_SR&SR_BUSY))||(SSIx->SSI_SR&SR_RFNE) )
	while( num>0)
	{   
		if(SSIx->SSI_SR&SR_RFNE)
		{
				*(buf+i)=SSIx->SSI_DR;
				i++;
				num--;
		}
	}	
	
}

													
//------------------------------------------------------------------ DMA --------------------------------------------------------------------------
void NorFlash_DMA_Read_Init(UINT8 CmdLen, UINT8 waitCycles,UINT32 data_len)
{
	SSI_TypeDef *SSIx=SSI1;
	//-----------------DUAL MODE-----------------------
	#if 1
	SSIx->SSI_SSIENR = 0x00;	 
	SSIx->SSI_BAUDR =  QUAD_BAUDR;
	SSIx->SSI_CTRLR1 = ((data_len == 0)?0:(data_len-1));
	SSIx->SSI_CTRLR0 = 07;
	SSIx->SSI_SPI_CTRLR0 = 0;
	SSIx->SSI_CTRLR0 |= (CTRLR0_SPI_FRF_DUAL|CTRLR0_FRF_MOT|CTRLR0_DFS_VALUE(0x07)|CTRLR0_TMOD_RX_ONLY);
	SSIx->SSI_SPI_CTRLR0|= ( CTRLR0_TRANS_TYPE_TT0  |CTRLR0_INST_L_VALUE(CmdLen)               		//CMD_Len: 0=0bit，1=4bit，2=8bit, 3=16bit
													|CTRLR0_WAIT_CYCLES_VALUE(waitCycles)      		//dummy_clock max=31 
													|CTRLR0_CLK_STRETCH_EN_MASK );
	if(Flash_Type==1)	SSIx->SSI_SPI_CTRLR0|=CTRLR0_ADDR_L_VALUE(0x08);     // 4 Byte addr
	else   					  SSIx->SSI_SPI_CTRLR0|=CTRLR0_ADDR_L_VALUE(0x06);     // 3 Byte addr     //addr_len= n*4 bit ( max_n=15)
	
	SSIx->SSI_TXFTLR = 0x00010000;
	SSIx->SSI_RXFTLR = 0x7;
//	SSIx->SSI_RXFTLR = 0x15;
	if(QUAD_BAUDR==0x02&&g_sys_clk>=80000000)//high speed
	{
	 SSIx->SSI_RX_SAMPLE_DELAY=0x00010001;
	}
	SSIx->SSI_IMR = 0x00;
	SSIx->SSI_DMACR = 0;          //dma
	SSIx->SSI_SSIENR = 0x01;
	//----------------- END -----------------------------------------------------
	#else
	//-----------------QUAL MODE---------------------------
	//----------------- END -----------------------------------------------------
	#endif
}

void NorFlash_DMA_Read(UINT8* buf, UINT32 addr, UINT32 length)
{
	//-----------------DUAL MODE---------------------------
	#if 1
	SSI_TypeDef *SSIx=SSI1;
	
	//NorFlash_DMA_Read_Init(2,8,num);
	//DMA_REG_Init(DMA2_BASE_ADDR);
	SSIx->SSI_SSIENR = 0x00;	 
	SSIx->SSI_BAUDR =  QUAD_BAUDR;
	SSIx->SSI_CTRLR1 = ((length == 0)?0:(length-1));
	SSIx->SSI_CTRLR0 = 07;
	SSIx->SSI_SPI_CTRLR0 = 0;
	SSIx->SSI_CTRLR0 |= (CTRLR0_SPI_FRF_DUAL|CTRLR0_FRF_MOT|CTRLR0_DFS_VALUE(0x07)|CTRLR0_TMOD_RX_ONLY);
	SSIx->SSI_SPI_CTRLR0|= ( CTRLR0_TRANS_TYPE_TT0  |CTRLR0_INST_L_VALUE(2)               		//CMD_Len: 0=0bit，1=4bit，2=8bit, 3=16bit
													|CTRLR0_WAIT_CYCLES_VALUE(8)      		//dummy_clock max=31 
													|CTRLR0_CLK_STRETCH_EN_MASK );
	if(Flash_Type==1)	SSIx->SSI_SPI_CTRLR0|=CTRLR0_ADDR_L_VALUE(0x08);     // 4 Byte addr
	else   						SSIx->SSI_SPI_CTRLR0|=CTRLR0_ADDR_L_VALUE(0x06);     // 3 Byte addr     //addr_len= n*4 bit ( max_n=15)
	SSIx->SSI_TXFTLR = 0x00010000;
	SSIx->SSI_RXFTLR = 0x7;	
	if(QUAD_BAUDR==0x02&&g_sys_clk>=80000000)//high speed
	{
	 SSIx->SSI_RX_SAMPLE_DELAY=0x00010001;
	}
	SSIx->SSI_IMR = 0x00;
	SSIx->SSI_SSIENR = 0x01;

	DelayUS(1);
		
	//DMA_Rx
	exFlash_dma_control->DMA_CONFIG = 1;
	
	exFlash_dma_channel[exFlash_CHNUM]->DMA_SADDR = (UINT32)&SSIx->SSI_DR;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_DADDR = (UINT32)buf;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL = DIEC|SNOCHG|P2M_DMA|DWIDTH_B|SWIDTH_B;       // 1x8 bits
//	exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL = DIEC|SNOCHG|P2M_DMA|DWIDTH_HW|SWIDTH_HW;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL_HIGH = length ;  //最大长度为0x0FFF
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CFG = (HS_SEL_SRC_HARD)|(HS_SEL_DST_SOFT);//|(CH_PRIOR1);
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CFG_HIGH = exFlash_SRC_RX;
	//enable dma channel
	exFlash_dma_control->DMA_CHEN |= CHANNEL_WRITE_ENABLE(exFlash_CHNUM)|CHANNEL_ENABLE(exFlash_CHNUM);

	SSIx->SSI_DR = W25X_FastReadDual;
	SSIx->SSI_DR = addr;
	SSIx->SSI_DMACR = DMACR_RDMAE;	 
	//----------------- END -----------------------------------------------------
	#else
	//-----------------QUAL MODE-----------------------------
	//----------------- END -----------------------------------------------------
	#endif
}

void NorFlash_DMA_Wait(void)
{
	SSI_TypeDef *SSIx=SSI1;
	while(exFlash_dma_control->DMA_CHEN & CHANNEL_STAT(exFlash_CHNUM))  {  ; }	
	exFlash_dma_control->DMA_CHEN &=~(CHANNEL_WRITE_ENABLE(exFlash_CHNUM)|CHANNEL_ENABLE(exFlash_CHNUM));
//	exFlash_dma_channel[0]->DMA_CFG &= ~(1<<8);
	//exFlash_dma_control->DMA_CONFIG = 0;				//wav 和 picture 同一DMA,不禁用 	
	SSIx->SSI_DMACR = 0;
}