Driver for SST 64Mbit flash (8Mbyte) model 25VF064C including higher level methods for rewrite and buffered read/write to help optimize I/O. Can also work with other 25 series flash and eeprom devices, requiring minor revisions for their capabilities.

Dependencies:   SPIDebug

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SST25VF064C.cpp Source File

SST25VF064C.cpp

00001 ///////////////////////////////////////////////////////////////////////////////
00002 // SST25VF064C.cpp - Flash driver
00003 //
00004 // COPYRIGHT (c) 2012 by David Van Wagner
00005 //
00006 // dave@vanwagner.org
00007 // http://techwithdave.blogspot.com
00008 //
00009 // License: Creative Commons Attribution-ShareAlike 3.0 Unported License
00010 // http://creativecommons.org/licenses/by-sa/3.0/
00011 ///////////////////////////////////////////////////////////////////////////////
00012 
00013 #include "SST25VF064C.h"
00014 //#include <assert.h>
00015 
00016 SST25VF064C::uint8 SST25VF064C::SID_buffer[SID_LEN];
00017 SST25VF064C::uint8 SST25VF064C::sector_buffer[SECTOR_LEN];
00018 SST25VF064C::int32 SST25VF064C::buffered_addr;
00019 bool SST25VF064C::buffered_erased;
00020 
00021 SST25VF064C::SST25VF064C(PinName mosi, PinName miso, PinName sclk, PinName cs, int frequency)
00022 {
00023 #ifdef SPIDEBUG
00024     this->cs = new CSDebug(cs);
00025 #else
00026     this->cs = new DigitalOut(cs);    
00027 #endif    
00028     this->cs->write(true);
00029     this->frequency = frequency;
00030 #ifdef SPIDEBUG    
00031     spi = new SPIDebug(mosi, miso, sclk);
00032 #else
00033     spi = new SPI(mosi, miso, sclk);    
00034 #endif    
00035     spi->format(8, 0);
00036     spi->frequency(frequency);
00037     buffered_addr = -1;
00038     buffered_erased = false;
00039     //assert(Id() == 0x4bbf);
00040     //assert(JEDECId() == 0xbf254b);
00041 }
00042 
00043 SST25VF064C::~SST25VF064C()
00044 {
00045     delete spi;
00046     delete cs;
00047 }
00048 
00049 SST25VF064C::uint16 SST25VF064C::Id()
00050 {
00051     cs->write(0);
00052     spi->write(0xab);
00053     spi->write(0);
00054     spi->write(0);
00055     spi->write(0);
00056     unsigned id = (spi->write(0) << 8) | spi->write(0);
00057     cs->write(1);
00058     return id;
00059 }
00060 
00061 SST25VF064C::uint32 SST25VF064C::JEDECId()
00062 {
00063     cs->write(0);
00064     spi->write(0x9f);
00065     unsigned id = (spi->write(0) << 16) | (spi->write(0) << 8) | spi->write(0);
00066     cs->write(1);
00067     return id;
00068 }
00069 
00070 SST25VF064C::uint8* SST25VF064C::SID()
00071 {
00072     cs->write(0);
00073     spi->write(0x88);
00074     spi->write(0); // address
00075     spi->write(0); // dummy
00076     for (int i=0; i<SID_LEN; ++i)
00077         SID_buffer[i] = spi->write(0);
00078     cs->write(1);
00079     return SID_buffer;
00080 }
00081 
00082 // Read Status Register    
00083 // bit 0 BUSY 1=Write in progress
00084 // bit 1 WEL  1=Write Enabled
00085 // bit 2 BP0  block write protection
00086 // bit 3 BP1  block write protection
00087 // bit 4 BP2  block write protection
00088 // bit 5 BP3  block write protection
00089 // bit 6 SEC  1=Security ID space locked
00090 // bit 7 BPL  1=BP0..BP3 are read-only, 0=r/w
00091 SST25VF064C::uint8 SST25VF064C::RDSR()
00092 {
00093     cs->write(0);
00094     spi->write(0x05);
00095     uint8 status = spi->write(0);
00096     cs->write(1);
00097     return status;
00098 }
00099 
00100 // Enable Write Status Register
00101 void SST25VF064C::EWSR()
00102 {
00103     cs->write(0);
00104     spi->write(0x50);
00105     cs->write(1);
00106 }
00107 
00108 // Write Status Register
00109 void SST25VF064C::WRSR(SST25VF064C::uint8 status)
00110 {
00111     cs->write(0);
00112     spi->write(0x01);
00113     spi->write(status);
00114     cs->write(1);
00115 }
00116 
00117 // Write Enable
00118 void SST25VF064C::WREN()
00119 {
00120     cs->write(0);
00121     spi->write(0x06);
00122     cs->write(1);
00123 }
00124 
00125 // Write Disable
00126 void SST25VF064C::WRDI()
00127 {
00128     cs->write(0);
00129     spi->write(0x04);
00130     cs->write(1);
00131 }
00132 
00133 bool SST25VF064C::BUSY()
00134 {
00135     return (RDSR() & 0x01) != 0;
00136 }
00137 
00138 bool SST25VF064C::WEL()
00139 {
00140     return (RDSR() & 0x02) != 0;
00141 }
00142 
00143 SST25VF064C::uint8 SST25VF064C::BP()
00144 {
00145     return (RDSR() >> 2) & 0xF;
00146 }
00147 
00148 bool SST25VF064C::SEC()
00149 {
00150     return (RDSR() & 0x40) != 0;
00151 }
00152 
00153 bool SST25VF064C::BPL()
00154 {
00155     return (RDSR() & 0x80) != 0;
00156 }
00157 
00158 void SST25VF064C::wait_while_busy()
00159 {
00160     while (BUSY())
00161         ;
00162 }
00163 
00164 SST25VF064C::uint8 SST25VF064C::read(SST25VF064C::int32 addr)
00165 {
00166     cs->write(0);
00167     spi->write(0x03);
00168     spi->write((addr >> 16) & 0xff);
00169     spi->write((addr >> 8) & 0xff);
00170     spi->write(addr & 0xff);
00171     uint8 data = spi->write(0);
00172     cs->write(1);
00173     return data;
00174 }
00175 
00176 bool SST25VF064C::read(SST25VF064C::int32 addr, SST25VF064C::uint8* dst, SST25VF064C::int32 len)
00177 {
00178     if (addr < 0 || addr >= MAX_ADDR || dst == 0 || len < 1 || addr+len > MAX_ADDR)
00179         return false;
00180 
00181     cs->write(0);
00182     spi->write(0x03);
00183     spi->write((addr >> 16) & 0xff);
00184     spi->write((addr >> 8) & 0xff);
00185     spi->write(addr & 0xff);
00186     for (int32 i=0; i<len; ++i)
00187         dst[i] = spi->write(0);
00188     cs->write(1);
00189     
00190     return true;
00191 }
00192 
00193 void SST25VF064C::hsread(SST25VF064C::int32 addr, SST25VF064C::uint8* dst, SST25VF064C::int32 len, int frequency)
00194 {
00195     int save_frequency = this->frequency;
00196     spi->frequency(frequency);
00197     cs->write(0);
00198     spi->write(0x0B);
00199     spi->write((addr >> 16) & 0xff);
00200     spi->write((addr >> 8) & 0xff);
00201     spi->write(addr & 0xff);
00202     spi->write(0); // dummy
00203     for (int32 i=0; i<len; ++i)
00204         dst[i] = spi->write(0);
00205     cs->write(1);
00206     spi->frequency(save_frequency);
00207 }
00208 
00209 void SST25VF064C::sector_erase_4k(SST25VF064C::int32 addr)
00210 {
00211     cs->write(0);
00212     spi->write(0x20);
00213     spi->write((uint8)(addr >> 16));
00214     spi->write((uint8)(addr >> 8));
00215     spi->write((uint8)addr);
00216     cs->write(1);
00217     wait_while_busy();
00218 }
00219 
00220 void SST25VF064C::block_erase_32k(SST25VF064C::int32 addr)
00221 {
00222     cs->write(0);
00223     spi->write(0x52);
00224     spi->write((uint8)(addr >> 16));
00225     spi->write((uint8)(addr >> 8));
00226     spi->write((uint8)addr);
00227     cs->write(1);
00228     wait_while_busy();
00229 }    
00230 
00231 void SST25VF064C::block_erase_64k(SST25VF064C::int32 addr)
00232 {
00233     cs->write(0);
00234     spi->write(0xd8);
00235     spi->write((uint8)(addr >> 16));
00236     spi->write((uint8)(addr >> 8));
00237     spi->write((uint8)addr);
00238     cs->write(1);
00239     wait_while_busy();
00240 }    
00241 
00242 void SST25VF064C::chip_erase()
00243 {
00244     cs->write(0);
00245     spi->write(0x60);
00246     cs->write(1);
00247     wait_while_busy();
00248 }
00249 
00250 bool SST25VF064C::page_program(SST25VF064C::int32 addr, SST25VF064C::uint8* write_buffer, short len)
00251 {
00252     // no point in writing FF as an empty sector already has those
00253     // (and if not empty, write won't succeed)
00254     bool skipped = false;
00255     while (len > 0 && *write_buffer == 0xFF)
00256     {
00257         ++write_buffer;
00258         --len;
00259         ++addr;
00260         skipped = true;
00261     }
00262     if (len == 0 && skipped)
00263         return true; // special case when succeeds when nothing to do
00264 
00265     if (len < 1 || len > 256)
00266         return false;
00267         
00268     // write enable
00269     WREN();
00270 
00271     cs->write(0);
00272     spi->write(0x02);
00273     spi->write((uint8)(addr >> 16));
00274     spi->write((uint8)(addr >> 8));
00275     spi->write((uint8)addr);
00276     for (short i=0; i<len; ++i)
00277         spi->write(write_buffer[i]);
00278     cs->write(1);
00279     wait_while_busy();
00280     
00281     return true;
00282 }
00283 
00284 bool SST25VF064C::write(SST25VF064C::int32 addr, SST25VF064C::uint8* write_buffer, SST25VF064C::int32 len)
00285 {
00286     if (len < 0 || addr < 0 || addr > MAX_ADDR || (addr+len > MAX_ADDR) || (addr+len < 0))
00287         return false;
00288 
00289     if (len == 0)
00290         return true; // done!
00291 
00292     // calculate first page size based on address and length
00293     int32 page_len = PAGE_LEN-(addr & (PAGE_LEN-1)); // remaining space in page
00294 
00295     while (len > 0)
00296     {
00297         if (page_len > len)
00298             page_len = len;
00299 
00300         page_program(addr, write_buffer, page_len);
00301 
00302         addr += page_len;        
00303         write_buffer += page_len;
00304         len -= page_len;
00305         page_len = PAGE_LEN;
00306     }
00307     
00308     return true;
00309 }    
00310 
00311 bool SST25VF064C::rewrite(SST25VF064C::int32 addr, SST25VF064C::uint8* write_buffer, SST25VF064C::int32 len)
00312 {
00313     // validate parameters
00314     if (len < 0 || addr < 0 || addr > MAX_ADDR || (addr+len > MAX_ADDR) || (addr+len < 0))
00315         return false;
00316 
00317     // are we done before we've started?
00318     if (len == 0)
00319         return true; // done!
00320 
00321     // calculate first sector size based on address and length
00322     int32 sector_len = SECTOR_LEN-(addr & (SECTOR_LEN-1)); // remaining space in sector
00323 
00324     while (len > 0)
00325     {
00326         // adjust if buffer than sector size
00327         if (sector_len > len)
00328             sector_len = len;
00329 
00330         // read existing data into entire sector buffer
00331         read(addr & (MAX_ADDR ^ (SECTOR_LEN-1)), sector_buffer, SECTOR_LEN);
00332         
00333         // overwrite with requested data at proper offset
00334         memcpy(sector_buffer + (addr & (SECTOR_LEN-1)), write_buffer, sector_len);
00335 
00336         // reset to beginning of sector
00337         addr = addr ^ (addr & (SECTOR_LEN-1));
00338         
00339         // erase sector
00340         WREN();
00341         sector_erase_4k(addr);            
00342         
00343         // rewrite the sector
00344         uint8 *p = sector_buffer;
00345         int sectors_in_page = SECTOR_LEN/PAGE_LEN;
00346         for (int i=0; i<sectors_in_page; ++i)
00347         {
00348             page_program(addr, p, PAGE_LEN);
00349             addr += PAGE_LEN;
00350             p += PAGE_LEN;
00351         }
00352 
00353         // adjust where we are, what left to do
00354         write_buffer += sector_len;
00355         len -= sector_len;
00356         sector_len = SECTOR_LEN;
00357     }
00358 
00359     wait_while_busy();
00360     
00361     return true;
00362 }    
00363 
00364 bool SST25VF064C::buffered_write(SST25VF064C::uint8 data)
00365 {
00366     int32& addr = buffered_addr;
00367 
00368     if (addr < 0 || addr > MAX_ADDR)
00369         return false;
00370 
00371     bool result = true;
00372 
00373     // if at sector boundary
00374     if ((addr & (SECTOR_LEN-1)) == 0 || !buffered_erased)
00375     {
00376         WREN();
00377         sector_erase_4k(addr ^ (addr & (SECTOR_LEN-1)));
00378         buffered_erased = true;
00379     }
00380 
00381     sector_buffer[addr & (SECTOR_LEN-1)] = data;
00382     
00383     ++addr;
00384 
00385     // if at sector boundary
00386     if ((addr & (SECTOR_LEN-1)) == 0)
00387     {
00388         // write sector
00389         result = write(addr-SECTOR_LEN, sector_buffer, SECTOR_LEN);
00390         buffered_erased = false;
00391 
00392         // read more
00393         if (addr != MAX_ADDR)
00394             result = result && read(addr, sector_buffer, SECTOR_LEN);
00395     }
00396     
00397     return result;
00398 }
00399 
00400 bool SST25VF064C::buffered_write(SST25VF064C::uint8* src, int len)
00401 {
00402     bool result = true;
00403     
00404     while (result && len > 0)
00405     {
00406         result = buffered_write(*src);
00407         --len;
00408         ++src;
00409     }
00410     
00411     return result;
00412 }
00413 
00414 SST25VF064C::uint8 SST25VF064C::buffered_read()
00415 {
00416     int32& addr = buffered_addr;
00417     if (addr < 0 || addr >= MAX_ADDR)
00418     {
00419         addr = -1;
00420         return 0xff;
00421     }
00422     uint8 data = sector_buffer[addr & (SECTOR_LEN-1)];
00423     ++addr;
00424     if ((addr & (SECTOR_LEN-1)) == 0)
00425     {
00426         if (buffered_erased)
00427         {
00428             write(addr-SECTOR_LEN, sector_buffer, SECTOR_LEN);
00429             buffered_erased = false;
00430         }
00431         if (addr == MAX_ADDR)
00432             addr = -1;
00433         else
00434             read(addr, sector_buffer, SECTOR_LEN);
00435     }
00436     return data;
00437 }
00438 
00439 bool SST25VF064C::buffered_read(SST25VF064C::uint8* dest, int len)
00440 {
00441     while (len > 0)
00442     {
00443         if (buffered_addr < 0 || buffered_addr >= MAX_ADDR)
00444             return false;
00445     
00446         *dest = buffered_read();
00447         --len;
00448         ++dest;
00449     }
00450     
00451     return true;
00452 }
00453 
00454 void SST25VF064C::buffered_seek(SST25VF064C::int32 addr)
00455 {
00456     if (buffered_erased)
00457         write(buffered_addr ^ (buffered_addr & (SECTOR_LEN-1)), sector_buffer, SECTOR_LEN);
00458     if (addr < 0 || addr >= MAX_ADDR)
00459     {
00460         buffered_addr = -1;
00461         buffered_erased = false;
00462     }
00463     else
00464     {
00465         read(addr ^ (addr & (SECTOR_LEN-1)), sector_buffer, SECTOR_LEN);
00466         buffered_addr = addr;
00467         buffered_erased = false;
00468     }
00469 }
00470 
00471 void SST25VF064C::buffered_sync()
00472 {
00473     int32& addr = buffered_addr;
00474 
00475     if (buffered_erased)
00476     {
00477         write(addr ^ (addr & (SECTOR_LEN-1)), sector_buffer, SECTOR_LEN);
00478         buffered_erased = false;
00479     }
00480 }