/* Copyright Silicon Storage Technology, Inc. (SST), 1989-2003 Device Driver for SST39VF010 in generic C language Jerry Deng, Silicon Storage Technology, Inc. Revision 2.0, December, 2003 ABOUT THE SOFTWARE This is example of software device driver for SST39VF010, 1 Mbit Multi-Purpose Flash. The driver is written in generic C language, hoping it can be used in as many application systems as possible. Extensive comments are included in each routine to describe its function and usage. SST39VF010 datasheet should be reviewed in conjunction with this code to completely understand the operation of this device. Customer may need to change the delay numbers in subroutines Delay_150_Nanosecond( ) and Delay_1_Microsecond( ) according to application system's speed in order to get highest write performance. ------------------------------------------------------------------ */ #define FALSE 0 #define TRUE 1 typedef unsigned char BYTE; typedef unsigned short int WORD; typedef unsigned long DWORD; #define DeviceBaseAddress 0x0 /* default device base address for SST39VF010 */ #define ChipEraseTime 2222222 /* maximum timeout of read cycles for chip-erase, 100ms/45ns */ #define SectorEraseTime 555555 /* maximum timeout of read cycles for sector-erase, 25ms/45ns */ #define ByteProgramTime 445 /* maximum timeout of read cycles for byte-program, 20us/45ns */ DWORD BaseAddrs=DeviceBaseAddress; // this is a globe variable to keep the device base address // In some cases, system will assign a device base address for flash only at run time. // This is the reason that we define BaseAddrs as a variable rather than a CONSTANT. // This device driver contains the following routines, in this order: // Name Function WORD Check_SST_39VF010(void); // Check manufacturer ID and device ID WORD Erase_Entire_Chip(void); // Erase all contents of the whole chip WORD Erase_One_Sector(DWORD); // Erase one sector (4096 bytes) WORD Program_One_Byte(BYTE, DWORD); // Program one byte data into device WORD Check_Toggle_Ready(DWORD, DWORD); // Check Toggle bit DQ6 until it stops toggling WORD Check_Data_Polling(DWORD, BYTE, DWORD); // Check Data# polling bit DQ7 until it shows true data void Delay_150_Nanosecond(void); // Delay 150ns. void Delay_1_Microsecond(void); // Delay 1us /************************************************************************/ /* PROCEDURE: Check_SST_39VF010 */ /* */ /* This procedure decides whether a physical hardware device has a */ /* SST39VF010 1 Mbit Multi-Purpose Flash installed or not. */ /* */ /* Input: */ /* None */ /* */ /* Output: */ /* BFD5h for SST39VF010. */ /* Any other value indicates non SST39VF010, */ /* high byte of returned value is vendor ID, low byte is device ID. */ /************************************************************************/ WORD Check_SST_39VF010(void) { BYTE Vendor_ID; BYTE Device_ID; WORD ReturnStatus; // there are three mandatory writing cycles in order to enter into Software ID Entry mode *(BYTE *)(BaseAddrs + 0x5555) = 0xAA; /* 1st cycle, writing data AAh into device physical address 5555h */ *(BYTE *)(BaseAddrs + 0x2AAA) = 0x55; /* 2nd cycle, writing data 55h into device physical address 2AAAh */ *(BYTE *)(BaseAddrs + 0x5555) = 0x90; /* 3rd cycle, writing data 90h into device physical address 5555h */ Delay_150_Nanosecond( ); // there is 150ns delay before device is ready to output ID. // now the device is ready to read both manufacturer ID and device ID. Vendor_ID = *(BYTE *)(BaseAddrs + 0); // read manufacturer ID, should be BFh for SST device Device_ID = *(BYTE *)(BaseAddrs + 1); // read device ID, should be D5h for SST39VF010 ReturnStatus = Vendor_ID * 256 + Device_ID; // issue the Soffware Product ID Exit command for SST39VF010 to return to normal read mode */ // there are two equivalent commands of Software ID Exit, // the simpler one is 1 cycle of writing F0h into any valid device address such as 1234h. // the alternate one is 3 cycles, see example code below. *(BYTE *)(BaseAddrs + 0x1234) = 0xF0; // *(BYTE *)(BaseAddrs + 0x5555) = 0xAA; /* 1st cycle, writing data AAh into device physical address 5555h */ // *(BYTE *)(BaseAddrs + 0x2AAA) = 0x55; /* 2nd cycle, writing data 55h into device physical address 2AAAh */ // *(BYTE *)(BaseAddrs + 0x5555) = 0xF0; /* 3rd cycle, writing data F0h into device physical address 5555h */ // Again the device needs 150ns to exit Software ID mode. Delay_150_Nanosecond( ); return ReturnStatus; } /*************************************************************************/ /* PROCEDURE: Erase_Entire_Chip */ /* */ /* This procedure can be used to erase the entire chip. */ /* */ /* Input: none */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /* */ /************************************************************************/ WORD Erase_Entire_Chip(void) { WORD ReturnStatus=TRUE; *(BYTE *)(BaseAddrs + 0x5555) = 0xAA; /* 1st cycle, writing data AAh into device physical address 5555h */ *(BYTE *)(BaseAddrs + 0x2AAA) = 0x55; /* 2nd cycle, writing data 55h into device physical address 2AAAh */ *(BYTE *)(BaseAddrs + 0x5555) = 0x80; /* 3rd cycle, writing data 80h into device physical address 5555h */ *(BYTE *)(BaseAddrs + 0x5555) = 0xAA; /* 4th cycle, writing data AAh into device physical address 5555h */ *(BYTE *)(BaseAddrs + 0x2AAA) = 0x55; /* 5th cycle, writing data 55h into device physical address 2AAAh */ *(BYTE *)(BaseAddrs + 0x5555) = 0x10; /* 6th cycle, writing data 10h into device physical address 5555h */ // There are three different means to check the completion of SST39VF010 internal erase or programming operation. // The simplest but slowest one is delay a certain time no less than the maximum time allowed for that operation, // for example, the maximum chip-erase time is 100ms(worst case), so delay 100ms before exit this subroutine. // The 2nd one is checking Toggle bit DQ6, the device completes erase when DQ6 stops toggling of 0-1-0-1-0... // The last one is polling data bit DQ7. When DQ7 outputs 1, then chip-erase is done. ReturnStatus=Check_Toggle_Ready(0, ChipEraseTime); // any valid address is OK here. // The code below shows how to call Check_Data_Polling subroutine to determine the completion of chip-erase // ReturnStatus=Check_Data_Polling(0, 0x80, ChipEraseTime); Delay_1_Microsecond( ); // there's 1us delay for bus recovery after chip-erase. return ReturnStatus; } /************************************************************************/ /* PROCEDURE: Erase_One_Sector */ /* */ /* This procedure can be used to erase one sector (4096 bytes). */ /* */ /* Input: */ /* Dst Destination address of sector to be erased. */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ WORD Erase_One_Sector(DWORD Dst) { WORD ReturnStatus=TRUE; *(BYTE *)(BaseAddrs + 0x5555) = 0xAA; /* 1st cycle, writing data AAh into device physical address 5555h */ *(BYTE *)(BaseAddrs + 0x2AAA) = 0x55; /* 2nd cycle, writing data 55h into device physical address 2AAAh */ *(BYTE *)(BaseAddrs + 0x5555) = 0x80; /* 3rd cycle, writing data 80h into device physical address 5555h */ *(BYTE *)(BaseAddrs + 0x5555) = 0xAA; /* 4th cycle, writing data AAh into device physical address 5555h */ *(BYTE *)(BaseAddrs + 0x2AAA) = 0x55; /* 5th cycle, writing data 55h into device physical address 2AAAh */ *(BYTE *)(BaseAddrs + Dst ) = 0x30; /* 6th cycle, writing data 30h into device physical address at Dst*/ // There are three different means to check the completion of SST39VF010 internal erase or programming operation. // The simplest but slowest one is delay a certain time no less than the maximum time allowed for that operation, // for example, the maximum sector-erase time is 25ms(worst case), so delay 25ms before exit this subroutine. // The 2nd one is checking Toggle bit DQ6, the device completes erase when DQ6 stops toggling of 0-1-0-1-0... // The last one is polling data bit DQ7. When DQ7 outputs 1, then sector-erase is done. ReturnStatus=Check_Data_Polling (Dst, 0xFF, SectorEraseTime); // any data is OK as long as DQ7=1 for second parameter. // The code below shows how to call Check_Toggle_Ready subroutine to determine the completion of sector-erase // ReturnStatus=Check_Toggle_Ready(Dst, SectorEraseTime); Delay_1_Microsecond( ); // there's 1us delay for bus recovery after sector-erase. return ReturnStatus; } /************************************************************************/ /* PROCEDURE: Program_One_Byte */ /* */ /* This procedure can be used to program one byte of data to SST39VF010.*/ /* */ /* NOTE: It is VERY important the sector containing the byte to be */ /* programmed was ERASED first. */ /* */ /* Input: */ /* SrcByte The byte data to be written into SST39VF010. */ /* Dst DESTINATION address where data will be written into. */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ WORD Program_One_Byte (BYTE SrcByte, DWORD Dst) { WORD ReturnStatus=TRUE; *(BYTE *)(BaseAddrs + 0x5555) = 0xAA; /* 1st cycle, writing data AAh into device physical address 5555h */ *(BYTE *)(BaseAddrs + 0x2AAA) = 0x55; /* 2nd cycle, writing data 55h into device physical address 2AAAh */ *(BYTE *)(BaseAddrs + 0x5555) = 0xA0; /* 3rd cycle, writing data 80h into device physical address 5555h */ *(BYTE *)(BaseAddrs + Dst ) = SrcByte; /* 4th cycle, writing true data SrcByte into device physical address at Dst */ // There are three different means to check the completion of SST39VF010 internal erase or programming operation. // The simplest but slowest one is delay a certain time no less than the maximum time allowed for that operation, // for example, the maximum byte-program time is 20us(worst case), so delay 20us before exit this subroutine. // The 2nd one is checking Toggle bit DQ6, the device completes programming when DQ6 stops toggling of 0-1-0-1-0... // The last one is polling data bit DQ7. When DQ7 outputs true data, then byte-program is done. ReturnStatus=Check_Toggle_Ready(Dst, ByteProgramTime); /* wait for device to be ready. */ // The code below shows how to call Check_Data_Polling subroutine to determine the completion of byte-program // ReturnStatus=Check_Data_Polling(Dst, SrcByte, ByteProgramTime); Delay_1_Microsecond( ); // there's 1us delay for bus recovery after byte-programming. return ReturnStatus; } /************************************************************************/ /* PROCEDURE: Check_Toggle_Ready */ /* */ /* During the internal program/erase cycle, any consecutive read */ /* operation on DQ6 will produce alternating 0's and 1's i.e. toggling */ /* between 0 and 1. When the program/erase cycle is completed, DQ6 will */ /* stop toggling. After 1us bus recovery time, the device is ready for */ /* next operation. */ /* */ /* Input: */ /* Dst valid device address for desired operation */ /* */ /* MaxTime maximum time allowed for that specific operation */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ WORD Check_Toggle_Ready(DWORD Dst, DWORD MaxTime) { BYTE PreData, CurrData; DWORD TimeOut = 0; PreData = *(BYTE*)(BaseAddrs + Dst); // read data at device physical address Dst PreData = PreData & 0x40; // keep bit DQ6 only while (TimeOut < MaxTime) { CurrData = *(BYTE*)(BaseAddrs + Dst); // read again CurrData = CurrData & 0x40; // don't care other bits except DQ6 if (PreData == CurrData) return TRUE; // return true if DQ6 stops toggling PreData = CurrData; TimeOut++; } return FALSE; // return FALSE if timeout } /************************************************************************/ /* PROCEDURE: Check_Data_Polling */ /* */ /* During the internal program cycle, any attempt to read DQ7 of the */ /* last byte loaded will receive the complement of the true data. */ /* Once the program cycle is completed, DQ7 will show true data. */ /* For sector-erase and chip-erase, DQ7 will output 0 during busy of */ /* internal operation, it will output 1 once erase operation is done. */ /* */ /* Input: */ /* Dst valid destination address in SST39VF010 */ /* */ /* TrueData this is the original (true) data which */ /* SST39VF010 should output when it's ready */ /* */ /* MaxTime maximum time allowed for that specific operation */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ WORD Check_Data_Polling(DWORD Dst, BYTE TrueData, DWORD MaxTime) { BYTE CurrData; DWORD TimeOut = 0; TrueData = TrueData & 0x80; // don't care all bits other than DQ7 while (TimeOut < MaxTime) { CurrData = *(BYTE*)(BaseAddrs + Dst); // read data at device physical address Dst CurrData = CurrData & 0x80; // keep bit DQ7 only if (CurrData==TrueData) return TRUE; // return true if DQ7 outputs true data else TimeOut++; } return FALSE; // return FALSE if timeout } void Delay_150_Nanosecond(void) // delay 150ns. {for(int i=0; i<10; i++); // change the number according to your system speed. } void Delay_1_Microsecond(void) // delay 1us {for(int i=0; i<70; i++); // change number 70 according to application system speed. }