#include <string.h>
#include "spi_drv.h"
#include "dmac_drv.h"
#include "eport_drv.h"
#include "ssi_drv.h"
#include "delay.h"

#include "Flash_drv.h"

u8 Flash_Type = 0;  	//用于判断 是NorFlash(0) 或者 NANDFlash(1)
u16 BlockQty = 1024;		// Minimum block size
u32 Flash_ID = 0;

u8 MUC_SS_flag = 1; 		//记录当前MCU这边的SD卡片选脚

u8 wrBuff[4*1024];

UINT16  NandPage = 0;
extern u32 g_sys_clk;
// =========================================================================
//
// LT269 use SSI1 for Flash port
//
SSI_TypeDef *SSIx=SSI1;

void FlashPort_Init(void)
{
	while(SSIx->SSI_SR&SR_BUSY){;}

	SSIx->SSI_SSIENR = 0x00;
	SSIx->SSI_CTRLR1 = 0x00;
	SSIx->SSI_CTRLR0 = 0x07;
	SSIx->SSI_BAUDR  = 0x0C;	// 0x0c
	SSIx->SSI_TXFTLR = 0x00;
	SSIx->SSI_RXFTLR = 0x00;
	SSIx->SSI_SPI_CTRLR0 = 0x8000;
	SSIx->SSI_IMR = 0x00;
	SSIx->SSI_SSIENR = 0x01;
}

#define DST_SSI1_TX   		(0x3<<11)

void NORFlash_DMASend(UINT32 addr,UINT8* psend,UINT32 length)
{
   int num;
	
	int dma_ch=0; 
	
	m_dma2_control->DMA_CONFIG = 1;
	//Tx
	m_dma2_channel[dma_ch]->DMA_SADDR = (UINT32)psend;
	m_dma2_channel[dma_ch]->DMA_DADDR = (UINT32)&SSIx->SSI_DR;

	m_dma2_channel[dma_ch]->DMA_CTRL = DNOCHG|SIEC|M2P_DMA|DWIDTH_B|SWIDTH_B|SBSIZE_4|DBSIZE_4;

	m_dma2_channel[dma_ch]->DMA_CTRL_HIGH = length ;  //最大长度为0x0FFF
	m_dma2_channel[dma_ch]->DMA_CFG = (HS_SEL_DST_HARD);
	if(SSIx == SSI1)
	{
		m_dma2_channel[dma_ch]->DMA_CFG_HIGH = DST_PER_SPI_TX(3);
	}
	else if(SSIx == SSI2)
	{
		m_dma2_channel[dma_ch]->DMA_CFG_HIGH = DST_PER_SPI_TX(2);
	}
    else
    {
        printf("unknown SSIx\r\n");
    }
	//enable dma channel

	m_dma2_control->DMA_CHEN = (CHANNEL_WRITE_ENABLE(dma_ch)|CHANNEL_ENABLE(dma_ch));
	//printf("1m_dma2_control->DMA_RAWTFR: 0x%08x\r\n", m_dma2_control->DMA_RAWTFR);
	
	SSI_STD_DMA_Trig(SSIx, PAGE_PROG_CMD, addr, DMACR_TDMAE);
	
	// bug here it will cause data write error
/*
	num=length;
	while(num)
	{
		if( (SSIx->SSI_SR&SR_TFNF)&&(num>0) )
		{	
			SSIx->SSI_DR=DUMMY_BYTE;
			num--;	
			while(0);
		}
	}
*/ 
	 
	while(SSIx->SSI_SR&SR_BUSY){}

	while((m_dma2_control->DMA_RAWTFR & CHANNEL_STAT(dma_ch)) != CHANNEL_STAT(dma_ch)){ }    		
	m_dma2_control->DMA_CLRTFR =  m_dma2_control->DMA_STATTFR;

	while(m_dma2_control->DMA_CHEN & CHANNEL_STAT(dma_ch)){}
	m_dma2_control->DMA_CHEN = 0;
//  m_dma2_control->DMA_CONFIG = 0;
		  
	SSIx->SSI_DMACR = 0;	
	// 2023/10/20: Bert removed. why this?			
	FlashPort_Init();
}

// Okay
static u8 SSI_WaitReady(void)
{
	u8 retVal;
	__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);
}	

static void SSI_WaitTXFIFOEmpty(void)
{
	u8 retVal;
	__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) retVal=SSIx->SSI_DR;
}


// =========================================================================


/*********************** Winbond NOR Flash ***********************/

//Status register器
//BIT7  6   5   4   3   2   1   0
//SPR   RV  TB BP2 BP1 BP0 WEL BUSY
//SPR: Default 0x00: Flash write protect
//TB,BP2,BP1,BP0:For FLASH Write Protection
//WEL:Lock 
//BUSY =1: Bysy; 0: Idle
// OKay
static u8 NORFlash_ReadSR(u8 reg)   
{
	uint8_t retVal=0; 
	
	SSIx->SSI_DR = reg;
	SSIx->SSI_DR = 0xff;
	return (SSI_WaitReady()); 
}

// Okay
static void NORFlash_WaitBusy(void)   		
{	
	while((NORFlash_ReadSR(W25X_RERADSTATUSREG)&0x01));  		
}

