Teensy 4.1 core updated for C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

eeprom.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2013 PJRC.COM, LLC.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * 1. The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * 2. If the Software is incorporated into a build system that allows
  17. * selection among a list of target devices, then similar target
  18. * devices manufactured by PJRC.COM must be included in the list of
  19. * target devices and selectable in the same manner.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  25. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  26. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  28. * SOFTWARE.
  29. */
  30. #include "kinetis.h"
  31. #include <stdint.h>
  32. //#include "HardwareSerial.h"
  33. #if defined(KINETISK)
  34. // The EEPROM is really RAM with a hardware-based backup system to
  35. // flash memory. Selecting a smaller size EEPROM allows more wear
  36. // leveling, for higher write endurance. If you edit this file,
  37. // set this to the smallest size your application can use. Also,
  38. // due to Freescale's implementation, writing 16 or 32 bit words
  39. // (aligned to 2 or 4 byte boundaries) has twice the endurance
  40. // compared to writing 8 bit bytes.
  41. //
  42. #define EEPROM_SIZE 2048
  43. // Writing unaligned 16 or 32 bit data is handled automatically when
  44. // this is defined, but at a cost of extra code size. Without this,
  45. // any unaligned write will cause a hard fault exception! If you're
  46. // absolutely sure all 16 and 32 bit writes will be aligned, you can
  47. // remove the extra unnecessary code.
  48. //
  49. #define HANDLE_UNALIGNED_WRITES
  50. // Minimum EEPROM Endurance
  51. // ------------------------
  52. #if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
  53. #define EEESIZE 0x33
  54. #elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
  55. #define EEESIZE 0x34
  56. #elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
  57. #define EEESIZE 0x35
  58. #elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
  59. #define EEESIZE 0x36
  60. #elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
  61. #define EEESIZE 0x37
  62. #elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
  63. #define EEESIZE 0x38
  64. #elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
  65. #define EEESIZE 0x39
  66. #endif
  67. void eeprom_initialize(void)
  68. {
  69. uint32_t count=0;
  70. uint16_t do_flash_cmd[] = {
  71. 0xf06f, 0x037f, 0x7003, 0x7803,
  72. 0xf013, 0x0f80, 0xd0fb, 0x4770};
  73. uint8_t status;
  74. if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) {
  75. // FlexRAM is configured as traditional RAM
  76. // We need to reconfigure for EEPROM usage
  77. FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command
  78. FTFL_FCCOB4 = EEESIZE; // EEPROM Size
  79. FTFL_FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
  80. __disable_irq();
  81. // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
  82. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);
  83. __enable_irq();
  84. status = FTFL_FSTAT;
  85. if (status & 0x70) {
  86. FTFL_FSTAT = (status & 0x70);
  87. return; // error
  88. }
  89. }
  90. // wait for eeprom to become ready (is this really necessary?)
  91. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  92. if (++count > 20000) break;
  93. }
  94. }
  95. #define FlexRAM ((uint8_t *)0x14000000)
  96. uint8_t eeprom_read_byte(const uint8_t *addr)
  97. {
  98. uint32_t offset = (uint32_t)addr;
  99. if (offset >= EEPROM_SIZE) return 0;
  100. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  101. return FlexRAM[offset];
  102. }
  103. uint16_t eeprom_read_word(const uint16_t *addr)
  104. {
  105. uint32_t offset = (uint32_t)addr;
  106. if (offset >= EEPROM_SIZE-1) return 0;
  107. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  108. return *(uint16_t *)(&FlexRAM[offset]);
  109. }
  110. uint32_t eeprom_read_dword(const uint32_t *addr)
  111. {
  112. uint32_t offset = (uint32_t)addr;
  113. if (offset >= EEPROM_SIZE-3) return 0;
  114. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  115. return *(uint32_t *)(&FlexRAM[offset]);
  116. }
  117. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  118. {
  119. uint32_t offset = (uint32_t)addr;
  120. uint8_t *dest = (uint8_t *)buf;
  121. uint32_t end = offset + len;
  122. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  123. if (end > EEPROM_SIZE) end = EEPROM_SIZE;
  124. while (offset < end) {
  125. *dest++ = FlexRAM[offset++];
  126. }
  127. }
  128. int eeprom_is_ready(void)
  129. {
  130. return (FTFL_FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
  131. }
  132. static void flexram_wait(void)
  133. {
  134. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  135. // TODO: timeout
  136. }
  137. }
  138. void eeprom_write_byte(uint8_t *addr, uint8_t value)
  139. {
  140. uint32_t offset = (uint32_t)addr;
  141. if (offset >= EEPROM_SIZE) return;
  142. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  143. if (FlexRAM[offset] != value) {
  144. FlexRAM[offset] = value;
  145. flexram_wait();
  146. }
  147. }
  148. void eeprom_write_word(uint16_t *addr, uint16_t value)
  149. {
  150. uint32_t offset = (uint32_t)addr;
  151. if (offset >= EEPROM_SIZE-1) return;
  152. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  153. #ifdef HANDLE_UNALIGNED_WRITES
  154. if ((offset & 1) == 0) {
  155. #endif
  156. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  157. *(uint16_t *)(&FlexRAM[offset]) = value;
  158. flexram_wait();
  159. }
  160. #ifdef HANDLE_UNALIGNED_WRITES
  161. } else {
  162. if (FlexRAM[offset] != value) {
  163. FlexRAM[offset] = value;
  164. flexram_wait();
  165. }
  166. if (FlexRAM[offset + 1] != (value >> 8)) {
  167. FlexRAM[offset + 1] = value >> 8;
  168. flexram_wait();
  169. }
  170. }
  171. #endif
  172. }
  173. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  174. {
  175. uint32_t offset = (uint32_t)addr;
  176. if (offset >= EEPROM_SIZE-3) return;
  177. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  178. #ifdef HANDLE_UNALIGNED_WRITES
  179. switch (offset & 3) {
  180. case 0:
  181. #endif
  182. if (*(uint32_t *)(&FlexRAM[offset]) != value) {
  183. *(uint32_t *)(&FlexRAM[offset]) = value;
  184. flexram_wait();
  185. }
  186. return;
  187. #ifdef HANDLE_UNALIGNED_WRITES
  188. case 2:
  189. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  190. *(uint16_t *)(&FlexRAM[offset]) = value;
  191. flexram_wait();
  192. }
  193. if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
  194. *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
  195. flexram_wait();
  196. }
  197. return;
  198. default:
  199. if (FlexRAM[offset] != value) {
  200. FlexRAM[offset] = value;
  201. flexram_wait();
  202. }
  203. if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
  204. *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
  205. flexram_wait();
  206. }
  207. if (FlexRAM[offset + 3] != (value >> 24)) {
  208. FlexRAM[offset + 3] = value >> 24;
  209. flexram_wait();
  210. }
  211. }
  212. #endif
  213. }
  214. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  215. {
  216. uint32_t offset = (uint32_t)addr;
  217. const uint8_t *src = (const uint8_t *)buf;
  218. if (offset >= EEPROM_SIZE) return;
  219. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  220. if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
  221. if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
  222. while (len > 0) {
  223. uint32_t lsb = offset & 3;
  224. if (lsb == 0 && len >= 4) {
  225. // write aligned 32 bits
  226. uint32_t val32;
  227. val32 = *src++;
  228. val32 |= (*src++ << 8);
  229. val32 |= (*src++ << 16);
  230. val32 |= (*src++ << 24);
  231. if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
  232. *(uint32_t *)(&FlexRAM[offset]) = val32;
  233. flexram_wait();
  234. }
  235. offset += 4;
  236. len -= 4;
  237. } else if ((lsb == 0 || lsb == 2) && len >= 2) {
  238. // write aligned 16 bits
  239. uint16_t val16;
  240. val16 = *src++;
  241. val16 |= (*src++ << 8);
  242. if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
  243. *(uint16_t *)(&FlexRAM[offset]) = val16;
  244. flexram_wait();
  245. }
  246. offset += 2;
  247. len -= 2;
  248. } else {
  249. // write 8 bits
  250. uint8_t val8 = *src++;
  251. if (FlexRAM[offset] != val8) {
  252. FlexRAM[offset] = val8;
  253. flexram_wait();
  254. }
  255. offset++;
  256. len--;
  257. }
  258. }
  259. }
  260. /*
  261. void do_flash_cmd(volatile uint8_t *fstat)
  262. {
  263. *fstat = 0x80;
  264. while ((*fstat & 0x80) == 0) ; // wait
  265. }
  266. 00000000 <do_flash_cmd>:
  267. 0: f06f 037f mvn.w r3, #127 ; 0x7f
  268. 4: 7003 strb r3, [r0, #0]
  269. 6: 7803 ldrb r3, [r0, #0]
  270. 8: f013 0f80 tst.w r3, #128 ; 0x80
  271. c: d0fb beq.n 6 <do_flash_cmd+0x6>
  272. e: 4770 bx lr
  273. */
  274. #elif defined(KINETISL)
  275. #define EEPROM_SIZE 128
  276. #define FLASH_BEGIN (uint16_t *)63488
  277. #define FLASH_END (uint16_t *)65536
  278. static uint16_t flashend = 0;
  279. void eeprom_initialize(void)
  280. {
  281. const uint16_t *p = FLASH_BEGIN;
  282. do {
  283. if (*p++ == 0xFFFF) {
  284. flashend = (uint32_t)(p - 2);
  285. return;
  286. }
  287. } while (p < FLASH_END);
  288. flashend = (uint32_t)(FLASH_END - 1);
  289. }
  290. uint8_t eeprom_read_byte(const uint8_t *addr)
  291. {
  292. uint32_t offset = (uint32_t)addr;
  293. const uint16_t *p = FLASH_BEGIN;
  294. const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
  295. uint16_t val;
  296. uint8_t data=0xFF;
  297. if (!end) {
  298. eeprom_initialize();
  299. end = (const uint16_t *)((uint32_t)flashend);
  300. }
  301. if (offset < EEPROM_SIZE) {
  302. while (p <= end) {
  303. val = *p++;
  304. if ((val & 255) == offset) data = val >> 8;
  305. }
  306. }
  307. return data;
  308. }
  309. static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
  310. {
  311. // with great power comes great responsibility....
  312. uint32_t stat;
  313. *(uint32_t *)&FTFL_FCCOB3 = 0x06000000 | (addr & 0x00FFFFFC);
  314. *(uint32_t *)&FTFL_FCCOB7 = data;
  315. __disable_irq();
  316. (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&FTFL_FSTAT);
  317. __enable_irq();
  318. stat = FTFL_FSTAT & 0x70;
  319. if (stat) {
  320. FTFL_FSTAT = stat;
  321. }
  322. MCM_PLACR |= MCM_PLACR_CFCC;
  323. }
  324. void eeprom_write_byte(uint8_t *addr, uint8_t data)
  325. {
  326. uint32_t offset = (uint32_t)addr;
  327. const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
  328. uint32_t i, val, flashaddr;
  329. uint16_t do_flash_cmd[] = {
  330. 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
  331. uint8_t buf[EEPROM_SIZE];
  332. if (offset >= EEPROM_SIZE) return;
  333. if (!end) {
  334. eeprom_initialize();
  335. end = (const uint16_t *)((uint32_t)flashend);
  336. }
  337. if (++end < FLASH_END) {
  338. val = (data << 8) | offset;
  339. flashaddr = (uint32_t)end;
  340. flashend = flashaddr;
  341. if ((flashaddr & 2) == 0) {
  342. val |= 0xFFFF0000;
  343. } else {
  344. val <<= 16;
  345. val |= 0x0000FFFF;
  346. }
  347. flash_write(do_flash_cmd, flashaddr, val);
  348. } else {
  349. for (i=0; i < EEPROM_SIZE; i++) {
  350. buf[i] = 0xFF;
  351. }
  352. for (p = FLASH_BEGIN; p < FLASH_END; p++) {
  353. val = *p;
  354. if ((val & 255) < EEPROM_SIZE) {
  355. buf[val & 255] = val >> 8;
  356. }
  357. }
  358. buf[offset] = data;
  359. for (flashaddr=(uint32_t)FLASH_BEGIN; flashaddr < (uint32_t)FLASH_END; flashaddr += 1024) {
  360. *(uint32_t *)&FTFL_FCCOB3 = 0x09000000 | flashaddr;
  361. __disable_irq();
  362. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);
  363. __enable_irq();
  364. val = FTFL_FSTAT & 0x70;
  365. if (val) FTFL_FSTAT = val;
  366. MCM_PLACR |= MCM_PLACR_CFCC;
  367. }
  368. flashaddr=(uint32_t)FLASH_BEGIN;
  369. for (i=0; i < EEPROM_SIZE; i++) {
  370. if (buf[i] == 0xFF) continue;
  371. if ((flashaddr & 2) == 0) {
  372. val = (buf[i] << 8) | i;
  373. } else {
  374. val = val | (buf[i] << 24) | (i << 16);
  375. flash_write(do_flash_cmd, flashaddr, val);
  376. }
  377. flashaddr += 2;
  378. }
  379. flashend = flashaddr;
  380. if ((flashaddr & 2)) {
  381. val |= 0xFFFF0000;
  382. flash_write(do_flash_cmd, flashaddr, val);
  383. }
  384. }
  385. }
  386. /*
  387. void do_flash_cmd(volatile uint8_t *fstat)
  388. {
  389. *fstat = 0x80;
  390. while ((*fstat & 0x80) == 0) ; // wait
  391. }
  392. 00000000 <do_flash_cmd>:
  393. 0: 2380 movs r3, #128 ; 0x80
  394. 2: 7003 strb r3, [r0, #0]
  395. 4: 7803 ldrb r3, [r0, #0]
  396. 6: b25b sxtb r3, r3
  397. 8: 2b00 cmp r3, #0
  398. a: dafb bge.n 4 <do_flash_cmd+0x4>
  399. c: 4770 bx lr
  400. */
  401. uint16_t eeprom_read_word(const uint16_t *addr)
  402. {
  403. const uint8_t *p = (const uint8_t *)addr;
  404. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
  405. }
  406. uint32_t eeprom_read_dword(const uint32_t *addr)
  407. {
  408. const uint8_t *p = (const uint8_t *)addr;
  409. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
  410. | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
  411. }
  412. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  413. {
  414. const uint8_t *p = (const uint8_t *)addr;
  415. uint8_t *dest = (uint8_t *)buf;
  416. while (len--) {
  417. *dest++ = eeprom_read_byte(p++);
  418. }
  419. }
  420. int eeprom_is_ready(void)
  421. {
  422. return 1;
  423. }
  424. void eeprom_write_word(uint16_t *addr, uint16_t value)
  425. {
  426. uint8_t *p = (uint8_t *)addr;
  427. eeprom_write_byte(p++, value);
  428. eeprom_write_byte(p, value >> 8);
  429. }
  430. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  431. {
  432. uint8_t *p = (uint8_t *)addr;
  433. eeprom_write_byte(p++, value);
  434. eeprom_write_byte(p++, value >> 8);
  435. eeprom_write_byte(p++, value >> 16);
  436. eeprom_write_byte(p, value >> 24);
  437. }
  438. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  439. {
  440. uint8_t *p = (uint8_t *)addr;
  441. const uint8_t *src = (const uint8_t *)buf;
  442. while (len--) {
  443. eeprom_write_byte(p++, *src++);
  444. }
  445. }
  446. #endif // KINETISL