eeprom_teensy.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. #include "ch.h"
  2. #include "hal.h"
  3. #include "eeconfig.h"
  4. /*************************************/
  5. /* Hardware backend */
  6. /* */
  7. /* Code from PJRC/Teensyduino */
  8. /*************************************/
  9. /* Teensyduino Core Library
  10. * http://www.pjrc.com/teensy/
  11. * Copyright (c) 2013 PJRC.COM, LLC.
  12. *
  13. * Permission is hereby granted, free of charge, to any person obtaining
  14. * a copy of this software and associated documentation files (the
  15. * "Software"), to deal in the Software without restriction, including
  16. * without limitation the rights to use, copy, modify, merge, publish,
  17. * distribute, sublicense, and/or sell copies of the Software, and to
  18. * permit persons to whom the Software is furnished to do so, subject to
  19. * the following conditions:
  20. *
  21. * 1. The above copyright notice and this permission notice shall be
  22. * included in all copies or substantial portions of the Software.
  23. *
  24. * 2. If the Software is incorporated into a build system that allows
  25. * selection among a list of target devices, then similar target
  26. * devices manufactured by PJRC.COM must be included in the list of
  27. * target devices and selectable in the same manner.
  28. *
  29. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  30. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  31. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  32. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  33. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  34. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  35. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  36. * SOFTWARE.
  37. */
  38. #if defined(K20x) /* chip selection */
  39. /* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
  40. // The EEPROM is really RAM with a hardware-based backup system to
  41. // flash memory. Selecting a smaller size EEPROM allows more wear
  42. // leveling, for higher write endurance. If you edit this file,
  43. // set this to the smallest size your application can use. Also,
  44. // due to Freescale's implementation, writing 16 or 32 bit words
  45. // (aligned to 2 or 4 byte boundaries) has twice the endurance
  46. // compared to writing 8 bit bytes.
  47. //
  48. #define EEPROM_SIZE 32
  49. // Writing unaligned 16 or 32 bit data is handled automatically when
  50. // this is defined, but at a cost of extra code size. Without this,
  51. // any unaligned write will cause a hard fault exception! If you're
  52. // absolutely sure all 16 and 32 bit writes will be aligned, you can
  53. // remove the extra unnecessary code.
  54. //
  55. #define HANDLE_UNALIGNED_WRITES
  56. // Minimum EEPROM Endurance
  57. // ------------------------
  58. #if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
  59. #define EEESIZE 0x33
  60. #elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
  61. #define EEESIZE 0x34
  62. #elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
  63. #define EEESIZE 0x35
  64. #elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
  65. #define EEESIZE 0x36
  66. #elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
  67. #define EEESIZE 0x37
  68. #elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
  69. #define EEESIZE 0x38
  70. #elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
  71. #define EEESIZE 0x39
  72. #endif
  73. /** \brief eeprom initialization
  74. *
  75. * FIXME: needs doc
  76. */
  77. void eeprom_initialize(void)
  78. {
  79. uint32_t count=0;
  80. uint16_t do_flash_cmd[] = {
  81. 0xf06f, 0x037f, 0x7003, 0x7803,
  82. 0xf013, 0x0f80, 0xd0fb, 0x4770};
  83. uint8_t status;
  84. if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
  85. // FlexRAM is configured as traditional RAM
  86. // We need to reconfigure for EEPROM usage
  87. FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
  88. FTFL->FCCOB4 = EEESIZE; // EEPROM Size
  89. FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
  90. __disable_irq();
  91. // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
  92. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
  93. __enable_irq();
  94. status = FTFL->FSTAT;
  95. if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
  96. FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
  97. return; // error
  98. }
  99. }
  100. // wait for eeprom to become ready (is this really necessary?)
  101. while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
  102. if (++count > 20000) break;
  103. }
  104. }
  105. #define FlexRAM ((uint8_t *)0x14000000)
  106. /** \brief eeprom read byte
  107. *
  108. * FIXME: needs doc
  109. */
  110. uint8_t eeprom_read_byte(const uint8_t *addr)
  111. {
  112. uint32_t offset = (uint32_t)addr;
  113. if (offset >= EEPROM_SIZE) return 0;
  114. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  115. return FlexRAM[offset];
  116. }
  117. /** \brief eeprom read word
  118. *
  119. * FIXME: needs doc
  120. */
  121. uint16_t eeprom_read_word(const uint16_t *addr)
  122. {
  123. uint32_t offset = (uint32_t)addr;
  124. if (offset >= EEPROM_SIZE-1) return 0;
  125. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  126. return *(uint16_t *)(&FlexRAM[offset]);
  127. }
  128. /** \brief eeprom read dword
  129. *
  130. * FIXME: needs doc
  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. /** \brief eeprom read block
  140. *
  141. * FIXME: needs doc
  142. */
  143. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  144. {
  145. uint32_t offset = (uint32_t)addr;
  146. uint8_t *dest = (uint8_t *)buf;
  147. uint32_t end = offset + len;
  148. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  149. if (end > EEPROM_SIZE) end = EEPROM_SIZE;
  150. while (offset < end) {
  151. *dest++ = FlexRAM[offset++];
  152. }
  153. }
  154. /** \brief eeprom is ready
  155. *
  156. * FIXME: needs doc
  157. */
  158. int eeprom_is_ready(void)
  159. {
  160. return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
  161. }
  162. /** \brief flexram wait
  163. *
  164. * FIXME: needs doc
  165. */
  166. static void flexram_wait(void)
  167. {
  168. while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
  169. // TODO: timeout
  170. }
  171. }
  172. /** \brief eeprom_write_byte
  173. *
  174. * FIXME: needs doc
  175. */
  176. void eeprom_write_byte(uint8_t *addr, uint8_t value)
  177. {
  178. uint32_t offset = (uint32_t)addr;
  179. if (offset >= EEPROM_SIZE) return;
  180. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  181. if (FlexRAM[offset] != value) {
  182. FlexRAM[offset] = value;
  183. flexram_wait();
  184. }
  185. }
  186. /** \brief eeprom write word
  187. *
  188. * FIXME: needs doc
  189. */
  190. void eeprom_write_word(uint16_t *addr, uint16_t value)
  191. {
  192. uint32_t offset = (uint32_t)addr;
  193. if (offset >= EEPROM_SIZE-1) return;
  194. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  195. #ifdef HANDLE_UNALIGNED_WRITES
  196. if ((offset & 1) == 0) {
  197. #endif
  198. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  199. *(uint16_t *)(&FlexRAM[offset]) = value;
  200. flexram_wait();
  201. }
  202. #ifdef HANDLE_UNALIGNED_WRITES
  203. } else {
  204. if (FlexRAM[offset] != value) {
  205. FlexRAM[offset] = value;
  206. flexram_wait();
  207. }
  208. if (FlexRAM[offset + 1] != (value >> 8)) {
  209. FlexRAM[offset + 1] = value >> 8;
  210. flexram_wait();
  211. }
  212. }
  213. #endif
  214. }
  215. /** \brief eeprom write dword
  216. *
  217. * FIXME: needs doc
  218. */
  219. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  220. {
  221. uint32_t offset = (uint32_t)addr;
  222. if (offset >= EEPROM_SIZE-3) return;
  223. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  224. #ifdef HANDLE_UNALIGNED_WRITES
  225. switch (offset & 3) {
  226. case 0:
  227. #endif
  228. if (*(uint32_t *)(&FlexRAM[offset]) != value) {
  229. *(uint32_t *)(&FlexRAM[offset]) = value;
  230. flexram_wait();
  231. }
  232. return;
  233. #ifdef HANDLE_UNALIGNED_WRITES
  234. case 2:
  235. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  236. *(uint16_t *)(&FlexRAM[offset]) = value;
  237. flexram_wait();
  238. }
  239. if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
  240. *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
  241. flexram_wait();
  242. }
  243. return;
  244. default:
  245. if (FlexRAM[offset] != value) {
  246. FlexRAM[offset] = value;
  247. flexram_wait();
  248. }
  249. if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
  250. *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
  251. flexram_wait();
  252. }
  253. if (FlexRAM[offset + 3] != (value >> 24)) {
  254. FlexRAM[offset + 3] = value >> 24;
  255. flexram_wait();
  256. }
  257. }
  258. #endif
  259. }
  260. /** \brief eeprom write block
  261. *
  262. * FIXME: needs doc
  263. */
  264. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  265. {
  266. uint32_t offset = (uint32_t)addr;
  267. const uint8_t *src = (const uint8_t *)buf;
  268. if (offset >= EEPROM_SIZE) return;
  269. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  270. if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
  271. if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
  272. while (len > 0) {
  273. uint32_t lsb = offset & 3;
  274. if (lsb == 0 && len >= 4) {
  275. // write aligned 32 bits
  276. uint32_t val32;
  277. val32 = *src++;
  278. val32 |= (*src++ << 8);
  279. val32 |= (*src++ << 16);
  280. val32 |= (*src++ << 24);
  281. if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
  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. *(uint16_t *)(&FlexRAM[offset]) = val16;
  294. flexram_wait();
  295. }
  296. offset += 2;
  297. len -= 2;
  298. } else {
  299. // write 8 bits
  300. uint8_t val8 = *src++;
  301. if (FlexRAM[offset] != val8) {
  302. FlexRAM[offset] = val8;
  303. flexram_wait();
  304. }
  305. offset++;
  306. len--;
  307. }
  308. }
  309. }
  310. /*
  311. void do_flash_cmd(volatile uint8_t *fstat)
  312. {
  313. *fstat = 0x80;
  314. while ((*fstat & 0x80) == 0) ; // wait
  315. }
  316. 00000000 <do_flash_cmd>:
  317. 0: f06f 037f mvn.w r3, #127 ; 0x7f
  318. 4: 7003 strb r3, [r0, #0]
  319. 6: 7803 ldrb r3, [r0, #0]
  320. 8: f013 0f80 tst.w r3, #128 ; 0x80
  321. c: d0fb beq.n 6 <do_flash_cmd+0x6>
  322. e: 4770 bx lr
  323. */
  324. #elif defined(KL2x) /* chip selection */
  325. /* Teensy LC (emulated) */
  326. #define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
  327. extern uint32_t __eeprom_workarea_start__;
  328. extern uint32_t __eeprom_workarea_end__;
  329. #define EEPROM_SIZE 128
  330. static uint32_t flashend = 0;
  331. void eeprom_initialize(void)
  332. {
  333. const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
  334. do {
  335. if (*p++ == 0xFFFF) {
  336. flashend = (uint32_t)(p - 2);
  337. return;
  338. }
  339. } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
  340. flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
  341. }
  342. uint8_t eeprom_read_byte(const uint8_t *addr)
  343. {
  344. uint32_t offset = (uint32_t)addr;
  345. const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
  346. const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
  347. uint16_t val;
  348. uint8_t data=0xFF;
  349. if (!end) {
  350. eeprom_initialize();
  351. end = (const uint16_t *)((uint32_t)flashend);
  352. }
  353. if (offset < EEPROM_SIZE) {
  354. while (p <= end) {
  355. val = *p++;
  356. if ((val & 255) == offset) data = val >> 8;
  357. }
  358. }
  359. return data;
  360. }
  361. static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
  362. {
  363. // with great power comes great responsibility....
  364. uint32_t stat;
  365. *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
  366. *(uint32_t *)&(FTFA->FCCOB7) = data;
  367. __disable_irq();
  368. (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
  369. __enable_irq();
  370. stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
  371. if (stat) {
  372. FTFA->FSTAT = stat;
  373. }
  374. MCM->PLACR |= MCM_PLACR_CFCC;
  375. }
  376. void eeprom_write_byte(uint8_t *addr, uint8_t data)
  377. {
  378. uint32_t offset = (uint32_t)addr;
  379. const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
  380. uint32_t i, val, flashaddr;
  381. uint16_t do_flash_cmd[] = {
  382. 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
  383. uint8_t buf[EEPROM_SIZE];
  384. if (offset >= EEPROM_SIZE) return;
  385. if (!end) {
  386. eeprom_initialize();
  387. end = (const uint16_t *)((uint32_t)flashend);
  388. }
  389. if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
  390. val = (data << 8) | offset;
  391. flashaddr = (uint32_t)end;
  392. flashend = flashaddr;
  393. if ((flashaddr & 2) == 0) {
  394. val |= 0xFFFF0000;
  395. } else {
  396. val <<= 16;
  397. val |= 0x0000FFFF;
  398. }
  399. flash_write(do_flash_cmd, flashaddr, val);
  400. } else {
  401. for (i=0; i < EEPROM_SIZE; i++) {
  402. buf[i] = 0xFF;
  403. }
  404. val = 0;
  405. for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
  406. val = *p;
  407. if ((val & 255) < EEPROM_SIZE) {
  408. buf[val & 255] = val >> 8;
  409. }
  410. }
  411. buf[offset] = data;
  412. for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
  413. *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
  414. __disable_irq();
  415. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
  416. __enable_irq();
  417. val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
  418. if (val) FTFA->FSTAT = val;
  419. MCM->PLACR |= MCM_PLACR_CFCC;
  420. }
  421. flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
  422. for (i=0; i < EEPROM_SIZE; i++) {
  423. if (buf[i] == 0xFF) continue;
  424. if ((flashaddr & 2) == 0) {
  425. val = (buf[i] << 8) | i;
  426. } else {
  427. val = val | (buf[i] << 24) | (i << 16);
  428. flash_write(do_flash_cmd, flashaddr, val);
  429. }
  430. flashaddr += 2;
  431. }
  432. flashend = flashaddr;
  433. if ((flashaddr & 2)) {
  434. val |= 0xFFFF0000;
  435. flash_write(do_flash_cmd, flashaddr, val);
  436. }
  437. }
  438. }
  439. /*
  440. void do_flash_cmd(volatile uint8_t *fstat)
  441. {
  442. *fstat = 0x80;
  443. while ((*fstat & 0x80) == 0) ; // wait
  444. }
  445. 00000000 <do_flash_cmd>:
  446. 0: 2380 movs r3, #128 ; 0x80
  447. 2: 7003 strb r3, [r0, #0]
  448. 4: 7803 ldrb r3, [r0, #0]
  449. 6: b25b sxtb r3, r3
  450. 8: 2b00 cmp r3, #0
  451. a: dafb bge.n 4 <do_flash_cmd+0x4>
  452. c: 4770 bx lr
  453. */
  454. uint16_t eeprom_read_word(const uint16_t *addr)
  455. {
  456. const uint8_t *p = (const uint8_t *)addr;
  457. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
  458. }
  459. uint32_t eeprom_read_dword(const uint32_t *addr)
  460. {
  461. const uint8_t *p = (const uint8_t *)addr;
  462. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
  463. | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
  464. }
  465. void eeprom_read_block(void *buf, const void *addr, uint32_t len)
  466. {
  467. const uint8_t *p = (const uint8_t *)addr;
  468. uint8_t *dest = (uint8_t *)buf;
  469. while (len--) {
  470. *dest++ = eeprom_read_byte(p++);
  471. }
  472. }
  473. int eeprom_is_ready(void)
  474. {
  475. return 1;
  476. }
  477. void eeprom_write_word(uint16_t *addr, uint16_t value)
  478. {
  479. uint8_t *p = (uint8_t *)addr;
  480. eeprom_write_byte(p++, value);
  481. eeprom_write_byte(p, value >> 8);
  482. }
  483. void eeprom_write_dword(uint32_t *addr, uint32_t value)
  484. {
  485. uint8_t *p = (uint8_t *)addr;
  486. eeprom_write_byte(p++, value);
  487. eeprom_write_byte(p++, value >> 8);
  488. eeprom_write_byte(p++, value >> 16);
  489. eeprom_write_byte(p, value >> 24);
  490. }
  491. void eeprom_write_block(const void *buf, void *addr, uint32_t len)
  492. {
  493. uint8_t *p = (uint8_t *)addr;
  494. const uint8_t *src = (const uint8_t *)buf;
  495. while (len--) {
  496. eeprom_write_byte(p++, *src++);
  497. }
  498. }
  499. #else
  500. // No EEPROM supported, so emulate it
  501. #define EEPROM_SIZE 32
  502. static uint8_t buffer[EEPROM_SIZE];
  503. uint8_t eeprom_read_byte(const uint8_t *addr) {
  504. uint32_t offset = (uint32_t)addr;
  505. return buffer[offset];
  506. }
  507. void eeprom_write_byte(uint8_t *addr, uint8_t value) {
  508. uint32_t offset = (uint32_t)addr;
  509. buffer[offset] = value;
  510. }
  511. uint16_t eeprom_read_word(const uint16_t *addr) {
  512. const uint8_t *p = (const uint8_t *)addr;
  513. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
  514. }
  515. uint32_t eeprom_read_dword(const uint32_t *addr) {
  516. const uint8_t *p = (const uint8_t *)addr;
  517. return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
  518. | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
  519. }
  520. void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
  521. const uint8_t *p = (const uint8_t *)addr;
  522. uint8_t *dest = (uint8_t *)buf;
  523. while (len--) {
  524. *dest++ = eeprom_read_byte(p++);
  525. }
  526. }
  527. void eeprom_write_word(uint16_t *addr, uint16_t value) {
  528. uint8_t *p = (uint8_t *)addr;
  529. eeprom_write_byte(p++, value);
  530. eeprom_write_byte(p, value >> 8);
  531. }
  532. void eeprom_write_dword(uint32_t *addr, uint32_t value) {
  533. uint8_t *p = (uint8_t *)addr;
  534. eeprom_write_byte(p++, value);
  535. eeprom_write_byte(p++, value >> 8);
  536. eeprom_write_byte(p++, value >> 16);
  537. eeprom_write_byte(p, value >> 24);
  538. }
  539. void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
  540. uint8_t *p = (uint8_t *)addr;
  541. const uint8_t *src = (const uint8_t *)buf;
  542. while (len--) {
  543. eeprom_write_byte(p++, *src++);
  544. }
  545. }
  546. #endif /* chip selection */
  547. // The update functions just calls write for now, but could probably be optimized
  548. void eeprom_update_byte(uint8_t *addr, uint8_t value) {
  549. eeprom_write_byte(addr, value);
  550. }
  551. void eeprom_update_word(uint16_t *addr, uint16_t value) {
  552. uint8_t *p = (uint8_t *)addr;
  553. eeprom_write_byte(p++, value);
  554. eeprom_write_byte(p, value >> 8);
  555. }
  556. void eeprom_update_dword(uint32_t *addr, uint32_t value) {
  557. uint8_t *p = (uint8_t *)addr;
  558. eeprom_write_byte(p++, value);
  559. eeprom_write_byte(p++, value >> 8);
  560. eeprom_write_byte(p++, value >> 16);
  561. eeprom_write_byte(p, value >> 24);
  562. }
  563. void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
  564. uint8_t *p = (uint8_t *)addr;
  565. const uint8_t *src = (const uint8_t *)buf;
  566. while (len--) {
  567. eeprom_write_byte(p++, *src++);
  568. }
  569. }