#define THIS_FILE_ID 13


#include "includes.h"
//4KbytesΪһ��Sector
//16������Ϊ1��Block
//W25X16
//����Ϊ2M�ֽ�,����32��Block,512��Sector 


//��Ҫ���ú�������sector�Ᵽ��������ȫ�ֽⱣ�������д��.
//W25ϵ���ϵ�Ĭ��û������д�������ʿ�ֱ��д��
#define sFLASH_CS_PIN                    GPIO_Pin_4                  /* PA.04 */
#define sFLASH_CS_GPIO_PORT              GPIOA                       /* GPIOA */
#define sFLASH_CS_GPIO_CLK               RCC_APB2Periph_GPIOA
#define sFLASH_SPI                       SPI1
#define sFLASH_SPI_CLK                   RCC_APB2Periph_SPI1
#define sFLASH_SPI_SCK_PIN               GPIO_Pin_5                  /* PA.05 */
#define sFLASH_SPI_SCK_GPIO_PORT         GPIOA                       /* GPIOA */
#define sFLASH_SPI_SCK_GPIO_CLK          RCC_APB2Periph_GPIOA
#define sFLASH_SPI_MISO_PIN              GPIO_Pin_6                  /* PA.06 */
#define sFLASH_SPI_MISO_GPIO_PORT        GPIOA                       /* GPIOA */
#define sFLASH_SPI_MISO_GPIO_CLK         RCC_APB2Periph_GPIOA
#define sFLASH_SPI_MOSI_PIN              GPIO_Pin_7                  /* PA.07 */
#define sFLASH_SPI_MOSI_GPIO_PORT        GPIOA                       /* GPIOA */
#define sFLASH_SPI_MOSI_GPIO_CLK         RCC_APB2Periph_GPIOA


#define sFLASH_CS_LOW()										GPIO_ResetBits(sFLASH_CS_GPIO_PORT, sFLASH_CS_PIN)
#define sFLASH_CS_HIGH()									GPIO_SetBits(sFLASH_CS_GPIO_PORT, sFLASH_CS_PIN)  

//ָ���
#define W25Q64_WriteEnable			0x06 
#define W25Q64_WriteDisable			0x04 
#define W25Q64_ReadStatusReg		0x05 
#define W25Q64_WriteStatusReg		0x01 
#define W25Q64_ReadData					0x03 
#define W25Q64_FastReadData			0x0B 
#define W25Q64_FastReadDual			0x3B //??
#define W25Q64_PageProgram			0x02 
#define W25Q64_SectorErase			0x20 //erase 4k
#define W25Q64_BlockErase				0x52 //erase 32k
#define W25Q64_BigBlockErase		0xd8 //erase 64k
#define W25Q64_ChipErase				0xC7 //0x60
#define W25Q64_PowerDown				0xB9 
#define W25Q64_ReleasePowerDown	0xAB 
#define W25Q64_DeviceID					0x9F 
//#define W25Q64_UnprotectSector	0x39
//#define W25Q64_ProtectSector	  0x36


uint32_t  sFlash_ReadID(void);  	    //��ȡFLASH ID
u8	sFlash_ReadSR(void);        //��ȡ״̬�Ĵ��� 
void sFlash_Write_SR(u8 sr);  	//д״̬�Ĵ���
void sFlash_Write_Enable(void);  //дʹ�� 
void sFlash_Write_Disable(void);	//���
void sFlash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //��ȡflash
void sFlash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//�flash
void sFlash_Erase_Chip(void);    	  //��Ƭ����
void sFlash_Erase_Sector(u32 Dst_Addr);//��������
void sFlash_Wait_Busy(void);           //�ȴ�����
void sFlash_PowerDown(void);           //�������ģʽ
void sFlash_WAKEUP(void);			  //����
//void sFlash_Protect_Sector(u32 Dst_Addr);
//void sFlash_Unprotect_Sector(u32 Dst_Addr);
void sFlash_SetProtectMode(unsigned char mode);//���ñ���ģʽ 0--�Ĵ�����ʽ 1--Ӳ��WP������ʽ
void sFlash_Global_Protect(void);
void sFlash_Global_Unprotect(void);

static unsigned char sFlashProtectMode=0;

