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 void eeprom_initialize(void)
85 uint16_t do_flash_cmd
[] = {
86 0xf06f, 0x037f, 0x7003, 0x7803,
87 0xf013, 0x0f80, 0xd0fb, 0x4770};
90 if (FTFL
->FCNFG
& FTFL_FCNFG_RAMRDY
) {
91 // FlexRAM is configured as traditional RAM
92 // We need to reconfigure for EEPROM usage
93 FTFL
->FCCOB0
= 0x80; // PGMPART = Program Partition Command
94 FTFL
->FCCOB4
= EEESIZE
; // EEPROM Size
95 FTFL
->FCCOB5
= 0x03; // 0K for Dataflash, 32K for EEPROM backup
97 // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
98 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd
| 1)))(&(FTFL
->FSTAT
));
100 status
= FTFL
->FSTAT
;
101 if (status
& (FTFL_FSTAT_RDCOLERR
|FTFL_FSTAT_ACCERR
|FTFL_FSTAT_FPVIOL
)) {
102 FTFL
->FSTAT
= (status
& (FTFL_FSTAT_RDCOLERR
|FTFL_FSTAT_ACCERR
|FTFL_FSTAT_FPVIOL
));
106 // wait for eeprom to become ready (is this really necessary?)
107 while (!(FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
)) {
108 if (++count
> 20000) break;
112 #define FlexRAM ((uint8_t *)0x14000000)
114 uint8_t eeprom_read_byte(const uint8_t *addr
)
116 uint32_t offset
= (uint32_t)addr
;
117 if (offset
>= EEPROM_SIZE
) return 0;
118 if (!(FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
)) eeprom_initialize();
119 return FlexRAM
[offset
];
122 uint16_t eeprom_read_word(const uint16_t *addr
)
124 uint32_t offset
= (uint32_t)addr
;
125 if (offset
>= EEPROM_SIZE
-1) return 0;
126 if (!(FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
)) eeprom_initialize();
127 return *(uint16_t *)(&FlexRAM
[offset
]);
130 uint32_t eeprom_read_dword(const uint32_t *addr
)
132 uint32_t offset
= (uint32_t)addr
;
133 if (offset
>= EEPROM_SIZE
-3) return 0;
134 if (!(FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
)) eeprom_initialize();
135 return *(uint32_t *)(&FlexRAM
[offset
]);
138 void eeprom_read_block(void *buf
, const void *addr
, uint32_t len
)
140 uint32_t offset
= (uint32_t)addr
;
141 uint8_t *dest
= (uint8_t *)buf
;
142 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
++];
151 int eeprom_is_ready(void)
153 return (FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
) ? 1 : 0;
156 static void flexram_wait(void)
158 while (!(FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
)) {
163 void eeprom_write_byte(uint8_t *addr
, uint8_t value
)
165 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
;
175 void eeprom_write_word(uint16_t *addr
, uint16_t value
)
177 uint32_t offset
= (uint32_t)addr
;
179 if (offset
>= EEPROM_SIZE
-1) return;
180 if (!(FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
)) eeprom_initialize();
181 #ifdef HANDLE_UNALIGNED_WRITES
182 if ((offset
& 1) == 0) {
184 if (*(uint16_t *)(&FlexRAM
[offset
]) != value
) {
185 *(uint16_t *)(&FlexRAM
[offset
]) = value
;
188 #ifdef HANDLE_UNALIGNED_WRITES
190 if (FlexRAM
[offset
] != value
) {
191 FlexRAM
[offset
] = value
;
194 if (FlexRAM
[offset
+ 1] != (value
>> 8)) {
195 FlexRAM
[offset
+ 1] = value
>> 8;
202 void eeprom_write_dword(uint32_t *addr
, uint32_t value
)
204 uint32_t offset
= (uint32_t)addr
;
206 if (offset
>= EEPROM_SIZE
-3) return;
207 if (!(FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
)) eeprom_initialize();
208 #ifdef HANDLE_UNALIGNED_WRITES
209 switch (offset
& 3) {
212 if (*(uint32_t *)(&FlexRAM
[offset
]) != value
) {
213 *(uint32_t *)(&FlexRAM
[offset
]) = value
;
217 #ifdef HANDLE_UNALIGNED_WRITES
219 if (*(uint16_t *)(&FlexRAM
[offset
]) != value
) {
220 *(uint16_t *)(&FlexRAM
[offset
]) = value
;
223 if (*(uint16_t *)(&FlexRAM
[offset
+ 2]) != (value
>> 16)) {
224 *(uint16_t *)(&FlexRAM
[offset
+ 2]) = value
>> 16;
229 if (FlexRAM
[offset
] != value
) {
230 FlexRAM
[offset
] = value
;
233 if (*(uint16_t *)(&FlexRAM
[offset
+ 1]) != (value
>> 8)) {
234 *(uint16_t *)(&FlexRAM
[offset
+ 1]) = value
>> 8;
237 if (FlexRAM
[offset
+ 3] != (value
>> 24)) {
238 FlexRAM
[offset
+ 3] = value
>> 24;
245 void eeprom_write_block(const void *buf
, void *addr
, uint32_t len
)
247 uint32_t offset
= (uint32_t)addr
;
248 const uint8_t *src
= (const uint8_t *)buf
;
250 if (offset
>= EEPROM_SIZE
) return;
251 if (!(FTFL
->FCNFG
& FTFL_FCNFG_EEERDY
)) eeprom_initialize();
252 if (len
>= EEPROM_SIZE
) len
= EEPROM_SIZE
;
253 if (offset
+ len
>= EEPROM_SIZE
) len
= EEPROM_SIZE
- offset
;
255 uint32_t lsb
= offset
& 3;
256 if (lsb
== 0 && len
>= 4) {
257 // write aligned 32 bits
260 val32
|= (*src
++ << 8);
261 val32
|= (*src
++ << 16);
262 val32
|= (*src
++ << 24);
263 if (*(uint32_t *)(&FlexRAM
[offset
]) != val32
) {
264 *(uint32_t *)(&FlexRAM
[offset
]) = val32
;
269 } else if ((lsb
== 0 || lsb
== 2) && len
>= 2) {
270 // write aligned 16 bits
273 val16
|= (*src
++ << 8);
274 if (*(uint16_t *)(&FlexRAM
[offset
]) != val16
) {
275 *(uint16_t *)(&FlexRAM
[offset
]) = val16
;
282 uint8_t val8
= *src
++;
283 if (FlexRAM
[offset
] != val8
) {
284 FlexRAM
[offset
] = val8
;
294 void do_flash_cmd(volatile uint8_t *fstat)
297 while ((*fstat & 0x80) == 0) ; // wait
299 00000000 <do_flash_cmd>:
300 0: f06f 037f mvn.w r3, #127 ; 0x7f
301 4: 7003 strb r3, [r0, #0]
302 6: 7803 ldrb r3, [r0, #0]
303 8: f013 0f80 tst.w r3, #128 ; 0x80
304 c: d0fb beq.n 6 <do_flash_cmd+0x6>
308 #elif defined(KL2x) /* chip selection */
309 /* Teensy LC (emulated) */
311 #define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
313 extern uint32_t __eeprom_workarea_start__
;
314 extern uint32_t __eeprom_workarea_end__
;
316 #define EEPROM_SIZE 128
318 static uint32_t flashend
= 0;
320 void eeprom_initialize(void)
322 const uint16_t *p
= (uint16_t *)SYMVAL(__eeprom_workarea_start__
);
325 if (*p
++ == 0xFFFF) {
326 flashend
= (uint32_t)(p
- 2);
329 } while (p
< (uint16_t *)SYMVAL(__eeprom_workarea_end__
));
330 flashend
= (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__
) - 1);
333 uint8_t eeprom_read_byte(const uint8_t *addr
)
335 uint32_t offset
= (uint32_t)addr
;
336 const uint16_t *p
= (uint16_t *)SYMVAL(__eeprom_workarea_start__
);
337 const uint16_t *end
= (const uint16_t *)((uint32_t)flashend
);
343 end
= (const uint16_t *)((uint32_t)flashend
);
345 if (offset
< EEPROM_SIZE
) {
348 if ((val
& 255) == offset
) data
= val
>> 8;
354 static void flash_write(const uint16_t *code
, uint32_t addr
, uint32_t data
)
356 // with great power comes great responsibility....
358 *(uint32_t *)&(FTFA
->FCCOB3
) = 0x06000000 | (addr
& 0x00FFFFFC);
359 *(uint32_t *)&(FTFA
->FCCOB7
) = data
;
361 (*((void (*)(volatile uint8_t *))((uint32_t)code
| 1)))(&(FTFA
->FSTAT
));
363 stat
= FTFA
->FSTAT
& (FTFA_FSTAT_RDCOLERR
|FTFA_FSTAT_ACCERR
|FTFA_FSTAT_FPVIOL
);
367 MCM
->PLACR
|= MCM_PLACR_CFCC
;
370 void eeprom_write_byte(uint8_t *addr
, uint8_t data
)
372 uint32_t offset
= (uint32_t)addr
;
373 const uint16_t *p
, *end
= (const uint16_t *)((uint32_t)flashend
);
374 uint32_t i
, val
, flashaddr
;
375 uint16_t do_flash_cmd
[] = {
376 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
377 uint8_t buf
[EEPROM_SIZE
];
379 if (offset
>= EEPROM_SIZE
) return;
382 end
= (const uint16_t *)((uint32_t)flashend
);
384 if (++end
< (uint16_t *)SYMVAL(__eeprom_workarea_end__
)) {
385 val
= (data
<< 8) | offset
;
386 flashaddr
= (uint32_t)end
;
387 flashend
= flashaddr
;
388 if ((flashaddr
& 2) == 0) {
394 flash_write(do_flash_cmd
, flashaddr
, val
);
396 for (i
=0; i
< EEPROM_SIZE
; i
++) {
399 for (p
= (uint16_t *)SYMVAL(__eeprom_workarea_start__
); p
< (uint16_t *)SYMVAL(__eeprom_workarea_end__
); p
++) {
401 if ((val
& 255) < EEPROM_SIZE
) {
402 buf
[val
& 255] = val
>> 8;
406 for (flashaddr
=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__
); flashaddr
< (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__
); flashaddr
+= 1024) {
407 *(uint32_t *)&(FTFA
->FCCOB3
) = 0x09000000 | flashaddr
;
409 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd
| 1)))(&(FTFA
->FSTAT
));
411 val
= FTFA
->FSTAT
& (FTFA_FSTAT_RDCOLERR
|FTFA_FSTAT_ACCERR
|FTFA_FSTAT_FPVIOL
);;
412 if (val
) FTFA
->FSTAT
= val
;
413 MCM
->PLACR
|= MCM_PLACR_CFCC
;
415 flashaddr
=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__
);
416 for (i
=0; i
< EEPROM_SIZE
; i
++) {
417 if (buf
[i
] == 0xFF) continue;
418 if ((flashaddr
& 2) == 0) {
419 val
= (buf
[i
] << 8) | i
;
421 val
= val
| (buf
[i
] << 24) | (i
<< 16);
422 flash_write(do_flash_cmd
, flashaddr
, val
);
426 flashend
= flashaddr
;
427 if ((flashaddr
& 2)) {
429 flash_write(do_flash_cmd
, flashaddr
, val
);
435 void do_flash_cmd(volatile uint8_t *fstat)
438 while ((*fstat & 0x80) == 0) ; // wait
440 00000000 <do_flash_cmd>:
441 0: 2380 movs r3, #128 ; 0x80
442 2: 7003 strb r3, [r0, #0]
443 4: 7803 ldrb r3, [r0, #0]
446 a: dafb bge.n 4 <do_flash_cmd+0x4>
451 uint16_t eeprom_read_word(const uint16_t *addr
)
453 const uint8_t *p
= (const uint8_t *)addr
;
454 return eeprom_read_byte(p
) | (eeprom_read_byte(p
+1) << 8);
457 uint32_t eeprom_read_dword(const uint32_t *addr
)
459 const uint8_t *p
= (const uint8_t *)addr
;
460 return eeprom_read_byte(p
) | (eeprom_read_byte(p
+1) << 8)
461 | (eeprom_read_byte(p
+2) << 16) | (eeprom_read_byte(p
+3) << 24);
464 void eeprom_read_block(void *buf
, const void *addr
, uint32_t len
)
466 const uint8_t *p
= (const uint8_t *)addr
;
467 uint8_t *dest
= (uint8_t *)buf
;
469 *dest
++ = eeprom_read_byte(p
++);
473 int eeprom_is_ready(void)
478 void eeprom_write_word(uint16_t *addr
, uint16_t value
)
480 uint8_t *p
= (uint8_t *)addr
;
481 eeprom_write_byte(p
++, value
);
482 eeprom_write_byte(p
, value
>> 8);
485 void eeprom_write_dword(uint32_t *addr
, uint32_t value
)
487 uint8_t *p
= (uint8_t *)addr
;
488 eeprom_write_byte(p
++, value
);
489 eeprom_write_byte(p
++, value
>> 8);
490 eeprom_write_byte(p
++, value
>> 16);
491 eeprom_write_byte(p
, value
>> 24);
494 void eeprom_write_block(const void *buf
, void *addr
, uint32_t len
)
496 uint8_t *p
= (uint8_t *)addr
;
497 const uint8_t *src
= (const uint8_t *)buf
;
499 eeprom_write_byte(p
++, *src
++);
504 #error EEPROM support not implemented for your chip
505 #endif /* chip selection */
512 void eeconfig_init(void)
514 eeprom_write_word(EECONFIG_MAGIC
, EECONFIG_MAGIC_NUMBER
);
515 eeprom_write_byte(EECONFIG_DEBUG
, 0);
516 eeprom_write_byte(EECONFIG_DEFAULT_LAYER
, 0);
517 eeprom_write_byte(EECONFIG_KEYMAP
, 0);
518 eeprom_write_byte(EECONFIG_MOUSEKEY_ACCEL
, 0);
519 #ifdef BACKLIGHT_ENABLE
520 eeprom_write_byte(EECONFIG_BACKLIGHT
, 0);
524 void eeconfig_enable(void)
526 eeprom_write_word(EECONFIG_MAGIC
, EECONFIG_MAGIC_NUMBER
);
529 void eeconfig_disable(void)
531 eeprom_write_word(EECONFIG_MAGIC
, 0xFFFF);
534 bool eeconfig_is_enabled(void)
536 return (eeprom_read_word(EECONFIG_MAGIC
) == EECONFIG_MAGIC_NUMBER
);
539 uint8_t eeconfig_read_debug(void) { return eeprom_read_byte(EECONFIG_DEBUG
); }
540 void eeconfig_write_debug(uint8_t val
) { eeprom_write_byte(EECONFIG_DEBUG
, val
); }
542 uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER
); }
543 void eeconfig_write_default_layer(uint8_t val
) { eeprom_write_byte(EECONFIG_DEFAULT_LAYER
, val
); }
545 uint8_t eeconfig_read_keymap(void) { return eeprom_read_byte(EECONFIG_KEYMAP
); }
546 void eeconfig_write_keymap(uint8_t val
) { eeprom_write_byte(EECONFIG_KEYMAP
, val
); }
548 #ifdef BACKLIGHT_ENABLE
549 uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BACKLIGHT
); }
550 void eeconfig_write_backlight(uint8_t val
) { eeprom_write_byte(EECONFIG_BACKLIGHT
, val
); }