6 /*************************************/
9 /* Code from PJRC/Teensyduino */
10 /*************************************/
12 /* Teensyduino Core Library
13 * http://www.pjrc.com/teensy/
14 * Copyright (c) 2013 PJRC.COM, LLC.
16 * Permission is hereby granted, free of charge, to any person obtaining
17 * a copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
24 * 1. The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
27 * 2. If the Software is incorporated into a build system that allows
28 * selection among a list of target devices, then similar target
29 * devices manufactured by PJRC.COM must be included in the list of
30 * target devices and selectable in the same manner.
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
36 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
37 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43 #if defined(K20x) /* chip selection */
44 /* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
46 // The EEPROM is really RAM with a hardware-based backup system to
47 // flash memory. Selecting a smaller size EEPROM allows more wear
48 // leveling, for higher write endurance. If you edit this file,
49 // set this to the smallest size your application can use. Also,
50 // due to Freescale's implementation, writing 16 or 32 bit words
51 // (aligned to 2 or 4 byte boundaries) has twice the endurance
52 // compared to writing 8 bit bytes.
54 #define EEPROM_SIZE 32
56 // Writing unaligned 16 or 32 bit data is handled automatically when
57 // this is defined, but at a cost of extra code size. Without this,
58 // any unaligned write will cause a hard fault exception! If you're
59 // absolutely sure all 16 and 32 bit writes will be aligned, you can
60 // remove the extra unnecessary code.
62 #define HANDLE_UNALIGNED_WRITES
64 // Minimum EEPROM Endurance
65 // ------------------------
66 #if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
68 #elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
70 #elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
72 #elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
74 #elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
76 #elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
78 #elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
82 /** \brief eeprom initialization
86 void eeprom_initialize(void)
89 uint16_t do_flash_cmd[] = {
90 0xf06f, 0x037f, 0x7003, 0x7803,
91 0xf013, 0x0f80, 0xd0fb, 0x4770};
94 if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
95 // FlexRAM is configured as traditional RAM
96 // We need to reconfigure for EEPROM usage
97 FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
98 FTFL->FCCOB4 = EEESIZE; // EEPROM Size
99 FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
101 // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
102 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
104 status = FTFL->FSTAT;
105 if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
106 FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
110 // wait for eeprom to become ready (is this really necessary?)
111 while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
112 if (++count > 20000) break;
116 #define FlexRAM ((uint8_t *)0x14000000)
118 /** \brief eeprom read byte
122 uint8_t eeprom_read_byte(const uint8_t *addr)
124 uint32_t offset = (uint32_t)addr;
125 if (offset >= EEPROM_SIZE) return 0;
126 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
127 return FlexRAM[offset];
130 /** \brief eeprom read word
134 uint16_t eeprom_read_word(const uint16_t *addr)
136 uint32_t offset = (uint32_t)addr;
137 if (offset >= EEPROM_SIZE-1) return 0;
138 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
139 return *(uint16_t *)(&FlexRAM[offset]);
142 /** \brief eeprom read dword
146 uint32_t eeprom_read_dword(const uint32_t *addr)
148 uint32_t offset = (uint32_t)addr;
149 if (offset >= EEPROM_SIZE-3) return 0;
150 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
151 return *(uint32_t *)(&FlexRAM[offset]);
154 /** \brief eeprom read block
158 void eeprom_read_block(void *buf, const void *addr, uint32_t len)
160 uint32_t offset = (uint32_t)addr;
161 uint8_t *dest = (uint8_t *)buf;
162 uint32_t end = offset + len;
164 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
165 if (end > EEPROM_SIZE) end = EEPROM_SIZE;
166 while (offset < end) {
167 *dest++ = FlexRAM[offset++];
171 /** \brief eeprom is ready
175 int eeprom_is_ready(void)
177 return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
180 /** \brief flexram wait
184 static void flexram_wait(void)
186 while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
191 /** \brief eeprom_write_byte
195 void eeprom_write_byte(uint8_t *addr, uint8_t value)
197 uint32_t offset = (uint32_t)addr;
199 if (offset >= EEPROM_SIZE) return;
200 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
201 if (FlexRAM[offset] != value) {
202 FlexRAM[offset] = value;
207 /** \brief eeprom write word
211 void eeprom_write_word(uint16_t *addr, uint16_t value)
213 uint32_t offset = (uint32_t)addr;
215 if (offset >= EEPROM_SIZE-1) return;
216 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
217 #ifdef HANDLE_UNALIGNED_WRITES
218 if ((offset & 1) == 0) {
220 if (*(uint16_t *)(&FlexRAM[offset]) != value) {
221 *(uint16_t *)(&FlexRAM[offset]) = value;
224 #ifdef HANDLE_UNALIGNED_WRITES
226 if (FlexRAM[offset] != value) {
227 FlexRAM[offset] = value;
230 if (FlexRAM[offset + 1] != (value >> 8)) {
231 FlexRAM[offset + 1] = value >> 8;
238 /** \brief eeprom write dword
242 void eeprom_write_dword(uint32_t *addr, uint32_t value)
244 uint32_t offset = (uint32_t)addr;
246 if (offset >= EEPROM_SIZE-3) return;
247 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
248 #ifdef HANDLE_UNALIGNED_WRITES
249 switch (offset & 3) {
252 if (*(uint32_t *)(&FlexRAM[offset]) != value) {
253 *(uint32_t *)(&FlexRAM[offset]) = value;
257 #ifdef HANDLE_UNALIGNED_WRITES
259 if (*(uint16_t *)(&FlexRAM[offset]) != value) {
260 *(uint16_t *)(&FlexRAM[offset]) = value;
263 if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
264 *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
269 if (FlexRAM[offset] != value) {
270 FlexRAM[offset] = value;
273 if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
274 *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
277 if (FlexRAM[offset + 3] != (value >> 24)) {
278 FlexRAM[offset + 3] = value >> 24;
285 /** \brief eeprom write block
289 void eeprom_write_block(const void *buf, void *addr, uint32_t len)
291 uint32_t offset = (uint32_t)addr;
292 const uint8_t *src = (const uint8_t *)buf;
294 if (offset >= EEPROM_SIZE) return;
295 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
296 if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
297 if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
299 uint32_t lsb = offset & 3;
300 if (lsb == 0 && len >= 4) {
301 // write aligned 32 bits
304 val32 |= (*src++ << 8);
305 val32 |= (*src++ << 16);
306 val32 |= (*src++ << 24);
307 if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
308 *(uint32_t *)(&FlexRAM[offset]) = val32;
313 } else if ((lsb == 0 || lsb == 2) && len >= 2) {
314 // write aligned 16 bits
317 val16 |= (*src++ << 8);
318 if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
319 *(uint16_t *)(&FlexRAM[offset]) = val16;
326 uint8_t val8 = *src++;
327 if (FlexRAM[offset] != val8) {
328 FlexRAM[offset] = val8;
338 void do_flash_cmd(volatile uint8_t *fstat)
341 while ((*fstat & 0x80) == 0) ; // wait
343 00000000 <do_flash_cmd>:
344 0: f06f 037f mvn.w r3, #127 ; 0x7f
345 4: 7003 strb r3, [r0, #0]
346 6: 7803 ldrb r3, [r0, #0]
347 8: f013 0f80 tst.w r3, #128 ; 0x80
348 c: d0fb beq.n 6 <do_flash_cmd+0x6>
352 #elif defined(KL2x) /* chip selection */
353 /* Teensy LC (emulated) */
355 #define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
357 extern uint32_t __eeprom_workarea_start__;
358 extern uint32_t __eeprom_workarea_end__;
360 #define EEPROM_SIZE 128
362 static uint32_t flashend = 0;
364 void eeprom_initialize(void)
366 const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
369 if (*p++ == 0xFFFF) {
370 flashend = (uint32_t)(p - 2);
373 } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
374 flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
377 uint8_t eeprom_read_byte(const uint8_t *addr)
379 uint32_t offset = (uint32_t)addr;
380 const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
381 const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
387 end = (const uint16_t *)((uint32_t)flashend);
389 if (offset < EEPROM_SIZE) {
392 if ((val & 255) == offset) data = val >> 8;
398 static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
400 // with great power comes great responsibility....
402 *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
403 *(uint32_t *)&(FTFA->FCCOB7) = data;
405 (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
407 stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
411 MCM->PLACR |= MCM_PLACR_CFCC;
414 void eeprom_write_byte(uint8_t *addr, uint8_t data)
416 uint32_t offset = (uint32_t)addr;
417 const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
418 uint32_t i, val, flashaddr;
419 uint16_t do_flash_cmd[] = {
420 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
421 uint8_t buf[EEPROM_SIZE];
423 if (offset >= EEPROM_SIZE) return;
426 end = (const uint16_t *)((uint32_t)flashend);
428 if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
429 val = (data << 8) | offset;
430 flashaddr = (uint32_t)end;
431 flashend = flashaddr;
432 if ((flashaddr & 2) == 0) {
438 flash_write(do_flash_cmd, flashaddr, val);
440 for (i=0; i < EEPROM_SIZE; i++) {
444 for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
446 if ((val & 255) < EEPROM_SIZE) {
447 buf[val & 255] = val >> 8;
451 for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
452 *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
454 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
456 val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
457 if (val) FTFA->FSTAT = val;
458 MCM->PLACR |= MCM_PLACR_CFCC;
460 flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
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;
466 val = val | (buf[i] << 24) | (i << 16);
467 flash_write(do_flash_cmd, flashaddr, val);
471 flashend = flashaddr;
472 if ((flashaddr & 2)) {
474 flash_write(do_flash_cmd, flashaddr, val);
480 void do_flash_cmd(volatile uint8_t *fstat)
483 while ((*fstat & 0x80) == 0) ; // wait
485 00000000 <do_flash_cmd>:
486 0: 2380 movs r3, #128 ; 0x80
487 2: 7003 strb r3, [r0, #0]
488 4: 7803 ldrb r3, [r0, #0]
491 a: dafb bge.n 4 <do_flash_cmd+0x4>
496 uint16_t eeprom_read_word(const uint16_t *addr)
498 const uint8_t *p = (const uint8_t *)addr;
499 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
502 uint32_t eeprom_read_dword(const uint32_t *addr)
504 const uint8_t *p = (const uint8_t *)addr;
505 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
506 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
509 void eeprom_read_block(void *buf, const void *addr, uint32_t len)
511 const uint8_t *p = (const uint8_t *)addr;
512 uint8_t *dest = (uint8_t *)buf;
514 *dest++ = eeprom_read_byte(p++);
518 int eeprom_is_ready(void)
523 void eeprom_write_word(uint16_t *addr, uint16_t value)
525 uint8_t *p = (uint8_t *)addr;
526 eeprom_write_byte(p++, value);
527 eeprom_write_byte(p, value >> 8);
530 void eeprom_write_dword(uint32_t *addr, uint32_t value)
532 uint8_t *p = (uint8_t *)addr;
533 eeprom_write_byte(p++, value);
534 eeprom_write_byte(p++, value >> 8);
535 eeprom_write_byte(p++, value >> 16);
536 eeprom_write_byte(p, value >> 24);
539 void eeprom_write_block(const void *buf, void *addr, uint32_t len)
541 uint8_t *p = (uint8_t *)addr;
542 const uint8_t *src = (const uint8_t *)buf;
544 eeprom_write_byte(p++, *src++);
549 // No EEPROM supported, so emulate it
551 #define EEPROM_SIZE 32
552 static uint8_t buffer[EEPROM_SIZE];
554 uint8_t eeprom_read_byte(const uint8_t *addr) {
555 uint32_t offset = (uint32_t)addr;
556 return buffer[offset];
559 void eeprom_write_byte(uint8_t *addr, uint8_t value) {
560 uint32_t offset = (uint32_t)addr;
561 buffer[offset] = value;
564 uint16_t eeprom_read_word(const uint16_t *addr) {
565 const uint8_t *p = (const uint8_t *)addr;
566 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
569 uint32_t eeprom_read_dword(const uint32_t *addr) {
570 const uint8_t *p = (const uint8_t *)addr;
571 return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
572 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
575 void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
576 const uint8_t *p = (const uint8_t *)addr;
577 uint8_t *dest = (uint8_t *)buf;
579 *dest++ = eeprom_read_byte(p++);
583 void eeprom_write_word(uint16_t *addr, uint16_t value) {
584 uint8_t *p = (uint8_t *)addr;
585 eeprom_write_byte(p++, value);
586 eeprom_write_byte(p, value >> 8);
589 void eeprom_write_dword(uint32_t *addr, uint32_t value) {
590 uint8_t *p = (uint8_t *)addr;
591 eeprom_write_byte(p++, value);
592 eeprom_write_byte(p++, value >> 8);
593 eeprom_write_byte(p++, value >> 16);
594 eeprom_write_byte(p, value >> 24);
597 void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
598 uint8_t *p = (uint8_t *)addr;
599 const uint8_t *src = (const uint8_t *)buf;
601 eeprom_write_byte(p++, *src++);
605 #endif /* chip selection */
606 // The update functions just calls write for now, but could probably be optimized
608 void eeprom_update_byte(uint8_t *addr, uint8_t value) {
609 eeprom_write_byte(addr, value);
612 void eeprom_update_word(uint16_t *addr, uint16_t value) {
613 uint8_t *p = (uint8_t *)addr;
614 eeprom_write_byte(p++, value);
615 eeprom_write_byte(p, value >> 8);
618 void eeprom_update_dword(uint32_t *addr, uint32_t value) {
619 uint8_t *p = (uint8_t *)addr;
620 eeprom_write_byte(p++, value);
621 eeprom_write_byte(p++, value >> 8);
622 eeprom_write_byte(p++, value >> 16);
623 eeprom_write_byte(p, value >> 24);
626 void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
627 uint8_t *p = (uint8_t *)addr;
628 const uint8_t *src = (const uint8_t *)buf;
630 eeprom_write_byte(p++, *src++);