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.cpp 33KB

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