/**********************************************************************
1ms��8000~9000֮��
***********************************************************************/
void DelayMs(unsigned short ms)
{
	unsigned short i;
	unsigned short t=ms;
	//IWDG_ReloadCounter();
	while(t--){
		for(i=0;i<6000;i++);
		//IWDG_ReloadCounter();
	}
}
/**********************************************************************
1ms��8000~9000֮��
fclk=24M
24*1.24=29.75M
***********************************************************************/
void DelayUs(unsigned short us)
{
	unsigned short i;
	unsigned short t=us;
	while(t--){
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	}
}
/***************************************************************
W25Q64_PortInit
****************************************************************/
void W25Q64_PortInit(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /*!< sFLASH_SPI_CS_GPIO, sFLASH_SPI_MOSI_GPIO, sFLASH_SPI_MISO_GPIO 
	and sFLASH_SPI_SCK_GPIO Periph clock enable */
  RCC_APB2PeriphClockCmd(sFLASH_CS_GPIO_CLK | sFLASH_SPI_MOSI_GPIO_CLK | sFLASH_SPI_MISO_GPIO_CLK |
	
	sFLASH_SPI_SCK_GPIO_CLK, ENABLE);

  /*!< sFLASH_SPI Periph clock enable */
  RCC_APB2PeriphClockCmd(sFLASH_SPI_CLK, ENABLE);
  
  /*!< Configure sFLASH_SPI pins: SCK */
  GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_SCK_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(sFLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);

  /*!< Configure sFLASH_SPI pins: MOSI */
  GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_MOSI_PIN;
  GPIO_Init(sFLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

  /*!< Configure sFLASH_SPI pins: MISO */
  GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_MISO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  GPIO_Init(sFLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
  
  /*!< Configure sFLASH_CS_PIN pin: sFLASH Card CS pin */
  GPIO_InitStructure.GPIO_Pin = sFLASH_CS_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(sFLASH_CS_GPIO_PORT, &GPIO_InitStructure);
}

/***************************************************************
W25Q64_Init
****************************************************************/
int W25Q64_Init(void)
{
	uint32_t sFlashId;
  SPI_InitTypeDef  SPI_InitStructure;
//	printf("sFlash Init...\r\n");
	
  W25Q64_PortInit();
  /*!< Deselect the FLASH: Chip Select high */
  sFLASH_CS_HIGH();

  /*!< SPI configuration */
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(sFLASH_SPI, &SPI_InitStructure);
	//
	
  /*!< Enable the sFLASH_SPI  */
  SPI_Cmd(sFLASH_SPI, ENABLE);
	//
	DelayUs(1000);
	//
	sFlashId=sFlash_ReadID();
	//printf("sFlash ID=%04x\r\n",sFlashId);
	//if(sFlashId==0x00000000 || sFlashId==0xffffffff){
	//	printf("sFlash Init Fail!\r\n");
	//	return 0;
	//}
	//printf("sFlash Init OK!\r\n");


	return 1;
	
	
}  

/**********************************************************************
*
***********************************************************************/

u8 SPIx_ReadWriteByte(u8 byte)
{
 // < Loop while DR register in not emplty 
  while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);

 // !< Send byte through the SPI1 peripheral 
  SPI_I2S_SendData(sFLASH_SPI, byte);

 // !< Wait to receive a byte 
  while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);

 // !< Return the byte read from the SPI bus 
  return SPI_I2S_ReceiveData(sFLASH_SPI);
}

/*
//SPIx ��дһ���ֽ�
//����ֵ:��ȡ�����ֽ�
u8 SPIx_ReadWriteByte(u8 TxData)
{		
	u8 retry=0;				 
	while((SPI1->SR&1<<1)==0)//�ȴ���������	
	{
		retry++;
		if(retry>200)return 0;
	}			  
	SPI1->DR=TxData;	 	  //����һ��byte 
	retry=0;
	while((SPI1->SR&1<<0)==0) //�ȴ�������һ��byte  
	{
		retry++;
		if(retry>200)return 0;
	}	  						    
	return SPI1->DR;          //�����յ�������				    
}
*/

