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 13KB

9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
9 yıl önce
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  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. uint16_t SerialFlashChip::dirindex = 0;
  33. uint8_t SerialFlashChip::flags = 0;
  34. uint8_t SerialFlashChip::busy = 0;
  35. static volatile IO_REG_TYPE *cspin_basereg;
  36. static IO_REG_TYPE cspin_bitmask;
  37. #define FLAG_32BIT_ADDR 0x01 // larger than 16 MByte address
  38. #define FLAG_STATUS_CMD70 0x02 // requires special busy flag check
  39. #define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands
  40. #define FLAG_MULTI_DIE 0x08 // multiple die, don't read cross 32M barrier
  41. #define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks
  42. #define FLAG_DIE_MASK 0xC0 // top 2 bits count during multi-die erase
  43. void SerialFlashChip::wait(void)
  44. {
  45. uint32_t status;
  46. //Serial.print("wait-");
  47. while (1) {
  48. SPI.beginTransaction(SPICONFIG);
  49. CSASSERT();
  50. if (flags & FLAG_STATUS_CMD70) {
  51. // some Micron chips require this different
  52. // command to detect program and erase completion
  53. SPI.transfer(0x70);
  54. status = SPI.transfer(0);
  55. CSRELEASE();
  56. SPI.endTransaction();
  57. //Serial.printf("b=%02x.", status & 0xFF);
  58. if ((status & 0x80)) break;
  59. } else {
  60. // all others work by simply reading the status reg
  61. SPI.transfer(0x05);
  62. status = SPI.transfer(0);
  63. CSRELEASE();
  64. SPI.endTransaction();
  65. //Serial.printf("b=%02x.", status & 0xFF);
  66. if (!(status & 1)) break;
  67. }
  68. }
  69. busy = 0;
  70. //Serial.println();
  71. }
  72. void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)
  73. {
  74. uint8_t *p = (uint8_t *)buf;
  75. uint8_t b, f, status, cmd;
  76. memset(p, 0, len);
  77. f = flags;
  78. SPI.beginTransaction(SPICONFIG);
  79. b = busy;
  80. if (b) {
  81. // read status register ... chip may no longer be busy
  82. CSASSERT();
  83. if (flags & FLAG_STATUS_CMD70) {
  84. SPI.transfer(0x70);
  85. status = SPI.transfer(0);
  86. if ((status & 0x80)) b = 0;
  87. } else {
  88. SPI.transfer(0x05);
  89. status = SPI.transfer(0);
  90. if (!(status & 1)) b = 0;
  91. }
  92. CSRELEASE();
  93. if (b == 0) {
  94. // chip is no longer busy :-)
  95. busy = 0;
  96. } else if (b < 3) {
  97. // TODO: this may not work on Spansion chips
  98. // which apparently have 2 different suspend
  99. // commands, for program vs erase
  100. CSASSERT();
  101. SPI.transfer(0x06); // write enable (Micron req'd)
  102. CSRELEASE();
  103. delayMicroseconds(1);
  104. cmd = 0x75; //Suspend program/erase for almost all chips
  105. // but Spansion just has to be different for program suspend!
  106. if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85;
  107. CSASSERT();
  108. SPI.transfer(cmd); // Suspend command
  109. CSRELEASE();
  110. if (f & FLAG_STATUS_CMD70) {
  111. // Micron chips don't actually suspend until flags read
  112. CSASSERT();
  113. SPI.transfer(0x70);
  114. do {
  115. status = SPI.transfer(0);
  116. } while (!(status & 0x80));
  117. CSRELEASE();
  118. } else {
  119. CSASSERT();
  120. SPI.transfer(0x05);
  121. do {
  122. status = SPI.transfer(0);
  123. } while ((status & 0x01));
  124. CSRELEASE();
  125. }
  126. } else {
  127. // chip is busy with an operation that can not suspend
  128. SPI.endTransaction(); // is this a good idea?
  129. wait(); // should we wait without ending
  130. b = 0; // the transaction??
  131. SPI.beginTransaction(SPICONFIG);
  132. }
  133. }
  134. do {
  135. uint32_t rdlen = len;
  136. if (f & FLAG_MULTI_DIE) {
  137. if ((addr & 0xFE000000) != ((addr + len - 1) & 0xFE000000)) {
  138. rdlen = 0x2000000 - (addr & 0x1FFFFFF);
  139. }
  140. }
  141. CSASSERT();
  142. // TODO: FIFO optimize....
  143. if (f & FLAG_32BIT_ADDR) {
  144. SPI.transfer(0x03);
  145. SPI.transfer16(addr >> 16);
  146. SPI.transfer16(addr);
  147. } else {
  148. SPI.transfer16(0x0300 | ((addr >> 16) & 255));
  149. SPI.transfer16(addr);
  150. }
  151. SPI.transfer(p, rdlen);
  152. CSRELEASE();
  153. p += rdlen;
  154. addr += rdlen;
  155. len -= rdlen;
  156. } while (len > 0);
  157. if (b) {
  158. CSASSERT();
  159. SPI.transfer(0x06); // write enable (Micron req'd)
  160. CSRELEASE();
  161. delayMicroseconds(1);
  162. cmd = 0x7A;
  163. if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A;
  164. CSASSERT();
  165. SPI.transfer(cmd); // Resume program/erase
  166. CSRELEASE();
  167. }
  168. SPI.endTransaction();
  169. }
  170. void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len)
  171. {
  172. const uint8_t *p = (const uint8_t *)buf;
  173. uint32_t max, pagelen;
  174. //Serial.printf("WR: addr %08X, len %d\n", addr, len);
  175. do {
  176. if (busy) wait();
  177. SPI.beginTransaction(SPICONFIG);
  178. CSASSERT();
  179. // write enable command
  180. SPI.transfer(0x06);
  181. CSRELEASE();
  182. max = 256 - (addr & 0xFF);
  183. pagelen = (len <= max) ? len : max;
  184. //Serial.printf("WR: addr %08X, pagelen %d\n", addr, pagelen);
  185. CSASSERT();
  186. if (flags & FLAG_32BIT_ADDR) {
  187. SPI.transfer(0x02); // program page command
  188. SPI.transfer16(addr >> 16);
  189. SPI.transfer16(addr);
  190. } else {
  191. SPI.transfer16(0x0200 | ((addr >> 16) & 255));
  192. SPI.transfer16(addr);
  193. }
  194. addr += pagelen;
  195. len -= pagelen;
  196. do {
  197. SPI.transfer(*p++);
  198. } while (--pagelen > 0);
  199. CSRELEASE();
  200. busy = 1;
  201. SPI.endTransaction();
  202. } while (len > 0);
  203. }
  204. void SerialFlashChip::eraseAll()
  205. {
  206. if (busy) wait();
  207. uint8_t id[5];
  208. readID(id);
  209. //Serial.printf("ID: %02X %02X %02X\n", id[0], id[1], id[2]);
  210. if (id[0] == 0x20 && id[2] >= 0x20 && id[2] <= 0x22) {
  211. // Micron's multi-die chips require special die erase commands
  212. // N25Q512A 20 BA 20 2 dies 32 Mbyte/die 65 nm transitors
  213. // N25Q00AA 20 BA 21 4 dies 32 Mbyte/die 65 nm transitors
  214. // MT25QL02GC 20 BA 22 2 dies 128 Mbyte/die 45 nm transitors
  215. uint8_t die_count = 2;
  216. if (id[2] == 0x21) die_count = 4;
  217. uint8_t die_index = flags >> 6;
  218. //Serial.printf("Micron die erase %d\n", die_index);
  219. flags &= 0x3F;
  220. if (die_index >= die_count) return; // all dies erased :-)
  221. uint8_t die_size = 2; // in 16 Mbyte units
  222. if (id[2] == 0x22) die_size = 8;
  223. SPI.beginTransaction(SPICONFIG);
  224. CSASSERT();
  225. SPI.transfer(0x06); // write enable command
  226. CSRELEASE();
  227. delayMicroseconds(1);
  228. CSASSERT();
  229. // die erase command
  230. SPI.transfer(0xC4);
  231. SPI.transfer16((die_index * die_size) << 8);
  232. SPI.transfer16(0x0000);
  233. CSRELEASE();
  234. //Serial.printf("Micron erase begin\n");
  235. flags |= (die_index + 1) << 6;
  236. } else {
  237. // All other chips support the bulk erase command
  238. SPI.beginTransaction(SPICONFIG);
  239. CSASSERT();
  240. // write enable command
  241. SPI.transfer(0x06);
  242. CSRELEASE();
  243. delayMicroseconds(1);
  244. CSASSERT();
  245. // bulk erase command
  246. SPI.transfer(0xC7);
  247. CSRELEASE();
  248. SPI.endTransaction();
  249. }
  250. busy = 3;
  251. }
  252. void SerialFlashChip::eraseBlock(uint32_t addr)
  253. {
  254. uint8_t f = flags;
  255. if (busy) wait();
  256. SPI.beginTransaction(SPICONFIG);
  257. CSASSERT();
  258. SPI.transfer(0x06); // write enable command
  259. CSRELEASE();
  260. delayMicroseconds(1);
  261. CSASSERT();
  262. if (f & FLAG_32BIT_ADDR) {
  263. SPI.transfer(0xD8);
  264. SPI.transfer16(addr >> 16);
  265. SPI.transfer16(addr);
  266. } else {
  267. SPI.transfer16(0xD800 | ((addr >> 16) & 255));
  268. SPI.transfer16(addr);
  269. }
  270. CSRELEASE();
  271. SPI.endTransaction();
  272. busy = 2;
  273. }
  274. bool SerialFlashChip::ready()
  275. {
  276. uint32_t status;
  277. if (!busy) return true;
  278. SPI.beginTransaction(SPICONFIG);
  279. CSASSERT();
  280. if (flags & FLAG_STATUS_CMD70) {
  281. // some Micron chips require this different
  282. // command to detect program and erase completion
  283. SPI.transfer(0x70);
  284. status = SPI.transfer(0);
  285. CSRELEASE();
  286. SPI.endTransaction();
  287. //Serial.printf("ready=%02x\n", status & 0xFF);
  288. if ((status & 0x80) == 0) return false;
  289. } else {
  290. // all others work by simply reading the status reg
  291. SPI.transfer(0x05);
  292. status = SPI.transfer(0);
  293. CSRELEASE();
  294. SPI.endTransaction();
  295. //Serial.printf("ready=%02x\n", status & 0xFF);
  296. if ((status & 1)) return false;
  297. }
  298. busy = 0;
  299. if (flags & 0xC0) {
  300. // continue a multi-die erase
  301. eraseAll();
  302. return false;
  303. }
  304. return true;
  305. }
  306. #define ID0_WINBOND 0xEF
  307. #define ID0_SPANSION 0x01
  308. #define ID0_MICRON 0x20
  309. #define ID0_MACRONIX 0xC2
  310. #define ID0_SST 0xBF
  311. //#define FLAG_32BIT_ADDR 0x01 // larger than 16 MByte address
  312. //#define FLAG_STATUS_CMD70 0x02 // requires special busy flag check
  313. //#define FLAG_DIFF_SUSPEND 0x04 // uses 2 different suspend commands
  314. //#define FLAG_256K_BLOCKS 0x10 // has 256K erase blocks
  315. bool SerialFlashChip::begin(uint8_t pin)
  316. {
  317. uint8_t id[5];
  318. uint8_t f;
  319. uint32_t size;
  320. cspin_basereg = PIN_TO_BASEREG(pin);
  321. cspin_bitmask = PIN_TO_BITMASK(pin);
  322. SPI.begin();
  323. pinMode(pin, OUTPUT);
  324. CSRELEASE();
  325. readID(id);
  326. f = 0;
  327. size = capacity(id);
  328. if (size > 16777216) {
  329. // more than 16 Mbyte requires 32 bit addresses
  330. f |= FLAG_32BIT_ADDR;
  331. SPI.beginTransaction(SPICONFIG);
  332. if (id[0] == ID0_SPANSION) {
  333. // spansion uses MSB of bank register
  334. CSASSERT();
  335. SPI.transfer16(0x1780); // bank register write
  336. CSRELEASE();
  337. } else {
  338. // micron & winbond & macronix use command
  339. CSASSERT();
  340. SPI.transfer(0x06); // write enable
  341. CSRELEASE();
  342. delayMicroseconds(1);
  343. CSASSERT();
  344. SPI.transfer(0xB7); // enter 4 byte addr mode
  345. CSRELEASE();
  346. }
  347. SPI.endTransaction();
  348. if (id[0] == ID0_MICRON) f |= FLAG_MULTI_DIE;
  349. }
  350. if (id[0] == ID0_SPANSION) {
  351. // Spansion has separate suspend commands
  352. f |= FLAG_DIFF_SUSPEND;
  353. if (!id[4]) {
  354. // Spansion chips with id[4] == 0 use 256K sectors
  355. f |= FLAG_256K_BLOCKS;
  356. }
  357. }
  358. if (id[0] == ID0_MICRON) {
  359. // Micron requires busy checks with a different command
  360. f |= FLAG_STATUS_CMD70; // TODO: all or just multi-die chips?
  361. }
  362. flags = f;
  363. readID(id);
  364. return true;
  365. }
  366. // chips tested: https://github.com/PaulStoffregen/SerialFlash/pull/12#issuecomment-169596992
  367. //
  368. void SerialFlashChip::sleep()
  369. {
  370. if (busy) wait();
  371. SPI.beginTransaction(SPICONFIG);
  372. CSASSERT();
  373. SPI.transfer(0xB9); // Deep power down command
  374. CSRELEASE();
  375. }
  376. void SerialFlashChip::wakeup()
  377. {
  378. SPI.beginTransaction(SPICONFIG);
  379. CSASSERT();
  380. SPI.transfer(0xAB); // Wake up from deep power down command
  381. CSRELEASE();
  382. }
  383. void SerialFlashChip::readID(uint8_t *buf)
  384. {
  385. if (busy) wait();
  386. SPI.beginTransaction(SPICONFIG);
  387. CSASSERT();
  388. SPI.transfer(0x9F);
  389. buf[0] = SPI.transfer(0); // manufacturer ID
  390. buf[1] = SPI.transfer(0); // memory type
  391. buf[2] = SPI.transfer(0); // capacity
  392. if (buf[0] == ID0_SPANSION) {
  393. buf[3] = SPI.transfer(0); // ID-CFI
  394. buf[4] = SPI.transfer(0); // sector size
  395. }
  396. CSRELEASE();
  397. SPI.endTransaction();
  398. //Serial.printf("ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]);
  399. }
  400. uint32_t SerialFlashChip::capacity(const uint8_t *id)
  401. {
  402. uint32_t n = 1048576; // unknown chips, default to 1 MByte
  403. if (id[2] >= 16 && id[2] <= 31) {
  404. n = 1ul << id[2];
  405. } else
  406. if (id[2] >= 32 && id[2] <= 37) {
  407. n = 1ul << (id[2] - 6);
  408. }
  409. //Serial.printf("capacity %lu\n", n);
  410. return n;
  411. }
  412. uint32_t SerialFlashChip::blockSize()
  413. {
  414. // Spansion chips >= 512 mbit use 256K sectors
  415. if (flags & FLAG_256K_BLOCKS) return 262144;
  416. // everything else seems to have 64K sectors
  417. return 65536;
  418. }
  419. /*
  420. Chip Uniform Sector Erase
  421. 20/21 52 D8/DC
  422. ----- -- -----
  423. W25Q64CV 4 32 64
  424. W25Q128FV 4 32 64
  425. S25FL127S 64
  426. N25Q512A 4 64
  427. N25Q00AA 4 64
  428. S25FL512S 256
  429. SST26VF032 4
  430. */
  431. // size sector busy pgm/erase chip
  432. // Part Mbyte kbyte ID bytes cmd suspend erase
  433. // ---- ---- ----- -------- --- ------- -----
  434. // Winbond W25Q64CV 8 64 EF 40 17
  435. // Winbond W25Q128FV 16 64 EF 40 18 05 single 60 & C7
  436. // Winbond W25Q256FV 32 64 EF 40 19
  437. // Spansion S25FL064A 8 ? 01 02 16
  438. // Spansion S25FL127S 16 64 01 20 18 05
  439. // Spansion S25FL128P 16 64 01 20 18
  440. // Spansion S25FL256S 32 64 01 02 19 05 60 & C7
  441. // Spansion S25FL512S 64 256 01 02 20
  442. // Macronix MX25L12805D 16 ? C2 20 18
  443. // Macronix MX66L51235F 64 C2 20 1A
  444. // Numonyx M25P128 16 ? 20 20 18
  445. // Micron M25P80 1 ? 20 20 14
  446. // Micron N25Q128A 16 64 20 BA 18
  447. // Micron N25Q512A 64 ? 20 BA 20 70 single C4 x2
  448. // Micron N25Q00AA 128 64 20 BA 21 single C4 x4
  449. // Micron MT25QL02GC 256 64 20 BA 22 70 C4 x2
  450. // SST SST25WF010 1/8 ? BF 25 02
  451. // SST SST25WF020 1/4 ? BF 25 03
  452. // SST SST25WF040 1/2 ? BF 25 04
  453. // SST SST25VF016B 1 ? BF 25 41
  454. // SST26VF016 ? BF 26 01
  455. // SST26VF032 ? BF 26 02
  456. // SST25VF032 4 64 BF 25 4A
  457. // SST26VF064 8 ? BF 26 43
  458. // LE25U40CMC 1/2 64 62 06 13
  459. SerialFlashChip SerialFlash;