Flash handler for M25P* chips with no Device ID.
Fork of flash25spi by
Revision 3:318fabd6708c, committed 2014-04-25
- Comitter:
- Tomo2k
- Date:
- Fri Apr 25 12:25:08 2014 +0000
- Parent:
- 2:14c5db5e54df
- Child:
- 4:af870c53c0e9
- Commit message:
- Now supports two M25P* flash chips that do not have Device ID info
Changed in this revision
flash25spi.cpp | Show annotated file Show diff for this revision Revisions of this file |
flash25spi.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/flash25spi.cpp Sun Feb 20 11:16:27 2011 +0000 +++ b/flash25spi.cpp Fri Apr 25 12:25:08 2014 +0000 @@ -1,22 +1,26 @@ /* 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 -* the BSD license also applies to this code - have fun. + +* 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 @@ -30,220 +34,209 @@ #include "flash25spi.h" #include "wait_api.h" -//#define DEBUG +#include "cdi.h" + +#define DEBUG struct dataBase { -unsigned char vendor; -unsigned char device; -unsigned char capacity; -unsigned int memsize; -unsigned int blocksize; -unsigned int sectorsize; -unsigned int pagesize; + uint8_t signature; + size_t memsize; + size_t sectorsize; + size_t pagesize; }; const struct dataBase devices[] = { -// vendor, device, capacity, memsize, blocksize, sectorsize, pagesize -{ 0x1c, 0x31, 0x10, 0x10000, 0x8000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F05 (untested) -{ 0x1c, 0x31, 0x11, 0x20000, 0x8000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F10 (untested) -{ 0x1c, 0x31, 0x12, 0x40000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F20 (untested) -{ 0x1c, 0x31, 0x13, 0x80000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F40 (untested) -{ 0x1c, 0x31, 0x14, 0x100000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F80 (untested) -{ 0x1c, 0x31, 0x15, 0x200000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F16 (untested) -{ 0x1c, 0x30, 0x15, 0x200000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25Q16 (untested) -{ 0x1c, 0x31, 0x16, 0x400000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25F32 (untested) -{ 0x1c, 0x30, 0x16, 0x400000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25Q32A -{ 0x1c, 0x30, 0x17, 0x800000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25Q64 (untested) -{ 0x1c, 0x30, 0x18, 0x1000000, 0x10000, 0x1000, 0x100}, // Manufacturer: EON, Device: EN25Q128 (untested) - -{ 0x20, 0x20, 0x10, 0x10000, 0x8000, 0, 0x100}, // Manufacturer: Numonyx, Device: M25P05-A (untested) -{ 0x20, 0x20, 0x16, 0x400000, 0x10000, 0, 0x100}, // Manufacturer: Numonyx, Device: M25P32 (untested) -{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // end of table + //signature, memsize, sectorsize, pagesize + { 0x10, 0x20000, 0x8000, 0x100 }, // M25P10-A Numonyx/ST + { 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) -flash25spi::flash25spi(SPI *spi, PinName enable) { - unsigned char chipid[3]; - unsigned int i = 0; - _spi=spi; - _enable=new DigitalOut(enable); - _enable->write(1); - +FlashM25PSpi::FlashM25PSpi(SPI *spi, PinName enable, CDI *cdi) : + _spi(spi) + , _enable(enable) + , _size(0) +{ + _spi->format(8,0); + + _enable = 1; wait_us(1000); - - _enable->write(0); + _enable = 0; wait_us(1); - // send address - _spi->write(0x9f); - chipid[0] = _spi->write(0); // get vendor ID - chipid[1] = _spi->write(0); // get device ID - chipid[2] = _spi->write(0); // get capacity + 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->write(1); - - _size = 0; + _enable = 1; -#ifdef DEBUG - printf ("got flash ids: %x, %x, %x\n", chipid[0], chipid[1], chipid[2]); -#endif - + unsigned int i = 0; while (_size == 0) { + if (devices[i].memsize == 0) { // Nobody makes a memory of zero size #ifdef DEBUG - printf ("checking: %x, %x, %x\n", devices[i].vendor, devices[i].device, devices[i].capacity); + if (cdi) cdi->printf("\r\nUnknown Flash Memory signature: %xh\r\n", chipSig); #endif - if (devices[i].vendor == 0) { - printf("flash device not found\n"); return; } - if ((chipid[0] == devices[i].vendor) && - (chipid[1] == devices[i].device) && - (chipid[2] == devices[i].capacity)) { - _size=devices[i].memsize; - _blockSize=devices[i].blocksize; - _sectorSize=devices[i].sectorsize; - _pageSize=devices[i].pagesize; + if (chipSig == devices[i].signature) { + _size=devices[i].memsize; + _sectorSize=devices[i].sectorsize; + _pageSize=devices[i].pagesize; #ifdef DEBUG - printf("device found: %x - %x, %x, %x, %x\n",i, _size, _blockSize, _sectorSize, _pageSize); + if (cdi) cdi->printf("\r\nFlash Memory Sig:%Xh : %u bytes Org: %x, %x\r\n", + chipSig, _size, _sectorSize, _pageSize); #endif - } - else + } else i++; } - return; } -flash25spi::~flash25spi() { - delete _enable; +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; } -char* flash25spi::read(unsigned int startAdr, unsigned int len) { - // assertion - if (startAdr+len>_size) - return NULL; - char* ret=(char*)malloc(len); - if (!len) return NULL; - - _enable->write(0); +bool FlashM25PSpi::read(uint32_t startAddr, void* destination, size_t len) +{ + // Check size + if (startAddr + len > _size) + return false; + _enable = 0; wait_us(1); - // send address - _spi->write(0x03); - _spi->write(HIGH(startAdr)); - _spi->write(MID(startAdr)); - _spi->write(LOW(startAdr)); + + // Cast to char + char *dest8 = (char*)destination; - // read data into buffer - for (unsigned int i=0;i<len;i++) { - ret[i]=_spi->write(0); + // 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->write(1); - return ret; + _enable = 1; + return true; } -bool flash25spi::write(unsigned int startAdr, unsigned int len, const char* data) { - if (startAdr+len>_size) +bool FlashM25PSpi::write(uint32_t startAddr, const void* data, size_t len) +{ + if (startAddr + len > _size) return false; - unsigned int ofs=0; - while (ofs<len) { + // Cast to char + char *data8 = (char*)data; + + size_t ofs = 0; + while (ofs < len) { // calculate amount of data to write into current page - int pageLen=_pageSize-((startAdr+ofs)%_pageSize); - if (ofs+pageLen>len) - pageLen=len-ofs; + size_t pageLen = _pageSize - ((startAddr + ofs) % _pageSize); + if (ofs + pageLen > len) + pageLen = len - ofs; // write single page - bool b=writePage(startAdr+ofs,pageLen,data+ofs); - if (!b) - return false; + if (!writePage(startAddr + ofs, data8 + ofs, pageLen)) + return false; // Oh dear // and switch to next page - ofs+=pageLen; + ofs += pageLen; } return true; } -bool flash25spi::writePage(unsigned int startAdr, unsigned int len, const char* data) { +bool FlashM25PSpi::writePage(uint32_t startAddr, const char* data, size_t len) +{ enableWrite(); - _enable->write(0); + _enable = 0; wait_us(1); - _spi->write(0x02); - _spi->write(HIGH(startAdr)); - _spi->write(MID(startAdr)); - _spi->write(LOW(startAdr)); + _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++) { + for (unsigned int i=0; i<len; ++i) { _spi->write(data[i]); } wait_us(1); // disable to start physical write - _enable->write(1); - + _enable = 1; + waitForWrite(); return true; } -void flash25spi::clearSector(unsigned int addr) { - if (_sectorSize == 0) { - clearBlock(addr); - return; - } - +void FlashM25PSpi::eraseSector(unsigned int addr) +{ addr &= ~(_sectorSize-1); enableWrite(); - _enable->write(0); + _enable = 0; wait_us(1); - _spi->write(0x20); + _spi->write(FLASH_SE); _spi->write(HIGH(addr)); _spi->write(MID(addr)); _spi->write(LOW(addr)); wait_us(1); - _enable->write(1); - waitForWrite(); -} - -void flash25spi::clearBlock(unsigned int addr) { - addr &= ~(_blockSize-1); - - enableWrite(); - _enable->write(0); - wait_us(1); - _spi->write(0xd8); - _spi->write(HIGH(addr)); - _spi->write(MID(addr)); - _spi->write(LOW(addr)); - wait_us(1); - _enable->write(1); + _enable = 1; waitForWrite(); } -void flash25spi::clearMem() { +void FlashM25PSpi::eraseMem() +{ enableWrite(); - _enable->write(0); + _enable = 0; wait_us(1); - _spi->write(0xc7); + _spi->write(FLASH_BE); wait_us(1); - _enable->write(1); + _enable = 1; waitForWrite(); } -int flash25spi::readStatus() { - _enable->write(0); +int FlashM25PSpi::readStatus() +{ + _enable = 0; wait_us(1); - _spi->write(0x5); + _spi->write(FLASH_RDSR); int status=_spi->write(0x00); wait_us(1); - _enable->write(1); + _enable = 1; return status; } -void flash25spi::waitForWrite() { +void FlashM25PSpi::waitForWrite() +{ while (true) { if (0==readStatus()&1) break; @@ -251,11 +244,11 @@ } } -void flash25spi::enableWrite() +void FlashM25PSpi::enableWrite() { - _enable->write(0); + _enable = 0; wait_us(1); - _spi->write(0x06); + _spi->write(FLASH_WREN); wait_us(1); - _enable->write(1); + _enable = 1; }
--- a/flash25spi.h Sun Feb 20 11:16:27 2011 +0000 +++ b/flash25spi.h Fri Apr 25 12:25:08 2014 +0000 @@ -1,22 +1,26 @@ /* 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 -* the BSD license also applies to this code - have fun. +* +* 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 @@ -26,83 +30,78 @@ * THE SOFTWARE. */ -#ifndef __FLASH25SPI_H__ -#define __FLASH25SPI_H__ +#pragma once +#include "mbed.h" -#include "mbed.h" +class CDI; /** -A class to read and write all 25* serial SPI flash devices from various manufacturers. -It tries to autodetect the connected device. If your flash is not in the device list, but -it compatible, feel free to modify the library and add it to the list. +A class to read and write M25P* serial SPI flash devices. */ - -class flash25spi +class FlashM25PSpi { - public: - /** - create the handler class. it tries to autodetect your device. If your device is not recognized, add the devices parameters - to the device data structure at the library sources. - @param spi the SPI port where the flash is connected. Must be set to format(8,3), and with a speed matching the one of your device - @param enable the pin name for the port where /CS is connected - */ - flash25spi(SPI *spi, PinName enable); - - /** - destroys the handler, and frees the /CS pin - */ - ~flash25spi(); - - /** - read a part of the flashs memory. The buffer will be allocated here, and must be freed by the user - @param startAdr the adress where to start reading. Doesn't need to match a page boundary - @param len the number of bytes to read (must not exceed the end of memory) - @return NULL in case of an error or if the adresses are out of range, the pointer to the data otherwise - */ - char* read(unsigned int startAdr, unsigned int len); - - /** - writes the give buffer into the memory. This function handles dividing the write into - pages, and waites until the phyiscal write has finished - @param startAdr the adress where to start writing. Doesn't need to match a page boundary - @param len the number of bytes to read (must not exceed the end of memory) - @return false if the adresses are out of range - */ - bool write(unsigned int startAdr, unsigned int len, const char* data); - - /** - fills the sector containing the given address with 0xFF - this erases several pages. - Refer to the flashes datasheet about the memory organisation. - @param addr an address within the sector to be cleared - */ - void clearSector(unsigned int addr); +public: + /** + Create the handler class. it tries to autodetect your device. If your device is not recognized, add the devices parameters + to the device data structure at the library sources. + @param spi the SPI port where the flash is connected. Must be set to format(8,3), and with a speed matching the one of your device + @param enable the pin name for the port where /CS is connected + */ + FlashM25PSpi(SPI *spi, PinName enable, CDI *cdi = 0); + + /** + Destroy the handler and powers down the flash chip + */ + ~FlashM25PSpi(); + + /** + Read a part of the flash memory into destination. + The buffer must be pre-allocated by the caller + @param startAdr Flash address to start reading from. Doesn't need to match a page boundary + @param destination Destination buffer + @param len Number of bytes to read (must not exceed the end of memory) + @return true if succeeded + */ + bool read(uint32_t startAddr, void* destination, size_t len); - /** - fills the block containing the given address with 0xFF - this erases several pages and several sectors. - Refer to the flashes datasheet about the memory organisation. - @param addr an address within the sector to be cleared - */ - void clearBlock(unsigned int addr); + /** + Write the give buffer into the memory. + This function handles dividing the write into pages until the physical write has finished. + @note The flash must be erased before starting a write cycle. + @param startAdr Address to start writing. Doesn't need to match a page boundary + @param data Source data buffer + @param len the number of bytes to write (must not exceed the end of memory) + @return false if the adresses are out of range + */ + bool write(uint32_t startAddr, const void* data, size_t len); + + /** + Erases the sector containing the given address to 0xFF - this erases several pages. + Refer to the IC datasheet or Size() methods for memory organisation. + @param addr Any address within the sector to be cleared + */ + void eraseSector(uint32_t addr); - - /** - fills the whole flash with 0xFF - */ - void clearMem(); - - private: - bool writePage(unsigned int startAdr, unsigned int len, const char* data); - int readStatus(); - void waitForWrite(); - void enableWrite(); - + //! Erases the whole flash to 0xFF + void eraseMem(); + + //! Read detected flash size + size_t flashSize() const {return _size;} + + //! Read detected flash sector size + size_t sectorSize() const {return _sectorSize;} + + //! Read detected flash page size + size_t pageSize() const {return _pageSize;} - SPI* _spi; - DigitalOut* _enable; - unsigned int _size,_pageSize,_sectorSize,_blockSize; - -}; +private: + bool writePage(uint32_t startAddr, const char* data, size_t len); + int readStatus(); + void waitForWrite(); + void enableWrite(); - -#endif + SPI* _spi; + DigitalOut _enable; + size_t _size, _pageSize, _sectorSize; +};