//��ȡsFlash��״̬�Ĵ���
//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
u8 sFlash_ReadSR(void)   
{  
	u8 byte=0;   
	sFLASH_CS_LOW();                            //ʹ������   
	SPIx_ReadWriteByte(W25Q64_ReadStatusReg);    //���Ͷ�ȡ״̬�Ĵ�������    
	byte=SPIx_ReadWriteByte(0Xff);             //��ȡһ���ֽ�  
	sFLASH_CS_HIGH();                           //ȡ��Ƭѡ     
	return byte;   
} 
//дsFlash״̬�Ĵ���
//ֻ��SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)����д!!!
void sFlash_Write_SR(u8 sr)   
{   
	sFLASH_CS_LOW();                            //ʹ������   
	SPIx_ReadWriteByte(W25Q64_WriteStatusReg);   //����дȡ״̬�Ĵ�������    
	SPIx_ReadWriteByte(sr);               //д��һ���ֽ�  
	sFLASH_CS_HIGH();                            //ȡ��Ƭѡ     	      
}   
//sFlashдʹ��	
//��WEL��λ   
void sFlash_Write_Enable(void)   
{
	sFLASH_CS_LOW();															//ʹ������   
	SPIx_ReadWriteByte(W25Q64_WriteEnable);      //����дʹ��  
	sFLASH_CS_HIGH();                            //ȡ��Ƭѡ     	      
} 
//sFlashд��ֹ	
//��WEL����  
void sFlash_Write_Disable(void)   
{  
	sFLASH_CS_LOW();                           //ʹ������   
	SPIx_ReadWriteByte(W25Q64_WriteDisable);     //����д��ָֹ��    
	sFLASH_CS_HIGH();                            //ȡ��Ƭѡ     	      
} 			    
//��ȡоƬID W25X16��ID:0XEF14
uint32_t sFlash_ReadID(void)
{
    uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
	sFLASH_CS_LOW();			    
	SPIx_ReadWriteByte(W25Q64_DeviceID);//���Ͷ�ȡID����	    	 			   
	Temp0=SPIx_ReadWriteByte(0xFF);  
	Temp1=SPIx_ReadWriteByte(0xFF);	 
	Temp2=SPIx_ReadWriteByte(0xFF);	 
	sFLASH_CS_HIGH();		
    Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;	
	return Temp;
}



