Flash handler for M25P* chips with no Device ID.
Fork of flash25spi by
flash25spi.cpp@6:94558d4243f8, 2014-04-26 (annotated)
- Committer:
- Tomo2k
- Date:
- Sat Apr 26 11:52:28 2014 +0000
- Revision:
- 6:94558d4243f8
- Parent:
- 4:af870c53c0e9
- Child:
- 7:fae78b14f38f
SPI format (8,3) - better clock LED. Fixed ARM-GCC warnings
Who changed what in which revision?
User | Revision | Line number | New 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 | 3:318fabd6708c | 49 | { 0x12, 0x80000, 0x10000, 0x100 }, // M25P40 Numonyx/ST |
Tomo2k | 3:318fabd6708c | 50 | { 0x00, 0x00, 0x00, 0x00}, // end of table |
stonie | 0:d07f90d3c670 | 51 | }; |
stonie | 0:d07f90d3c670 | 52 | |
Tomo2k | 3:318fabd6708c | 53 | // Instruction Set |
Tomo2k | 3:318fabd6708c | 54 | const uint8_t FLASH_WREN = 0x06; // Write Enable |
Tomo2k | 3:318fabd6708c | 55 | //const uint8_t FLASH_WRDI = 0x04; // Write Disable (Unused) |
Tomo2k | 3:318fabd6708c | 56 | //const uint8_t FLASH_RDID = 0x9F; // Read Device IDentification (not supported) |
Tomo2k | 3:318fabd6708c | 57 | const uint8_t FLASH_RDSR = 0x05; // Read Status Register |
Tomo2k | 3:318fabd6708c | 58 | const uint8_t FLASH_WRSR = 0x01; // Write Status Register |
Tomo2k | 3:318fabd6708c | 59 | const uint8_t FLASH_READ = 0x03; // Read Data Bytes |
Tomo2k | 3:318fabd6708c | 60 | //const uint8_t FLASH_FAST_READ = 0x0B; // Read Data Bytes Faster |
Tomo2k | 3:318fabd6708c | 61 | const uint8_t FLASH_PP = 0x02; // Page Program (max pagesize bytes) |
Tomo2k | 3:318fabd6708c | 62 | const uint8_t FLASH_SE = 0xD8; // Sector Erase |
Tomo2k | 3:318fabd6708c | 63 | const uint8_t FLASH_BE = 0xC7; // Bulk Erase (wipe complete system) |
Tomo2k | 3:318fabd6708c | 64 | const uint8_t FLASH_DP = 0xB9; // Deep Power Down (shutdown into very-low-power) |
Tomo2k | 3:318fabd6708c | 65 | const uint8_t FLASH_RES = 0xAB; // Wake Up and Read Electronic Signature |
stonie | 0:d07f90d3c670 | 66 | |
stonie | 0:d07f90d3c670 | 67 | #define HIGH(x) ((x&0xff0000)>>16) |
stonie | 0:d07f90d3c670 | 68 | #define MID(x) ((x&0xff00)>>8) |
stonie | 0:d07f90d3c670 | 69 | #define LOW(x) (x&0xff) |
stonie | 0:d07f90d3c670 | 70 | |
Tomo2k | 4:af870c53c0e9 | 71 | FlashM25PSpi::FlashM25PSpi(SPI *spi, PinName enable) : |
Tomo2k | 3:318fabd6708c | 72 | _spi(spi) |
Tomo2k | 3:318fabd6708c | 73 | , _enable(enable) |
Tomo2k | 3:318fabd6708c | 74 | , _size(0) |
Tomo2k | 3:318fabd6708c | 75 | { |
Tomo2k | 6:94558d4243f8 | 76 | _spi->format(8,3); |
Tomo2k | 3:318fabd6708c | 77 | |
Tomo2k | 3:318fabd6708c | 78 | _enable = 1; |
stonie | 0:d07f90d3c670 | 79 | wait_us(1000); |
Tomo2k | 3:318fabd6708c | 80 | _enable = 0; |
stonie | 0:d07f90d3c670 | 81 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 82 | uint8_t chipSig; |
Tomo2k | 3:318fabd6708c | 83 | // Reset and Ask for chip signature |
Tomo2k | 3:318fabd6708c | 84 | _spi->write(FLASH_RES); |
Tomo2k | 3:318fabd6708c | 85 | _spi->write(0); // Dummy writes |
Tomo2k | 3:318fabd6708c | 86 | _spi->write(0); // Dummy writes |
Tomo2k | 3:318fabd6708c | 87 | _spi->write(0); // Dummy writes |
Tomo2k | 3:318fabd6708c | 88 | chipSig = _spi->write(0); // Get Electronic Signature |
stonie | 0:d07f90d3c670 | 89 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 90 | _enable = 1; |
stonie | 0:d07f90d3c670 | 91 | |
Tomo2k | 3:318fabd6708c | 92 | unsigned int i = 0; |
stonie | 0:d07f90d3c670 | 93 | while (_size == 0) { |
Tomo2k | 3:318fabd6708c | 94 | if (devices[i].memsize == 0) { // Nobody makes a memory of zero size |
stonie | 0:d07f90d3c670 | 95 | #ifdef DEBUG |
Tomo2k | 4:af870c53c0e9 | 96 | printf("\r\nUnknown Flash Memory signature: %xh\r\n", chipSig); |
stonie | 0:d07f90d3c670 | 97 | #endif |
stonie | 0:d07f90d3c670 | 98 | return; |
stonie | 0:d07f90d3c670 | 99 | } |
Tomo2k | 3:318fabd6708c | 100 | if (chipSig == devices[i].signature) { |
Tomo2k | 3:318fabd6708c | 101 | _size=devices[i].memsize; |
Tomo2k | 3:318fabd6708c | 102 | _sectorSize=devices[i].sectorsize; |
Tomo2k | 3:318fabd6708c | 103 | _pageSize=devices[i].pagesize; |
stonie | 0:d07f90d3c670 | 104 | #ifdef DEBUG |
Tomo2k | 4:af870c53c0e9 | 105 | printf("\r\nFlash Memory Sig:%Xh : %u bytes Org: %x, %x\r\n", |
Tomo2k | 4:af870c53c0e9 | 106 | chipSig, _size, _sectorSize, _pageSize); |
stonie | 0:d07f90d3c670 | 107 | #endif |
Tomo2k | 3:318fabd6708c | 108 | } else |
stonie | 0:d07f90d3c670 | 109 | i++; |
stonie | 0:d07f90d3c670 | 110 | } |
stonie | 0:d07f90d3c670 | 111 | } |
stonie | 0:d07f90d3c670 | 112 | |
Tomo2k | 3:318fabd6708c | 113 | FlashM25PSpi::~FlashM25PSpi() |
Tomo2k | 3:318fabd6708c | 114 | { |
Tomo2k | 3:318fabd6708c | 115 | // Shutdown the flash chip into lowest-power mode |
Tomo2k | 3:318fabd6708c | 116 | // Assumes no writes could be in progress |
Tomo2k | 3:318fabd6708c | 117 | _enable = 0; |
Tomo2k | 3:318fabd6708c | 118 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 119 | _spi->write(FLASH_DP); |
Tomo2k | 3:318fabd6708c | 120 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 121 | _enable = 1; |
stonie | 0:d07f90d3c670 | 122 | } |
stonie | 0:d07f90d3c670 | 123 | |
Tomo2k | 3:318fabd6708c | 124 | bool FlashM25PSpi::read(uint32_t startAddr, void* destination, size_t len) |
Tomo2k | 3:318fabd6708c | 125 | { |
Tomo2k | 3:318fabd6708c | 126 | // Check size |
Tomo2k | 3:318fabd6708c | 127 | if (startAddr + len > _size) |
Tomo2k | 3:318fabd6708c | 128 | return false; |
Tomo2k | 3:318fabd6708c | 129 | _enable = 0; |
stonie | 0:d07f90d3c670 | 130 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 131 | |
Tomo2k | 3:318fabd6708c | 132 | // Cast to char |
Tomo2k | 3:318fabd6708c | 133 | char *dest8 = (char*)destination; |
stonie | 0:d07f90d3c670 | 134 | |
Tomo2k | 3:318fabd6708c | 135 | // Send address |
Tomo2k | 3:318fabd6708c | 136 | _spi->write(FLASH_READ); |
Tomo2k | 3:318fabd6708c | 137 | _spi->write(HIGH(startAddr)); |
Tomo2k | 3:318fabd6708c | 138 | _spi->write(MID(startAddr)); |
Tomo2k | 3:318fabd6708c | 139 | _spi->write(LOW(startAddr)); |
Tomo2k | 3:318fabd6708c | 140 | |
Tomo2k | 4:af870c53c0e9 | 141 | // Read into destination buffer |
Tomo2k | 3:318fabd6708c | 142 | while (len--) { |
Tomo2k | 3:318fabd6708c | 143 | *dest8++ = _spi->write(0); |
stonie | 0:d07f90d3c670 | 144 | } |
stonie | 0:d07f90d3c670 | 145 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 146 | _enable = 1; |
Tomo2k | 3:318fabd6708c | 147 | return true; |
stonie | 0:d07f90d3c670 | 148 | } |
stonie | 0:d07f90d3c670 | 149 | |
Tomo2k | 3:318fabd6708c | 150 | bool FlashM25PSpi::write(uint32_t startAddr, const void* data, size_t len) |
Tomo2k | 3:318fabd6708c | 151 | { |
Tomo2k | 3:318fabd6708c | 152 | if (startAddr + len > _size) |
stonie | 2:14c5db5e54df | 153 | return false; |
stonie | 0:d07f90d3c670 | 154 | |
Tomo2k | 3:318fabd6708c | 155 | // Cast to char |
Tomo2k | 3:318fabd6708c | 156 | char *data8 = (char*)data; |
Tomo2k | 4:af870c53c0e9 | 157 | |
Tomo2k | 3:318fabd6708c | 158 | size_t ofs = 0; |
Tomo2k | 3:318fabd6708c | 159 | while (ofs < len) { |
stonie | 0:d07f90d3c670 | 160 | // calculate amount of data to write into current page |
Tomo2k | 3:318fabd6708c | 161 | size_t pageLen = _pageSize - ((startAddr + ofs) % _pageSize); |
Tomo2k | 3:318fabd6708c | 162 | if (ofs + pageLen > len) |
Tomo2k | 3:318fabd6708c | 163 | pageLen = len - ofs; |
stonie | 0:d07f90d3c670 | 164 | // write single page |
Tomo2k | 3:318fabd6708c | 165 | if (!writePage(startAddr + ofs, data8 + ofs, pageLen)) |
Tomo2k | 3:318fabd6708c | 166 | return false; // Oh dear |
stonie | 0:d07f90d3c670 | 167 | // and switch to next page |
Tomo2k | 3:318fabd6708c | 168 | ofs += pageLen; |
stonie | 0:d07f90d3c670 | 169 | } |
stonie | 0:d07f90d3c670 | 170 | return true; |
stonie | 0:d07f90d3c670 | 171 | } |
stonie | 0:d07f90d3c670 | 172 | |
Tomo2k | 3:318fabd6708c | 173 | bool FlashM25PSpi::writePage(uint32_t startAddr, const char* data, size_t len) |
Tomo2k | 3:318fabd6708c | 174 | { |
stonie | 0:d07f90d3c670 | 175 | enableWrite(); |
stonie | 0:d07f90d3c670 | 176 | |
Tomo2k | 3:318fabd6708c | 177 | _enable = 0; |
stonie | 0:d07f90d3c670 | 178 | wait_us(1); |
stonie | 0:d07f90d3c670 | 179 | |
Tomo2k | 3:318fabd6708c | 180 | _spi->write(FLASH_PP); |
Tomo2k | 3:318fabd6708c | 181 | _spi->write(HIGH(startAddr)); |
Tomo2k | 3:318fabd6708c | 182 | _spi->write(MID(startAddr)); |
Tomo2k | 3:318fabd6708c | 183 | _spi->write(LOW(startAddr)); |
stonie | 0:d07f90d3c670 | 184 | |
stonie | 0:d07f90d3c670 | 185 | // do real write |
Tomo2k | 3:318fabd6708c | 186 | for (unsigned int i=0; i<len; ++i) { |
stonie | 0:d07f90d3c670 | 187 | _spi->write(data[i]); |
stonie | 0:d07f90d3c670 | 188 | } |
stonie | 0:d07f90d3c670 | 189 | wait_us(1); |
stonie | 0:d07f90d3c670 | 190 | // disable to start physical write |
Tomo2k | 3:318fabd6708c | 191 | _enable = 1; |
Tomo2k | 3:318fabd6708c | 192 | |
stonie | 0:d07f90d3c670 | 193 | waitForWrite(); |
stonie | 0:d07f90d3c670 | 194 | |
stonie | 0:d07f90d3c670 | 195 | return true; |
stonie | 0:d07f90d3c670 | 196 | } |
stonie | 0:d07f90d3c670 | 197 | |
Tomo2k | 6:94558d4243f8 | 198 | void FlashM25PSpi::eraseSector(uint32_t addr) |
Tomo2k | 3:318fabd6708c | 199 | { |
stonie | 0:d07f90d3c670 | 200 | addr &= ~(_sectorSize-1); |
stonie | 0:d07f90d3c670 | 201 | |
stonie | 0:d07f90d3c670 | 202 | enableWrite(); |
Tomo2k | 3:318fabd6708c | 203 | _enable = 0; |
stonie | 0:d07f90d3c670 | 204 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 205 | _spi->write(FLASH_SE); |
stonie | 0:d07f90d3c670 | 206 | _spi->write(HIGH(addr)); |
stonie | 0:d07f90d3c670 | 207 | _spi->write(MID(addr)); |
stonie | 0:d07f90d3c670 | 208 | _spi->write(LOW(addr)); |
stonie | 0:d07f90d3c670 | 209 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 210 | _enable = 1; |
stonie | 0:d07f90d3c670 | 211 | waitForWrite(); |
stonie | 0:d07f90d3c670 | 212 | } |
stonie | 0:d07f90d3c670 | 213 | |
Tomo2k | 3:318fabd6708c | 214 | void FlashM25PSpi::eraseMem() |
Tomo2k | 3:318fabd6708c | 215 | { |
stonie | 0:d07f90d3c670 | 216 | enableWrite(); |
Tomo2k | 3:318fabd6708c | 217 | _enable = 0; |
stonie | 0:d07f90d3c670 | 218 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 219 | _spi->write(FLASH_BE); |
stonie | 0:d07f90d3c670 | 220 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 221 | _enable = 1; |
stonie | 0:d07f90d3c670 | 222 | waitForWrite(); |
stonie | 0:d07f90d3c670 | 223 | } |
stonie | 0:d07f90d3c670 | 224 | |
Tomo2k | 3:318fabd6708c | 225 | int FlashM25PSpi::readStatus() |
Tomo2k | 3:318fabd6708c | 226 | { |
Tomo2k | 3:318fabd6708c | 227 | _enable = 0; |
stonie | 0:d07f90d3c670 | 228 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 229 | _spi->write(FLASH_RDSR); |
stonie | 0:d07f90d3c670 | 230 | int status=_spi->write(0x00); |
stonie | 0:d07f90d3c670 | 231 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 232 | _enable = 1; |
stonie | 0:d07f90d3c670 | 233 | return status; |
stonie | 0:d07f90d3c670 | 234 | } |
stonie | 0:d07f90d3c670 | 235 | |
Tomo2k | 3:318fabd6708c | 236 | void FlashM25PSpi::waitForWrite() |
Tomo2k | 3:318fabd6708c | 237 | { |
stonie | 0:d07f90d3c670 | 238 | while (true) { |
Tomo2k | 6:94558d4243f8 | 239 | if (0 == (readStatus()&1)) |
stonie | 0:d07f90d3c670 | 240 | break; |
stonie | 0:d07f90d3c670 | 241 | wait_us(10); |
stonie | 0:d07f90d3c670 | 242 | } |
stonie | 0:d07f90d3c670 | 243 | } |
stonie | 0:d07f90d3c670 | 244 | |
Tomo2k | 3:318fabd6708c | 245 | void FlashM25PSpi::enableWrite() |
stonie | 0:d07f90d3c670 | 246 | { |
Tomo2k | 3:318fabd6708c | 247 | _enable = 0; |
stonie | 0:d07f90d3c670 | 248 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 249 | _spi->write(FLASH_WREN); |
stonie | 0:d07f90d3c670 | 250 | wait_us(1); |
Tomo2k | 3:318fabd6708c | 251 | _enable = 1; |
stonie | 0:d07f90d3c670 | 252 | } |