/*
* 文件名：w25N01.c
* 功能  ：驱动LT268外挂的W25n01系列的FLASH
* 接口  ：SSI
* 作者  ：LEVETOP
*/

#include "w25N01.h"
#include "sys.h"
#include "ssi_drv.h"
#include "dmac_drv.h"
#include "delay.h"
#include "trans_port.h"



// 3个状态寄存器
// 保护寄存器1：地址0xA0
// 配置寄存器2: 地址0xB0
// 状态寄存器3: 地址0xC0  (只读寄存器)
UINT8 LT_W25N01GV_ReadSR(UINT8 reg)
{
	UINT8 byte = 0;
	volatile unsigned char status;
	volatile unsigned char temp;
	
	SSI_TypeDef *SSIx=SSI1;
	
	SSIx->SSI_DR = W25N01GV_ReadStatusReg;
	SSIx->SSI_DR = reg;
	SSIx->SSI_DR = 0xFF;

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

	while((SSIx->SSI_SR&SR_TFE)==0x00){;}			
	while(SSIx->SSI_SR&SR_BUSY){;}
		
	temp = SSIx->SSI_DR;//清空fifo
	temp = SSIx->SSI_DR;//清空fifo
	byte = SSIx->SSI_DR;//清空fifo		
		
	return byte;
}

// 3个状态寄存器
// 保护寄存器1：地址0xA0
// 配置寄存器2: 地址0xB0
// 状态寄存器3: 地址0xC0  (只读寄存器)
void LT_W25N01GV_Write_SR(UINT8 reg, UINT8 val)
{
	volatile unsigned char status;
	volatile unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	LT_W25N01GV_Write_Enable();
		
	SSIx->SSI_DR = W25N01GV_WriteStatusReg;
	SSIx->SSI_DR = reg;
	SSIx->SSI_DR = val;

	__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
	}	
	
	LT_W25N01GV_Wait_Busy(); 
}

/*
* 函数名：LT_W25qxx_Wait_Busy
* 功能  ：等待W25qxx忙
* 输入  ：无
* 输出  ：无
* 作者  ：LEVETOP
*/
void LT_W25N01GV_Wait_Busy(void)   
{   
	while((LT_W25N01GV_ReadSR(W25N01GV_SR3)&0x01)==0x01);  		// 等待BUSY位清空
} 

/*
* 函数名：LT_W25qxx_Write_Enable
* 功能  ：W25qxx写使能
* 输入  ：无
* 输出  ：无
* 作者  ：LEVETOP
*/
void LT_W25N01GV_Write_Enable(void)   
{
	volatile unsigned char status;
	volatile unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	SSIx->SSI_DR = W25N01GV_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
	}	

	LT_W25N01GV_Wait_Busy(); 	
} 

/*
* 函数名：LT_W25QXX_Write_Disable
* 功能  ：禁止写W25qxx
* 输入  ：无
* 输出  ：无
* 作者  ：LEVETOP
*/
void LT_W25N01GV_Write_Disable(void)   
{
	volatile unsigned char status;
	volatile unsigned char temp;
	SSI_TypeDef *SSIx=SSI1;
	
	SSIx->SSI_DR = W25N01GV_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
	}	
		
}

//配置 BUF=0 、 ECC-E=1   连续读模式
void W25N01GV_ContinuousRead_Mode(void)
{
	UINT8 statut = 0;
	statut = LT_W25N01GV_ReadSR(W25N01GV_SR2);
	statut &= 0xe7;
	statut |= 0x10;
	LT_W25N01GV_Write_SR(W25N01GV_SR2,statut);
}

//配置 BUF=1 、 ECC-E=1    页读模式
void W25N01GV_BufferRead_Mode(void)
{
	UINT8 statut = 0;
	statut = LT_W25N01GV_ReadSR(W25N01GV_SR2);
	statut |= 0x08;
	statut |= 0x10;
	LT_W25N01GV_Write_SR(W25N01GV_SR2,statut);      
}