// Okay
static void NORFlash_WriteEnable(void)   
{	
	FlashPort_Init();
	
	if((NORFlash_ReadSR(W25X_RERADSTATUSREG)&0x02) == 0)
	{
		SSIx->SSI_DR=W25X_WRITEENABLE;
		SSI_WaitTXFIFOEmpty();	
		
		NORFlash_WaitBusy();
	} 
	FlashPort_Init();	
}

// Okay
static void NORFlash_WriteEnable_Volatile(void)   
{  
 	volatile unsigned char temp;
	
	SSIx->SSI_DR=W25X_WRITEENABLE_VSR;
	
	SSI_WaitTXFIFOEmpty();
	
	NORFlash_WaitBusy();                         	      
}

static uint8_t NORFlash_WriteSR(unsigned char Reg, unsigned char val)   
{  
	volatile unsigned char retVal;
	
	NORFlash_WriteEnable_Volatile();
		
	SSIx->SSI_DR=Reg;
	SSIx->SSI_DR=val;
	
	retVal=SSI_WaitReady();
	
	NORFlash_WaitBusy();
	return(retVal);
}

// Okay
static void NORFlash_WriteDisable(void)
{
	volatile unsigned char temp;
	
	if((NORFlash_ReadSR(W25X_RERADSTATUSREG)&0x02) == 0x02)
	{
		SSIx->SSI_DR=W25X_WRITEDISABLE;
		
		SSI_WaitTXFIFOEmpty();
			
		NORFlash_WaitBusy();
	}	
}

// Okay
static UINT8 NORFlash_QEEnable(void)
{
	UINT8 temp=0;

	volatile unsigned char retVal;
	
	//开启双线四线模式
	temp=NORFlash_ReadSR(W25X_RERADSTATUSREG2);   								//SET QE 
	if(!(temp&0x02))
	{
		NORFlash_WriteEnable_Volatile();  //W25QXX_Write_Enable();
			
		retVal=NORFlash_WriteSR(W25X_WRITESTATUSREG2,temp|0x02);

		NORFlash_WaitBusy();
	}
	return(retVal);
}

/*----------------------------------------------------
* Description    : For some flashes with 4 byte address  
* Input          : None
* Output         : None
* Return         : None
-----------------------------------------------------*/
// Okay
static void NORFlash_Enter4ByteAddressMode(void)
{
	unsigned char temp;
	temp = 0x00;
	SSIx->SSI_DR = W25X_ENTER4BYTEADDRMODE;  //进入

	__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
}

static void NORFlash_Init(void)
{
	if(Flash_ID==0xEF18||Flash_ID==0xC818||Flash_ID==0x0B16)  //256M flash
	{
		//Flash_Type=NOR_FLASH; 
		NORFlash_Enter4ByteAddressMode();
	}
	NORFlash_QEEnable();       			//QE
}

// Okay
u32 NORFlash_ReadID(void)
{
	int i;
	volatile unsigned short Device_ID;
	
	FlashPort_Init();
	
	SSIx->SSI_DR=W25X_MANUFACTUREDEVICEID;
	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;
}

u32 NORFlash_ReadID_9F(void)
{
	int i;
	volatile unsigned Device_ID;
		
	SSIx->SSI_DR=W25X_JEDECID;
	SSIx->SSI_DR = 0x00;
	SSIx->SSI_DR = 0x00;
	SSIx->SSI_DR = 0x00;

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

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

	for(i=0; i<1; i++)
	{
		Device_ID = SSIx->SSI_DR;
	}
	Device_ID=0;
	Device_ID |= (SSIx->SSI_DR<<16);
	Device_ID |= (SSIx->SSI_DR<<8);
	Device_ID |= (SSIx->SSI_DR);
	
	return Device_ID;

}


/*----------------------------------------------------
* Description    : Erase a single sector (4KB/sector)
* Input          : Sector number
* Output         : None
* Return         : None
----------------------------------------------------*/
// Okay
void NORFlash_EraseSector(u32 sector)
{
	u32 addr;
	addr=sector*NORFLASH_SECTORSIZE; // 1sector=4096B;
	
	NORFlash_WriteEnable();                 	 	  //SET WEL 
	NORFlash_WaitBusy();
	
	SSIx->SSI_DR = W25X_SECTORERASE;
	
	if (Flash_Type==NOR_FLASH_W25Q256)
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送32bit块地址		
	SSIx->SSI_DR = (addr>>16)&0xFF;
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR = (addr)&0xFF;
	
	SSI_WaitTXFIFOEmpty();

	NORFlash_WaitBusy();
}

/*----------------------------------------------------
* Description    : Erase a single block (64KB/block)
* Input          : Block number
* Output         : None
* Return         : None
----------------------------------------------------*/

