Advertisement
Guest User

Untitled

a guest
Jan 24th, 2017
293
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.60 KB | None | 0 0
  1. /*
  2. windbond_serial_debug.cpp
  3. A simple program for the Arduino IDE to help familiarize you with
  4. using WinBond flash memory; can also be used to download the entire
  5. contents of a flash chip to a file via a serial port interface.
  6.  
  7. Important bits of the code: the low-level flash functions (which
  8. implement the timing diagrams in the datasheet), and a simple
  9. serial-port command interface that allows you to talk to your
  10. UNO with any generic terminal application (even the command line).
  11.  
  12. Copyright 2014, Peter J. Torelli
  13.  
  14. This program is free software: you can redistribute it and/or modify
  15. it under the terms of the GNU General Public License as published by
  16. the Free Software Foundation, either version 3 of the License, or
  17. (at your option) any later version.
  18.  
  19. This program is distributed in the hope that it will be useful,
  20. but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. GNU General Public License for more details.
  23.  
  24. You should have received a copy of the GNU General Public License
  25. along with this program. If not, see <http://www.gnu.org/licenses/>
  26.  
  27.  
  28. Revisions:
  29. rev 2 - 21-SEP-2014.
  30. User 'fiaskow' pointed out that driving the WEL instruction after
  31. program and erase w/o waiting for the op to finish may be corrupting
  32. execution. Removed this code (also not needed b/c the WEL is already
  33. cleared after page write or chip erase).
  34. */
  35.  
  36. #include <SPI.h>
  37. // SS: pin 10
  38. // MOSI: pin 11
  39. // MISO: pin 12
  40. // SCK: pin 13
  41.  
  42. // WinBond flash commands
  43. #define WB_WRITE_ENABLE 0x06
  44. #define WB_WRITE_DISABLE 0x04
  45. #define WB_CHIP_ERASE 0xc7
  46. #define WB_READ_STATUS_REG_1 0x05
  47. #define WB_READ_DATA 0x03
  48. #define WB_PAGE_PROGRAM 0x02
  49. #define WB_JEDEC_ID 0x9f
  50.  
  51. /*
  52. * These global variables enable assembly of the user serial
  53. * input command.
  54. */
  55. boolean g_command_ready(false);
  56. String g_command;
  57.  
  58. /*
  59. * print_page_bytes() is a simple helperf function that formats 256
  60. * bytes of data into an easier to read grid.
  61. */
  62. void print_page_bytes(byte *page_buffer) {
  63. char buf[10];
  64. for (int i = 0; i < 16; ++i) {
  65. for (int j = 0; j < 16; ++j) {
  66. sprintf(buf, "%02x", page_buffer[i * 16 + j]);
  67. Serial.print(buf);
  68. }
  69. Serial.println();
  70. }
  71. }
  72.  
  73. /*
  74. ================================================================================
  75. User Interface Routines
  76. The functions below map to user commands. They wrap the low-level calls with
  77. print/debug statements for readability.
  78. ================================================================================
  79. */
  80.  
  81. /*
  82. * The JEDEC ID is fairly generic, I use this function to verify the setup
  83. * is working properly.
  84. */
  85. void get_jedec_id(void) {
  86. Serial.println("command: get_jedec_id");
  87. byte b1, b2, b3;
  88. _get_jedec_id(&b1, &b2, &b3);
  89. char buf[128];
  90. sprintf(buf, "Manufacturer ID: %02xhnMemory Type: %02xhnCapacity: %02xh",
  91. b1, b2, b3);
  92. Serial.println(buf);
  93. Serial.println("Ready");
  94. }
  95.  
  96. void chip_erase(void) {
  97. Serial.println("command: chip_erase");
  98. _chip_erase();
  99. Serial.println("Ready");
  100. }
  101.  
  102. void read_page(unsigned int page_number) {
  103. char buf[80];
  104. sprintf(buf, "command: read_page(%04xh)", page_number);
  105. Serial.println(buf);
  106. byte page_buffer[256];
  107. _read_page(page_number, page_buffer);
  108. print_page_bytes(page_buffer);
  109. Serial.println("Ready");
  110. }
  111.  
  112. void delayed_read_all_pages(void) {
  113. delay(5000);
  114. read_all_pages();
  115. }
  116.  
  117. void read_all_pages(void) {
  118. Serial.println("command: read_all_pages");
  119. byte page_buffer[256];
  120. for (int i = 0; i < 4096; ++i) {
  121. _read_page(i, page_buffer);
  122. print_page_bytes(page_buffer);
  123. }
  124. Serial.println("Ready");
  125. }
  126.  
  127. void write_byte(word page, byte offset, byte databyte) {
  128. char buf[80];
  129. sprintf(buf, "command: write_byte(%04xh, %04xh, %02xh)", page, offset, databyte);
  130. Serial.println(buf);
  131. byte page_data[256];
  132. _read_page(page, page_data);
  133. page_data[offset] = databyte;
  134. _write_page(page, page_data);
  135. Serial.println("Ready");
  136. }
  137.  
  138. /*
  139. ================================================================================
  140. Low-Level Device Routines
  141. The functions below perform the lowest-level interactions with the flash device.
  142. They match the timing diagrams of the datahsheet. They are called by wrapper
  143. functions which provide a little more feedback to the user. I made them stand-
  144. alone functions so they can be re-used. Each function corresponds to a flash
  145. instruction opcode.
  146. ================================================================================
  147. */
  148.  
  149. /*
  150. * See the timing diagram in section 9.2.35 of the
  151. * data sheet, "Read JEDEC ID (9Fh)".
  152. */
  153. void _get_jedec_id(byte *b1, byte *b2, byte *b3) {
  154. digitalWrite(SS, HIGH);
  155. digitalWrite(SS, LOW);
  156. SPI.transfer(WB_JEDEC_ID);
  157. *b1 = SPI.transfer(0); // manufacturer id
  158. *b2 = SPI.transfer(0); // memory type
  159. *b3 = SPI.transfer(0); // capacity
  160. digitalWrite(SS, HIGH);
  161. not_busy();
  162. }
  163.  
  164. /*
  165. * See the timing diagram in section 9.2.26 of the
  166. * data sheet, "Chip Erase (C7h / 06h)". (Note:
  167. * either opcode works.)
  168. */
  169. void _chip_erase(void) {
  170. digitalWrite(SS, HIGH);
  171. digitalWrite(SS, LOW);
  172. SPI.transfer(WB_WRITE_ENABLE);
  173. digitalWrite(SS, HIGH);
  174. digitalWrite(SS, LOW);
  175. SPI.transfer(WB_CHIP_ERASE);
  176. digitalWrite(SS, HIGH);
  177. /* See notes on rev 2
  178. digitalWrite(SS, LOW);
  179. SPI.transfer(WB_WRITE_DISABLE);
  180. digitalWrite(SS, HIGH);
  181. */
  182. not_busy();
  183. }
  184. void _write_test(void) {
  185. String sampleText = "Hello World";
  186. byte data[sampleText.length()];
  187. sampleText.getBytes(data, sizeof(data));
  188. _write_page(0,data);
  189. }
  190. /*
  191. * See the timing diagram in section 9.2.10 of the
  192. * data sheet, "Read Data (03h)".
  193. */
  194. void _read_page(word page_number, byte *page_buffer) {
  195. digitalWrite(SS, HIGH);
  196. digitalWrite(SS, LOW);
  197. SPI.transfer(WB_READ_DATA);
  198. // Construct the 24-bit address from the 16-bit page
  199. // number and 0x00, since we will read 256 bytes (one
  200. // page).
  201. SPI.transfer((page_number >> 8) & 0xFF);
  202. SPI.transfer((page_number >> 0) & 0xFF);
  203. SPI.transfer(0);
  204. for (int i = 0; i < 256; ++i) {
  205. page_buffer[i] = SPI.transfer(0);
  206. }
  207. digitalWrite(SS, HIGH);
  208. not_busy();
  209. }
  210.  
  211. /*
  212. * See the timing diagram in section 9.2.21 of the
  213. * data sheet, "Page Program (02h)".
  214. */
  215. void _write_page(word page_number, byte *page_buffer) {
  216. digitalWrite(SS, HIGH);
  217. digitalWrite(SS, LOW);
  218. SPI.transfer(WB_WRITE_ENABLE);
  219. digitalWrite(SS, HIGH);
  220. digitalWrite(SS, LOW);
  221. SPI.transfer(WB_PAGE_PROGRAM);
  222. SPI.transfer((page_number >> 8) & 0xFF);
  223. SPI.transfer((page_number >> 0) & 0xFF);
  224. SPI.transfer(0);
  225. for (int i = 0; i < 256; ++i) {
  226. SPI.transfer(page_buffer[i]);
  227. }
  228. digitalWrite(SS, HIGH);
  229. /* See notes on rev 2
  230. digitalWrite(SS, LOW);
  231. SPI.transfer(WB_WRITE_DISABLE);
  232. digitalWrite(SS, HIGH);
  233. */
  234. not_busy();
  235. }
  236.  
  237. /*
  238. * not_busy() polls the status bit of the device until it
  239. * completes the current operation. Most operations finish
  240. * in a few hundred microseconds or less, but chip erase
  241. * may take 500+ms. Finish all operations with this poll.
  242. *
  243. * See section 9.2.8 of the datasheet
  244. */
  245. void not_busy(void) {
  246. digitalWrite(SS, HIGH);
  247. digitalWrite(SS, LOW);
  248. SPI.transfer(WB_READ_STATUS_REG_1);
  249. while (SPI.transfer(0) & 1) {};
  250. digitalWrite(SS, HIGH);
  251. }
  252.  
  253. /*
  254. * This handy built-in callback function alerts the UNO
  255. * whenever a serial event occurs. In our case, we check
  256. * for available input data and concatenate a command
  257. * string, setting a boolean used by the loop() routine
  258. * as a dispatch trigger.
  259. */
  260. void serialEvent() {
  261. char c;
  262. while (Serial.available()) {
  263. c = (char)Serial.read();
  264. if (c == ';') {
  265. g_command_ready = true;
  266. }
  267. else {
  268. g_command += c;
  269. }
  270. }
  271. }
  272.  
  273. void setup(void) {
  274. SPI.begin();
  275. SPI.setDataMode(0);
  276. SPI.setBitOrder(MSBFIRST);
  277. Serial.begin(9600);
  278. Serial.println("");
  279. Serial.println("Ready");
  280. }
  281.  
  282. /*
  283. * loop() dispatches the commands compiled by the serialEvent
  284. * parser callback. Some commands take multiple arguments, so
  285. * I have to split up the strings with some messy manipulation.
  286. */
  287. void loop(void) {
  288. if (g_command_ready) {
  289. if (g_command == "get_jedec_id") {
  290. get_jedec_id();
  291. }
  292. else if (g_command == "test_write") {
  293. Serial.println("Custom command: test_write");
  294. _write_test();
  295. }
  296. else if (g_command == "chip_erase") {
  297. chip_erase();
  298. }
  299. else if (g_command == "read_all_pages") {
  300. read_all_pages();
  301. }
  302. else if (g_command == "delayed_read_all_pages") {
  303. Serial.println("Custom command: delayed_read_all_pages");
  304. delayed_read_all_pages();
  305. }
  306. // A one-parameter command...
  307. else if (g_command.startsWith("read_page")) {
  308. int pos = g_command.indexOf(" ");
  309. if (pos == -1) {
  310. Serial.println("Error: Command 'read_page' expects an int operand");
  311. } else {
  312. word page = (word)g_command.substring(pos).toInt();
  313. read_page(page);
  314. }
  315. }
  316. // A three-parameter command..
  317. else if (g_command.startsWith("write_byte")) {
  318. word pageno;
  319. byte offset;
  320. byte data;
  321.  
  322. String args[3];
  323. for (int i = 0; i < 3; ++i) {
  324. int pos = g_command.indexOf(" ");
  325. if (pos == -1) {
  326. Serial.println("Syntax error in write_byte");
  327. goto done;
  328. }
  329. args[i] = g_command.substring(pos + 1);
  330. g_command = args[i];
  331. }
  332. pageno = (word)args[0].toInt();
  333. offset = (byte)args[1].toInt();
  334. data = (byte)args[2].toInt();
  335. write_byte(pageno, offset, data);
  336. }
  337. else {
  338. Serial.print("Invalid command sent: ");
  339. Serial.println(g_command);
  340. g_command = "";
  341. }
  342. done:
  343. g_command = "";
  344. g_command_ready = false;
  345. }
  346. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement