Flash handler for M25P* chips with no Device ID.

Dependencies:   RTOS_SPI_Clean

Fork of flash25spi by Klaus Steinhammer

Revision:
3:318fabd6708c
Parent:
2:14c5db5e54df
Child:
4:af870c53c0e9
--- 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;
 }