Browse Source

Clean up EEPROM interfaces (#17803)

Scott Lahteine 4 years ago
parent
commit
2107bc5836
No account linked to committer's email address

+ 947
- 15
Marlin/src/HAL/DUE/eeprom_flash.cpp View File

@@ -26,35 +26,967 @@
26 26
 
27 27
 #if ENABLED(FLASH_EEPROM_EMULATION)
28 28
 
29
-#include "../../inc/MarlinConfig.h"
29
+#ifndef E2END
30
+  #define E2END 0xFFF // Default to Flash emulated EEPROM size (eeprom_emul.cpp)
31
+#endif
30 32
 
31
-#include "../shared/eeprom_if.h"
32
-#include "../shared/eeprom_api.h"
33
+/* EEPROM emulation over flash with reduced wear
34
+ *
35
+ * We will use 2 contiguous groups of pages as main and alternate.
36
+ * We want an structure that allows to read as fast as possible,
37
+ * without the need of scanning the whole FLASH memory.
38
+ *
39
+ * FLASH bits default erased state is 1, and can be set to 0
40
+ * on a per bit basis. To reset them to 1, a full page erase
41
+ * is needed.
42
+ *
43
+ * Values are stored as differences that should be applied to a
44
+ * completely erased EEPROM (filled with 0xFFs). We just encode
45
+ * the starting address of the values to change, the length of
46
+ * the block of new values, and the values themselves. All diffs
47
+ * are accumulated into a RAM buffer, compacted into the least
48
+ * amount of non overlapping diffs possible and sorted by starting
49
+ * address before being saved into the next available page of FLASH
50
+ * of the current group.
51
+ * Once the current group is completely full, we compact it and save
52
+ * it into the other group, then erase the current group and switch
53
+ * to that new group and set it as current.
54
+ *
55
+ * The FLASH endurance is about 1/10 ... 1/100 of an EEPROM
56
+ * endurance, but EEPROM endurance is specified per byte, not
57
+ * per page. We can't emulate EE endurance with FLASH for all
58
+ * bytes, but we can emulate endurance for a given percent of
59
+ * bytes.
60
+ *
61
+ */
62
+
63
+//#define EE_EMU_DEBUG
64
+
65
+#define EEPROMSize     4096
66
+#define PagesPerGroup   128
67
+#define GroupCount        2
68
+#define PageSize        256u
69
+
70
+ /* Flash storage */
71
+typedef struct FLASH_SECTOR {
72
+  uint8_t page[PageSize];
73
+} FLASH_SECTOR_T;
74
+
75
+#define PAGE_FILL \
76
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
77
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
78
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
79
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
80
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
81
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
82
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
83
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
84
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
85
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
86
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
87
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
88
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
89
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
90
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
91
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
92
+
93
+#define FLASH_INIT_FILL \
94
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
95
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
96
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
97
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
98
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
99
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
100
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
101
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
102
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
103
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
104
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
105
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
106
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
107
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
108
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
109
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
110
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
111
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
112
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
113
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
114
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
115
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
116
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
117
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
118
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
119
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
120
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
121
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
122
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
123
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
124
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
125
+  PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL
126
+
127
+/* This is the FLASH area used to emulate a 2Kbyte EEPROM  -- We need this buffer aligned
128
+   to a 256 byte boundary. */
129
+static const uint8_t flashStorage[PagesPerGroup * GroupCount * PageSize] __attribute__ ((aligned (PageSize))) = { FLASH_INIT_FILL };
130
+
131
+/* Get the address of an specific page */
132
+static const FLASH_SECTOR_T* getFlashStorage(int page) {
133
+  return (const FLASH_SECTOR_T*)&flashStorage[page*PageSize];
134
+}
135
+
136
+static uint8_t buffer[256] = {0},   // The RAM buffer to accumulate writes
137
+               curPage = 0,         // Current FLASH page inside the group
138
+               curGroup = 0xFF;     // Current FLASH group
139
+
140
+#define DEBUG_OUT ENABLED(EE_EMU_DEBUG)
141
+#include "../../core/debug_out.h"
142
+
143
+static void ee_Dump(const int page, const void* data) {
144
+
145
+  #ifdef EE_EMU_DEBUG
146
+
147
+    const uint8_t* c = (const uint8_t*) data;
148
+    char buffer[80];
149
+
150
+    sprintf_P(buffer, PSTR("Page: %d (0x%04x)\n"), page, page);
151
+    DEBUG_ECHO(buffer);
152
+
153
+    char* p = &buffer[0];
154
+    for (int i = 0; i< PageSize; ++i) {
155
+      if ((i & 0xF) == 0) p += sprintf_P(p, PSTR("%04x] "), i);
33 156
 
34
-#if !defined(E2END)
35
-  #define E2END 0xFFF // Default to Flash emulated EEPROM size (EepromEmulation_Due.cpp)
157
+      p += sprintf_P(p, PSTR(" %02x"), c[i]);
158
+      if ((i & 0xF) == 0xF) {
159
+        *p++ = '\n';
160
+        *p = 0;
161
+        DEBUG_ECHO(buffer);
162
+        p = &buffer[0];
163
+      }
164
+    }
165
+
166
+  #else
167
+    UNUSED(page);
168
+    UNUSED(data);
169
+  #endif
170
+}
171
+
172
+/* Flash Writing Protection Key */
173
+#define FWP_KEY    0x5Au
174
+
175
+#if SAM4S_SERIES
176
+  #define EEFC_FCR_FCMD(value) \
177
+  ((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos)))
178
+  #define EEFC_ERROR_FLAGS  (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)
179
+#else
180
+  #define EEFC_ERROR_FLAGS  (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)
36 181
 #endif
