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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2016 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 <avr/eeprom.h>
  32. //#include "HardwareSerial.h"
  33. #if defined(__MK20DX128__) || defined(__MK20DX256__)
  34. #define EEPROM_MAX 2048
  35. #define EEPARTITION 0x03 // all 32K dataflash for EEPROM, none for Data
  36. #define EEESPLIT 0x30 // must be 0x30 on these chips
  37. #elif defined(__MK64FX512__)
  38. #define EEPROM_MAX 4096
  39. #define EEPARTITION 0x05 // all 128K dataflash for EEPROM
  40. #define EEESPLIT 0x10 // best endurance: 0x00 = first 12%, 0x10 = first 25%, 0x30 = all equal
  41. #elif defined(__MK66FX1M0__)
  42. #define EEPROM_MAX 4096
  43. #define EEPARTITION 0x05 // 128K dataflash for EEPROM, 128K for Data
  44. #define EEESPLIT 0x10 // best endurance: 0x00 = first 12%, 0x10 = first 25%, 0x30 = all equal
  45. #elif defined(__MKL26Z64__)
  46. #define EEPROM_MAX 255
  47. #endif
  48. #if E2END > (EEPROM_MAX-1)
  49. #error "E2END is set larger than the maximum possible EEPROM size"
  50. #endif
  51. #if defined(KINETISK)
  52. // The EEPROM is really RAM with a hardware-based backup system to
  53. // flash memory. Selecting a smaller size EEPROM allows more wear
  54. // leveling, for higher write endurance. If you edit this file,
  55. // set this to the smallest size your application can use. Also,
  56. // due to Freescale's implementation, writing 16 or 32 bit words
  57. // (aligned to 2 or 4 byte boundaries) has twice the endurance
  58. // compared to writing 8 bit bytes.
  59. //
  60. #if E2END < 32
  61. #define EEPROM_SIZE 32
  62. #define EEESIZE 0x09
  63. #elif E2END < 64
  64. #define EEPROM_SIZE 64
  65. #define EEESIZE 0x08
  66. #elif E2END < 128
  67. #define EEPROM_SIZE 128
  68. #define EEESIZE 0x07
  69. #elif E2END < 256
  70. #define EEPROM_SIZE 256
  71. #define EEESIZE 0x06
  72. #elif E2END < 512
  73. #define EEPROM_SIZE 512
  74. #define EEESIZE 0x05
  75. #elif E2END < 1024
  76. #define EEPROM_SIZE 1024
  77. #define EEESIZE 0x04
  78. #elif E2END < 2048
  79. #define EEPROM_SIZE 2048
  80. #define EEESIZE 0x03
  81. #elif E2END < 4096
  82. #define EEPROM_SIZE 4096
  83. #define EEESIZE 0x02
  84. #endif
  85. // Writing unaligned 16 or 32 bit data is handled automatically when
  86. // this is defined, but at a cost of extra code size. Without this,
  87. // any unaligned write will cause a hard fault exception! If you're
  88. // absolutely sure all 16 and 32 bit writes will be aligned, you can
  89. // remove the extra unnecessary code.
  90. //
  91. #define HANDLE_UNALIGNED_WRITES
  92. void eeprom_initialize(void)
  93. {
  94. uint32_t count=0;
  95. uint16_t do_flash_cmd[] = {
  96. 0xf06f, 0x037f, 0x7003, 0x7803,
  97. 0xf013, 0x0f80, 0xd0fb, 0x4770};
  98. uint8_t status;
  99. if (FTFL_FCNFG & FTFL_FCNFG_RAMRDY) {
  100. uint8_t stat = FTFL_FSTAT & 0x70;
  101. if (stat) FTFL_FSTAT = stat;
  102. // FlexRAM is configured as traditional RAM
  103. // We need to reconfigure for EEPROM usage
  104. FTFL_FCCOB0 = 0x80; // PGMPART = Program Partition Command
  105. FTFL_FCCOB3 = 0;
  106. FTFL_FCCOB4 = EEESPLIT | EEESIZE;
  107. FTFL_FCCOB5 = EEPARTITION;
  108. __disable_irq();
  109. // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
  110. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);
  111. __enable_irq();
  112. status = FTFL_FSTAT;
  113. if (status & 0x70) {
  114. FTFL_FSTAT = (status & 0x70);
  115. return; // error
  116. }
  117. }
  118. // wait for eeprom to become ready (is this really necessary?)
  119. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  120. if (++count > 200000) break;
  121. }
  122. }
  123. #define FlexRAM ((volatile uint8_t *)0x14000000)
  124. uint8_t eeprom_read_byte(const uint8_t *addr)
  125. {
  126. uint32_t offset = (uint32_t)addr;
  127. if (offset >= EEPROM_SIZE) return 0;
  128. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  129. return FlexRAM[offset];
  130. }
  131. uint16_t eeprom_read_word(const uint16_t *addr)
  132. {
  133. uint32_t offset = (uint32_t)addr;
  134. if (offset >= EEPROM_SIZE-1) return 0;
  135. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  136. return *(uint16_t *)(&FlexRAM[offset]);
  137. }
  138. uint32_t eeprom_read_dword(const uint32_t *addr)
  139. {
  140. uint32_t offset = (uint32_t)addr;
  141. if (offset >= EEPROM_SIZE-3) return 0;
  142. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  143. return *(uint32_t *)(&FlexRAM[offset]);
  144. }
  145. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  146. {
  147. uint32_t offset = (uint32_t)addr;
  148. uint8_t *dest = (uint8_t *)buf;
  149. uint32_t end = offset + len;
  150. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  151. if (end > EEPROM_SIZE) end = EEPROM_SIZE;
  152. while (offset < end) {
  153. *dest++ = FlexRAM[offset++];
  154. }
  155. }
  156. int eeprom_is_ready(void)
  157. {
  158. return (FTFL_FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
  159. }
  160. static void flexram_wait(void)
  161. {
  162. while (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) {
  163. // TODO: timeout
  164. }
  165. }
  166. void eeprom_write_byte(uint8_t *addr, uint8_t value)
  167. {
  168. uint32_t offset = (uint32_t)addr;
  169. if (offset >= EEPROM_SIZE) return;
  170. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  171. if (FlexRAM[offset] != value) {
  172. uint8_t stat = FTFL_FSTAT & 0x70;
  173. if (stat) FTFL_FSTAT = stat;
  174. FlexRAM[offset] = value;
  175. flexram_wait();
  176. }
  177. }
  178. void eeprom_write_word(uint16_t *addr, uint16_t value)
  179. {
  180. uint32_t offset = (uint32_t)addr;
  181. if (offset >= EEPROM_SIZE-1) return;
  182. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  183. #ifdef HANDLE_UNALIGNED_WRITES
  184. if ((offset & 1) == 0) {
  185. #endif
  186. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  187. uint8_t stat = FTFL_FSTAT & 0x70;
  188. if (stat) FTFL_FSTAT = stat;
  189. *(uint16_t *)(&FlexRAM[offset]) = value;
  190. flexram_wait();
  191. }
  192. #ifdef HANDLE_UNALIGNED_WRITES
  193. } else {
  194. if (FlexRAM[offset] != value) {
  195. uint8_t stat = FTFL_FSTAT & 0x70;
  196. if (stat) FTFL_FSTAT = stat;
  197. FlexRAM[offset] = value;
  198. flexram_wait();
  199. }
  200. if (FlexRAM[offset + 1] != (value >> 8)) {
  201. uint8_t stat = FTFL_FSTAT & 0x70;
  202. if (stat) FTFL_FSTAT = stat;
  203. FlexRAM[offset + 1] = value >> 8;
  204. flexram_wait();
  205. }
  206. }
  207. #endif
  208. }
  209. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  210. {
  211. uint32_t offset = (uint32_t)addr;
  212. if (offset >= EEPROM_SIZE-3) return;
  213. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  214. #ifdef HANDLE_UNALIGNED_WRITES
  215. switch (offset & 3) {
  216. case 0:
  217. #endif
  218. if (*(uint32_t *)(&FlexRAM[offset]) != value) {
  219. uint8_t stat = FTFL_FSTAT & 0x70;
  220. if (stat) FTFL_FSTAT = stat;
  221. *(uint32_t *)(&FlexRAM[offset]) = value;
  222. flexram_wait();
  223. }
  224. return;
  225. #ifdef HANDLE_UNALIGNED_WRITES
  226. case 2:
  227. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  228. uint8_t stat = FTFL_FSTAT & 0x70;
  229. if (stat) FTFL_FSTAT = stat;
  230. *(uint16_t *)(&FlexRAM[offset]) = value;
  231. flexram_wait();
  232. }
  233. if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
  234. uint8_t stat = FTFL_FSTAT & 0x70;
  235. if (stat) FTFL_FSTAT = stat;
  236. *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
  237. flexram_wait();
  238. }
  239. return;
  240. default:
  241. if (FlexRAM[offset] != value) {
  242. uint8_t stat = FTFL_FSTAT & 0x70;
  243. if (stat) FTFL_FSTAT = stat;
  244. FlexRAM[offset] = value;
  245. flexram_wait();
  246. }
  247. if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
  248. uint8_t stat = FTFL_FSTAT & 0x70;
  249. if (stat) FTFL_FSTAT = stat;
  250. *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
  251. flexram_wait();
  252. }
  253. if (FlexRAM[offset + 3] != (value >> 24)) {
  254. uint8_t stat = FTFL_FSTAT & 0x70;
  255. if (stat) FTFL_FSTAT = stat;
  256. FlexRAM[offset + 3] = value >> 24;
  257. flexram_wait();
  258. }
  259. }
  260. #endif
  261. }
  262. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  263. {
  264. uint32_t offset = (uint32_t)addr;
  265. const uint8_t *src = (const uint8_t *)buf;
  266. if (offset >= EEPROM_SIZE) return;
  267. if (!(FTFL_FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  268. if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
  269. if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
  270. while (len > 0) {
  271. uint32_t lsb = offset & 3;
  272. if (lsb == 0 && len >= 4) {
  273. // write aligned 32 bits
  274. uint32_t val32;
  275. val32 = *src++;
  276. val32 |= (*src++ << 8);
  277. val32 |= (*src++ << 16);
  278. val32 |= (*src++ << 24);
  279. if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
  280. uint8_t stat = FTFL_FSTAT & 0x70;
  281. if (stat) FTFL_FSTAT = stat;
  282. *(uint32_t *)(&FlexRAM[offset]) = val32;
  283. flexram_wait();
  284. }
  285. offset += 4;
  286. len -= 4;
  287. } else if ((lsb == 0 || lsb == 2) && len >= 2) {
  288. // write aligned 16 bits
  289. uint16_t val16;
  290. val16 = *src++;
  291. val16 |= (*src++ << 8);
  292. if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
  293. uint8_t stat = FTFL_FSTAT & 0x70;
  294. if (stat) FTFL_FSTAT = stat;
  295. *(uint16_t *)(&FlexRAM[offset]) = val16;
  296. flexram_wait();
  297. }
  298. offset += 2;
  299. len -= 2;
  300. } else {
  301. // write 8 bits
  302. uint8_t val8 = *src++;
  303. if (FlexRAM[offset] != val8) {
  304. uint8_t stat = FTFL_FSTAT & 0x70;
  305. if (stat) FTFL_FSTAT = stat;
  306. FlexRAM[offset] = val8;
  307. flexram_wait();
  308. }
  309. offset++;
  310. len--;
  311. }
  312. }
  313. }
  314. /*
  315. void do_flash_cmd(volatile uint8_t *fstat)
  316. {
  317. *fstat = 0x80;
  318. while ((*fstat & 0x80) == 0) ; // wait
  319. }
  320. 00000000 <do_flash_cmd>:
  321. 0: f06f 037f mvn.w r3, #127 ; 0x7f
  322. 4: 7003 strb r3, [r0, #0]
  323. 6: 7803 ldrb r3, [r0, #0]
  324. 8: f013 0f80 tst.w r3, #128 ; 0x80
  325. c: d0fb beq.n 6 <do_flash_cmd+0x6>
  326. e: 4770 bx lr
  327. */
  328. #elif defined(KINETISL)
  329. #define EEPROM_SIZE (E2END+1)
  330. #define FLASH_BEGIN (uint16_t *)63488
  331. #define FLASH_END (uint16_t *)65536
  332. static uint16_t flashend = 0;
  333. void eeprom_initialize(void)
  334. {
  335. const uint16_t *p = FLASH_BEGIN;
  336. do {
  337. if (*p++ == 0xFFFF) {
  338. flashend = (uint32_t)(p - 2);
  339. return;
  340. }
  341. } while (p < FLASH_END);
  342. flashend = (uint32_t)(FLASH_END - 1);
  343. }
  344. uint8_t eeprom_read_byte(const uint8_t *addr)
  345. {
  346. uint32_t offset = (uint32_t)addr;
  347. const uint16_t *p = FLASH_BEGIN;
  348. const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
  349. uint16_t val;
  350. uint8_t data=0xFF;
  351. if (!end) {
  352. eeprom_initialize();
  353. end = (const uint16_t *)((uint32_t)flashend);
  354. }
  355. if (offset < EEPROM_SIZE) {
  356. while (p <= end) {
  357. val = *p++;
  358. if ((val & 255) == offset) data = val >> 8;
  359. }
  360. }
  361. return data;
  362. }
  363. static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
  364. {
  365. // with great power comes great responsibility....
  366. uint32_t stat;
  367. *(uint32_t *)&FTFL_FCCOB3 = 0x06000000 | (addr & 0x00FFFFFC);
  368. *(uint32_t *)&FTFL_FCCOB7 = data;
  369. __disable_irq();
  370. (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&FTFL_FSTAT);
  371. __enable_irq();
  372. stat = FTFL_FSTAT & 0x70;
  373. if (stat) {
  374. FTFL_FSTAT = stat;
  375. }
  376. MCM_PLACR |= MCM_PLACR_CFCC;
  377. }
  378. void eeprom_write_byte(uint8_t *addr, uint8_t data)
  379. {
  380. uint32_t offset = (uint32_t)addr;
  381. const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
  382. uint32_t i, val, flashaddr;
  383. uint16_t do_flash_cmd[] = {
  384. 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
  385. uint8_t buf[EEPROM_SIZE];
  386. if (offset >= EEPROM_SIZE) return;
  387. if (!end) {
  388. eeprom_initialize();
  389. end = (const uint16_t *)((uint32_t)flashend);
  390. }
  391. if (++end < FLASH_END) {
  392. val = (data << 8) | offset;
  393. flashaddr = (uint32_t)end;
  394. flashend = flashaddr;
  395. if ((flashaddr & 2) == 0) {
  396. val |= 0xFFFF0000;
  397. } else {
  398. val <<= 16;
  399. val |= 0x0000FFFF;
  400. }
  401. flash_write(do_flash_cmd, flashaddr, val);
  402. } else {
  403. for (i=0; i < EEPROM_SIZE; i++) {
  404. buf[i] = 0xFF;
  405. }
  406. for (p = FLASH_BEGIN; p < FLASH_END; p++) {
  407. val = *p;
  408. if ((val & 255) < EEPROM_SIZE) {
  409. buf[val & 255] = val >> 8;
  410. }
  411. }
  412. buf[offset] = data;
  413. for (flashaddr=(uint32_t)FLASH_BEGIN; flashaddr < (uint32_t)FLASH_END; flashaddr += 1024) {
  414. *(uint32_t *)&FTFL_FCCOB3 = 0x09000000 | flashaddr;
  415. __disable_irq();
  416. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&FTFL_FSTAT);
  417. __enable_irq();
  418. val = FTFL_FSTAT & 0x70;
  419. if (val) FTFL_FSTAT = val;
  420. MCM_PLACR |= MCM_PLACR_CFCC;
  421. }
  422. flashaddr=(uint32_t)FLASH_BEGIN;
  423. for (i=0; i < EEPROM_SIZE; i++) {
  424. if (buf[i] == 0xFF) continue;
  425. if ((flashaddr & 2) == 0) {
  426. val = (buf[i] << 8) | i;
  427. } else {
  428. val = val | (buf[i] << 24) | (i << 16);
  429. flash_write(do_flash_cmd, flashaddr, val);
  430. }
  431. flashaddr += 2;
  432. }
  433. flashend = flashaddr;
  434. if ((flashaddr & 2)) {
  435. val |= 0xFFFF0000;
  436. flash_write(do_flash_cmd, flashaddr, val);
  437. }
  438. }
  439. }
  440. /*
  441. void do_flash_cmd(volatile uint8_t *fstat)
  442. {
  443. *fstat = 0x80;
  444. while ((*fstat & 0x80) == 0) ; // wait
  445. }
  446. 00000000 <do_flash_cmd>:
  447. 0: 2380 movs r3, #128 ; 0x80
  448. 2: 7003 strb r3, [r0, #0]
  449. 4: 7803 ldrb r3, [r0, #0]
  450. 6: b25b sxtb r3, r3
  451. 8: 2b00 cmp r3, #0
  452. a: dafb bge.n 4 <do_flash_cmd+0x4>
  453. c: 4770 bx lr
  454. */
  455. uint16_t eeprom_read_word(const uint16_t *addr)
  456. {
  457. const uint8_t *p = (const uint8_t *)addr;
  458. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
  459. }
  460. uint32_t eeprom_read_dword(const uint32_t *addr)
  461. {
  462. const uint8_t *p = (const uint8_t *)addr;
  463. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
  464. | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
  465. }
  466. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  467. {
  468. const uint8_t *p = (const uint8_t *)addr;
  469. uint8_t *dest = (uint8_t *)buf;
  470. while (len--) {
  471. *dest++ = eeprom_read_byte(p++);
  472. }
  473. }
  474. int eeprom_is_ready(void)
  475. {
  476. return 1;
  477. }
  478. void eeprom_write_word(uint16_t *addr, uint16_t value)
  479. {
  480. uint8_t *p = (uint8_t *)addr;
  481. eeprom_write_byte(p++, value);
  482. eeprom_write_byte(p, value >> 8);
  483. }
  484. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  485. {
  486. uint8_t *p = (uint8_t *)addr;
  487. eeprom_write_byte(p++, value);
  488. eeprom_write_byte(p++, value >> 8);
  489. eeprom_write_byte(p++, value >> 16);
  490. eeprom_write_byte(p, value >> 24);
  491. }
  492. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  493. {
  494. uint8_t *p = (uint8_t *)addr;
  495. const uint8_t *src = (const uint8_t *)buf;
  496. while (len--) {
  497. eeprom_write_byte(p++, *src++);
  498. }
  499. }
  500. #endif // KINETISL