You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SerialFlashChip.cpp 14KB

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