summaryrefslogtreecommitdiffstats
path: root/tmk_core/common
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core/common')
-rw-r--r--tmk_core/common/action_tapping.c2
-rw-r--r--tmk_core/common/avr/sleep_led.c (renamed from tmk_core/common/sleep_led.c)0
-rw-r--r--tmk_core/common/avr/suspend.c6
-rw-r--r--tmk_core/common/bootmagic.c23
-rw-r--r--tmk_core/common/chibios/bootloader.c47
-rw-r--r--tmk_core/common/chibios/eeprom.c588
-rw-r--r--tmk_core/common/chibios/printf.c240
-rw-r--r--tmk_core/common/chibios/printf.h111
-rw-r--r--tmk_core/common/chibios/sleep_led.c226
-rw-r--r--tmk_core/common/chibios/suspend.c65
-rw-r--r--tmk_core/common/chibios/timer.c27
-rw-r--r--tmk_core/common/command.c23
-rw-r--r--tmk_core/common/eeconfig.c (renamed from tmk_core/common/avr/eeconfig.c)2
-rw-r--r--tmk_core/common/eeprom.h22
-rw-r--r--tmk_core/common/keyboard.c107
-rw-r--r--tmk_core/common/magic.c4
-rw-r--r--tmk_core/common/matrix.h57
-rw-r--r--tmk_core/common/print.c8
-rw-r--r--tmk_core/common/print.h10
-rw-r--r--tmk_core/common/progmem.h4
-rw-r--r--tmk_core/common/report.h5
-rw-r--r--tmk_core/common/wait.h8
22 files changed, 1476 insertions, 109 deletions
diff --git a/tmk_core/common/action_tapping.c b/tmk_core/common/action_tapping.c
index ff78d7f2ab..e16e11be7f 100644
--- a/tmk_core/common/action_tapping.c
+++ b/tmk_core/common/action_tapping.c
@@ -257,7 +257,7 @@ bool process_tapping(keyrecord_t *keyp)
return true;
}
} else {
- if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n");
+ if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n") {};
process_record(keyp);
return true;
}
diff --git a/tmk_core/common/sleep_led.c b/tmk_core/common/avr/sleep_led.c
index dab3eb0f3c..dab3eb0f3c 100644
--- a/tmk_core/common/sleep_led.c
+++ b/tmk_core/common/avr/sleep_led.c
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c
index a6f3c64414..8a7272bbc5 100644
--- a/tmk_core/common/avr/suspend.c
+++ b/tmk_core/common/avr/suspend.c
@@ -114,8 +114,10 @@ bool suspend_wakeup_condition(void)
matrix_power_up();
matrix_scan();
matrix_power_down();
- if (matrix_key_count()) return true;
- return false;
+ for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+ if (matrix_get_row(r)) return true;
+ }
+ return false;
}
// run immediately after wakeup
diff --git a/tmk_core/common/bootmagic.c b/tmk_core/common/bootmagic.c
index 30e8a0f20f..6730a2a4aa 100644
--- a/tmk_core/common/bootmagic.c
+++ b/tmk_core/common/bootmagic.c
@@ -1,6 +1,6 @@
#include <stdint.h>
#include <stdbool.h>
-#include <util/delay.h>
+#include "wait.h"
#include "matrix.h"
#include "bootloader.h"
#include "debug.h"
@@ -10,6 +10,7 @@
#include "eeconfig.h"
#include "bootmagic.h"
+keymap_config_t keymap_config;
void bootmagic(void)
{
@@ -19,9 +20,9 @@ void bootmagic(void)
}
/* do scans in case of bounce */
- print("boogmagic scan: ... ");
+ print("bootmagic scan: ... ");
uint8_t scan = 100;
- while (scan--) { matrix_scan(); _delay_ms(10); }
+ while (scan--) { matrix_scan(); wait_ms(10); }
print("done.\n");
/* bootmagic skip */
@@ -105,13 +106,15 @@ void bootmagic(void)
}
}
-static bool scan_keycode(uint8_t keycode) {
- for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
+static bool scan_keycode(uint8_t keycode)
+{
+ for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
matrix_row_t matrix_row = matrix_get_row(r);
- for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
- if (matrix_row & (matrix_row_t)1 << c) {
- keypos_t key = (keypos_t){ .row = r, .col = c };
- if (keycode == keymap_key_to_keycode(0, key)) return true;
+ for (uint8_t c = 0; c < MATRIX_COLS; c++) {
+ if (matrix_row & ((matrix_row_t)1<<c)) {
+ if (keycode == keymap_key_to_keycode(0, (keypos_t){ .row = r, .col = c })) {
+ return true;
+ }
}
}
}
@@ -123,4 +126,4 @@ bool bootmagic_scan_keycode(uint8_t keycode)
if (!scan_keycode(BOOTMAGIC_KEY_SALT)) return false;
return scan_keycode(keycode);
-}
+} \ No newline at end of file
diff --git a/tmk_core/common/chibios/bootloader.c b/tmk_core/common/chibios/bootloader.c
new file mode 100644
index 0000000000..8a533ab6f6
--- /dev/null
+++ b/tmk_core/common/chibios/bootloader.c
@@ -0,0 +1,47 @@
+#include "bootloader.h"
+
+#include "ch.h"
+#include "hal.h"
+
+#ifdef STM32_BOOTLOADER_ADDRESS
+/* STM32 */
+
+#if defined(STM32F0XX)
+/* This code should be checked whether it runs correctly on platforms */
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+extern uint32_t __ram0_end__;
+
+void bootloader_jump(void) {
+ *((unsigned long *)(SYMVAL(__ram0_end__) - 4)) = 0xDEADBEEF; // set magic flag => reset handler will jump into boot loader
+ NVIC_SystemReset();
+}
+
+#else /* defined(STM32F0XX) */
+#error Check that the bootloader code works on your platform and add it to bootloader.c!
+#endif /* defined(STM32F0XX) */
+
+#elif defined(KL2x) || defined(K20x) /* STM32_BOOTLOADER_ADDRESS */
+/* Kinetis */
+
+#if defined(KIIBOHD_BOOTLOADER)
+/* Kiibohd Bootloader (MCHCK and Infinity KB) */
+#define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
+const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
+void bootloader_jump(void) {
+ __builtin_memcpy((void *)VBAT, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
+ // request reset
+ SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
+}
+
+#else /* defined(KIIBOHD_BOOTLOADER) */
+/* Default for Kinetis - expecting an ARM Teensy */
+void bootloader_jump(void) {
+ chThdSleepMilliseconds(100);
+ __BKPT(0);
+}
+#endif /* defined(KIIBOHD_BOOTLOADER) */
+
+#else /* neither STM32 nor KINETIS */
+__attribute__((weak))
+void bootloader_jump(void) {}
+#endif \ No newline at end of file
diff --git a/tmk_core/common/chibios/eeprom.c b/tmk_core/common/chibios/eeprom.c
new file mode 100644
index 0000000000..5ff8ee86f4
--- /dev/null
+++ b/tmk_core/common/chibios/eeprom.c
@@ -0,0 +1,588 @@
+#include "ch.h"
+#include "hal.h"
+
+#include "eeconfig.h"
+
+/*************************************/
+/* Hardware backend */
+/* */
+/* Code from PJRC/Teensyduino */
+/*************************************/
+
+/* Teensyduino Core Library
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2013 PJRC.COM, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 2. If the Software is incorporated into a build system that allows
+ * selection among a list of target devices, then similar target
+ * devices manufactured by PJRC.COM must be included in the list of
+ * target devices and selectable in the same manner.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#if defined(K20x) /* chip selection */
+/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
+
+// The EEPROM is really RAM with a hardware-based backup system to
+// flash memory. Selecting a smaller size EEPROM allows more wear
+// leveling, for higher write endurance. If you edit this file,
+// set this to the smallest size your application can use. Also,
+// due to Freescale's implementation, writing 16 or 32 bit words
+// (aligned to 2 or 4 byte boundaries) has twice the endurance
+// compared to writing 8 bit bytes.
+//
+#define EEPROM_SIZE 32
+
+// Writing unaligned 16 or 32 bit data is handled automatically when
+// this is defined, but at a cost of extra code size. Without this,
+// any unaligned write will cause a hard fault exception! If you're
+// absolutely sure all 16 and 32 bit writes will be aligned, you can
+// remove the extra unnecessary code.
+//
+#define HANDLE_UNALIGNED_WRITES
+
+// Minimum EEPROM Endurance
+// ------------------------
+#if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
+ #define EEESIZE 0x33
+#elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
+ #define EEESIZE 0x34
+#elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
+ #define EEESIZE 0x35
+#elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
+ #define EEESIZE 0x36
+#elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
+ #define EEESIZE 0x37
+#elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
+ #define EEESIZE 0x38
+#elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
+ #define EEESIZE 0x39
+#endif
+
+void eeprom_initialize(void)
+{
+ uint32_t count=0;
+ uint16_t do_flash_cmd[] = {
+ 0xf06f, 0x037f, 0x7003, 0x7803,
+ 0xf013, 0x0f80, 0xd0fb, 0x4770};
+ uint8_t status;
+
+ if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
+ // FlexRAM is configured as traditional RAM
+ // We need to reconfigure for EEPROM usage
+ FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
+ FTFL->FCCOB4 = EEESIZE; // EEPROM Size
+ FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
+ __disable_irq();
+ // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
+ (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
+ __enable_irq();
+ status = FTFL->FSTAT;
+ if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
+ FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
+ return; // error
+ }
+ }
+ // wait for eeprom to become ready (is this really necessary?)
+ while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+ if (++count > 20000) break;
+ }
+}
+
+#define FlexRAM ((uint8_t *)0x14000000)
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+ uint32_t offset = (uint32_t)addr;
+ if (offset >= EEPROM_SIZE) return 0;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ return FlexRAM[offset];
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+ uint32_t offset = (uint32_t)addr;
+ if (offset >= EEPROM_SIZE-1) return 0;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ return *(uint16_t *)(&FlexRAM[offset]);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+ uint32_t offset = (uint32_t)addr;
+ if (offset >= EEPROM_SIZE-3) return 0;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ return *(uint32_t *)(&FlexRAM[offset]);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+ uint32_t offset = (uint32_t)addr;
+ uint8_t *dest = (uint8_t *)buf;
+ uint32_t end = offset + len;
+
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ if (end > EEPROM_SIZE) end = EEPROM_SIZE;
+ while (offset < end) {
+ *dest++ = FlexRAM[offset++];
+ }
+}
+
+int eeprom_is_ready(void)
+{
+ return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
+}
+
+static void flexram_wait(void)
+{
+ while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+ // TODO: timeout
+ }
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value)
+{
+ uint32_t offset = (uint32_t)addr;
+
+ if (offset >= EEPROM_SIZE) return;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ if (FlexRAM[offset] != value) {
+ FlexRAM[offset] = value;
+ flexram_wait();
+ }
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+ uint32_t offset = (uint32_t)addr;
+
+ if (offset >= EEPROM_SIZE-1) return;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+ if ((offset & 1) == 0) {
+#endif
+ if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+ *(uint16_t *)(&FlexRAM[offset]) = value;
+ flexram_wait();
+ }
+#ifdef HANDLE_UNALIGNED_WRITES
+ } else {
+ if (FlexRAM[offset] != value) {
+ FlexRAM[offset] = value;
+ flexram_wait();
+ }
+ if (FlexRAM[offset + 1] != (value >> 8)) {
+ FlexRAM[offset + 1] = value >> 8;
+ flexram_wait();
+ }
+ }
+#endif
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+ uint32_t offset = (uint32_t)addr;
+
+ if (offset >= EEPROM_SIZE-3) return;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+ switch (offset & 3) {
+ case 0:
+#endif
+ if (*(uint32_t *)(&FlexRAM[offset]) != value) {
+ *(uint32_t *)(&FlexRAM[offset]) = value;
+ flexram_wait();
+ }
+ return;
+#ifdef HANDLE_UNALIGNED_WRITES
+ case 2:
+ if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+ *(uint16_t *)(&FlexRAM[offset]) = value;
+ flexram_wait();
+ }
+ if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
+ *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
+ flexram_wait();
+ }
+ return;
+ default:
+ if (FlexRAM[offset] != value) {
+ FlexRAM[offset] = value;
+ flexram_wait();
+ }
+ if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
+ *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
+ flexram_wait();
+ }
+ if (FlexRAM[offset + 3] != (value >> 24)) {
+ FlexRAM[offset + 3] = value >> 24;
+ flexram_wait();
+ }
+ }
+#endif
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+ uint32_t offset = (uint32_t)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+
+ if (offset >= EEPROM_SIZE) return;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
+ if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
+ while (len > 0) {
+ uint32_t lsb = offset & 3;
+ if (lsb == 0 && len >= 4) {
+ // write aligned 32 bits
+ uint32_t val32;
+ val32 = *src++;
+ val32 |= (*src++ << 8);
+ val32 |= (*src++ << 16);
+ val32 |= (*src++ << 24);
+ if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
+ *(uint32_t *)(&FlexRAM[offset]) = val32;
+ flexram_wait();
+ }
+ offset += 4;
+ len -= 4;
+ } else if ((lsb == 0 || lsb == 2) && len >= 2) {
+ // write aligned 16 bits
+ uint16_t val16;
+ val16 = *src++;
+ val16 |= (*src++ << 8);
+ if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
+ *(uint16_t *)(&FlexRAM[offset]) = val16;
+ flexram_wait();
+ }
+ offset += 2;
+ len -= 2;
+ } else {
+ // write 8 bits
+ uint8_t val8 = *src++;
+ if (FlexRAM[offset] != val8) {
+ FlexRAM[offset] = val8;
+ flexram_wait();
+ }
+ offset++;
+ len--;
+ }
+ }
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+ *fstat = 0x80;
+ while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+ 0: f06f 037f mvn.w r3, #127 ; 0x7f
+ 4: 7003 strb r3, [r0, #0]
+ 6: 7803 ldrb r3, [r0, #0]
+ 8: f013 0f80 tst.w r3, #128 ; 0x80
+ c: d0fb beq.n 6 <do_flash_cmd+0x6>
+ e: 4770 bx lr
+*/
+
+#elif defined(KL2x) /* chip selection */
+/* Teensy LC (emulated) */
+
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+
+extern uint32_t __eeprom_workarea_start__;
+extern uint32_t __eeprom_workarea_end__;
+
+#define EEPROM_SIZE 128
+
+static uint32_t flashend = 0;
+
+void eeprom_initialize(void)
+{
+ const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+
+ do {
+ if (*p++ == 0xFFFF) {
+ flashend = (uint32_t)(p - 2);
+ return;
+ }
+ } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
+ flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
+}
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+ uint32_t offset = (uint32_t)addr;
+ const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+ const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
+ uint16_t val;
+ uint8_t data=0xFF;
+
+ if (!end) {
+ eeprom_initialize();
+ end = (const uint16_t *)((uint32_t)flashend);
+ }
+ if (offset < EEPROM_SIZE) {
+ while (p <= end) {
+ val = *p++;
+ if ((val & 255) == offset) data = val >> 8;
+ }
+ }
+ return data;
+}
+
+static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
+{
+ // with great power comes great responsibility....
+ uint32_t stat;
+ *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
+ *(uint32_t *)&(FTFA->FCCOB7) = data;
+ __disable_irq();
+ (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
+ __enable_irq();
+ stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
+ if (stat) {
+ FTFA->FSTAT = stat;
+ }
+ MCM->PLACR |= MCM_PLACR_CFCC;
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t data)
+{
+ uint32_t offset = (uint32_t)addr;
+ const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
+ uint32_t i, val, flashaddr;
+ uint16_t do_flash_cmd[] = {
+ 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
+ uint8_t buf[EEPROM_SIZE];
+
+ if (offset >= EEPROM_SIZE) return;
+ if (!end) {
+ eeprom_initialize();
+ end = (const uint16_t *)((uint32_t)flashend);
+ }
+ if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
+ val = (data << 8) | offset;
+ flashaddr = (uint32_t)end;
+ flashend = flashaddr;
+ if ((flashaddr & 2) == 0) {
+ val |= 0xFFFF0000;
+ } else {
+ val <<= 16;
+ val |= 0x0000FFFF;
+ }
+ flash_write(do_flash_cmd, flashaddr, val);
+ } else {
+ for (i=0; i < EEPROM_SIZE; i++) {
+ buf[i] = 0xFF;
+ }
+ val = 0;
+ for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
+ val = *p;
+ if ((val & 255) < EEPROM_SIZE) {
+ buf[val & 255] = val >> 8;
+ }
+ }
+ buf[offset] = data;
+ for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
+ *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
+ __disable_irq();
+ (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
+ __enable_irq();
+ val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
+ if (val) FTFA->FSTAT = val;
+ MCM->PLACR |= MCM_PLACR_CFCC;
+ }
+ flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
+ for (i=0; i < EEPROM_SIZE; i++) {
+ if (buf[i] == 0xFF) continue;
+ if ((flashaddr & 2) == 0) {
+ val = (buf[i] << 8) | i;
+ } else {
+ val = val | (buf[i] << 24) | (i << 16);
+ flash_write(do_flash_cmd, flashaddr, val);
+ }
+ flashaddr += 2;
+ }
+ flashend = flashaddr;
+ if ((flashaddr & 2)) {
+ val |= 0xFFFF0000;
+ flash_write(do_flash_cmd, flashaddr, val);
+ }
+ }
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+ *fstat = 0x80;
+ while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+ 0: 2380 movs r3, #128 ; 0x80
+ 2: 7003 strb r3, [r0, #0]
+ 4: 7803 ldrb r3, [r0, #0]
+ 6: b25b sxtb r3, r3
+ 8: 2b00 cmp r3, #0
+ a: dafb bge.n 4 <do_flash_cmd+0x4>
+ c: 4770 bx lr
+*/
+
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+ | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+ const uint8_t *p = (const uint8_t *)addr;
+ uint8_t *dest = (uint8_t *)buf;
+ while (len--) {
+ *dest++ = eeprom_read_byte(p++);
+ }
+}
+
+int eeprom_is_ready(void)
+{
+ return 1;
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p++, value >> 8);
+ eeprom_write_byte(p++, value >> 16);
+ eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+ uint8_t *p = (uint8_t *)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+ while (len--) {
+ eeprom_write_byte(p++, *src++);
+ }
+}
+
+#else
+// No EEPROM supported, so emulate it
+
+#define EEPROM_SIZE 32
+static uint8_t buffer[EEPROM_SIZE];
+
+uint8_t eeprom_read_byte(const uint8_t *addr) {
+ uint32_t offset = (uint32_t)addr;
+ return buffer[offset];
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value) {
+ uint32_t offset = (uint32_t)addr;
+ buffer[offset] = value;
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr) {
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr) {
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+ | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
+ const uint8_t *p = (const uint8_t *)addr;
+ uint8_t *dest = (uint8_t *)buf;
+ while (len--) {
+ *dest++ = eeprom_read_byte(p++);
+ }
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p++, value >> 8);
+ eeprom_write_byte(p++, value >> 16);
+ eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
+ uint8_t *p = (uint8_t *)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+ while (len--) {
+ eeprom_write_byte(p++, *src++);
+ }
+}
+
+#endif /* chip selection */
+// The update functions just calls write for now, but could probably be optimized
+
+void eeprom_update_byte(uint8_t *addr, uint8_t value) {
+ eeprom_write_byte(addr, value);
+}
+
+void eeprom_update_word(uint16_t *addr, uint16_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_update_dword(uint32_t *addr, uint32_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p++, value >> 8);
+ eeprom_write_byte(p++, value >> 16);
+ eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
+ uint8_t *p = (uint8_t *)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+ while (len--) {
+ eeprom_write_byte(p++, *src++);
+ }
+}
diff --git a/tmk_core/common/chibios/printf.c b/tmk_core/common/chibios/printf.c
new file mode 100644
index 0000000000..72e3d4f8c4
--- /dev/null
+++ b/tmk_core/common/chibios/printf.c
@@ -0,0 +1,240 @@
+/*
+ * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * and: http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
+ */
+
+/*
+File: printf.c
+
+Copyright (C) 2004 Kustaa Nyholm
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "printf.h"
+
+typedef void (*putcf) (void*,char);
+static putcf stdout_putf;
+static void* stdout_putp;
+
+// this adds cca 400 bytes
+#define PRINTF_LONG_SUPPORT
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%=d;
+ d/=base;
+ if (n || dgt>0|| d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void li2a (long num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ uli2a(num,10,0,bf);
+ }
+
+#endif
+
+static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%= d;
+ d/=base;
+ if (n || dgt>0 || d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void i2a (int num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ ui2a(num,10,0,bf);
+ }
+
+static int a2d(char ch)
+ {
+ if (ch>='0' && ch<='9')
+ return ch-'0';
+ else if (ch>='a' && ch<='f')
+ return ch-'a'+10;
+ else if (ch>='A' && ch<='F')
+ return ch-'A'+10;
+ else return -1;
+ }
+
+static char a2i(char ch, char** src,int base,int* nump)
+ {
+ char* p= *src;
+ int num=0;
+ int digit;
+ while ((digit=a2d(ch))>=0) {
+ if (digit>base) break;
+ num=num*base+digit;
+ ch=*p++;
+ }
+ *src=p;
+ *nump=num;
+ return ch;
+ }
+
+static void putchw(void* putp,putcf putf,int n, char z, char* bf)
+ {
+ char fc=z? '0' : ' ';
+ char ch;
+ char* p=bf;
+ while (*p++ && n > 0)
+ n--;
+ while (n-- > 0)
+ putf(putp,fc);
+ while ((ch= *bf++))
+ putf(putp,ch);
+ }
+
+void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
+ {
+ char bf[12];
+
+ char ch;
+
+
+ while ((ch=*(fmt++))) {
+ if (ch!='%')
+ putf(putp,ch);
+ else {
+ char lz=0;
+#ifdef PRINTF_LONG_SUPPORT
+ char lng=0;
+#endif
+ int w=0;
+ ch=*(fmt++);
+ if (ch=='0') {
+ ch=*(fmt++);
+ lz=1;
+ }
+ if (ch>='0' && ch<='9') {
+ ch=a2i(ch,&fmt,10,&w);
+ }
+#ifdef PRINTF_LONG_SUPPORT
+ if (ch=='l') {
+ ch=*(fmt++);
+ lng=1;
+ }
+#endif
+ switch (ch) {
+ case 0:
+ goto abort;
+ case 'u' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),10,0,bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),10,0,bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'd' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ li2a(va_arg(va, unsigned long int),bf);
+ else
+#endif
+ i2a(va_arg(va, int),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'x': case 'X' :
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ case 'c' :
+ putf(putp,(char)(va_arg(va, int)));
+ break;
+ case 's' :
+ putchw(putp,putf,w,0,va_arg(va, char*));
+ break;
+ case '%' :
+ putf(putp,ch);
+ default:
+ break;
+ }
+ }
+ }
+ abort:;
+ }
+
+
+void init_printf(void* putp,void (*putf) (void*,char))
+ {
+ stdout_putf=putf;
+ stdout_putp=putp;
+ }
+
+void tfp_printf(char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(stdout_putp,stdout_putf,fmt,va);
+ va_end(va);
+ }
+
+static void putcp(void* p,char c)
+ {
+ *(*((char**)p))++ = c;
+ }
+
+
+</