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.
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 }
Generated on Thu Jul 14 2022 21:23:10 by 1.7.2