37 182
 
38
-extern void eeprom_flush();
183
+/**
184
+ * Writes the contents of the specified page (no previous erase)
185
+ * @param page    (page #)
186
+ * @param data    (pointer to the data buffer)
187
+ */
188
+__attribute__ ((long_call, section (".ramfunc")))
189
+static bool ee_PageWrite(uint16_t page, const void* data) {
190
+
191
+  uint16_t i;
192
+  uint32_t addrflash = uint32_t(getFlashStorage(page));
39 193
 
40
-size_t PersistentStore::capacity()    { return E2END + 1; }
41
-bool PersistentStore::access_start()  { return true; }
194
+  // Read the flash contents
195
+  uint32_t pageContents[PageSize>>2];
196
+  memcpy(pageContents, (void*)addrflash, PageSize);
197
+
198
+  // We ONLY want to toggle bits that have changed, and that have changed to 0.
199
+  // SAM3X8E tends to destroy contiguous bits if reprogrammed without erasing, so
200
+  // we try by all means to avoid this. That is why it says: "The Partial
201
+  // Programming mode works only with 128-bit (or higher) boundaries. It cannot
202
+  // be used with boundaries lower than 128 bits (8, 16 or 32-bit for example)."
203
+  // All bits that did not change, set them to 1.
204
+  for (i = 0; i <PageSize >> 2; i++)
205
+    pageContents[i] = (((uint32_t*)data)[i]) | (~(pageContents[i] ^ ((uint32_t*)data)[i]));
206
+
207
+  DEBUG_ECHO_START();
208
+  DEBUG_ECHOLNPAIR("EEPROM PageWrite   ", page);
209
+  DEBUG_ECHOLNPAIR(" in FLASH address ", (uint32_t)addrflash);
210
+  DEBUG_ECHOLNPAIR(" base address     ", (uint32_t)getFlashStorage(0));
211
+  DEBUG_FLUSH();
212
+
213
+  // Get the page relative to the start of the EFC controller, and the EFC controller to use
214
+  Efc *efc;
215
+  uint16_t fpage;
216
+  if (addrflash >= IFLASH1_ADDR) {
217
+    efc = EFC1;
218
+    fpage = (addrflash - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
219
+  }
220
+  else {
221
+    efc = EFC0;
222
+    fpage = (addrflash - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
223
+  }
224
+
225
+  // Get the page that must be unlocked, then locked
226
+  uint16_t lpage = fpage & (~((IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) - 1));
227
+
228
+  // Disable all interrupts
229
+  __disable_irq();
230
+
231
+  // Get the FLASH wait states
232
+  uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
233
+
234
+  // Set wait states to 6 (SAM errata)
235
+  efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
236
+
237
+  // Unlock the flash page
238
+  uint32_t status;
239
+  efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(lpage) | EEFC_FCR_FCMD(EFC_FCMD_CLB);
240
+  while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
241
+    // force compiler to not optimize this -- NOPs don't work!
242
+    __asm__ __volatile__("");
243
+  };
244
+
245
+  if ((status & EEFC_ERROR_FLAGS) != 0) {
246
+
247
+    // Restore original wait states
248
+    efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
249
+
250
+    // Reenable interrupts
251
+    __enable_irq();
252
+
253
+    DEBUG_ECHO_START();
254
+    DEBUG_ECHOLNPAIR("EEPROM Unlock failure for page ", page);
255
+    return false;
256
+  }
257
+
258
+  // Write page and lock:  Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
259
+  const uint32_t * aligned_src = (const uint32_t *) &pageContents[0]; /*data;*/
260
+  uint32_t * p_aligned_dest = (uint32_t *) addrflash;
261
+  for (i = 0; i < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++i) {
262
+    *p_aligned_dest++ = *aligned_src++;
263
+  }
264
+  efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(fpage) | EEFC_FCR_FCMD(EFC_FCMD_WPL);
265
+  while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
266
+    // force compiler to not optimize this -- NOPs don't work!
267
+    __asm__ __volatile__("");
268
+  };
269
+
270
+  if ((status & EEFC_ERROR_FLAGS) != 0) {
271
+
272
+    // Restore original wait states
273
+    efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
274
+
275
+    // Reenable interrupts
276
+    __enable_irq();
277
+
278
+    DEBUG_ECHO_START();
279
+    DEBUG_ECHOLNPAIR("EEPROM Write failure for page ", page);
280
+
281
+    return false;
282
+  }
283
+
284
+  // Restore original wait states
285
+  efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
286
+
287
+  // Reenable interrupts
288
+  __enable_irq();
289
+
290
+  // Compare contents
291
+  if (memcmp(getFlashStorage(page),data,PageSize)) {
292
+
293
+    #ifdef EE_EMU_DEBUG
294
+      DEBUG_ECHO_START();
295
+      DEBUG_ECHOLNPAIR("EEPROM Verify Write failure for page ", page);
296
+
297
+      ee_Dump( page, (uint32_t *)addrflash);
298
+      ee_Dump(-page, data);
299
+
300
+      // Calculate count of changed bits
301
+      uint32_t* p1 = (uint32_t*)addrflash;
302
+      uint32_t* p2 = (uint32_t*)data;
303
+      int count = 0;
304
+      for (i =0; i<PageSize >> 2; i++) {
305
+        if (p1[i] != p2[i]) {
306
+          uint32_t delta = p1[i] ^ p2[i];
307
+          while (delta) {
308
+            if ((delta&1) != 0)
309
+              count++;
310
+            delta >>= 1;
311
+          }
312
+        }
313
+      }
314
+      DEBUG_ECHOLNPAIR("--> Differing bits: ", count);
315
+    #endif
316
+
317
+    return false;
318
+  }
319
+
320
+  return true;
321
+}
322
+
323
+/**
324
+ * Erases the contents of the specified page
325
+ * @param page    (page #)
326
+  */
327
+__attribute__ ((long_call, section (".ramfunc")))
328
+static bool ee_PageErase(uint16_t page) {
329
+
330
+  uint16_t i;
331
+  uint32_t addrflash = uint32_t(getFlashStorage(page));
332
+
333
+  DEBUG_ECHO_START();
334
+  DEBUG_ECHOLNPAIR("EEPROM PageErase  ", page);
335
+  DEBUG_ECHOLNPAIR(" in FLASH address ", (uint32_t)addrflash);
336
+  DEBUG_ECHOLNPAIR(" base address     ", (uint32_t)getFlashStorage(0));
337
+  DEBUG_FLUSH();
338
+
339
+  // Get the page relative to the start of the EFC controller, and the EFC controller to use
340
+  Efc *efc;
341
+  uint16_t fpage;
342
+  if (addrflash >= IFLASH1_ADDR) {
343
+    efc = EFC1;
344
+    fpage = (addrflash - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
345
+  }
346
+  else {
347
+    efc = EFC0;
348
+    fpage = (addrflash - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
349
+  }
350
+
351
+  // Get the page that must be unlocked, then locked
352
+  uint16_t lpage = fpage & (~((IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) - 1));
353
+
354
+  // Disable all interrupts
355
+  __disable_irq();
356
+
357
+  // Get the FLASH wait states
358
+  uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
359
+
360
+  // Set wait states to 6 (SAM errata)
361
+  efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
362
+
363
+  // Unlock the flash page
364
+  uint32_t status;
365
+  efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(lpage) | EEFC_FCR_FCMD(EFC_FCMD_CLB);
366
+  while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
367
+    // force compiler to not optimize this -- NOPs don't work!
368
+    __asm__ __volatile__("");
369
+  };
370
+  if ((status & EEFC_ERROR_FLAGS) != 0) {
371
+
372
+    // Restore original wait states
373
+    efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
374
+
375
+    // Reenable interrupts
376
+    __enable_irq();
377
+
378
+    DEBUG_ECHO_START();
379
+    DEBUG_ECHOLNPAIR("EEPROM Unlock failure for page ",page);
380
+
381
+    return false;
382
+  }
383
+
384
+  // Erase Write page and lock: Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
385
+  uint32_t * p_aligned_dest = (uint32_t *) addrflash;
386
+  for (i = 0; i < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++i) {
387
+    *p_aligned_dest++ = 0xFFFFFFFF;
388
+  }
389
+  efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(fpage) | EEFC_FCR_FCMD(EFC_FCMD_EWPL);
390
+  while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
391
+    // force compiler to not optimize this -- NOPs don't work!
392
+    __asm__ __volatile__("");
393
+  };
394
+  if ((status & EEFC_ERROR_FLAGS) != 0) {
395
+
396
+    // Restore original wait states
397
+    efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
398
+
399
+    // Reenable interrupts
400
+    __enable_irq();
401
+
402
+    DEBUG_ECHO_START();
403
+    DEBUG_ECHOLNPAIR("EEPROM Erase failure for page ",page);
404
+
405
+    return false;
406
+  }
407
+
408
+  // Restore original wait states
409
+  efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
410
+
411
+  // Reenable interrupts
412
+  __enable_irq();
413
+
414
+  // Check erase
415
+  uint32_t * aligned_src = (uint32_t *) addrflash;
416
+  for (i = 0; i < PageSize >> 2; i++) {
417
+    if (*aligned_src++ != 0xFFFFFFFF) {
418
+      DEBUG_ECHO_START();
419
+      DEBUG_ECHOLNPAIR("EEPROM Verify Erase failure for page ",page);
420
+      ee_Dump(page, (uint32_t *)addrflash);
421
+      return false;
422
+    }
423
+  }
42 424
 
43
-bool PersistentStore::access_finish() {
44
-  eeprom_flush();
45 425
   return true;
46 426
 }
47 427
 
428
+static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer=false) {
429
+
430
+  uint32_t baddr;
431
+  uint32_t blen;
432
+
433
+  // If we were requested an address outside of the emulated range, fail now
434
+  if (address >= EEPROMSize)
435
+    return false;
436
+
437
+  // Check that the value is not contained in the RAM buffer
438
+  if (!excludeRAMBuffer) {
439
+    uint16_t i = 0;
440
+    while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
441
+
442
+      // Get the address of the block
443
+      baddr = buffer[i] | (buffer[i + 1] << 8);
444
+
445
+      // Get the length of the block
446
+      blen = buffer[i + 2];
447
+
448
+      // If we reach the end of the list, break loop
449
+      if (blen == 0xFF)
450
+        break;
451
+
452
+      // Check if data is contained in this block
453
+      if (address >= baddr &&
454
+        address < (baddr + blen)) {
455
+
456
+        // Yes, it is contained. Return it!
457
+        return buffer[i + 3 + address - baddr];
458
+      }
459
+
460
+      // As blocks are always sorted, if the starting address of this block is higher
461
+      // than the address we are looking for, break loop now - We wont find the value
462
+      // associated to the address
463
+      if (baddr > address)
464
+        break;
465
+
466
+      // Jump to the next block
467
+      i += 3 + blen;
468
+    }
469
+  }
470
+
471
+  // It is NOT on the RAM buffer. It could be stored in FLASH. We are
472
+  //  ensured on a given FLASH page, address contents are never repeated
473
+  //  but on different pages, there is no such warranty, so we must go
474
+  //  backwards from the last written FLASH page to the first one.
475
+  for (int page = curPage - 1; page >= 0; --page) {
476
+
477
+    // Get a pointer to the flash page
478
+    uint8_t* pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
479
+
480
+    uint16_t i = 0;
481
+    while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
482
+
483
+      // Get the address of the block
484
+      baddr = pflash[i] | (pflash[i + 1] << 8);
485
+
486
+      // Get the length of the block
487
+      blen = pflash[i + 2];
488
+
489
+      // If we reach the end of the list, break loop
490
+      if (blen == 0xFF)
491
+        break;
492
+
493
+      // Check if data is contained in this block
494
+      if (address >= baddr && address < (baddr + blen))
495
+        return pflash[i + 3 + address - baddr]; // Yes, it is contained. Return it!
496
+
497
+      // As blocks are always sorted, if the starting address of this block is higher
498
+      // than the address we are looking for, break loop now - We wont find the value
499
+      // associated to the address
500
+      if (baddr > address) break;
501
+
502
+      // Jump to the next block
503
+      i += 3 + blen;
504
+    }
505
+  }
506
+
507
+  // If reached here, value is not stored, so return its default value
508
+  return 0xFF;
509
+}
510
+
511
+static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer=false) {
512
+  uint32_t baddr,
513
+           blen,
514
+           nextAddr = 0xFFFF,
515
+           nextRange = 0;
516
+
517
+  // Check that the value is not contained in the RAM buffer
518
+  if (!excludeRAMBuffer) {
519
+    uint16_t i = 0;
520
+    while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
521
+
522
+      // Get the address of the block
523
+      baddr = buffer[i] | (buffer[i + 1] << 8);
524
+
525
+      // Get the length of the block
526
+      blen = buffer[i + 2];
527
+
528
+      // If we reach the end of the list, break loop
529
+      if (blen == 0xFF) break;
530
+
531
+      // Check if address and address + 1 is contained in this block
532
+      if (address >= baddr && address < (baddr + blen))
533
+        return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
534
+
535
+      // Otherwise, check if we can use it as a limit
536
+      if (baddr > address && baddr < nextAddr) {
537
+        nextAddr = baddr;
538
+        nextRange = blen;
539
+      }
540
+
541
+      // As blocks are always sorted, if the starting address of this block is higher
542
+      // than the address we are looking for, break loop now - We wont find the value
543
+      // associated to the address
544
+      if (baddr > address) break;
545
+
546
+      // Jump to the next block
547
+      i += 3 + blen;
548
+    }
549
+  }
550
+
551
+  // It is NOT on the RAM buffer. It could be stored in FLASH. We are
552
+  //  ensured on a given FLASH page, address contents are never repeated
553
+  //  but on different pages, there is no such warranty, so we must go
554
+  //  backwards from the last written FLASH page to the first one.
555
+  for (int page = curPage - 1; page >= 0; --page) {
556
+
557
+    // Get a pointer to the flash page
558
+    uint8_t* pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
559
+
560
+    uint16_t i = 0;
561
+    while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
562
+
563
+      // Get the address of the block
564
+      baddr = pflash[i] | (pflash[i + 1] << 8);
565
+
566
+      // Get the length of the block
567
+      blen = pflash[i + 2];
568
+
569
+      // If we reach the end of the list, break loop
570
+      if (blen == 0xFF) break;
571
+
572
+      // Check if data is contained in this block
573
+      if (address >= baddr && address < (baddr + blen))
574
+        return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
575
+
576
+      // Otherwise, check if we can use it as a limit
577
+      if (baddr > address && baddr < nextAddr) {
578
+        nextAddr = baddr;
579
+        nextRange = blen;
580
+      }
581
+
582
+      // As blocks are always sorted, if the starting address of this block is higher
583
+      // than the address we are looking for, break loop now - We wont find the value
584
+      // associated to the address
585
+      if (baddr > address) break;
586
+
587
+      // Jump to the next block
588
+      i += 3 + blen;
589
+    }
590
+  }
591
+
592
+  // If reached here, we will return the next valid address
593
+  return nextAddr | (nextRange << 16);
594
+}
595
+
596
+static bool ee_IsPageClean(int page) {
597
+  uint32_t* pflash = (uint32_t*) getFlashStorage(page);
598
+  for (uint16_t i = 0; i < (PageSize >> 2); ++i)
599
+    if (*pflash++ != 0xFFFFFFFF) return false;
600
+  return true;
601
+}
602
+
603
+static bool ee_Flush(uint32_t overrideAddress = 0xFFFFFFFF, uint8_t overrideData=0xFF) {
604
+
605
+  // Check if RAM buffer has something to be written
606
+  bool isEmpty = true;
607
+  uint32_t* p = (uint32_t*) &buffer[0];
608
+  for (uint16_t j = 0; j < (PageSize >> 2); j++) {
609
+    if (*p++ != 0xFFFFFFFF) {
610
+      isEmpty = false;
611
+      break;
612
+    }
613
+  }
614
+
615
+  // If something has to be written, do so!
616
+  if (!isEmpty) {
617
+
618
+    // Write the current ram buffer into FLASH
619
+    ee_PageWrite(curPage + curGroup * PagesPerGroup, buffer);
620
+
621
+    // Clear the RAM buffer
622
+    memset(buffer, 0xFF, sizeof(buffer));
623
+
624
+    // Increment the page to use the next time
625
+    ++curPage;
626
+  }
627
+
628
+  // Did we reach the maximum count of available pages per group for storage ?
629
+  if (curPage < PagesPerGroup) {
630
+
631
+    // Do we have an override address ?
632
+    if (overrideAddress < EEPROMSize) {
633
+
634
+      // Yes, just store the value into the RAM buffer
635
+      buffer[0] = overrideAddress & 0xFF;
636
+      buffer[0 + 1] = (overrideAddress >> 8) & 0xFF;
637
+      buffer[0 + 2] = 1;
638
+      buffer[0 + 3] = overrideData;
639
+    }
640
+
641
+    // Done!
642
+    return true;
643
+  }
644
+
645
+  // We have no space left on the current group - We must compact the values
646
+  uint16_t i = 0;
647
+
648
+  // Compute the next group to use
649
+  int curwPage = 0, curwGroup = curGroup + 1;
650
+  if (curwGroup >= GroupCount) curwGroup = 0;
651
+
652
+  uint32_t rdAddr = 0;
653
+  do {
654
+
655
+    // Get the next valid range
656
+    uint32_t addrRange = ee_GetAddrRange(rdAddr, true);
657
+
658
+    // Make sure not to skip the override address, if specified
659
+    int rdRange;
660
+    if (overrideAddress < EEPROMSize &&
661
+      rdAddr <= overrideAddress &&
662
+      (addrRange & 0xFFFF) > overrideAddress) {
663
+
664
+      rdAddr = overrideAddress;
665
+      rdRange = 1;
666
+    }
667
+    else {
668
+      rdAddr = addrRange & 0xFFFF;
669
+      rdRange = addrRange >> 16;
670
+    }
671
+
672
+    // If no range, break loop
673
+    if (rdRange == 0)
674
+      break;
675
+
676
+    do {
677
+
678
+      // Get the value
679
+      uint8_t rdValue = overrideAddress == rdAddr ? overrideData : ee_Read(rdAddr, true);
680
+
681
+      // Do not bother storing default values
682
+      if (rdValue != 0xFF) {
683
+
684
+        // If we have room, add it to the buffer
685
+        if (buffer[i + 2] == 0xFF) {
686
+
687
+          // Uninitialized buffer, just add it!
688
+          buffer[i] = rdAddr & 0xFF;
689
+          buffer[i + 1] = (rdAddr >> 8) & 0xFF;
690
+          buffer[i + 2] = 1;
691
+          buffer[i + 3] = rdValue;
692
+
693
+        }
694
+        else {
695
+          // Buffer already has contents. Check if we can extend it
696
+
697
+          // Get the address of the block
698
+          uint32_t baddr = buffer[i] | (buffer[i + 1] << 8);
699
+
700
+          // Get the length of the block
701
+          uint32_t blen = buffer[i + 2];
702
+
703
+          // Can we expand it ?
704
+          if (rdAddr == (baddr + blen) &&
705
+            i < (PageSize - 4) && /* This block has a chance to contain data AND */
706
+            buffer[i + 2] < (PageSize - i - 3)) {/* There is room for this block to be expanded */
707
+
708
+            // Yes, do it
709
+            ++buffer[i + 2];
710
+
711
+            // And store the value
712
+            buffer[i + 3 + rdAddr - baddr] = rdValue;
713
+
714
+          }
715
+          else {
716
+
717
+            // No, we can't expand it - Skip the existing block
718
+            i += 3 + blen;
719
+
720
+            // Can we create a new slot ?
721
+            if (i > (PageSize - 4)) {
722
+
723
+              // Not enough space - Write the current buffer to FLASH
724
+              ee_PageWrite(curwPage + curwGroup * PagesPerGroup, buffer);
725
+
726
+              // Advance write page (as we are compacting, should never overflow!)
727
+              ++curwPage;
728
+
729
+              // Clear RAM buffer
730
+              memset(buffer, 0xFF, sizeof(buffer));
731
+
732
+              // Start fresh */
733
+              i = 0;
734
+            }
735
+
736
+            // Enough space, add the new block
737
+            buffer[i] = rdAddr & 0xFF;
738
+            buffer[i + 1] = (rdAddr >> 8) & 0xFF;
739
+            buffer[i + 2] = 1;
740
+            buffer[i + 3] = rdValue;
741
+          }
742
+        }
743
+      }
744
+
745
+      // Go to the next address
746
+      ++rdAddr;
747
+
748
+      // Repeat for bytes of this range
749
+    } while (--rdRange);
750
+
751
+    // Repeat until we run out of ranges
752
+  } while (rdAddr < EEPROMSize);
753
+
754
+  // We must erase the previous group, in preparation for the next swap
755
+  for (int page = 0; page < curPage; page++) {
756
+    ee_PageErase(page + curGroup * PagesPerGroup);
757
+  }
758
+
759
+  // Finally, Now the active group is the created new group
760
+  curGroup = curwGroup;
761
+  curPage = curwPage;
762
+
763
+  // Done!
764
+  return true;
765
+}
766
+
767
+static bool ee_Write(uint32_t address, uint8_t data) {
768
+
769
+  // If we were requested an address outside of the emulated range, fail now
770
+  if (address >= EEPROMSize) return false;
771
+
772
+  // Lets check if we have a block with that data previously defined. Block
773
+  //  start addresses are always sorted in ascending order
774
+  uint16_t i = 0;
775
+  while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
776
+
777
+    // Get the address of the block
778
+    uint32_t baddr = buffer[i] | (buffer[i + 1] << 8);
779
+
780
+    // Get the length of the block
781
+    uint32_t blen = buffer[i + 2];
782
+
783
+    // If we reach the end of the list, break loop
784
+    if (blen == 0xFF)
785
+      break;
786
+
787
+    // Check if data is contained in this block
788
+    if (address >= baddr &&
789
+      address < (baddr + blen)) {
790
+
791
+      // Yes, it is contained. Just modify it
792
+      buffer[i + 3 + address - baddr] = data;
793
+
794
+      // Done!
795
+      return true;
796
+    }
797
+
798
+    // Maybe we could add it to the front or to the back
799
+    // of this block ?
800
+    if ((address + 1) == baddr || address == (baddr + blen)) {
801
+
802
+      // Potentially, it could be done. But we must ensure there is room
803
+      // so we can expand the block. Lets find how much free space remains
804
+      uint32_t iend = i;
805
+      do {
806
+        uint32_t ln = buffer[iend + 2];
807
+        if (ln == 0xFF) break;
808
+        iend += 3 + ln;
809
+      } while (iend <= (PageSize - 4)); /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
810
+
811
+      // Here, inxt points to the first free address in the buffer. Do we have room ?
812
+      if (iend < PageSize) {
813
+        // Yes, at least a byte is free - We can expand the block
814
+
815
+        // Do we have to insert at the beginning ?
816
+        if ((address + 1) == baddr) {
817
+
818
+          // Insert at the beginning
819
+
820
+          // Make room at the beginning for our byte
821
+          memmove(&buffer[i + 3 + 1], &buffer[i + 3], iend - i - 3);
822
+
823
+          // Adjust the header and store the data
824
+          buffer[i] = address & 0xFF;
825
+          buffer[i + 1] = (address >> 8) & 0xFF;
826
+          buffer[i + 2]++;
827
+          buffer[i + 3] = data;
828
+
829
+        }
830
+        else {
831
+
832
+          // Insert at the end - There is a very interesting thing that could happen here:
833
+          //  Maybe we could coalesce the next block with this block. Let's try to do it!
834
+          uint16_t inext = i + 3 + blen;
835
+          if (inext <= (PageSize - 4) &&
836
+            (buffer[inext] | uint16_t(buffer[inext + 1] << 8)) == (baddr + blen + 1)) {
837
+            // YES! ... we can coalesce blocks! . Do it!
838
+
839
+            // Adjust this block header to include the next one
840
+            buffer[i + 2] += buffer[inext + 2] + 1;
841
+
842
+            // Store data at the right place
843
+            buffer[i + 3 + blen] = data;
844
+
845
+            // Remove the next block header and append its data
846
+            memmove(&buffer[inext + 1], &buffer[inext + 3], iend - inext - 3);
847
+
848
+            // Finally, as we have saved 2 bytes at the end, make sure to clean them
849
+            buffer[iend - 2] = 0xFF;
850
+            buffer[iend - 1] = 0xFF;
851
+
852
+          }
853
+          else {
854
+            // NO ... No coalescing possible yet
855
+
856
+            // Make room at the end for our byte
857
+            memmove(&buffer[i + 3 + blen + 1], &buffer[i + 3 + blen], iend - i - 3 - blen);
858
+
859
+            // And add the data to the block
860
+            buffer[i + 2]++;
861
+            buffer[i + 3 + blen] = data;
862
+          }
863
+        }
864
+
865
+        // Done!
866
+        return true;
867
+      }
868
+    }
869
+
870
+    // As blocks are always sorted, if the starting address of this block is higher
871
+    // than the address we are looking for, break loop now - We wont find the value
872
+    // associated to the address
873
+    if (baddr > address) break;
874
+
875
+    // Jump to the next block
876
+    i += 3 + blen;
877
+  }
878
+
879
+  // Value is not stored AND we can't expand previous block to contain it. We must create a new block
880
+
881
+  // First, lets find how much free space remains
882
+  uint32_t iend = i;
883
+  while (iend <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
884
+    uint32_t ln = buffer[iend + 2];
885
+    if (ln == 0xFF) break;
886
+    iend += 3 + ln;
887
+  }
888
+
889
+  // If there is room for a new block, insert it at the proper place
890
+  if (iend <= (PageSize - 4)) {
891
+
892
+    // We have room to create a new block. Do so --- But add
893
+    // the block at the proper position, sorted by starting
894
+    // address, so it will be possible to compact it with other blocks.
895
+
896
+    // Make space
897
+    memmove(&buffer[i + 4], &buffer[i], iend - i);
898
+
899
+    // And add the block
900
+    buffer[i] = address & 0xFF;
901
+    buffer[i + 1] = (address >> 8) & 0xFF;
902
+    buffer[i + 2] = 1;
903
+    buffer[i + 3] = data;
904
+
905
+    // Done!
906
+    return true;
907
+  }
908
+
909
+  // Not enough room to store this information on this FLASH page -  Perform a
910
+  // flush and override the address with the specified contents
911
+  return ee_Flush(address, data);
912
+}
913
+
914
+static void ee_Init() {
915
+
916
+  // Just init once!
917
+  if (curGroup != 0xFF) return;
918
+
919
+  // Clean up the SRAM buffer
920
+  memset(buffer, 0xFF, sizeof(buffer));
921
+
922
+  // Now, we must find out the group where settings are stored
923
+  for (curGroup = 0; curGroup < GroupCount; curGroup++)
924
+    if (!ee_IsPageClean(curGroup * PagesPerGroup)) break;
925
+
926
+  // If all groups seem to be used, default to first group
927
+  if (curGroup >= GroupCount) curGroup = 0;
928
+
929
+  DEBUG_ECHO_START();
930
+  DEBUG_ECHOLNPAIR("EEPROM Current Group: ",curGroup);
931
+  DEBUG_FLUSH();
932
+
933
+  // Now, validate that all the other group pages are empty
934
+  for (int grp = 0; grp < GroupCount; grp++) {
935
+    if (grp == curGroup) continue;
936
+
937
+    for (int page = 0; page < PagesPerGroup; page++) {
938
+      if (!ee_IsPageClean(grp * PagesPerGroup + page)) {
939
+        DEBUG_ECHO_START();
940
+        DEBUG_ECHOLNPAIR("EEPROM Page ", page, " not clean on group ", grp);
941
+        DEBUG_FLUSH();
942
+        ee_PageErase(grp * PagesPerGroup + page);
943
+      }
944
+    }
945
+  }
946
+
947
+  // Finally, for the active group, determine the first unused page
948
+  // and also validate that all the other ones are clean
949
+  for (curPage = 0; curPage < PagesPerGroup; curPage++) {
950
+    if (ee_IsPageClean(curGroup * PagesPerGroup + curPage)) {
951
+      ee_Dump(curGroup * PagesPerGroup + curPage, getFlashStorage(curGroup * PagesPerGroup + curPage));
952
+      break;
953
+    }
954
+  }
955
+
956
+  DEBUG_ECHO_START();
957
+  DEBUG_ECHOLNPAIR("EEPROM Active page: ", curPage);
958
+  DEBUG_FLUSH();
959
+
960
+  // Make sure the pages following the first clean one are also clean
961
+  for (int page = curPage + 1; page < PagesPerGroup; page++) {
962
+    if (!ee_IsPageClean(curGroup * PagesPerGroup + page)) {
963
+      DEBUG_ECHO_START();
964
+      DEBUG_ECHOLNPAIR("EEPROM Page ", page, " not clean on active group ", curGroup);
965
+      DEBUG_FLUSH();
966
+      ee_Dump(curGroup * PagesPerGroup + page, getFlashStorage(curGroup * PagesPerGroup + page));
967
+      ee_PageErase(curGroup * PagesPerGroup + page);
968
+    }
969
+  }
970
+}
971
+
972
+/* PersistentStore -----------------------------------------------------------*/
973
+
974
+#include "../shared/eeprom_api.h"
975
+
976
+size_t PersistentStore::capacity()    { return E2END + 1; }
977
+bool PersistentStore::access_start()  { ee_Init();  return true; }
978
+bool PersistentStore::access_finish() { ee_Flush(); return true; }
979
+
48 980
 bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