//��ȡSPI FLASH  
//��ָ����ַ��ʼ��ȡָ�����ȵ�����
//pBuffer:���ݴ洢��
//ReadAddr:��ʼ��ȡ�ĵ�ַ(24bit)
//NumByteToRead:Ҫ��ȡ���ֽ���(���65535)
void sFlash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{ 
 	u16 i;    												    
	sFLASH_CS_LOW();                           //ʹ������   
    //SPIx_ReadWriteByte(W25Q64_ReadData);         //���Ͷ�ȡ����   
	  SPIx_ReadWriteByte(W25Q64_FastReadData);//���ٶ�����
    SPIx_ReadWriteByte((u8)((ReadAddr)>>16));  //����24bit��ַ    
    SPIx_ReadWriteByte((u8)((ReadAddr)>>8));   
    SPIx_ReadWriteByte((u8)ReadAddr);   
	  pBuffer[0]=SPIx_ReadWriteByte(0XFF);//���ٶ������һ���ֽ�
    for(i=0;i<NumByteToRead;i++)
	{ 
        pBuffer[i]=SPIx_ReadWriteByte(0XFF);   //ѭ������  
    }
	sFLASH_CS_HIGH();                            //ȡ��Ƭѡ     	      
}  
//SPI��һҳ(0~65535)��д������256���ֽڵ�����
//��ָ����ַ��ʼд�����256�ֽڵ�����
//pBuffer:���ݴ洢��
//WriteAddr:��ʼд��ĵ�ַ(24bit)
//NumByteToWrite:Ҫд����ֽ���(���256),������Ӧ�ó�����ҳ��ʣ���ֽ���!!!	 
void sFlash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
 	u16 i;  
    sFlash_Write_Enable();                  //SET WEL 
	sFLASH_CS_LOW();                           //ʹ������   
    SPIx_ReadWriteByte(W25Q64_PageProgram);      //����дҳ����   
    SPIx_ReadWriteByte((u8)((WriteAddr)>>16)); //����24bit��ַ    
    SPIx_ReadWriteByte((u8)((WriteAddr)>>8));   
    SPIx_ReadWriteByte((u8)WriteAddr);   
    for(i=0;i<NumByteToWrite;i++) SPIx_ReadWriteByte(pBuffer[i]);//ѭ��д��  
	sFLASH_CS_HIGH();                           //ȡ��Ƭѡ 
	sFlash_Wait_Busy();					   //�ȴ�д�����
} 
//�޼���дSPI FLASH 
//����ȷ����д�ĵ�ַ��Χ�ڵ�����ȫ��Ϊ0XFF,�����ڷ�0XFF��д������ݽ�ʧ��!
//�����Զ���ҳ���� 
//��ָ����ַ��ʼд��ָ�����ȵ�����,����Ҫȷ����ַ��Խ��!
//pBuffer:���ݴ洢��
//WriteAddr:��ʼд��ĵ�ַ(24bit)
//NumByteToWrite:Ҫд����ֽ���(���65535)
//CHECK OK
void sFlash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 			 		 
	u16 pageremain;	   
	pageremain=256-WriteAddr%256; //��ҳʣ����ֽ���		 	    
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//������256���ֽ�
	while(1)
	{	   
		sFlash_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���ֽ���
		}
	};	    
} 
//дSPI FLASH  
//��ָ����ַ��ʼд��ָ�����ȵ�����
//�ú�������������!
//pBuffer:���ݴ洢��
//WriteAddr:��ʼд��ĵ�ַ(24bit)
//NumByteToWrite:Ҫд����ֽ���(���65535)  		   
u8 sFlash_BUF[4096];
void sFlash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 
	u32 secpos;
	u16 secoff;
	u16 secremain;	   
 	u16 i;  
	secpos=WriteAddr/4096;//������ַ 0~511 for w25x16
	secoff=WriteAddr%4096;//�������ڵ�ƫ��
	secremain=4096-secoff;//����ʣ��ռ��С   
	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//������4096���ֽ�
	while(1) 
	{	
		sFlash_Read(sFlash_BUF,secpos*4096,4096);//������������������
		for(i=0;i<secremain;i++)//������
		{
			if(sFlash_BUF[secoff+i]!=0XFF)break;//��Ҫ����  	  
		}
		if(i<secremain)//��Ҫ����
		{
			sFlash_Erase_Sector(secpos);//�����������
			for(i=0;i<secremain;i++)	   //����
			{
				sFlash_BUF[i+secoff]=pBuffer[i];	  
			}
			sFlash_Write_NoCheck(sFlash_BUF,secpos*4096,4096);//���������  

		}else sFlash_Write_NoCheck(pBuffer,WriteAddr,secremain);//д�Ѿ������˵�,ֱ��д������ʣ������. 				   
		if(NumByteToWrite==secremain)break;//������
		else//д��δ����
		{
			secpos++;//������ַ��1
			secoff=0;//ƫ��λ��Ϊ0 	 

		   	pBuffer+=secremain;  //ָ��ƫ��
			WriteAddr+=secremain;//д��ַƫ��	   
		   	NumByteToWrite-=secremain;				//�ֽ����ݼ�
			if(NumByteToWrite>4096)secremain=4096;	//��һ����������д����
			else secremain=NumByteToWrite;			//��һ����������д����
		}	 
	}	 	 
}

//��������оƬ
//��Ƭ����ʱ��:
//W25X16:25s 
//W25X32:40s 
//W25X64:40s 
//�ȴ�ʱ�䳬��...
void sFlash_Erase_Chip(void)   
{     
	sFlash_Write_Enable();                  //SET WEL 
	sFlash_Wait_Busy();   
	sFLASH_CS_LOW();                           //ʹ������   
	SPIx_ReadWriteByte(W25Q64_ChipErase);        //����Ƭ��������  
	sFLASH_CS_HIGH();                            //ȡ��Ƭѡ     	      
	sFlash_Wait_Busy();   				   //�ȴ�оƬ��������
}   

