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.

589 lines
16KB

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