eeprom_teensy.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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. uint32_t count = 0;
  79. uint16_t do_flash_cmd[] = {0xf06f, 0x037f, 0x7003, 0x7803, 0xf013, 0x0f80, 0xd0fb, 0x4770};
  80. uint8_t status;
  81. if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
  82. // FlexRAM is configured as traditional RAM
  83. // We need to reconfigure for EEPROM usage
  84. FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
  85. FTFL->FCCOB4 = EEESIZE; // EEPROM Size
  86. FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
  87. __disable_irq();
  88. // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
  89. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
  90. __enable_irq();
  91. status = FTFL->FSTAT;
  92. if (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)) {
  93. FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL));
  94. return; // error
  95. }
  96. }
  97. // wait for eeprom to become ready (is this really necessary?)
  98. while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
  99. if (++count > 20000) break;
  100. }
  101. }
  102. # define FlexRAM ((uint8_t *)0x14000000)
  103. /** \brief eeprom read byte
  104. *
  105. * FIXME: needs doc
  106. */
  107. uint8_t eeprom_read_byte(const uint8_t *addr) {
  108. uint32_t offset = (uint32_t)addr;
  109. if (offset >= EEPROM_SIZE) return 0;
  110. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  111. return FlexRAM[offset];
  112. }
  113. /** \brief eeprom read word
  114. *
  115. * FIXME: needs doc
  116. */
  117. uint16_t eeprom_read_word(const uint16_t *addr) {
  118. uint32_t offset = (uint32_t)addr;
  119. if (offset >= EEPROM_SIZE - 1) return 0;
  120. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  121. return *(uint16_t *)(&FlexRAM[offset]);
  122. }
  123. /** \brief eeprom read dword
  124. *
  125. * FIXME: needs doc
  126. */
  127. uint32_t eeprom_read_dword(const uint32_t *addr) {
  128. uint32_t offset = (uint32_t)addr;
  129. if (offset >= EEPROM_SIZE - 3) return 0;
  130. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  131. return *(uint32_t *)(&FlexRAM[offset]);
  132. }
  133. /** \brief eeprom read block
  134. *
  135. * FIXME: needs doc
  136. */
  137. void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
  138. uint32_t offset = (uint32_t)addr;
  139. uint8_t *dest = (uint8_t *)buf;
  140. uint32_t end = offset + len;
  141. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  142. if (end > EEPROM_SIZE) end = EEPROM_SIZE;
  143. while (offset < end) {
  144. *dest++ = FlexRAM[offset++];
  145. }
  146. }
  147. /** \brief eeprom is ready
  148. *
  149. * FIXME: needs doc
  150. */
  151. int eeprom_is_ready(void) { return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; }
  152. /** \brief flexram wait
  153. *
  154. * FIXME: needs doc
  155. */
  156. static void flexram_wait(void) {
  157. while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
  158. // TODO: timeout
  159. }
  160. }
  161. /** \brief eeprom_write_byte
  162. *
  163. * FIXME: needs doc
  164. */
  165. void eeprom_write_byte(uint8_t *addr, uint8_t value) {
  166. uint32_t offset = (uint32_t)addr;
  167. if (offset >= EEPROM_SIZE) return;
  168. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  169. if (FlexRAM[offset] != value) {
  170. FlexRAM[offset] = value;
  171. flexram_wait();
  172. }
  173. }
  174. /** \brief eeprom write word
  175. *
  176. * FIXME: needs doc
  177. */
  178. void eeprom_write_word(uint16_t *addr, uint16_t value) {
  179. uint32_t offset = (uint32_t)addr;
  180. if (offset >= EEPROM_SIZE - 1) return;
  181. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  182. # ifdef HANDLE_UNALIGNED_WRITES
  183. if ((offset & 1) == 0) {
  184. # endif
  185. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  186. *(uint16_t *)(&FlexRAM[offset]) = value;
  187. flexram_wait();
  188. }
  189. # ifdef HANDLE_UNALIGNED_WRITES
  190. } else {
  191. if (FlexRAM[offset] != value) {
  192. FlexRAM[offset] = value;
  193. flexram_wait();
  194. }
  195. if (FlexRAM[offset + 1] != (value >> 8)) {
  196. FlexRAM[offset + 1] = value >> 8;
  197. flexram_wait();
  198. }
  199. }
  200. # endif
  201. }
  202. /** \brief eeprom write dword
  203. *
  204. * FIXME: needs doc
  205. */
  206. void eeprom_write_dword(uint32_t *addr, uint32_t value) {
  207. uint32_t offset = (uint32_t)addr;
  208. if (offset >= EEPROM_SIZE - 3) return;
  209. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  210. # ifdef HANDLE_UNALIGNED_WRITES
  211. switch (offset & 3) {
  212. case 0:
  213. # endif
  214. if (*(uint32_t *)(&FlexRAM[offset]) != value) {
  215. *(uint32_t *)(&FlexRAM[offset]) = value;
  216. flexram_wait();
  217. }
  218. return;
  219. # ifdef HANDLE_UNALIGNED_WRITES
  220. case 2:
  221. if (*(uint16_t *)(&FlexRAM[offset]) != value) {
  222. *(uint16_t *)(&FlexRAM[offset]) = value;
  223. flexram_wait();
  224. }
  225. if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
  226. *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
  227. flexram_wait();
  228. }
  229. return;
  230. default:
  231. if (FlexRAM[offset] != value) {
  232. FlexRAM[offset] = value;
  233. flexram_wait();
  234. }
  235. if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
  236. *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
  237. flexram_wait();
  238. }
  239. if (FlexRAM[offset + 3] != (value >> 24)) {
  240. FlexRAM[offset + 3] = value >> 24;
  241. flexram_wait();
  242. }
  243. }
  244. # endif
  245. }
  246. /** \brief eeprom write block
  247. *
  248. * FIXME: needs doc
  249. */
  250. void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
  251. uint32_t offset = (uint32_t)addr;
  252. const uint8_t *src = (const uint8_t *)buf;
  253. if (offset >= EEPROM_SIZE) return;
  254. if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
  255. if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
  256. if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
  257. while (len > 0) {
  258. uint32_t lsb = offset & 3;
  259. if (lsb == 0 && len >= 4) {
  260. // write aligned 32 bits
  261. uint32_t val32;
  262. val32 = *src++;
  263. val32 |= (*src++ << 8);
  264. val32 |= (*src++ << 16);
  265. val32 |= (*src++ << 24);
  266. if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
  267. *(uint32_t *)(&FlexRAM[offset]) = val32;
  268. flexram_wait();
  269. }
  270. offset += 4;
  271. len -= 4;
  272. } else if ((lsb == 0 || lsb == 2) && len >= 2) {
  273. // write aligned 16 bits
  274. uint16_t val16;
  275. val16 = *src++;
  276. val16 |= (*src++ << 8);
  277. if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
  278. *(uint16_t *)(&FlexRAM[offset]) = val16;
  279. flexram_wait();
  280. }
  281. offset += 2;
  282. len -= 2;
  283. } else {
  284. // write 8 bits
  285. uint8_t val8 = *src++;
  286. if (FlexRAM[offset] != val8) {
  287. FlexRAM[offset] = val8;
  288. flexram_wait();
  289. }
  290. offset++;
  291. len--;
  292. }
  293. }
  294. }
  295. /*
  296. void do_flash_cmd(volatile uint8_t *fstat)
  297. {
  298. *fstat = 0x80;
  299. while ((*fstat & 0x80) == 0) ; // wait
  300. }
  301. 00000000 <do_flash_cmd>:
  302. 0: f06f 037f mvn.w r3, #127 ; 0x7f
  303. 4: 7003 strb r3, [r0, #0]
  304. 6: 7803 ldrb r3, [r0, #0]
  305. 8: f013 0f80 tst.w r3, #128 ; 0x80
  306. c: d0fb beq.n 6 <do_flash_cmd+0x6>
  307. e: 4770 bx lr
  308. */
  309. #elif defined(KL2x) /* chip selection */
  310. /* Teensy LC (emulated) */
  311. # define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
  312. extern uint32_t __eeprom_workarea_start__;
  313. extern uint32_t __eeprom_workarea_end__;
  314. # define EEPROM_SIZE 128
  315. static uint32_t flashend = 0;
  316. void eeprom_initialize(void) {
  317. const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
  318. do {
  319. if (*p++ == 0xFFFF) {
  320. flashend = (uint32_t)(p - 2);
  321. return;
  322. }
  323. } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
  324. flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
  325. }
  326. uint8_t eeprom_read_byte(const uint8_t *addr) {
  327. uint32_t offset = (uint32_t)addr;
  328. const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
  329. const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
  330. uint16_t val;
  331. uint8_t data = 0xFF;
  332. if (!end) {
  333. eeprom_initialize();
  334. end = (const uint16_t *)((uint32_t)flashend);
  335. }
  336. if (offset < EEPROM_SIZE) {
  337. while (p <= end) {
  338. val = *p++;
  339. if ((val & 255) == offset) data = val >> 8;
  340. }
  341. }
  342. return data;
  343. }
  344. static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) {
  345. // with great power comes great responsibility....
  346. uint32_t stat;
  347. *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
  348. *(uint32_t *)&(FTFA->FCCOB7) = data;
  349. __disable_irq();
  350. (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
  351. __enable_irq();
  352. stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL);
  353. if (stat) {
  354. FTFA->FSTAT = stat;
  355. }
  356. MCM->PLACR |= MCM_PLACR_CFCC;
  357. }
  358. void eeprom_write_byte(uint8_t *addr, uint8_t data) {
  359. uint32_t offset = (uint32_t)addr;
  360. const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
  361. uint32_t i, val, flashaddr;
  362. uint16_t do_flash_cmd[] = {0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
  363. uint8_t buf[EEPROM_SIZE];
  364. if (offset >= EEPROM_SIZE) return;
  365. if (!end) {
  366. eeprom_initialize();
  367. end = (const uint16_t *)((uint32_t)flashend);
  368. }
  369. if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
  370. val = (data << 8) | offset;
  371. flashaddr = (uint32_t)end;
  372. flashend = flashaddr;
  373. if ((flashaddr & 2) == 0) {
  374. val |= 0xFFFF0000;
  375. } else {
  376. val <<= 16;
  377. val |= 0x0000FFFF;
  378. }
  379. flash_write(do_flash_cmd, flashaddr, val);
  380. } else {
  381. for (i = 0; i < EEPROM_SIZE; i++) {
  382. buf[i] = 0xFF;
  383. }
  384. val = 0;
  385. for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
  386. val = *p;
  387. if ((val & 255) < EEPROM_SIZE) {
  388. buf[val & 255] = val >> 8;
  389. }
  390. }
  391. buf[offset] = data;
  392. for (flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
  393. *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
  394. __disable_irq();
  395. (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
  396. __enable_irq();
  397. val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL);
  398. ;
  399. if (val) FTFA->FSTAT = val;
  400. MCM->PLACR |= MCM_PLACR_CFCC;
  401. }
  402. flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
  403. for (i = 0; i < EEPROM_SIZE; i++) {
  404. if (buf[i] == 0xFF) continue;
  405. if ((flashaddr & 2) == 0) {
  406. val = (buf[i] << 8) | i;
  407. } else {
  408. val = val | (buf[i] << 24) | (i << 16);
  409. flash_write(do_flash_cmd, flashaddr, val);
  410. }
  411. flashaddr += 2;
  412. }
  413. flashend = flashaddr;
  414. if ((flashaddr & 2)) {
  415. val |= 0xFFFF0000;
  416. flash_write(do_flash_cmd, flashaddr, val);
  417. }
  418. }
  419. }
  420. /*
  421. void do_flash_cmd(volatile uint8_t *fstat)
  422. {
  423. *fstat = 0x80;
  424. while ((*fstat & 0x80) == 0) ; // wait
  425. }
  426. 00000000 <do_flash_cmd>:
  427. 0: 2380 movs r3, #128 ; 0x80
  428. 2: 7003 strb r3, [r0, #0]
  429. 4: 7803 ldrb r3, [r0, #0]
  430. 6: b25b sxtb r3, r3
  431. 8: 2b00 cmp r3, #0
  432. a: dafb bge.n 4 <do_flash_cmd+0x4>
  433. c: 4770 bx lr
  434. */
  435. uint16_t eeprom_read_word(const uint16_t *addr) {
  436. const uint8_t *p = (const uint8_t *)addr;
  437. return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
  438. }
  439. uint32_t eeprom_read_dword(const uint32_t *addr) {
  440. const uint8_t *p = (const uint8_t *)addr;
  441. return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
  442. }
  443. void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
  444. const uint8_t *p = (const uint8_t *)addr;
  445. uint8_t * dest = (uint8_t *)buf;
  446. while (len--) {
  447. *dest++ = eeprom_read_byte(p++);
  448. }
  449. }
  450. int eeprom_is_ready(void) { return 1; }
  451. void eeprom_write_word(uint16_t *addr, uint16_t value) {
  452. uint8_t *p = (uint8_t *)addr;
  453. eeprom_write_byte(p++, value);
  454. eeprom_write_byte(p, value >> 8);
  455. }
  456. void eeprom_write_dword(uint32_t *addr, uint32_t value) {
  457. uint8_t *p = (uint8_t *)addr;
  458. eeprom_write_byte(p++, value);
  459. eeprom_write_byte(p++, value >> 8);
  460. eeprom_write_byte(p++, value >> 16);
  461. eeprom_write_byte(p, value >> 24);
  462. }
  463. void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
  464. uint8_t * p = (uint8_t *)addr;
  465. const uint8_t *src = (const uint8_t *)buf;
  466. while (len--) {
  467. eeprom_write_byte(p++, *src++);
  468. }
  469. }
  470. #else
  471. // No EEPROM supported, so emulate it
  472. # define EEPROM_SIZE 32
  473. static uint8_t buffer[EEPROM_SIZE];
  474. uint8_t eeprom_read_byte(const uint8_t *addr) {
  475. uint32_t offset = (uint32_t)addr;
  476. return buffer[offset];
  477. }
  478. void eeprom_write_byte(uint8_t *addr, uint8_t value) {
  479. uint32_t offset = (uint32_t)addr;
  480. buffer[offset] = value;
  481. }
  482. uint16_t eeprom_read_word(const uint16_t *addr) {
  483. const uint8_t *p = (const uint8_t *)addr;
  484. return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
  485. }
  486. uint32_t eeprom_read_dword(const uint32_t *addr) {
  487. const uint8_t *p = (const uint8_t *)addr;
  488. return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
  489. }
  490. void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
  491. const uint8_t *p = (const uint8_t *)addr;
  492. uint8_t * dest = (uint8_t *)buf;
  493. while (len--) {
  494. *dest++ = eeprom_read_byte(p++);
  495. }
  496. }
  497. void eeprom_write_word(uint16_t *addr, uint16_t value) {
  498. uint8_t *p = (uint8_t *)addr;
  499. eeprom_write_byte(p++, value);
  500. eeprom_write_byte(p, value >> 8);
  501. }
  502. void eeprom_write_dword(uint32_t *addr, uint32_t value) {
  503. uint8_t *p = (uint8_t *)addr;
  504. eeprom_write_byte(p++, value);
  505. eeprom_write_byte(p++, value >> 8);
  506. eeprom_write_byte(p++, value >> 16);
  507. eeprom_write_byte(p, value >> 24);
  508. }
  509. void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
  510. uint8_t * p = (uint8_t *)addr;
  511. const uint8_t *src = (const uint8_t *)buf;
  512. while (len--) {
  513. eeprom_write_byte(p++, *src++);
  514. }
  515. }
  516. #endif /* chip selection */
  517. // The update functions just calls write for now, but could probably be optimized
  518. void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
  519. void eeprom_update_word(uint16_t *addr, uint16_t value) {
  520. uint8_t *p = (uint8_t *)addr;
  521. eeprom_write_byte(p++, value);
  522. eeprom_write_byte(p, value >> 8);
  523. }
  524. void eeprom_update_dword(uint32_t *addr, uint32_t value) {
  525. uint8_t *p = (uint8_t *)addr;
  526. eeprom_write_byte(p++, value);
  527. eeprom_write_byte(p++, value >> 8);
  528. eeprom_write_byte(p++, value >> 16);
  529. eeprom_write_byte(p, value >> 24);
  530. }
  531. void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
  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. }