// okay
void NORFlash_EraseBlock(u32 block)
{
	u32 addr;
	addr=block*NORFLASH_BLCOKSIZE;	// 1block=65536B
	
	NORFlash_WriteEnable();                 	 	  //SET WEL 
	NORFlash_WaitBusy();

	SSIx->SSI_DR = W25X_BLOCKERASE;   //W25X_64KBlockErase_4B; ----不兼
	
	if (Flash_Type==NOR_FLASH_W25Q256)
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送32bit块地址		
	SSIx->SSI_DR = (addr>>16)&0xFF;
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR = (addr)&0xFF;

	SSI_WaitTXFIFOEmpty();
	
	NORFlash_WaitBusy();
}

/*----------------------------------------------------
* Description    : Erase entire Flash block  
* Input          : None
* Output         : None
* Return         : None
----------------------------------------------------*/

// okay
void NORFlash_EraseChip(void)
{
	NORFlash_WriteEnable();                 	//SET WEL 
	
	SSIx->SSI_DR = W25X_CHIPERASE;
	
	SSI_WaitTXFIFOEmpty();

	NORFlash_WaitBusy();
}


void NORFlash_SetSSIHeader(u16 length)
{
	//NorFlash_Read_Init(2,8,num);
	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;
}

/*----------------------------------------------------
* Description    : Read a 8-bit data at addr  
* Input          : addr: Destination addr
* Output         : None
* Return         : 8-bit data
----------------------------------------------------*/
// Okay
u8 NORFlash_ReadByte(u32 addr)
{
	u8 data,i;
	
	NORFlash_SetSSIHeader(1);
	
	SSIx->SSI_DR =W25N_FASTREAD_DUAL;
	SSIx->SSI_DR=addr;
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}

	while(1)
	{   
		if(SSIx->SSI_SR&SR_RFNE)
		{
			data=SSIx->SSI_DR;
			break;
		}
	}	
	return(data);	
}

/*----------------------------------------------------
* Description    : Read Read a 16-bit data at addr  
* Input          : addr: Destination addr
* Output         : None
* Return         : 16-bit data
----------------------------------------------------*/
// Okay
u16 NORFlash_ReadHWord(u32 addr)
{
	u8 data[2],i,length;

	NORFlash_SetSSIHeader(2);
	
	SSIx->SSI_DR =W25N_FASTREAD_DUAL;
	
	SSIx->SSI_DR=addr;
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}	
		
	i=0;
	length=2;	
	while(length)
	{   
		if(SSIx->SSI_SR&SR_RFNE)
		{
			data[i++]=SSIx->SSI_DR;
			length--;
		}
	}
	
	return(*(u16 *) data);
}

/*----------------------------------------------------
* Description    : Read a 32-bit data from addr  
* Input          : addr: Destination addr
* Output         : None
* Return         : 32-bit data
----------------------------------------------------*/
// Okay
u32 NORFlash_ReadWord(u32 addr)
{
	u8 data[4],i,length;
	
	NORFlash_SetSSIHeader(4);
	
	SSIx->SSI_DR =W25N_FASTREAD_DUAL;
	SSIx->SSI_DR=addr;
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}
		
	i=0;
	length=4;	
	while( length)
	{   
		if(SSIx->SSI_SR&SR_RFNE)
		{
			data[i++]=SSIx->SSI_DR;
			length--;
		}
	}	

	return(*(u32 *) data);
}

/*----------------------------------------------------
* Description    : Read length bytes from addr  
* Input          : addr: Destination addr
*					  : buffer: buffer for read data
*					  : length: bytes to read
* Output         : data
* Return         : None
----------------------------------------------------*/
// Okay
void NORFlash_ReadBytes(u32 addr,u8* buffer,u16 length)
{
	u16 i;
	NORFlash_SetSSIHeader(length);
	
	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){;}
		
	i=0;	
	while( length>0)
	{   
		if(SSIx->SSI_SR&SR_RFNE)
		{
			*(buffer+i++)=SSIx->SSI_DR;
			length--;
		}
	}	
}

/*----------------------------------------------------
* Description    : Write a 8-bit data at addr  
* Input          : addr: destination addr
*                : data: 8-bit data
* Output         : data
* Return         : None
----------------------------------------------------*/
// Okay
void NORFlash_WriteByte(u32 addr,u8 data)
{	
	NORFlash_WriteEnable();
	
	//FlashPort_Init();
	
	SSIx->SSI_DR = W25X_PAGEPROGRAM;

	if (Flash_Type==NOR_FLASH_W25Q256)
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送32bit块地址		
	SSIx->SSI_DR = (addr>>16)&0xFF;
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR = (addr)&0xFF;
		
	SSIx->SSI_DR=data;
	
	//FlashPort_Init();
	while(SSIx->SSI_SR&SR_BUSY){;}
	NORFlash_WaitBusy();					   		
}

/*----------------------------------------------------
* Function Name  : NORFlash_WriteHWord
* Description    : Write a 16-bit data at addr   
* Input          : addr: destination addr
*                : buffer: 16-bit data
* Output         : data
* Return         : None
----------------------------------------------------*/
// OKay
void NORFlash_WriteHWord(u32 addr,u16 data)
{
	NORFlash_WriteEnable();
	
	//FlashPort_Init();	
	
	SSIx->SSI_DR = W25X_PAGEPROGRAM;

	if (Flash_Type==NOR_FLASH_W25Q256)
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送32bit块地址		
	SSIx->SSI_DR = (addr>>16)&0xFF;
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR = (addr)&0xFF;
		
	SSIx->SSI_DR=data;
	SSIx->SSI_DR=data>>8;

	//FlashPort_Init();	
	while(SSIx->SSI_SR&SR_BUSY){;}
	NORFlash_WaitBusy();					   		
}

