极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 639|回复: 0

LGT8F328P 跟 M25P16 SPI Flash Memory

[复制链接]
发表于 2019-9-12 16:30:20 | 显示全部楼层 |阅读模式
根據 https://www.instructables.com/id ... e-SPI-Flash-Memory/
M25P16 Pins.JPG
Erase Timing.JPG

  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.     This program is free software: you can redistribute it and/or modify
  14.     it under the terms of the GNU General Public License as published by
  15.     the Free Software Foundation, either version 3 of the License, or
  16.     (at your option) any later version.

  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of

  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.

  21.     You should have received a copy of the GNU General Public License
  22.     along with this program.  If not, see <http://www.gnu.org/licenses/>   


  23. Revisions:
  24.     rev 2 - 21-SEP-2014.
  25.     User 'fiaskow' pointed out that driving the WEL instruction after
  26.     program and erase w/o waiting for the op to finish may be corrupting
  27.     execution. Removed this code (also not needed b/c the WEL is already
  28.     cleared after page write or chip erase).
  29. */

  30. #include <SPI.h>
  31. // SS:   pin 10
  32. // MOSI: pin 11
  33. // MISO: pin 12
  34. // SCK:  pin 13

  35. // WinBond flash commands
  36. #define WB_WRITE_ENABLE       0x06
  37. #define WB_WRITE_DISABLE      0x04
  38. #define WB_CHIP_ERASE         0xc7
  39. #define WB_READ_STATUS_REG_1  0x05
  40. #define WB_READ_DATA          0x03
  41. #define WB_PAGE_PROGRAM       0x02
  42. #define WB_JEDEC_ID           0x9f

  43. /*
  44. * These global variables enable assembly of the user serial
  45. * input command.
  46. */
  47. boolean g_command_ready(false);
  48. String g_command;

  49. /*
  50. * print_page_bytes() is a simple helperf function that formats 256
  51. * bytes of data into an easier to read grid.
  52. */
  53. void print_page_bytes(byte *page_buffer) {
  54.   char buf[10];
  55.   for (int i = 0; i < 16; ++i) {
  56.     for (int j = 0; j < 16; ++j) {
  57.       sprintf(buf, "%02x", page_buffer[i * 16 + j]);
  58.       Serial.print(buf);
  59.     }
  60.     Serial.println();
  61.   }
  62. }

  63. /*
  64. ================================================================================
  65. User Interface Routines
  66. The functions below map to user commands. They wrap the low-level calls with
  67. print/debug statements for readability.
  68. ================================================================================
  69. */

  70. /*
  71. * The JEDEC ID is fairly generic, I use this function to verify the setup
  72. * is working properly.
  73. */
  74. void get_jedec_id(void) {
  75.   Serial.println("command: get_jedec_id");
  76.   byte b1, b2, b3;
  77.   _get_jedec_id(&b1, &b2, &b3);
  78.   char buf[128];
  79.   sprintf(buf, "Manufacturer ID: %02xh\nMemory Type: %02xh\nCapacity: %02xh",
  80.     b1, b2, b3);
  81.   Serial.println(buf);
  82.   Serial.println("Ready");
  83. }

  84. void chip_erase(void) {
  85.   Serial.println("command: chip_erase");
  86.   _chip_erase();
  87.   Serial.println("Ready");
  88. }

  89. void read_page(unsigned int page_number) {
  90.   char buf[80];
  91.   sprintf(buf, "command: read_page(%04xh)", page_number);
  92.   Serial.println(buf);
  93.   byte page_buffer[256];
  94.   _read_page(page_number, page_buffer);
  95.   print_page_bytes(page_buffer);
  96.   Serial.println("Ready");
  97. }

  98. void read_all_pages(void) {
  99.   Serial.println("command: read_all_pages");
  100.   byte page_buffer[256];
  101.   for (int i = 0; i < 4096; ++i) {
  102.     _read_page(i, page_buffer);
  103.     print_page_bytes(page_buffer);
  104.   }
  105.   Serial.println("Ready");
  106. }

  107. void write_byte(word page, byte offset, byte databyte) {
  108.   char buf[80];
  109.   sprintf(buf, "command: write_byte(%04xh, %04xh, %02xh)", page, offset, databyte);
  110.   Serial.println(buf);
  111.   byte page_data[256];
  112.   _read_page(page, page_data);
  113.   page_data[offset] = databyte;
  114.   _write_page(page, page_data);
  115.   Serial.println("Ready");
  116. }

  117. /*
  118. ================================================================================
  119. Low-Level Device Routines
  120. The functions below perform the lowest-level interactions with the flash device.
  121. They match the timing diagrams of the datahsheet. They are called by wrapper
  122. functions which provide a little more feedback to the user. I made them stand-
  123. alone functions so they can be re-used. Each function corresponds to a flash
  124. instruction opcode.
  125. ================================================================================
  126. */

  127. /*
  128. * See the timing diagram in section 9.2.35 of the
  129. * data sheet, "Read JEDEC ID (9Fh)".
  130. */
  131. void _get_jedec_id(byte *b1, byte *b2, byte *b3) {
  132.   digitalWrite(SS, HIGH);
  133.   digitalWrite(SS, LOW);
  134.   SPI.transfer(WB_JEDEC_ID);
  135.   *b1 = SPI.transfer(0); // manufacturer id
  136.   *b2 = SPI.transfer(0); // memory type
  137.   *b3 = SPI.transfer(0); // capacity
  138.   digitalWrite(SS, HIGH);
  139.   not_busy();
  140. }  

  141. /*
  142. * See the timing diagram in section 9.2.26 of the
  143. * data sheet, "Chip Erase (C7h / 06h)". (Note:
  144. * either opcode works.)
  145. */
  146. void _chip_erase(void) {
  147.   digitalWrite(SS, HIGH);
  148.   digitalWrite(SS, LOW);  
  149.   SPI.transfer(WB_WRITE_ENABLE);
  150.   digitalWrite(SS, HIGH);
  151.   digitalWrite(SS, LOW);  
  152.   SPI.transfer(WB_CHIP_ERASE);
  153.   digitalWrite(SS, HIGH);
  154.   /* See notes on rev 2
  155.   digitalWrite(SS, LOW);  
  156.   SPI.transfer(WB_WRITE_DISABLE);
  157.   digitalWrite(SS, HIGH);
  158.   */
  159.   not_busy();
  160. }

  161. /*
  162. * See the timing diagram in section 9.2.10 of the
  163. * data sheet, "Read Data (03h)".
  164. */
  165. void _read_page(word page_number, byte *page_buffer) {
  166.   digitalWrite(SS, HIGH);
  167.   digitalWrite(SS, LOW);
  168.   SPI.transfer(WB_READ_DATA);
  169.   // Construct the 24-bit address from the 16-bit page
  170.   // number and 0x00, since we will read 256 bytes (one
  171.   // page).
  172.   SPI.transfer((page_number >> 8) & 0xFF);
  173.   SPI.transfer((page_number >> 0) & 0xFF);
  174.   SPI.transfer(0);
  175.   for (int i = 0; i < 256; ++i) {
  176.     page_buffer[i] = SPI.transfer(0);
  177.   }
  178.   digitalWrite(SS, HIGH);
  179.   not_busy();
  180. }

  181. /*
  182. * See the timing diagram in section 9.2.21 of the
  183. * data sheet, "Page Program (02h)".
  184. */
  185. void _write_page(word page_number, byte *page_buffer) {
  186.   digitalWrite(SS, HIGH);
  187.   digitalWrite(SS, LOW);  
  188.   SPI.transfer(WB_WRITE_ENABLE);
  189.   digitalWrite(SS, HIGH);
  190.   digitalWrite(SS, LOW);  
  191.   SPI.transfer(WB_PAGE_PROGRAM);
  192.   SPI.transfer((page_number >>  8) & 0xFF);
  193.   SPI.transfer((page_number >>  0) & 0xFF);
  194.   SPI.transfer(0);
  195.   for (int i = 0; i < 256; ++i) {
  196.     SPI.transfer(page_buffer[i]);
  197.   }
  198.   digitalWrite(SS, HIGH);
  199.   /* See notes on rev 2
  200.   digitalWrite(SS, LOW);  
  201.   SPI.transfer(WB_WRITE_DISABLE);
  202.   digitalWrite(SS, HIGH);
  203.   */
  204.   not_busy();
  205. }

  206. /*
  207. * not_busy() polls the status bit of the device until it
  208. * completes the current operation. Most operations finish
  209. * in a few hundred microseconds or less, but chip erase
  210. * may take 500+ms. Finish all operations with this poll.
  211. *
  212. * See section 9.2.8 of the datasheet
  213. */
  214. void not_busy(void) {
  215.   digitalWrite(SS, HIGH);  
  216.   digitalWrite(SS, LOW);
  217.   SPI.transfer(WB_READ_STATUS_REG_1);      
  218.   while (SPI.transfer(0) & 1) {};
  219.   digitalWrite(SS, HIGH);  
  220. }

  221. /*
  222. * This handy built-in callback function alerts the UNO
  223. * whenever a serial event occurs. In our case, we check
  224. * for available input data and concatenate a command
  225. * string, setting a boolean used by the loop() routine
  226. * as a dispatch trigger.
  227. */
  228. void serialEvent() {
  229.   char c;
  230.   while (Serial.available()) {
  231.     c = (char)Serial.read();
  232.     if (c == ';') {
  233.       g_command_ready = true;
  234.     }
  235.     else {
  236.       g_command += c;
  237.     }   
  238.   }
  239. }

  240. void setup(void) {
  241.   SPI.begin();
  242.   SPI.setDataMode(0);
  243.   SPI.setBitOrder(MSBFIRST);
  244.   Serial.begin(9600);
  245.   Serial.println("");
  246.   Serial.println("Ready");
  247. }

  248. /*
  249. * loop() dispatches the commands compiled by the serialEvent
  250. * parser callback. Some commands take multiple arguments, so
  251. * I have to split up the strings with some messy manipulation.
  252. */
  253. void loop(void) {
  254.   if (g_command_ready) {
  255.     if (g_command == "get_jedec_id") {
  256.       get_jedec_id();
  257.     }
  258.     else if (g_command == "chip_erase") {
  259.       chip_erase();
  260.     }
  261.     else if (g_command == "read_all_pages") {
  262.       read_all_pages();
  263.     }
  264.     // A one-parameter command...
  265.     else if (g_command.startsWith("read_page")) {
  266.       int pos = g_command.indexOf(" ");
  267.       if (pos == -1) {
  268.         Serial.println("Error: Command 'read_page' expects an int operand");
  269.       } else {
  270.         word page = (word)g_command.substring(pos).toInt();
  271.         read_page(page);
  272.       }
  273.     }
  274.     // A three-parameter command..
  275.     else if (g_command.startsWith("write_byte")) {
  276.       word pageno;
  277.       byte offset;
  278.       byte data;
  279.       
  280.       String args[3];
  281.       for (int i = 0; i < 3; ++i) {
  282.         int pos = g_command.indexOf(" ");
  283.         if (pos == -1) {
  284.           Serial.println("Syntax error in write_byte");
  285.           goto done;
  286.         }
  287.         args[i] = g_command.substring(pos + 1);
  288.         g_command = args[i];
  289.       }
  290.       pageno = (word)args[0].toInt();
  291.       offset = (byte)args[1].toInt();
  292.       data = (byte)args[2].toInt();
  293.       write_byte(pageno, offset, data);
  294.     }
  295.     else {
  296.       Serial.print("Invalid command sent: ");
  297.       Serial.println(g_command);
  298.     }
  299. done:
  300.     g_command = "";
  301.     g_command_ready = false;
  302.   }
  303. }
复制代码


Test operation.JPG


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2019-11-18 12:58 , Processed in 0.048009 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表