//-------------------------------------------------------------------------*
//文件名:  EFlash.c (外扩Flash芯片操作函数文件)                            *
//-------------------------------------------------------------------------*

//头文件
#include "EFlash.h"

//-----------------------------------------------------------------------*
//函数名: EFlash_Init                                                    *
//功  能: 初始化SPI模块,使用模式0,波特率为系统总线/2                     *
//参  数: 无                                                             *
//返  回: 无                                                             *
//-----------------------------------------------------------------------*
void EFlash_Init(void)
{
	SPI_init();
   	GPIO_Init(EFlash_RST_PORT,EFlash_RST_PIN,1,1);//初始化RST引脚, 输出高电平
	GPIO_Init(EFlash_WP_PORT,EFlash_WP_PIN,1,1);  //初始化WP引脚,  输出高电平
	GPIO_Init(EFlash_CS_PORT,EFlash_CS_PIN,1,1);  //初始化CS0T引脚,输出高电平
    Delay(5);//1us
}

//-----------------------------------------------------------------------*
//函数名: SPI_HostReadByte                                               *
//功  能: 从AT45DB041B通过SPI_SO口读入1BYTE数据                          *
//参  数: 无                                                             *
//返  回: 返回读入的1BYTE数据                                            *
//说  明: 调用了SPI_ReceiveOneByte函数                                   *
//-----------------------------------------------------------------------*
uint8 SPI_HostReadByte(void) 
{ 
    uint16 r2ByteBit;
	uint8 rByte;
	
    SPI_SendOneByte(0xFF);    
    rByte=SPI_ReceiveOneByte();  //从AT45DB041B通过SPI_SO口读入1BYTE数据
    
    return rByte;  
} 

//-----------------------------------------------------------------------*
//函数名: SPI_HostWriteByte                                              *
//功  能: 将1字节数据wByte由SPI_SI口写入AT45DB041B                       *
//参  数: uint8 wByte:待发送的数据                                       *
//返  回: 无                                                             *
//说  明: 调用了SPI_SendOneByte函数                                      *
//-----------------------------------------------------------------------* 
void SPI_HostWriteByte(uint8 wByte) 
{ 	
	SPI_SendOneByte(wByte);
} 

    //-----------------------------------------------------------------------* 
//名  称: EFlash_StatusRegisterRead                                      *
//功  能: 由SPI_SI口读AT45DB041B的状态字                                 *
//参  数: 无                                                             *
//返  回: 返回状态字                                                     *
//说    明:                                                              *
//Status Register Format:                                                *       
// -------------------------------------------------------------------   * 
// |   bit7 | bit6   | bit5  | bit4  | bit3  | bit2  | bit1  | bit0  |   *       
// |--------|--------|-------|-------|-------|-------|-------|-------|   *       
// |RDY/BUSY| COMP   |   0   |   1   |   1   |   1   |   X   |   X   |   *       
// -------------------------------------------------------------------   * 
// bit7 - 忙标记，0为忙1为空闲。                                         *       
//        当Status Register的位0移出之后，接下来的时钟脉冲序列将使SPI器件*   
//        继续将最新的状态字节送出。                                     *           
// bit6 - 标记最近一次Main Memory Page和Buffer的比较结果，0相同，1不同。 *       
// bit5 -                                                                *        
// bit4 -                                                                *        
// bit3 -                                                                *        
// bit2 - 这4位用来标记器件密度，对于AT45DB041B，这4位应该是0111，       *
//        一共能标记16种不同密度的器件。                                 *                  
// bit1 - 1=扇区保护使能；0=扇区保护禁用                                 *
// bit0 - 这2位暂时无效(主存页大小) 0=264字节/页；1=256字节/页           *                                              
//-----------------------------------------------------------------------* 
uint8 EFlash_StatusRegisterRead(void) 
{ 
    uint8 stateRegister; 

    CLR_SPI_CS(); //使能片选
    
    SPI_HostWriteByte(0xD7);            //发送读寄存器命令 
    stateRegister = SPI_HostReadByte(); //读取状态值

    SET_SPI_CS();//片选无效

    return stateRegister;  
} 