/*----------------------------------------------------
* Function Name  : NORFlash_WriteBytes
* Description    : Write a 32-bit data at addr   
* Input          : addr: destination addr
*                : buffer: 32-bit data 
* Output         : data
* Return         : None
----------------------------------------------------*/
// OKay
void NORFlash_WriteWord(u32 addr,u32 data)
{
	u32 length=4;
	u8 status;
	NORFlash_WriteEnable();
	
	//NORFlash_DMATrans(addr,(u8 *)&data,4);
	
	//FlashPort_Init();	
	
	SSIx->SSI_DR = W25X_PAGEPROGRAM;
	
	if (Flash_Type==NOR_FLASH_W25Q256)
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送32bit块地址		
	SSIx->SSI_DR = (addr>>16)&0xFF;
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR = (addr)&0xFF;

	SSIx->SSI_DR=(data);
	SSIx->SSI_DR=(data>>8);
	SSIx->SSI_DR=(data>>16);
	SSIx->SSI_DR=(data>>24);

	//FlashPort_Init();
	while(SSIx->SSI_SR&SR_BUSY){;}	
	NORFlash_WaitBusy();
}

/*----------------------------------------------------
* Function Name  : NORFlash_WritePageAddrData
* Description    : Write length bytes data at any page addr   
* Input          : addr: destination addr
*                : buffer: data buffer
*                : length: bytes to write
* Output         : data
* Return         : None
----------------------------------------------------*/
// OKay
void NORFlash_WriteBytes(u32 addr,u8* buffer,u16 length)
{
	u8 status;
	NORFlash_WriteEnable();
	
	//FlashPort_Init();	
	
	SSIx->SSI_DR = W25X_PAGEPROGRAM;
	
	// Do not use this
	//NORFlash_DMASend(addr,buffer,length);
	
	if (Flash_Type==NOR_FLASH_W25Q256)
		SSIx->SSI_DR = (addr>>24)&0xFF;  	//发送32bit块地址		
	SSIx->SSI_DR = (addr>>16)&0xFF;
	SSIx->SSI_DR = (addr>>8)&0xFF;
	SSIx->SSI_DR = (addr)&0xFF;

	while(length)
	{   
		status=SSIx->SSI_SR;
		if(status&SR_TFNF)
		{
			SSIx->SSI_DR=*buffer++;
			length--;
		}
	}
	
	//FlashPort_Init();
	while(SSIx->SSI_SR&SR_BUSY){;}
	NORFlash_WaitBusy();
}

/*----------------------------------------------------
* Description    : Write length bytes data from address  
* Input          : addr: Destination addr
*                : buffer: Data buffer
*                : length: 
*					  : check: Enable for Checking the correction of written data
*                         0: Disable; 1: Enable 
* Output         : None
* Return         : 0: Okay, 1: Failure
----------------------------------------------------*/
// OKay
bool NORFlash_WritePages(u32 addr,u8* buffer,u16 length, bool check)
{
	u16 pageremain;

	pageremain=NORFLASH_PAGESIZE-(addr%NORFLASH_PAGESIZE); //单页剩余的字节数
	if(length<=pageremain) pageremain=length;//不大于256个字节
	
	while(1)
	{
		NORFlash_WriteBytes(addr,buffer,pageremain);
		if (check)
		{		
			NORFlash_ReadBytes(addr,wrBuff,pageremain);
			if (strncmp((char *)buffer,(char *)wrBuff,pageremain)) return(1);
		}
		
		if(length==pageremain)break;//写入结束了
	 	else //NumByteToWrite>pageremain
		{
			buffer+=pageremain;
			addr+=pageremain;

			length-=pageremain;			  //减去已经写入了的字节数
			if(length>NORFLASH_PAGESIZE)pageremain=NORFLASH_PAGESIZE; //一次可以写入256个字节
			else pageremain=length; 	  //不够256个字节了
		}
	}

	return(0);
}


static UINT8 W25NXX_ReadSR(UINT8 reg)
{
	UINT8 byte = 0;
	volatile unsigned char status;
	volatile unsigned char temp;
	
	SSIx->SSI_DR = W25N_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;
}

/*
* 函数名：W25qxx_Wait_Busy
* 功能  ：等待W25qxx忙
* 输入  ：无
* 输出  ：无
* 作者  ：LEVETOP
*/
static void W25NXX_WaitBusy(void)   
{   
	while((W25NXX_ReadSR(W25N_STATUSREGISTE2)&0x01)==0x01);  		// 等待BUSY位清空
} 

void W25NXX_WriteEnable(void)   
{
	volatile unsigned char status;
	volatile unsigned char temp;
	
	// Need this
	FlashPort_Init();
	
	SSIx->SSI_DR = W25N_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
	}	

	W25NXX_WaitBusy(); 	
} 

