Squashed 'tmk_core/' changes from 57d27a8..08ce4c3

08ce4c3 Add update for chibios in README
30cac1d Merge remote-tracking branch 'flabbergast-tmk_keyboard/chibios'
f218a38 core: Remove unused warning. Fix tmk_keyboard/#293
3e68807 Chibios: add more guards for transmitting (fix a deadlock bug).
cecc807 core: Speed up compilation
d01d959 Merge remote-tracking branch 'upstream/master' into chibios
8ff12ae Merge pull request #230 from jerryen/master
3afb83d core: Add note about sudo and git
2525d5d Chibios: Update to new USB API.
2fc5cd6 Merge branch 'master' into chibios
6f5511a core: Fix variable initialize
02a15fa core: Fix variable init and header include
1833ca1 Merge pull request #292 from obones/command_warning
bc9dc6f Merge pull request #294 from shayneholmes/fix-debug-message
c1b891b Merge pull request #295 from doopai/master
1da837c core: Add macro commands SM(), RM() and CM()
d9d5a93 Add support for storing, restoring and clearing modifiers in macros
4f371c0 core: Add dfu-programmer example to doc/build.md
ba3792e core: Fix doc/build.md
4b99fed remove  SERIAL_SOFT_DEBUG macro
984accb Fix typo in bootmagic debug message
67a7ea1 usb_usb: Fix for keymap editor
2fc9ae4 host_driver is only used if KEYBOARD_LOCK_ENABLE is defined
a35cdea Chibios: add 'core/protocol' to the makefiles' search path.
5ed2fd6 Merge remote-tracking branch 'upstream/master' into chibios
bbc4851 Do timeout when writing to CONSOLE EP queue.
2450559 Remove an errant comma trailing the KC_ERAS macro alias
8465747 Merge pull request #270 from jeffgran/single-tap-toggle
a37339a Merge pull request #271 from jeffgran/default-layer-toggle
8e732f7 core: Update doc/build.md and remove other_projects.md
e47dc15 Workaround for compiler warnings when console disabled.
4184c52 Add maple mini code.
b555238 core: Fix rules.mk for dfu target
26dacf4 add ACTION_DEFAULT_LAYER_TOGGLE to toggle a default layer on/off
83607d9 enable TAPPING_TOGGLE=1 to work correctly
bef3089 Merge branch 'master' into chibios
f7a55fd core: Fix debug print of usb_hid
1402f7d core: Add keycode KC_JPY for JIS
8e3a460 Chibios: Remove the wait in the main loop.
7d41746 ChibiOS: prettify/document sleep_led code.
235cdee ChibiOS: Update infinity bootloader code to match updated ChibiOS.
807bf1e Chibios: Add breathing sleep LED on Kinetis MCUs.
ba3bf7c ChibiOS: make reset request more CMSISy.
bf2ffd4 Add correct chibios/bootloader_jump for infinity KB.
f5e03fd Chibios/usb_main: rename a variable for clarity.
63a330c Fix drop key stroke
d8f5b06 Fix report size of boot protocol.
38abb50 ChibiOS/STM32: send remote wakeup.
6725650 ChibiOS/kinetis: sending remote wakeup.
69f6e54 Chibios: use WFI in idle. WIP suspend stuff.
02f044b Move chibios/cortex selection to local Makefiles.
fa59dfa Rename chibios example keyboard.
5c060de Add eeprom support for chibios/kinetis.
efd0044 Move declaration of keymap_config.
7196b24 Make bootmagic.c code portable (_delay_ms -> wait_ms).
37b15b2 Add missing #include to keymap.c.
31316e3 Merge branch 'master' into chibios
166f312 Fix chibios/usb_main GET_REPORT handing.
57ac6c2 Add ARM Teensies bootloader code.
1758086 Move STM32 bootloader address config to separate .h file.
03bb026 Rename some Makefile defines.
76ba6ac NKRO fixes.
06498f8 Update chibios README.
db0a4f5 Add basic sleep_led for chibios.
c3f930e Move AVR specific sleep_led.c into avr.
4069494 Fix bootloader-jump compiling.
9117f7b Small updates.
269cb85 Implement jump-to-bootloader.
7e81b34 Move chibios to tool.
923a892 Make usb_main more USB_DRIVER #define independent.
aa054f0 Add ChibiOS support (USB stack + support files).
1e3e282 Modularity and gcc warnings fixes.
2f60ce0 Add KEYBOARD_LOCK_ENABLE to makefile

