Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

283 lines
7.0KB

  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;