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

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