Browse Source

Use flash memory to emulate EEPROM (#11500)

Use a sector of the LPC flash memory to emulate EEPROM storage, removing the need to have an SD card to store system parameters.
Andy Shaw 6 years ago
parent
commit
5be2559eda

+ 24
- 0
Marlin/src/HAL/HAL_LPC1768/persistent_store_api.h View File

@@ -0,0 +1,24 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (C) 2016, 2017 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#include "../persistent_store_api.h"
23
+
24
+//#define FLASH_EEPROM

+ 139
- 0
Marlin/src/HAL/HAL_LPC1768/persistent_store_flash.cpp View File

@@ -0,0 +1,139 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (C) 2016, 2017 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#ifdef TARGET_LPC1768
23
+
24
+/**
25
+ * Emulate EEPROM storage using Flash Memory
26
+ *
27
+ * Use a single 32K flash sector to store EEPROM data. To reduce the
28
+ * number of erase operations a simple "levelling" scheme is used that
29
+ * maintains a number of EEPROM "slots" within the larger flash sector.
30
+ * Each slot is used in turn and the entire sector is only erased when all
31
+ * slots have been used.
32
+ *
33
+ * A simple RAM image is used to hold the EEPROM data during I/O operations
34
+ * and this is flushed to the next available slot when an update is complete.
35
+ * If RAM usage becomes an issue we could store this image in one of the two
36
+ * 16Kb I/O buffers (intended to hold DMA USB and Ethernet data, but currently
37
+ * unused).
38
+ */
39
+#include "../../inc/MarlinConfigPre.h"
40
+
41
+#if ENABLED(EEPROM_SETTINGS)
42
+
43
+#include "persistent_store_api.h"
44
+
45
+#if ENABLED(FLASH_EEPROM)
46
+
47
+extern "C" {
48
+  #include "lpc17xx_iap.h"
49
+}
50
+
51
+#define SECTOR_START(sector)	((sector < 16) ? (sector * 0x1000) : ((sector - 14) * 0x8000))
52
+#define EEPROM_SECTOR 29
53
+#define EEPROM_SIZE (E2END+1)
54
+#define SECTOR_SIZE (32768)
55
+#define EEPROM_SLOTS (SECTOR_SIZE/EEPROM_SIZE)
56
+#define EEPROM_ERASE (0xff)
57
+#define SLOT_ADDRESS(sector, slot) (((uint8_t *)SECTOR_START(sector)) + slot * EEPROM_SIZE)
58
+
59
+#if EEPROM_SIZE != 4096
60
+  #error "EEPROM_SIZE must match flash write size"
61
+#endif
62
+
63
+static uint8_t ram_eeprom[EEPROM_SIZE];
64
+static bool eeprom_dirty = false;
65
+static int current_slot = 0;
66
+
67
+bool PersistentStore::access_start() {
68
+  uint32_t first_nblank_loc, first_nblank_val;
69
+  IAP_STATUS_CODE status;
70
+
71
+  // discover which slot we are currently using.
72
+  __disable_irq();
73
+  status = BlankCheckSector(EEPROM_SECTOR, EEPROM_SECTOR, &first_nblank_loc, &first_nblank_val);
74
+  __enable_irq();
75
+  SERIAL_PROTOCOLLNPAIR("Blank check status: ", status);
76
+  if (status == CMD_SUCCESS) {
77
+    // sector is blank so nothing stored yet
78
+    SERIAL_PROTOCOLLNPGM("FLASH empty");
79
+    for (int i = 0; i < EEPROM_SIZE; i++) ram_eeprom[i] = EEPROM_ERASE;
80
+    current_slot = EEPROM_SLOTS;
81
+  }
82
+  else {
83
+    // current slot is the first non blank one
84
+    current_slot = first_nblank_loc / EEPROM_SIZE;
85
+    SERIAL_PROTOCOLLNPAIR("Flash slot: ", current_slot);
86
+    uint8_t *eeprom_data = SLOT_ADDRESS(EEPROM_SECTOR, current_slot);
87
+    SERIAL_PROTOCOLLNPAIR("Address: ", (int)eeprom_data);
88
+
89
+    // load current settings
90
+    for (int i = 0; i < EEPROM_SIZE; i++) ram_eeprom[i] = eeprom_data[i];
91
+  }
92
+  eeprom_dirty = false;
93
+
94
+  return true;
95
+}
96
+
97
+bool PersistentStore::access_finish() {
98
+  if (eeprom_dirty) {
99
+    IAP_STATUS_CODE status;
100
+    if (--current_slot < 0) {
101
+      // all slots have been used, erase everything and start again
102
+      __disable_irq();
103
+      PrepareSector(EEPROM_SECTOR, EEPROM_SECTOR);
104
+      status = EraseSector(EEPROM_SECTOR, EEPROM_SECTOR);
105
+      __enable_irq();
106
+      SERIAL_PROTOCOLLNPAIR("Erase status: ", status);
107
+      current_slot = EEPROM_SLOTS - 1;
108
+    }
109
+    SERIAL_PROTOCOLLNPAIR("Writing data to: ", current_slot);
110
+    __disable_irq();
111
+    PrepareSector(EEPROM_SECTOR, EEPROM_SECTOR);
112
+    status = CopyRAM2Flash(SLOT_ADDRESS(EEPROM_SECTOR, current_slot), ram_eeprom, IAP_WRITE_4096);
113
+    __enable_irq();
114
+    SERIAL_PROTOCOLLNPAIR("CopyRAM2Flash status: ", status);
115
+    if (status != CMD_SUCCESS) return false;
116
+    eeprom_dirty = false;
117
+  }
118
+  return true;
119
+}
120
+
121
+bool PersistentStore::write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
122
+  for (int i = 0; i < size; i++) ram_eeprom[pos + i] = value[i];
123
+  eeprom_dirty = true;
124
+  crc16(crc, value, size);
125
+  pos += size;
126
+  return false;  // return true for any error
127
+}
128
+
129
+bool PersistentStore::read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc, const bool writing/*=true*/) {
130
+  const uint8_t * const buff = writing ? &value[0] : &ram_eeprom[pos];
131
+  if (writing) for (int i = 0; i < size; i++) value[i] = ram_eeprom[pos + i];
132
+  crc16(crc, buff, size);
133
+  pos += size;
134
+  return false;  // return true for any error
135
+}
136
+
137
+#endif // FLASH_EEPROM
138
+#endif // EEPROM_SETTINGS
139
+#endif // TARGET_LPC1768