49 981
   while (size--) {
50 982
     uint8_t * const p = (uint8_t * const)pos;
51 983
     uint8_t v = *value;
52 984
     // EEPROM has only ~100,000 write cycles,
53 985
     // so only write bytes that have changed!
54
-    if (v != eeprom_read_byte(p)) {
55
-      eeprom_write_byte(p, v);
986
+    if (v != ee_Read(uint32_t(p))) {
987
+      ee_Write(uint32_t(p), v);
56 988
       delay(2);
57
-      if (eeprom_read_byte(p) != v) {
989
+      if (ee_Read(uint32_t(p)) != v) {
58 990
         SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
59 991
         return true;
60 992
       }
@@ -68,7 +1000,7 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
68 1000
 
69 1001
 bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
70 1002
   do {
71
-    uint8_t c = eeprom_read_byte((uint8_t*)pos);
1003
+    uint8_t c = ee_Read(uint32_t(pos));
72 1004
     if (writing) *value = c;
73 1005
     crc16(crc, &c, 1);
74 1006
     pos++;
@@ -77,5 +1009,5 @@ bool PersistentStore::read_data(int &pos, uint8_t* value, size_t size, uint16_t
77 1009
   return false;
78 1010
 }
79 1011
 
80
-#endif // EEPROM_SETTINGS
1012
+#endif // FLASH_EEPROM_EMULATION
81 1013
 #endif // ARDUINO_ARCH_SAM

+ 0
- 1006
Marlin/src/HAL/DUE/eeprom_if_flash.cpp
File diff suppressed because it is too large
View File


+ 2
- 1
Marlin/src/HAL/LPC1768/eeprom_wired.cpp View File

@@ -30,6 +30,7 @@
30 30
  * with implementations supplied by the framework.
31 31
  */
32 32
 
33
+#include "../shared/eeprom_if.h"
33 34
 #include "../shared/eeprom_api.h"
34 35
 
35 36
 #ifndef EEPROM_SIZE
@@ -40,7 +41,7 @@ size_t PersistentStore::capacity()    { return EEPROM_SIZE; }
40 41
 bool PersistentStore::access_finish() { return true; }
41 42
 
42 43
 bool PersistentStore::access_start() {
43
-  TERN_(I2C_EEPROM, eeprom_init());
44
+  eeprom_init();
44 45
   return true;
45 46
 }
46 47
 

+ 1
- 0
Marlin/src/HAL/STM32/eeprom_wired.cpp View File

@@ -38,6 +38,7 @@ size_t PersistentStore::capacity()    { return E2END + 1; }
38 38
 bool PersistentStore::access_finish() { return true; }
39 39
 
40 40
 bool PersistentStore::access_start()  {
41
+  eeprom_init();
41 42
   return true;
42 43
 }
43 44
 

+ 17
- 22
Marlin/src/HAL/STM32_F4_F7/eeprom_flash.cpp View File

@@ -34,25 +34,7 @@
34 34
   //#define FLASH_FLAG_PGSERR FLASH_FLAG_ERSERR
35 35
 #endif
36 36
 
37
-void ee_init() {
38
-  static bool ee_initialized = false;
39
-  if (!ee_initialized) {
40
-    HAL_FLASH_Unlock();
41
-
42
-    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
43
-
44
-    /* EEPROM Init */
45
-    if (EE_Initialize() != EE_OK)
46
-      for (;;) HAL_Delay(1); // Spin forever until watchdog reset
47
-
48
-    HAL_FLASH_Lock();
49
-    ee_initialized = true;
50
-  }
51
-}
52
-
53 37
 void ee_write_byte(uint8_t *pos, unsigned char value) {
54
-  ee_init();
55
-
56 38
   HAL_FLASH_Unlock();
57 39
   __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
58 40
 
@@ -64,19 +46,32 @@ void ee_write_byte(uint8_t *pos, unsigned char value) {
64 46
 }
65 47
 
66 48
 uint8_t ee_read_byte(uint8_t *pos) {
67
-  ee_init();
68
-
69 49
   uint16_t data = 0xFF;
70 50
   const unsigned eeprom_address = (unsigned)pos;
71 51
   (void)EE_ReadVariable(eeprom_address, &data); // Data unchanged on error
72
-
73 52
   return uint8_t(data);
74 53
 }
75 54
 
76 55
 size_t PersistentStore::capacity()    { return E2END + 1; }
77
-bool PersistentStore::access_start()  { return true; }
78 56
 bool PersistentStore::access_finish() { return true; }
79 57
 
58
+bool PersistentStore::access_start()  {
59
+  static bool ee_initialized = false;
60
+  if (!ee_initialized) {
61
+    HAL_FLASH_Unlock();
62
+
63
+    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
64
+
65
+    /* EEPROM Init */
66
+    if (EE_Initialize() != EE_OK)
67
+      for (;;) HAL_Delay(1); // Spin forever until watchdog reset
68
+
69
+    HAL_FLASH_Lock();
70
+    ee_initialized = true;
71
+  }
72
+  return true;
73
+}
74
+
80 75
 bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
81 76
   while (size--) {
82 77
     uint8_t * const p = (uint8_t * const)pos;

+ 1
- 1
Marlin/src/HAL/STM32_F4_F7/eeprom_wired.cpp View File

@@ -35,10 +35,10 @@
35 35
 #include "../shared/eeprom_api.h"
36 36
 
37 37
 size_t PersistentStore::capacity()    { return E2END + 1; }
38
-bool PersistentStore::access_start()  { return true; }
39 38
 bool PersistentStore::access_finish() { return true; }
40 39
 
41 40
 bool PersistentStore::access_start()  {
41
+  eeprom_init();
42 42
   return true;
43 43
 }
44 44
 

+ 7
- 11
Marlin/src/HAL/shared/eeprom_if_i2c.cpp View File

@@ -27,21 +27,18 @@
27 27
 
28 28
 #include "../../inc/MarlinConfig.h"
29 29
 
30
-#if BOTH(USE_SHARED_EEPROM, I2C_EEPROM)
30
+#if ENABLED(I2C_EEPROM)
31 31
 
32
-#include "../HAL.h"
32
+#include "eeprom_if.h"
33 33
 #include <Wire.h>
34 34
 
35
-#include "eeprom_if.h"
35
+void eeprom_init() { Wire.begin(); }
36
+
37
+#if ENABLED(USE_SHARED_EEPROM)
36 38
 
37 39
 #ifndef EEPROM_WRITE_DELAY
38 40
   #define EEPROM_WRITE_DELAY    5
39 41
 #endif
40
-
41
-// ------------------------
42
-// Private Variables
43
-// ------------------------
44
-
45 42
 #ifndef EEPROM_DEVICE_ADDRESS
46 43
   #define EEPROM_DEVICE_ADDRESS  0x50
47 44
 #endif
@@ -52,8 +49,6 @@ static constexpr uint8_t eeprom_device_address = I2C_ADDRESS(EEPROM_DEVICE_ADDRE
52 49
 // Public functions
53 50
 // ------------------------
54 51
 
55
-void eeprom_init() { Wire.begin(); }
56
-
57 52
 void eeprom_write_byte(uint8_t *pos, unsigned char value) {
58 53
   const unsigned eeprom_address = (unsigned)pos;
59 54
 
@@ -79,4 +74,5 @@ uint8_t eeprom_read_byte(uint8_t *pos) {
79 74
   return Wire.available() ? Wire.read() : 0xFF;
80 75
 }
81 76
 
82
-#endif // USE_SHARED_EEPROM && I2C_EEPROM
77
+#endif // USE_SHARED_EEPROM
78
+#endif // I2C_EEPROM

+ 7
- 3
Marlin/src/HAL/shared/eeprom_if_spi.cpp View File

@@ -27,11 +27,14 @@
27 27
 
28 28
 #include "../../inc/MarlinConfig.h"
29 29
 
30
-#if BOTH(USE_SHARED_EEPROM, SPI_EEPROM)
30
+#if ENABLED(SPI_EEPROM)
31 31
 
32
-#include "../HAL.h"
33 32
 #include "eeprom_if.h"
34 33
 
34
+void eeprom_init() {}
35
+
36
+#if ENABLED(USE_SHARED_EEPROM)
37
+
35 38
 #define CMD_WREN  6   // WREN
36 39
 #define CMD_READ  2   // WRITE
37 40
 #define CMD_WRITE 2   // WRITE
@@ -80,4 +83,5 @@ void eeprom_write_byte(uint8_t* pos, uint8_t value) {
80 83
   delay(EEPROM_WRITE_DELAY);   // wait for page write to complete
81 84
 }
82 85
 
83
-#endif // USE_SHARED_EEPROM && I2C_EEPROM
86
+#endif // USE_SHARED_EEPROM
87
+#endif // I2C_EEPROM

Loading…
Cancel
Save