git-subtree-dir: tmk_core
git-subtree-split: 08ce4c3021d2ecd446c5b9a137aded65423d241e
This commit is contained in:
tmk 2016-02-11 12:21:21 +09:00
parent fdc38ef3f9
commit 28203e909e
41 changed files with 3534 additions and 141 deletions

View file

@ -0,0 +1,46 @@
#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 */
void bootloader_jump(void) {}
#endif

551
common/chibios/eeconfig.c Normal file
View file

@ -0,0 +1,551 @@
#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;
}
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
#error EEPROM support not implemented for your chip
#endif /* chip selection */
/*****************/
/* TMK functions */
/*****************/
void eeconfig_init(void)
{
eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
eeprom_write_byte(EECONFIG_DEBUG, 0);
eeprom_write_byte(EECONFIG_DEFAULT_LAYER, 0);
eeprom_write_byte(EECONFIG_KEYMAP, 0);
eeprom_write_byte(EECONFIG_MOUSEKEY_ACCEL, 0);
#ifdef BACKLIGHT_ENABLE
eeprom_write_byte(EECONFIG_BACKLIGHT, 0);
#endif
}
void eeconfig_enable(void)
{
eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
}
void eeconfig_disable(void)
{
eeprom_write_word(EECONFIG_MAGIC, 0xFFFF);
}
bool eeconfig_is_enabled(void)
{
return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER);
}
uint8_t eeconfig_read_debug(void) { return eeprom_read_byte(EECONFIG_DEBUG); }
void eeconfig_write_debug(uint8_t val) { eeprom_write_byte(EECONFIG_DEBUG, val); }
uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); }
void eeconfig_write_default_layer(uint8_t val) { eeprom_write_byte(EECONFIG_DEFAULT_LAYER, val); }
uint8_t eeconfig_read_keymap(void) { return eeprom_read_byte(EECONFIG_KEYMAP); }
void eeconfig_write_keymap(uint8_t val) { eeprom_write_byte(EECONFIG_KEYMAP, val); }
#ifdef BACKLIGHT_ENABLE
uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BACKLIGHT); }
void eeconfig_write_backlight(uint8_t val) { eeprom_write_byte(EECONFIG_BACKLIGHT, val); }
#endif

240
common/chibios/printf.c Normal file
View file

@ -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;
}
void tfp_sprintf(char* s,char *fmt, ...)
{
va_list va;
va_start(va,fmt);
tfp_format(&s,putcp,fmt,va);
putcp(&s,0);
va_end(va);
}

111
common/chibios/printf.h Normal file
View file