+ 41
- 39
Marlin/src/HAL/HAL_LPC1768/persistent_store_sdcard.cpp View File

@@ -22,11 +22,13 @@
22 22
  */
23 23
 #ifdef TARGET_LPC1768
24 24
 
25
-#include "../../inc/MarlinConfig.h"
25
+#include "../../inc/MarlinConfigPre.h"
26 26
 
27 27
 #if ENABLED(EEPROM_SETTINGS)
28 28
 
29
-#include "../persistent_store_api.h"
29
+#include "persistent_store_api.h"
30
+
31
+#if DISABLED(FLASH_EEPROM)
30 32
 
31 33
 #include <chanfs/diskio.h>
32 34
 #include <chanfs/ff.h>
@@ -73,8 +75,31 @@ bool PersistentStore::access_finish() {
73 75
   return true;
74 76
 }
75 77
 
76
-// File function return codes for type FRESULT   This goes away soon.   But it is helpful right now to see
77
-// the different errors the read_data() and write_data() functions are seeing.
78
+// This extra chit-chat goes away soon, but is helpful for now
79
+// to see errors that are happening in read_data / write_data
80
+static void debug_rw(const bool write, int &pos, const uint8_t *value, const size_t size, const FRESULT s, const size_t total=0) {
81
+  const char * const rw_str = write ? PSTR("write") : PSTR("read");
82
+  SERIAL_PROTOCOLCHAR(' ');
83
+  serialprint_PGM(rw_str);
84
+  SERIAL_PROTOCOLPAIR("_data(", pos);
85
+  SERIAL_PROTOCOLPAIR(",", (int)value);
86
+  SERIAL_PROTOCOLPAIR(",", (int)size);
87
+  SERIAL_PROTOCOLLNPGM(", ...)");
88
+  if (total) {
89
+    SERIAL_PROTOCOLPGM(" f_");
90
+    serialprint_PGM(rw_str);
91
+    SERIAL_PROTOCOLPAIR("()=", (int)s);
92
+    SERIAL_PROTOCOLPAIR("\n size=", size);
93
+    SERIAL_PROTOCOLPGM("\n bytes_");
94
+    serialprint_PGM(write ? PSTR("written=") : PSTR("read="));
95
+    SERIAL_PROTOCOLLN(total);
96
+  }
97
+  else
98
+    SERIAL_PROTOCOLLNPAIR(" f_lseek()=", (int)s);
99
+}
100
+
101
+// File function return codes for type FRESULT. This goes away soon, but
102
+// is helpful right now to see any errors in read_data and write_data.
78 103
 //
79 104
 //  typedef enum {
80 105
 //    FR_OK = 0,               /* (0) Succeeded */
@@ -106,28 +131,18 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, const size_t si
106 131
 
107 132
   s = f_lseek(&eeprom_file, pos);
108 133
   if (s) {
109
-   SERIAL_PROTOCOLPAIR(" write_data(", pos);         // This extra chit-chat goes away soon.  But it is helpful
110
-   SERIAL_PROTOCOLPAIR(",", (int)value);            // right now to see errors that are happening in the
111
-   SERIAL_PROTOCOLPAIR(",", (int)size);             // read_data() and write_data() functions
112
-   SERIAL_PROTOCOLLNPGM("...)");
113
-   SERIAL_PROTOCOLLNPAIR(" f_lseek()=", (int)s);
114
-   return s;
134
+    debug_rw(true, pos, value, size, s);
135
+    return s;
115 136
   }