//-----------------------------------------------------------------------*
//函数名: EFlash_ContinueRead                                            *
//功  能: 由SPI_SI口读AT45DB041B中指定首地址的数据块到数组pHeader[]      *
//参  数: uint32 PA:   页地址，0~2047                                    *
//        uint32 BFA:  指定flash页中的起始读入地址                       *
//        uint8 *pHead:存入指定数据的首地址                              *
//        uint32 len:  读出指定数据的长度                                *
//返  回: 0=失败;1=成功                                                  *
//-----------------------------------------------------------------------* 
uint8 EFlash_ContinueRead(uint32 PA,uint32 BFA,uint8 *pHeader,uint32 len) 
{
    uint32 i=0; 
    uint8  stateRegister;
    uint8  rtnValue;

	rtnValue = 0;
    while(i++<255) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=255)
    	goto EFlash_ContinueRead_Exit;    //退出函数
    
    CLR_SPI_CS(); //使能片选 
   
    //发送队列读取命令页面大小为264字节
    //格式: 0xE8 + 0000 PA10-PA0 BFA8-BAF0 共4字节(地址的最高4位补0)
    SPI_HostWriteByte(0xE8);                     //连续队列读取命令
    SPI_HostWriteByte((uint8)(PA>>7));           //PA10-PA7(页地址高4位)
    SPI_HostWriteByte((uint8)((PA<<1)|(BFA>>8)));//PA6-PA0,BFA8(页地址低7位,页内地址高1位)
    SPI_HostWriteByte((uint8)BFA);               //BFA7-BFA0(页内地址低8位)
     /*
    //二进制 页面大小为256字节   
    SPI_HostWriteByte(0xE8); 
    SPI_HostWriteByte((uint8)(PA>>8));   //
	SPI_HostWriteByte((uint8)(PA)); //
	SPI_HostWriteByte(BFA);  //
    */
    
    
    
    //发送4字节任意码主要是为了给芯片初始化读操作时间的
    //在此之后，再变化时钟就可以读取数据了
    for(i=0;i<4;i++) 
    { 
        SPI_HostWriteByte(0x00); //4字节任意码
    } 

	//读取指定长度数据 
    for(i=0;i<len;i++) 
    { 
        pHeader[i] = SPI_HostReadByte();//读取1字节数据
    } 
    
    SET_SPI_CS(); //片选无效 
    
EFlash_ContinueRead_Exit:
	return rtnValue;    
} 

//-----------------------------------------------------------------------*
//函数名: EFlash_HostFlashToBuffer                                       *
//功  能: 将FLASH中的数据传送到BUFFER中                                  *
//参  数: uint8  bufferNo:   选择缓存区 0 或者 1                         *
//        uint32 PA:   页地址，0~2047                                    *
//返  回: 0=失败;1=成功                                                  *
//-----------------------------------------------------------------------*
uint8 EFlash_HostFlashToBuffer(uint8 bufferNo,uint32 PA) 
{ 
    uint32 i=0;
    uint8  stateRegister; 
    uint8  rtnValue;
    
	rtnValue = 0;
    while(i++<255) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=255)
    	goto EFlash_HostFlashToBuffer_Exit; //退出函数
    
    Delay_1us();//延时1us
    
    CLR_SPI_CS(); //片选使能 
    
    switch(bufferNo)    //根据不同的缓冲区号选择不同的命令
    { 
        case 1:
            SPI_HostWriteByte(0x84);
            break; 
        case 2:
            SPI_HostWriteByte(0x87);
            break;
        default:
            SPI_HostWriteByte(0x84);
            break; 
    } 
    SPI_HostWriteByte((uint8)(PA>>7));        //PA10-PA7(页地址高4位)      
    SPI_HostWriteByte((uint8)((PA<<1)|0x01)); //PA6-PA0,BFA8(页地址低7位,页内地址高1位)
    SPI_HostWriteByte(0x00);                  //发送任意值
    
    SET_SPI_CS();//片选无效 

    Delay_1us();//延时1us

