1
0

flashProgrammer.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. // Flash programmer
  2. // Tool to flash the SPI flash chip
  3. #define word char
  4. #include "data/ASCII_BW.c"
  5. #include "lib/math.c"
  6. #include "lib/stdlib.c"
  7. #include "lib/gfx.c"
  8. #define COMMAND_IDLE 0
  9. #define COMMAND_FLASH_READ 114 // 'r'
  10. #define COMMAND_FLASH_ERASE_BLOCK 101 // 'e'
  11. #define COMMAND_FLASH_WRITE 119 // 'w'
  12. #define COMMAND_FILL_BUFFER 98 // 'b'
  13. #define COMMAND_DONE 100 // 'd'
  14. #define BLOCK_SIZE 32768
  15. #define SECTOR_SIZE 4096
  16. #define PAGE_SIZE 256
  17. #define COMMAND_SIZE 8
  18. // the current command the program is busy with
  19. // if idle, should listen to UART for new command
  20. word currentCommand;
  21. // UART buffer that stores a single command
  22. word UARTbufferIndex = 0;
  23. word UARTbuffer[COMMAND_SIZE];
  24. // Buffer of a page to write
  25. word pageBufferIndex = 0;
  26. word pageBuffer[PAGE_SIZE];
  27. /* Description of commands:
  28. READ x(24bit) Bytes from address y(24bit):
  29. b0: 'r'
  30. b1: x[23:16]
  31. b2: x[15:8]
  32. b3: x[7:0]
  33. b4: y[23:16]
  34. b5: y[15:8]
  35. b6: y[7:0]
  36. b7: '\n' (indicate end of command)
  37. */
  38. void initVram()
  39. {
  40. GFX_initVram(); // clear all VRAM
  41. GFX_copyPaletteTable((word)DATA_PALETTE_DEFAULT);
  42. GFX_copyPatternTable((word)DATA_ASCII_DEFAULT);
  43. GFX_cursor = 0;
  44. }
  45. // Workaround for defines in ASM
  46. void SpiFlash_asmDefines()
  47. {
  48. asm(
  49. "define SPI0_CS_ADDR = 0xC02729 ; address of SPI0_CS\n"
  50. "define SPI0_ADDR = 0xC02728 ; address of SPI0\n"
  51. );
  52. }
  53. // Sets SPI0_CS low
  54. void SpiBeginTransfer()
  55. {
  56. asm(
  57. "; backup regs\n"
  58. "push r1\n"
  59. "push r2\n"
  60. "load32 SPI0_CS_ADDR r2 ; r2 = SPI0_CS_ADDR\n"
  61. "load 0 r1 ; r1 = 0 (enable)\n"
  62. "write 0 r2 r1 ; write to SPI0_CS\n"
  63. "; restore regs\n"
  64. "pop r2\n"
  65. "pop r1\n"
  66. );
  67. }
  68. // Sets SPI0_CS high
  69. void SpiEndTransfer()
  70. {
  71. asm(
  72. "; backup regs\n"
  73. "push r1\n"
  74. "push r2\n"
  75. "load32 SPI0_CS_ADDR r2 ; r2 = SPI0_CS_ADDR\n"
  76. "load 1 r1 ; r1 = 1 (disable)\n"
  77. "write 0 r2 r1 ; write to SPI0_CS\n"
  78. "; restore regs\n"
  79. "pop r2\n"
  80. "pop r1\n"
  81. );
  82. }
  83. // write dataByte and return read value
  84. // write 0x00 for a read
  85. // Writes byte over SPI0
  86. word SpiTransfer(word dataByte)
  87. {
  88. word retval = 0;
  89. asm(
  90. "load32 SPI0_ADDR r2 ; r2 = SPI0_ADDR\n"
  91. "write 0 r2 r4 ; write r4 over SPI0\n"
  92. "read 0 r2 r2 ; read return value\n"
  93. "write -4 r14 r2 ; write to stack to return\n"
  94. );
  95. return retval;
  96. }
  97. // inits SPI by enabling SPI0 and resetting the chip
  98. void initSPI()
  99. {
  100. // already set CS high before enabling SPI0
  101. SpiEndTransfer();
  102. // enable SPI0
  103. word *p = (word *) 0xC0272A; // set address (SPI0 enable)
  104. *p = 1; // write value
  105. delay(10);
  106. // reset to get out of continuous read mode
  107. SpiBeginTransfer();
  108. SpiTransfer(0x66);
  109. SpiEndTransfer();
  110. delay(1);
  111. SpiBeginTransfer();
  112. SpiTransfer(0x99);
  113. SpiEndTransfer();
  114. delay(1);
  115. SpiBeginTransfer();
  116. SpiTransfer(0x66);
  117. SpiEndTransfer();
  118. delay(1);
  119. SpiBeginTransfer();
  120. SpiTransfer(0x99);
  121. SpiEndTransfer();
  122. delay(1);
  123. }
  124. // Should print 0xEF as Winbond device ID, and 0x17 for W25Q128
  125. void readDeviceID()
  126. {
  127. SpiBeginTransfer();
  128. SpiTransfer(0x90);
  129. SpiTransfer(0);
  130. SpiTransfer(0);
  131. SpiTransfer(0);
  132. word manufacturer = SpiTransfer(0);
  133. word deviceID = SpiTransfer(0);
  134. SpiEndTransfer();
  135. char b[10];
  136. itoah(manufacturer, b);
  137. GFX_PrintConsole("Chip manufacturer: ");
  138. GFX_PrintConsole(b);
  139. GFX_PrintConsole("\n");
  140. GFX_PrintConsole("Chip ID: ");
  141. itoah(deviceID, b);
  142. GFX_PrintConsole(b);
  143. GFX_PrintConsole("\n");
  144. }
  145. void readAndPrint(word len, word addr24, word addr16, word addr8)
  146. {
  147. word l = len;
  148. word a24 = addr24;
  149. word a16 = addr16;
  150. word a8 = addr8;
  151. SpiBeginTransfer();
  152. SpiTransfer(0x03);
  153. SpiTransfer(a24);
  154. SpiTransfer(a16);
  155. SpiTransfer(a8);
  156. word i;
  157. for (i = 0; i < l; i++)
  158. {
  159. word x = SpiTransfer(0x00);
  160. // delay a bit here
  161. word n = 3;
  162. word m = 4;
  163. word f = n*m;
  164. uprintc(x);
  165. }
  166. SpiEndTransfer();
  167. }
  168. /* Returns status register 1 2 or 3, depending on the value of reg (1, 2 or 3)
  169. Status register description:
  170. Register 1: (default: 0x0)
  171. b7: Status Register Protect 0
  172. b6: Sector Protect Bit
  173. b5: Top/Bottom Protect Bit
  174. b4: Block Protect Bit 2
  175. b3: Block Protect Bit 1
  176. b2: Block Protect Bit 0
  177. b1: Write Enable Latch
  178. b0: BUSY: Erase/Write in Progress
  179. Register 2: (default: 0x2)
  180. b7: Suspend Status
  181. b6: Complement Protect
  182. b5: Security Register Lock bit 2
  183. b4: Security Register Lock bit 1
  184. b3: Security Register Lock bit 0
  185. b2: Reserved
  186. b1: Quad Enable
  187. b0: Status Register Protect 1
  188. Register 3: (default: 0x60)
  189. b7: Reserved
  190. b6: Output Driver Strength bit 1
  191. b5: Output Driver Strength bit 0
  192. b4: Reserved
  193. b3: Reserved
  194. b2: Write Protect Selection
  195. b1: Reserved
  196. b0: Reserved
  197. */
  198. word readStatusRegister(word reg)
  199. {
  200. SpiBeginTransfer();
  201. if (reg == 2)
  202. SpiTransfer(0x35);
  203. else if (reg == 3)
  204. SpiTransfer(0x15);
  205. else
  206. SpiTransfer(0x05);
  207. word status = SpiTransfer(0);
  208. SpiEndTransfer();
  209. return status;
  210. }
  211. void enableWrite()
  212. {
  213. SpiBeginTransfer();
  214. SpiTransfer(0x06);
  215. SpiEndTransfer();
  216. }
  217. // Executes chip erase operation
  218. // TAKES AT LEAST 20 SECONDS!
  219. // Returns 1 on success
  220. word chipErase()
  221. {
  222. enableWrite();
  223. word status = readStatusRegister(1);
  224. // Check if write is enabled
  225. if ((status & 0x2) == 0)
  226. return 0;
  227. // Send command
  228. SpiBeginTransfer();
  229. SpiTransfer(0xC7);
  230. SpiEndTransfer();
  231. // Wait for busy bit to be 0
  232. status = 1;
  233. while((status & 0x1) == 1)
  234. {
  235. status = readStatusRegister(1);
  236. }
  237. return 1;
  238. }
  239. // Executes 32KiB block erase operation
  240. // Erases the 32KiB block that contains the given byte address
  241. // Returns 1 on success
  242. word blockErase(word addr24, word addr16, word addr8)
  243. {
  244. word a24 = addr24;
  245. word a16 = addr16;
  246. word a8 = addr8;
  247. enableWrite();
  248. word status = readStatusRegister(1);
  249. // Check if write is enabled
  250. if ((status & 0x2) == 0)
  251. return 0;
  252. // Send command
  253. SpiBeginTransfer();
  254. SpiTransfer(0x52);
  255. SpiTransfer(a24);
  256. SpiTransfer(a16);
  257. SpiTransfer(a8);
  258. SpiEndTransfer();
  259. // Wait for busy bit to be 0
  260. status = 1;
  261. while((status & 0x1) == 1)
  262. {
  263. status = readStatusRegister(1);
  264. }
  265. return 1;
  266. }
  267. // Executes 256 byte page program operation
  268. // The address is the byte address of the first byte to write
  269. // Data wraps around at the end of a page,
  270. // so last address byte will usually be 0
  271. // Returns 1 on success
  272. word pageProgram(word addr24, word addr16, word addr8)
  273. {
  274. word a24 = addr24;
  275. word a16 = addr16;
  276. word a8 = addr8;
  277. enableWrite();
  278. word status = readStatusRegister(1);
  279. // Check if write is enabled
  280. if ((status & 0x2) == 0)
  281. return 0;
  282. // Send command
  283. SpiBeginTransfer();
  284. SpiTransfer(0x2);
  285. SpiTransfer(a24);
  286. SpiTransfer(a16);
  287. SpiTransfer(a8);
  288. // Send page
  289. word *p_pageBuffer = pageBuffer;
  290. word i;
  291. for (i = 0; i < 256; i++)
  292. {
  293. SpiTransfer(*(p_pageBuffer + i));
  294. }
  295. SpiEndTransfer();
  296. // Wait for busy bit to be 0
  297. status = 1;
  298. while((status & 0x1) == 1)
  299. {
  300. status = readStatusRegister(1);
  301. }
  302. return 1;
  303. }
  304. void processCommand()
  305. {
  306. if (currentCommand == COMMAND_IDLE)
  307. {
  308. // do nothing
  309. }
  310. else if (currentCommand == COMMAND_FLASH_READ)
  311. {
  312. word len = UARTbuffer[1] << 16;
  313. len += UARTbuffer[2] << 8;
  314. len += UARTbuffer[3];
  315. word addr24 = UARTbuffer[4];
  316. word addr16 = UARTbuffer[5];
  317. word addr8 = UARTbuffer[6];
  318. GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 8), 0);
  319. GFX_printWindowColored("Reading ", 8, GFX_WindowPosFromXY(0, 8), 0);
  320. char b[10];
  321. itoa(len, b);
  322. GFX_printWindowColored(b, strlen(b), GFX_WindowPosFromXY(8, 8), 0);
  323. GFX_printWindowColored(" bytes", 6, GFX_WindowPosFromXY(8 + strlen(b), 8), 0);
  324. readAndPrint(len, addr24, addr16, addr8);
  325. GFX_printWindowColored(" done!", 5, GFX_WindowPosFromXY(8 + strlen(b) + 6, 8), 0);
  326. currentCommand = COMMAND_IDLE;
  327. uprintc('r');
  328. }
  329. else if (currentCommand == COMMAND_FLASH_ERASE_BLOCK)
  330. {
  331. word addr24 = UARTbuffer[4];
  332. word addr16 = UARTbuffer[5];
  333. word addr8 = UARTbuffer[6];
  334. blockErase(addr24, addr16, addr8);
  335. word addrCombined = (unsigned) ((addr24 << 16) + (addr16 << 8) + addr8) >> 15;
  336. GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 8), 0);
  337. GFX_printWindowColored("Block ", 6, GFX_WindowPosFromXY(0, 8), 0);
  338. char b[10];
  339. itoa(addrCombined, b);
  340. GFX_printWindowColored(b, strlen(b), GFX_WindowPosFromXY(6, 8), 0);
  341. GFX_printWindowColored(" erased", 7, GFX_WindowPosFromXY(6 + strlen(b), 8), 0);
  342. currentCommand = COMMAND_IDLE;
  343. uprintc('r');
  344. }
  345. else if (currentCommand == COMMAND_FLASH_WRITE)
  346. {
  347. word addr24 = UARTbuffer[4];
  348. word addr16 = UARTbuffer[5];
  349. word addr8 = UARTbuffer[6];
  350. pageProgram(addr24, addr16, addr8);
  351. word addrCombined = (addr24 << 8) + addr16;
  352. GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 8), 0);
  353. GFX_printWindowColored("Page ", 5, GFX_WindowPosFromXY(0, 8), 0);
  354. char b[10];
  355. itoa(addrCombined, b);
  356. GFX_printWindowColored(b, strlen(b), GFX_WindowPosFromXY(5, 8), 0);
  357. GFX_printWindowColored(" written", 8, GFX_WindowPosFromXY(5 + strlen(b), 8), 0);
  358. currentCommand = COMMAND_IDLE;
  359. uprintc('r');
  360. }
  361. else if (currentCommand == COMMAND_FILL_BUFFER)
  362. {
  363. // done when full page is received
  364. if (pageBufferIndex == PAGE_SIZE)
  365. {
  366. pageBufferIndex = 0;
  367. currentCommand = COMMAND_IDLE;
  368. uprintc('r');
  369. }
  370. }
  371. else if (currentCommand == COMMAND_DONE)
  372. {
  373. // notify done
  374. GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 6), 0);
  375. GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 8), 0);
  376. GFX_printWindowColored("Done!", 5, GFX_WindowPosFromXY(0, 6), 0);
  377. // allow new commands, just in case
  378. currentCommand = COMMAND_IDLE;
  379. }
  380. }
  381. int main()
  382. {
  383. initVram();
  384. GFX_PrintConsole("Flash Programmer\n\n");
  385. currentCommand = COMMAND_IDLE;
  386. initSPI();
  387. GFX_PrintConsole("SPI0 mode set\n");
  388. readDeviceID();
  389. GFX_PrintConsole("\nReady to receive commands\n\n");
  390. // Notify that we are ready to recieve commands
  391. uprintc('r');
  392. while (1)
  393. {
  394. processCommand();
  395. }
  396. return 48;
  397. }
  398. void int1()
  399. {
  400. /*
  401. word *p = (word *) 0x4C0000; // set address (timer1 state)
  402. *p = 1; // write value
  403. */
  404. timer1Value = 1; // notify ending of timer1
  405. }
  406. void int2()
  407. {
  408. }
  409. void int3()
  410. {
  411. // UART RX interrupt
  412. // Fill buffer
  413. if (currentCommand == COMMAND_FILL_BUFFER)
  414. {
  415. // read byte
  416. word *p = (word *)0xC02722; // address of UART RX
  417. word b = *p; // read byte from UART
  418. // write byte to buffer, increase index
  419. word *p_pageBuffer = pageBuffer;
  420. *(p_pageBuffer + pageBufferIndex) = b;
  421. pageBufferIndex++;
  422. //uprintc('a'); // notify write to buffer is done
  423. }
  424. // Get command
  425. else if (currentCommand == COMMAND_IDLE)
  426. {
  427. // read byte
  428. word *p = (word *)0xC02722; // address of UART RX
  429. word b = *p; // read byte from UART
  430. // write byte to buffer, increase index
  431. word *p_UARTbuffer = UARTbuffer;
  432. *(p_UARTbuffer + UARTbufferIndex) = b;
  433. UARTbufferIndex++;
  434. // execute command when 8 bytes received
  435. if (UARTbufferIndex == COMMAND_SIZE)
  436. {
  437. currentCommand = *(p_UARTbuffer);
  438. UARTbufferIndex = 0;
  439. // notify ready to receive when filling buffer
  440. if (currentCommand == COMMAND_FILL_BUFFER)
  441. {
  442. uprintc('b');
  443. }
  444. }
  445. }
  446. }
  447. void int4()
  448. {
  449. }
  450. void interrupt()
  451. {
  452. word i = getIntID();
  453. if (i == 1)
  454. {
  455. int1();
  456. }
  457. else if (i == 3)
  458. {
  459. int3();
  460. }
  461. }