116 137
 
117 138
   s = f_write(&eeprom_file, (void*)value, size, &bytes_written);
118 139
   if (s) {
119
-   SERIAL_PROTOCOLPAIR(" write_data(", pos);         // This extra chit-chat goes away soon.  But it is helpful
120
-   SERIAL_PROTOCOLPAIR(",", (int)value);            // right now to see errors that are happening in the
121
-   SERIAL_PROTOCOLPAIR(",", size);             // read_data() and write_data() functions
122
-   SERIAL_PROTOCOLLNPGM("...)");
123
-   SERIAL_PROTOCOLLNPAIR(" f_write()=", (int)s);
124
-   SERIAL_PROTOCOLPAIR(" size=", size);
125
-   SERIAL_PROTOCOLLNPAIR("\n bytes_written=", bytes_written);
126
-   return s;
140
+    debug_rw(true, pos, value, size, s, bytes_written);
141
+    return s;
127 142
   }
128 143
   crc16(crc, value, size);
129
-  pos = pos + size;
130
-  return (bytes_written != size);  // return true for any error
144
+  pos += size;
145
+  return bytes_written != size;  // return true for any error
131 146
 }
132 147
 
133 148
 bool PersistentStore::read_data(int &pos, uint8_t* value, const size_t size, uint16_t *crc, const bool writing/*=true*/) {
@@ -137,14 +152,8 @@ bool PersistentStore::read_data(int &pos, uint8_t* value, const size_t size, uin
137 152
   s = f_lseek(&eeprom_file, pos);
138 153
 
139 154
   if (s) {
140
-   SERIAL_PROTOCOLPAIR(" read_data(", pos);         // This extra chit-chat goes away soon.  But it is helpful
141
-   SERIAL_PROTOCOLCHAR(',');
142
-   SERIAL_PROTOCOL((int)value);                     // right now to see errors that are happening in the
143
-   SERIAL_PROTOCOLCHAR(',');
144
-   SERIAL_PROTOCOL(size);                           // read_data() and write_data() functions
145
-   SERIAL_PROTOCOLLNPGM("...)");
146
-   SERIAL_PROTOCOLLNPAIR(" f_lseek()=", (int)s);
147
-   return true;
155
+    debug_rw(false, pos, value, size, s);
156
+    return true;
148 157
   }
149 158
 
150 159
   if (writing) {
@@ -158,23 +167,16 @@ bool PersistentStore::read_data(int &pos, uint8_t* value, const size_t size, uin
158 167
   }
159 168
 
160 169
   if (s) {
161
-   SERIAL_PROTOCOLPAIR(" read_data(", pos);         // This extra chit-chat goes away soon.  But it is helpful
162
-   SERIAL_PROTOCOLCHAR(',');
163
-   SERIAL_PROTOCOL((int)value);                     // right now to see errors that are happening in the
164
-   SERIAL_PROTOCOLCHAR(',');
165
-   SERIAL_PROTOCOL(size);                           // read_data() and write_data() functions
166
-   SERIAL_PROTOCOLLNPGM("...)");
167
-   SERIAL_PROTOCOLLNPAIR(" f_write()=", (int)s);
168
-   SERIAL_PROTOCOLPAIR(" size=", size);
169
-   SERIAL_PROTOCOLLNPAIR("\n bytes_read=",  bytes_read);
170
-   return true;
170
+    debug_rw(false, pos, value, size, s, bytes_read);
171
+    return true;
171 172
   }
172 173
 
173
-  pos = pos + size;
174
+  pos += size;
174 175
   return bytes_read != size;  // return true for any error
175 176
 }
176 177
 
177 178
 const size_t PersistentStore::capacity() { return 4096; } // 4KiB of Emulated EEPROM
178 179
 
180
+#endif // !FLASH_EEPROM
179 181
 #endif // EEPROM_SETTINGS
180 182
 #endif // TARGET_LPC1768

+ 4
- 2
frameworks/CMSIS/LPC1768/system/LPC1768.ld View File

@@ -1,8 +1,10 @@
1 1
 /* Linker script for mbed LPC1768 */
2 2
 MEMORY
3 3
 {
4
-  //FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
5
-  FLASH (rx) : ORIGIN = 16K, LENGTH = (512K - 16K)
4
+  /* Reserve first 16K (4 sectors * 4KB) for bootloader
5
+   * Reserve the last 32KB sector for EEPROM emulation
6
+   */
7
+  FLASH (rx) : ORIGIN = 16K, LENGTH = (512K - 48K)
6 8
   RAM (rwx) : ORIGIN = 0x100000C8, LENGTH = (32K - 0xC8)
7 9
 
8 10
   USB_RAM(rwx) : ORIGIN = 0x2007C000, LENGTH = 16K

Loading…
Cancel
Save