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.

EepromEmulation_Due.cpp 33KB

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