// 3个状态寄存器
// 保护寄存器1：地址0xA0
// 配置寄存器2: 地址0xB0
// 状态寄存器3: 地址0xC0  (只读寄存器)
static void W25NXX_WriteSR(UINT8 reg, UINT8 val)
{
	volatile unsigned char status;
	volatile unsigned char temp;
	
	W25NXX_WriteEnable();
		
	SSIx->SSI_DR = W25N_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
	}	
	
	W25NXX_WaitBusy(); 
}

/*
* 函数名：W25qxx_Write_Enable
* 功能  ：W25qxx写使能
* 输入  ：无
* 输出  ：无
* 作者  ：LEVETOP
*/

/*
* 函数名：W25QXX_Write_Disable
* 功能  ：禁止写W25qxx
* 输入  ：无
* 输出  ：无
* 作者  ：LEVETOP
*/
void W25NXX_WriteDisable(void)   
{
	volatile unsigned char status;
	volatile unsigned char temp;
	
	SSIx->SSI_DR = W25N_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 W25NXX_ContinuousRead_Mode(void)
{
	UINT8 statut = 0;
	statut = W25NXX_ReadSR(W25N_STATUSREGISTE1);
	statut &= 0xe7;
	statut |= 0x10;
	W25NXX_WriteSR(W25N_STATUSREGISTE1,statut);
}

//配置 BUF=1 、 ECC-E=1    页读模式
void NANDFlash_BufferReadMode(void)
{
	UINT8 statut = 0;
	statut = W25NXX_ReadSR(W25N_STATUSREGISTE1);
	statut |= 0x08;
	statut |= 0x10;
	W25NXX_WriteSR(W25N_STATUSREGISTE1,statut);      
}

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

* W25nxx系列的ID号如下：

* 作者  ：LEVETOP
*/
UINT32 NANDFlash_ReadID(void)
{

	UINT32 Device_ID = 0;

	SSIx->SSI_DR = W25N_READJEDECID;
	SSIx->SSI_DR = 0xff;
	
	SSIx->SSI_DR = 0xff;           
	SSIx->SSI_DR = 0xff;
	SSIx->SSI_DR = 0xff;

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

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

/*
* 函数名：W25NXX_BlockErase128KB
* 功能  ：擦除一个扇区（擦除一个扇区的最少时间:150ms）
* 输入  ：Dst_Addr:扇区地址 根据实际容量设置
* 输出  ：无
* 作者  ：LEVETOP
*/

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

	W25NXX_WriteSR(0xA0, 0x00); // 关flash保护功能
	W25NXX_WriteEnable(); // SET WEL
	W25NXX_WaitBusy();

	SSIx->SSI_DR=(0xD8); //发送片擦除命令
	SSIx->SSI_DR=(uint8_t)(0xFF);
	SSIx->SSI_DR=(uint8_t)(addr >> 8);
	SSIx->SSI_DR=(uint8_t)(addr);
	
	__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)
		SSIx->SSI_DR;//清空fifo

	W25NXX_WaitBusy();			 //等待芯片擦除结束
	W25NXX_WriteSR(0xA0, 0x7C); // 开flash保护功能
}

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

	DelayUS(1);
	
	SSIx->SSI_DR = W25N_READPAGEDATA;
	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
	}	
		
    W25NXX_WaitBusy();
}


void NANDFlash_SetSSIHeader(u16 length)
{
	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_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;

}

void NANDFlash_ReadData(u16 page, u16 column, UINT8 *buf, UINT32 length) 
{
	int i=0;
	
	FlashPort_Init(); 
	
	W25NXX_PageDataRead(page);
	
//	DelayUS(1);
//	if(page!=Nand_page)
//	{
//		W25NXX_PageDataRead(page);     //page addr
//		Nand_page=page;
//		//DelayUS(50);      //50us
//	}
//	
//	NandFlash_Read_Init(2,4,4,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);//|
//						 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 -----------------------------------------------------
*/
	NANDFlash_SetSSIHeader(length);
	
	DelayUS(1);																	//need after Init							

	SSIx->SSI_DR = W25N_FASTREAD_DUALIO;	
	SSIx->SSI_DR = column;	            						//column
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}

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

}

/*
void NANDFlash_ReadBytes(UINT32 ReadAddr,UINT8* pBuffer,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){;}

} 
*/

u8 NANDFlash_ReadByte(u32 addr)             
{
	u8 data;
	u16 columnAddr;          //业内地址
	u32 pageAddr;
	
	pageAddr = addr/2048;
	columnAddr = (addr%2048);
	
	FlashPort_Init();

	W25NXX_PageDataRead(pageAddr);	

	NANDFlash_SetSSIHeader(1);
	
	DelayUS(1);																	//need after Init							

	SSIx->SSI_DR = W25N_FASTREAD_DUALIO;	
	SSIx->SSI_DR = columnAddr;	            						//column
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}
	while(((SSIx->SSI_SR&SR_BUSY))||(SSIx->SSI_SR&SR_RFNE))
	{
		if(SSIx->SSI_SR&SR_RFNE) 
		{
			data=SSIx->SSI_DR;
			break;
		}
	}	

	DelayUS(50);
	return(data);
}

