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 34KB

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