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

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