Flash handler for M25P* chips with no Device ID.

Dependencies:   RTOS_SPI_Clean

Fork of flash25spi by Klaus Steinhammer

Committer:
Tomo2k
Date:
Tue Aug 19 16:56:06 2014 +0000
Revision:
12:63399e648bfc
Parent:
8:7b09546cb412
Switched to private RTOS_SPI_Clean

Who changed what in which revision?

UserRevisionLine numberNew contents of line
stonie 0:d07f90d3c670 1 /* This library is based on the Ser25lcxxx library by Hendrik Lipka
stonie 0:d07f90d3c670 2 * It was adapted to flash memory chips on 19.2.2011 by Klaus Steinhammer
Tomo2k 3:318fabd6708c 3
Tomo2k 3:318fabd6708c 4 * It was further adapted to M25P* SPI Flash memory chips that do not
Tomo2k 3:318fabd6708c 5 * support the "RDID" device ID instructions on 25.03.2014 by Richard Thompson
Tomo2k 3:318fabd6708c 6 *
Tomo2k 3:318fabd6708c 7 * The BSD license also applies to this code - have fun.
stonie 0:d07f90d3c670 8 */
stonie 0:d07f90d3c670 9
stonie 0:d07f90d3c670 10 /*
stonie 0:d07f90d3c670 11 * Ser25lcxxx library
stonie 0:d07f90d3c670 12 * Copyright (c) 2010 Hendrik Lipka
Tomo2k 3:318fabd6708c 13 *
stonie 0:d07f90d3c670 14 * Permission is hereby granted, free of charge, to any person obtaining a copy
stonie 0:d07f90d3c670 15 * of this software and associated documentation files (the "Software"), to deal
stonie 0:d07f90d3c670 16 * in the Software without restriction, including without limitation the rights
stonie 0:d07f90d3c670 17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
stonie 0:d07f90d3c670 18 * copies of the Software, and to permit persons to whom the Software is
stonie 0:d07f90d3c670 19 * furnished to do so, subject to the following conditions:
Tomo2k 3:318fabd6708c 20 *
stonie 0:d07f90d3c670 21 * The above copyright notice and this permission notice shall be included in
stonie 0:d07f90d3c670 22 * all copies or substantial portions of the Software.
Tomo2k 3:318fabd6708c 23 *
stonie 0:d07f90d3c670 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
stonie 0:d07f90d3c670 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
stonie 0:d07f90d3c670 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
stonie 0:d07f90d3c670 27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
stonie 0:d07f90d3c670 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
stonie 0:d07f90d3c670 29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
stonie 0:d07f90d3c670 30 * THE SOFTWARE.
stonie 0:d07f90d3c670 31 */
stonie 0:d07f90d3c670 32
stonie 0:d07f90d3c670 33
stonie 0:d07f90d3c670 34 #include "flash25spi.h"
stonie 0:d07f90d3c670 35 #include "wait_api.h"
stonie 0:d07f90d3c670 36
Tomo2k 4:af870c53c0e9 37 //#define DEBUG
stonie 0:d07f90d3c670 38
stonie 0:d07f90d3c670 39 struct dataBase {
Tomo2k 3:318fabd6708c 40 uint8_t signature;
Tomo2k 3:318fabd6708c 41 size_t memsize;
Tomo2k 3:318fabd6708c 42 size_t sectorsize;
Tomo2k 3:318fabd6708c 43 size_t pagesize;
stonie 0:d07f90d3c670 44 };
stonie 0:d07f90d3c670 45
stonie 0:d07f90d3c670 46 const struct dataBase devices[] = {
Tomo2k 3:318fabd6708c 47 //signature, memsize, sectorsize, pagesize
Tomo2k 3:318fabd6708c 48 { 0x10, 0x20000, 0x8000, 0x100 }, // M25P10-A Numonyx/ST
Tomo2k 7:fae78b14f38f 49 { 0x11, 0x40000, 0x10000, 0x100 }, // M25P20 Numonyx/ST/Micron
Tomo2k 3:318fabd6708c 50 { 0x12, 0x80000, 0x10000, 0x100 }, // M25P40 Numonyx/ST
Tomo2k 3:318fabd6708c 51 { 0x00, 0x00, 0x00, 0x00}, // end of table
stonie 0:d07f90d3c670 52 };
stonie 0:d07f90d3c670 53
Tomo2k 3:318fabd6708c 54 // Instruction Set
Tomo2k 3:318fabd6708c 55 const uint8_t FLASH_WREN = 0x06; // Write Enable
Tomo2k 3:318fabd6708c 56 //const uint8_t FLASH_WRDI = 0x04; // Write Disable (Unused)
Tomo2k 3:318fabd6708c 57 //const uint8_t FLASH_RDID = 0x9F; // Read Device IDentification (not supported)
Tomo2k 3:318fabd6708c 58 const uint8_t FLASH_RDSR = 0x05; // Read Status Register
Tomo2k 8:7b09546cb412 59 //const uint8_t FLASH_WRSR = 0x01; // Write Status Register (not used)
Tomo2k 3:318fabd6708c 60 const uint8_t FLASH_READ = 0x03; // Read Data Bytes
Tomo2k 3:318fabd6708c 61 //const uint8_t FLASH_FAST_READ = 0x0B; // Read Data Bytes Faster
Tomo2k 3:318fabd6708c 62 const uint8_t FLASH_PP = 0x02; // Page Program (max pagesize bytes)
Tomo2k 3:318fabd6708c 63 const uint8_t FLASH_SE = 0xD8; // Sector Erase
Tomo2k 3:318fabd6708c 64 const uint8_t FLASH_BE = 0xC7; // Bulk Erase (wipe complete system)
Tomo2k 3:318fabd6708c 65 const uint8_t FLASH_DP = 0xB9; // Deep Power Down (shutdown into very-low-power)
Tomo2k 3:318fabd6708c 66 const uint8_t FLASH_RES = 0xAB; // Wake Up and Read Electronic Signature
stonie 0:d07f90d3c670 67
stonie 0:d07f90d3c670 68 #define HIGH(x) ((x&0xff0000)>>16)
stonie 0:d07f90d3c670 69 #define MID(x) ((x&0xff00)>>8)
stonie 0:d07f90d3c670 70 #define LOW(x) (x&0xff)
stonie 0:d07f90d3c670 71
Tomo2k 8:7b09546cb412 72
Tomo2k 8:7b09546cb412 73 FlashM25PSpi::FlashM25PSpi(RTOS_SPI *spi, PinName enable, int bits, int mode) :
Tomo2k 3:318fabd6708c 74 _spi(spi)
Tomo2k 3:318fabd6708c 75 , _enable(enable)
Tomo2k 3:318fabd6708c 76 , _size(0)
Tomo2k 3:318fabd6708c 77 {
Tomo2k 8:7b09546cb412 78 if (bits) _spi->format(bits, mode);
Tomo2k 3:318fabd6708c 79
Tomo2k 3:318fabd6708c 80 _enable = 1;
Tomo2k 8:7b09546cb412 81 if (osKernelRunning()) {
Tomo2k 8:7b09546cb412 82 Thread::wait(1);
Tomo2k 8:7b09546cb412 83 } else {
Tomo2k 8:7b09546cb412 84 wait_us(1000);
Tomo2k 8:7b09546cb412 85 }
Tomo2k 3:318fabd6708c 86 _enable = 0;
stonie 0:d07f90d3c670 87 wait_us(1);
Tomo2k 3:318fabd6708c 88 uint8_t chipSig;
Tomo2k 3:318fabd6708c 89 // Reset and Ask for chip signature
Tomo2k 3:318fabd6708c 90 _spi->write(FLASH_RES);
Tomo2k 3:318fabd6708c 91 _spi->write(0); // Dummy writes
Tomo2k 3:318fabd6708c 92 _spi->write(0); // Dummy writes
Tomo2k 3:318fabd6708c 93 _spi->write(0); // Dummy writes
Tomo2k 3:318fabd6708c 94 chipSig = _spi->write(0); // Get Electronic Signature
stonie 0:d07f90d3c670 95 wait_us(1);
Tomo2k 3:318fabd6708c 96 _enable = 1;
stonie 0:d07f90d3c670 97
Tomo2k 3:318fabd6708c 98 unsigned int i = 0;
stonie 0:d07f90d3c670 99 while (_size == 0) {
Tomo2k 3:318fabd6708c 100 if (devices[i].memsize == 0) { // Nobody makes a memory of zero size
stonie 0:d07f90d3c670 101 #ifdef DEBUG
Tomo2k 4:af870c53c0e9 102 printf("\r\nUnknown Flash Memory signature: %xh\r\n", chipSig);
stonie 0:d07f90d3c670 103 #endif
stonie 0:d07f90d3c670 104 return;
stonie 0:d07f90d3c670 105 }
Tomo2k 3:318fabd6708c 106 if (chipSig == devices[i].signature) {
Tomo2k 3:318fabd6708c 107 _size=devices[i].memsize;
Tomo2k 3:318fabd6708c 108 _sectorSize=devices[i].sectorsize;
Tomo2k 3:318fabd6708c 109 _pageSize=devices[i].pagesize;
stonie 0:d07f90d3c670 110 #ifdef DEBUG
Tomo2k 4:af870c53c0e9 111 printf("\r\nFlash Memory Sig:%Xh : %u bytes Org: %x, %x\r\n",
Tomo2k 4:af870c53c0e9 112 chipSig, _size, _sectorSize, _pageSize);
stonie 0:d07f90d3c670 113 #endif
Tomo2k 3:318fabd6708c 114 } else
stonie 0:d07f90d3c670 115 i++;
stonie 0:d07f90d3c670 116 }
stonie 0:d07f90d3c670 117 }
stonie 0:d07f90d3c670 118
Tomo2k 3:318fabd6708c 119 FlashM25PSpi::~FlashM25PSpi()
Tomo2k 3:318fabd6708c 120 {
Tomo2k 8:7b09546cb412 121 // Wait until chip finishes cycle
Tomo2k 8:7b09546cb412 122 // waitForWrite();
Tomo2k 3:318fabd6708c 123 // Shutdown the flash chip into lowest-power mode
Tomo2k 3:318fabd6708c 124 _enable = 0;
Tomo2k 3:318fabd6708c 125 wait_us(1);
Tomo2k 3:318fabd6708c 126 _spi->write(FLASH_DP);
Tomo2k 3:318fabd6708c 127 wait_us(1);
Tomo2k 3:318fabd6708c 128 _enable = 1;
stonie 0:d07f90d3c670 129 }
stonie 0:d07f90d3c670 130
Tomo2k 3:318fabd6708c 131 bool FlashM25PSpi::read(uint32_t startAddr, void* destination, size_t len)
Tomo2k 3:318fabd6708c 132 {
Tomo2k 3:318fabd6708c 133 // Check size
Tomo2k 3:318fabd6708c 134 if (startAddr + len > _size)
Tomo2k 3:318fabd6708c 135 return false;
Tomo2k 3:318fabd6708c 136 _enable = 0;
stonie 0:d07f90d3c670 137 wait_us(1);
Tomo2k 3:318fabd6708c 138
Tomo2k 3:318fabd6708c 139 // Send address
Tomo2k 3:318fabd6708c 140 _spi->write(FLASH_READ);
Tomo2k 3:318fabd6708c 141 _spi->write(HIGH(startAddr));
Tomo2k 3:318fabd6708c 142 _spi->write(MID(startAddr));
Tomo2k 3:318fabd6708c 143 _spi->write(LOW(startAddr));
Tomo2k 3:318fabd6708c 144
Tomo2k 8:7b09546cb412 145 uint8_t dummy = 0;
Tomo2k 8:7b09546cb412 146
Tomo2k 8:7b09546cb412 147 // Bulk read into destination buffer (DMA)
Tomo2k 8:7b09546cb412 148 // Be sure to write the same dummy databyte repeatedly
Tomo2k 8:7b09546cb412 149 _spi->bulkReadWrite((uint8_t*)destination, &dummy, len, false);
Tomo2k 8:7b09546cb412 150
stonie 0:d07f90d3c670 151 wait_us(1);
Tomo2k 3:318fabd6708c 152 _enable = 1;
Tomo2k 3:318fabd6708c 153 return true;
stonie 0:d07f90d3c670 154 }
stonie 0:d07f90d3c670 155
Tomo2k 3:318fabd6708c 156 bool FlashM25PSpi::write(uint32_t startAddr, const void* data, size_t len)
Tomo2k 3:318fabd6708c 157 {
Tomo2k 3:318fabd6708c 158 if (startAddr + len > _size)
stonie 2:14c5db5e54df 159 return false;
stonie 0:d07f90d3c670 160
Tomo2k 8:7b09546cb412 161 // Cast to uint8_t
Tomo2k 8:7b09546cb412 162 uint8_t *data8 = (uint8_t*)data;
Tomo2k 4:af870c53c0e9 163
Tomo2k 3:318fabd6708c 164 size_t ofs = 0;
Tomo2k 3:318fabd6708c 165 while (ofs < len) {
stonie 0:d07f90d3c670 166 // calculate amount of data to write into current page
Tomo2k 3:318fabd6708c 167 size_t pageLen = _pageSize - ((startAddr + ofs) % _pageSize);
Tomo2k 3:318fabd6708c 168 if (ofs + pageLen > len)
Tomo2k 3:318fabd6708c 169 pageLen = len - ofs;
stonie 0:d07f90d3c670 170 // write single page
Tomo2k 3:318fabd6708c 171 if (!writePage(startAddr + ofs, data8 + ofs, pageLen))
Tomo2k 3:318fabd6708c 172 return false; // Oh dear
stonie 0:d07f90d3c670 173 // and switch to next page
Tomo2k 3:318fabd6708c 174 ofs += pageLen;
stonie 0:d07f90d3c670 175 }
stonie 0:d07f90d3c670 176 return true;
stonie 0:d07f90d3c670 177 }
stonie 0:d07f90d3c670 178
Tomo2k 8:7b09546cb412 179 bool FlashM25PSpi::writePage(uint32_t startAddr, const uint8_t* data, size_t len)
Tomo2k 3:318fabd6708c 180 {
stonie 0:d07f90d3c670 181 enableWrite();
stonie 0:d07f90d3c670 182
Tomo2k 3:318fabd6708c 183 _enable = 0;
stonie 0:d07f90d3c670 184 wait_us(1);
stonie 0:d07f90d3c670 185
Tomo2k 3:318fabd6708c 186 _spi->write(FLASH_PP);
Tomo2k 3:318fabd6708c 187 _spi->write(HIGH(startAddr));
Tomo2k 3:318fabd6708c 188 _spi->write(MID(startAddr));
Tomo2k 3:318fabd6708c 189 _spi->write(LOW(startAddr));
stonie 0:d07f90d3c670 190
Tomo2k 8:7b09546cb412 191 // Bulk write using DMA
Tomo2k 8:7b09546cb412 192 _spi->bulkWrite(data, len);
Tomo2k 8:7b09546cb412 193
stonie 0:d07f90d3c670 194 wait_us(1);
stonie 0:d07f90d3c670 195 // disable to start physical write
Tomo2k 3:318fabd6708c 196 _enable = 1;
Tomo2k 3:318fabd6708c 197
stonie 0:d07f90d3c670 198 waitForWrite();
stonie 0:d07f90d3c670 199
stonie 0:d07f90d3c670 200 return true;
stonie 0:d07f90d3c670 201 }
stonie 0:d07f90d3c670 202
Tomo2k 6:94558d4243f8 203 void FlashM25PSpi::eraseSector(uint32_t addr)
Tomo2k 3:318fabd6708c 204 {
stonie 0:d07f90d3c670 205 addr &= ~(_sectorSize-1);
stonie 0:d07f90d3c670 206
stonie 0:d07f90d3c670 207 enableWrite();
Tomo2k 3:318fabd6708c 208 _enable = 0;
stonie 0:d07f90d3c670 209 wait_us(1);
Tomo2k 3:318fabd6708c 210 _spi->write(FLASH_SE);
stonie 0:d07f90d3c670 211 _spi->write(HIGH(addr));
stonie 0:d07f90d3c670 212 _spi->write(MID(addr));
stonie 0:d07f90d3c670 213 _spi->write(LOW(addr));
stonie 0:d07f90d3c670 214 wait_us(1);
Tomo2k 3:318fabd6708c 215 _enable = 1;
stonie 0:d07f90d3c670 216 waitForWrite();
stonie 0:d07f90d3c670 217 }
stonie 0:d07f90d3c670 218
Tomo2k 3:318fabd6708c 219 void FlashM25PSpi::eraseMem()
Tomo2k 3:318fabd6708c 220 {
stonie 0:d07f90d3c670 221 enableWrite();
Tomo2k 3:318fabd6708c 222 _enable = 0;
stonie 0:d07f90d3c670 223 wait_us(1);
Tomo2k 3:318fabd6708c 224 _spi->write(FLASH_BE);
stonie 0:d07f90d3c670 225 wait_us(1);
Tomo2k 3:318fabd6708c 226 _enable = 1;
stonie 0:d07f90d3c670 227 waitForWrite();
stonie 0:d07f90d3c670 228 }
stonie 0:d07f90d3c670 229
Tomo2k 3:318fabd6708c 230 int FlashM25PSpi::readStatus()
Tomo2k 3:318fabd6708c 231 {
Tomo2k 3:318fabd6708c 232 _enable = 0;
stonie 0:d07f90d3c670 233 wait_us(1);
Tomo2k 3:318fabd6708c 234 _spi->write(FLASH_RDSR);
stonie 0:d07f90d3c670 235 int status=_spi->write(0x00);
stonie 0:d07f90d3c670 236 wait_us(1);
Tomo2k 3:318fabd6708c 237 _enable = 1;
stonie 0:d07f90d3c670 238 return status;
stonie 0:d07f90d3c670 239 }
stonie 0:d07f90d3c670 240
Tomo2k 3:318fabd6708c 241 void FlashM25PSpi::waitForWrite()
Tomo2k 3:318fabd6708c 242 {
stonie 0:d07f90d3c670 243 while (true) {
Tomo2k 8:7b09546cb412 244 // Allow something else to do some work
Tomo2k 8:7b09546cb412 245 Thread::yield();
Tomo2k 8:7b09546cb412 246 if (0 == (readStatus()&1)) return;
stonie 0:d07f90d3c670 247 }
stonie 0:d07f90d3c670 248 }
stonie 0:d07f90d3c670 249
Tomo2k 3:318fabd6708c 250 void FlashM25PSpi::enableWrite()
stonie 0:d07f90d3c670 251 {
Tomo2k 3:318fabd6708c 252 _enable = 0;
stonie 0:d07f90d3c670 253 wait_us(1);
Tomo2k 3:318fabd6708c 254 _spi->write(FLASH_WREN);
stonie 0:d07f90d3c670 255 wait_us(1);
Tomo2k 3:318fabd6708c 256 _enable = 1;
stonie 0:d07f90d3c670 257 }