u16 NANDFlash_ReadHWord(u32 addr)             
{
	int i=0,length=2;
	u8 data[2];
	
	u16 columnAddr;          //业内地址
	u32 pageAddr;
	
	pageAddr = addr/2048;
	columnAddr = (addr%2048);
	
	FlashPort_Init();

	W25NXX_PageDataRead(pageAddr);	

	NANDFlash_SetSSIHeader(2);
	
	DelayUS(1);																//need after Init							

	SSIx->SSI_DR = W25N_FASTREAD_DUALIO;	
	SSIx->SSI_DR = columnAddr;	            						//column
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}
	while(((length>0)&&(SSIx->SSI_SR&SR_BUSY))||(SSIx->SSI_SR&SR_RFNE))
	{
		if(SSIx->SSI_SR&SR_RFNE)
		{
			data[i++]=SSIx->SSI_DR;
			length--;
		}	
	}	

	DelayUS(50);
	return(*(u16 *) data);
}

u32 NANDFlash_ReadWord(u32 addr)             
{
	int i=0,length=4;
	u8 data[4];
	
	u16 columnAddr;          //业内地址
	u32 pageAddr;
	
	pageAddr = addr/2048;
	columnAddr = (addr%2048);
	
	FlashPort_Init();
	
	W25NXX_PageDataRead(pageAddr);
	
	NANDFlash_SetSSIHeader(4);
	
	DelayUS(1);	//need after Init

	SSIx->SSI_DR = W25N_FASTREAD_DUALIO;	
	SSIx->SSI_DR = columnAddr;	            						//column
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}

	while(((length>0)&&(SSIx->SSI_SR&SR_BUSY))||(SSIx->SSI_SR&SR_RFNE))
	{
		if(SSIx->SSI_SR&SR_RFNE)
		{
			data[i++]=SSIx->SSI_DR;
			length--;
		}	
	}	
	DelayUS(50);
	return(*(u32 *) data);
}


/*----------------------------------------------------
* Function Name  : NANDFlash_ReadBytes
* Description    : Read 8-bit's data from addr  
* Input          : addr: Destination addr
* Output         : 8-bit data pointer
* Return         : None
----------------------------------------------------*/
void NANDFlash_ReadBytes(u32 addr,u8* buffer,u16 length)     
{ 
	u16 columnAddr;          //业内地址
	u32 pageAddr;
	
	pageAddr = addr/2048;
	columnAddr = (addr%2048);
	
	FlashPort_Init();
	
	W25NXX_PageDataRead(pageAddr);
	
	NANDFlash_SetSSIHeader(length);
	
	DelayUS(1);	//need after Init							

	SSIx->SSI_DR = W25N_FASTREAD_DUALIO;	
	SSIx->SSI_DR = columnAddr;	            						//column
	
	__asm("nop"); __asm("nop"); __asm("nop");
	
	while((SSIx->SSI_SR&SR_TFE)!=SR_TFE){;}

	while( ((length>0)&&(SSIx->SSI_SR&SR_BUSY))||(SSIx->SSI_SR&SR_RFNE) )
	{
		if(SSIx->SSI_SR&SR_RFNE)
		{
			*buffer++=SSIx->SSI_DR;
			length--;
		}	
	}	
	DelayUS(50);
}


void NANDFlash_ReadPages(u32 pageBeginAddr,u8* buffer,u16 length)   //函数内部自动将32位地址转换为对应的页地址和页内地址
{             
	u16 ReadNum = 0;         //读取每一页的数据量
	u16 columnAddr;          //业内地址
	u32 pageAddr;
	
//判断第一次读取时，对应的页内地址，页地址，写入的数据量。
	pageAddr = pageBeginAddr/2048;
	columnAddr = (pageBeginAddr%2048);

	if(length<(2048-columnAddr)) ReadNum = length;         
	else ReadNum = 2048-columnAddr;
	
	while(1)
	{	
		NANDFlash_ReadData(pageAddr,columnAddr,buffer,ReadNum);
		if(length == ReadNum)break;    //如果已经写入的数据达到要求，则写入完毕，退出。因为NumByteToWrite是不断减少的，当减到最后一次的时候，要写入的数据必定等于剩余的数据。
		
		buffer += ReadNum;                     //数组头跟着移动
		columnAddr = 0;           				//下一次读取操作必定从页内0地址写起。		
		pageAddr++;								//下一次读取操作必定从新页开始写。
		length -= ReadNum;				//总读取数据量根据已经读取的量进行减少。
		
		if(length<2048)                //下一次不需要写满一页
		{
			 ReadNum =length;
		}
		else ReadNum = 2048;                  //下一次要写满一页
	}
}

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

	u16 chNum=0;
	m_dma2_control->DMA_CONFIG = 1;
	//Tx
	
	m_dma2_channel[chNum]->DMA_SADDR = (UINT32)psend;
	m_dma2_channel[chNum]->DMA_DADDR = (UINT32)&SSIx->SSI_DR;
	m_dma2_channel[chNum]->DMA_CTRL = DNOCHG|SIEC|M2P_DMA|DWIDTH_B|SWIDTH_B|SBSIZE_4|DBSIZE_4;
	m_dma2_channel[chNum]->DMA_CTRL_HIGH = length ;  //最大长度为0x0FFF
	m_dma2_channel[chNum]->DMA_CFG = (HS_SEL_DST_HARD);
	m_dma2_channel[chNum]->DMA_CFG_HIGH = DST_SSI1_TX;
	m_dma2_control->DMA_CHEN |= (CHANNEL_WRITE_ENABLE(chNum)|CHANNEL_ENABLE(chNum));
	
	//Nand_SSI_STD_DMA_Trig(SSIx, W25N01GV_LoadProgramData,DMACR_TDMAE);
	SSIx->SSI_DR = W25N_READPROGRAMDATA;
	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(m_dma2_control->DMA_CHEN & CHANNEL_STAT(chNum)){;}
	m_dma2_control->DMA_CHEN &=~(CHANNEL_WRITE_ENABLE(chNum)|CHANNEL_ENABLE(chNum));
