Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
