diff --git a/Marlin/src/gcode/control/M993_M994.cpp b/Marlin/src/gcode/control/M993_M994.cpp
new file mode 100644
index 000000000..4e13aa9d7
--- /dev/null
+++ b/Marlin/src/gcode/control/M993_M994.cpp
@@ -0,0 +1,92 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 .
+ *
+ */
+
+#include "../../inc/MarlinConfig.h"
+
+#if ALL(HAS_SPI_FLASH, SDSUPPORT, MARLIN_DEV_MODE)
+
+#include "../gcode.h"
+#include "../../sd/cardreader.h"
+#include "../../libs/W25Qxx.h"
+
+/**
+ * M993: Backup SPI Flash to SD
+ */
+void GcodeSuite::M993() {
+ if (!card.isMounted()) card.mount();
+
+ char fname[] = "spiflash.bin";
+ card.openFileWrite(fname);
+ if (!card.isFileOpen()) {
+ SERIAL_ECHOLNPAIR("Failed to open ", fname, " to write.");
+ return;
+ }
+
+ W25QXXFlash W25QXX;
+
+ uint8_t buf[1024];
+ uint32_t addr = 0;
+ W25QXX.init(SPI_QUARTER_SPEED);
+ SERIAL_ECHOPGM("Save SPI Flash");
+ while (addr < SPI_FLASH_SIZE) {
+ W25QXX.SPI_FLASH_BufferRead(buf, addr, COUNT(buf));
+ addr += COUNT(buf);
+ card.write(buf, COUNT(buf));
+ if (addr % (COUNT(buf) * 10) == 0) SERIAL_CHAR('.');
+ }
+ SERIAL_ECHOLNPGM(" done");
+
+ card.closefile();
+}
+
+/**
+ * M994: Load a backup from SD to SPI Flash
+ */
+void GcodeSuite::M994() {
+ if (!card.isMounted()) card.mount();
+
+ char fname[] = "spiflash.bin";
+ card.openFileRead(fname);
+ if (!card.isFileOpen()) {
+ SERIAL_ECHOLNPAIR("Failed to open ", fname, " to read.");
+ return;
+ }
+
+ W25QXXFlash W25QXX;
+
+ uint8_t buf[1024];
+ uint32_t addr = 0;
+ W25QXX.init(SPI_QUARTER_SPEED);
+ W25QXX.SPI_FLASH_BulkErase();
+ SERIAL_ECHOPGM("Load SPI Flash");
+ while(addr < SPI_FLASH_SIZE) {
+ card.read(buf, COUNT(buf));
+ W25QXX.SPI_FLASH_BufferWrite(buf, addr, COUNT(buf));
+ addr += COUNT(buf);
+ if (addr % (COUNT(buf) * 10) == 0) SERIAL_CHAR('.');
+ }
+ SERIAL_ECHOLNPGM(" done");
+
+ card.closefile();
+}
+
+#endif // HAS_SPI_FLASH && SDSUPPORT && MARLIN_DEV_MODE
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index f1692ee80..2309953f8 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -871,6 +871,11 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 422: M422(); break; // M422: Set Z Stepper automatic alignment position using probe
#endif
+ #if BOTH(HAS_SPI_FLASH, SDSUPPORT)
+ case 993: M993(); break; // M993: Backup SPI Flash to SD
+ case 994: M994(); break; // M994: Load a Backup from SD to SPI Flash
+ #endif
+
#if ENABLED(TOUCH_SCREEN_CALIBRATION)
case 995: M995(); break; // M995: Touch screen calibration for TFT display
#endif
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index 7e89e809d..783781b9c 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -276,6 +276,8 @@
* ************ Custom codes - This can change to suit future G-code regulations
* G425 - Calibrate using a conductive object. (Requires CALIBRATION_GCODE)
* M928 - Start SD logging: "M928 filename.gco". Stop with M29. (Requires SDSUPPORT)
+ * M993 - Backup SPI Flash to SD
+ * M994 - Load a Backup from SD to SPI Flash
* M995 - Touch screen calibration for TFT display
* M997 - Perform in-application firmware update
* M999 - Restart after being stopped by error
@@ -846,6 +848,11 @@ private:
TERN_(TOUCH_SCREEN_CALIBRATION, static void M995());
+ #if BOTH(HAS_SPI_FLASH, SDSUPPORT)
+ static void M993();
+ static void M994();
+ #endif
+
TERN_(PLATFORM_M997_SUPPORT, static void M997());
static void M999();
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp
index 9d3adc1ba..979c916e5 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp
@@ -27,6 +27,8 @@
#include "../../../../inc/MarlinConfig.h"
#include "SPIFlashStorage.h"
+extern W25QXXFlash W25QXX;
+
uint8_t SPIFlashStorage::m_pageData[SPI_FLASH_PageSize];
uint32_t SPIFlashStorage::m_currentPage;
uint16_t SPIFlashStorage::m_pageDataUsed;
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h
index 5a1241370..98c8067bd 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h
+++ b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h
@@ -21,7 +21,7 @@
*/
#pragma once
-#include "W25Qxx.h"
+#include "../../../../libs/W25Qxx.h"
#define HAS_SPI_FLASH_COMPRESSION 1
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
index e8899b9ad..5d87eb9f8 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
@@ -27,7 +27,6 @@
#include "SPI_TFT.h"
#endif
-#include "W25Qxx.h"
#include "tft_lvgl_configuration.h"
#include "pic_manager.h"
@@ -50,6 +49,7 @@
#include "../../../../feature/pause.h"
#endif
+W25QXXFlash W25QXX;
CFG_ITMES gCfgItems;
UI_CFG uiCfg;
DISP_STATE_STACK disp_state_stack;
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp
index 00371d7ab..a35ae2970 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp
@@ -29,7 +29,6 @@
#include "tft_lvgl_configuration.h"
#include "draw_ready_print.h"
-#include "W25Qxx.h"
#include "mks_hardware_test.h"
#include "draw_ui.h"
#include "pic_manager.h"
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp
index 072213e49..447303a88 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp
@@ -29,10 +29,10 @@
#include "mks_hardware_test.h"
#include "SPIFlashStorage.h"
-#include "W25Qxx.h"
+#include "../../../../libs/W25Qxx.h"
-#include "../../../../MarlinCore.h"
#include "../../../../sd/cardreader.h"
+#include "../../../../MarlinCore.h"
extern uint16_t DeviceCode;
extern unsigned char bmp_public_buf[17 * 1024];
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h
index 354e11a54..4d9d08a9b 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h
+++ b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h
@@ -23,6 +23,8 @@
#include "../../../../inc/MarlinConfig.h"
+#include "../../../../libs/W25Qxx.h"
+
#include
#include
@@ -154,6 +156,8 @@ extern void spi_flash_read_test();
extern void default_view_Read(uint8_t *default_view_Rbuff, uint32_t default_view_Readsize);
extern void flash_view_Read(uint8_t *flash_view_Rbuff, uint32_t flash_view_Readsize);
+extern W25QXXFlash W25QXX;
+
#ifdef __cplusplus
} /* C-declarations for C++ */
#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp
index fc5b8c1bf..81b50a101 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp
@@ -35,7 +35,6 @@
#include "tft_lvgl_configuration.h"
#include "draw_ready_print.h"
-#include "W25Qxx.h"
#include "pic_manager.h"
#include "mks_hardware_test.h"
#include "draw_ui.h"
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/W25Qxx.cpp b/Marlin/src/libs/W25Qxx.cpp
similarity index 90%
rename from Marlin/src/lcd/extui/lib/mks_ui/W25Qxx.cpp
rename to Marlin/src/libs/W25Qxx.cpp
index 60b4d0b7e..d51dfb819 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/W25Qxx.cpp
+++ b/Marlin/src/libs/W25Qxx.cpp
@@ -19,13 +19,12 @@
* along with this program. If not, see .
*
*/
-#include "../../../../inc/MarlinConfigPre.h"
-#if 1 // ENABLED(SPI_FLASH)
-#if HAS_TFT_LVGL_UI
+#include "../inc/MarlinConfig.h"
+
+#if HAS_SPI_FLASH
#include
-#include "../../../../inc/MarlinConfig.h"
#include "W25Qxx.h"
@@ -45,9 +44,7 @@
#define W25QXX_CS_H OUT_WRITE(SPI_FLASH_CS_PIN, HIGH)
#define W25QXX_CS_L OUT_WRITE(SPI_FLASH_CS_PIN, LOW)
-ext_FLASH W25QXX;
-
-void ext_FLASH::init(uint8_t spiRate) {
+void W25QXXFlash::init(uint8_t spiRate) {
OUT_WRITE(SPI_FLASH_CS_PIN, HIGH);
@@ -85,12 +82,12 @@ void ext_FLASH::init(uint8_t spiRate) {
*
* @details
*/
-uint8_t ext_FLASH::spi_flash_Rec() {
+uint8_t W25QXXFlash::spi_flash_Rec() {
uint8_t returnByte = SPI.transfer(ff);
return returnByte;
}
-uint8_t ext_FLASH::spi_flash_read_write_byte(uint8_t data) {
+uint8_t W25QXXFlash::spi_flash_read_write_byte(uint8_t data) {
uint8_t returnByte = SPI.transfer(data);
return returnByte;
}
@@ -104,7 +101,7 @@ uint8_t ext_FLASH::spi_flash_read_write_byte(uint8_t data) {
*
* @details Uses DMA
*/
-void ext_FLASH::spi_flash_Read(uint8_t* buf, uint16_t nbyte) { SPI.dmaTransfer(0, const_cast(buf), nbyte); }
+void W25QXXFlash::spi_flash_Read(uint8_t* buf, uint16_t nbyte) { SPI.dmaTransfer(0, const_cast(buf), nbyte); }
/**
* @brief Send a single byte on SPI port
@@ -113,7 +110,7 @@ void ext_FLASH::spi_flash_Read(uint8_t* buf, uint16_t nbyte) { SPI.dmaTransfer(0
*
* @details
*/
-void ext_FLASH::spi_flash_Send(uint8_t b) { SPI.send(b); }
+void W25QXXFlash::spi_flash_Send(uint8_t b) { SPI.send(b); }
/**
* @brief Write token and then write from 512 byte buffer to SPI (for SD card)
@@ -123,12 +120,12 @@ void ext_FLASH::spi_flash_Send(uint8_t b) { SPI.send(b); }
*
* @details Use DMA
*/
-void ext_FLASH::spi_flash_SendBlock(uint8_t token, const uint8_t* buf) {
+void W25QXXFlash::spi_flash_SendBlock(uint8_t token, const uint8_t* buf) {
SPI.send(token);
SPI.dmaSend(const_cast(buf), 512);
}
-uint16_t ext_FLASH::W25QXX_ReadID(void) {
+uint16_t W25QXXFlash::W25QXX_ReadID(void) {
uint16_t Temp = 0;
W25QXX_CS_L;
spi_flash_Send(0x90);
@@ -141,7 +138,7 @@ uint16_t ext_FLASH::W25QXX_ReadID(void) {
return Temp;
}
-void ext_FLASH::SPI_FLASH_WriteEnable(void) {
+void W25QXXFlash::SPI_FLASH_WriteEnable(void) {
/* Select the FLASH: Chip Select low */
W25QXX_CS_L;
/* Send "Write Enable" instruction */
@@ -159,7 +156,7 @@ void ext_FLASH::SPI_FLASH_WriteEnable(void) {
* Output : None
* Return : None
*******************************************************************************/
-void ext_FLASH::SPI_FLASH_WaitForWriteEnd(void) {
+void W25QXXFlash::SPI_FLASH_WaitForWriteEnd(void) {
uint8_t FLASH_Status = 0;
/* Select the FLASH: Chip Select low */
@@ -178,7 +175,7 @@ void ext_FLASH::SPI_FLASH_WaitForWriteEnd(void) {
W25QXX_CS_H;
}
-void ext_FLASH::SPI_FLASH_SectorErase(uint32_t SectorAddr) {
+void W25QXXFlash::SPI_FLASH_SectorErase(uint32_t SectorAddr) {
/* Send write enable instruction */
SPI_FLASH_WriteEnable();
@@ -200,7 +197,7 @@ void ext_FLASH::SPI_FLASH_SectorErase(uint32_t SectorAddr) {
SPI_FLASH_WaitForWriteEnd();
}
-void ext_FLASH::SPI_FLASH_BlockErase(uint32_t BlockAddr) {
+void W25QXXFlash::SPI_FLASH_BlockErase(uint32_t BlockAddr) {
SPI_FLASH_WriteEnable();
W25QXX_CS_L;
/* Send Sector Erase instruction */
@@ -224,7 +221,7 @@ void ext_FLASH::SPI_FLASH_BlockErase(uint32_t BlockAddr) {
* Output : None
* Return : None
*******************************************************************************/
-void ext_FLASH::SPI_FLASH_BulkErase(void) {
+void W25QXXFlash::SPI_FLASH_BulkErase(void) {
/* Send write enable instruction */
SPI_FLASH_WriteEnable();
@@ -253,7 +250,7 @@ void ext_FLASH::SPI_FLASH_BulkErase(void) {
* Output : None
* Return : None
*******************************************************************************/
-void ext_FLASH::SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
+void W25QXXFlash::SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
/* Enable the write access to the FLASH */
SPI_FLASH_WriteEnable();
@@ -296,7 +293,7 @@ void ext_FLASH::SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16
* Output : None
* Return : None
*******************************************************************************/
-void ext_FLASH::SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
+void W25QXXFlash::SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % SPI_FLASH_PageSize;
@@ -361,7 +358,7 @@ void ext_FLASH::SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint
* Output : None
* Return : None
*******************************************************************************/
-void ext_FLASH::SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead) {
+void W25QXXFlash::SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead) {
/* Select the FLASH: Chip Select low */
W25QXX_CS_L;
@@ -389,7 +386,4 @@ void ext_FLASH::SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16
W25QXX_CS_H;
}
-void ext_FLASH::lv_pic_read(uint8_t *P_Rbuff, uint32_t addr, uint32_t size) {SPI_FLASH_BufferRead((uint8_t *)P_Rbuff, addr, size);}
-
-#endif // HAS_TFT_LVGL_UI
-#endif // 1 ... SPI_FLASH
+#endif // HAS_SPI_FLASH
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/W25Qxx.h b/Marlin/src/libs/W25Qxx.h
similarity index 67%
rename from Marlin/src/lcd/extui/lib/mks_ui/W25Qxx.h
rename to Marlin/src/libs/W25Qxx.h
index 88d5d6c2f..81e964345 100644
--- a/Marlin/src/lcd/extui/lib/mks_ui/W25Qxx.h
+++ b/Marlin/src/libs/W25Qxx.h
@@ -52,49 +52,7 @@
#define SPI_FLASH_PageSize 256
#define SPI_FLASH_PerWritePageSize 256
-#if 0
-
- #define PIC_NAME_MAX_LEN 50
-
- #define LOGO_MAX_SIZE (300*1024)
- #define TITLELOGO_MAX_SIZE (150*1024)
- #define DEFAULT_VIEW_MAX_SIZE (200*200*2)
- #define FLASH_VIEW_MAX_SIZE (200*200*2)
-
- //Robin 2
- #define PIC_NAME_ADDR 0x003000
- #define PIC_SIZE_ADDR 0x007000
- #define PIC_COUNTER_ADDR 0x008000
- #define PIC_LOGO_ADDR 0x009000
- //#define PIC_DATA_ADDR 0x02f000
-
- #define DEFAULT_VIEW_ADDR 0XC5800
- #define BAK_VIEW_ADDR (DEFAULT_VIEW_ADDR+90*1024)
- #define PIC_ICON_LOGO_ADDR (BAK_VIEW_ADDR+80*1024)
-
- #define PIC_DATA_ADDR (PIC_ICON_LOGO_ADDR+350*1024)
-
- #define FONTINFOADDR 0x600000
- #define UNIGBK_FLASH_ADDR (FONTINFOADDR+4096) // 4*1024
- #define GBK_FLASH_ADDR (UNIGBK_FLASH_ADDR+180224) // 176*1024
-
- #define PER_PIC_MAX_SPACE (32*1024)
-
- union union32 {
- uint8_t bytes[4];
- uint32_t dwords;
- };
-
- struct pic_msg {
- uint8_t name[PIC_NAME_MAX_LEN];
- union union32 size;
- };
-
- typedef struct pic_msg PIC_MSG;
-
-#endif // if 0
-
-class ext_FLASH {
+class W25QXXFlash {
public:
void init(uint8_t spiRate);
static uint8_t spi_flash_Rec();
@@ -111,14 +69,8 @@ public:
static void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
static void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
static void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
- //uint32_t lv_get_pic_addr(uint8_t *Pname);
- void lv_pic_read(uint8_t *P_Rbuff, uint32_t addr, uint32_t size);
};
-extern ext_FLASH W25QXX;
-
-//extern uint32_t lv_get_pic_addr(uint8_t *Pname);
-
//#ifdef __cplusplus
//} /* C-declarations for C++ */
//#endif
diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO.h
index afa9354aa..160406435 100644
--- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO.h
+++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO.h
@@ -240,8 +240,9 @@
#define ILI9488_ORIENTATION ILI9488_MADCTL_MX | ILI9488_MADCTL_MV
#endif
-#define SPI_FLASH
-#if ENABLED(SPI_FLASH)
+#define HAS_SPI_FLASH 1
+#define SPI_FLASH_SIZE 0x1000000 // 16MB
+#if HAS_SPI_FLASH
#define W25QXX_CS_PIN PB12
#define W25QXX_MOSI_PIN PB15
#define W25QXX_MISO_PIN PB14
diff --git a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h
index 4552f8cd9..be363e453 100644
--- a/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h
+++ b/Marlin/src/pins/stm32f1/pins_MKS_ROBIN_NANO_V2.h
@@ -398,8 +398,9 @@
#endif // HAS_SPI_LCD
-#define SPI_FLASH
-#if ENABLED(SPI_FLASH)
+#define HAS_SPI_FLASH 1
+#define SPI_FLASH_SIZE 0x1000000 // 16MB
+#if HAS_SPI_FLASH
#define W25QXX_CS_PIN PB12
#define W25QXX_MOSI_PIN PB15
#define W25QXX_MISO_PIN PB14