EFlash_HostFlashToBuffer_Exit:
	return rtnValue;	    
} 

//-----------------------------------------------------------------------*
//函数名: EFlash_BufferRead                                              *
//功  能: 读BUFFER中指定首地址的数据块到数组pHeader[]                    *
//参  数: uint8  bufferNo:   选择缓存区 0 或者 1                         *
//        uint32 BFA:  BUFFER中的起始地址，0~263                         *
//        uint8 *pHead: 待写入数据的首地址                               *
//        uint32 len:  待存数据的长度1~264                               *
//返  回: 0=失败;1=成功                                                  *
//-----------------------------------------------------------------------*
uint8 EFlash_BufferRead(uint8 bufferNo,uint32 BFA,uint8 *pHeader,uint32 len) 
{ 
    uint32 i=0; 
    uint8  stateRegister; 
    uint8  rtnValue;
    
	rtnValue = 0;
    while(i++<255) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=255)
    	goto EFlash_BufferRead_Exit;
    
    CLR_SPI_CS();  //片选使能          
    switch(bufferNo)  //根据不同的缓冲区号选择不同的命令
    { 
        case 1:
            SPI_HostWriteByte(0x84);//选择缓冲1
            break; 
        case 2:
            SPI_HostWriteByte(0x87);//选择缓冲2
            break; 
        default:
        	SPI_HostWriteByte(0x84);//
        	break;
    } 
    SPI_HostWriteByte(0x00); 
    SPI_HostWriteByte((uint8)(BFA>>8));  //地址第9位
    SPI_HostWriteByte((uint8)BFA);       //地址低8位
    for(i=0;i<len;i++) 
    { 
        pHeader[i] = SPI_HostReadByte(); 
    } 
    SET_SPI_CS();//片选无效 
    
 EFlash_BufferRead_Exit:
 	return rtnValue;    
} 

//-----------------------------------------------------------------------*
//函数名: EFlash_BufferWrite                                             *
//功  能: 将指定数据写入从某个地址（0~263）开始的BUFFER中                *
//参  数: uint8  bufferNo: 选择BUFFER，01H选择BUFFER1，02H选择BUFFER 2   *         
//        uint32 BFA:  BUFFER中的起始地址，0~263                         *
//        uint8 *pHead: 待写入数据的首地址                               *
//        uint32 len:  待存数据的长度1~264                               *
//返  回: 0=失败;1=成功                                                  *
//-----------------------------------------------------------------------* 
uint8 EFlash_BufferWrite(uint8 bufferNo,uint32 BFA,uint8 *pHeader,uint32 len) 
{ 
    uint32 i=0; 
	uint8  stateRegister; 
    uint8  rtnValue;
    
	rtnValue = 0;
    while(i++<255) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=255)
    	goto EFlash_BufferWrite_Exit;
    
    CLR_SPI_CS(); //片选使能

    switch(bufferNo)//根据不同的缓冲区号选择不同的命令 
    { 
        case 1:
            SPI_HostWriteByte(0x84);
            break; 
        case 2:
            SPI_HostWriteByte(0x87);
            break;
        default:
        	SPI_HostWriteByte(0x84);//
        	break; 
    } 
    
    SPI_HostWriteByte(0x00); 
    SPI_HostWriteByte((unsigned char)(BFA>>8)); //地址第9位
    SPI_HostWriteByte((unsigned char)BFA);      //地址低8位
    
    for(i=0;i<len;i++) 
    { 
        SPI_HostWriteByte(pHeader[i]); 
    } 
    
    SET_SPI_CS(); //片选无效
    
    Delay_10us();//延时10us 
    
