/************************************************/
/*SST39LF010 Flash Memory Configuration Code    */
/*PIC32MX795F512L-80I/PF                        */
/************************************************/

#include "xc.h"
#include "SST39LF010.h"
#include "Delay.h"

void SST39LF010_Init(void)
{
    //A16 address line
    TRISBbits.TRISB8 = 0;
    PORTBbits.RB8 = 0;
    
    //RF12 = /CS2
    TRISFbits.TRISF12 = 0;
    PORTFbits.RF12 = 1;
    
    //Get Flash Manufacturer ID
    //upper address lines
    PORTBbits.RB8 = 0;
    
    //RF12 = /CS2
    PORTFbits.RF12 = 0;
    
    //Get Chip ID
    //Enter sequence
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    PMADDR = 0x5555;
    PMDIN = 0x90;
    while(PMMODEbits.BUSY == 1);  
            
    Delay(100);
    
    //read device ID
    PMADDR = 0x0;
    //dummy read then real data
    Flash_MID = PMDIN;
    while(PMMODEbits.BUSY == 1); 
    
    Flash_MID = PMDIN;
    while(PMMODEbits.BUSY == 1);  
    
    //Exit sequence
    PMDIN = 0xf0;
    while(PMMODEbits.BUSY == 1);  
            
    Delay(100);
    
    PORTFbits.RF12 = 1;
    
///////////////////////////////////////
    
    //Get Flash Device ID
    //upper address lines
    PORTBbits.RB8 = 0;
    
    //RF12 = /CS2
    PORTFbits.RF12 = 0;
    
    //Get Chip ID
    //Enter sequence
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    PMADDR = 0x5555;
    PMDIN = 0x90;
    while(PMMODEbits.BUSY == 1);  
            
    Delay(100);
    
    //read device ID
    PMADDR = 0x1;
    //dummy read then real data
    Flash_DID = PMDIN;
    while(PMMODEbits.BUSY == 1); 
    
    Flash_DID = PMDIN;
    while(PMMODEbits.BUSY == 1);  
    
    //Exit sequence
    PMDIN = 0xf0;
    while(PMMODEbits.BUSY == 1);  
            
    Delay(100);
    
    PORTFbits.RF12 = 1;
    
    //Determine the Flash size
    switch(Flash_DID)
    {
      case 0xd5 :
            flash_size = 0x1ffff;
            break;
         
      case 0x6d :
            flash_size = 0x3ffff;
            break;
         
      case 0x7d :
            flash_size = 0x7ffff;
            break;
    }

    return;
}

void SST39LF010_GetMID(void)
{  
    //upper address lines
    PORTBbits.RB8 = 0;
    
    //RF12 = /CS2
    PORTFbits.RF12 = 0;
    
    //Get Chip ID
    //Enter sequence
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    PMADDR = 0x5555;
    PMDIN = 0x90;
    while(PMMODEbits.BUSY == 1);  
            
    Delay(100);
    
    //read device ID
    PMADDR = 0x0;
    //dummy read then real data
    Flash_MID = PMDIN;
    while(PMMODEbits.BUSY == 1); 
    
    Flash_MID = PMDIN;
    while(PMMODEbits.BUSY == 1);  
    
    //Exit sequence
    PMDIN = 0xf0;
    while(PMMODEbits.BUSY == 1);  
            
    Delay(100);
    
    PORTFbits.RF12 = 1;
    
    return;
}  
    
void SST39LF010_GetDID(void)
{  
    //upper address lines
    PORTBbits.RB8 = 0;
    
    //RF12 = /CS2
    PORTFbits.RF12 = 0;
    
    //Get Chip ID
    //Enter sequence
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    PMADDR = 0x5555;
    PMDIN = 0x90;
    while(PMMODEbits.BUSY == 1);  
            
    Delay(100);
    
    //read device ID
    PMADDR = 0x1;
    //dummy read then real data
    Flash_DID = PMDIN;
    while(PMMODEbits.BUSY == 1); 
    
    Flash_DID = PMDIN;
    while(PMMODEbits.BUSY == 1);  
    
    //Exit sequence
    PMDIN = 0xf0;
    while(PMMODEbits.BUSY == 1);  
            
    Delay(100);
    
    PORTFbits.RF12 = 1;
    
    //Determine the Flash size
    switch(Flash_DID)
    {
      case 0xd5 :
            flash_size = 0x1ffff;
            break;
         
      case 0x6d :
            flash_size = 0x3ffff;
            break;
         
      case 0x7d :
            flash_size = 0x7ffff;
            break;
    }
    
    return;
}  
    
