Richard Thompson / FlashM25PSpi

Dependencies:   RTOS_SPI_Clean

Fork of flash25spi by Klaus Steinhammer

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers flash25spi.cpp Source File

flash25spi.cpp

00001 /* This library is based on the Ser25lcxxx library by Hendrik Lipka
00002 * It was adapted to flash memory chips on 19.2.2011 by Klaus Steinhammer
00003 
00004 * It was further adapted to M25P* SPI Flash memory chips that do not
00005 * support the "RDID" device ID instructions on 25.03.2014 by Richard Thompson
00006 *
00007 * The BSD license also applies to this code - have fun.
00008 */
00009 
00010 /*
00011 * Ser25lcxxx library
00012 * Copyright (c) 2010 Hendrik Lipka
00013 *
00014 * Permission is hereby granted, free of charge, to any person obtaining a copy
00015 * of this software and associated documentation files (the "Software"), to deal
00016 * in the Software without restriction, including without limitation the rights
00017 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00018 * copies of the Software, and to permit persons to whom the Software is
00019 * furnished to do so, subject to the following conditions:
00020 *
00021 * The above copyright notice and this permission notice shall be included in
00022 * all copies or substantial portions of the Software.
00023 *
00024 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00025 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00026 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00027 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00028 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00029 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00030 * THE SOFTWARE.
00031 */
00032 
00033 
00034 #include "flash25spi.h"
00035 #include "wait_api.h"
00036 
00037 //#define DEBUG
00038 
00039 struct dataBase {
00040     uint8_t signature;
00041     size_t memsize;
00042     size_t sectorsize;
00043     size_t pagesize;
00044 };
00045 
00046 const struct dataBase devices[] = {
00047     //signature,   memsize,    sectorsize, pagesize
00048     {   0x10,       0x20000,    0x8000,     0x100   },  // M25P10-A Numonyx/ST
00049     {   0x11,       0x40000,    0x10000,    0x100   },  // M25P20   Numonyx/ST/Micron
00050     {   0x12,       0x80000,    0x10000,    0x100   },  // M25P40   Numonyx/ST
00051     {   0x00,       0x00,       0x00,       0x00},      // end of table
00052 };
00053 
00054 // Instruction Set
00055 const uint8_t FLASH_WREN = 0x06;    // Write Enable
00056 //const uint8_t FLASH_WRDI = 0x04;    // Write Disable (Unused)
00057 //const uint8_t FLASH_RDID = 0x9F;    // Read Device IDentification (not supported)
00058 const uint8_t FLASH_RDSR = 0x05;    // Read Status Register
00059 //const uint8_t FLASH_WRSR = 0x01;    // Write Status Register (not used)
00060 const uint8_t FLASH_READ = 0x03;    // Read Data Bytes
00061 //const uint8_t FLASH_FAST_READ = 0x0B;   // Read Data Bytes Faster
00062 const uint8_t FLASH_PP = 0x02;      // Page Program (max pagesize bytes)
00063 const uint8_t FLASH_SE = 0xD8;      // Sector Erase
00064 const uint8_t FLASH_BE = 0xC7;      // Bulk Erase (wipe complete system)
00065 const uint8_t FLASH_DP = 0xB9;      // Deep Power Down (shutdown into very-low-power)
00066 const uint8_t FLASH_RES = 0xAB;     // Wake Up and Read Electronic Signature
00067 
00068 #define HIGH(x) ((x&0xff0000)>>16)
00069 #define MID(x) ((x&0xff00)>>8)
00070 #define LOW(x) (x&0xff)
00071 
00072 
00073 FlashM25PSpi::FlashM25PSpi(RTOS_SPI *spi, PinName enable, int bits, int mode) :
00074     _spi(spi)
00075     , _enable(enable)
00076     , _size(0)
00077 {
00078     if (bits) _spi->format(bits, mode);
00079 
00080     _enable = 1;
00081     if (osKernelRunning()) {
00082         Thread::wait(1);
00083     } else {
00084         wait_us(1000);
00085     }
00086     _enable = 0;
00087     wait_us(1);
00088     uint8_t chipSig;
00089     // Reset and Ask for chip signature
00090     _spi->write(FLASH_RES);
00091     _spi->write(0); // Dummy writes
00092     _spi->write(0); // Dummy writes
00093     _spi->write(0); // Dummy writes
00094     chipSig = _spi->write(0); // Get Electronic Signature
00095     wait_us(1);
00096     _enable = 1;
00097 
00098     unsigned int i = 0;
00099     while (_size == 0) {
00100         if (devices[i].memsize == 0) {  // Nobody makes a memory of zero size
00101 #ifdef DEBUG
00102             printf("\r\nUnknown Flash Memory signature: %xh\r\n", chipSig);
00103 #endif
00104             return;
00105         }
00106         if (chipSig == devices[i].signature) {
00107             _size=devices[i].memsize;
00108             _sectorSize=devices[i].sectorsize;
00109             _pageSize=devices[i].pagesize;
00110 #ifdef DEBUG
00111             printf("\r\nFlash Memory Sig:%Xh : %u bytes Org: %x, %x\r\n",
00112                    chipSig, _size, _sectorSize, _pageSize);
00113 #endif
00114         } else
00115             i++;
00116     }
00117 }
00118 
00119 FlashM25PSpi::~FlashM25PSpi()
00120 {
00121     // Wait until chip finishes cycle
00122 //    waitForWrite();
00123     // Shutdown the flash chip into lowest-power mode
00124     _enable = 0;
00125     wait_us(1);
00126     _spi->write(FLASH_DP);
00127     wait_us(1);
00128     _enable = 1;
00129 }
00130 
00131 bool FlashM25PSpi::read(uint32_t startAddr, void* destination, size_t len)
00132 {
00133     // Check size
00134     if (startAddr + len > _size)
00135         return false;
00136     _enable = 0;
00137     wait_us(1);
00138 
00139     // Send address
00140     _spi->write(FLASH_READ);
00141     _spi->write(HIGH(startAddr));
00142     _spi->write(MID(startAddr));
00143     _spi->write(LOW(startAddr));
00144 
00145     uint8_t dummy = 0;
00146 
00147     // Bulk read into destination buffer (DMA)
00148     // Be sure to write the same dummy databyte repeatedly
00149     _spi->bulkReadWrite((uint8_t*)destination, &dummy, len, false);
00150 
00151     wait_us(1);
00152     _enable = 1;
00153     return true;
00154 }
00155 
00156 bool FlashM25PSpi::write(uint32_t startAddr, const void* data, size_t len)
00157 {
00158     if (startAddr + len > _size)
00159         return false;
00160 
00161     // Cast to uint8_t
00162     uint8_t *data8 = (uint8_t*)data;
00163 
00164     size_t ofs = 0;
00165     while (ofs < len) {
00166         // calculate amount of data to write into current page
00167         size_t pageLen = _pageSize - ((startAddr + ofs) % _pageSize);
00168         if (ofs + pageLen > len)
00169             pageLen = len - ofs;
00170         // write single page
00171         if (!writePage(startAddr + ofs, data8 + ofs, pageLen))
00172             return false;   // Oh dear
00173         // and switch to next page
00174         ofs += pageLen;
00175     }
00176     return true;
00177 }
00178 
00179 bool FlashM25PSpi::writePage(uint32_t startAddr, const uint8_t* data, size_t len)
00180 {
00181     enableWrite();
00182 
00183     _enable = 0;
00184     wait_us(1);
00185 
00186     _spi->write(FLASH_PP);
00187     _spi->write(HIGH(startAddr));
00188     _spi->write(MID(startAddr));
00189     _spi->write(LOW(startAddr));
00190 
00191     // Bulk write using DMA
00192     _spi->bulkWrite(data, len);
00193 
00194     wait_us(1);
00195     // disable to start physical write
00196     _enable = 1;
00197 
00198     waitForWrite();
00199 
00200     return true;
00201 }
00202 
00203 void FlashM25PSpi::eraseSector(uint32_t addr)
00204 {
00205     addr &= ~(_sectorSize-1);
00206 
00207     enableWrite();
00208     _enable = 0;
00209     wait_us(1);
00210     _spi->write(FLASH_SE);
00211     _spi->write(HIGH(addr));
00212     _spi->write(MID(addr));
00213     _spi->write(LOW(addr));
00214     wait_us(1);
00215     _enable = 1;
00216     waitForWrite();
00217 }
00218 
00219 void FlashM25PSpi::eraseMem()
00220 {
00221     enableWrite();
00222     _enable = 0;
00223     wait_us(1);
00224     _spi->write(FLASH_BE);
00225     wait_us(1);
00226     _enable = 1;
00227     waitForWrite();
00228 }
00229 
00230 int FlashM25PSpi::readStatus()
00231 {
00232     _enable = 0;
00233     wait_us(1);
00234     _spi->write(FLASH_RDSR);
00235     int status=_spi->write(0x00);
00236     wait_us(1);
00237     _enable = 1;
00238     return status;
00239 }
00240 
00241 void FlashM25PSpi::waitForWrite()
00242 {
00243     while (true) {
00244         // Allow something else to do some work
00245         Thread::yield();
00246         if (0 == (readStatus()&1)) return;
00247     }
00248 }
00249 
00250 void FlashM25PSpi::enableWrite()
00251 {
00252     _enable = 0;
00253     wait_us(1);
00254     _spi->write(FLASH_WREN);
00255     wait_us(1);
00256     _enable = 1;
00257 }