/*
* 函数名：LT_W25qxx_ReadID
* 功能  ：读取W25qxxID
* 输入  ：无
* 输出  ：W25qxxID

* W25nxx系列的ID号如下：

* 作者  ：LEVETOP
*/
UINT32 LT_W25N01GV_ReadID(void)
{
	UINT32 Device_ID = 0;

	SSI_TypeDef *SSI_1=SSI1;
	
	SSI_1->SSI_DR = W25N01GV_ID;
	SSI_1->SSI_DR = 0xff;
	
	SSI_1->SSI_DR = 0xff;           
	SSI_1->SSI_DR = 0xff;
	SSI_1->SSI_DR = 0xff;

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

	while((SSI_1->SSI_SR&SR_TFE)!=SR_TFE){;}
	while(SSI_1->SSI_SR&SR_BUSY){;}
 
	Device_ID = SSI_1->SSI_DR;             //对齐    
	Device_ID = SSI_1->SSI_DR;
		
	Device_ID = SSI_1->SSI_DR;
	Device_ID = (Device_ID<<8)&0xFF00;
	Device_ID |= SSI_1->SSI_DR;
	Device_ID = (Device_ID<<8)&0xFFFF00;
	Device_ID |= SSI_1->SSI_DR;
		
	return Device_ID;

}

//Init
void W25N01GV_Init(void)
{
	W25N01GV_BufferRead_Mode();             //缓冲读模式
	LT_W25N01GV_PageDataRead(0);					  //缓冲page 0 数据
	DelayUS(50);
	Nand_page=0;
}

/*
* 函数名：LT_W25N01GV_BlockErase128KB
* 功能  ：擦除一个扇区（擦除一个扇区的最少时间:150ms）
* 输入  ：Dst_Addr:扇区地址 根据实际容量设置
* 输出  ：无
* 作者  ：LEVETOP
*/
void LT_W25N01GV_BlockErase128KB(UINT32 addr)   
{
	UINT8 temp=0;
	UINT16 Page = (addr/2048);

	SSI_TypeDef *SSIx=SSI1;
	
	LT_W25N01GV_Write_SR(W25N01GV_SR1, 0x00);
	LT_W25N01GV_Write_Enable();
	LT_W25N01GV_Wait_Busy(); 

	SSIx->SSI_DR = W25N01GV_128KBlockErase;
	SSIx->SSI_DR = 0xff;
	SSIx->SSI_DR = (UINT8)((Page)>>8);        
	SSIx->SSI_DR = (UINT8)Page;

	__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)
	{
		temp=SSIx->SSI_DR;//清空fifo
	}			
		
	LT_W25N01GV_Wait_Busy();
	LT_W25N01GV_Write_SR(W25N01GV_SR1,0x7C);
} 

/*缓冲一页数据，等待主机读取*/
void LT_W25N01GV_PageDataRead(UINT32 PageNum)
{
	volatile unsigned char rdByte;
	int txnum,rxnum;
	SSI_TypeDef *SSIx=SSI1;

	SSIx->SSI_DR = W25N01GV_PageDataRead;
	SSIx->SSI_DR = 0x00;	//Dummy
	SSIx->SSI_DR = (UINT8)((PageNum>>8)&0xFF);       //页地址
	SSIx->SSI_DR = (UINT8)(PageNum&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)
	{
		rdByte=SSIx->SSI_DR;//清空fifo
	}	
		
    LT_W25N01GV_Wait_Busy();
}

void LT_W25N01GV_Read(UINT8* pBuffer,UINT32 ReadAddr,UINT16 NumByteToRead)
{
	volatile unsigned char temp;
	int i=0,j=0;
	int txnum;
	SSI_TypeDef *SSIx=SSI1;

	txnum=NumByteToRead;
	SSIx->SSI_DR = W25N01GV_ReadData;
	SSIx->SSI_DR = (UINT8)(ReadAddr>>8)&0xff;
	SSIx->SSI_DR = (UINT8)(ReadAddr>>0)&0xff;
	SSIx->SSI_DR =  0xff;	//DUMMY
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	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){;}

} 