void SST39LF010_RD(unsigned address_39LF010)
{       
    //A16 - above 0x10000
    if(address_39LF010 > 0xffff)
    {
        PORTBbits.RB8 = 1;
    }
    else
    {
        PORTBbits.RB8 = 0;
    }

    PMADDR = address_39LF010;
    
    ///CS2
    PORTFbits.RF12 = 0;
        
    //dummy read
    data_39LF010 = PMDIN;
    while(PMMODEbits.BUSY == 1);
   
    data_39LF010 = PMDIN;
    while(PMMODEbits.BUSY == 1);

    ///CS2
    PORTFbits.RF12 = 1;
    
    return;
}

void SST39LF010_WR(unsigned address_39LF010, uint8_t data_39LF010)
{        
    //A16 - above 0x10000
    if(address_39LF010 > 0xffff)
    {
        PORTBbits.RB8 = 1;
    }
    else
    {
        PORTBbits.RB8 = 0;
    }
    
    //Chip Enable - active low
    PORTFbits.RF12 = 0;
    
    //Enter sequence
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    PMADDR = 0x5555;
    PMDIN = 0xa0;
    while(PMMODEbits.BUSY == 1);  
            
    //write data
    PMADDR = address_39LF010;
    PMDIN = data_39LF010;
    while(PMMODEbits.BUSY == 1);  
    
    //Wait for end of program
    //using D7 - Data# polling
    while(data_39LF010 != PMDIN);
    
    //now we must verify at least 2 times
    //to prevent false rejection
    int i = PMDIN;
    while(i != data_39LF010)
    {
        i = PMDIN;
    }
    
    //Chip Enable - active low
    PORTFbits.RF12 = 1;
    
    return;
}

void SST39LF010_Sector_Erase(int erase_sector)
{  
    data_39LF010 = 0;
    
    erase_sector = erase_sector << 12;
    //Chip Enable - active low
    PORTFbits.RF12 = 0;
    
    //Enter sequence
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    PMADDR = 0x5555;
    PMDIN = 0x80;
    while(PMMODEbits.BUSY == 1);  
            
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    //Sector address
    PMADDR = erase_sector;
    PMDIN = 0x30;
    while(PMMODEbits.BUSY == 1);  
    
    while(data_39LF010  == 0)
    {
        data_39LF010 = PMDIN;
        data_39LF010 = data_39LF010 & 0x80;        
    }
    
    return;
}

void SST39LF010_Chip_Erase(void)
{  
    data_39LF010 = 0;
    
    //Chip Enable - active low
    PORTFbits.RF12 = 0;
    
    //Enter sequence
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    PMADDR = 0x5555;
    PMDIN = 0x80;
    while(PMMODEbits.BUSY == 1);  
            
    PMADDR = 0x5555;
    PMDIN = 0xaa;
    while(PMMODEbits.BUSY == 1);  
   
    PMADDR = 0x2aaa;
    PMDIN = 0x55;
    while(PMMODEbits.BUSY == 1);  
    
    PMADDR = 0x5555;
    PMDIN = 0x10;
    while(PMMODEbits.BUSY == 1);  
    
    while(data_39LF010  == 0)
    {
        data_39LF010 = PMDIN;
        data_39LF010 = data_39LF010 & 0x80;        
    }
    
    return;
}

void SST39LF010_Get_Bytes_Used(void)
{  
    unsigned i;
    Bytes_used = 0;
    
    for(i=0;i<=flash_size;i++)
    {
        SST39LF010_RD(i);
        if(data_39LF010 != 0xff)
        {
            Bytes_used++;
        }
    }
    
    return;
}
    




