eddiewwm 发表于 2019-9-12 16:30:20

LGT8F328P 跟 M25P16 SPI Flash Memory

根據 https://www.instructables.com/id/How-to-Design-with-Discrete-SPI-Flash-Memory/



/*
    windbond_serial_debug.cpp
    A simple program for the Arduino IDE to help familiarize you with
    using WinBond flash memory; can also be used to download the entire
    contents of a flash chip to a file via a serial port interface.
   
    Important bits of the code: the low-level flash functions (which
    implement the timing diagrams in the datasheet), and a simple
    serial-port command interface that allows you to talk to your
    UNO with any generic terminal application (even the command line).
   
    Copyright 2014, Peter J. Torelli

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

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

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

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


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

#include <SPI.h>
// SS:   pin 10
// MOSI: pin 11
// MISO: pin 12
// SCK:pin 13

// WinBond flash commands
#define WB_WRITE_ENABLE       0x06
#define WB_WRITE_DISABLE      0x04
#define WB_CHIP_ERASE         0xc7
#define WB_READ_STATUS_REG_10x05
#define WB_READ_DATA          0x03
#define WB_PAGE_PROGRAM       0x02
#define WB_JEDEC_ID         0x9f

/*
* These global variables enable assembly of the user serial
* input command.
*/
boolean g_command_ready(false);
String g_command;

/*
* print_page_bytes() is a simple helperf function that formats 256
* bytes of data into an easier to read grid.
*/
void print_page_bytes(byte *page_buffer) {
char buf;
for (int i = 0; i < 16; ++i) {
    for (int j = 0; j < 16; ++j) {
      sprintf(buf, "%02x", page_buffer);
      Serial.print(buf);
    }
    Serial.println();
}
}

/*
================================================================================
User Interface Routines
The functions below map to user commands. They wrap the low-level calls with
print/debug statements for readability.
================================================================================
*/

/*
* The JEDEC ID is fairly generic, I use this function to verify the setup
* is working properly.
*/
void get_jedec_id(void) {
Serial.println("command: get_jedec_id");
byte b1, b2, b3;
_get_jedec_id(&b1, &b2, &b3);
char buf;
sprintf(buf, "Manufacturer ID: %02xh\nMemory Type: %02xh\nCapacity: %02xh",
    b1, b2, b3);
Serial.println(buf);
Serial.println("Ready");
}

void chip_erase(void) {
Serial.println("command: chip_erase");
_chip_erase();
Serial.println("Ready");
}

void read_page(unsigned int page_number) {
char buf;
sprintf(buf, "command: read_page(%04xh)", page_number);
Serial.println(buf);
byte page_buffer;
_read_page(page_number, page_buffer);
print_page_bytes(page_buffer);
Serial.println("Ready");
}

void read_all_pages(void) {
Serial.println("command: read_all_pages");
byte page_buffer;
for (int i = 0; i < 4096; ++i) {
    _read_page(i, page_buffer);
    print_page_bytes(page_buffer);
}
Serial.println("Ready");
}

void write_byte(word page, byte offset, byte databyte) {
char buf;
sprintf(buf, "command: write_byte(%04xh, %04xh, %02xh)", page, offset, databyte);
Serial.println(buf);
byte page_data;
_read_page(page, page_data);
page_data = databyte;
_write_page(page, page_data);
Serial.println("Ready");
}

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

/*
* See the timing diagram in section 9.2.35 of the
* data sheet, "Read JEDEC ID (9Fh)".
*/
void _get_jedec_id(byte *b1, byte *b2, byte *b3) {
digitalWrite(SS, HIGH);
digitalWrite(SS, LOW);
SPI.transfer(WB_JEDEC_ID);
*b1 = SPI.transfer(0); // manufacturer id
*b2 = SPI.transfer(0); // memory type
*b3 = SPI.transfer(0); // capacity
digitalWrite(SS, HIGH);
not_busy();
}