void Nand_LT_W25N01GV_DMA_PageRead(SSI_TypeDef *SSIx,UINT8* pread,UINT32 length)
{
	unsigned char status;
	int num2;
	
	exFlash_dma_control->DMA_CONFIG = 1;
	//Rx
	exFlash_dma_channel[exFlash_CHNUM]->DMA_SADDR = (UINT32)&SSIx->SSI_DR;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_DADDR = (UINT32)pread;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL  = DIEC|SNOCHG|P2M_DMA|DWIDTH_B|SWIDTH_B;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL_HIGH = length+4 ;  //最大长度为0x0FFF
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CFG = (HS_SEL_SRC_HARD);
	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));
	//printf("1m_dma_control->DMA_RAWTFR: 0x%08x\r\n", exFlash_dma_control->DMA_RAWTFR);
	

	num2=length;
	//Nand_LT_W25N01GV_DMA_Read_Trig(SSIx);//SSI_STD_DMA_Trig(SSIx, READ_CMD, addr, DMACR_RDMAE);
	SSIx->SSI_DR = W25N01GV_ReadData;        
	SSIx->SSI_DR = 0x00;
	SSIx->SSI_DR = 0x00;
	SSIx->SSI_DR = 0xFF;
	SSIx->SSI_DMACR = DMACR_RDMAE;
	
	while(num2)
	{	
		while( (SSIx->SSI_SR&SR_TFNF)&&(num2>0) )
		{	
			  SSIx->SSI_DR = DUMMY_BYTE;
			  num2--;	
			  while(0);
		}
	}		 
 	 
	while(SSIx->SSI_SR&SR_BUSY){;}
	 

//	while((exFlash_dma_control->DMA_RAWTFR & CHANNEL_STAT(exFlash_CHNUM)) != CHANNEL_STAT(exFlash_CHNUM));    		
//	exFlash_dma_control->DMA_CLRTFR =  exFlash_dma_control->DMA_STATTFR;	 

	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_control->DMA_CHEN = 0;
//	exFlash_dma_control->DMA_CONFIG = 0;
	SSIx->SSI_DMACR = 0;
	
}	

//--------------------------------------------------写---------------------------

void LT_W25N01GV_STD_DMA_Send(SSI_TypeDef *SSIx,UINT8* psend,UINT16 Column,UINT32 length)
{

	exFlash_dma_control->DMA_CONFIG = 1;
	//Tx
	exFlash_dma_channel[exFlash_CHNUM]->DMA_SADDR = (UINT32)psend;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_DADDR = (UINT32)&SSIx->SSI_DR;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL = DNOCHG|SIEC|M2P_DMA|DWIDTH_B|SWIDTH_B|SBSIZE_4|DBSIZE_4;
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL_HIGH = length ;  //最大长度为0x0FFF
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CFG = (HS_SEL_DST_HARD);
	exFlash_dma_channel[exFlash_CHNUM]->DMA_CFG_HIGH = exFlash_DST_TX;
	exFlash_dma_control->DMA_CHEN |= (CHANNEL_WRITE_ENABLE(exFlash_CHNUM)|CHANNEL_ENABLE(exFlash_CHNUM));
	
	//Nand_SSI_STD_DMA_Trig(SSIx, W25N01GV_LoadProgramData,DMACR_TDMAE);
	SSIx->SSI_DR = W25N01GV_LoadProgramData;
	SSIx->SSI_DR = Column>>8;
	SSIx->SSI_DR = Column;
	SSIx->SSI_DMACR = DMACR_TDMAE;	
	
//	while((exFlash_dma_control->DMA_RAWTFR & CHANNEL_STAT(exFlash_CHNUM)));
//	exFlash_dma_control->DMA_CLRTFR =  exFlash_dma_control->DMA_STATTFR;
	//printf("2m_dma_control->DMA_RAWTFR: 0x%08x\r\n", exFlash_dma_control->DMA_RAWTFR);
	
	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_control->DMA_CONFIG = 0;
	SSIx->SSI_DMACR = 0;
}

