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

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