@ -0,0 +1,111 @@
/*
* found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
* and: http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
*/
/*
File: printf.h
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
This library is realy just two files: 'printf.h' and 'printf.c'.
They provide a simple and small (+200 loc) printf functionality to
be used in embedded systems.
I've found them so usefull in debugging that I do not bother with a
debugger at all.
They are distributed in source form, so to use them, just compile them
into your project.
Two printf variants are provided: printf and sprintf.
The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
Zero padding and field width are also supported.
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
long specifier is also
supported. Note that this will pull in some long math routines (pun intended!)
and thus make your executable noticably longer.
The memory foot print of course depends on the target cpu, compiler and
compiler options, but a rough guestimate (based on a H8S target) is about
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
Not too bad. Your milage may vary. By hacking the source code you can
get rid of some hunred bytes, I'm sure, but personally I feel the balance of
functionality and flexibility versus code size is close to optimal for
many embedded systems.
To use the printf you need to supply your own character output function,
something like :
void putc ( void* p, char c)
{
while (!SERIAL_PORT_EMPTY) ;
SERIAL_PORT_TX_REGISTER = c;
}
Before you can call printf you need to initialize it to use your
character output function with something like:
init_printf(NULL,putc);
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
the NULL (or any pointer) you pass into the 'init_printf' will eventually be
passed to your 'putc' routine. This allows you to pass some storage space (or
anything realy) to the character output function, if necessary.
This is not often needed but it was implemented like that because it made
implementing the sprintf function so neat (look at the source code).
The code is re-entrant, except for the 'init_printf' function, so it
is safe to call it from interupts too, although this may result in mixed output.
If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
The printf and sprintf functions are actually macros that translate to
'tfp_printf' and 'tfp_sprintf'. This makes it possible
to use them along with 'stdio.h' printf's in a single source file.
You just need to undef the names before you include the 'stdio.h'.
Note that these are not function like macros, so if you have variables
or struct members with these names, things will explode in your face.
Without variadic macros this is the best we can do to wrap these
fucnction. If it is a problem just give up the macros and use the
functions directly or rename them.
For further details see source code.
regs Kusti, 23.10.2004
*/
#ifndef __TFP_PRINTF__
#define __TFP_PRINTF__
#include <stdarg.h>
void init_printf(void* putp,void (*putf) (void*,char));
void tfp_printf(char *fmt, ...);
void tfp_sprintf(char* s,char *fmt, ...);
void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
#define printf tfp_printf
#define sprintf tfp_sprintf
#endif

164
common/chibios/sleep_led.c Normal file
View file

@ -0,0 +1,164 @@
#include "ch.h"
#include "hal.h"
#include "led.h"
#include "sleep_led.h"
#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */
/* All right, we go the "software" way: LP timer, toggle LED in interrupt.
* Based on hasu's code for AVRs.
*/
/* Breathing Sleep LED brighness(PWM On period) table
* (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
*
* http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
* (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
*/
static const uint8_t breathing_table[64] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* Low Power Timer interrupt handler */
OSAL_IRQ_HANDLER(KINETIS_LPTMR0_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
/* Software PWM
* timer:1111 1111 1111 1111
* \_____/\/ \_______/____ count(0-255)
* \ \______________ duration of step(4)
* \__________________ index of step table(0-63)
*/
// this works for cca 65536 irqs/sec
static union {
uint16_t row;
struct {
uint8_t count:8;
uint8_t duration:2;
uint8_t index:6;
} pwm;
} timer = { .row = 0 };
timer.row++;
// LED on
if (timer.pwm.count == 0) {
led_set(1<<USB_LED_CAPS_LOCK);
}
// LED off
if (timer.pwm.count == breathing_table[timer.pwm.index]) {
led_set(0);
}
/* Reset the counter */
LPTMR0->CSR |= LPTMRx_CSR_TCF;
OSAL_IRQ_EPILOGUE();
}
/* LPTMR clock options */
#define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */
#define LPTMR_CLOCK_LPO 1 /* 1kHz clock */
#define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */
#define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */
/* Work around inconsistencies in Freescale naming */
#if !defined(SIM_SCGC5_LPTMR)
#define SIM_SCGC5_LPTMR SIM_SCGC5_LPTIMER
#endif
/* Initialise the timer */
void sleep_led_init(void) {
/* Make sure the clock to the LPTMR is enabled */
SIM->SCGC5 |= SIM_SCGC5_LPTMR;
/* Reset LPTMR settings */
LPTMR0->CSR = 0;
/* Set the compare value */
LPTMR0->CMR = 0; // trigger on counter value (i.e. every time)
/* Set up clock source and prescaler */
/* Software PWM
* ______ ______ __
* | ON |___OFF___| ON |___OFF___| ....
* |<-------------->|<-------------->|<- ....
* PWM period PWM period
*
* R interrupts/period[resolution]
* F periods/second[frequency]
* R * F interrupts/second
*/
/* === OPTION 1 === */
#if 0
// 1kHz LPO
// No prescaler => 1024 irqs/sec
// Note: this is too slow for a smooth breathe
LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP;
#endif /* OPTION 1 */
/* === OPTION 2 === */
#if 1
// nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z)
MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock
#if defined(KL27) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
#endif /* KL27 */
MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock
// to work in stop mode, also MCG_C1_IREFSTEN
// Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>
// => approx F=61, R=256, duration = 4
LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK)|LPTMRx_PSR_PRESCALE(6);
#endif /* OPTION 2 */
/* === OPTION 3 === */
#if 0
// OSC output (external crystal), usually 8MHz or 16MHz
OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock
// to work in stop mode, also OSC_CR_EREFSTEN
// Divide by 2^N
LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7);
#endif /* OPTION 3 */
/* === END OPTIONS === */
/* Interrupt on TCF set (compare flag) */
nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority
LPTMR0->CSR |= LPTMRx_CSR_TIE;
}
void sleep_led_enable(void) {
/* Enable the timer */
LPTMR0->CSR |= LPTMRx_CSR_TEN;
}
void sleep_led_disable(void) {
/* Disable the timer */
LPTMR0->CSR &= ~LPTMRx_CSR_TEN;
}
void sleep_led_toggle(void) {
/* Toggle the timer */
LPTMR0->CSR ^= LPTMRx_CSR_TEN;
}
#else /* platform selection: not on familiar Kinetis chips */
void sleep_led_init(void) {
}
void sleep_led_enable(void) {
led_set(1<<USB_LED_CAPS_LOCK);
}
void sleep_led_disable(void) {
led_set(0);
}
void sleep_led_toggle(void) {
// not implemented
}
#endif /* platform selection */

