Flash handler for M25P* chips with no Device ID.
Fork of flash25spi by
flash25spi.cpp
- Committer:
- Tomo2k
- Date:
- 2014-04-28
- Revision:
- 7:fae78b14f38f
- Parent:
- 6:94558d4243f8
- Child:
- 8:7b09546cb412
File content as of revision 7:fae78b14f38f:
/* This library is based on the Ser25lcxxx library by Hendrik Lipka * It was adapted to flash memory chips on 19.2.2011 by Klaus Steinhammer * It was further adapted to M25P* SPI Flash memory chips that do not * support the "RDID" device ID instructions on 25.03.2014 by Richard Thompson * * The BSD license also applies to this code - have fun. */ /* * Ser25lcxxx library * Copyright (c) 2010 Hendrik Lipka * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "flash25spi.h" #include "wait_api.h" //#define DEBUG struct dataBase { uint8_t signature; size_t memsize; size_t sectorsize; size_t pagesize; }; const struct dataBase devices[] = { //signature, memsize, sectorsize, pagesize { 0x10, 0x20000, 0x8000, 0x100 }, // M25P10-A Numonyx/ST { 0x11, 0x40000, 0x10000, 0x100 }, // M25P20 Numonyx/ST/Micron { 0x12, 0x80000, 0x10000, 0x100 }, // M25P40 Numonyx/ST { 0x00, 0x00, 0x00, 0x00}, // end of table }; // Instruction Set const uint8_t FLASH_WREN = 0x06; // Write Enable //const uint8_t FLASH_WRDI = 0x04; // Write Disable (Unused) //const uint8_t FLASH_RDID = 0x9F; // Read Device IDentification (not supported) const uint8_t FLASH_RDSR = 0x05; // Read Status Register const uint8_t FLASH_WRSR = 0x01; // Write Status Register const uint8_t FLASH_READ = 0x03; // Read Data Bytes //const uint8_t FLASH_FAST_READ = 0x0B; // Read Data Bytes Faster const uint8_t FLASH_PP = 0x02; // Page Program (max pagesize bytes) const uint8_t FLASH_SE = 0xD8; // Sector Erase const uint8_t FLASH_BE = 0xC7; // Bulk Erase (wipe complete system) const uint8_t FLASH_DP = 0xB9; // Deep Power Down (shutdown into very-low-power) const uint8_t FLASH_RES = 0xAB; // Wake Up and Read Electronic Signature #define HIGH(x) ((x&0xff0000)>>16) #define MID(x) ((x&0xff00)>>8) #define LOW(x) (x&0xff) FlashM25PSpi::FlashM25PSpi(SPI *spi, PinName enable) : _spi(spi) , _enable(enable) , _size(0) { _spi->format(8,3); _enable = 1; wait_us(1000); _enable = 0; wait_us(1); uint8_t chipSig; // Reset and Ask for chip signature _spi->write(FLASH_RES); _spi->write(0); // Dummy writes _spi->write(0); // Dummy writes _spi->write(0); // Dummy writes chipSig = _spi->write(0); // Get Electronic Signature wait_us(1); _enable = 1; unsigned int i = 0; while (_size == 0) { if (devices[i].memsize == 0) { // Nobody makes a memory of zero size #ifdef DEBUG printf("\r\nUnknown Flash Memory signature: %xh\r\n", chipSig); #endif return; } if (chipSig == devices[i].signature) { _size=devices[i].memsize; _sectorSize=devices[i].sectorsize; _pageSize=devices[i].pagesize; #ifdef DEBUG printf("\r\nFlash Memory Sig:%Xh : %u bytes Org: %x, %x\r\n", chipSig, _size, _sectorSize, _pageSize); #endif } else i++; } } FlashM25PSpi::~FlashM25PSpi() { // Shutdown the flash chip into lowest-power mode // Assumes no writes could be in progress _enable = 0; wait_us(1); _spi->write(FLASH_DP); wait_us(1); _enable = 1; } bool FlashM25PSpi::read(uint32_t startAddr, void* destination, size_t len) { // Check size if (startAddr + len > _size) return false; _enable = 0; wait_us(1); // Cast to char char *dest8 = (char*)destination; // Send address _spi->write(FLASH_READ); _spi->write(HIGH(startAddr)); _spi->write(MID(startAddr)); _spi->write(LOW(startAddr)); // Read into destination buffer while (len--) { *dest8++ = _spi->write(0); } wait_us(1); _enable = 1; return true; } bool FlashM25PSpi::write(uint32_t startAddr, const void* data, size_t len) { if (startAddr + len > _size) return false; // Cast to char char *data8 = (char*)data; size_t ofs = 0; while (ofs < len) { // calculate amount of data to write into current page size_t pageLen = _pageSize - ((startAddr + ofs) % _pageSize); if (ofs + pageLen > len) pageLen = len - ofs; // write single page if (!writePage(startAddr + ofs, data8 + ofs, pageLen)) return false; // Oh dear // and switch to next page ofs += pageLen; } return true; } bool FlashM25PSpi::writePage(uint32_t startAddr, const char* data, size_t len) { enableWrite(); _enable = 0; wait_us(1); _spi->write(FLASH_PP); _spi->write(HIGH(startAddr)); _spi->write(MID(startAddr)); _spi->write(LOW(startAddr)); // do real write for (unsigned int i=0; i<len; ++i) { _spi->write(data[i]); } wait_us(1); // disable to start physical write _enable = 1; waitForWrite(); return true; } void FlashM25PSpi::eraseSector(uint32_t addr) { addr &= ~(_sectorSize-1); enableWrite(); _enable = 0; wait_us(1); _spi->write(FLASH_SE); _spi->write(HIGH(addr)); _spi->write(MID(addr)); _spi->write(LOW(addr)); wait_us(1); _enable = 1; waitForWrite(); } void FlashM25PSpi::eraseMem() { enableWrite(); _enable = 0; wait_us(1); _spi->write(FLASH_BE); wait_us(1); _enable = 1; waitForWrite(); } int FlashM25PSpi::readStatus() { _enable = 0; wait_us(1); _spi->write(FLASH_RDSR); int status=_spi->write(0x00); wait_us(1); _enable = 1; return status; } void FlashM25PSpi::waitForWrite() { while (true) { if (0 == (readStatus()&1)) break; wait_us(10); } } void FlashM25PSpi::enableWrite() { _enable = 0; wait_us(1); _spi->write(FLASH_WREN); wait_us(1); _enable = 1; }