/*
* See the timing diagram in section 9.2.26 of the
* data sheet, "Chip Erase (C7h / 06h)". (Note:
* either opcode works.)
*/
void _chip_erase(void) {
digitalWrite(SS, HIGH);
digitalWrite(SS, LOW);
SPI.transfer(WB_WRITE_ENABLE);
digitalWrite(SS, HIGH);
digitalWrite(SS, LOW);
SPI.transfer(WB_CHIP_ERASE);
digitalWrite(SS, HIGH);
/* See notes on rev 2
digitalWrite(SS, LOW);
SPI.transfer(WB_WRITE_DISABLE);
digitalWrite(SS, HIGH);
*/
not_busy();
}

/*
* See the timing diagram in section 9.2.10 of the
* data sheet, "Read Data (03h)".
*/
void _read_page(word page_number, byte *page_buffer) {
digitalWrite(SS, HIGH);
digitalWrite(SS, LOW);
SPI.transfer(WB_READ_DATA);
// Construct the 24-bit address from the 16-bit page
// number and 0x00, since we will read 256 bytes (one
// page).
SPI.transfer((page_number >> 8) & 0xFF);
SPI.transfer((page_number >> 0) & 0xFF);
SPI.transfer(0);
for (int i = 0; i < 256; ++i) {
    page_buffer = SPI.transfer(0);
}
digitalWrite(SS, HIGH);
not_busy();
}

/*
* See the timing diagram in section 9.2.21 of the
* data sheet, "Page Program (02h)".
*/
void _write_page(word page_number, byte *page_buffer) {
digitalWrite(SS, HIGH);
digitalWrite(SS, LOW);
SPI.transfer(WB_WRITE_ENABLE);
digitalWrite(SS, HIGH);
digitalWrite(SS, LOW);
SPI.transfer(WB_PAGE_PROGRAM);
SPI.transfer((page_number >>8) & 0xFF);
SPI.transfer((page_number >>0) & 0xFF);
SPI.transfer(0);
for (int i = 0; i < 256; ++i) {
    SPI.transfer(page_buffer);
}
digitalWrite(SS, HIGH);
/* See notes on rev 2
digitalWrite(SS, LOW);
SPI.transfer(WB_WRITE_DISABLE);
digitalWrite(SS, HIGH);
*/
not_busy();
}

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

/*
* This handy built-in callback function alerts the UNO
* whenever a serial event occurs. In our case, we check
* for available input data and concatenate a command
* string, setting a boolean used by the loop() routine
* as a dispatch trigger.
*/
void serialEvent() {
char c;
while (Serial.available()) {
    c = (char)Serial.read();
    if (c == ';') {
      g_command_ready = true;
    }
    else {
      g_command += c;
    }   
}
}

void setup(void) {
SPI.begin();
SPI.setDataMode(0);
SPI.setBitOrder(MSBFIRST);
Serial.begin(9600);
Serial.println("");
Serial.println("Ready");
}

/*
* loop() dispatches the commands compiled by the serialEvent
* parser callback. Some commands take multiple arguments, so
* I have to split up the strings with some messy manipulation.
*/
void loop(void) {
if (g_command_ready) {
    if (g_command == "get_jedec_id") {
      get_jedec_id();
    }
    else if (g_command == "chip_erase") {
      chip_erase();
    }
    else if (g_command == "read_all_pages") {
      read_all_pages();
    }
    // A one-parameter command...
    else if (g_command.startsWith("read_page")) {
      int pos = g_command.indexOf(" ");
      if (pos == -1) {
      Serial.println("Error: Command 'read_page' expects an int operand");
      } else {
      word page = (word)g_command.substring(pos).toInt();
      read_page(page);
      }
    }
    // A three-parameter command..
    else if (g_command.startsWith("write_byte")) {
      word pageno;
      byte offset;
      byte data;
      
      String args;
      for (int i = 0; i < 3; ++i) {
      int pos = g_command.indexOf(" ");
      if (pos == -1) {
          Serial.println("Syntax error in write_byte");
          goto done;
      }
      args = g_command.substring(pos + 1);
      g_command = args;
      }
      pageno = (word)args.toInt();
      offset = (byte)args.toInt();
      data = (byte)args.toInt();
      write_byte(pageno, offset, data);
    }
    else {
      Serial.print("Invalid command sent: ");
      Serial.println(g_command);
    }
done:
    g_command = "";
    g_command_ready = false;
}
}





页: [1]
查看完整版本: LGT8F328P 跟 M25P16 SPI Flash Memory