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

пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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. #define CSCONFIG() pinMode(6, OUTPUT)
  29. #define CSASSERT() digitalWriteFast(6, LOW)
  30. #define CSRELEASE() digitalWriteFast(6, HIGH)
  31. #define SPICONFIG SPISettings(50000000, MSBFIRST, SPI_MODE0)
  32. #if !defined(__arm__) || !defined(CORE_TEENSY)
  33. #define digitalWriteFast(pin, state) digitalWrite((pin), (state))
  34. #endif
  35. uint16_t SerialFlashChip::dirindex = 0;
  36. uint8_t SerialFlashChip::fourbytemode = 0;
  37. uint8_t SerialFlashChip::busy = 0;
  38. void SerialFlashChip::wait(void)
  39. {
  40. uint32_t status;
  41. do {
  42. SPI.beginTransaction(SPICONFIG);
  43. CSASSERT();
  44. status = SPI.transfer16(0x0500);
  45. CSRELEASE();
  46. SPI.endTransaction();
  47. } while ((status & 1));
  48. busy = 0;
  49. }
  50. void SerialFlashChip::read(void *buf, uint32_t addr, uint32_t len)
  51. {
  52. uint8_t *p = (uint8_t *)buf;
  53. uint8_t b;
  54. memset(p, 0, len);
  55. b = busy;
  56. if (b) {
  57. if (b == 1) {
  58. // TODO: this may not work on Spansion chips
  59. // which apparently have 2 different suspend
  60. // commands, for program vs erase
  61. SPI.beginTransaction(SPICONFIG);
  62. CSASSERT();
  63. SPI.transfer(0x75); // Suspend program/erase
  64. CSRELEASE();
  65. SPI.endTransaction();
  66. delayMicroseconds(20); // Tsus = 20us
  67. } else {
  68. wait();
  69. }
  70. }
  71. SPI.beginTransaction(SPICONFIG);
  72. CSASSERT();
  73. // TODO: FIFO optimize....
  74. if (fourbytemode) {
  75. SPI.transfer(0x13);
  76. SPI.transfer16(addr >> 16);
  77. SPI.transfer16(addr);
  78. } else {
  79. SPI.transfer16(0x0300 | ((addr >> 16) & 255));
  80. SPI.transfer16(addr);
  81. }
  82. SPI.transfer(p, len);
  83. CSRELEASE();
  84. SPI.endTransaction();
  85. if (b == 1) {
  86. SPI.beginTransaction(SPICONFIG);
  87. CSASSERT();
  88. SPI.transfer(0x7A); // Resume program/erase
  89. CSRELEASE();
  90. SPI.endTransaction();
  91. }
  92. }
  93. void SerialFlashChip::write(const void *buf, uint32_t addr, uint32_t len)
  94. {
  95. const uint8_t *p = (const uint8_t *)buf;
  96. uint32_t max, pagelen;
  97. do {
  98. if (busy) wait();
  99. SPI.beginTransaction(SPICONFIG);
  100. CSASSERT();
  101. SPI.transfer(0x06);
  102. CSRELEASE();
  103. //delayMicroseconds(1);
  104. max = 256 - (addr & 0xFF);
  105. pagelen = (len <= max) ? len : max;
  106. len -= pagelen;
  107. CSASSERT();
  108. if (fourbytemode) {
  109. // TODO: Winbond doesn't implement 0x12 on W25Q256FV
  110. SPI.transfer(0x12);
  111. SPI.transfer16(addr >> 16);
  112. SPI.transfer16(addr);
  113. } else {
  114. SPI.transfer16(0x0200 | ((addr >> 16) & 255));
  115. SPI.transfer16(addr);
  116. }
  117. do {
  118. SPI.transfer(*p++);
  119. } while (--pagelen > 0);
  120. CSRELEASE();
  121. SPI.endTransaction();
  122. busy = 1;
  123. } while (len > 0);
  124. }
  125. void SerialFlashChip::eraseAll()
  126. {
  127. if (busy) wait();
  128. SPI.beginTransaction(SPICONFIG);
  129. CSASSERT();
  130. SPI.transfer(0x06);
  131. CSRELEASE();
  132. CSASSERT();
  133. SPI.transfer(0xC7);
  134. CSRELEASE();
  135. SPI.endTransaction();
  136. busy = 2;
  137. }
  138. void SerialFlashChip::eraseBlock(uint32_t addr)
  139. {
  140. if (busy) wait();
  141. SPI.beginTransaction(SPICONFIG);
  142. CSASSERT();
  143. if (fourbytemode) {
  144. // TODO: Winbond doesn't implement 0xDC on W25Q256FV
  145. SPI.transfer(0xDC);
  146. SPI.transfer16(addr >> 16);
  147. SPI.transfer16(addr);
  148. } else {
  149. SPI.transfer16(0xD800 | ((addr >> 16) & 255));
  150. SPI.transfer16(addr);
  151. }
  152. CSRELEASE();
  153. SPI.endTransaction();
  154. busy = 1;
  155. }
  156. bool SerialFlashChip::ready()
  157. {
  158. uint32_t status;
  159. if (!busy) return true;
  160. SPI.beginTransaction(SPICONFIG);
  161. CSASSERT();
  162. status = SPI.transfer16(0x0500);
  163. CSRELEASE();
  164. SPI.endTransaction();
  165. if ((status & 1)) return false;
  166. busy = 0;
  167. return true;
  168. }
  169. bool SerialFlashChip::begin()
  170. {
  171. SPI.begin();
  172. CSCONFIG();
  173. CSRELEASE();
  174. if (capacity() <= 16777216) {
  175. fourbytemode = 0;
  176. } else {
  177. fourbytemode = 1; // chip larger than 16 MByte
  178. // TODO: need to configure for 32 bit address mode
  179. // because Winbond doesn't implement 0x12 & 0xDC
  180. }
  181. return true;
  182. }
  183. void SerialFlashChip::readID(uint8_t *buf)
  184. {
  185. if (busy) wait();
  186. SPI.beginTransaction(SPICONFIG);
  187. CSASSERT();
  188. SPI.transfer(0x9F);
  189. buf[0] = SPI.transfer(0); // manufacturer ID
  190. buf[1] = SPI.transfer(0); // memory type
  191. buf[2] = SPI.transfer(0); // capacity
  192. CSRELEASE();
  193. SPI.endTransaction();
  194. }
  195. uint32_t SerialFlashChip::capacity()
  196. {
  197. uint8_t id[3];
  198. readID(id);
  199. //Serial.print("capacity ");
  200. //Serial.println(id[3], HEX);
  201. if (id[2] >= 16 && id[2] <= 31) {
  202. return 1 >> id[2];
  203. }
  204. if (id[2] >= 32 && id[2] <= 37) {
  205. return 1 >> (id[2] - 6);
  206. }
  207. return 1048576; // unknown, guess 1 MByte
  208. }
  209. uint32_t SerialFlashChip::blockSize()
  210. {
  211. uint8_t id[3];
  212. readID(id);
  213. if (id[0] == 1 && id[2] > 0x19) {
  214. // Spansion chips >= 512 mbit use 256K sectors
  215. return 262144;
  216. }
  217. // everything else seems to have 64K sectors
  218. return 65536;
  219. }
  220. /*
  221. Chip Uniform Sector Erase
  222. 20/21 52 D8/DC
  223. ----- -- -----
  224. W25Q64CV 4 32 64
  225. W25Q128FV 4 32 64
  226. S25FL127S 64
  227. N25Q512A 4 64
  228. N25Q00AA 4 64
  229. S25FL512S 256
  230. SST26VF032 4
  231. */
  232. // size sector
  233. // Part Mbit kbyte ID bytes Digikey
  234. // ---- ---- ----- -------- -------
  235. // Winbond W25Q64CV 64 4/32/64 EF 40 17 W25Q128FVSIG-ND
  236. // Winbond W25Q128FV 128 4/32/64 EF 40 18 W25Q128FVSIG-ND
  237. // Winbond W25Q256FV 256 64 EF 40 19
  238. // Spansion S25FL064A 64 01 02 16 ?
  239. // Spansion S25FL127S 128 64 01 20 18 1274-1045-ND
  240. // Spansion S25FL128P 128 64 01 20 18
  241. // Spansion S25FL256S 256 64 01 02 19
  242. // Spansion S25FL512S 512 256 01 02 20
  243. // Macronix MX25L12805D 128 C2 20 18
  244. // Numonyx M25P128 128 20 20 18
  245. // Micron M25P80 8 20 20 14
  246. // Micron N25Q512A 512 4 20 BA 20 557-1569-ND
  247. // Micron N25Q00AA 1024 4/64 20 BA 21 557-1571-5-ND
  248. // Micron MT25QL02GC 2048 4/64 20 BB 22
  249. // SST SST25WF512 0.5 BF 25 01
  250. // SST SST25WF010 1 BF 25 02
  251. // SST SST25WF020 2 BF 25 03
  252. // SST SST25WF040 4 BF 25 04
  253. // SST SST25VF016B 16 BF 25 41
  254. // SST26VF016 BF 26 01
  255. // SST26VF032 BF 26 02
  256. // SST25VF032 32 4/32/64 BF 25 4A
  257. // SST26VF064 64 BF 26 43
  258. // LE25U40CMC 4 4/64 62 06 13
  259. SerialFlashChip SerialFlash;