/*
* 函数名：LT_W25QXX_Write_Page
* 功能  ：在指定地址开始写入最大256字节的数据
* 输入  ：pBuffer:数据存储区
*         WriteAddr:开始写入的地址(24bit)
*         NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数
* 输出  ：无
* 作者  ：LEVETOP
*/
void LT_W25N01GV_Write_Page(UINT8* pBuffer,UINT16 page,UINT16 column,UINT16 NumByteToWrite)
{
 	UINT8  reV;

	SSI_TypeDef *SSIx=SSI1;
	
	SSI1_STD_Init(SSI1);

 	LT_W25N01GV_Write_SR(W25N01GV_SR1, 0x00);      // 关flash保护功能      
   LT_W25N01GV_Write_Enable();				//写入使能

	//DMA_REG_Init(DMA2_BASE_ADDR);
	LT_W25N01GV_STD_DMA_Send(SSIx,pBuffer,column,NumByteToWrite);
	
	SSI1_STD_Init(SSI1); 
	
  LT_W25N01GV_Wait_Busy();
	
	SSIx->SSI_DR = W25N01GV_ProgramExecute;
	SSIx->SSI_DR = 0xff;
	SSIx->SSI_DR = (UINT8)((page)>>8);
	SSIx->SSI_DR = (UINT8)page;

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

	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}
	while(SSIx->SSI_SR&SR_BUSY){;}
	
	reV = SSIx->SSI_DR;
	reV = SSIx->SSI_DR;
	reV = SSIx->SSI_DR;
	reV = SSIx->SSI_DR;
      
	LT_W25N01GV_Wait_Busy();
  LT_W25N01GV_Write_SR(W25N01GV_SR1, 0x7C);      // 开flash保护功能
}

/*
* 函数名：LT_W25qxx_Write
* 功能  ：无检验写SPI FLASH
*         必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败
*         具有自动换页功能 
* 输入  ：pBuffer:数据存储区
*         WriteAddr:开始写入的地址(24bit)
*         NumByteToWrite:要写入的字节数(最大65535)
* 输出  ：无
* 作者  ：LEVETOP
*/
void LT_W25N01GV_Write(UINT8* pBuffer,UINT32 WriteAddr,UINT16 NumByteToWrite)
{
 	UINT16 page,column,endpage;
	UINT16 pageremain;
	
	if(NumByteToWrite==0) return;

	page = WriteAddr/2048;
	column = WriteAddr%2048;
	pageremain=2048-column;


	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;
	while(1)
	{	   
		LT_W25N01GV_Write_Page(pBuffer,page,column,pageremain);
		if(NumByteToWrite==pageremain)break;
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;	
			page++;
			column=0;
			
			NumByteToWrite-=pageremain;			 
			if(NumByteToWrite>2048)pageremain=2048;
			else pageremain=NumByteToWrite; 	  
		}
	}
} 



/* NandFlash Dual_Read_Model*/
void NandFlash_Read_Init(UINT8 command_num,UINT8 addr_bits_num, UINT8 waitCycles, UINT32 data_len)
{
	//-----------------DUAL MODE-----------------------------------------------------
	SSI_TypeDef *SSIx=SSI1;
	#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_TT1  |CTRLR0_INST_L_VALUE(command_num)        //CMD_Len: 0=0bit，1=4bit，2=8bit, 3=16bit
													|CTRLR0_ADDR_L_VALUE(addr_bits_num)      //ADDR_Len: n*4 bit   ( max_n=15)
													|CTRLR0_WAIT_CYCLES_VALUE(waitCycles)    //dummy_clock: max=31 
													|CTRLR0_CLK_STRETCH_EN_MASK);
	
	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 NandFlash_Read(u16 page, u16 column, UINT8 *buf, UINT32 num)             
{
	int i=0;
	
	SSI_TypeDef *SSIx=SSI1; 
	
	SSI1_STD_Init(SSI1); 
	DelayUS(1);
	if(page!=Nand_page)
	{
		LT_W25N01GV_PageDataRead(page);     //page addr
		Nand_page=page;
		//DelayUS(50);      //50us
	}
	
//	NandFlash_Read_Init(2,4,4,num);
	#if 1
	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);//|
