You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

779 lines
20 KiB

#include <string.h>
#include "Flash.h"
#include "spi_drv.h"
#include "dmac_drv.h"
#include "eport_drv.h"
#include "wdt_drv.h"
u8  W25Q256 = 0; 	 //256 NorFlash的标志 ,用于识别到256的时候开启4Byte 地址
u8  Flash_type = 0;  //用于判断 是NorFlash(0) 或者 NandFlash(1)
//u32 Flash_size =0;  //用于记录Flash的容量
u8 MUC_SS_flag = 1; //记录当前MCU这边的SD卡片选脚
UINT8 wrbuff[4*1024];
#if MCU_SPI
void SPI1_Flash_Init(void)
{
	SPI_InitTypeDef SPI_InitStruct;
	
	SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
	SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
	SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
	SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_Init(SPI1,&SPI_InitStruct);
}
void MCU_SS_RESET(void)
{
	if(MUC_SS_flag == 1)    //SPI1.SS
	{
		SPI1->U8SPIPORT.SS = 0;
	}
	else		//GINT5
	{
		MUC_CS0_RESET
	}	
		
}
void MCU_SS_SET(void)
{
	if(MUC_SS_flag == 1)    //SPI1.SS
	{
		SPI1->U8SPIPORT.SS = 1;
	}
	else		//GINT5
	{
		MUC_CS0_SET
	}	
			
}
UINT8 SPI1_ReadWriteByte(UINT8 Send)
{
	
	while(((SPI1->SPISRHW)&(SPISR_TXFFULL_MASK)));
//	printf("while1\r\n");
	SPI1->SPIDR = Send;
	
//	while(!(0x80 & SPI1->SPISR));
//	printf("SPI1->SPISRHW=%d\r\n",SPI1->SPISRHW);
	while(((SPI1->SPISRHW) & (SPISR_RXFEMP_MASK)));
//	printf("SPI10->SPISRHW=%d\r\n",SPI1->SPISRHW);
//	printf("while2\r\n");
	return SPI1->SPIDR;
}
void SPI1_DMA_Tran(UINT8* Tx_Addr, UINT8* Rx_Addr, UINT32 length)
{
	DMA_Init(DMA1_BASE_ADDR);
	SPI1->SPIDMACR |= 0x03;	//使能SPI TX RX的DMA
	
	m_dma_control->DMA_CONFIG = 1;
	//tx配置
	m_dma_channel[0]->DMA_SADDR = (UINT32)Tx_Addr;
	m_dma_channel[0]->DMA_DADDR = (UINT32)&SPI1->SPIDR;
	m_dma_channel[0]->DMA_CTRL_HIGH = length ;
	m_dma_channel[0]->DMA_CTRL = DNOCHG|SIEC|M2P_DMA;
	m_dma_channel[0]->DMA_CFG = (HS_SEL_SRC_SOFT);
	m_dma_channel[0]->DMA_CFG_HIGH = DST_PER_SPI_TX(0)|SRC_PER_SPI_TX(0);
	
	//rx配置
	m_dma_channel[1]->DMA_SADDR = (UINT32)&SPI1->SPIDR;
	m_dma_channel[1]->DMA_DADDR = (UINT32)Rx_Addr;
	m_dma_channel[1]->DMA_CTRL_HIGH = length ;
	m_dma_channel[1]->DMA_CTRL = SNOCHG|DIEC|P2M_DMA;
	m_dma_channel[1]->DMA_CFG = (HS_SEL_DST_SOFT);
	m_dma_channel[1]->DMA_CFG_HIGH = SRC_PER_SPI_RX(3)|DST_PER_SPI_RX(3);
//	m_dma_control->DMA_CONFIG = 0;
//	m_dma_control->DMA_CONFIG = 1;
	
	m_dma_control->DMA_MASKTFR = CHANNEL_UMASK(0)|CHANNEL_UMASK(1);
	m_dma_control->DMA_CHEN = CHANNEL_WRITE_ENABLE(0)|CHANNEL_ENABLE(0)|CHANNEL_WRITE_ENABLE(1)|CHANNEL_ENABLE(1);
}
void SPI1_DMA_Wait(void)
{
	while((m_dma_control->DMA_RAWTFR & (CHANNEL_STAT(0) | CHANNEL_STAT(1))) != (CHANNEL_STAT(0) | CHANNEL_STAT(1)))
	{
			//WDT_FeedDog();
	}
	m_dma_control->DMA_CLRTFR = (CHANNEL_STAT(0) | CHANNEL_STAT(1));
	
	m_dma_control->DMA_CHEN = 0;
	m_dma_control->DMA_CONFIG = 0;
	SPI1->SPIDMACR &= (~0x03);	//禁止SPI TX RX的DMA
}
void SPI1_Clock(u8 prescale)
{
	SPI1->SPICR1 &= ~(1<<6);   //disable spi2
	
	SPI1->SPIBR = prescale;
	
	SPI1->SPICR1 |= (1<<6);   //enable spi2
}
#endif
void  Close_SPI1(void)
{
	SPI_Cmd(SPI1,DISABLE);
	SPI_ConfigGpio(SPI1,SPI_SS,GPIO_INPUT);
	SPI_ConfigGpio(SPI1,SPI_MOSI,GPIO_INPUT);
	SPI_ConfigGpio(SPI1,SPI_MISO,GPIO_INPUT);
	SPI_ConfigGpio(SPI1,SPI_SCK,GPIO_INPUT);
	MUC_CS0_INPUT
}
/*************************************************************** winbond NorFlash **********************************************************************/
#define W25X_WriteEnable		0x06
#define W25X_WriteDisable		0x04
#define W25X_ReadStatusReg		0x05
#define W25X_WriteStatusReg		0x01
#define W25X_ReadData			0x03
#define W25X_FastReadData		0x0B
#define W25X_FastReadDual		0x3B
#define W25X_PageProgram		0x02
#define W25X_BlockErase			0xD8
#define W25X_SectorErase		0x20
#define W25X_ChipErase			0xC7
#define W25X_PowerDown			0xB9
#define W25X_ReleasePowerDown	0xAB
#define W25X_DeviceID			0xAB
#define W25X_ManufactDeviceID	0x90
#define W25X_JedecDeviceID		0x9F
//读取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 W25QXX_ReadSR(void)   //读取W25QXX的状态寄存器
{
	UINT8 byte=0;
	Flash_SS_RESET;                            		//使能器件
	SPIWR(W25X_ReadStatusReg); 	//发送读取状态寄存器命令
	byte=SPIWR(0Xff);          	//读取一个字节
	Flash_SS_SET;                            		//取消片选
	return byte;
}
//将WEL置位
void  W25QXX_Write_Enable(void)   //W25QXX写使能
{
	Flash_SS_RESET;                         //使能器件
	SPIWR(W25X_WriteEnable); 	//发送写使能
	Flash_SS_SET;                           //取消片选
}
void W25QXX_Write_Disable(void)   //W25QXX写禁止
{  
	Flash_SS_RESET;                         //使能器件   
    SPIWR(W25X_WriteDisable); 	//发送写禁止指令    
	Flash_SS_SET;                           //取消片选     	      
} 
void W25QXX_Wait_Busy(void)   		//等待空闲
{
	while((W25QXX_ReadSR()&0x01)==0x01);  		// 等待BUSY位清空
}
UINT16 W25QXX_ReadID(void)
{
	UINT16 Temp = 0;
	Flash_SS_RESET;
	SPIWR(0x90);//发送读取ID命令
	SPIWR(0x00);
	SPIWR(0x00);
	SPIWR(0x00);
	Temp|=SPIWR(0xFF)<<8;
	Temp|=SPIWR(0xFF);
	Flash_SS_SET;
	return Temp;
}
UINT32 W25QXX_ReadID_9F(void)
{
	UINT32 Temp = 0;
	Flash_SS_RESET;
	SPIWR(0x9F);//发送读取ID命令
//	SPIWR(0x00);
//	SPIWR(0x00);
//	SPIWR(0x00);
	Temp|=SPIWR(0xFF)<<16;
	Temp|=SPIWR(0xFF)<<8;
	Temp|=SPIWR(0xFF);
	Flash_SS_SET;
	return Temp;
}
void W25QXX_Read(UINT8* pBuffer,UINT32 ReadAddr,UINT16 NumByteToRead)
{
	UINT16 i;
	Flash_SS_RESET;                     //使能器件
	SPIWR(W25X_ReadData);         	    //发送读取命令
	
	if (W25Q256)
	SPIWR((UINT8)((ReadAddr)>>24));  	//256Flash发送32bit地址
	SPIWR((UINT8)((ReadAddr)>>16));  	//发送24bit地址
	SPIWR((UINT8)((ReadAddr)>>8));
	SPIWR((UINT8)ReadAddr);
#if MCU_SPI		
	#if DMA_flag
				SPI1_DMA_Tran(wrbuff,pBuffer,NumByteToRead);
				SPI1_DMA_Wait();
	#else
		for(i=0;i<NumByteToRead;i++)
		{
				pBuffer[i]=SPIWR(0XFF);   	//循环读数
		}
	#endif
#else
	for(i=0;i<NumByteToRead;i++)
	{ 
        pBuffer[i]=SPIWR(0XFF);   	//循环读数  
    }
	
#endif
	
	Flash_SS_SET;	
}
//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
void W25QXX_Write_Page(UINT8* pBuffer,UINT32 WriteAddr,UINT16 NumByteToWrite)
{
	UINT16 i;
	
	W25QXX_Write_Enable();                  							//SET WEL
	Flash_SS_RESET;                            							//使能器件
	SPIWR(W25X_PageProgram);      					//发送写页命令
	
	if (W25Q256)
	SPIWR((uint8_t)((WriteAddr)>>24));  	//256Flash发送32bit地址
	SPIWR((UINT8)((WriteAddr)>>16)); 					//发送24bit地址
	SPIWR((UINT8)((WriteAddr)>>8));
	SPIWR((UINT8)WriteAddr);
	
#if MCU_SPI		
	#if DMA_flag
				SPI1_DMA_Tran(pBuffer,wrbuff,NumByteToWrite);
				SPI1_DMA_Wait();
	#else
		for(i=0;i<NumByteToWrite;i++)SPIWR(pBuffer[i]);	//循环写数
	#endif 	
#else
	LCD_CmdWrite(0xB8);
	SS_RESET;
	SPI2_ReadWriteByte(0x80);
    for(i=0;i<NumByteToWrite;i++)
		SPI2_ReadWriteByte(pBuffer[i]);	
	SS_SET;	
#endif
	Flash_SS_SET;                           							//取消片选
	W25QXX_Wait_Busy();					   								//等待写入结束
}
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(UINT8* pBuffer,UINT32 WriteAddr,UINT16 NumByteToWrite)
{
	UINT16 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个字节了
		}
	}
}
void W25QXX_BlockErase64KB(UINT32 addr)
{
	addr*=(64*1024);
	W25QXX_Write_Enable();                 	//SET WEL
	W25QXX_Wait_Busy();
	Flash_SS_RESET;                            	  	//使能器件
	SPIWR(W25X_BlockErase);   			//发送片擦除命令
    if (W25Q256)
    SPIWR((uint8_t)((addr)>>24));  	//256Flash发送32bit地址	
	
	SPIWR((UINT8)((addr)>>16)); 			//发送24bit地址
	SPIWR((UINT8)((addr)>>8));
	SPIWR((UINT8)addr);
	Flash_SS_SET;                           	//取消片选
	W25QXX_Wait_Busy();   				   	//等待芯片擦除结束
}
void W25QXX_SectorErase4KB(UINT32 addr)
{
	addr*=4096;
	W25QXX_Write_Enable();                 	//SET WEL
	W25QXX_Wait_Busy();
	Flash_SS_RESET;                           	  	//使能器件
	SPIWR(W25X_SectorErase);   			//发送片擦除命令
	
	if (W25Q256)
	SPIWR((uint8_t)((addr)>>24));  	//256Flash发送32bit地址	
	
	SPIWR((UINT8)((addr)>>16)); 			//发送24bit地址
	SPIWR((UINT8)((addr)>>8));
	SPIWR((UINT8)addr);
	Flash_SS_SET;                            	//取消片选
	W25QXX_Wait_Busy();   				   	//等待芯片擦除结束
}
void W25QXX_Erase_Chip(void)
{
	W25QXX_Write_Enable();                 	 	  //SET WEL
	W25QXX_Wait_Busy();
	Flash_SS_RESET;                            	  //使能器件
	SPIWR(W25X_ChipErase);   //发送片擦除命令
	Flash_SS_SET;                           	//取消片选
	W25QXX_Wait_Busy();   				   		        //等待芯片擦除结束
}
void W25QXX_Enter_4Byte_AddressMode(void)
{
	Flash_SS_RESET; 
	SPIWR(0xB7);
	Flash_SS_SET;
}
/********************************************************************************************************************************************************/
/*************************************************************** winbond NandFlash **********************************************************************/
//指令表
#define W25N01GV_WriteEnable		0x06       
#define W25N01GV_WriteDisable		0x04 
#define W25N01GV_ReadStatusReg		0x05 
#define W25N01GV_WriteStatusReg		0x01 
#define W25N01GV_ReadData			0x03 
#define W25N01GV_FastReadData		0x0B 
#define W25N01GV_FastReadDual		0x3B 
#define W25N01GV_PageProgram		0x02 
#define W25N01GV_BlockErase			0xD8 
#define W25N01GV_SectorErase		0x20 
#define W25N01GV_ChipErase			0xC7 
#define W25N01GV_PowerDown			0xB9 
#define W25N01GV_ReleasePowerDown	0xAB 
#define W25N01GV_DeviceID			0xAB 
#define W25N01GV_ManufactDeviceID	0x90 
#define W25N01GV_JedecDeviceID		0x9F
//读取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 W25N01GV_ReadSR(uint8_t reg)   //读取W25N01的状态寄存器
{  
	uint8_t byte = 0;   
	Flash_SS_RESET;                                  	//使能器件 
	SPIWR(0x0F);   					//发送读取状态寄存器命令 
	SPIWR(reg);                     //寄存器地址 
	byte = SPIWR(0Xff);             //读取一个字节 
	Flash_SS_SET;                                 	//取消片选  	
	
	return byte;  
} 
// 3个状态寄存器
// 保护寄存器1:地址0xA0
// 配置寄存器2: 地址0xB0
// 状态寄存器3: 地址0xC0  (只读寄存器)
void W25N01GV_Write_SR(uint8_t reg, uint8_t val)   
{   
	W25N01GV_Write_Enable();	
//	printf("aaa\r\n");
	Flash_SS_RESET; 							//使能器件
//     printf("bbb\r\n");  
	SPIWR(0x1F);          //发送写取状态寄存器命令    
	SPIWR(reg);                      //寄存器地址 
	SPIWR(val);               	      //写入一个字节      	      
//	printf("ccc\r\n");
	Flash_SS_SET;                                 //取消片选 
//	printf("ddd\r\n");
	W25N01GV_Write_Disable();
} 
//将WEL置位   
void W25N01GV_Write_Enable(void)   //W25QXX写使能
{
//	printf("!!!\r\n");
	Flash_SS_RESET;                         			//使能器件   
//	printf("@@@\r\n");
    SPIWR(0x06); 	//发送写使能  
//	printf("###\r\n");
	Flash_SS_SET;                          		//取消片选     	   
//		printf("$$$\r\n");	
} 
	
