/* Device Driver for SST39VF088 in generic C language Jerry Deng Silicon Storage Technology, Inc. Revision 1.0, Feb 2004 This code is for customer's reference ONLY and is provided AS IS, SST MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR PARTICULAR PURPOSE. IN NO EVENT SHALL SST BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES WITH RESPECT TO THE USE OF THIS CODE AND/OR SST PRODUCTS. SST39VF088 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 DefaultBaseAddress 0x0 /* default device base address for SST39VF1601C */ #define ChipEraseTime 1428571 /* maximum timeout of read cycles for chip-erase, 100ms/70ns */ #define BlockEraseTime 357143 /* maximum timeout of read cycles for sector-erase, 25ms/70ns */ #define SectorEraseTime 357143 /* maximum timeout of read cycles for sector-erase, 25ms/70ns */ #define ByteProgramTime 286 /* maximum timeout of read cycles for BYTE-program, 20us/70ns */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef BYTE typedef unsigned char BYTE; #endif #ifndef WORD typedef unsigned short WORD; #endif #ifndef U32 typedef unsigned long U32; #endif U32 BaseAddrs=DefaultBaseAddress; // 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. // The C code in this document contains the following routines in order: // Name Function BYTE Program_One_Byte(BYTE, U32); // Program one byte data into device BYTE Erase_One_Block(U32); // Erase one block (64KByte) BYTE Erase_One_Sector(U32); // Erase one sector(4KByte) BYTE Erase_Entire_Chip(void); // Erase the whole chip WORD Check_SST39VF088(void); // Check manufacturer ID and device ID BYTE Check_ToggleDQ6(U32, U32); // Wait until DQ6 stops toggling BYTE Check_DataPollingDQ7(U32, BYTE, U32);// Wait until DQ7 outputs true data void Delay_150_Nanosecond(void); // delay 150ns void Delay_1_Microsecond(void); // delay 1us /************************************************************************/ /* PROCEDURE: Program_One_Byte */ /* */ /* This procedure programs one byte of data into SST39VF088. */ /* */ /* NOTE: Prior to being programmed, the byte must be blank FFh state. */ /* */ /* Input: SrcByte Data byte to be written into SST39VF088. */ /* Dst DeSTination address where to be written into. */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ BYTE Program_One_Byte (BYTE SrcByte, U32 Dst) { BYTE ReturnStatus=TRUE; *(BYTE *) (BaseAddrs + 0xAAA) = 0xAA; // 1st write data AAH to device addr AAAH *(BYTE *) (BaseAddrs + 0x555) = 0x55; // 2nd write data 55H to device addr 555H *(BYTE *) (BaseAddrs + 0xAAA) = 0xA0; // 3rd write data A0H to device addr AAAH *(BYTE *) (BaseAddrs + Dst) = SrcByte; // 4th write data SrcByte into device address Dst // Then there are three ways to determine when internal operation will be ready: // First check DQ6, Secondly check DQ7, Last delay 20us. ReturnStatus = Check_ToggleDQ6(Dst, ByteProgramTime); // wait TOGGLE bit stops toggling // ReturnStatus = Check_DataPollingDQ7(Dst, SrcByte, ByteProgramTime); // wait until DQ7 outputs true data bit return ReturnStatus; } /************************************************************************/ /* PROCEDURE: Erase_One_Block */ /* */ /* This procedure erases one block with total 64KByte. */ /* */ /* Input: Dst Address of Block to be erased. */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ BYTE Erase_One_Block (U32 Dst) { BYTE ReturnStatus=TRUE; *(BYTE *) (BaseAddrs + 0xAAA) = 0xAA; // 1st write data AAH to device addr AAAH *(BYTE *) (BaseAddrs + 0x555) = 0x55; // 2nd write data 55H to device addr 555H *(BYTE *) (BaseAddrs + 0xAAA) = 0x80; // 3rd write data 80H to device addr AAAH *(BYTE *) (BaseAddrs + 0xAAA) = 0xAA; // 4th write data AAH to device addr AAAH *(BYTE *) (BaseAddrs + 0x555) = 0x55; // 5th write data 55H to device addr 555H *(BYTE *) (BaseAddrs + Dst ) = 0x30; // 6th write data 30H to device block addr Dst // Then there are three ways to determine when internal operation will be ready: // First check DQ6, Secondly check DQ7, Last delay 25ms. // ReturnStatus = Check_ToggleDQ6(Dst, BlockEraseTime); // wait TOGGLE bit stops toggling ReturnStatus = Check_DataPollingDQ7(Dst, 0xFF, BlockEraseTime); // wait until DQ7 outputs 1 return ReturnStatus; } /************************************************************************/ /* PROCEDURE: Erase_One_Sector */ /* */ /* This procedure erases one sector with total 4KByte. */ /* */ /* Input: Dst Address of Sector to be erased. */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ BYTE Erase_One_Sector(U32 Dst) { BYTE ReturnStatus=TRUE; *(BYTE *) (BaseAddrs + 0xAAA) = 0xAA; // 1st write data AAH to device addr AAAH *(BYTE *) (BaseAddrs + 0x555) = 0x55; // 2nd write data 55H to device addr 555H *(BYTE *) (BaseAddrs + 0xAAA) = 0x80; // 3rd write data 80H to device addr AAAH *(BYTE *) (BaseAddrs + 0xAAA) = 0xAA; // 4th write data AAH to device addr AAAH *(BYTE *) (BaseAddrs + 0x555) = 0x55; // 5th write data 55H to device addr 555H *(BYTE *) (BaseAddrs + Dst ) = 0x50; // 6th write data 50H to device sector addr Dst // Then there are three ways to determine when internal operation will be ready: // First check DQ6, Secondly check DQ7, Last delay 25ms. // ReturnStatus = Check_ToggleDQ6(Dst,SectorEraseTime); // wait TOGGLE bit stops toggling ReturnStatus = Check_DataPollingDQ7(Dst, 0xFF, SectorEraseTime); // wait until DQ7 outputs 1 return ReturnStatus; } /************************************************************************/ /* PROCEDURE: Erase_Entire_Chip */ /* */ /* This procedure erases the entire chip. */ /* */ /* Input: NONE. */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ BYTE Erase_Entire_Chip(void) { BYTE ReturnStatus=TRUE; *(BYTE *) (BaseAddrs + 0xAAA) = 0xAA; // write data AAH to device addr AAAH *(BYTE *) (BaseAddrs + 0x555) = 0x55; // write data 55H to device addr 555H *(BYTE *) (BaseAddrs + 0xAAA) = 0x80; // write data 80H to device addr AAAH *(BYTE *) (BaseAddrs + 0xAAA) = 0xAA; // write data AAH to device addr AAAH *(BYTE *) (BaseAddrs + 0x555) = 0x55; // write data 55H to device addr 555H *(BYTE *) (BaseAddrs + 0xAAA) = 0x10; // write data 10H to device addr AAAH // Then there are three ways to determine when internal operation will be ready: // First check DQ6, Secondly check DQ7, Last delay 100ms. // ReturnStatus = Check_ToggleDQ6(0, ChipEraseTime); // wait TOGGLE bit stops toggling ReturnStatus = Check_DataPollingDQ7(0, 0xFF, ChipEraseTime); // wait until DQ7 outputs 1 return ReturnStatus; } /************************************************************************/ /* PROCEDURE: Check_SST39VF088 */ /* */ /* This procedure checks if it's SST39VF088 8 Mbit Multi-Purpose Flash. */ /* */ /* Input: NONE */ /* */ /* Output: BFD8h for SST39VF088, */ /* Any other value indicates non SST39VF088. */ /* High byte returns vendor ID, low byte is device ID. */ /************************************************************************/ WORD Check_SST39VF088(void) { WORD ReturnStatus=0; // Issue Software ID Entry command to SST39VF088 *(BYTE *) (BaseAddrs + 0xAAA) = 0xAA; // 1st write data AAH to device addr AAAH *(BYTE *) (BaseAddrs + 0x555) = 0x55; // 2nd write data 55H to device addr 555H *(BYTE *) (BaseAddrs + 0xAAA) = 0x90; // 3rd write data 90H to device addr AAAH Delay_150_Nanosecond(); // delay Tida (max. 150ns) for SST39VF088 ReturnStatus = (*(BYTE *) (BaseAddrs + 0))<<8 |(*(BYTE *) (BaseAddrs + 1)); // Issue Software ID Exit command to put SST39VF088 into normal read mode. *(BYTE *) (BaseAddrs + 0x12345) = 0xF0; // write data F0H into any device addr such as 12345H Delay_150_Nanosecond(); // then delay Tida (max. 150ns) for SST39VF088 return ReturnStatus; } /************************************************************************/ /* PROCEDURE: Check_ToggleDQ6 */ /* */ /* During the internal erase/program, any consecutive read operation */ /* on DQ6 will produce alternating 0's and 1's i.e. toggling between */ /* 0 and 1. When the operation is completed, DQ6 will stop toggling. */ /* After 1us bus recovery time, the device is ready for next operation. */ /* */ /* Input: Dst Any valid address within device. */ /* MaxCycles Maximum read cycles allowed for this operation. */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ BYTE Check_ToggleDQ6(U32 Dst, U32 MaxCycles) { BYTE CurrData, PreData; U32 TimeOut = 0; PreData = *(BYTE *) (BaseAddrs + Dst); // read data PreData = PreData & 0x40; // get DQ6 while (TimeOut < MaxCycles) // check if time-out { CurrData = *(BYTE *) (BaseAddrs + Dst); // read again CurrData = CurrData & 0x40; // retrieve bit DQ6 if (PreData == CurrData) { Delay_1_Microsecond( ); // delay 1us for bus recovery return TRUE; // return true if DQ6 stops toggling. } PreData = CurrData; TimeOut++; } return FALSE; // timeout error } /************************************************************************/ /* PROCEDURE: Check_DataPollingDQ7 */ /* */ /* During the internal program, 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 erase, DQ7 will output 0 during busy of internal operation. */ /* DQ7 will ouput 1 once the internal erase operation is completed. */ /* */ /* Input: Dst Any valid address within device. */ /* TrueData This is the original (true) data. */ /* MaxCycles Maximum read cycles allowed for this operation. */ /* */ /* Output: TRUE if success, otherwise FALSE if timeout. */ /************************************************************************/ BYTE Check_DataPollingDQ7(U32 Dst, BYTE TrueData, U32 MaxCycles) { BYTE CurrData; U32 Timeout = 0; TrueData = TrueData & 0x80; // keep DQ7 only while (Timeout < MaxCycles) // compare if timeout {CurrData = *(BYTE *) (BaseAddrs + Dst); // read data BYTE. CurrData = CurrData & 0x80; // get bit DQ7 if (CurrData == TrueData) {Delay_1_Microsecond( ); // delay 1us for bus recovery return TRUE; // return TRUE if DQ7 outputs true data. } Timeout++; } return FALSE; // otherwise, return FALSE if timeout error. } void Delay_150_Nanosecond(void) // delay 150ns. {for(int i=0; i<10; i++); // change the number 10 according to your system speed. } void Delay_1_Microsecond(void) // delay 1us {for(int i=0; i<70; i++); // change number 70 according to your system speed. }