//						 CTRLR0_SSTE_MASK(0)|CTRLR0_SCPOL_MASK(0)|CTRLR0_SCPH_MASK(0));
	SSIx->SSI_SPI_CTRLR0|= ( CTRLR0_TRANS_TYPE_TT1  |CTRLR0_INST_L_VALUE(2)        //CMD_Len: 0=0bit，1=4bit，2=8bit, 3=16bit
													|CTRLR0_ADDR_L_VALUE(4)      //ADDR_Len: n*4 bit   ( max_n=15)
													|CTRLR0_WAIT_CYCLES_VALUE(4)    //dummy_clock: max=31 
													|CTRLR0_CLK_STRETCH_EN_MASK);
	
	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
	
	#endif
	
	DelayUS(1);																	//need after Init							

	SSIx->SSI_DR = W25N01GV_FastReadDualIO;	
	SSIx->SSI_DR = column;	            						//column
	
	__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) )
	{
		if(SSIx->SSI_SR&SR_RFNE)
		{
				*(buf+i)=SSIx->SSI_DR;
				i++;
				num--;
		}	
	}	
	DelayUS(50);

}

/* NandFlash DMA_Read_Model*/
void NandFlash_DMA_Read_Init(UINT8 command_num,UINT8 addr_bits_num, UINT8 waitCycles,UINT32 data_len)
{
	//-----------------DUAL MODE----------
	SSI_TypeDef *SSIx=SSI1;
	#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_TT1  |CTRLR0_INST_L_VALUE(command_num)        //CMD_Len: 0=0bit，1=4bit，2=8bit, 3=16bit
													|CTRLR0_ADDR_L_VALUE(addr_bits_num)      //ADDR_Len: n*4 bit   ( max_n=15)
													|CTRLR0_WAIT_CYCLES_VALUE(waitCycles)    //dummy_clock: max=31 
													|CTRLR0_CLK_STRETCH_EN_MASK);
	
	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-------
	while(SSIx->SSI_SR&SR_BUSY){;}
	
	 SSIx->SSI_SSIENR = 0x00;
		
	 SSIx->SSI_CTRLR1 = ((num == 0)?0:(num-1));
	 SSIx->SSI_BAUDR =  0x02;

//	    SSIx->SSI_CTRLR0 = 0x00800807;
	SSIx->SSI_CTRLR0 =(CTRLR0_SPI_FRF_QUAD|CTRLR0_FRF_MOT|CTRLR0_DFS_VALUE(7)|CTRLR0_TMOD_RX_ONLY|
					   CTRLR0_SSTE_MASK(0)|CTRLR0_SCPOL_MASK(0)|CTRLR0_SCPH_MASK(0));
	
//    SSIx->SSI_SPI_CTRLR0 =  0x40000218|(waitCycles<<11);
    SSIx->SSI_SPI_CTRLR0 = CTRLR0_CLK_STRETCH_EN_MASK|                                     //时钟拓展（发送时必要）
						   CTRLR0_TRANS_TYPE_TT0|
						   CTRLR0_INST_L_VALUE(command_num)|
						   CTRLR0_ADDR_L_VALUE(addr_bits_num)|
						   CTRLR0_WAIT_CYCLES_VALUE(waitCycles);
	
//	    SSIx->SSI_TXFTLR = 0x00010000;
//		SSIx->SSI_RXFTLR = 0x07;
	SSIx->SSI_TXFTLR = TXFTLR_TFT(0)|TXFTLR_TXFTHR(1);
	SSIx->SSI_RXFTLR = RXFTLR_TFT(7);	  

//	if( SSIx->SSI_BAUDR==0x02&&g_sys_clk>=80000000)//high speed
	{
//	 SSIx->SSI_RX_SAMPLE_DELAY=0x00010001;
	 SSIx->SSI_RX_SAMPLE_DELAY=RXSDR_SE(1)|RXSDR_RSD(1);
	}

	SSIx->SSI_IMR = 0x00;
	SSIx->SSI_SSIENR = 0x01;
	//----------------- END -----------------------------------------------------
	#endif
}