//将WEL清零  
void W25N01GV_Write_Disable(void)   //W25QXX写禁止
{  
	Flash_SS_RESET;                          		//使能器件   
    SPIWR(0x04); 	//发送写禁止指令    
	Flash_SS_SET;                            	//取消片选     	      
} 		
void W25N01GV_Wait_Busy(void)   		//等待空闲
{   
	while((W25N01GV_ReadSR(0xc0)&0x01)==0x01);  		// 等待BUSY位清空
}  
//读取芯片ID
//返回值如下:				   
//0xefaa21,表示芯片型号为W25N01  
  
uint32_t W25N01GV_ReadID(void)
{
	uint8_t Mfr_id = 0;
	uint16_t Device_id = 0;
	uint32_t id = 0;
	
	Flash_SS_RESET;	
	SPIWR(0x9f);
	SPIWR(0x00);
	Mfr_id = SPIWR(0xff);
	Device_id = SPIWR(0xff);
	Device_id = Device_id<<8 | SPIWR(0xff);
	Flash_SS_SET;
	
	id = Mfr_id;
	id = (id<<16)+Device_id;
	return id;
}  
/**********************擦除**********************/
//擦除128KB Block //一共1024块  0-1023 511
void W25N01GV_Erase_Block(uint16_t block)   
{               
	uint32_t addr = 0;	
	addr = 64 * block;  //输入的是页地址,一个块有64页。
//		WDT_FeedDog();
//		printf("----\r\n");
		W25N01GV_Write_SR(0xA0, 0x00);          // 关flash保护功能
//		printf("+++++\r\n");
    W25N01GV_Write_Enable();                //SET WEL 
//		printf("0000\r\n");
//		WDT_FeedDog();
		W25N01GV_Wait_Busy();
//		printf("1111\r\n");	
		
    Flash_SS_RESET;  						    //使能器件
    SPIWR(0xD8);        	//发送片擦除命令  
//	SPIWR((uint8_t)(addr>>16));        	//发送片擦除命令  
	SPIWR(0xFF);        	//发送片擦除命令  
	SPIWR((uint8_t)(addr>>8)); 
	SPIWR((uint8_t)(addr));
	Flash_SS_SET;                         //取消片选     	
//	printf("222\r\n");
//	WDT_FeedDog();
	W25N01GV_Wait_Busy();   				        //等待芯片擦除结束
	
	W25N01GV_Write_SR(0xA0,0x7C);                 // 开flash保护功能
}
void W25N01GV_EraseFlash(void)           //一共有1024个block
{
	uint16_t block = 0;
	for(block = 0 ;block < 1024 ; block++)
	{
		W25N01GV_Erase_Block(block);
	}
}
//-----------------------------------------------------------------------
/**********************页模式**********************/
//单页写函数
//SPI在一页(0~65535)内写入不大于2048个字节的数据
//在指定地址开始写入最大2048字节的数据
//pBuffer:数据存储区
//ColumnAddr:开始写入的页内地址(0-2047)
//PageAddr:页地址(0-65535)
//NumByteToWrite:要写入的字节数(最大2048),该数不应该超过该页的剩余字节数!!!
void W25N01GV_WritePageAddr_Data(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToWrite)   //不能写入超过2048 Byte(一页2048个Byte,后面的64 Byte非数据位)
{
 	uint16_t i;
 	
	W25N01GV_Write_SR(0xa0, 0x00);      // 关flash保护功能
	
	//------写BUFF------
		WDT_FeedDog();
    W25N01GV_Write_Enable();                  	//SET WEL 
//		printf("3333\r\n");
    Flash_SS_RESET;                           //使能器件   
    SPIWR(0x02);      	    //发送写BUFF命令   
    SPIWR(ColumnAddr>>8); 	//BUFF地址   
    SPIWR(ColumnAddr);
//			printf("44444\r\n");
#if  MCU_SPI	
	#if DMA_flag
//				WDT_FeedDog();
				SPI1_DMA_Tran(pBuffer,wrbuff,NumByteToWrite);
//				printf("55555\r\n");
//				WDT_FeedDog();
				SPI1_DMA_Wait();
//				printf("6666\r\n");
	#else	
		
		for(i=0;i<NumByteToWrite;i++)SPIWR(pBuffer[i]);//循环写数 
		
	#endif	
#else
	LCD_CmdWrite(0xB8);
	SS_RESET;
	SPI2_ReadWriteByte(0x80);
    for(i=0;i<NumByteToWrite;i++)
		SPI2_ReadWriteByte(pBuffer[i]);	
	SS_SET;
#endif
	Flash_SS_SET;                          //取消片选 
//	WDT_FeedDog();
	W25N01GV_Wait_Busy();					    	//等待写入结束
	
	//-------BUFF数据写入flash--------
	W25N01GV_Write_Enable();
	Flash_SS_RESET;                          	//使能器件   
	SPIWR(0x10);      	    	//发送写页命令   
//	SPIWR(PageAddr>>16); 	       	 	//发送16it地址   
	SPIWR(0xff); 	       	 	//发送16it地址    
	SPIWR(PageAddr>>8); 		//发送16it地址    
	SPIWR(PageAddr);   
	Flash_SS_SET;   
//	WDT_FeedDog();
	W25N01GV_Wait_Busy();					        //等待写入结束 
	
	W25N01GV_Write_SR(0xa0, 0x7c);                // 开flash保护功能
//	 printf("777\r\n");
} 
//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界! 
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(32bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25N01GV_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   //函数内部自动将32位地址转换为对应的页地址和页内地址
{             
	uint16_t WriteNum = 0;         //写入每一页的数据量
	uint16_t ColumnAddr;           //页内地址
	uint32_t PageAddr;             //页地址
	
//判断第一次写入时,对应的页内地址,页地址,写入的数据量。
	ColumnAddr = (WriteAddr%2048);
	PageAddr = WriteAddr/2048;
	
	if(NumByteToWrite<(2048-ColumnAddr)) WriteNum = NumByteToWrite;         
	else WriteNum = 2048-ColumnAddr;
	
	
	
	while(1)
	{
//		printf("ColumnAddr:%d\r\n",ColumnAddr);
//		printf("PageAddr:%d\r\n",PageAddr);
		
		W25N01GV_WritePageAddr_Data(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 W25N01GV_ReadPageAddr_Data(uint8_t* pBuffer,uint16_t ColumnAddr,uint32_t PageAddr,uint16_t NumByteToRead)   
{ 
 	uint16_t i; 
	W25N01GV_Write_SR(0xB0,W25N01GV_ReadSR(0xB0)|0x08);
    //------从flash读数据到BUFF-----	
	Flash_SS_RESET;                            //使能器件   
	SPIWR(0x13);
//	SPIWR(PageAddr>>16);            //空周期
	SPIWR(0x00);            //空周期
    SPIWR(PageAddr>>8);     //发送16bit页地址,将对应页的数据提取到BUFF中     
    SPIWR(PageAddr);   
	Flash_SS_SET; 	
	W25N01GV_Wait_Busy();
	
	W25N01GV_Write_SR(0xB0,W25N01GV_ReadSR(0xB0)|0x08);
	//------再从BUFF读数据到单片机内-----
	Flash_SS_RESET;   	
	SPIWR(0x03); 
	SPIWR(ColumnAddr>>8);  
	SPIWR(ColumnAddr); 	
	SPIWR(0x00);
#if MCU_SPI		
	#if DMA_flag
				SPI1_DMA_Tran(wrbuff,pBuffer,NumByteToRead);
				SPI1_DMA_Wait();
	#else
		for(i=0;i<NumByteToRead;i++)
		{ 
			pBuffer[i]= SPIWR(0xFF);   	//循环读数  
		}
	#endif
#else 
	for(i=0;i<NumByteToRead;i++)
	{ 
        pBuffer[i]=SPIWR(0XFF);   	//循环读数  
    }
#endif
	 Flash_SS_SET; //---------------------	
	 W25N01GV_Wait_Busy();
}
//无检验读SPI FLASH 
//具有自动换页功能 
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(32bit)
//NumByteToRead:要读取的字节数(最大65535)
//CHECK OK
void W25N01GV_Read_NoCheck(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   //函数内部自动将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)
	{
		
		W25N01GV_ReadPageAddr_Data(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 W25N01GV_Read_BBM_LUT(BBM * L )
{
	uint8_t i;
	
	Flash_SS_RESET;  						     
	SPIWR(0xA5);
	SPIWR(0xFF);	
	
	for(i=0;i<20;i++)
	{
		L[i].LBA = ((uint16_t)SPIWR(0xFF)<<8); 
		L[i].LBA |= SPIWR(0xFF);
		L[i].PBA = ((uint16_t)SPIWR(0xFF)<<8); 
		L[i].PBA |= SPIWR(0xFF);
	}
	Flash_SS_SET; 
}
//uint8_t W25N01GV_Bad_Block_Management(uint16_t LBA,uint16_t PBA)
uint8_t W25N01GV_Bad_Block_Replace(uint16_t LBA,uint16_t PBA) //Bad LBA,good PBA
{
	if((W25N01GV_ReadSR(0xC0) &0x40) == 0)  //Look Up Table not full
	{
		W25N01GV_Write_Enable();
		W25N01GV_Wait_Busy();
		
		Flash_SS_RESET;  						     
		SPIWR(0xA1);        	 
		SPIWR((uint8_t)(LBA>>8)); 
		SPIWR((uint8_t)(LBA));
		SPIWR((uint8_t)(PBA>>8)); 
		SPIWR((uint8_t)(PBA));
		Flash_SS_SET;                           
		
		W25N01GV_Wait_Busy();
		return 0;  //OK
	}
	else
	{
		return 1;  //Failure
	}
}
/*********************************************************************W25N01GV*****************************************************************************************/