EFlash_BufferWrite_Exit:
	return rtnValue;   
} 

//-----------------------------------------------------------------------*
//函数名: EFlash_ProgramFlash                                            *
//功  能: 将长度为len个字节数组pHeader[]写入到AT45DB041B                 *
//参  数: uint8  bufferNo:   选择缓存区 0 或者 1                         *
//        uint32 PA:   页地址，0~2047                                    *
//        uint32 BFA:  指定flash页中的起始读入地址                       *
//        uint8 *pHead: 存放待写入的数组首地址                           *
//        uint32 len:  要写入的数据长度                                  *
//返  回: 0=失败;1=成功                                                  *
//-----------------------------------------------------------------------*
uint8 EFlash_ProgramFlash(uint8 bufferNo,uint32 PA,uint32 BFA,uint8 *pHeader,uint32 len) 
{ 
    uint32 i=0;
    uint8  stateRegister; 
    uint8  rtnValue;

    //将长度为len,首地址为pHeader的数写入以BFA为首地址的缓冲区中 
    rtnValue = EFlash_BufferWrite(bufferNo,BFA,pHeader,len); 
    if(0==rtnValue)
    	goto ProgramFlash_Exit;	
    
    //等待 AT45DB041B 的ready 
    while(i++<1000) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=1000)
    	goto ProgramFlash_Exit;

    CLR_SPI_CS();//使能片选
    
    //执行命令--带自擦除的缓存内容写主存     
    //选择缓冲区           
    switch(bufferNo) 
    { 
        case 1:
            SPI_HostWriteByte(0x83);//缓冲1的命令
            break; 
        case 2:
            SPI_HostWriteByte(0x86);//缓冲2的命令
            break; 
    } 
    
    //页地址大小为 264字节
    SPI_HostWriteByte((uint8)(PA>>7)); //页地址高4为
    SPI_HostWriteByte((uint8)(PA<<1)); //页地址低7位
    SPI_HostWriteByte(0x00); //因为是整页写入，故页内地址为0
    /*
    //二进制  页地址大小为 256字节
    SPI_HostWriteByte((uint8)(PA>>8)); //
    SPI_HostWriteByte((uint8)(PA)); //
    SPI_HostWriteByte(0x00); //因为是整页写入，故页内地址为0
    */
    
    SET_SPI_CS(); //片选无效
    
    delay_ms(10); //
    
ProgramFlash_Exit:
	return rtnValue;    
}

//-----------------------------------------------------------------------*
//函数名: EFlash_setReadprotectReg                                       *
//功  能: 读取扇区保护寄存器的值                                         *
//参  数: uint8 *pHead: 读取的扇区(0-7)保护寄存器的值                    *
//返  回: 0=失败;1=成功                                                  *
//-----------------------------------------------------------------------* 
uint8 EFlash_setReadprotectReg(uint8 *pHeader) 
{
    uint32 i=0;
    uint8  stateRegister; 
    uint8  rtnValue;
    
	rtnValue = 0;
    while(i++<255) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=255)
    	goto EFlash_setReadprotectReg_Exit;
     
    CLR_SPI_CS(); //使能片选

	//发送读扇区保护寄存器命令
    SPI_HostWriteByte(0x32); //读扇区保护寄存器命令
    SPI_HostWriteByte(0x55); //虚拟码
    SPI_HostWriteByte(0x55); //虚拟码
    SPI_HostWriteByte(0x55); //虚拟码
    
	//读取扇区(0-7)保护寄存器的值
    for(i=0;i<8;i++) 
    { 
    	pHeader[i] = SPI_HostReadByte(); //读1字节数据 
    } 
    SET_SPI_CS(); //片选无效

