++

Fork of SerialFlash by tom dunigan

Committer:
lzbpli
Date:
Mon Jul 11 07:49:22 2016 +0000
Revision:
1:5f1a6c63fa57
Parent:
0:e5c9fd5789d7
053

Who changed what in which revision?

UserRevisionLine numberNew contents of line
manitou 0:e5c9fd5789d7 1 /* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory
manitou 0:e5c9fd5789d7 2 * https://github.com/PaulStoffregen/SerialFlash
manitou 0:e5c9fd5789d7 3 * Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com
manitou 0:e5c9fd5789d7 4 *
manitou 0:e5c9fd5789d7 5 * Development of this library was funded by PJRC.COM, LLC by sales of Teensy.
manitou 0:e5c9fd5789d7 6 * Please support PJRC's efforts to develop open source software by purchasing
manitou 0:e5c9fd5789d7 7 * Teensy or other genuine PJRC products.
manitou 0:e5c9fd5789d7 8 *
manitou 0:e5c9fd5789d7 9 * Permission is hereby granted, free of charge, to any person obtaining a copy
manitou 0:e5c9fd5789d7 10 * of this software and associated documentation files (the "Software"), to deal
manitou 0:e5c9fd5789d7 11 * in the Software without restriction, including without limitation the rights
manitou 0:e5c9fd5789d7 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
manitou 0:e5c9fd5789d7 13 * copies of the Software, and to permit persons to whom the Software is
manitou 0:e5c9fd5789d7 14 * furnished to do so, subject to the following conditions:
manitou 0:e5c9fd5789d7 15 *
manitou 0:e5c9fd5789d7 16 * The above copyright notice, development funding notice, and this permission
manitou 0:e5c9fd5789d7 17 * notice shall be included in all copies or substantial portions of the Software.
manitou 0:e5c9fd5789d7 18 *
manitou 0:e5c9fd5789d7 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
manitou 0:e5c9fd5789d7 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
manitou 0:e5c9fd5789d7 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
manitou 0:e5c9fd5789d7 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
manitou 0:e5c9fd5789d7 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
manitou 0:e5c9fd5789d7 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
manitou 0:e5c9fd5789d7 25 * THE SOFTWARE.
manitou 0:e5c9fd5789d7 26 */
manitou 0:e5c9fd5789d7 27 #include "mbed.h"
manitou 0:e5c9fd5789d7 28 #include "SerialFlash.h"
manitou 0:e5c9fd5789d7 29
lzbpli 1:5f1a6c63fa57 30 static SPI spi(PB_15,PB_14,PB_13); // mosi, miso, sclk
lzbpli 1:5f1a6c63fa57 31 DigitalOut cspin(PB_12);
manitou 0:e5c9fd5789d7 32
manitou 0:e5c9fd5789d7 33 #define CSASSERT() cspin = 0
manitou 0:e5c9fd5789d7 34 #define CSRELEASE() cspin = 1
manitou 0:e5c9fd5789d7 35
manitou 0:e5c9fd5789d7 36 uint16_t SerialFlashChip::dirindex = 0;
manitou 0:e5c9fd5789d7 37 uint8_t SerialFlashChip::flags = 0;
manitou 0:e5c9fd5789d7 38 uint8_t SerialFlashChip::busy = 0;
manitou 0:e5c9fd5789d7 39
manitou 0:e5c9fd5789d7 40
manitou 0:e5c9fd5789d7 41 #define FLAG_32BIT_ADDR 0x01 // larger than 16 MByte address
manitou 0:e5c9fd5789d7 42 #define FLAG_STATUS_CMD70 0x02 // requires special busy flag check
manitou 0:e5c9fd5789d7 43 #define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands
manitou 0:e5c9fd5789d7 44 #define FLAG_MULTI_DIE 0x08 // multiple die, don't read cross 32M barrier
manitou 0:e5c9fd5789d7 45 #define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks
manitou 0:e5c9fd5789d7 46 #define FLAG_DIE_MASK 0xC0 // top 2 bits count during multi-die erase
manitou 0:e5c9fd5789d7 47
manitou 0:e5c9fd5789d7 48 void SerialFlashChip::wait(void)
manitou 0:e5c9fd5789d7 49 {
manitou 0:e5c9fd5789d7 50 uint32_t status;
manitou 0:e5c9fd5789d7 51 //Serial.print("wait-");
manitou 0:e5c9fd5789d7 52 while (1) {
manitou 0:e5c9fd5789d7 53 CSASSERT();
manitou 0:e5c9fd5789d7 54 if (flags & FLAG_STATUS_CMD70) {
manitou 0:e5c9fd5789d7 55 // some Micron chips require this different
manitou 0:e5c9fd5789d7 56 // command to detect program and erase completion
manitou 0:e5c9fd5789d7 57 spi.write(0x70);
manitou 0:e5c9fd5789d7 58 status = spi.write(0);
manitou 0:e5c9fd5789d7 59 CSRELEASE();
manitou 0:e5c9fd5789d7 60 //Serial.printf("b=%02x.", status & 0xFF);
manitou 0:e5c9fd5789d7 61 if ((status & 0x80)) break;
manitou 0:e5c9fd5789d7 62 } else {
manitou 0:e5c9fd5789d7 63 // all others work by simply reading the status reg
manitou 0:e5c9fd5789d7 64 spi.write(0x05);
manitou 0:e5c9fd5789d7 65 status = spi.write(0);
manitou 0:e5c9fd5789d7 66 CSRELEASE();
manitou 0:e5c9fd5789d7 67 //Serial.printf("b=%02x.", status & 0xFF);
manitou 0:e5c9fd5789d7 68 if (!(status & 1)) break;
manitou 0:e5c9fd5789d7 69 }
manitou 0:e5c9fd5789d7 70 }
manitou 0:e5c9fd5789d7 71 busy = 0;
manitou 0:e5c9fd5789d7 72 //Serial.println();
manitou 0:e5c9fd5789d7 73 }
manitou 0:e5c9fd5789d7 74
manitou 0:e5c9fd5789d7 75 void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)
manitou 0:e5c9fd5789d7 76 {
manitou 0:e5c9fd5789d7 77 uint8_t *p = (uint8_t *)buf;
manitou 0:e5c9fd5789d7 78 uint8_t b, f, status, cmd;
manitou 0:e5c9fd5789d7 79
manitou 0:e5c9fd5789d7 80 memset(p, 0, len);
manitou 0:e5c9fd5789d7 81 f = flags;
manitou 0:e5c9fd5789d7 82 b = busy;
manitou 0:e5c9fd5789d7 83 if (b) {
manitou 0:e5c9fd5789d7 84 // read status register ... chip may no longer be busy
manitou 0:e5c9fd5789d7 85 CSASSERT();
manitou 0:e5c9fd5789d7 86 if (flags & FLAG_STATUS_CMD70) {
manitou 0:e5c9fd5789d7 87 spi.write(0x70);
manitou 0:e5c9fd5789d7 88 status = spi.write(0);
manitou 0:e5c9fd5789d7 89 if ((status & 0x80)) b = 0;
manitou 0:e5c9fd5789d7 90 } else {
manitou 0:e5c9fd5789d7 91 spi.write(0x05);
manitou 0:e5c9fd5789d7 92 status = spi.write(0);
manitou 0:e5c9fd5789d7 93 if (!(status & 1)) b = 0;
manitou 0:e5c9fd5789d7 94 }
manitou 0:e5c9fd5789d7 95 CSRELEASE();
manitou 0:e5c9fd5789d7 96 if (b == 0) {
manitou 0:e5c9fd5789d7 97 // chip is no longer busy :-)
manitou 0:e5c9fd5789d7 98 busy = 0;
manitou 0:e5c9fd5789d7 99 } else if (b < 3) {
manitou 0:e5c9fd5789d7 100 // TODO: this may not work on Spansion chips
manitou 0:e5c9fd5789d7 101 // which apparently have 2 different suspend
manitou 0:e5c9fd5789d7 102 // commands, for program vs erase
manitou 0:e5c9fd5789d7 103 CSASSERT();
manitou 0:e5c9fd5789d7 104 spi.write(0x06); // write enable (Micron req'd)
manitou 0:e5c9fd5789d7 105 CSRELEASE();
manitou 0:e5c9fd5789d7 106 wait_us(1);
manitou 0:e5c9fd5789d7 107 cmd = 0x75; //Suspend program/erase for almost all chips
manitou 0:e5c9fd5789d7 108 // but Spansion just has to be different for program suspend!
manitou 0:e5c9fd5789d7 109 if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85;
manitou 0:e5c9fd5789d7 110 CSASSERT();
manitou 0:e5c9fd5789d7 111 spi.write(cmd); // Suspend command
manitou 0:e5c9fd5789d7 112 CSRELEASE();
manitou 0:e5c9fd5789d7 113 if (f & FLAG_STATUS_CMD70) {
manitou 0:e5c9fd5789d7 114 // Micron chips don't actually suspend until flags read
manitou 0:e5c9fd5789d7 115 CSASSERT();
manitou 0:e5c9fd5789d7 116 spi.write(0x70);
manitou 0:e5c9fd5789d7 117 do {
manitou 0:e5c9fd5789d7 118 status = spi.write(0);
manitou 0:e5c9fd5789d7 119 } while (!(status & 0x80));
manitou 0:e5c9fd5789d7 120 CSRELEASE();
manitou 0:e5c9fd5789d7 121 } else {
manitou 0:e5c9fd5789d7 122 CSASSERT();
manitou 0:e5c9fd5789d7 123 spi.write(0x05);
manitou 0:e5c9fd5789d7 124 do {
manitou 0:e5c9fd5789d7 125 status = spi.write(0);
manitou 0:e5c9fd5789d7 126 } while ((status & 0x01));
manitou 0:e5c9fd5789d7 127 CSRELEASE();
manitou 0:e5c9fd5789d7 128 }
manitou 0:e5c9fd5789d7 129 } else {
manitou 0:e5c9fd5789d7 130 // chip is busy with an operation that can not suspend
manitou 0:e5c9fd5789d7 131 wait(); // should we wait without ending
manitou 0:e5c9fd5789d7 132 b = 0; // the transaction??
manitou 0:e5c9fd5789d7 133 }
manitou 0:e5c9fd5789d7 134 }
manitou 0:e5c9fd5789d7 135 do {
manitou 0:e5c9fd5789d7 136 uint32_t rdlen = len;
manitou 0:e5c9fd5789d7 137 if (f & FLAG_MULTI_DIE) {
manitou 0:e5c9fd5789d7 138 if ((addr & 0xFE000000) != ((addr + len - 1) & 0xFE000000)) {
manitou 0:e5c9fd5789d7 139 rdlen = 0x2000000 - (addr & 0x1FFFFFF);
manitou 0:e5c9fd5789d7 140 }
manitou 0:e5c9fd5789d7 141 }
manitou 0:e5c9fd5789d7 142 CSASSERT();
manitou 0:e5c9fd5789d7 143 // TODO: FIFO optimize....
manitou 0:e5c9fd5789d7 144 if (f & FLAG_32BIT_ADDR) {
manitou 0:e5c9fd5789d7 145 spi.write(0x03);
manitou 0:e5c9fd5789d7 146 spi.write(addr >> 24);
manitou 0:e5c9fd5789d7 147 spi.write(addr >> 16);
manitou 0:e5c9fd5789d7 148 spi.write(addr >> 8);
manitou 0:e5c9fd5789d7 149 spi.write(addr);
manitou 0:e5c9fd5789d7 150 } else {
manitou 0:e5c9fd5789d7 151 spi.write(3);
manitou 0:e5c9fd5789d7 152 spi.write(addr >> 16);
manitou 0:e5c9fd5789d7 153 spi.write(addr >> 8);
manitou 0:e5c9fd5789d7 154 spi.write(addr);
manitou 0:e5c9fd5789d7 155 }
manitou 0:e5c9fd5789d7 156 uint32_t i = rdlen; // need block transfer
manitou 0:e5c9fd5789d7 157 while(i>0){
manitou 0:e5c9fd5789d7 158 *p++ = spi.write(0);
manitou 0:e5c9fd5789d7 159 i--;
manitou 0:e5c9fd5789d7 160 }
manitou 0:e5c9fd5789d7 161 CSRELEASE();
manitou 0:e5c9fd5789d7 162 addr += rdlen;
manitou 0:e5c9fd5789d7 163 len -= rdlen;
manitou 0:e5c9fd5789d7 164 } while (len > 0);
manitou 0:e5c9fd5789d7 165 if (b) {
manitou 0:e5c9fd5789d7 166 CSASSERT();
manitou 0:e5c9fd5789d7 167 spi.write(0x06); // write enable (Micron req'd)
manitou 0:e5c9fd5789d7 168 CSRELEASE();
manitou 0:e5c9fd5789d7 169 wait_us(1);
manitou 0:e5c9fd5789d7 170 cmd = 0x7A;
manitou 0:e5c9fd5789d7 171 if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A;
manitou 0:e5c9fd5789d7 172 CSASSERT();
manitou 0:e5c9fd5789d7 173 spi.write(cmd); // Resume program/erase
manitou 0:e5c9fd5789d7 174 CSRELEASE();
manitou 0:e5c9fd5789d7 175 }
manitou 0:e5c9fd5789d7 176 }
manitou 0:e5c9fd5789d7 177
manitou 0:e5c9fd5789d7 178 void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len)
manitou 0:e5c9fd5789d7 179 {
manitou 0:e5c9fd5789d7 180 const uint8_t *p = (const uint8_t *)buf;
manitou 0:e5c9fd5789d7 181 uint32_t max, pagelen;
manitou 0:e5c9fd5789d7 182
manitou 0:e5c9fd5789d7 183 //Serial.printf("WR: addr %08X, len %d\n", addr, len);
manitou 0:e5c9fd5789d7 184 do {
manitou 0:e5c9fd5789d7 185 if (busy) wait();
manitou 0:e5c9fd5789d7 186 CSASSERT();
manitou 0:e5c9fd5789d7 187 // write enable command
manitou 0:e5c9fd5789d7 188 spi.write(0x06);
manitou 0:e5c9fd5789d7 189 CSRELEASE();
manitou 0:e5c9fd5789d7 190 max = 256 - (addr & 0xFF);
manitou 0:e5c9fd5789d7 191 pagelen = (len <= max) ? len : max;
manitou 0:e5c9fd5789d7 192 //Serial.printf("WR: addr %08X, pagelen %d\n", addr, pagelen);
manitou 0:e5c9fd5789d7 193 wait_us(1); // TODO: reduce this, but prefer safety first
manitou 0:e5c9fd5789d7 194 CSASSERT();
manitou 0:e5c9fd5789d7 195 if (flags & FLAG_32BIT_ADDR) {
manitou 0:e5c9fd5789d7 196 spi.write(0x02); // program page command
manitou 0:e5c9fd5789d7 197 spi.write(addr >> 24);
manitou 0:e5c9fd5789d7 198 spi.write(addr >> 16);
manitou 0:e5c9fd5789d7 199 spi.write(addr >> 8);
manitou 0:e5c9fd5789d7 200 spi.write(addr);
manitou 0:e5c9fd5789d7 201 } else {
manitou 0:e5c9fd5789d7 202 spi.write(2);
manitou 0:e5c9fd5789d7 203 spi.write(addr >> 16);
manitou 0:e5c9fd5789d7 204 spi.write(addr >> 8);
manitou 0:e5c9fd5789d7 205 spi.write(addr);
manitou 0:e5c9fd5789d7 206 }
manitou 0:e5c9fd5789d7 207 addr += pagelen;
manitou 0:e5c9fd5789d7 208 len -= pagelen;
manitou 0:e5c9fd5789d7 209 do {
manitou 0:e5c9fd5789d7 210 spi.write(*p++);
manitou 0:e5c9fd5789d7 211 } while (--pagelen > 0);
manitou 0:e5c9fd5789d7 212 CSRELEASE();
manitou 0:e5c9fd5789d7 213 busy = 4;
manitou 0:e5c9fd5789d7 214 } while (len > 0);
manitou 0:e5c9fd5789d7 215 }
manitou 0:e5c9fd5789d7 216
manitou 0:e5c9fd5789d7 217 void SerialFlashChip::eraseAll()
manitou 0:e5c9fd5789d7 218 {
manitou 0:e5c9fd5789d7 219 if (busy) wait();
manitou 0:e5c9fd5789d7 220 uint8_t id[5];
manitou 0:e5c9fd5789d7 221 readID(id);
manitou 0:e5c9fd5789d7 222 //Serial.printf("ID: %02X %02X %02X\n", id[0], id[1], id[2]);
manitou 0:e5c9fd5789d7 223 if (id[0] == 0x20 && id[2] >= 0x20 && id[2] <= 0x22) {
manitou 0:e5c9fd5789d7 224 // Micron's multi-die chips require special die erase commands
manitou 0:e5c9fd5789d7 225 // N25Q512A 20 BA 20 2 dies 32 Mbyte/die 65 nm transitors
manitou 0:e5c9fd5789d7 226 // N25Q00AA 20 BA 21 4 dies 32 Mbyte/die 65 nm transitors
manitou 0:e5c9fd5789d7 227 // MT25QL02GC 20 BA 22 2 dies 128 Mbyte/die 45 nm transitors
manitou 0:e5c9fd5789d7 228 uint8_t die_count = 2;
manitou 0:e5c9fd5789d7 229 if (id[2] == 0x21) die_count = 4;
manitou 0:e5c9fd5789d7 230 uint8_t die_index = flags >> 6;
manitou 0:e5c9fd5789d7 231 //Serial.printf("Micron die erase %d\n", die_index);
manitou 0:e5c9fd5789d7 232 flags &= 0x3F;
manitou 0:e5c9fd5789d7 233 if (die_index >= die_count) return; // all dies erased :-)
manitou 0:e5c9fd5789d7 234 uint8_t die_size = 2; // in 16 Mbyte units
manitou 0:e5c9fd5789d7 235 if (id[2] == 0x22) die_size = 8;
manitou 0:e5c9fd5789d7 236 CSASSERT();
manitou 0:e5c9fd5789d7 237 spi.write(0x06); // write enable command
manitou 0:e5c9fd5789d7 238 CSRELEASE();
manitou 0:e5c9fd5789d7 239 wait_us(1);
manitou 0:e5c9fd5789d7 240 CSASSERT();
manitou 0:e5c9fd5789d7 241 // die erase command
manitou 0:e5c9fd5789d7 242 spi.write(0xC4);
manitou 0:e5c9fd5789d7 243 spi.write((die_index * die_size) );
manitou 0:e5c9fd5789d7 244 spi.write(0);
manitou 0:e5c9fd5789d7 245 spi.write(0);
manitou 0:e5c9fd5789d7 246 spi.write(0);
manitou 0:e5c9fd5789d7 247 CSRELEASE();
manitou 0:e5c9fd5789d7 248 //Serial.printf("Micron erase begin\n");
manitou 0:e5c9fd5789d7 249 flags |= (die_index + 1) << 6;
manitou 0:e5c9fd5789d7 250 } else {
manitou 0:e5c9fd5789d7 251 // All other chips support the bulk erase command
manitou 0:e5c9fd5789d7 252 CSASSERT();
manitou 0:e5c9fd5789d7 253 // write enable command
manitou 0:e5c9fd5789d7 254 spi.write(0x06);
manitou 0:e5c9fd5789d7 255 CSRELEASE();
manitou 0:e5c9fd5789d7 256 wait_us(1);
manitou 0:e5c9fd5789d7 257 CSASSERT();
manitou 0:e5c9fd5789d7 258 // bulk erase command
manitou 0:e5c9fd5789d7 259 spi.write(0xC7);
manitou 0:e5c9fd5789d7 260 CSRELEASE();
manitou 0:e5c9fd5789d7 261 }
manitou 0:e5c9fd5789d7 262 busy = 3;
manitou 0:e5c9fd5789d7 263 }
manitou 0:e5c9fd5789d7 264
manitou 0:e5c9fd5789d7 265 void SerialFlashChip::eraseBlock(uint32_t addr)
manitou 0:e5c9fd5789d7 266 {
manitou 0:e5c9fd5789d7 267 uint8_t f = flags;
manitou 0:e5c9fd5789d7 268 if (busy) wait();
manitou 0:e5c9fd5789d7 269 CSASSERT();
manitou 0:e5c9fd5789d7 270 spi.write(0x06); // write enable command
manitou 0:e5c9fd5789d7 271 CSRELEASE();
manitou 0:e5c9fd5789d7 272 wait_us(1);
manitou 0:e5c9fd5789d7 273 CSASSERT();
manitou 0:e5c9fd5789d7 274 if (f & FLAG_32BIT_ADDR) {
manitou 0:e5c9fd5789d7 275 spi.write(0xD8);
manitou 0:e5c9fd5789d7 276 spi.write(addr >> 24);
manitou 0:e5c9fd5789d7 277 spi.write(addr >> 16);
manitou 0:e5c9fd5789d7 278 spi.write(addr >> 8);
manitou 0:e5c9fd5789d7 279 spi.write(addr);
manitou 0:e5c9fd5789d7 280 } else {
manitou 0:e5c9fd5789d7 281 spi.write(0xD8);
manitou 0:e5c9fd5789d7 282 spi.write(addr >> 16);
manitou 0:e5c9fd5789d7 283 spi.write(addr >> 8);
manitou 0:e5c9fd5789d7 284 spi.write(addr);
manitou 0:e5c9fd5789d7 285 }
manitou 0:e5c9fd5789d7 286 CSRELEASE();
manitou 0:e5c9fd5789d7 287 busy = 2;
manitou 0:e5c9fd5789d7 288 }
manitou 0:e5c9fd5789d7 289
manitou 0:e5c9fd5789d7 290
manitou 0:e5c9fd5789d7 291 bool SerialFlashChip::ready()
manitou 0:e5c9fd5789d7 292 {
manitou 0:e5c9fd5789d7 293 uint32_t status;
manitou 0:e5c9fd5789d7 294 if (!busy) return true;
manitou 0:e5c9fd5789d7 295 CSASSERT();
manitou 0:e5c9fd5789d7 296 if (flags & FLAG_STATUS_CMD70) {
manitou 0:e5c9fd5789d7 297 // some Micron chips require this different
manitou 0:e5c9fd5789d7 298 // command to detect program and erase completion
manitou 0:e5c9fd5789d7 299 spi.write(0x70);
manitou 0:e5c9fd5789d7 300 status = spi.write(0);
manitou 0:e5c9fd5789d7 301 CSRELEASE();
manitou 0:e5c9fd5789d7 302 //Serial.printf("ready=%02x\n", status & 0xFF);
manitou 0:e5c9fd5789d7 303 if ((status & 0x80) == 0) return false;
manitou 0:e5c9fd5789d7 304 } else {
manitou 0:e5c9fd5789d7 305 // all others work by simply reading the status reg
manitou 0:e5c9fd5789d7 306 spi.write(0x05);
manitou 0:e5c9fd5789d7 307 status = spi.write(0);
manitou 0:e5c9fd5789d7 308 CSRELEASE();
manitou 0:e5c9fd5789d7 309 //Serial.printf("ready=%02x\n", status & 0xFF);
manitou 0:e5c9fd5789d7 310 if ((status & 1)) return false;
manitou 0:e5c9fd5789d7 311 }
manitou 0:e5c9fd5789d7 312 busy = 0;
manitou 0:e5c9fd5789d7 313 if (flags & 0xC0) {
manitou 0:e5c9fd5789d7 314 // continue a multi-die erase
manitou 0:e5c9fd5789d7 315 eraseAll();
manitou 0:e5c9fd5789d7 316 return false;
manitou 0:e5c9fd5789d7 317 }
manitou 0:e5c9fd5789d7 318 return true;
manitou 0:e5c9fd5789d7 319 }
manitou 0:e5c9fd5789d7 320
manitou 0:e5c9fd5789d7 321
manitou 0:e5c9fd5789d7 322 #define ID0_WINBOND 0xEF
manitou 0:e5c9fd5789d7 323 #define ID0_SPANSION 0x01
manitou 0:e5c9fd5789d7 324 #define ID0_MICRON 0x20
manitou 0:e5c9fd5789d7 325 #define ID0_MACRONIX 0xC2
manitou 0:e5c9fd5789d7 326 #define ID0_SST 0xBF
manitou 0:e5c9fd5789d7 327
manitou 0:e5c9fd5789d7 328 //#define FLAG_32BIT_ADDR 0x01 // larger than 16 MByte address
manitou 0:e5c9fd5789d7 329 //#define FLAG_STATUS_CMD70 0x02 // requires special busy flag check
manitou 0:e5c9fd5789d7 330 //#define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands
manitou 0:e5c9fd5789d7 331 //#define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks
manitou 0:e5c9fd5789d7 332
manitou 0:e5c9fd5789d7 333 bool SerialFlashChip::begin(uint8_t pin)
manitou 0:e5c9fd5789d7 334 {
manitou 0:e5c9fd5789d7 335 uint8_t id[5];
manitou 0:e5c9fd5789d7 336 uint8_t f;
manitou 0:e5c9fd5789d7 337 uint32_t size;
manitou 0:e5c9fd5789d7 338
manitou 0:e5c9fd5789d7 339 spi.frequency(30000000); // max
manitou 0:e5c9fd5789d7 340 CSRELEASE();
manitou 0:e5c9fd5789d7 341 readID(id);
manitou 0:e5c9fd5789d7 342 f = 0;
manitou 0:e5c9fd5789d7 343 size = capacity(id);
manitou 0:e5c9fd5789d7 344 if (size > 16777216) {
manitou 0:e5c9fd5789d7 345 // more than 16 Mbyte requires 32 bit addresses
manitou 0:e5c9fd5789d7 346 f |= FLAG_32BIT_ADDR;
manitou 0:e5c9fd5789d7 347 if (id[0] == ID0_SPANSION) {
manitou 0:e5c9fd5789d7 348 // spansion uses MSB of bank register
manitou 0:e5c9fd5789d7 349 CSASSERT();
manitou 0:e5c9fd5789d7 350 spi.write(0x17); // bank register write
manitou 0:e5c9fd5789d7 351 spi.write(0x80);
manitou 0:e5c9fd5789d7 352 CSRELEASE();
manitou 0:e5c9fd5789d7 353 } else {
manitou 0:e5c9fd5789d7 354 // micron & winbond & macronix use command
manitou 0:e5c9fd5789d7 355 CSASSERT();
manitou 0:e5c9fd5789d7 356 spi.write(0x06); // write enable
manitou 0:e5c9fd5789d7 357 CSRELEASE();
manitou 0:e5c9fd5789d7 358 wait_us(1);
manitou 0:e5c9fd5789d7 359 CSASSERT();
manitou 0:e5c9fd5789d7 360 spi.write(0xB7); // enter 4 byte addr mode
manitou 0:e5c9fd5789d7 361 CSRELEASE();
manitou 0:e5c9fd5789d7 362 }
manitou 0:e5c9fd5789d7 363 if (id[0] == ID0_MICRON) f |= FLAG_MULTI_DIE;
manitou 0:e5c9fd5789d7 364 }
manitou 0:e5c9fd5789d7 365 if (id[0] == ID0_SPANSION) {
manitou 0:e5c9fd5789d7 366 // Spansion has separate suspend commands
manitou 0:e5c9fd5789d7 367 f |= FLAG_DIFF_SUSPEND;
manitou 0:e5c9fd5789d7 368 if (!id[4]) {
manitou 0:e5c9fd5789d7 369 // Spansion chips with id[4] == 0 use 256K sectors
manitou 0:e5c9fd5789d7 370 f |= FLAG_256K_BLOCKS;
manitou 0:e5c9fd5789d7 371 }
manitou 0:e5c9fd5789d7 372 }
manitou 0:e5c9fd5789d7 373 if (id[0] == ID0_MICRON) {
manitou 0:e5c9fd5789d7 374 // Micron requires busy checks with a different command
manitou 0:e5c9fd5789d7 375 f |= FLAG_STATUS_CMD70; // TODO: all or just multi-die chips?
manitou 0:e5c9fd5789d7 376 }
manitou 0:e5c9fd5789d7 377 flags = f;
manitou 0:e5c9fd5789d7 378 readID(id);
manitou 0:e5c9fd5789d7 379 return true;
manitou 0:e5c9fd5789d7 380 }
manitou 0:e5c9fd5789d7 381
manitou 0:e5c9fd5789d7 382 // chips tested: https://github.com/PaulStoffregen/SerialFlash/pull/12#issuecomment-169596992
manitou 0:e5c9fd5789d7 383 //
manitou 0:e5c9fd5789d7 384 void SerialFlashChip::sleep()
manitou 0:e5c9fd5789d7 385 {
manitou 0:e5c9fd5789d7 386 if (busy) wait();
manitou 0:e5c9fd5789d7 387 CSASSERT();
manitou 0:e5c9fd5789d7 388 spi.write(0xB9); // Deep power down command
manitou 0:e5c9fd5789d7 389 CSRELEASE();
manitou 0:e5c9fd5789d7 390 }
manitou 0:e5c9fd5789d7 391
manitou 0:e5c9fd5789d7 392 void SerialFlashChip::wakeup()
manitou 0:e5c9fd5789d7 393 {
manitou 0:e5c9fd5789d7 394 CSASSERT();
manitou 0:e5c9fd5789d7 395 spi.write(0xAB); // Wake up from deep power down command
manitou 0:e5c9fd5789d7 396 CSRELEASE();
manitou 0:e5c9fd5789d7 397 }
manitou 0:e5c9fd5789d7 398
manitou 0:e5c9fd5789d7 399 void SerialFlashChip::readID(uint8_t *buf)
manitou 0:e5c9fd5789d7 400 {
manitou 0:e5c9fd5789d7 401 if (busy) wait();
manitou 0:e5c9fd5789d7 402 CSASSERT();
manitou 0:e5c9fd5789d7 403 spi.write(0x9F);
manitou 0:e5c9fd5789d7 404 buf[0] = spi.write(0); // manufacturer ID
manitou 0:e5c9fd5789d7 405 buf[1] = spi.write(0); // memory type
manitou 0:e5c9fd5789d7 406 buf[2] = spi.write(0); // capacity
manitou 0:e5c9fd5789d7 407 if (buf[0] == ID0_SPANSION) {
manitou 0:e5c9fd5789d7 408 buf[3] = spi.write(0); // ID-CFI
manitou 0:e5c9fd5789d7 409 buf[4] = spi.write(0); // sector size
manitou 0:e5c9fd5789d7 410 }
manitou 0:e5c9fd5789d7 411 CSRELEASE();
manitou 0:e5c9fd5789d7 412 //Serial.printf("ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]);
manitou 0:e5c9fd5789d7 413 }
manitou 0:e5c9fd5789d7 414
manitou 0:e5c9fd5789d7 415 void SerialFlashChip::readSerialNumber(uint8_t *buf) //needs room for 8 bytes
manitou 0:e5c9fd5789d7 416 {
manitou 0:e5c9fd5789d7 417 if (busy) wait();
manitou 0:e5c9fd5789d7 418 CSASSERT();
manitou 0:e5c9fd5789d7 419 spi.write(0x4B);
manitou 0:e5c9fd5789d7 420 spi.write(0);
manitou 0:e5c9fd5789d7 421 spi.write(0);
manitou 0:e5c9fd5789d7 422 spi.write(0);
manitou 0:e5c9fd5789d7 423 spi.write(0);
manitou 0:e5c9fd5789d7 424 for (int i=0; i<8; i++) {
manitou 0:e5c9fd5789d7 425 buf[i] = spi.write(0);
manitou 0:e5c9fd5789d7 426 }
manitou 0:e5c9fd5789d7 427 CSRELEASE();
manitou 0:e5c9fd5789d7 428 // Serial.printf("Serial Number: %02X %02X %02X %02X %02X %02X %02X %02X\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
manitou 0:e5c9fd5789d7 429 }
manitou 0:e5c9fd5789d7 430
manitou 0:e5c9fd5789d7 431 uint32_t SerialFlashChip::capacity(const uint8_t *id)
manitou 0:e5c9fd5789d7 432 {
manitou 0:e5c9fd5789d7 433 uint32_t n = 1048576; // unknown chips, default to 1 MByte
manitou 0:e5c9fd5789d7 434
manitou 0:e5c9fd5789d7 435 if (id[2] >= 16 && id[2] <= 31) {
manitou 0:e5c9fd5789d7 436 n = 1ul << id[2];
manitou 0:e5c9fd5789d7 437 } else
manitou 0:e5c9fd5789d7 438 if (id[2] >= 32 && id[2] <= 37) {
manitou 0:e5c9fd5789d7 439 n = 1ul << (id[2] - 6);
manitou 0:e5c9fd5789d7 440 }
manitou 0:e5c9fd5789d7 441 //Serial.printf("capacity %lu\n", n);
manitou 0:e5c9fd5789d7 442 return n;
manitou 0:e5c9fd5789d7 443 }
manitou 0:e5c9fd5789d7 444
manitou 0:e5c9fd5789d7 445 uint32_t SerialFlashChip::blockSize()
manitou 0:e5c9fd5789d7 446 {
manitou 0:e5c9fd5789d7 447 // Spansion chips >= 512 mbit use 256K sectors
manitou 0:e5c9fd5789d7 448 if (flags & FLAG_256K_BLOCKS) return 262144;
manitou 0:e5c9fd5789d7 449 // everything else seems to have 64K sectors
manitou 0:e5c9fd5789d7 450 return 65536;
manitou 0:e5c9fd5789d7 451 }
manitou 0:e5c9fd5789d7 452
manitou 0:e5c9fd5789d7 453
manitou 0:e5c9fd5789d7 454
manitou 0:e5c9fd5789d7 455
manitou 0:e5c9fd5789d7 456 /*
manitou 0:e5c9fd5789d7 457 Chip Uniform Sector Erase
manitou 0:e5c9fd5789d7 458 20/21 52 D8/DC
manitou 0:e5c9fd5789d7 459 ----- -- -----
manitou 0:e5c9fd5789d7 460 W25Q64CV 4 32 64
manitou 0:e5c9fd5789d7 461 W25Q128FV 4 32 64
manitou 0:e5c9fd5789d7 462 S25FL127S 64
manitou 0:e5c9fd5789d7 463 N25Q512A 4 64
manitou 0:e5c9fd5789d7 464 N25Q00AA 4 64
manitou 0:e5c9fd5789d7 465 S25FL512S 256
manitou 0:e5c9fd5789d7 466 SST26VF032 4
manitou 0:e5c9fd5789d7 467 */
manitou 0:e5c9fd5789d7 468
manitou 0:e5c9fd5789d7 469
manitou 0:e5c9fd5789d7 470
manitou 0:e5c9fd5789d7 471 // size sector busy pgm/erase chip
manitou 0:e5c9fd5789d7 472 // Part Mbyte kbyte ID bytes cmd suspend erase
manitou 0:e5c9fd5789d7 473 // ---- ---- ----- -------- --- ------- -----
lzbpli 1:5f1a6c63fa57 474 // Winbond W25Q64CV 8 64 EF 40 17
manitou 0:e5c9fd5789d7 475 // Winbond W25Q128FV 16 64 EF 40 18 05 single 60 & C7
manitou 0:e5c9fd5789d7 476 // Winbond W25Q256FV 32 64 EF 40 19
manitou 0:e5c9fd5789d7 477 // Spansion S25FL064A 8 ? 01 02 16
manitou 0:e5c9fd5789d7 478 // Spansion S25FL127S 16 64 01 20 18 05
manitou 0:e5c9fd5789d7 479 // Spansion S25FL128P 16 64 01 20 18
manitou 0:e5c9fd5789d7 480 // Spansion S25FL256S 32 64 01 02 19 05 60 & C7
manitou 0:e5c9fd5789d7 481 // Spansion S25FL512S 64 256 01 02 20
manitou 0:e5c9fd5789d7 482 // Macronix MX25L12805D 16 ? C2 20 18
manitou 0:e5c9fd5789d7 483 // Macronix MX66L51235F 64 C2 20 1A
manitou 0:e5c9fd5789d7 484 // Numonyx M25P128 16 ? 20 20 18
manitou 0:e5c9fd5789d7 485 // Micron M25P80 1 ? 20 20 14
manitou 0:e5c9fd5789d7 486 // Micron N25Q128A 16 64 20 BA 18
manitou 0:e5c9fd5789d7 487 // Micron N25Q512A 64 ? 20 BA 20 70 single C4 x2
manitou 0:e5c9fd5789d7 488 // Micron N25Q00AA 128 64 20 BA 21 single C4 x4
manitou 0:e5c9fd5789d7 489 // Micron MT25QL02GC 256 64 20 BA 22 70 C4 x2
manitou 0:e5c9fd5789d7 490 // SST SST25WF010 1/8 ? BF 25 02
manitou 0:e5c9fd5789d7 491 // SST SST25WF020 1/4 ? BF 25 03
manitou 0:e5c9fd5789d7 492 // SST SST25WF040 1/2 ? BF 25 04
manitou 0:e5c9fd5789d7 493 // SST SST25VF016B 1 ? BF 25 41
manitou 0:e5c9fd5789d7 494 // SST26VF016 ? BF 26 01
manitou 0:e5c9fd5789d7 495 // SST26VF032 ? BF 26 02
manitou 0:e5c9fd5789d7 496 // SST25VF032 4 64 BF 25 4A
manitou 0:e5c9fd5789d7 497 // SST26VF064 8 ? BF 26 43
manitou 0:e5c9fd5789d7 498 // LE25U40CMC 1/2 64 62 06 13
manitou 0:e5c9fd5789d7 499
manitou 0:e5c9fd5789d7 500 SerialFlashChip SerialFlash;