spiflash.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. * SPI Flash library
  3. * Contains functions to interact with the Winbond W25Q128 SPI Flash chip
  4. */
  5. // Sets SPI0_CS low
  6. void spiflash_begin_transfer()
  7. {
  8. asm(
  9. "; Backup regs\n"
  10. "push r1\n"
  11. "push r2\n"
  12. "load32 0xC02729 r2 ; r2 = 0xC02729\n"
  13. "load 0 r1 ; r1 = 0 (enable)\n"
  14. "write 0 r2 r1 ; write to SPI0_CS\n"
  15. "; Restore regs\n"
  16. "pop r2\n"
  17. "pop r1\n"
  18. );
  19. }
  20. // Sets SPI0_CS high
  21. void spiflash_end_transfer()
  22. {
  23. asm(
  24. "; Backup regs\n"
  25. "push r1\n"
  26. "push r2\n"
  27. "load32 0xC02729 r2 ; r2 = 0xC02729\n"
  28. "load 1 r1 ; r1 = 1 (disable)\n"
  29. "write 0 r2 r1 ; write to SPI0_CS\n"
  30. "; Restore regs\n"
  31. "pop r2\n"
  32. "pop r1\n"
  33. );
  34. }
  35. // Write dataByte and return read value
  36. // Write 0x00 for a read
  37. // Writes byte over SPI0
  38. word spiflash_transfer(word dataByte)
  39. {
  40. word retval = 0;
  41. asm(
  42. "load32 0xC02728 r2 ; r2 = 0xC02728\n"
  43. "write 0 r2 r4 ; write r4 over SPI0\n"
  44. "read 0 r2 r2 ; read return value\n"
  45. "write -4 r14 r2 ; write to stack to return\n"
  46. );
  47. return retval;
  48. }
  49. // Disable manual operation and set SPI0 back to QSPI mode
  50. // This allows SPI content to be read directly from memory at high speeds
  51. // However, this disables writing and other manual operations
  52. void spiflash_qspi()
  53. {
  54. // Send QSPI command
  55. spiflash_begin_transfer();
  56. spiflash_transfer(0xEB);
  57. spiflash_end_transfer();
  58. // Disable SPI0 (connects SPIreader.v and disconnects simpleSPI.v)
  59. word *p = (word *) 0xC0272A; // Set address (SPI0 enable)
  60. *p = 0; // Write value
  61. delay(10);
  62. }
  63. // Initialize manual operation of SPI flash by enabling SPI0 and resetting the chip
  64. // This is needed to get out of continuous read mode and allow manual commands
  65. void spiflash_init()
  66. {
  67. // Already set CS high before enabling SPI0
  68. spiflash_end_transfer();
  69. // Enable SPI0 (connects simpleSPI.v and disconnects SPIreader.v)
  70. word *p = (word *) 0xC0272A; // Set address (SPI0 enable)
  71. *p = 1; // Write value
  72. delay(10);
  73. // Reset to get out of continuous read mode
  74. spiflash_begin_transfer();
  75. spiflash_transfer(0x66);
  76. spiflash_end_transfer();
  77. delay(1);
  78. spiflash_begin_transfer();
  79. spiflash_transfer(0x99);
  80. spiflash_end_transfer();
  81. delay(1);
  82. spiflash_begin_transfer();
  83. spiflash_transfer(0x66);
  84. spiflash_end_transfer();
  85. delay(1);
  86. spiflash_begin_transfer();
  87. spiflash_transfer(0x99);
  88. spiflash_end_transfer();
  89. delay(1);
  90. }
  91. // Reads manufacturer and device IDs and prints them over UART
  92. // Should print 239 as Winbond manufacturer, and 23 for W25Q128 device ID
  93. void spiflash_read_chip_ids()
  94. {
  95. spiflash_begin_transfer();
  96. spiflash_transfer(0x90);
  97. spiflash_transfer(0);
  98. spiflash_transfer(0);
  99. spiflash_transfer(0);
  100. word manufacturer = spiflash_transfer(0);
  101. word deviceID = spiflash_transfer(0);
  102. spiflash_end_transfer();
  103. uprint("Manufacturer ID: ");
  104. uprintDec(manufacturer);
  105. uprint("\n");
  106. uprint("Device ID: ");
  107. uprintDec(deviceID);
  108. uprint("\n");
  109. }
  110. // Enables write operation on the chip
  111. void spiflash_enable_write()
  112. {
  113. spiflash_begin_transfer();
  114. spiflash_transfer(0x06);
  115. spiflash_end_transfer();
  116. }
  117. // Reads len bytes from addr and stores them in output
  118. // If bytes_to_word is 1, then each 4 bytes are shifted into one word in output with len in words
  119. void spiflash_read_from_address(word* output, word addr, word len, word bytes_to_word)
  120. {
  121. spiflash_begin_transfer();
  122. spiflash_transfer(0x03);
  123. spiflash_transfer(addr >> 16);
  124. spiflash_transfer(addr >> 8);
  125. spiflash_transfer(addr);
  126. if (bytes_to_word)
  127. {
  128. len = len << 2;
  129. word i;
  130. for (i = 0; i < len; i++)
  131. {
  132. if ((i & 3) == 0)
  133. {
  134. output[i >> 2] = 0;
  135. }
  136. output[i >> 2] |= spiflash_transfer(0) << (24 - ((i & 3) << 3));
  137. }
  138. }
  139. else
  140. {
  141. word i;
  142. for (i = 0; i < len; i++)
  143. {
  144. output[i] = spiflash_transfer(0);
  145. }
  146. }
  147. spiflash_end_transfer();
  148. }
  149. // Writes up to 64 words as 256 bytes to the given address
  150. // Address must be aligned to a page boundary
  151. void spiflash_write_page_in_words(word* input, word addr, word len)
  152. {
  153. // Check if length exceeds page size
  154. if (len > 64)
  155. {
  156. uprintln("Error: cannot write more than a page!");
  157. return;
  158. }
  159. // Check if address is aligned to a page boundary
  160. if (addr & 0x3F)
  161. {
  162. uprintln("Error: address must be aligned to a page boundary!");
  163. return;
  164. }
  165. spiflash_enable_write();
  166. word status = spiflash_read_status_reg(1);
  167. // Check if write is enabled
  168. if ((status & 0x2) == 0)
  169. {
  170. uprintln("WE disabled!");
  171. return;
  172. }
  173. spiflash_begin_transfer();
  174. spiflash_transfer(0x02);
  175. spiflash_transfer(addr >> 16);
  176. spiflash_transfer(addr >> 8);
  177. spiflash_transfer(addr);
  178. word i;
  179. for (i = 0; i < len; i++)
  180. {
  181. spiflash_transfer(input[i] >> 24);
  182. spiflash_transfer(input[i] >> 16);
  183. spiflash_transfer(input[i] >> 8);
  184. spiflash_transfer(input[i]);
  185. }
  186. spiflash_end_transfer();
  187. // Wait for busy bit to be 0
  188. status = 1;
  189. while((status & 0x1) == 1)
  190. {
  191. status = spiflash_read_status_reg(1);
  192. }
  193. }
  194. // Reads status register 1, 2, or 3
  195. word spiflash_read_status_reg(word reg_idx)
  196. {
  197. if (reg_idx < 1 || reg_idx > 3)
  198. return 0;
  199. spiflash_begin_transfer();
  200. word command;
  201. switch (reg_idx)
  202. {
  203. case 1:
  204. command = 0x05;
  205. break;
  206. case 2:
  207. command = 0x35;
  208. break;
  209. case 3:
  210. command = 0x15;
  211. break;
  212. }
  213. spiflash_transfer(command);
  214. word status = spiflash_transfer(0);
  215. spiflash_end_transfer();
  216. return status;
  217. }
  218. // Executes sector erase operation
  219. // Erases the 4KiB sector of the given address
  220. // (e.g. addr 4096 erases the second sector)
  221. // This is the smallest unit that can be erased
  222. // Returns 1 on success
  223. word spiflash_sector_erase(word addr)
  224. {
  225. spiflash_enable_write();
  226. word status = spiflash_read_status_reg(1);
  227. // Check if write is enabled
  228. if ((status & 0x2) == 0)
  229. {
  230. uprintln("WE disabled!");
  231. return 0;
  232. }
  233. // Send command
  234. spiflash_begin_transfer();
  235. spiflash_transfer(0x20);
  236. spiflash_transfer(addr >> 16);
  237. spiflash_transfer(addr >> 8);
  238. spiflash_transfer(addr);
  239. spiflash_end_transfer();
  240. // Wait for busy bit to be 0
  241. status = 1;
  242. while((status & 0x1) == 1)
  243. {
  244. status = spiflash_read_status_reg(1);
  245. }
  246. return 1;
  247. }
  248. // Executes chip erase operation
  249. // TAKES AT LEAST 20 SECONDS!
  250. // Returns 1 on success
  251. word spiflash_chip_erase()
  252. {
  253. spiflash_enable_write();
  254. word status = spiflash_read_status_reg(1);
  255. // Check if write is enabled
  256. if ((status & 0x2) == 0)
  257. {
  258. uprintln("WE disabled!");
  259. return 0;
  260. }
  261. // Send erase chip command
  262. spiflash_begin_transfer();
  263. spiflash_transfer(0xC7);
  264. spiflash_end_transfer();
  265. // Wait for busy bit to be 0
  266. status = 1;
  267. while((status & 0x1) == 1)
  268. {
  269. delay(100);
  270. status = spiflash_read_status_reg(1);
  271. }
  272. return 1;
  273. }