My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

eeprom_flash.cpp 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. /**
  2. * Marlin 3D Printer Firmware
  3. *
  4. * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  5. * Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
  6. * Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
  7. * Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21. *
  22. */
  23. #ifdef ARDUINO_ARCH_SAM
  24. #include "../../inc/MarlinConfig.h"
  25. #if ENABLED(FLASH_EEPROM_EMULATION)
  26. /* EEPROM emulation over flash with reduced wear
  27. *
  28. * We will use 2 contiguous groups of pages as main and alternate.
  29. * We want an structure that allows to read as fast as possible,
  30. * without the need of scanning the whole FLASH memory.
  31. *
  32. * FLASH bits default erased state is 1, and can be set to 0
  33. * on a per bit basis. To reset them to 1, a full page erase
  34. * is needed.
  35. *
  36. * Values are stored as differences that should be applied to a
  37. * completely erased EEPROM (filled with 0xFFs). We just encode
  38. * the starting address of the values to change, the length of
  39. * the block of new values, and the values themselves. All diffs
  40. * are accumulated into a RAM buffer, compacted into the least
  41. * amount of non overlapping diffs possible and sorted by starting
  42. * address before being saved into the next available page of FLASH
  43. * of the current group.
  44. * Once the current group is completely full, we compact it and save
  45. * it into the other group, then erase the current group and switch
  46. * to that new group and set it as current.
  47. *
  48. * The FLASH endurance is about 1/10 ... 1/100 of an EEPROM
  49. * endurance, but EEPROM endurance is specified per byte, not
  50. * per page. We can't emulate EE endurance with FLASH for all
  51. * bytes, but we can emulate endurance for a given percent of
  52. * bytes.
  53. */
  54. //#define EE_EMU_DEBUG
  55. #define EEPROMSize 4096
  56. #define PagesPerGroup 128
  57. #define GroupCount 2
  58. #define PageSize 256U
  59. /* Flash storage */
  60. typedef struct FLASH_SECTOR {
  61. uint8_t page[PageSize];
  62. } FLASH_SECTOR_T;
  63. #define PAGE_FILL \
  64. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  65. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  66. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  67. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  68. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  69. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  70. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  71. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  72. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  73. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  74. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  75. 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
  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. #define FLASH_INIT_FILL \
  81. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  82. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  83. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  84. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  85. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  86. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  87. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  88. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  89. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  90. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  91. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  92. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
  93. PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_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. /* This is the FLASH area used to emulate a 2Kbyte EEPROM -- We need this buffer aligned
  114. to a 256 byte boundary. */
  115. static const uint8_t flashStorage[PagesPerGroup * GroupCount * PageSize] __attribute__ ((aligned (PageSize))) = { FLASH_INIT_FILL };
  116. /* Get the address of an specific page */
  117. static const FLASH_SECTOR_T* getFlashStorage(int page) {
  118. return (const FLASH_SECTOR_T*)&flashStorage[page*PageSize];
  119. }
  120. static uint8_t buffer[256] = {0}, // The RAM buffer to accumulate writes
  121. curPage = 0, // Current FLASH page inside the group
  122. curGroup = 0xFF; // Current FLASH group
  123. #define DEBUG_OUT ENABLED(EE_EMU_DEBUG)
  124. #include "../../core/debug_out.h"
  125. static void ee_Dump(const int page, const void *data) {
  126. #ifdef EE_EMU_DEBUG
  127. const uint8_t *c = (const uint8_t*) data;
  128. char buffer[80];
  129. sprintf_P(buffer, PSTR("Page: %d (0x%04x)\n"), page, page);
  130. DEBUG_ECHO(buffer);
  131. char* p = &buffer[0];
  132. for (int i = 0; i< PageSize; ++i) {
  133. if ((i & 0xF) == 0) p += sprintf_P(p, PSTR("%04x] "), i);
  134. p += sprintf_P(p, PSTR(" %02x"), c[i]);
  135. if ((i & 0xF) == 0xF) {
  136. *p++ = '\n';
  137. *p = 0;
  138. DEBUG_ECHO(buffer);
  139. p = &buffer[0];
  140. }
  141. }
  142. #else
  143. UNUSED(page);
  144. UNUSED(data);
  145. #endif
  146. }
  147. /* Flash Writing Protection Key */
  148. #define FWP_KEY 0x5Au
  149. #if SAM4S_SERIES
  150. #define EEFC_FCR_FCMD(value) \
  151. ((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos)))
  152. #define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)
  153. #else
  154. #define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)
  155. #endif
  156. /**
  157. * Writes the contents of the specified page (no previous erase)
  158. * @param page (page #)
  159. * @param data (pointer to the data buffer)
  160. */
  161. __attribute__ ((long_call, section (".ramfunc")))
  162. static bool ee_PageWrite(uint16_t page, const void *data) {
  163. uint16_t i;
  164. uint32_t addrflash = uint32_t(getFlashStorage(page));
  165. // Read the flash contents
  166. uint32_t pageContents[PageSize>>2];
  167. memcpy(pageContents, (void*)addrflash, PageSize);
  168. // We ONLY want to toggle bits that have changed, and that have changed to 0.
  169. // SAM3X8E tends to destroy contiguous bits if reprogrammed without erasing, so
  170. // we try by all means to avoid this. That is why it says: "The Partial
  171. // Programming mode works only with 128-bit (or higher) boundaries. It cannot
  172. // be used with boundaries lower than 128 bits (8, 16 or 32-bit for example)."
  173. // All bits that did not change, set them to 1.
  174. for (i = 0; i <PageSize >> 2; i++)
  175. pageContents[i] = (((uint32_t*)data)[i]) | (~(pageContents[i] ^ ((uint32_t*)data)[i]));
  176. DEBUG_ECHO_MSG("EEPROM PageWrite ", page);
  177. DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash);
  178. DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0));
  179. DEBUG_FLUSH();
  180. // Get the page relative to the start of the EFC controller, and the EFC controller to use
  181. Efc *efc;
  182. uint16_t fpage;
  183. if (addrflash >= IFLASH1_ADDR) {
  184. efc = EFC1;
  185. fpage = (addrflash - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
  186. }
  187. else {
  188. efc = EFC0;
  189. fpage = (addrflash - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
  190. }
  191. // Get the page that must be unlocked, then locked
  192. uint16_t lpage = fpage & (~((IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) - 1));
  193. // Disable all interrupts
  194. __disable_irq();
  195. // Get the FLASH wait states
  196. uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
  197. // Set wait states to 6 (SAM errata)
  198. efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
  199. // Unlock the flash page
  200. uint32_t status;
  201. efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(lpage) | EEFC_FCR_FCMD(EFC_FCMD_CLB);
  202. while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
  203. // force compiler to not optimize this -- NOPs don't work!
  204. __asm__ __volatile__("");
  205. };
  206. if ((status & EEFC_ERROR_FLAGS) != 0) {
  207. // Restore original wait states
  208. efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
  209. // Reenable interrupts
  210. __enable_irq();
  211. DEBUG_ECHO_MSG("EEPROM Unlock failure for page ", page);
  212. return false;
  213. }
  214. // Write page and lock: Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
  215. const uint32_t * aligned_src = (const uint32_t *) &pageContents[0]; /*data;*/
  216. uint32_t * p_aligned_dest = (uint32_t *) addrflash;
  217. for (i = 0; i < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++i) {
  218. *p_aligned_dest++ = *aligned_src++;
  219. }
  220. efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(fpage) | EEFC_FCR_FCMD(EFC_FCMD_WPL);
  221. while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
  222. // force compiler to not optimize this -- NOPs don't work!
  223. __asm__ __volatile__("");
  224. };
  225. if ((status & EEFC_ERROR_FLAGS) != 0) {
  226. // Restore original wait states
  227. efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
  228. // Reenable interrupts
  229. __enable_irq();
  230. DEBUG_ECHO_MSG("EEPROM Write failure for page ", page);
  231. return false;
  232. }
  233. // Restore original wait states
  234. efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
  235. // Reenable interrupts
  236. __enable_irq();
  237. // Compare contents
  238. if (memcmp(getFlashStorage(page),data,PageSize)) {
  239. #ifdef EE_EMU_DEBUG
  240. DEBUG_ECHO_MSG("EEPROM Verify Write failure for page ", page);
  241. ee_Dump( page, (uint32_t *)addrflash);
  242. ee_Dump(-page, data);
  243. // Calculate count of changed bits
  244. uint32_t *p1 = (uint32_t*)addrflash;
  245. uint32_t *p2 = (uint32_t*)data;
  246. int count = 0;
  247. for (i =0; i<PageSize >> 2; i++) {
  248. if (p1[i] != p2[i]) {
  249. uint32_t delta = p1[i] ^ p2[i];
  250. while (delta) {
  251. if ((delta&1) != 0)
  252. count++;
  253. delta >>= 1;
  254. }
  255. }
  256. }
  257. DEBUG_ECHOLNPGM("--> Differing bits: ", count);
  258. #endif
  259. return false;
  260. }
  261. return true;
  262. }
  263. /**
  264. * Erases the contents of the specified page
  265. * @param page (page #)
  266. */
  267. __attribute__ ((long_call, section (".ramfunc")))
  268. static bool ee_PageErase(uint16_t page) {
  269. uint16_t i;
  270. uint32_t addrflash = uint32_t(getFlashStorage(page));
  271. DEBUG_ECHO_MSG("EEPROM PageErase ", page);
  272. DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash);
  273. DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0));
  274. DEBUG_FLUSH();
  275. // Get the page relative to the start of the EFC controller, and the EFC controller to use
  276. Efc *efc;
  277. uint16_t fpage;
  278. if (addrflash >= IFLASH1_ADDR) {
  279. efc = EFC1;
  280. fpage = (addrflash - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
  281. }
  282. else {
  283. efc = EFC0;
  284. fpage = (addrflash - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
  285. }
  286. // Get the page that must be unlocked, then locked
  287. uint16_t lpage = fpage & (~((IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) - 1));
  288. // Disable all interrupts
  289. __disable_irq();
  290. // Get the FLASH wait states
  291. uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
  292. // Set wait states to 6 (SAM errata)
  293. efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
  294. // Unlock the flash page
  295. uint32_t status;
  296. efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(lpage) | EEFC_FCR_FCMD(EFC_FCMD_CLB);
  297. while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
  298. // force compiler to not optimize this -- NOPs don't work!
  299. __asm__ __volatile__("");
  300. };
  301. if ((status & EEFC_ERROR_FLAGS) != 0) {
  302. // Restore original wait states
  303. efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
  304. // Reenable interrupts
  305. __enable_irq();
  306. DEBUG_ECHO_MSG("EEPROM Unlock failure for page ",page);
  307. return false;
  308. }
  309. // Erase Write page and lock: Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
  310. uint32_t * p_aligned_dest = (uint32_t *) addrflash;
  311. for (i = 0; i < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++i) {
  312. *p_aligned_dest++ = 0xFFFFFFFF;
  313. }
  314. efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(fpage) | EEFC_FCR_FCMD(EFC_FCMD_EWPL);
  315. while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
  316. // force compiler to not optimize this -- NOPs don't work!
  317. __asm__ __volatile__("");
  318. };
  319. if ((status & EEFC_ERROR_FLAGS) != 0) {
  320. // Restore original wait states
  321. efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
  322. // Reenable interrupts
  323. __enable_irq();
  324. DEBUG_ECHO_MSG("EEPROM Erase failure for page ",page);
  325. return false;
  326. }
  327. // Restore original wait states
  328. efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
  329. // Reenable interrupts
  330. __enable_irq();
  331. // Check erase
  332. uint32_t * aligned_src = (uint32_t *) addrflash;
  333. for (i = 0; i < PageSize >> 2; i++) {
  334. if (*aligned_src++ != 0xFFFFFFFF) {
  335. DEBUG_ECHO_MSG("EEPROM Verify Erase failure for page ",page);
  336. ee_Dump(page, (uint32_t *)addrflash);
  337. return false;
  338. }
  339. }
  340. return true;
  341. }
  342. static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer=false) {
  343. uint32_t baddr;
  344. uint32_t blen;
  345. // If we were requested an address outside of the emulated range, fail now
  346. if (address >= EEPROMSize)
  347. return false;
  348. // Check that the value is not contained in the RAM buffer
  349. if (!excludeRAMBuffer) {
  350. uint16_t i = 0;
  351. while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
  352. // Get the address of the block
  353. baddr = buffer[i] | (buffer[i + 1] << 8);
  354. // Get the length of the block
  355. blen = buffer[i + 2];
  356. // If we reach the end of the list, break loop
  357. if (blen == 0xFF)
  358. break;
  359. // Check if data is contained in this block
  360. if (address >= baddr &&
  361. address < (baddr + blen)) {
  362. // Yes, it is contained. Return it!
  363. return buffer[i + 3 + address - baddr];
  364. }
  365. // As blocks are always sorted, if the starting address of this block is higher
  366. // than the address we are looking for, break loop now - We wont find the value
  367. // associated to the address
  368. if (baddr > address)
  369. break;
  370. // Jump to the next block
  371. i += 3 + blen;
  372. }
  373. }
  374. // It is NOT on the RAM buffer. It could be stored in FLASH. We are
  375. // ensured on a given FLASH page, address contents are never repeated
  376. // but on different pages, there is no such warranty, so we must go
  377. // backwards from the last written FLASH page to the first one.
  378. for (int page = curPage - 1; page >= 0; --page) {
  379. // Get a pointer to the flash page
  380. uint8_t *pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
  381. uint16_t i = 0;
  382. while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
  383. // Get the address of the block
  384. baddr = pflash[i] | (pflash[i + 1] << 8);
  385. // Get the length of the block
  386. blen = pflash[i + 2];
  387. // If we reach the end of the list, break loop
  388. if (blen == 0xFF)
  389. break;
  390. // Check if data is contained in this block
  391. if (address >= baddr && address < (baddr + blen))
  392. return pflash[i + 3 + address - baddr]; // Yes, it is contained. Return it!
  393. // As blocks are always sorted, if the starting address of this block is higher
  394. // than the address we are looking for, break loop now - We wont find the value
  395. // associated to the address
  396. if (baddr > address) break;
  397. // Jump to the next block
  398. i += 3 + blen;
  399. }
  400. }
  401. // If reached here, value is not stored, so return its default value
  402. return 0xFF;
  403. }
  404. static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer=false) {
  405. uint32_t baddr,
  406. blen,
  407. nextAddr = 0xFFFF,
  408. nextRange = 0;
  409. // Check that the value is not contained in the RAM buffer
  410. if (!excludeRAMBuffer) {
  411. uint16_t i = 0;
  412. while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
  413. // Get the address of the block
  414. baddr = buffer[i] | (buffer[i + 1] << 8);
  415. // Get the length of the block
  416. blen = buffer[i + 2];
  417. // If we reach the end of the list, break loop
  418. if (blen == 0xFF) break;
  419. // Check if address and address + 1 is contained in this block
  420. if (address >= baddr && address < (baddr + blen))
  421. return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
  422. // Otherwise, check if we can use it as a limit
  423. if (baddr > address && baddr < nextAddr) {
  424. nextAddr = baddr;
  425. nextRange = blen;
  426. }
  427. // As blocks are always sorted, if the starting address of this block is higher
  428. // than the address we are looking for, break loop now - We wont find the value
  429. // associated to the address
  430. if (baddr > address) break;
  431. // Jump to the next block
  432. i += 3 + blen;
  433. }
  434. }
  435. // It is NOT on the RAM buffer. It could be stored in FLASH. We are
  436. // ensured on a given FLASH page, address contents are never repeated
  437. // but on different pages, there is no such warranty, so we must go
  438. // backwards from the last written FLASH page to the first one.
  439. for (int page = curPage - 1; page >= 0; --page) {
  440. // Get a pointer to the flash page
  441. uint8_t *pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
  442. uint16_t i = 0;
  443. while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
  444. // Get the address of the block
  445. baddr = pflash[i] | (pflash[i + 1] << 8);
  446. // Get the length of the block
  447. blen = pflash[i + 2];
  448. // If we reach the end of the list, break loop
  449. if (blen == 0xFF) break;
  450. // Check if data is contained in this block
  451. if (address >= baddr && address < (baddr + blen))
  452. return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
  453. // Otherwise, check if we can use it as a limit
  454. if (baddr > address && baddr < nextAddr) {
  455. nextAddr = baddr;
  456. nextRange = blen;
  457. }
  458. // As blocks are always sorted, if the starting address of this block is higher
  459. // than the address we are looking for, break loop now - We wont find the value
  460. // associated to the address
  461. if (baddr > address) break;
  462. // Jump to the next block
  463. i += 3 + blen;
  464. }
  465. }
  466. // If reached here, we will return the next valid address
  467. return nextAddr | (nextRange << 16);
  468. }
  469. static bool ee_IsPageClean(int page) {
  470. uint32_t *pflash = (uint32_t*) getFlashStorage(page);
  471. for (uint16_t i = 0; i < (PageSize >> 2); ++i)
  472. if (*pflash++ != 0xFFFFFFFF) return false;
  473. return true;
  474. }
  475. static bool ee_Flush(uint32_t overrideAddress = 0xFFFFFFFF, uint8_t overrideData=0xFF) {
  476. // Check if RAM buffer has something to be written
  477. bool isEmpty = true;
  478. uint32_t *p = (uint32_t*) &buffer[0];
  479. for (uint16_t j = 0; j < (PageSize >> 2); j++) {
  480. if (*p++ != 0xFFFFFFFF) {
  481. isEmpty = false;
  482. break;
  483. }
  484. }
  485. // If something has to be written, do so!
  486. if (!isEmpty) {
  487. // Write the current ram buffer into FLASH
  488. ee_PageWrite(curPage + curGroup * PagesPerGroup, buffer);
  489. // Clear the RAM buffer
  490. memset(buffer, 0xFF, sizeof(buffer));
  491. // Increment the page to use the next time
  492. ++curPage;
  493. }
  494. // Did we reach the maximum count of available pages per group for storage ?
  495. if (curPage < PagesPerGroup) {
  496. // Do we have an override address ?
  497. if (overrideAddress < EEPROMSize) {
  498. // Yes, just store the value into the RAM buffer
  499. buffer[0] = overrideAddress & 0xFF;
  500. buffer[0 + 1] = (overrideAddress >> 8) & 0xFF;
  501. buffer[0 + 2] = 1;
  502. buffer[0 + 3] = overrideData;
  503. }
  504. // Done!
  505. return true;
  506. }
  507. // We have no space left on the current group - We must compact the values
  508. uint16_t i = 0;
  509. // Compute the next group to use
  510. int curwPage = 0, curwGroup = curGroup + 1;
  511. if (curwGroup >= GroupCount) curwGroup = 0;
  512. uint32_t rdAddr = 0;
  513. do {
  514. // Get the next valid range
  515. uint32_t addrRange = ee_GetAddrRange(rdAddr, true);
  516. // Make sure not to skip the override address, if specified
  517. int rdRange;
  518. if (overrideAddress < EEPROMSize &&
  519. rdAddr <= overrideAddress &&
  520. (addrRange & 0xFFFF) > overrideAddress) {
  521. rdAddr = overrideAddress;
  522. rdRange = 1;
  523. }
  524. else {
  525. rdAddr = addrRange & 0xFFFF;
  526. rdRange = addrRange >> 16;
  527. }
  528. // If no range, break loop
  529. if (rdRange == 0)
  530. break;
  531. do {
  532. // Get the value
  533. uint8_t rdValue = overrideAddress == rdAddr ? overrideData : ee_Read(rdAddr, true);
  534. // Do not bother storing default values
  535. if (rdValue != 0xFF) {
  536. // If we have room, add it to the buffer
  537. if (buffer[i + 2] == 0xFF) {
  538. // Uninitialized buffer, just add it!
  539. buffer[i] = rdAddr & 0xFF;
  540. buffer[i + 1] = (rdAddr >> 8) & 0xFF;
  541. buffer[i + 2] = 1;
  542. buffer[i + 3] = rdValue;
  543. }
  544. else {
  545. // Buffer already has contents. Check if we can extend it
  546. // Get the address of the block
  547. uint32_t baddr = buffer[i] | (buffer[i + 1] << 8);
  548. // Get the length of the block
  549. uint32_t blen = buffer[i + 2];
  550. // Can we expand it ?
  551. if (rdAddr == (baddr + blen) &&
  552. i < (PageSize - 4) && /* This block has a chance to contain data AND */
  553. buffer[i + 2] < (PageSize - i - 3)) {/* There is room for this block to be expanded */
  554. // Yes, do it
  555. ++buffer[i + 2];
  556. // And store the value
  557. buffer[i + 3 + rdAddr - baddr] = rdValue;
  558. }
  559. else {
  560. // No, we can't expand it - Skip the existing block
  561. i += 3 + blen;
  562. // Can we create a new slot ?
  563. if (i > (PageSize - 4)) {
  564. // Not enough space - Write the current buffer to FLASH
  565. ee_PageWrite(curwPage + curwGroup * PagesPerGroup, buffer);
  566. // Advance write page (as we are compacting, should never overflow!)
  567. ++curwPage;
  568. // Clear RAM buffer
  569. memset(buffer, 0xFF, sizeof(buffer));
  570. // Start fresh */
  571. i = 0;
  572. }
  573. // Enough space, add the new block
  574. buffer[i] = rdAddr & 0xFF;
  575. buffer[i + 1] = (rdAddr >> 8) & 0xFF;
  576. buffer[i + 2] = 1;
  577. buffer[i + 3] = rdValue;
  578. }
  579. }
  580. }
  581. // Go to the next address
  582. ++rdAddr;
  583. // Repeat for bytes of this range
  584. } while (--rdRange);
  585. // Repeat until we run out of ranges
  586. } while (rdAddr < EEPROMSize);
  587. // We must erase the previous group, in preparation for the next swap
  588. for (int page = 0; page < curPage; page++) {
  589. ee_PageErase(page + curGroup * PagesPerGroup);
  590. }
  591. // Finally, Now the active group is the created new group
  592. curGroup = curwGroup;
  593. curPage = curwPage;
  594. // Done!
  595. return true;
  596. }
  597. static bool ee_Write(uint32_t address, uint8_t data) {
  598. // If we were requested an address outside of the emulated range, fail now
  599. if (address >= EEPROMSize) return false;
  600. // Lets check if we have a block with that data previously defined. Block
  601. // start addresses are always sorted in ascending order
  602. uint16_t i = 0;
  603. while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
  604. // Get the address of the block
  605. uint32_t baddr = buffer[i] | (buffer[i + 1] << 8);
  606. // Get the length of the block
  607. uint32_t blen = buffer[i + 2];
  608. // If we reach the end of the list, break loop
  609. if (blen == 0xFF)
  610. break;
  611. // Check if data is contained in this block
  612. if (address >= baddr &&
  613. address < (baddr + blen)) {
  614. // Yes, it is contained. Just modify it
  615. buffer[i + 3 + address - baddr] = data;
  616. // Done!
  617. return true;
  618. }
  619. // Maybe we could add it to the front or to the back
  620. // of this block ?
  621. if ((address + 1) == baddr || address == (baddr + blen)) {
  622. // Potentially, it could be done. But we must ensure there is room
  623. // so we can expand the block. Lets find how much free space remains
  624. uint32_t iend = i;
  625. do {
  626. uint32_t ln = buffer[iend + 2];
  627. if (ln == 0xFF) break;
  628. iend += 3 + ln;
  629. } while (iend <= (PageSize - 4)); /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
  630. // Here, inxt points to the first free address in the buffer. Do we have room ?
  631. if (iend < PageSize) {
  632. // Yes, at least a byte is free - We can expand the block
  633. // Do we have to insert at the beginning ?
  634. if ((address + 1) == baddr) {
  635. // Insert at the beginning
  636. // Make room at the beginning for our byte
  637. memmove(&buffer[i + 3 + 1], &buffer[i + 3], iend - i - 3);
  638. // Adjust the header and store the data
  639. buffer[i] = address & 0xFF;
  640. buffer[i + 1] = (address >> 8) & 0xFF;
  641. buffer[i + 2]++;
  642. buffer[i + 3] = data;
  643. }
  644. else {
  645. // Insert at the end - There is a very interesting thing that could happen here:
  646. // Maybe we could coalesce the next block with this block. Let's try to do it!
  647. uint16_t inext = i + 3 + blen;
  648. if (inext <= (PageSize - 4) &&
  649. (buffer[inext] | uint16_t(buffer[inext + 1] << 8)) == (baddr + blen + 1)) {
  650. // YES! ... we can coalesce blocks! . Do it!
  651. // Adjust this block header to include the next one
  652. buffer[i + 2] += buffer[inext + 2] + 1;
  653. // Store data at the right place
  654. buffer[i + 3 + blen] = data;
  655. // Remove the next block header and append its data
  656. memmove(&buffer[inext + 1], &buffer[inext + 3], iend - inext - 3);
  657. // Finally, as we have saved 2 bytes at the end, make sure to clean them
  658. buffer[iend - 2] = 0xFF;
  659. buffer[iend - 1] = 0xFF;
  660. }
  661. else {
  662. // NO ... No coalescing possible yet
  663. // Make room at the end for our byte
  664. memmove(&buffer[i + 3 + blen + 1], &buffer[i + 3 + blen], iend - i - 3 - blen);
  665. // And add the data to the block
  666. buffer[i + 2]++;
  667. buffer[i + 3 + blen] = data;
  668. }
  669. }
  670. // Done!
  671. return true;
  672. }
  673. }
  674. // As blocks are always sorted, if the starting address of this block is higher
  675. // than the address we are looking for, break loop now - We wont find the value
  676. // associated to the address
  677. if (baddr > address) break;
  678. // Jump to the next block
  679. i += 3 + blen;
  680. }
  681. // Value is not stored AND we can't expand previous block to contain it. We must create a new block
  682. // First, lets find how much free space remains
  683. uint32_t iend = i;
  684. while (iend <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
  685. uint32_t ln = buffer[iend + 2];
  686. if (ln == 0xFF) break;
  687. iend += 3 + ln;
  688. }
  689. // If there is room for a new block, insert it at the proper place
  690. if (iend <= (PageSize - 4)) {
  691. // We have room to create a new block. Do so --- But add
  692. // the block at the proper position, sorted by starting
  693. // address, so it will be possible to compact it with other blocks.
  694. // Make space
  695. memmove(&buffer[i + 4], &buffer[i], iend - i);
  696. // And add the block
  697. buffer[i] = address & 0xFF;
  698. buffer[i + 1] = (address >> 8) & 0xFF;
  699. buffer[i + 2] = 1;
  700. buffer[i + 3] = data;
  701. // Done!
  702. return true;
  703. }
  704. // Not enough room to store this information on this FLASH page - Perform a
  705. // flush and override the address with the specified contents
  706. return ee_Flush(address, data);
  707. }
  708. static void ee_Init() {
  709. // Just init once!
  710. if (curGroup != 0xFF) return;
  711. // Clean up the SRAM buffer
  712. memset(buffer, 0xFF, sizeof(buffer));
  713. // Now, we must find out the group where settings are stored
  714. for (curGroup = 0; curGroup < GroupCount; curGroup++)
  715. if (!ee_IsPageClean(curGroup * PagesPerGroup)) break;
  716. // If all groups seem to be used, default to first group
  717. if (curGroup >= GroupCount) curGroup = 0;
  718. DEBUG_ECHO_MSG("EEPROM Current Group: ",curGroup);
  719. DEBUG_FLUSH();
  720. // Now, validate that all the other group pages are empty
  721. for (int grp = 0; grp < GroupCount; grp++) {
  722. if (grp == curGroup) continue;
  723. for (int page = 0; page < PagesPerGroup; page++) {
  724. if (!ee_IsPageClean(grp * PagesPerGroup + page)) {
  725. DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on group ", grp);
  726. DEBUG_FLUSH();
  727. ee_PageErase(grp * PagesPerGroup + page);
  728. }
  729. }
  730. }
  731. // Finally, for the active group, determine the first unused page
  732. // and also validate that all the other ones are clean
  733. for (curPage = 0; curPage < PagesPerGroup; curPage++) {
  734. if (ee_IsPageClean(curGroup * PagesPerGroup + curPage)) {
  735. ee_Dump(curGroup * PagesPerGroup + curPage, getFlashStorage(curGroup * PagesPerGroup + curPage));
  736. break;
  737. }
  738. }
  739. DEBUG_ECHO_MSG("EEPROM Active page: ", curPage);
  740. DEBUG_FLUSH();
  741. // Make sure the pages following the first clean one are also clean
  742. for (int page = curPage + 1; page < PagesPerGroup; page++) {
  743. if (!ee_IsPageClean(curGroup * PagesPerGroup + page)) {
  744. DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on active group ", curGroup);
  745. DEBUG_FLUSH();
  746. ee_Dump(curGroup * PagesPerGroup + page, getFlashStorage(curGroup * PagesPerGroup + page));
  747. ee_PageErase(curGroup * PagesPerGroup + page);
  748. }
  749. }
  750. }
  751. /* PersistentStore -----------------------------------------------------------*/
  752. #include "../shared/eeprom_api.h"
  753. #ifndef MARLIN_EEPROM_SIZE
  754. #define MARLIN_EEPROM_SIZE 0x1000 // 4KB
  755. #endif
  756. size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
  757. bool PersistentStore::access_start() { ee_Init(); return true; }
  758. bool PersistentStore::access_finish() { ee_Flush(); return true; }
  759. bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
  760. uint16_t written = 0;
  761. while (size--) {
  762. uint8_t * const p = (uint8_t * const)pos;
  763. uint8_t v = *value;
  764. if (v != ee_Read(uint32_t(p))) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
  765. ee_Write(uint32_t(p), v);
  766. if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
  767. if (ee_Read(uint32_t(p)) != v) {
  768. SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
  769. return true;
  770. }
  771. }
  772. crc16(crc, &v, 1);
  773. pos++;
  774. value++;
  775. }
  776. return false;
  777. }
  778. bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
  779. do {
  780. uint8_t c = ee_Read(uint32_t(pos));
  781. if (writing) *value = c;
  782. crc16(crc, &c, 1);
  783. pos++;
  784. value++;
  785. } while (--size);
  786. return false;
  787. }
  788. #endif // FLASH_EEPROM_EMULATION
  789. #endif // ARDUINO_ARCH_SAM