//	exFlash_dma_control->DMA_CONFIG = 0;
	SSIx->SSI_DMACR = 0;
}

void NANDFlash_WriteByte(u32 addr,u8 data)
{
  	UINT8  reV;
	u16 i;

	u16 columnAddr;          //业内地址
	u32 pageAddr;
	pageAddr = addr/NANDFLASH_PAGESIZE;
	columnAddr = (addr%NANDFLASH_PAGESIZE);

	FlashPort_Init();
	W25NXX_WriteSR(W25N_STATUSREGISTE, 0x00);      // 关flash保护功能      
   W25NXX_WriteEnable();				//写入使能

	DMA_REG_Init(DMA2_BASE_ADDR);
	NANDFlash_DMATrans(SSI1,(u8 *) &data,columnAddr,1);
	
	FlashPort_Init();
	
	W25NXX_WaitBusy();
	
	SSIx->SSI_DR = W25N_PROGRAMEXECUTE;
	SSIx->SSI_DR = 0xff;
	SSIx->SSI_DR = (UINT8)((pageAddr)>>8);
	SSIx->SSI_DR = (UINT8)pageAddr;

	__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;
      
	W25NXX_WaitBusy();
   W25NXX_WriteSR(W25N_STATUSREGISTE, 0x7C);      // 开flash保护功能
} 

void NANDFlash_WriteHWord(u32 addr,u16 data)
{
  	UINT8  reV;
	u16 i;

	u16 columnAddr;          //业内地址
	u32 pageAddr;
	pageAddr = addr/NANDFLASH_PAGESIZE;
	columnAddr = (addr%NANDFLASH_PAGESIZE);

	FlashPort_Init();
	
	W25NXX_WriteSR(W25N_STATUSREGISTE, 0x00);      // 关flash保护功能      
   W25NXX_WriteEnable();				//写入使能
	
	DMA_REG_Init(DMA2_BASE_ADDR);
	NANDFlash_DMATrans(SSI1,(u8 *) &data,columnAddr,2);
	
	FlashPort_Init();
	
	W25NXX_WaitBusy();
	
	SSIx->SSI_DR = W25N_PROGRAMEXECUTE;
	SSIx->SSI_DR = 0xff;
	SSIx->SSI_DR = (UINT8)((pageAddr)>>8);
	SSIx->SSI_DR = (UINT8)pageAddr;

	__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;
      
	W25NXX_WaitBusy();
   W25NXX_WriteSR(W25N_STATUSREGISTE, 0x7C);      // 开flash保护功能
} 

void NANDFlash_WriteWord(u32 addr,u32 data)
{
  	UINT8  reV;
	u16 i;

	u16 columnAddr;          //业内地址
	u32 pageAddr;
	pageAddr = addr/NANDFLASH_PAGESIZE;
	columnAddr = (addr%NANDFLASH_PAGESIZE);

	//SSI_TypeDef *SSIx=SSI1;
	FlashPort_Init();
	
	W25NXX_WriteSR(W25N_STATUSREGISTE, 0x00);      // 关flash保护功能      
   W25NXX_WriteEnable();				//写入使能

	
	
	DMA_REG_Init(DMA2_BASE_ADDR);
	NANDFlash_DMATrans(SSI1,(u8 *) &data,columnAddr,4);
	
	FlashPort_Init();
	
	W25NXX_WaitBusy();
	
	SSIx->SSI_DR = W25N_PROGRAMEXECUTE;
	SSIx->SSI_DR = 0xff;
	SSIx->SSI_DR = (UINT8)((pageAddr)>>8);
	SSIx->SSI_DR = (UINT8)pageAddr;

	__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;
      
	W25NXX_WaitBusy();
   W25NXX_WriteSR(W25N_STATUSREGISTE, 0x7C);      // 开flash保护功能
} 


/*----------------------------------------------------
//单页写函数
//SPI在一页(0~65535)内写入不大于2048个字节的数据
//在指定地址开始写入最大2048字节的数据
//pBuffer:数据存储区
//ColumnAddr:开始写入的页内地址(0-2047)
//PageAddr:页地址(0-65535)
//length:要写入的字节数(最大2048),该数不应该超过该页的剩余字节数!!!
----------------------------------------------------*/