65
common/chibios/suspend.c Normal file
View file

@ -0,0 +1,65 @@
/* TODO */
#include "ch.h"
#include "hal.h"
#include "matrix.h"
#include "action.h"
#include "action_util.h"
#include "mousekey.h"
#include "host.h"
#include "backlight.h"
#include "suspend.h"
void suspend_idle(uint8_t time) {
// TODO: this is not used anywhere - what units is 'time' in?
chThdSleepMilliseconds(time);
}
void suspend_power_down(void) {
// TODO: figure out what to power down and how
// shouldn't power down TPM/FTM if we want a breathing LED
// also shouldn't power down USB
// on AVR, this enables the watchdog for 15ms (max), and goes to
// SLEEP_MODE_PWR_DOWN
chThdSleepMilliseconds(17);
}
__attribute__ ((weak)) void matrix_power_up(void) {}
__attribute__ ((weak)) void matrix_power_down(void) {}
bool suspend_wakeup_condition(void)
{
matrix_power_up();
matrix_scan();
matrix_power_down();
for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
if (matrix_get_row(r)) return true;
}
return false;
}
// run immediately after wakeup
void suspend_wakeup_init(void)
{
// clear keyboard state
// need to do it manually, because we're running from ISR
// and clear_keyboard() calls print
// so only clear the variables in memory
// the reports will be sent from main.c afterwards
// or if the PC asks for GET_REPORT
clear_mods();
clear_weak_mods();
clear_keys();
#ifdef MOUSEKEY_ENABLE
mousekey_clear();
#endif /* MOUSEKEY_ENABLE */
#ifdef EXTRAKEY_ENABLE
host_system_send(0);
host_consumer_send(0);
#endif /* EXTRAKEY_ENABLE */
#ifdef BACKLIGHT_ENABLE
backlight_init();
#endif /* BACKLIGHT_ENABLE */
}

27
common/chibios/timer.c Normal file
View file

@ -0,0 +1,27 @@
#include "ch.h"
#include "timer.h"
void timer_init(void) {}
void timer_clear(void) {}
uint16_t timer_read(void)
{
return (uint16_t)ST2MS(chVTGetSystemTime());
}
uint32_t timer_read32(void)
{
return ST2MS(chVTGetSystemTime());
}
uint16_t timer_elapsed(uint16_t last)
{
return (uint16_t)(ST2MS(chVTTimeElapsedSinceX(MS2ST(last))));
}
uint32_t timer_elapsed32(uint32_t last)
{
return ST2MS(chVTTimeElapsedSinceX(MS2ST(last)));
}