void NandFlash_DMA_Read(UINT16 page,UINT16 column,UINT8* buff,UINT16 data_len)
{
	SSI_TypeDef *SSIx=SSI1;

	//-----------------DUAL MODE-----------------------------------------------------
	#if 1
		SSI1_STD_Init(SSI1); 				//ssi单线
		//DelayUS(1);	
		if(page!=Nand_page)
		{
			LT_W25N01GV_PageDataRead(page);
			Nand_page=page;
			//DelayUS(50);      //50us
		}
		
		//Init
//		NandFlash_DMA_Read_Init(data_len,2,4,4);  
		//DMA_REG_Init(DMA2_BASE_ADDR);
		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_TT1  |CTRLR0_INST_L_VALUE(2)        //CMD_Len: 0=0bit，1=4bit，2=8bit, 3=16bit
														|CTRLR0_ADDR_L_VALUE(4)      	//ADDR_Len: n*4 bit   ( max_n=15)
														|CTRLR0_WAIT_CYCLES_VALUE(4)    //dummy_clock: max=31 
														|CTRLR0_CLK_STRETCH_EN_MASK);
		
		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);																	//need after Init							
	
		//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)buff;
		exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL = DIEC|SNOCHG|P2M_DMA|DWIDTH_B|SWIDTH_B;
		exFlash_dma_channel[exFlash_CHNUM]->DMA_CTRL_HIGH = data_len;  //max_len: 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);
		
		exFlash_dma_control->DMA_CHEN |= CHANNEL_WRITE_ENABLE(exFlash_CHNUM)|CHANNEL_ENABLE(exFlash_CHNUM);   //enable dma channel
		//printf("1m_dma_control->DMA_RAWTFR: 0x%08x\r\n", exFlash_dma_control->DMA_RAWTFR);

		#if 1
		SSIx->SSI_DR=W25N01GV_FastReadDualIO;
		SSIx->SSI_DR=column;	            										//column
		#else
		SSIx->SSI_DR=((0x1300<<16)|(page));
		SSIx->SSI_DR=((0x3b<<16)|(column));
		#endif
		
		SSIx->SSI_DMACR=DMACR_RDMAE;
	//----------------- END -----------------------------------------------------
	#else
	//-----------------QUAL MODE-----------------------------------------------------
	//----------------- END -----------------------------------------------------
	#endif
}

void NandFlash_DMA_Wait(void)
{
	SSI_TypeDef *SSIx=SSI1;
//	while((exFlash_dma_control->DMA_RAWTFR & CHANNEL_STAT(0)) != CHANNEL_STAT(0));    		
//	exFlash_dma_control->DMA_CLRTFR =  exFlash_dma_control->DMA_STATTFR;
	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_control->DMA_CONFIG = 0;                 //wav 和 picture 同一DMA,不禁用 
	SSIx->SSI_DMACR = 0;

}



//------------------ TEST ---------------------------------------------
	/*
	NandFlash_DMA_Read( 0,0 , DMA_rxbuf1,2048);
	NandFlash_DMA_Wait();
	printf("DMA_rxbuf1 \r\n" );
	for(i=0;i<2048/16;i++)
	{
		for(j=0;j<16;j++)printf(" %x ",DMA_rxbuf1[i*16+j]);
		printf("\r\n" );
	}
		for(j=0;j<16;j++)printf(" %x ",DMA_rxbuf1[i*16+j]);
	
	NandFlash_DMA_Read( 1,0 ,DMA_rxbuf1, 2048);
	NandFlash_DMA_Wait();
	printf("DMA_rxbuf1 \r\n" );
	for(i=0;i<2048/16;i++)
	{
		for(j=0;j<16;j++)printf(" %x ",DMA_rxbuf1[i*16+j]);
		printf("\r\n" );
	}
		for(j=0;j<16;j++)printf(" %x ",DMA_rxbuf1[i*16+j]);
	*/
	//-------------------------