EFlash_setReadprotectReg_Exit:
	return rtnValue;
} 
//-----------------------------------------------------------------------*
//函数名: EFlash_ReadSecurityReg                                         *
//功  能: 读安全寄存器                                                   *
//参  数: uint8 *pHead: 读取的安全寄存器的值                             *
//返  回: 0=失败;1=成功                                                  *
//-----------------------------------------------------------------------*
uint8 EFlash_ReadSecurityReg(uint8 *pHeader) 
{
    uint32 i=0; 
    uint8  stateRegister; 
    uint8  rtnValue;
    
	rtnValue = 0;
    while(i++<255) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=255)
    	goto EFlash_ReadSecurityReg_Exit;

    CLR_SPI_CS(); //使能片选
    
    //发送读安全寄存器命令
    SPI_HostWriteByte(0x77); //读安全寄存器命令
    SPI_HostWriteByte(0x00); //虚拟码(任意码)
    SPI_HostWriteByte(0x00); //虚拟码(任意码)
    SPI_HostWriteByte(0x00); //虚拟码(任意码)
    
    //读取安全寄存器的值，共128字节
    //前64字节为单次可编程用户空间，后64字节为产品唯一号
    for(i=0;i<64;i++) 
    { 
        pHeader[i]=SPI_HostReadByte();//读1字节数据 
    } 
    
    SET_SPI_CS(); //片选无效
    
EFlash_ReadSecurityReg_Exit:
	return rtnValue;    
} 

//-----------------------------------------------------------------------*
//函数名: EFlash_WriteSecurityReg                                        *
//功  能: 写安全寄存器                                                   *
//参  数: uint8 *pHead: 待写入的安全寄存器的值                           *
//返  回: 0=失败;1=成功                                                  *
//-----------------------------------------------------------------------* 
uint8 EFlash_WriteSecurityReg(uint8 *pHeader) 
{
	uint32 i=0; 
	uint8  stateRegister; 
    uint8  rtnValue;
    
	rtnValue = 0;
    while(i++<255) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=255)
    	goto EFlash_WriteSecurityReg_Exit;
    
    CLR_SPI_CS(); //使能片选
    
    //发送烧写安全寄存器命令
    SPI_HostWriteByte(0x9B); //
    SPI_HostWriteByte(0x00); //
    SPI_HostWriteByte(0x00); //
    SPI_HostWriteByte(0x00); //
    
    //设置安全寄存器的值
    for(i=0;i<64;i++) 
    { 
        SPI_HostWriteByte(pHeader[i]); 
    } 
    
    SET_SPI_CS(); //片选无效
    delay_ms(1);//延时
    
EFlash_WriteSecurityReg_Exit:    
    return rtnValue;
} 
//-----------------------------------------------------------------------*
//函数名: EFlash_SetPage256                                              *
//功  能: 设置页大小为: 256字节/页                                       *
//参  数: 无                                                             *
//返  回: 0=失败;1=成功                                                  *
//说  明: 该操作只能执行一次,执行成功后，芯片重新上电                    *
//-----------------------------------------------------------------------* 
uint8 EFlash_SetPage256(void) 
{
	uint32 i=0; 
	uint8  stateRegister; 
    uint8  rtnValue;
    
	rtnValue = 0;
    while(i++<255) 
    { 
    	stateRegister = EFlash_StatusRegisterRead();//读状态寄存器
        if(stateRegister & 0x80)//空闲
        {
        	rtnValue = 1; 
            break; 
        } 
    } 
    if(i>=255)
    	goto EFlash_SetPage256_Exit;
    
    CLR_SPI_CS(); //使能片选
    
    //二进制页大小配置
    SPI_HostWriteByte(0x3D); // 
    SPI_HostWriteByte(0x2A); //
    SPI_HostWriteByte(0x80); //
    SPI_HostWriteByte(0xA6); //

    SET_SPI_CS(); //片选无效
    delay_ms(1);//延时
    
EFlash_SetPage256_Exit:    
    return rtnValue;   
} 