Flash handler for M25P* chips with no Device ID.

Dependencies:   RTOS_SPI_Clean

Fork of flash25spi by Klaus Steinhammer

Files at this revision

API Documentation at this revision

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;
+};