//void sFlash_EraseChip(void)
//{
///*!&lt; Send write enable instruction */
//sFlash_Write_Enable();
//sFlash_WaitForWriteEnd();
///*!&lt; Bulk Erase */
///*!&lt; Select the FLASH: Chip Select low */
//W25X_FLASH_CS_LOW();
///*!&lt; Send Bulk Erase instruction */
//sFlash_SendByte(W25X_CMD_ChipErase);
///*!&lt; Deselect the FLASH: Chip Select high */
//W25X_FLASH_CS_HIGH();
// 
///*!&lt; Wait the end of Flash writing */
//sFlash_WaitForWriteEnd();
//}


//����һ������
//Dst_Addr:������ַ 0~511 for w25x16
//����һ��ɽ��������ʱ��:150ms
void sFlash_Erase_Sector(u32 Dst_Addr)   
{   
    Dst_Addr*=4096;
    sFlash_Write_Enable();                  //SET WEL 	 
    sFlash_Wait_Busy();   
  	sFLASH_CS_LOW();                           //ʹ������   
    SPIx_ReadWriteByte(W25Q64_SectorErase);      //������������ָ�� 
    SPIx_ReadWriteByte((u8)((Dst_Addr)>>16));  //����24bit��ַ    
    SPIx_ReadWriteByte((u8)((Dst_Addr)>>8));   
    SPIx_ReadWriteByte((u8)Dst_Addr);  
    sFLASH_CS_HIGH();                          //ȡ��Ƭѡ     	      
    sFlash_Wait_Busy();   				   //�ȴ��������
}  

//����ȫоƬ
void sFlash_Global_Protect(void)   
{   
		//sFlash_Wait_Busy(); 
		sFlash_Write_Enable();                  //SET WEL 	 
    sFlash_Wait_Busy();   
    sFlash_Write_SR(0x3c);   
		//sFlash_Wait_Busy(); 	
} 

//�Ᵽ��ȫоƬ
void sFlash_Global_Unprotect(void)   
{   

		//sFlash_Wait_Busy();   
		sFlash_Write_Enable();                  //SET WEL 	 
    sFlash_Wait_Busy();   
    sFlash_Write_SR(0x80);    	 
		//sFlash_Wait_Busy();

} 

//�ȴ�����
void sFlash_Wait_Busy(void)   
{   
	while ((sFlash_ReadSR()&0x01)==0x01){		// �ȴ�BUSYλ���
		//IWDG_ReloadCounter();//�
	}
}  
//�������ģʽ
void sFlash_PowerDown(void)   
{ 
	sFLASH_CS_LOW();                           //ʹ������   
	SPIx_ReadWriteByte(W25Q64_PowerDown);        //���͵�������  
	sFLASH_CS_HIGH();                            //ȡ��Ƭѡ     	      
	DelayUs(3);                               //�ȴ�TPD  
}   
//����
void sFlash_WAKEUP(void)   
{  
	sFLASH_CS_LOW();                            //ʹ������   
	SPIx_ReadWriteByte(W25Q64_ReleasePowerDown);   //  send W25Q64_PowerDown command 0xAB    
	sFLASH_CS_HIGH();                            //ȡ��Ƭѡ     	      
	DelayUs(3);                               //�ȴ�TRES1
}


/*********************************************
*
***********************************************/
void W25Q64Test(void)
{
	uint32_t sFlashId;
  unsigned char sFlashSR;
	static int scStep=0;
	unsigned char t;
	char buf[200];
	int i;


	switch(scStep){
		case 0:
			sFlashId=sFlash_ReadID();
			printf("sFlashID=%04x\r\n",sFlashId);
			break;
		case 1:
			memset(buf,0,sizeof(buf));
			strcpy(buf,"333333333444444444455555555555\r\n");
			printf("sFlash Write=%s",buf);
			sFlash_Write((unsigned char *)buf,0,sizeof(buf));
			break;
		case 2:
			memset(buf,0,sizeof(buf));
			sFlash_Read((unsigned char *)buf,0,sizeof(buf));
			printf("sFlash Read=%s",buf);
			printf("sFlash write 8MB...\r\n");
			for(i=0;i<200;i++){
				buf[i]=i;
			}
			for(i=0;i<1000;i++){
				sFlash_Write_Page((unsigned char *)buf,i*4096,200);
			}
			printf("sFlash write 8MB OK!\r\n");
			break;
		case 3:
			
			break;
	}
	if(scStep<3)scStep++;
}