void NANDFlash_WriteBytes(u32 addr,u8* buffer,u16 length)
{
  	UINT8  reV;
	u16 i;

	u16 columnAddr;          //业内地址
	u32 pageAddr;
	pageAddr = addr/NANDFLASH_PAGESIZE;
	columnAddr = (addr%NANDFLASH_PAGESIZE);
	

	//SSI_TypeDef *SSIx=SSI1;
	FlashPort_Init();
	
	W25NXX_WriteSR(W25N_STATUSREGISTE, 0x00);      // 关flash保护功能      
   W25NXX_WriteEnable();				//写入使能

	//DMA_REG_Init(DMA2_BASE_ADDR);
	
	NANDFlash_DMATrans(SSI1,buffer,columnAddr,length);
	
	FlashPort_Init();
	
	W25NXX_WaitBusy();
	
	SSIx->SSI_DR = W25N_PROGRAMEXECUTE;
	SSIx->SSI_DR = 0xff;
	SSIx->SSI_DR = (UINT8)((pageAddr)>>8);
	SSIx->SSI_DR = (UINT8)pageAddr;

	__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;
      
	W25NXX_WaitBusy();
   W25NXX_WriteSR(W25N_STATUSREGISTE, 0x7C);      // 开flash保护功能
} 


/*----------------------------------------------------
//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界! 
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(32bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
----------------------------------------------------*/

bool NANDFlash_WritePages(u32 addr,u8* buffer,u16 length, bool check)
//u8 NANDFlash_WriteBytes(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite,u8 check)   //函数内部自动将32位地址转换为对应的页地址和页内地址
{             
	u16 WriteNum = 0;         //写入每一页的数据量
	u16 columnAddr;           //页内地址
	
//判断第一次写入时，对应的页内地址，页地址，写入的数据量。
	columnAddr = (addr%NANDFLASH_PAGESIZE);
	
	if(length<(NANDFLASH_PAGESIZE-columnAddr)) WriteNum = length;         
	else WriteNum = NANDFLASH_PAGESIZE-columnAddr;
	
	while(1)
	{
		NANDFlash_WriteBytes(addr,buffer,WriteNum);
		
		if (check)
		{
			NANDFlash_ReadBytes(addr,wrBuff,WriteNum);
			
			//NANDFlash_ReadPages(pageBeginAddr,wrBuff,WriteNum);
			if (strncmp((char *)buffer,(char *)wrBuff,WriteNum)) return(1);
		}
				
		if(length == WriteNum)break;  //如果已经写入的数据达到要求，则写入完毕，退出。因为NumByteToWrite是不断减少的，当减到最后一次的时候，要写入的数据必定等于剩余的数据。
		
		buffer += WriteNum;           //数组头跟着移动
		columnAddr = 0;           		//下一次写入操作必定从页内0地址写起。		
		
		addr+=WriteNum;		
		length -= WriteNum;				//总写入数据量根据已经写入的量进行减少。
		
		if(length<NANDFLASH_PAGESIZE)               //下一次不需要写满一页
		{
			 WriteNum =length;
		}
		else WriteNum = NANDFLASH_PAGESIZE;         //下一次要写满一页
	}
	return(0);
} 

/*----------------------------------------------------
* Function Name  : Flash_ReadID
* Description    : Get the Flash ID 
* Input          : None
* Output         : None
* Return         : 0: Okay, 1: Failure
----------------------------------------------------*/

u8 Flash_ReadID(void)
{
	u32 cmmpetiableFlash;
	
	FlashPort_Init();
	Flash_ID = NORFlash_ReadID();	// For NOR flash other than Winbond

	Flash_Type = 0;
	cmmpetiableFlash=(Flash_ID&0x000000FF);
	if (cmmpetiableFlash>=0x15&&cmmpetiableFlash<=0x18) Flash_ID=cmmpetiableFlash|0xEF00;	
	
	//Display_32BitHex(1,1,Flash_ID,0xFFFF,0x0000);
	if (Flash_ID>=ID_W25Q32&&Flash_ID<=ID_W25Q256)	// NOR_FLASH
	{
		Flash_Type = NOR_FLASH;
		if (Flash_ID==ID_W25Q256) 
		{						
			// For erase or write	
			Flash_Type=NOR_FLASH_W25Q256;
			NORFlash_Enter4ByteAddressMode();
		}
		NORFlash_QEEnable();
	}
	else	// NAND_FLASH
	{
		Flash_Type = NAND_FLASH;
		//NANDFlash_Init();
		NANDFlash_BufferReadMode();
		Flash_ID=NANDFlash_ReadID();
		
		//Display_32BitHex(21,1,Flash_ID,0xFFFF,0x0000);
	  	
		if (Flash_ID==ID_W25N01GV) BlockQty = 1024;
		else 
		{
			if (Flash_ID==ID_W25N02KV) BlockQty = 2048;
			else 
			{
				if (Flash_ID==ID_W25N04KV) BlockQty = 4096;
				else return(1);
			}
		}
	}
	return(0);
}






