From 96f44e120295e677d21d3dbb9dc4bf642ba2af09 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 5 Jul 2016 18:36:02 -0400 Subject: [PATCH 1/7] one half working --- keyboards/lets-split/Makefile | 73 ++++++++++++++++ keyboards/lets-split/config.h | 87 +++++++++++++++++++ keyboards/lets-split/keymaps/default/keymap.c | 42 +++++++++ keyboards/lets-split/lets-split.c | 48 ++++++++++ keyboards/lets-split/lets-split.h | 4 + keyboards/lets-split/readme.md | 0 6 files changed, 254 insertions(+) create mode 100644 keyboards/lets-split/Makefile create mode 100644 keyboards/lets-split/config.h create mode 100644 keyboards/lets-split/keymaps/default/keymap.c create mode 100644 keyboards/lets-split/lets-split.c create mode 100644 keyboards/lets-split/lets-split.h create mode 100644 keyboards/lets-split/readme.md diff --git a/keyboards/lets-split/Makefile b/keyboards/lets-split/Makefile new file mode 100644 index 0000000000..247f978f01 --- /dev/null +++ b/keyboards/lets-split/Makefile @@ -0,0 +1,73 @@ + + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + +# Build Options +# change to "no" to disable the options, or define them in the Makefile in +# the appropriate keymap folder that will get included automatically +# +BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) +EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) +CONSOLE_ENABLE ?= no # Console for debug(+400) +COMMAND_ENABLE ?= yes # Commands for debug and configuration +NKRO_ENABLE ?= no # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work +BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality +MIDI_ENABLE ?= no # MIDI controls +AUDIO_ENABLE ?= yes # Audio output on port C6 +UNICODE_ENABLE ?= no # Unicode +BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID +RGBLIGHT_ENABLE ?= no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. + +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend + +ifndef QUANTUM_DIR + include ../../Makefile +endif \ No newline at end of file diff --git a/keyboards/lets-split/config.h b/keyboards/lets-split/config.h new file mode 100644 index 0000000000..5b464147d3 --- /dev/null +++ b/keyboards/lets-split/config.h @@ -0,0 +1,87 @@ +/* +Copyright 2012 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "config_common.h" + +/* USB Device descriptor parameter */ +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x3060 +#define DEVICE_VER 0x0001 +#define MANUFACTURER Wootpatoot +#define PRODUCT Lets Split +#define DESCRIPTION A split keyboard for the cheap makers + +/* key matrix size */ +#define MATRIX_ROWS 4 +#define MATRIX_COLS 6 + +#define MATRIX_ROW_PINS { B5, B4, E6, D7, } +#define MATRIX_COL_PINS { F4, F5, F6, F7, B1, B3 } + +/* COL2ROW or ROW2COL */ +#define DIODE_DIRECTION COL2ROW + +/* define if matrix has ghost */ +//#define MATRIX_HAS_GHOST + +/* number of backlight levels */ +#define BACKLIGHT_LEVELS 3 + +/* Set 0 if debouncing isn't needed */ +#define DEBOUNCING_DELAY 5 + +/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ +#define LOCKING_SUPPORT_ENABLE +/* Locking resynchronize hack */ +#define LOCKING_RESYNC_ENABLE + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ +) + +/* ws2812 RGB LED */ +#define ws2812_PORTREG PORTD +#define ws2812_DDRREG DDRD +#define ws2812_pin PD1 +#define RGBLED_NUM 28 // Number of LEDs +#define RGBLIGHT_HUE_STEP 10 +#define RGBLIGHT_SAT_STEP 17 +#define RGBLIGHT_VAL_STEP 17 + +/* + * Feature disable options + * These options are also useful to firmware size reduction. + */ + +/* disable debug print */ +// #define NO_DEBUG + +/* disable print */ +// #define NO_PRINT + +/* disable action features */ +//#define NO_ACTION_LAYER +//#define NO_ACTION_TAPPING +//#define NO_ACTION_ONESHOT +//#define NO_ACTION_MACRO +//#define NO_ACTION_FUNCTION + +#endif \ No newline at end of file diff --git a/keyboards/lets-split/keymaps/default/keymap.c b/keyboards/lets-split/keymaps/default/keymap.c new file mode 100644 index 0000000000..00602394fe --- /dev/null +++ b/keyboards/lets-split/keymaps/default/keymap.c @@ -0,0 +1,42 @@ +#include "lets-split.h" +#include "action_layer.h" + +#define BASE 0 + +enum preonic_keycodes { + KC_IDK = SAFE_RANGE, + PM_RESET +}; + +// Fillers to make layering more clear +#define _______ KC_TRNS +#define XXXXXXX KC_NO + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[BASE] = { + {KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T }, + {KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G }, + {KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B }, + {KC_IDK, KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, PM_RESET } +} + +}; + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case KC_IDK: + if (record->event.pressed) { + SEND_STRING("IDK. "); + } + return false; + break; + case PM_RESET: + if (record->event.pressed) { + promicro_bootloader_jmp(true); + } + return false; + break; + } + return true; +}; \ No newline at end of file diff --git a/keyboards/lets-split/lets-split.c b/keyboards/lets-split/lets-split.c new file mode 100644 index 0000000000..ee98723037 --- /dev/null +++ b/keyboards/lets-split/lets-split.c @@ -0,0 +1,48 @@ +#include "lets-split.h" + +#ifdef AUDIO_ENABLE + float tone_startup[][2] = SONG(STARTUP_SOUND); + float tone_goodbye[][2] = SONG(GOODBYE_SOUND); +#endif + +void matrix_init_kb(void) { + + #ifdef AUDIO_ENABLE + _delay_ms(20); // gets rid of tick + PLAY_NOTE_ARRAY(tone_startup, false, 0); + #endif + + // green led on + DDRD |= (1<<5); + PORTD &= ~(1<<5); + + // orange led on + DDRB |= (1<<0); + PORTB &= ~(1<<0); + + matrix_init_user(); +}; + +void promicro_bootloader_jmp(bool program) { + + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_goodbye, false, 0); + _delay_ms(150); + stop_all_notes(); + #endif + + uint16_t *const bootKeyPtr = (uint16_t *)0x0800; + + // Value used by Caterina bootloader use to determine whether to run the + // sketch or the bootloader programmer. + uint16_t bootKey = program ? 0x7777 : 0; + + *bootKeyPtr = bootKey; + + // setup watchdog timeout + wdt_enable(WDTO_60MS); + + while(1) {} // wait for watchdog timer to trigger +} + + diff --git a/keyboards/lets-split/lets-split.h b/keyboards/lets-split/lets-split.h new file mode 100644 index 0000000000..c82b95a376 --- /dev/null +++ b/keyboards/lets-split/lets-split.h @@ -0,0 +1,4 @@ +#include "quantum.h" +#include + +void promicro_bootloader_jmp(bool program); \ No newline at end of file diff --git a/keyboards/lets-split/readme.md b/keyboards/lets-split/readme.md new file mode 100644 index 0000000000..e69de29bb2 From d707738616c140f8d9c8eded7b64e5fc806f4b24 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 5 Jul 2016 23:27:10 -0400 Subject: [PATCH 2/7] i2c working --- keyboards/lets-split/lets-split.h | 4 - keyboards/{lets-split => lets_split}/Makefile | 6 +- keyboards/{lets-split => lets_split}/config.h | 10 +- keyboards/lets_split/i2c.c | 159 ++++++++ keyboards/lets_split/i2c.h | 31 ++ .../keymaps/default/keymap.c | 14 +- .../lets-split.c => lets_split/lets_split.c} | 14 +- keyboards/lets_split/lets_split.h | 21 + keyboards/lets_split/matrix.c | 310 ++++++++++++++ keyboards/lets_split/pro_micro.h | 362 +++++++++++++++++ .../{lets-split => lets_split}/readme.md | 0 keyboards/lets_split/split_util.c | 67 ++++ keyboards/lets_split/split_util.h | 20 + keyboards/lets_split/uno-slave/Makefile | 226 +++++++++++ .../lets_split/uno-slave/keyboard-i2c-slave.c | 42 ++ keyboards/lets_split/uno-slave/readme.md | 1 + keyboards/lets_split/uno-slave/uno-matrix.c | 160 ++++++++ keyboards/lets_split/uno-slave/uno-matrix.h | 19 + keyboards/lets_split/usbconfig.h | 377 ++++++++++++++++++ tmk_core/common/matrix.h | 5 + 20 files changed, 1827 insertions(+), 21 deletions(-) delete mode 100644 keyboards/lets-split/lets-split.h rename keyboards/{lets-split => lets_split}/Makefile (97%) rename keyboards/{lets-split => lets_split}/config.h (93%) create mode 100644 keyboards/lets_split/i2c.c create mode 100644 keyboards/lets_split/i2c.h rename keyboards/{lets-split => lets_split}/keymaps/default/keymap.c (55%) rename keyboards/{lets-split/lets-split.c => lets_split/lets_split.c} (83%) create mode 100644 keyboards/lets_split/lets_split.h create mode 100644 keyboards/lets_split/matrix.c create mode 100644 keyboards/lets_split/pro_micro.h rename keyboards/{lets-split => lets_split}/readme.md (100%) create mode 100644 keyboards/lets_split/split_util.c create mode 100644 keyboards/lets_split/split_util.h create mode 100644 keyboards/lets_split/uno-slave/Makefile create mode 100644 keyboards/lets_split/uno-slave/keyboard-i2c-slave.c create mode 100644 keyboards/lets_split/uno-slave/readme.md create mode 100644 keyboards/lets_split/uno-slave/uno-matrix.c create mode 100644 keyboards/lets_split/uno-slave/uno-matrix.h create mode 100644 keyboards/lets_split/usbconfig.h diff --git a/keyboards/lets-split/lets-split.h b/keyboards/lets-split/lets-split.h deleted file mode 100644 index c82b95a376..0000000000 --- a/keyboards/lets-split/lets-split.h +++ /dev/null @@ -1,4 +0,0 @@ -#include "quantum.h" -#include - -void promicro_bootloader_jmp(bool program); \ No newline at end of file diff --git a/keyboards/lets-split/Makefile b/keyboards/lets_split/Makefile similarity index 97% rename from keyboards/lets-split/Makefile rename to keyboards/lets_split/Makefile index 247f978f01..d8e283896e 100644 --- a/keyboards/lets-split/Makefile +++ b/keyboards/lets_split/Makefile @@ -1,4 +1,6 @@ - +SRC += matrix.c \ + i2c.c \ + split_util.c # MCU name #MCU = at90usb1287 @@ -68,6 +70,8 @@ RGBLIGHT_ENABLE ?= no # Enable WS2812 RGB underlight. Do not enable this # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend +CUSTOM_MATRIX = yes + ifndef QUANTUM_DIR include ../../Makefile endif \ No newline at end of file diff --git a/keyboards/lets-split/config.h b/keyboards/lets_split/config.h similarity index 93% rename from keyboards/lets-split/config.h rename to keyboards/lets_split/config.h index 5b464147d3..e68787e0b5 100644 --- a/keyboards/lets-split/config.h +++ b/keyboards/lets_split/config.h @@ -29,12 +29,18 @@ along with this program. If not, see . #define DESCRIPTION A split keyboard for the cheap makers /* key matrix size */ -#define MATRIX_ROWS 4 +#define MATRIX_ROWS 8 #define MATRIX_COLS 6 -#define MATRIX_ROW_PINS { B5, B4, E6, D7, } +// wiring of each half +#define MATRIX_ROW_PINS { B5, B4, E6, D7 } #define MATRIX_COL_PINS { F4, F5, F6, F7, B1, B3 } +#define USE_I2C + +// #define I2C_MASTER_LEFT +#define I2C_MASTER_RIGHT + /* COL2ROW or ROW2COL */ #define DIODE_DIRECTION COL2ROW diff --git a/keyboards/lets_split/i2c.c b/keyboards/lets_split/i2c.c new file mode 100644 index 0000000000..c72789403e --- /dev/null +++ b/keyboards/lets_split/i2c.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include +#include "i2c.h" + +// Limits the amount of we wait for any one i2c transaction. +// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is +// 9 bits, a single transaction will take around 90μs to complete. +// +// (F_CPU/SCL_CLOCK) => # of μC cycles to transfer a bit +// poll loop takes at least 8 clock cycles to execute +#define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8 + +#define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE) + +volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; + +static volatile uint8_t slave_buffer_pos; +static volatile bool slave_has_register_set = false; + +// Wait for an i2c operation to finish +inline static +void i2c_delay(void) { + uint16_t lim = 0; + while(!(TWCR & (1<10. + // Check datasheets for more info. + TWBR = ((F_CPU/SCL_CLOCK)-16)/2; +} + +// Start a transaction with the given i2c slave address. The direction of the +// transfer is set with I2C_READ and I2C_WRITE. +// returns: 0 => success +// 1 => error +uint8_t i2c_master_start(uint8_t address) { + TWCR = (1< slave ACK +// 1 => slave NACK +uint8_t i2c_master_write(uint8_t data) { + TWDR = data; + TWCR = (1<= SLAVE_BUFFER_SIZE ) { + ack = 0; + slave_buffer_pos = 0; + } + slave_has_register_set = true; + } else { + i2c_slave_buffer[slave_buffer_pos] = TWDR; + BUFFER_POS_INC(); + } + break; + + case TW_ST_SLA_ACK: + case TW_ST_DATA_ACK: + // master has addressed this device as a slave transmitter and is + // requesting data. + TWDR = i2c_slave_buffer[slave_buffer_pos]; + BUFFER_POS_INC(); + break; + + case TW_BUS_ERROR: // something went wrong, reset twi state + TWCR = 0; + default: + break; + } + // Reset everything, so we are ready for the next TWI interrupt + TWCR |= (1< + +#ifndef F_CPU +#define F_CPU 16000000UL +#endif + +#define I2C_READ 1 +#define I2C_WRITE 0 + +#define I2C_ACK 1 +#define I2C_NACK 0 + +#define SLAVE_BUFFER_SIZE 0x10 + +// i2c SCL clock frequency +#define SCL_CLOCK 100000L + +extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE]; + +void i2c_master_init(void); +uint8_t i2c_master_start(uint8_t address); +void i2c_master_stop(void); +uint8_t i2c_master_write(uint8_t data); +uint8_t i2c_master_read(int); +void i2c_reset_state(void); +void i2c_slave_init(uint8_t address); + +#endif diff --git a/keyboards/lets-split/keymaps/default/keymap.c b/keyboards/lets_split/keymaps/default/keymap.c similarity index 55% rename from keyboards/lets-split/keymaps/default/keymap.c rename to keyboards/lets_split/keymaps/default/keymap.c index 00602394fe..01e3593c22 100644 --- a/keyboards/lets-split/keymaps/default/keymap.c +++ b/keyboards/lets_split/keymaps/default/keymap.c @@ -1,4 +1,4 @@ -#include "lets-split.h" +#include "lets_split.h" #include "action_layer.h" #define BASE 0 @@ -14,12 +14,12 @@ enum preonic_keycodes { const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { -[BASE] = { - {KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T }, - {KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G }, - {KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B }, - {KC_IDK, KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, PM_RESET } -} +[BASE] = KEYMAP( + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC, \ + KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, \ + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT, \ + KC_IDK, KC_LCTL, KC_LALT, KC_LGUI, PM_RESET,KC_SPC, KC_SPC, PM_RESET,KC_LEFT, KC_DOWN, KC_UP, KC_RGHT \ +) }; diff --git a/keyboards/lets-split/lets-split.c b/keyboards/lets_split/lets_split.c similarity index 83% rename from keyboards/lets-split/lets-split.c rename to keyboards/lets_split/lets_split.c index ee98723037..1859dc20a7 100644 --- a/keyboards/lets-split/lets-split.c +++ b/keyboards/lets_split/lets_split.c @@ -1,4 +1,4 @@ -#include "lets-split.h" +#include "lets_split.h" #ifdef AUDIO_ENABLE float tone_startup[][2] = SONG(STARTUP_SOUND); @@ -12,13 +12,13 @@ void matrix_init_kb(void) { PLAY_NOTE_ARRAY(tone_startup, false, 0); #endif - // green led on - DDRD |= (1<<5); - PORTD &= ~(1<<5); + // // green led on + // DDRD |= (1<<5); + // PORTD &= ~(1<<5); - // orange led on - DDRB |= (1<<0); - PORTB &= ~(1<<0); + // // orange led on + // DDRB |= (1<<0); + // PORTB &= ~(1<<0); matrix_init_user(); }; diff --git a/keyboards/lets_split/lets_split.h b/keyboards/lets_split/lets_split.h new file mode 100644 index 0000000000..e59aed5921 --- /dev/null +++ b/keyboards/lets_split/lets_split.h @@ -0,0 +1,21 @@ +#include "quantum.h" +#include + +void promicro_bootloader_jmp(bool program); + +#define KEYMAP( \ + k00, k01, k02, k03, k04, k05, k40, k41, k42, k43, k44, k45, \ + k10, k11, k12, k13, k14, k15, k50, k51, k52, k53, k54, k55, \ + k20, k21, k22, k23, k24, k25, k60, k61, k62, k63, k64, k65, \ + k30, k31, k32, k33, k34, k35, k70, k71, k72, k73, k74, k75 \ + ) \ + { \ + { k00, k01, k02, k03, k04, k05 }, \ + { k10, k11, k12, k13, k14, k15 }, \ + { k20, k21, k22, k23, k24, k25 }, \ + { k30, k31, k32, k33, k34, k35 }, \ + { k40, k41, k42, k43, k44, k45 }, \ + { k50, k51, k52, k53, k54, k55 }, \ + { k60, k61, k62, k63, k64, k65 }, \ + { k70, k71, k72, k73, k74, k75 } \ + } \ No newline at end of file diff --git a/keyboards/lets_split/matrix.c b/keyboards/lets_split/matrix.c new file mode 100644 index 0000000000..16c2ba0bad --- /dev/null +++ b/keyboards/lets_split/matrix.c @@ -0,0 +1,310 @@ +/* +Copyright 2012 Jun Wako + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +/* + * scan matrix + */ +#include +#include +#include +#include +#include +#include +#include "print.h" +#include "debug.h" +#include "util.h" +#include "matrix.h" +#include "i2c.h" +#include "split_util.h" +#include "pro_micro.h" +#include "config.h" + +#ifndef DEBOUNCE +# define DEBOUNCE 5 +#endif + +#define ERROR_DISCONNECT_COUNT 5 + +static uint8_t debouncing = DEBOUNCE; +static const int ROWS_PER_HAND = MATRIX_ROWS/2; +static uint8_t error_count = 0; + +static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; +static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; +static matrix_row_t matrix_debouncing[MATRIX_ROWS]; + +static matrix_row_t read_cols(void); +static void init_cols(void); +static void unselect_rows(void); +static void select_row(uint8_t row); + +__attribute__ ((weak)) +void matrix_init_quantum(void) { + matrix_init_kb(); +} + +__attribute__ ((weak)) +void matrix_scan_quantum(void) { + matrix_scan_kb(); +} + +__attribute__ ((weak)) +void matrix_init_kb(void) { + matrix_init_user(); +} + +__attribute__ ((weak)) +void matrix_scan_kb(void) { + matrix_scan_user(); +} + +__attribute__ ((weak)) +void matrix_init_user(void) { +} + +__attribute__ ((weak)) +void matrix_scan_user(void) { +} + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + debug_enable = true; + debug_matrix = true; + debug_mouse = true; + // initialize row and col + unselect_rows(); + init_cols(); + + TX_RX_LED_INIT; + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + matrix_debouncing[i] = 0; + } + + matrix_init_quantum(); +} + +uint8_t _matrix_scan(void) +{ + // Right hand is stored after the left in the matirx so, we need to offset it + int offset = isLeftHand ? 0 : (ROWS_PER_HAND); + + for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { + select_row(i); + _delay_us(30); // without this wait read unstable value. + matrix_row_t cols = read_cols(); + if (matrix_debouncing[i+offset] != cols) { + matrix_debouncing[i+offset] = cols; + debouncing = DEBOUNCE; + } + unselect_rows(); + } + + if (debouncing) { + if (--debouncing) { + _delay_ms(1); + } else { + for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { + matrix[i+offset] = matrix_debouncing[i+offset]; + } + } + } + + return 1; +} + +// Get rows from other half over i2c +int i2c_transaction(void) { + int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; + + int err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); + if (err) goto i2c_error; + + // start of matrix stored at 0x00 + err = i2c_master_write(0x00); + if (err) goto i2c_error; + + // Start read + err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); + if (err) goto i2c_error; + + if (!err) { + int i; + for (i = 0; i < ROWS_PER_HAND-1; ++i) { + matrix[slaveOffset+i] = i2c_master_read(I2C_ACK); + } + matrix[slaveOffset+i] = i2c_master_read(I2C_NACK); + i2c_master_stop(); + } else { +i2c_error: // the cable is disconnceted, or something else went wrong + i2c_reset_state(); + return err; + } + + return 0; +} + +#ifndef USE_I2C +int serial_transaction(void) { + int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; + + if (serial_update_buffers()) { + return 1; + } + + for (int i = 0; i < ROWS_PER_HAND; ++i) { + matrix[slaveOffset+i] = serial_slave_buffer[i]; + } + return 0; +} +#endif + +uint8_t matrix_scan(void) +{ + int ret = _matrix_scan(); + + + +#ifdef USE_I2C + if( i2c_transaction() ) { +#else + if( serial_transaction() ) { +#endif + // turn on the indicator led when halves are disconnected + TXLED1; + + error_count++; + + if (error_count > ERROR_DISCONNECT_COUNT) { + // reset other half if disconnected + int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; + for (int i = 0; i < ROWS_PER_HAND; ++i) { + matrix[slaveOffset+i] = 0; + } + } + } else { + // turn off the indicator led on no error + TXLED0; + error_count = 0; + } + + matrix_scan_quantum(); + + return ret; +} + +void matrix_slave_scan(void) { + _matrix_scan(); + + int offset = (isLeftHand) ? 0 : (MATRIX_ROWS / 2); + +#ifdef USE_I2C + for (int i = 0; i < ROWS_PER_HAND; ++i) { + /* i2c_slave_buffer[i] = matrix[offset+i]; */ + i2c_slave_buffer[i] = matrix[offset+i]; + } +#else + for (int i = 0; i < ROWS_PER_HAND; ++i) { + serial_slave_buffer[i] = matrix[offset+i]; + } +#endif +} + +bool matrix_is_modified(void) +{ + if (debouncing) return false; + return true; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & ((matrix_row_t)1<> 4) + 1) &= ~_BV(col_pins[x] & 0xF); + _SFR_IO8((col_pins[x] >> 4) + 2) |= _BV(col_pins[x] & 0xF); + } +} + +static matrix_row_t read_cols(void) +{ + matrix_row_t result = 0; + for(int x = 0; x < MATRIX_COLS; x++) { + result |= (_SFR_IO8(col_pins[x] >> 4) & _BV(col_pins[x] & 0xF)) ? 0 : (1 << x); + } + return result; +} + +static void unselect_rows(void) +{ + for(int x = 0; x < ROWS_PER_HAND; x++) { + _SFR_IO8((row_pins[x] >> 4) + 1) &= ~_BV(row_pins[x] & 0xF); + _SFR_IO8((row_pins[x] >> 4) + 2) |= _BV(row_pins[x] & 0xF); + } +} + +static void select_row(uint8_t row) +{ + _SFR_IO8((row_pins[row] >> 4) + 1) |= _BV(row_pins[row] & 0xF); + _SFR_IO8((row_pins[row] >> 4) + 2) &= ~_BV(row_pins[row] & 0xF); +} diff --git a/keyboards/lets_split/pro_micro.h b/keyboards/lets_split/pro_micro.h new file mode 100644 index 0000000000..09e219b7b1 --- /dev/null +++ b/keyboards/lets_split/pro_micro.h @@ -0,0 +1,362 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + 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 + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +// Workaround for wrong definitions in "iom32u4.h". +// This should be fixed in the AVR toolchain. +#undef UHCON +#undef UHINT +#undef UHIEN +#undef UHADDR +#undef UHFNUM +#undef UHFNUML +#undef UHFNUMH +#undef UHFLEN +#undef UPINRQX +#undef UPINTX +#undef UPNUM +#undef UPRST +#undef UPCONX +#undef UPCFG0X +#undef UPCFG1X +#undef UPSTAX +#undef UPCFG2X +#undef UPIENX +#undef UPDATX +#undef TCCR2A +#undef WGM20 +#undef WGM21 +#undef COM2B0 +#undef COM2B1 +#undef COM2A0 +#undef COM2A1 +#undef TCCR2B +#undef CS20 +#undef CS21 +#undef CS22 +#undef WGM22 +#undef FOC2B +#undef FOC2A +#undef TCNT2 +#undef TCNT2_0 +#undef TCNT2_1 +#undef TCNT2_2 +#undef TCNT2_3 +#undef TCNT2_4 +#undef TCNT2_5 +#undef TCNT2_6 +#undef TCNT2_7 +#undef OCR2A +#undef OCR2_0 +#undef OCR2_1 +#undef OCR2_2 +#undef OCR2_3 +#undef OCR2_4 +#undef OCR2_5 +#undef OCR2_6 +#undef OCR2_7 +#undef OCR2B +#undef OCR2_0 +#undef OCR2_1 +#undef OCR2_2 +#undef OCR2_3 +#undef OCR2_4 +#undef OCR2_5 +#undef OCR2_6 +#undef OCR2_7 + +#define NUM_DIGITAL_PINS 30 +#define NUM_ANALOG_INPUTS 12 + +#define TX_RX_LED_INIT DDRD |= (1<<5), DDRB |= (1<<0) +#define TXLED0 PORTD |= (1<<5) +#define TXLED1 PORTD &= ~(1<<5) +#define RXLED0 PORTB |= (1<<0) +#define RXLED1 PORTB &= ~(1<<0) + +static const uint8_t SDA = 2; +static const uint8_t SCL = 3; +#define LED_BUILTIN 13 + +// Map SPI port to 'new' pins D14..D17 +static const uint8_t SS = 17; +static const uint8_t MOSI = 16; +static const uint8_t MISO = 14; +static const uint8_t SCK = 15; + +// Mapping of analog pins as digital I/O +// A6-A11 share with digital pins +static const uint8_t A0 = 18; +static const uint8_t A1 = 19; +static const uint8_t A2 = 20; +static const uint8_t A3 = 21; +static const uint8_t A4 = 22; +static const uint8_t A5 = 23; +static const uint8_t A6 = 24; // D4 +static const uint8_t A7 = 25; // D6 +static const uint8_t A8 = 26; // D8 +static const uint8_t A9 = 27; // D9 +static const uint8_t A10 = 28; // D10 +static const uint8_t A11 = 29; // D12 + +#define digitalPinToPCICR(p) ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCICR) : ((uint8_t *)0)) +#define digitalPinToPCICRbit(p) 0 +#define digitalPinToPCMSK(p) ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCMSK0) : ((uint8_t *)0)) +#define digitalPinToPCMSKbit(p) ( ((p) >= 8 && (p) <= 11) ? (p) - 4 : ((p) == 14 ? 3 : ((p) == 15 ? 1 : ((p) == 16 ? 2 : ((p) == 17 ? 0 : (p - A8 + 4)))))) + +// __AVR_ATmega32U4__ has an unusual mapping of pins to channels +extern const uint8_t PROGMEM analog_pin_to_channel_PGM[]; +#define analogPinToChannel(P) ( pgm_read_byte( analog_pin_to_channel_PGM + (P) ) ) + +#define digitalPinToInterrupt(p) ((p) == 0 ? 2 : ((p) == 1 ? 3 : ((p) == 2 ? 1 : ((p) == 3 ? 0 : ((p) == 7 ? 4 : NOT_AN_INTERRUPT))))) + +#ifdef ARDUINO_MAIN + +// On the Arduino board, digital pins are also used +// for the analog output (software PWM). Analog input +// pins are a separate set. + +// ATMEL ATMEGA32U4 / ARDUINO LEONARDO +// +// D0 PD2 RXD1/INT2 +// D1 PD3 TXD1/INT3 +// D2 PD1 SDA SDA/INT1 +// D3# PD0 PWM8/SCL OC0B/SCL/INT0 +// D4 A6 PD4 ADC8 +// D5# PC6 ??? OC3A/#OC4A +// D6# A7 PD7 FastPWM #OC4D/ADC10 +// D7 PE6 INT6/AIN0 +// +// D8 A8 PB4 ADC11/PCINT4 +// D9# A9 PB5 PWM16 OC1A/#OC4B/ADC12/PCINT5 +// D10# A10 PB6 PWM16 OC1B/0c4B/ADC13/PCINT6 +// D11# PB7 PWM8/16 0C0A/OC1C/#RTS/PCINT7 +// D12 A11 PD6 T1/#OC4D/ADC9 +// D13# PC7 PWM10 CLK0/OC4A +// +// A0 D18 PF7 ADC7 +// A1 D19 PF6 ADC6 +// A2 D20 PF5 ADC5 +// A3 D21 PF4 ADC4 +// A4 D22 PF1 ADC1 +// A5 D23 PF0 ADC0 +// +// New pins D14..D17 to map SPI port to digital pins +// +// MISO D14 PB3 MISO,PCINT3 +// SCK D15 PB1 SCK,PCINT1 +// MOSI D16 PB2 MOSI,PCINT2 +// SS D17 PB0 RXLED,SS/PCINT0 +// +// Connected LEDs on board for TX and RX +// TXLED D24 PD5 XCK1 +// RXLED D17 PB0 +// HWB PE2 HWB + +// these arrays map port names (e.g. port B) to the +// appropriate addresses for various functions (e.g. reading +// and writing) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &DDRB, + (uint16_t) &DDRC, + (uint16_t) &DDRD, + (uint16_t) &DDRE, + (uint16_t) &DDRF, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PORTB, + (uint16_t) &PORTC, + (uint16_t) &PORTD, + (uint16_t) &PORTE, + (uint16_t) &PORTF, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PINB, + (uint16_t) &PINC, + (uint16_t) &PIND, + (uint16_t) &PINE, + (uint16_t) &PINF, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + PD, // D0 - PD2 + PD, // D1 - PD3 + PD, // D2 - PD1 + PD, // D3 - PD0 + PD, // D4 - PD4 + PC, // D5 - PC6 + PD, // D6 - PD7 + PE, // D7 - PE6 + + PB, // D8 - PB4 + PB, // D9 - PB5 + PB, // D10 - PB6 + PB, // D11 - PB7 + PD, // D12 - PD6 + PC, // D13 - PC7 + + PB, // D14 - MISO - PB3 + PB, // D15 - SCK - PB1 + PB, // D16 - MOSI - PB2 + PB, // D17 - SS - PB0 + + PF, // D18 - A0 - PF7 + PF, // D19 - A1 - PF6 + PF, // D20 - A2 - PF5 + PF, // D21 - A3 - PF4 + PF, // D22 - A4 - PF1 + PF, // D23 - A5 - PF0 + + PD, // D24 - PD5 + PD, // D25 / D6 - A7 - PD7 + PB, // D26 / D8 - A8 - PB4 + PB, // D27 / D9 - A9 - PB5 + PB, // D28 / D10 - A10 - PB6 + PD, // D29 / D12 - A11 - PD6 +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + _BV(2), // D0 - PD2 + _BV(3), // D1 - PD3 + _BV(1), // D2 - PD1 + _BV(0), // D3 - PD0 + _BV(4), // D4 - PD4 + _BV(6), // D5 - PC6 + _BV(7), // D6 - PD7 + _BV(6), // D7 - PE6 + + _BV(4), // D8 - PB4 + _BV(5), // D9 - PB5 + _BV(6), // D10 - PB6 + _BV(7), // D11 - PB7 + _BV(6), // D12 - PD6 + _BV(7), // D13 - PC7 + + _BV(3), // D14 - MISO - PB3 + _BV(1), // D15 - SCK - PB1 + _BV(2), // D16 - MOSI - PB2 + _BV(0), // D17 - SS - PB0 + + _BV(7), // D18 - A0 - PF7 + _BV(6), // D19 - A1 - PF6 + _BV(5), // D20 - A2 - PF5 + _BV(4), // D21 - A3 - PF4 + _BV(1), // D22 - A4 - PF1 + _BV(0), // D23 - A5 - PF0 + + _BV(5), // D24 - PD5 + _BV(7), // D25 / D6 - A7 - PD7 + _BV(4), // D26 / D8 - A8 - PB4 + _BV(5), // D27 / D9 - A9 - PB5 + _BV(6), // D28 / D10 - A10 - PB6 + _BV(6), // D29 / D12 - A11 - PD6 +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + TIMER0B, /* 3 */ + NOT_ON_TIMER, + TIMER3A, /* 5 */ + TIMER4D, /* 6 */ + NOT_ON_TIMER, + + NOT_ON_TIMER, + TIMER1A, /* 9 */ + TIMER1B, /* 10 */ + TIMER0A, /* 11 */ + + NOT_ON_TIMER, + TIMER4A, /* 13 */ + + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, +}; + +const uint8_t PROGMEM analog_pin_to_channel_PGM[] = { + 7, // A0 PF7 ADC7 + 6, // A1 PF6 ADC6 + 5, // A2 PF5 ADC5 + 4, // A3 PF4 ADC4 + 1, // A4 PF1 ADC1 + 0, // A5 PF0 ADC0 + 8, // A6 D4 PD4 ADC8 + 10, // A7 D6 PD7 ADC10 + 11, // A8 D8 PB4 ADC11 + 12, // A9 D9 PB5 ADC12 + 13, // A10 D10 PB6 ADC13 + 9 // A11 D12 PD6 ADC9 +}; + +#endif /* ARDUINO_MAIN */ + +// These serial port names are intended to allow libraries and architecture-neutral +// sketches to automatically default to the correct port name for a particular type +// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, +// the first hardware serial port whose RX/TX pins are not dedicated to another use. +// +// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor +// +// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial +// +// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library +// +// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. +// +// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX +// pins are NOT connected to anything by default. +#define SERIAL_PORT_MONITOR Serial +#define SERIAL_PORT_USBVIRTUAL Serial +#define SERIAL_PORT_HARDWARE Serial1 +#define SERIAL_PORT_HARDWARE_OPEN Serial1 + +#endif /* Pins_Arduino_h */ diff --git a/keyboards/lets-split/readme.md b/keyboards/lets_split/readme.md similarity index 100% rename from keyboards/lets-split/readme.md rename to keyboards/lets_split/readme.md diff --git a/keyboards/lets_split/split_util.c b/keyboards/lets_split/split_util.c new file mode 100644 index 0000000000..c394596e0c --- /dev/null +++ b/keyboards/lets_split/split_util.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include "split_util.h" +#include "matrix.h" +#include "i2c.h" +#include "keyboard.h" +#include "config.h" + +volatile bool isLeftHand = true; + +static void setup_handedness(void) { + isLeftHand = eeprom_read_byte(EECONFIG_HANDEDNESS); +} + +static void keyboard_master_setup(void) { +#ifdef USE_I2C + i2c_master_init(); +#else + serial_master_init(); +#endif +} + +static void keyboard_slave_setup(void) { +#ifdef USE_I2C + i2c_slave_init(SLAVE_I2C_ADDRESS); +#else + serial_slave_init(); +#endif +} + +bool has_usb(void) { + USBCON |= (1 << OTGPADE); //enables VBUS pad + _delay_us(5); + return (USBSTA & (1< + +#define EECONFIG_BOOTMAGIC_END (uint8_t *)10 +#define EECONFIG_HANDEDNESS EECONFIG_BOOTMAGIC_END + +#define SLAVE_I2C_ADDRESS 0x32 + +extern volatile bool isLeftHand; + +// slave version of matix scan, defined in matrix.c +void matrix_slave_scan(void); + +void split_keyboard_setup(void); +bool has_usb(void); +void keyboard_slave_loop(void); + +#endif diff --git a/keyboards/lets_split/uno-slave/Makefile b/keyboards/lets_split/uno-slave/Makefile new file mode 100644 index 0000000000..84e67de113 --- /dev/null +++ b/keyboards/lets_split/uno-slave/Makefile @@ -0,0 +1,226 @@ +# Hey Emacs, this is a -*- makefile -*- + +# AVR-GCC Makefile template, derived from the WinAVR template (which +# is public domain), believed to be neutral to any flavor of "make" +# (GNU make, BSD make, SysV make) + + +MCU = atmega328p +FORMAT = ihex +TARGET = keyboard-i2c-slave +SRC = \ + $(TARGET).c \ + uno-matrix.c \ + ../serial.c \ + ../i2c-slave.c + +ASRC = +OPT = s + +# Programming support using avrdude. Settings and variables. + +AVRDUDE_PROGRAMMER = arduino +AVRDUDE_PORT = /dev/ttyACM0 + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 + +# Place -D or -U options here +CDEFS = + +# Place -I options here +CINCS = + + +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) +CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) \ + -fno-aggressive-loop-optimizations + +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs + + +#Additional libraries. + +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +PRINTF_LIB = + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +SCANF_LIB = + +MATH_LIB = -lm + +# External memory options + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + +#LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref +LDFLAGS = $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) + + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_BASIC = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS = $(AVRDUDE_BASIC) $(AVRDUDE_NO_VERIFY) $(AVRDUDE_VERBOSE) $(AVRDUDE_ERASE_COUNTER) + + +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: build + +build: elf hex eep + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: $(TARGET).elf + $(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof + + +extcoff: $(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + + +# Link: create ELF output file from object files. +$(TARGET).elf: $(OBJ) + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +.c.o: + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +# Target: clean project. +clean: + $(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \ + $(TARGET).map $(TARGET).sym $(TARGET).lss \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build elf hex eep lss sym program coff extcoff clean depend diff --git a/keyboards/lets_split/uno-slave/keyboard-i2c-slave.c b/keyboards/lets_split/uno-slave/keyboard-i2c-slave.c new file mode 100644 index 0000000000..2043e7b94f --- /dev/null +++ b/keyboards/lets_split/uno-slave/keyboard-i2c-slave.c @@ -0,0 +1,42 @@ +#include "../i2c-slave.h" +#include "../serial.h" +#include "uno-matrix.h" + +#include +#include +#include + +void setup(void) { + // give some time for noise to clear + _delay_us(1000); + + // turn off arduino uno's led on pin 13 + DDRB |= (1 << 5); + PORTB &= ~(1 << 5); + + matrix_init(); + /* i2c_slave_init(0x32); */ + serial_slave_init(); + + /* serial_slave_buffer[0] = 0xa1; */ + /* serial_slave_buffer[1] = 0x52; */ + /* serial_slave_buffer[2] = 0xa2; */ + /* serial_slave_buffer[3] = 0x67; */ + + // need interrupts for i2c slave code to work + sei(); +} + +void loop(void) { + matrix_scan(); + for(int i=0; i +#include +#include + +#include "uno-matrix.h" + +#define debug(X) NULL +#define debug_hex(X) NULL + +#ifndef DEBOUNCE +# define DEBOUNCE 5 +#endif + +static uint8_t debouncing = DEBOUNCE; + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; +static matrix_row_t matrix_debouncing[MATRIX_ROWS]; + +static matrix_row_t read_cols(void); +static void init_cols(void); +static void unselect_rows(void); +static void select_row(uint8_t row); + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + //debug_enable = true; + //debug_matrix = true; + //debug_mouse = true; + // initialize row and col + unselect_rows(); + init_cols(); + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + matrix_debouncing[i] = 0; + } +} + +uint8_t matrix_scan(void) +{ + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + select_row(i); + _delay_us(30); // without this wait read unstable value. + matrix_row_t cols = read_cols(); + //Serial.println(cols, BIN); + if (matrix_debouncing[i] != cols) { + matrix_debouncing[i] = cols; + if (debouncing) { + debug("bounce!: "); debug_hex(debouncing); debug("\n"); + } + debouncing = DEBOUNCE; + } + unselect_rows(); + } + + if (debouncing) { + if (--debouncing) { + _delay_ms(1); + } else { + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + matrix[i] = matrix_debouncing[i]; + } + } + } + + return 1; +} + +bool matrix_is_modified(void) +{ + if (debouncing) return false; + return true; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & ((matrix_row_t)1< + +typedef uint8_t matrix_row_t; + +uint8_t matrix_rows(void); +uint8_t matrix_cols(void); +void matrix_init(void); +uint8_t matrix_scan(void); +bool matrix_is_modified(void); +bool matrix_is_on(uint8_t row, uint8_t col); +matrix_row_t matrix_get_row(uint8_t row); + +#endif diff --git a/keyboards/lets_split/usbconfig.h b/keyboards/lets_split/usbconfig.h new file mode 100644 index 0000000000..d0ca4c717e --- /dev/null +++ b/keyboards/lets_split/usbconfig.h @@ -0,0 +1,377 @@ +/* Name: usbconfig.h + * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers + * Author: Christian Starkjohann + * Creation Date: 2005-04-01 + * Tabsize: 4 + * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) + * This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $ + */ + +#ifndef __usbconfig_h_included__ +#define __usbconfig_h_included__ + + +/* +General Description: +This file is an example configuration (with inline documentation) for the USB +driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is +also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may +wire the lines to any other port, as long as D+ is also wired to INT0 (or any +other hardware interrupt, as long as it is the highest level interrupt, see +section at the end of this file). +*/ + +/* ---------------------------- Hardware Config ---------------------------- */ + +#define USB_CFG_IOPORTNAME D +/* This is the port where the USB bus is connected. When you configure it to + * "B", the registers PORTB, PINB and DDRB will be used. + */ +#define USB_CFG_DMINUS_BIT 3 +/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. + * This may be any bit in the port. + */ +#define USB_CFG_DPLUS_BIT 2 +/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. + * This may be any bit in the port. Please note that D+ must also be connected + * to interrupt pin INT0! [You can also use other interrupts, see section + * "Optional MCU Description" below, or you can connect D- to the interrupt, as + * it is required if you use the USB_COUNT_SOF feature. If you use D- for the + * interrupt, the USB interrupt will also be triggered at Start-Of-Frame + * markers every millisecond.] + */ +#define USB_CFG_CLOCK_KHZ (F_CPU/1000) +/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, + * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code + * require no crystal, they tolerate +/- 1% deviation from the nominal + * frequency. All other rates require a precision of 2000 ppm and thus a + * crystal! + * Since F_CPU should be defined to your actual clock rate anyway, you should + * not need to modify this setting. + */ +#define USB_CFG_CHECK_CRC 0 +/* Define this to 1 if you want that the driver checks integrity of incoming + * data packets (CRC checks). CRC checks cost quite a bit of code size and are + * currently only available for 18 MHz crystal clock. You must choose + * USB_CFG_CLOCK_KHZ = 18000 if you enable this option. + */ + +/* ----------------------- Optional Hardware Config ------------------------ */ + +/* #define USB_CFG_PULLUP_IOPORTNAME D */ +/* If you connect the 1.5k pullup resistor from D- to a port pin instead of + * V+, you can connect and disconnect the device from firmware by calling + * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). + * This constant defines the port on which the pullup resistor is connected. + */ +/* #define USB_CFG_PULLUP_BIT 4 */ +/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined + * above) where the 1.5k pullup resistor is connected. See description + * above for details. + */ + +/* --------------------------- Functional Range ---------------------------- */ + +#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 +/* Define this to 1 if you want to compile a version with two endpoints: The + * default control endpoint 0 and an interrupt-in endpoint (any other endpoint + * number). + */ +#define USB_CFG_HAVE_INTRIN_ENDPOINT3 1 +/* Define this to 1 if you want to compile a version with three endpoints: The + * default control endpoint 0, an interrupt-in endpoint 3 (or the number + * configured below) and a catch-all default interrupt-in endpoint as above. + * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature. + */ +#define USB_CFG_EP3_NUMBER 3 +/* If the so-called endpoint 3 is used, it can now be configured to any other + * endpoint number (except 0) with this macro. Default if undefined is 3. + */ +/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */ +/* The above macro defines the startup condition for data toggling on the + * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1. + * Since the token is toggled BEFORE sending any data, the first packet is + * sent with the oposite value of this configuration! + */ +#define USB_CFG_IMPLEMENT_HALT 0 +/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature + * for endpoint 1 (interrupt endpoint). Although you may not need this feature, + * it is required by the standard. We have made it a config option because it + * bloats the code considerably. + */ +#define USB_CFG_SUPPRESS_INTR_CODE 0 +/* Define this to 1 if you want to declare interrupt-in endpoints, but don't + * want to send any data over them. If this macro is defined to 1, functions + * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if + * you need the interrupt-in endpoints in order to comply to an interface + * (e.g. HID), but never want to send any data. This option saves a couple + * of bytes in flash memory and the transmit buffers in RAM. + */ +#define USB_CFG_INTR_POLL_INTERVAL 10 +/* If you compile a version with endpoint 1 (interrupt-in), this is the poll + * interval. The value is in milliseconds and must not be less than 10 ms for + * low speed devices. + */ +#define USB_CFG_IS_SELF_POWERED 0 +/* Define this to 1 if the device has its own power supply. Set it to 0 if the + * device is powered from the USB bus. + */ +#define USB_CFG_MAX_BUS_POWER 100 +/* Set this variable to the maximum USB bus power consumption of your device. + * The value is in milliamperes. [It will be divided by two since USB + * communicates power requirements in units of 2 mA.] + */ +#define USB_CFG_IMPLEMENT_FN_WRITE 1 +/* Set this to 1 if you want usbFunctionWrite() to be called for control-out + * transfers. Set it to 0 if you don't need it and want to save a couple of + * bytes. + */ +#define USB_CFG_IMPLEMENT_FN_READ 0 +/* Set this to 1 if you need to send control replies which are generated + * "on the fly" when usbFunctionRead() is called. If you only want to send + * data from a static buffer, set it to 0 and return the data from + * usbFunctionSetup(). This saves a couple of bytes. + */ +#define USB_CFG_IMPLEMENT_FN_WRITEOUT 0 +/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints. + * You must implement the function usbFunctionWriteOut() which receives all + * interrupt/bulk data sent to any endpoint other than 0. The endpoint number + * can be found in 'usbRxToken'. + */ +#define USB_CFG_HAVE_FLOWCONTROL 0 +/* Define this to 1 if you want flowcontrol over USB data. See the definition + * of the macros usbDisableAllRequests() and usbEnableAllRequests() in + * usbdrv.h. + */ +#define USB_CFG_DRIVER_FLASH_PAGE 0 +/* If the device has more than 64 kBytes of flash, define this to the 64 k page + * where the driver's constants (descriptors) are located. Or in other words: + * Define this to 1 for boot loaders on the ATMega128. + */ +#define USB_CFG_LONG_TRANSFERS 0 +/* Define this to 1 if you want to send/receive blocks of more than 254 bytes + * in a single control-in or control-out transfer. Note that the capability + * for long transfers increases the driver size. + */ +/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */ +/* This macro is a hook if you want to do unconventional things. If it is + * defined, it's inserted at the beginning of received message processing. + * If you eat the received message and don't want default processing to + * proceed, do a return after doing your things. One possible application + * (besides debugging) is to flash a status LED on each packet. + */ +/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */ +/* This macro is a hook if you need to know when an USB RESET occurs. It has + * one parameter which distinguishes between the start of RESET state and its + * end. + */ +/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */ +/* This macro (if defined) is executed when a USB SET_ADDRESS request was + * received. + */ +#define USB_COUNT_SOF 0 +/* define this macro to 1 if you need the global variable "usbSofCount" which + * counts SOF packets. This feature requires that the hardware interrupt is + * connected to D- instead of D+. + */ +/* #ifdef __ASSEMBLER__ + * macro myAssemblerMacro + * in YL, TCNT0 + * sts timer0Snapshot, YL + * endm + * #endif + * #define USB_SOF_HOOK myAssemblerMacro + * This macro (if defined) is executed in the assembler module when a + * Start Of Frame condition is detected. It is recommended to define it to + * the name of an assembler macro which is defined here as well so that more + * than one assembler instruction can be used. The macro may use the register + * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages + * immediately after an SOF pulse may be lost and must be retried by the host. + * What can you do with this hook? Since the SOF signal occurs exactly every + * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in + * designs running on the internal RC oscillator. + * Please note that Start Of Frame detection works only if D- is wired to the + * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! + */ +#define USB_CFG_CHECK_DATA_TOGGLING 0 +/* define this macro to 1 if you want to filter out duplicate data packets + * sent by the host. Duplicates occur only as a consequence of communication + * errors, when the host does not receive an ACK. Please note that you need to + * implement the filtering yourself in usbFunctionWriteOut() and + * usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable + * for each control- and out-endpoint to check for duplicate packets. + */ +#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0 +/* define this macro to 1 if you want the function usbMeasureFrameLength() + * compiled in. This function can be used to calibrate the AVR's RC oscillator. + */ +#define USB_USE_FAST_CRC 0 +/* The assembler module has two implementations for the CRC algorithm. One is + * faster, the other is smaller. This CRC routine is only used for transmitted + * messages where timing is not critical. The faster routine needs 31 cycles + * per byte while the smaller one needs 61 to 69 cycles. The faster routine + * may be worth the 32 bytes bigger code size if you transmit lots of data and + * run the AVR close to its limit. + */ + +/* -------------------------- Device Description --------------------------- */ + +#define USB_CFG_VENDOR_ID (VENDOR_ID & 0xFF), ((VENDOR_ID >> 8) & 0xFF) +/* USB vendor ID for the device, low byte first. If you have registered your + * own Vendor ID, define it here. Otherwise you may use one of obdev's free + * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_ID (PRODUCT_ID & 0xFF), ((PRODUCT_ID >> 8) & 0xFF) +/* This is the ID of the product, low byte first. It is interpreted in the + * scope of the vendor ID. If you have registered your own VID with usb.org + * or if you have licensed a PID from somebody else, define it here. Otherwise + * you may use one of obdev's free shared VID/PID pairs. See the file + * USB-IDs-for-free.txt for details! + * *** IMPORTANT NOTE *** + * This template uses obdev's shared VID/PID pair for Vendor Class devices + * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand + * the implications! + */ +#define USB_CFG_DEVICE_VERSION 0x00, 0x01 +/* Version number of the device: Minor number first, then major number. + */ +#define USB_CFG_VENDOR_NAME 't', '.', 'm', '.', 'k', '.' +#define USB_CFG_VENDOR_NAME_LEN 6 +/* These two values define the vendor name returned by the USB device. The name + * must be given as a list of characters under single quotes. The characters + * are interpreted as Unicode (UTF-16) entities. + * If you don't want a vendor name string, undefine these macros. + * ALWAYS define a vendor name containing your Internet domain name if you use + * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for + * details. + */ +#define USB_CFG_DEVICE_NAME 'P', 'S', '/', '2', ' ', 'k', 'e', 'y', 'b', 'o', 'a', 'r', 'd', ' ', 'c', 'o', 'n', 'v', 'e', 'r', 't', 'e', 'r' +#define USB_CFG_DEVICE_NAME_LEN 23 +/* Same as above for the device name. If you don't want a device name, undefine + * the macros. See the file USB-IDs-for-free.txt before you assign a name if + * you use a shared VID/PID. + */ +/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ +/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ +/* Same as above for the serial number. If you don't want a serial number, + * undefine the macros. + * It may be useful to provide the serial number through other means than at + * compile time. See the section about descriptor properties below for how + * to fine tune control over USB descriptors such as the string descriptor + * for the serial number. + */ +#define USB_CFG_DEVICE_CLASS 0 +#define USB_CFG_DEVICE_SUBCLASS 0 +/* See USB specification if you want to conform to an existing device class. + * Class 0xff is "vendor specific". + */ +#define USB_CFG_INTERFACE_CLASS 3 /* HID */ +#define USB_CFG_INTERFACE_SUBCLASS 1 /* Boot */ +#define USB_CFG_INTERFACE_PROTOCOL 1 /* Keyboard */ +/* See USB specification if you want to conform to an existing device class or + * protocol. The following classes must be set at interface level: + * HID class is 3, no subclass and protocol required (but may be useful!) + * CDC class is 2, use subclass 2 and protocol 1 for ACM + */ +#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0 +/* Define this to the length of the HID report descriptor, if you implement + * an HID device. Otherwise don't define it or define it to 0. + * If you use this define, you must add a PROGMEM character array named + * "usbHidReportDescriptor" to your code which contains the report descriptor. + * Don't forget to keep the array and this define in sync! + */ + +/* #define USB_PUBLIC static */ +/* Use the define above if you #include usbdrv.c instead of linking against it. + * This technique saves a couple of bytes in flash memory. + */ + +/* ------------------- Fine Control over USB Descriptors ------------------- */ +/* If you don't want to use the driver's default USB descriptors, you can + * provide our own. These can be provided as (1) fixed length static data in + * flash memory, (2) fixed length static data in RAM or (3) dynamically at + * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more + * information about this function. + * Descriptor handling is configured through the descriptor's properties. If + * no properties are defined or if they are 0, the default descriptor is used. + * Possible properties are: + * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched + * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is + * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if + * you want RAM pointers. + * + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found + * in static memory is in RAM, not in flash memory. + * + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), + * the driver must know the descriptor's length. The descriptor itself is + * found at the address of a well known identifier (see below). + * List of static descriptor names (must be declared PROGMEM if in flash): + * char usbDescriptorDevice[]; + * char usbDescriptorConfiguration[]; + * char usbDescriptorHidReport[]; + * char usbDescriptorString0[]; + * int usbDescriptorStringVendor[]; + * int usbDescriptorStringDevice[]; + * int usbDescriptorStringSerialNumber[]; + * Other descriptors can't be provided statically, they must be provided + * dynamically at runtime. + * + * Descriptor properties are or-ed or added together, e.g.: + * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) + * + * The following descriptors are defined: + * USB_CFG_DESCR_PROPS_DEVICE + * USB_CFG_DESCR_PROPS_CONFIGURATION + * USB_CFG_DESCR_PROPS_STRINGS + * USB_CFG_DESCR_PROPS_STRING_0 + * USB_CFG_DESCR_PROPS_STRING_VENDOR + * USB_CFG_DESCR_PROPS_STRING_PRODUCT + * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER + * USB_CFG_DESCR_PROPS_HID + * USB_CFG_DESCR_PROPS_HID_REPORT + * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) + * + * Note about string descriptors: String descriptors are not just strings, they + * are Unicode strings prefixed with a 2 byte header. Example: + * int serialNumberDescriptor[] = { + * USB_STRING_DESCRIPTOR_HEADER(6), + * 'S', 'e', 'r', 'i', 'a', 'l' + * }; + */ + +#define USB_CFG_DESCR_PROPS_DEVICE 0 +#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC +//#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 +#define USB_CFG_DESCR_PROPS_STRINGS 0 +#define USB_CFG_DESCR_PROPS_STRING_0 0 +#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 +#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 +#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 +//#define USB_CFG_DESCR_PROPS_HID USB_PROP_IS_DYNAMIC +#define USB_CFG_DESCR_PROPS_HID 0 +#define USB_CFG_DESCR_PROPS_HID_REPORT USB_PROP_IS_DYNAMIC +//#define USB_CFG_DESCR_PROPS_HID_REPORT 0 +#define USB_CFG_DESCR_PROPS_UNKNOWN 0 + +/* ----------------------- Optional MCU Description ------------------------ */ + +/* The following configurations have working defaults in usbdrv.h. You + * usually don't need to set them explicitly. Only if you want to run + * the driver on a device which is not yet supported or with a compiler + * which is not fully supported (such as IAR C) or if you use a differnt + * interrupt than INT0, you may have to define some of these. + */ +/* #define USB_INTR_CFG MCUCR */ +/* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */ +/* #define USB_INTR_CFG_CLR 0 */ +/* #define USB_INTR_ENABLE GIMSK */ +/* #define USB_INTR_ENABLE_BIT INT0 */ +/* #define USB_INTR_PENDING GIFR */ +/* #define USB_INTR_PENDING_BIT INTF0 */ +/* #define USB_INTR_VECTOR INT0_vect */ + +#endif /* __usbconfig_h_included__ */ diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h index 71153a5f58..cee3593eee 100644 --- a/tmk_core/common/matrix.h +++ b/tmk_core/common/matrix.h @@ -72,6 +72,11 @@ void matrix_scan_kb(void); void matrix_init_user(void); void matrix_scan_user(void); +#ifdef I2C_SPLIT + void slave_matrix_init(void); + uint8_t slave_matrix_scan(void); +#endif + #ifdef __cplusplus } #endif From ce01f88c43adef9344727998f53bb1cf74913f65 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 5 Jul 2016 23:40:54 -0400 Subject: [PATCH 3/7] images, docks, clean-up [skip ci] --- .../imgs/split-keyboard-i2c-schematic.png | Bin 0 -> 26565 bytes .../imgs/split-keyboard-serial-schematic.png | Bin 0 -> 19487 bytes keyboards/lets_split/matrix.c | 1 + keyboards/lets_split/readme.md | 102 ++++++++ keyboards/lets_split/serial.c | 225 ++++++++++++++++++ keyboards/lets_split/serial.h | 26 ++ keyboards/lets_split/split_util.c | 9 + keyboards/lets_split/split_util.h | 6 +- .../{uno-slave => uno_slave}/Makefile | 0 .../keyboard-i2c-slave.c | 0 .../{uno-slave => uno_slave}/readme.md | 0 .../{uno-slave => uno_slave}/uno-matrix.c | 0 .../{uno-slave => uno_slave}/uno-matrix.h | 0 13 files changed, 367 insertions(+), 2 deletions(-) create mode 100644 keyboards/lets_split/imgs/split-keyboard-i2c-schematic.png create mode 100644 keyboards/lets_split/imgs/split-keyboard-serial-schematic.png create mode 100644 keyboards/lets_split/serial.c create mode 100644 keyboards/lets_split/serial.h rename keyboards/lets_split/{uno-slave => uno_slave}/Makefile (100%) rename keyboards/lets_split/{uno-slave => uno_slave}/keyboard-i2c-slave.c (100%) rename keyboards/lets_split/{uno-slave => uno_slave}/readme.md (100%) rename keyboards/lets_split/{uno-slave => uno_slave}/uno-matrix.c (100%) rename keyboards/lets_split/{uno-slave => uno_slave}/uno-matrix.h (100%) diff --git a/keyboards/lets_split/imgs/split-keyboard-i2c-schematic.png b/keyboards/lets_split/imgs/split-keyboard-i2c-schematic.png new file mode 100644 index 0000000000000000000000000000000000000000..8882947187b15ae4c0cf70c90725d67fb2386d87 GIT binary patch literal 26565 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. #include "util.h" #include "matrix.h" #include "i2c.h" +#include "serial.h" #include "split_util.h" #include "pro_micro.h" #include "config.h" diff --git a/keyboards/lets_split/readme.md b/keyboards/lets_split/readme.md index e69de29bb2..73fdb0f789 100644 --- a/keyboards/lets_split/readme.md +++ b/keyboards/lets_split/readme.md @@ -0,0 +1,102 @@ +Let's Split +====== + +This readme and most of the code are from https://github.com/ahtn/tmk_keyboard/ + +Split keyboard firmware for Arduino Pro Micro or other ATmega32u4 +based boards. + +Features +-------- + +Some features supported by the firmware: + +* Either half can connect to the computer via USB, or both halves can be used + independently. +* You only need 3 wires to connect the two halves. Two for VCC and GND and one + for serial communication. +* Optional support for I2C connection between the two halves if for some + reason you require a faster connection between the two halves. Note this + requires an extra wire between halves and pull-up resistors on the data lines. + +Required Hardware +----------------- + +Apart from diodes and key switches for the keyboard matrix in each half, you +will need: + +* 2 Arduino Pro Micro's. You can find theses on aliexpress for ≈3.50USD each. +* 2 TRS sockets +* 1 TRS cable. + +Alternatively, you can use any sort of cable and socket that has at least 3 +wires. If you want to use I2C to communicate between halves, you will need a +cable with at least 4 wires and 2x 4.7kΩ pull-up resistors + +Optional Hardware +----------------- + +A speaker can be hooked-up to either side to the `5` (`C6`) pin and `GND`, and turned on via `AUDIO_ENABLE`. + +Wiring +------ + +The 3 wires of the TRS cable need to connect GND, VCC, and digital pin 3 (i.e. +PD0 on the ATmega32u4) between the two Pro Micros. + +Then wire your key matrix to any of the remaining 17 IO pins of the pro micro +and modify the `matrix.c` accordingly. + +The wiring for serial: + +![serial wiring](imgs/split-keyboard-serial-schematic.png) + +The wiring for i2c: + +![i2c wiring](imgs/split-keyboard-i2c-schematic.png) + +The pull-up resistors may be placed on either half. It is also possible +to use 4 resistors and have the pull-ups in both halves, but this is +unnecessary in simple use cases. + +Notes on Software Configuration +------------------------------- + +Configuring the firmware is similar to any other TMK project. One thing +to note is that `MATIX_ROWS` in `config.h` is the total number of rows between +the two halves, i.e. if your split keyboard has 4 rows in each half, then +`MATRIX_ROWS=8`. + +Also the current implementation assumes a maximum of 8 columns, but it would +not be very difficult to adapt it to support more if required. + + +Flashing +-------- + +If you define `EE_HANDS` in your `config.h`, you will need to set the +EEPROM for the left and right halves. The EEPROM is used to store whether the +half is left handed or right handed. This makes it so that the same firmware +file will run on both hands instead of having to flash left and right handed +versions of the firmware to each half. To flash the EEPROM file for the left +half run: +``` +make eeprom-left +``` +and similarly for right half +``` +make eeprom-right +``` + +After you have flashed the EEPROM for the first time, you then need to program +the flash memory: +``` +make program +``` +Note that you need to program both halves, but you have the option of using +different keymaps for each half. You could program the left half with a QWERTY +layout and the right half with a Colemak layout. Then if you connect the left +half to a computer by USB the keyboard will use QWERTY and Colemak when the +right half is connected. + + diff --git a/keyboards/lets_split/serial.c b/keyboards/lets_split/serial.c new file mode 100644 index 0000000000..f439c2f20b --- /dev/null +++ b/keyboards/lets_split/serial.c @@ -0,0 +1,225 @@ +/* + * WARNING: be careful changing this code, it is very timing dependent + */ + +#ifndef F_CPU +#define F_CPU 16000000 +#endif + +#include +#include +#include +#include + +#include "serial.h" + +// Serial pulse period in microseconds. Its probably a bad idea to lower this +// value. +#define SERIAL_DELAY 24 + +uint8_t volatile serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH] = {0}; +uint8_t volatile serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH] = {0}; + +#define SLAVE_DATA_CORRUPT (1<<0) +volatile uint8_t status = 0; + +inline static +void serial_delay(void) { + _delay_us(SERIAL_DELAY); +} + +inline static +void serial_output(void) { + SERIAL_PIN_DDR |= SERIAL_PIN_MASK; +} + +// make the serial pin an input with pull-up resistor +inline static +void serial_input(void) { + SERIAL_PIN_DDR &= ~SERIAL_PIN_MASK; + SERIAL_PIN_PORT |= SERIAL_PIN_MASK; +} + +inline static +uint8_t serial_read_pin(void) { + return !!(SERIAL_PIN_INPUT & SERIAL_PIN_MASK); +} + +inline static +void serial_low(void) { + SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK; +} + +inline static +void serial_high(void) { + SERIAL_PIN_PORT |= SERIAL_PIN_MASK; +} + +void serial_master_init(void) { + serial_output(); + serial_high(); +} + +void serial_slave_init(void) { + serial_input(); + + // Enable INT0 + EIMSK |= _BV(INT0); + // Trigger on falling edge of INT0 + EICRA &= ~(_BV(ISC00) | _BV(ISC01)); +} + +// Used by the master to synchronize timing with the slave. +static +void sync_recv(void) { + serial_input(); + // This shouldn't hang if the slave disconnects because the + // serial line will float to high if the slave does disconnect. + while (!serial_read_pin()); + serial_delay(); +} + +// Used by the slave to send a synchronization signal to the master. +static +void sync_send(void) { + serial_output(); + + serial_low(); + serial_delay(); + + serial_high(); +} + +// Reads a byte from the serial line +static +uint8_t serial_read_byte(void) { + uint8_t byte = 0; + serial_input(); + for ( uint8_t i = 0; i < 8; ++i) { + byte = (byte << 1) | serial_read_pin(); + serial_delay(); + _delay_us(1); + } + + return byte; +} + +// Sends a byte with MSB ordering +static +void serial_write_byte(uint8_t data) { + uint8_t b = 8; + serial_output(); + while( b-- ) { + if(data & (1 << b)) { + serial_high(); + } else { + serial_low(); + } + serial_delay(); + } +} + +// interrupt handle to be used by the slave device +ISR(SERIAL_PIN_INTERRUPT) { + sync_send(); + + uint8_t checksum = 0; + for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) { + serial_write_byte(serial_slave_buffer[i]); + sync_send(); + checksum += serial_slave_buffer[i]; + } + serial_write_byte(checksum); + sync_send(); + + // wait for the sync to finish sending + serial_delay(); + + // read the middle of pulses + _delay_us(SERIAL_DELAY/2); + + uint8_t checksum_computed = 0; + for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) { + serial_master_buffer[i] = serial_read_byte(); + sync_send(); + checksum_computed += serial_master_buffer[i]; + } + uint8_t checksum_received = serial_read_byte(); + sync_send(); + + serial_input(); // end transaction + + if ( checksum_computed != checksum_received ) { + status |= SLAVE_DATA_CORRUPT; + } else { + status &= ~SLAVE_DATA_CORRUPT; + } +} + +inline +bool serial_slave_DATA_CORRUPT(void) { + return status & SLAVE_DATA_CORRUPT; +} + +// Copies the serial_slave_buffer to the master and sends the +// serial_master_buffer to the slave. +// +// Returns: +// 0 => no error +// 1 => slave did not respond +int serial_update_buffers(void) { + // this code is very time dependent, so we need to disable interrupts + cli(); + + // signal to the slave that we want to start a transaction + serial_output(); + serial_low(); + _delay_us(1); + + // wait for the slaves response + serial_input(); + serial_high(); + _delay_us(SERIAL_DELAY); + + // check if the slave is present + if (serial_read_pin()) { + // slave failed to pull the line low, assume not present + sei(); + return 1; + } + + // if the slave is present syncronize with it + sync_recv(); + + uint8_t checksum_computed = 0; + // receive data from the slave + for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) { + serial_slave_buffer[i] = serial_read_byte(); + sync_recv(); + checksum_computed += serial_slave_buffer[i]; + } + uint8_t checksum_received = serial_read_byte(); + sync_recv(); + + if (checksum_computed != checksum_received) { + sei(); + return 1; + } + + uint8_t checksum = 0; + // send data to the slave + for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) { + serial_write_byte(serial_master_buffer[i]); + sync_recv(); + checksum += serial_master_buffer[i]; + } + serial_write_byte(checksum); + sync_recv(); + + // always, release the line when not in use + serial_output(); + serial_high(); + + sei(); + return 0; +} diff --git a/keyboards/lets_split/serial.h b/keyboards/lets_split/serial.h new file mode 100644 index 0000000000..15fe4db7b4 --- /dev/null +++ b/keyboards/lets_split/serial.h @@ -0,0 +1,26 @@ +#ifndef MY_SERIAL_H +#define MY_SERIAL_H + +#include "config.h" +#include + +/* TODO: some defines for interrupt setup */ +#define SERIAL_PIN_DDR DDRD +#define SERIAL_PIN_PORT PORTD +#define SERIAL_PIN_INPUT PIND +#define SERIAL_PIN_MASK _BV(PD0) +#define SERIAL_PIN_INTERRUPT INT0_vect + +#define SERIAL_SLAVE_BUFFER_LENGTH MATRIX_ROWS/2 +#define SERIAL_MASTER_BUFFER_LENGTH 1 + +// Buffers for master - slave communication +extern volatile uint8_t serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH]; +extern volatile uint8_t serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH]; + +void serial_master_init(void); +void serial_slave_init(void); +int serial_update_buffers(void); +bool serial_slave_data_corrupt(void); + +#endif diff --git a/keyboards/lets_split/split_util.c b/keyboards/lets_split/split_util.c index c394596e0c..65003a71a4 100644 --- a/keyboards/lets_split/split_util.c +++ b/keyboards/lets_split/split_util.c @@ -7,13 +7,22 @@ #include "split_util.h" #include "matrix.h" #include "i2c.h" +#include "serial.h" #include "keyboard.h" #include "config.h" volatile bool isLeftHand = true; static void setup_handedness(void) { + #ifdef EE_HANDS isLeftHand = eeprom_read_byte(EECONFIG_HANDEDNESS); + #else + #ifdef I2C_MASTER_RIGHT + isLeftHand = !has_usb(); + #else + isLeftHand = has_usb(); + #endif + #endif } static void keyboard_master_setup(void) { diff --git a/keyboards/lets_split/split_util.h b/keyboards/lets_split/split_util.h index cf6890d37f..6b896679ca 100644 --- a/keyboards/lets_split/split_util.h +++ b/keyboards/lets_split/split_util.h @@ -3,8 +3,10 @@ #include -#define EECONFIG_BOOTMAGIC_END (uint8_t *)10 -#define EECONFIG_HANDEDNESS EECONFIG_BOOTMAGIC_END +#ifdef EE_HANDS + #define EECONFIG_BOOTMAGIC_END (uint8_t *)10 + #define EECONFIG_HANDEDNESS EECONFIG_BOOTMAGIC_END +#endif #define SLAVE_I2C_ADDRESS 0x32 diff --git a/keyboards/lets_split/uno-slave/Makefile b/keyboards/lets_split/uno_slave/Makefile similarity index 100% rename from keyboards/lets_split/uno-slave/Makefile rename to keyboards/lets_split/uno_slave/Makefile diff --git a/keyboards/lets_split/uno-slave/keyboard-i2c-slave.c b/keyboards/lets_split/uno_slave/keyboard-i2c-slave.c similarity index 100% rename from keyboards/lets_split/uno-slave/keyboard-i2c-slave.c rename to keyboards/lets_split/uno_slave/keyboard-i2c-slave.c diff --git a/keyboards/lets_split/uno-slave/readme.md b/keyboards/lets_split/uno_slave/readme.md similarity index 100% rename from keyboards/lets_split/uno-slave/readme.md rename to keyboards/lets_split/uno_slave/readme.md diff --git a/keyboards/lets_split/uno-slave/uno-matrix.c b/keyboards/lets_split/uno_slave/uno-matrix.c similarity index 100% rename from keyboards/lets_split/uno-slave/uno-matrix.c rename to keyboards/lets_split/uno_slave/uno-matrix.c diff --git a/keyboards/lets_split/uno-slave/uno-matrix.h b/keyboards/lets_split/uno_slave/uno-matrix.h similarity index 100% rename from keyboards/lets_split/uno-slave/uno-matrix.h rename to keyboards/lets_split/uno_slave/uno-matrix.h From dd2522ba8b4acbf4bcd882d5e81df6410d9b69fb Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 5 Jul 2016 23:52:18 -0400 Subject: [PATCH 4/7] add options to config.h --- keyboards/lets_split/config.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/keyboards/lets_split/config.h b/keyboards/lets_split/config.h index e68787e0b5..5937ca44e2 100644 --- a/keyboards/lets_split/config.h +++ b/keyboards/lets_split/config.h @@ -29,6 +29,7 @@ along with this program. If not, see . #define DESCRIPTION A split keyboard for the cheap makers /* key matrix size */ +// Rows are doubled-up #define MATRIX_ROWS 8 #define MATRIX_COLS 6 @@ -38,8 +39,10 @@ along with this program. If not, see . #define USE_I2C -// #define I2C_MASTER_LEFT -#define I2C_MASTER_RIGHT +// #define EE_HANDS + +#define I2C_MASTER_LEFT +// #define I2C_MASTER_RIGHT /* COL2ROW or ROW2COL */ #define DIODE_DIRECTION COL2ROW From cb410729e631af9f962726c394956401b7c18079 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 5 Jul 2016 23:56:42 -0400 Subject: [PATCH 5/7] remove uno_slave for now, even though it's freakin cool --- keyboards/lets_split/uno_slave/Makefile | 226 ------------------ .../lets_split/uno_slave/keyboard-i2c-slave.c | 42 ---- keyboards/lets_split/uno_slave/readme.md | 1 - keyboards/lets_split/uno_slave/uno-matrix.c | 160 ------------- keyboards/lets_split/uno_slave/uno-matrix.h | 19 -- 5 files changed, 448 deletions(-) delete mode 100644 keyboards/lets_split/uno_slave/Makefile delete mode 100644 keyboards/lets_split/uno_slave/keyboard-i2c-slave.c delete mode 100644 keyboards/lets_split/uno_slave/readme.md delete mode 100644 keyboards/lets_split/uno_slave/uno-matrix.c delete mode 100644 keyboards/lets_split/uno_slave/uno-matrix.h diff --git a/keyboards/lets_split/uno_slave/Makefile b/keyboards/lets_split/uno_slave/Makefile deleted file mode 100644 index 84e67de113..0000000000 --- a/keyboards/lets_split/uno_slave/Makefile +++ /dev/null @@ -1,226 +0,0 @@ -# Hey Emacs, this is a -*- makefile -*- - -# AVR-GCC Makefile template, derived from the WinAVR template (which -# is public domain), believed to be neutral to any flavor of "make" -# (GNU make, BSD make, SysV make) - - -MCU = atmega328p -FORMAT = ihex -TARGET = keyboard-i2c-slave -SRC = \ - $(TARGET).c \ - uno-matrix.c \ - ../serial.c \ - ../i2c-slave.c - -ASRC = -OPT = s - -# Programming support using avrdude. Settings and variables. - -AVRDUDE_PROGRAMMER = arduino -AVRDUDE_PORT = /dev/ttyACM0 - -# Name of this Makefile (used for "make depend"). -MAKEFILE = Makefile - -# Debugging format. -# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. -# AVR (extended) COFF requires stabs, plus an avr-objcopy run. -DEBUG = stabs - -# Compiler flag to set the C Standard level. -# c89 - "ANSI" C -# gnu89 - c89 plus GCC extensions -# c99 - ISO C99 standard (not yet fully implemented) -# gnu99 - c99 plus GCC extensions -CSTANDARD = -std=gnu99 - -# Place -D or -U options here -CDEFS = - -# Place -I options here -CINCS = - - -CDEBUG = -g$(DEBUG) -CWARN = -Wall -Wstrict-prototypes -CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) -CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) \ - -fno-aggressive-loop-optimizations - -#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs - - -#Additional libraries. - -# Minimalistic printf version -PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min - -# Floating point printf version (requires MATH_LIB = -lm below) -PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt - -PRINTF_LIB = - -# Minimalistic scanf version -SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min - -# Floating point + %[ scanf version (requires MATH_LIB = -lm below) -SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt - -SCANF_LIB = - -MATH_LIB = -lm - -# External memory options - -# 64 KB of external RAM, starting after internal RAM (ATmega128!), -# used for variables (.data/.bss) and heap (malloc()). -#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff - -# 64 KB of external RAM, starting after internal RAM (ATmega128!), -# only used for heap (malloc()). -#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff - -EXTMEMOPTS = - -#LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref -LDFLAGS = $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) - - -AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex -#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep - - -# Uncomment the following if you want avrdude's erase cycle counter. -# Note that this counter needs to be initialized first using -Yn, -# see avrdude manual. -#AVRDUDE_ERASE_COUNTER = -y - -# Uncomment the following if you do /not/ wish a verification to be -# performed after programming the device. -#AVRDUDE_NO_VERIFY = -V - -# Increase verbosity level. Please use this when submitting bug -# reports about avrdude. See -# to submit bug reports. -#AVRDUDE_VERBOSE = -v -v - -AVRDUDE_BASIC = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -AVRDUDE_FLAGS = $(AVRDUDE_BASIC) $(AVRDUDE_NO_VERIFY) $(AVRDUDE_VERBOSE) $(AVRDUDE_ERASE_COUNTER) - - -CC = avr-gcc -OBJCOPY = avr-objcopy -OBJDUMP = avr-objdump -SIZE = avr-size -NM = avr-nm -AVRDUDE = avrdude -REMOVE = rm -f -MV = mv -f - -# Define all object files. -OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) - -# Define all listing files. -LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) - -# Combine all necessary flags and optional flags. -# Add target processor to flags. -ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) -ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) - - -# Default target. -all: build - -build: elf hex eep - -elf: $(TARGET).elf -hex: $(TARGET).hex -eep: $(TARGET).eep -lss: $(TARGET).lss -sym: $(TARGET).sym - - -# Program the device. -program: $(TARGET).hex $(TARGET).eep - $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) - - -# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. -COFFCONVERT=$(OBJCOPY) --debugging \ ---change-section-address .data-0x800000 \ ---change-section-address .bss-0x800000 \ ---change-section-address .noinit-0x800000 \ ---change-section-address .eeprom-0x810000 - - -coff: $(TARGET).elf - $(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof - - -extcoff: $(TARGET).elf - $(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof - - -.SUFFIXES: .elf .hex .eep .lss .sym - -.elf.hex: - $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ - -.elf.eep: - -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ - --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ - -# Create extended listing file from ELF output file. -.elf.lss: - $(OBJDUMP) -h -S $< > $@ - -# Create a symbol table from ELF output file. -.elf.sym: - $(NM) -n $< > $@ - - - -# Link: create ELF output file from object files. -$(TARGET).elf: $(OBJ) - $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) - - -# Compile: create object files from C source files. -.c.o: - $(CC) -c $(ALL_CFLAGS) $< -o $@ - - -# Compile: create assembler files from C source files. -.c.s: - $(CC) -S $(ALL_CFLAGS) $< -o $@ - - -# Assemble: create object files from assembler source files. -.S.o: - $(CC) -c $(ALL_ASFLAGS) $< -o $@ - - - -# Target: clean project. -clean: - $(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \ - $(TARGET).map $(TARGET).sym $(TARGET).lss \ - $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) - -depend: - if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ - then \ - sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ - $(MAKEFILE).$$$$ && \ - $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ - fi - echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ - >> $(MAKEFILE); \ - $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) - -.PHONY: all build elf hex eep lss sym program coff extcoff clean depend diff --git a/keyboards/lets_split/uno_slave/keyboard-i2c-slave.c b/keyboards/lets_split/uno_slave/keyboard-i2c-slave.c deleted file mode 100644 index 2043e7b94f..0000000000 --- a/keyboards/lets_split/uno_slave/keyboard-i2c-slave.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "../i2c-slave.h" -#include "../serial.h" -#include "uno-matrix.h" - -#include -#include -#include - -void setup(void) { - // give some time for noise to clear - _delay_us(1000); - - // turn off arduino uno's led on pin 13 - DDRB |= (1 << 5); - PORTB &= ~(1 << 5); - - matrix_init(); - /* i2c_slave_init(0x32); */ - serial_slave_init(); - - /* serial_slave_buffer[0] = 0xa1; */ - /* serial_slave_buffer[1] = 0x52; */ - /* serial_slave_buffer[2] = 0xa2; */ - /* serial_slave_buffer[3] = 0x67; */ - - // need interrupts for i2c slave code to work - sei(); -} - -void loop(void) { - matrix_scan(); - for(int i=0; i -#include -#include - -#include "uno-matrix.h" - -#define debug(X) NULL -#define debug_hex(X) NULL - -#ifndef DEBOUNCE -# define DEBOUNCE 5 -#endif - -static uint8_t debouncing = DEBOUNCE; - -/* matrix state(1:on, 0:off) */ -static matrix_row_t matrix[MATRIX_ROWS]; -static matrix_row_t matrix_debouncing[MATRIX_ROWS]; - -static matrix_row_t read_cols(void); -static void init_cols(void); -static void unselect_rows(void); -static void select_row(uint8_t row); - -inline -uint8_t matrix_rows(void) -{ - return MATRIX_ROWS; -} - -inline -uint8_t matrix_cols(void) -{ - return MATRIX_COLS; -} - -void matrix_init(void) -{ - //debug_enable = true; - //debug_matrix = true; - //debug_mouse = true; - // initialize row and col - unselect_rows(); - init_cols(); - - // initialize matrix state: all keys off - for (uint8_t i=0; i < MATRIX_ROWS; i++) { - matrix[i] = 0; - matrix_debouncing[i] = 0; - } -} - -uint8_t matrix_scan(void) -{ - for (uint8_t i = 0; i < MATRIX_ROWS; i++) { - select_row(i); - _delay_us(30); // without this wait read unstable value. - matrix_row_t cols = read_cols(); - //Serial.println(cols, BIN); - if (matrix_debouncing[i] != cols) { - matrix_debouncing[i] = cols; - if (debouncing) { - debug("bounce!: "); debug_hex(debouncing); debug("\n"); - } - debouncing = DEBOUNCE; - } - unselect_rows(); - } - - if (debouncing) { - if (--debouncing) { - _delay_ms(1); - } else { - for (uint8_t i = 0; i < MATRIX_ROWS; i++) { - matrix[i] = matrix_debouncing[i]; - } - } - } - - return 1; -} - -bool matrix_is_modified(void) -{ - if (debouncing) return false; - return true; -} - -inline -bool matrix_is_on(uint8_t row, uint8_t col) -{ - return (matrix[row] & ((matrix_row_t)1< - -typedef uint8_t matrix_row_t; - -uint8_t matrix_rows(void); -uint8_t matrix_cols(void); -void matrix_init(void); -uint8_t matrix_scan(void); -bool matrix_is_modified(void); -bool matrix_is_on(uint8_t row, uint8_t col); -matrix_row_t matrix_get_row(uint8_t row); - -#endif From eb6e17be6fc378fdfb8c5c2c7253c17ffc07d225 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 6 Jul 2016 09:04:04 -0400 Subject: [PATCH 6/7] adds eep, removes usbconfig.h --- keyboards/lets_split/eeprom-lefthand.eep | 2 + keyboards/lets_split/eeprom-righthand.eep | 2 + keyboards/lets_split/usbconfig.h | 377 ---------------------- 3 files changed, 4 insertions(+), 377 deletions(-) create mode 100644 keyboards/lets_split/eeprom-lefthand.eep create mode 100644 keyboards/lets_split/eeprom-righthand.eep delete mode 100644 keyboards/lets_split/usbconfig.h diff --git a/keyboards/lets_split/eeprom-lefthand.eep b/keyboards/lets_split/eeprom-lefthand.eep new file mode 100644 index 0000000000..a92200b124 --- /dev/null +++ b/keyboards/lets_split/eeprom-lefthand.eep @@ -0,0 +1,2 @@ +:080000000000000000000001F7 +:00000001FF diff --git a/keyboards/lets_split/eeprom-righthand.eep b/keyboards/lets_split/eeprom-righthand.eep new file mode 100644 index 0000000000..91a6831704 --- /dev/null +++ b/keyboards/lets_split/eeprom-righthand.eep @@ -0,0 +1,2 @@ +:080000000000000000000000F8 +:00000001FF diff --git a/keyboards/lets_split/usbconfig.h b/keyboards/lets_split/usbconfig.h deleted file mode 100644 index d0ca4c717e..0000000000 --- a/keyboards/lets_split/usbconfig.h +++ /dev/null @@ -1,377 +0,0 @@ -/* Name: usbconfig.h - * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers - * Author: Christian Starkjohann - * Creation Date: 2005-04-01 - * Tabsize: 4 - * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH - * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) - * This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $ - */ - -#ifndef __usbconfig_h_included__ -#define __usbconfig_h_included__ - - -/* -General Description: -This file is an example configuration (with inline documentation) for the USB -driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is -also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may -wire the lines to any other port, as long as D+ is also wired to INT0 (or any -other hardware interrupt, as long as it is the highest level interrupt, see -section at the end of this file). -*/ - -/* ---------------------------- Hardware Config ---------------------------- */ - -#define USB_CFG_IOPORTNAME D -/* This is the port where the USB bus is connected. When you configure it to - * "B", the registers PORTB, PINB and DDRB will be used. - */ -#define USB_CFG_DMINUS_BIT 3 -/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. - * This may be any bit in the port. - */ -#define USB_CFG_DPLUS_BIT 2 -/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. - * This may be any bit in the port. Please note that D+ must also be connected - * to interrupt pin INT0! [You can also use other interrupts, see section - * "Optional MCU Description" below, or you can connect D- to the interrupt, as - * it is required if you use the USB_COUNT_SOF feature. If you use D- for the - * interrupt, the USB interrupt will also be triggered at Start-Of-Frame - * markers every millisecond.] - */ -#define USB_CFG_CLOCK_KHZ (F_CPU/1000) -/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000, - * 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code - * require no crystal, they tolerate +/- 1% deviation from the nominal - * frequency. All other rates require a precision of 2000 ppm and thus a - * crystal! - * Since F_CPU should be defined to your actual clock rate anyway, you should - * not need to modify this setting. - */ -#define USB_CFG_CHECK_CRC 0 -/* Define this to 1 if you want that the driver checks integrity of incoming - * data packets (CRC checks). CRC checks cost quite a bit of code size and are - * currently only available for 18 MHz crystal clock. You must choose - * USB_CFG_CLOCK_KHZ = 18000 if you enable this option. - */ - -/* ----------------------- Optional Hardware Config ------------------------ */ - -/* #define USB_CFG_PULLUP_IOPORTNAME D */ -/* If you connect the 1.5k pullup resistor from D- to a port pin instead of - * V+, you can connect and disconnect the device from firmware by calling - * the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h). - * This constant defines the port on which the pullup resistor is connected. - */ -/* #define USB_CFG_PULLUP_BIT 4 */ -/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined - * above) where the 1.5k pullup resistor is connected. See description - * above for details. - */ - -/* --------------------------- Functional Range ---------------------------- */ - -#define USB_CFG_HAVE_INTRIN_ENDPOINT 1 -/* Define this to 1 if you want to compile a version with two endpoints: The - * default control endpoint 0 and an interrupt-in endpoint (any other endpoint - * number). - */ -#define USB_CFG_HAVE_INTRIN_ENDPOINT3 1 -/* Define this to 1 if you want to compile a version with three endpoints: The - * default control endpoint 0, an interrupt-in endpoint 3 (or the number - * configured below) and a catch-all default interrupt-in endpoint as above. - * You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature. - */ -#define USB_CFG_EP3_NUMBER 3 -/* If the so-called endpoint 3 is used, it can now be configured to any other - * endpoint number (except 0) with this macro. Default if undefined is 3. - */ -/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */ -/* The above macro defines the startup condition for data toggling on the - * interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1. - * Since the token is toggled BEFORE sending any data, the first packet is - * sent with the oposite value of this configuration! - */ -#define USB_CFG_IMPLEMENT_HALT 0 -/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature - * for endpoint 1 (interrupt endpoint). Although you may not need this feature, - * it is required by the standard. We have made it a config option because it - * bloats the code considerably. - */ -#define USB_CFG_SUPPRESS_INTR_CODE 0 -/* Define this to 1 if you want to declare interrupt-in endpoints, but don't - * want to send any data over them. If this macro is defined to 1, functions - * usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if - * you need the interrupt-in endpoints in order to comply to an interface - * (e.g. HID), but never want to send any data. This option saves a couple - * of bytes in flash memory and the transmit buffers in RAM. - */ -#define USB_CFG_INTR_POLL_INTERVAL 10 -/* If you compile a version with endpoint 1 (interrupt-in), this is the poll - * interval. The value is in milliseconds and must not be less than 10 ms for - * low speed devices. - */ -#define USB_CFG_IS_SELF_POWERED 0 -/* Define this to 1 if the device has its own power supply. Set it to 0 if the - * device is powered from the USB bus. - */ -#define USB_CFG_MAX_BUS_POWER 100 -/* Set this variable to the maximum USB bus power consumption of your device. - * The value is in milliamperes. [It will be divided by two since USB - * communicates power requirements in units of 2 mA.] - */ -#define USB_CFG_IMPLEMENT_FN_WRITE 1 -/* Set this to 1 if you want usbFunctionWrite() to be called for control-out - * transfers. Set it to 0 if you don't need it and want to save a couple of - * bytes. - */ -#define USB_CFG_IMPLEMENT_FN_READ 0 -/* Set this to 1 if you need to send control replies which are generated - * "on the fly" when usbFunctionRead() is called. If you only want to send - * data from a static buffer, set it to 0 and return the data from - * usbFunctionSetup(). This saves a couple of bytes. - */ -#define USB_CFG_IMPLEMENT_FN_WRITEOUT 0 -/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints. - * You must implement the function usbFunctionWriteOut() which receives all - * interrupt/bulk data sent to any endpoint other than 0. The endpoint number - * can be found in 'usbRxToken'. - */ -#define USB_CFG_HAVE_FLOWCONTROL 0 -/* Define this to 1 if you want flowcontrol over USB data. See the definition - * of the macros usbDisableAllRequests() and usbEnableAllRequests() in - * usbdrv.h. - */ -#define USB_CFG_DRIVER_FLASH_PAGE 0 -/* If the device has more than 64 kBytes of flash, define this to the 64 k page - * where the driver's constants (descriptors) are located. Or in other words: - * Define this to 1 for boot loaders on the ATMega128. - */ -#define USB_CFG_LONG_TRANSFERS 0 -/* Define this to 1 if you want to send/receive blocks of more than 254 bytes - * in a single control-in or control-out transfer. Note that the capability - * for long transfers increases the driver size. - */ -/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */ -/* This macro is a hook if you want to do unconventional things. If it is - * defined, it's inserted at the beginning of received message processing. - * If you eat the received message and don't want default processing to - * proceed, do a return after doing your things. One possible application - * (besides debugging) is to flash a status LED on each packet. - */ -/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */ -/* This macro is a hook if you need to know when an USB RESET occurs. It has - * one parameter which distinguishes between the start of RESET state and its - * end. - */ -/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */ -/* This macro (if defined) is executed when a USB SET_ADDRESS request was - * received. - */ -#define USB_COUNT_SOF 0 -/* define this macro to 1 if you need the global variable "usbSofCount" which - * counts SOF packets. This feature requires that the hardware interrupt is - * connected to D- instead of D+. - */ -/* #ifdef __ASSEMBLER__ - * macro myAssemblerMacro - * in YL, TCNT0 - * sts timer0Snapshot, YL - * endm - * #endif - * #define USB_SOF_HOOK myAssemblerMacro - * This macro (if defined) is executed in the assembler module when a - * Start Of Frame condition is detected. It is recommended to define it to - * the name of an assembler macro which is defined here as well so that more - * than one assembler instruction can be used. The macro may use the register - * YL and modify SREG. If it lasts longer than a couple of cycles, USB messages - * immediately after an SOF pulse may be lost and must be retried by the host. - * What can you do with this hook? Since the SOF signal occurs exactly every - * 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in - * designs running on the internal RC oscillator. - * Please note that Start Of Frame detection works only if D- is wired to the - * interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES! - */ -#define USB_CFG_CHECK_DATA_TOGGLING 0 -/* define this macro to 1 if you want to filter out duplicate data packets - * sent by the host. Duplicates occur only as a consequence of communication - * errors, when the host does not receive an ACK. Please note that you need to - * implement the filtering yourself in usbFunctionWriteOut() and - * usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable - * for each control- and out-endpoint to check for duplicate packets. - */ -#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0 -/* define this macro to 1 if you want the function usbMeasureFrameLength() - * compiled in. This function can be used to calibrate the AVR's RC oscillator. - */ -#define USB_USE_FAST_CRC 0 -/* The assembler module has two implementations for the CRC algorithm. One is - * faster, the other is smaller. This CRC routine is only used for transmitted - * messages where timing is not critical. The faster routine needs 31 cycles - * per byte while the smaller one needs 61 to 69 cycles. The faster routine - * may be worth the 32 bytes bigger code size if you transmit lots of data and - * run the AVR close to its limit. - */ - -/* -------------------------- Device Description --------------------------- */ - -#define USB_CFG_VENDOR_ID (VENDOR_ID & 0xFF), ((VENDOR_ID >> 8) & 0xFF) -/* USB vendor ID for the device, low byte first. If you have registered your - * own Vendor ID, define it here. Otherwise you may use one of obdev's free - * shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules! - * *** IMPORTANT NOTE *** - * This template uses obdev's shared VID/PID pair for Vendor Class devices - * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand - * the implications! - */ -#define USB_CFG_DEVICE_ID (PRODUCT_ID & 0xFF), ((PRODUCT_ID >> 8) & 0xFF) -/* This is the ID of the product, low byte first. It is interpreted in the - * scope of the vendor ID. If you have registered your own VID with usb.org - * or if you have licensed a PID from somebody else, define it here. Otherwise - * you may use one of obdev's free shared VID/PID pairs. See the file - * USB-IDs-for-free.txt for details! - * *** IMPORTANT NOTE *** - * This template uses obdev's shared VID/PID pair for Vendor Class devices - * with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand - * the implications! - */ -#define USB_CFG_DEVICE_VERSION 0x00, 0x01 -/* Version number of the device: Minor number first, then major number. - */ -#define USB_CFG_VENDOR_NAME 't', '.', 'm', '.', 'k', '.' -#define USB_CFG_VENDOR_NAME_LEN 6 -/* These two values define the vendor name returned by the USB device. The name - * must be given as a list of characters under single quotes. The characters - * are interpreted as Unicode (UTF-16) entities. - * If you don't want a vendor name string, undefine these macros. - * ALWAYS define a vendor name containing your Internet domain name if you use - * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for - * details. - */ -#define USB_CFG_DEVICE_NAME 'P', 'S', '/', '2', ' ', 'k', 'e', 'y', 'b', 'o', 'a', 'r', 'd', ' ', 'c', 'o', 'n', 'v', 'e', 'r', 't', 'e', 'r' -#define USB_CFG_DEVICE_NAME_LEN 23 -/* Same as above for the device name. If you don't want a device name, undefine - * the macros. See the file USB-IDs-for-free.txt before you assign a name if - * you use a shared VID/PID. - */ -/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */ -/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */ -/* Same as above for the serial number. If you don't want a serial number, - * undefine the macros. - * It may be useful to provide the serial number through other means than at - * compile time. See the section about descriptor properties below for how - * to fine tune control over USB descriptors such as the string descriptor - * for the serial number. - */ -#define USB_CFG_DEVICE_CLASS 0 -#define USB_CFG_DEVICE_SUBCLASS 0 -/* See USB specification if you want to conform to an existing device class. - * Class 0xff is "vendor specific". - */ -#define USB_CFG_INTERFACE_CLASS 3 /* HID */ -#define USB_CFG_INTERFACE_SUBCLASS 1 /* Boot */ -#define USB_CFG_INTERFACE_PROTOCOL 1 /* Keyboard */ -/* See USB specification if you want to conform to an existing device class or - * protocol. The following classes must be set at interface level: - * HID class is 3, no subclass and protocol required (but may be useful!) - * CDC class is 2, use subclass 2 and protocol 1 for ACM - */ -#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0 -/* Define this to the length of the HID report descriptor, if you implement - * an HID device. Otherwise don't define it or define it to 0. - * If you use this define, you must add a PROGMEM character array named - * "usbHidReportDescriptor" to your code which contains the report descriptor. - * Don't forget to keep the array and this define in sync! - */ - -/* #define USB_PUBLIC static */ -/* Use the define above if you #include usbdrv.c instead of linking against it. - * This technique saves a couple of bytes in flash memory. - */ - -/* ------------------- Fine Control over USB Descriptors ------------------- */ -/* If you don't want to use the driver's default USB descriptors, you can - * provide our own. These can be provided as (1) fixed length static data in - * flash memory, (2) fixed length static data in RAM or (3) dynamically at - * runtime in the function usbFunctionDescriptor(). See usbdrv.h for more - * information about this function. - * Descriptor handling is configured through the descriptor's properties. If - * no properties are defined or if they are 0, the default descriptor is used. - * Possible properties are: - * + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched - * at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is - * used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if - * you want RAM pointers. - * + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found - * in static memory is in RAM, not in flash memory. - * + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash), - * the driver must know the descriptor's length. The descriptor itself is - * found at the address of a well known identifier (see below). - * List of static descriptor names (must be declared PROGMEM if in flash): - * char usbDescriptorDevice[]; - * char usbDescriptorConfiguration[]; - * char usbDescriptorHidReport[]; - * char usbDescriptorString0[]; - * int usbDescriptorStringVendor[]; - * int usbDescriptorStringDevice[]; - * int usbDescriptorStringSerialNumber[]; - * Other descriptors can't be provided statically, they must be provided - * dynamically at runtime. - * - * Descriptor properties are or-ed or added together, e.g.: - * #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18)) - * - * The following descriptors are defined: - * USB_CFG_DESCR_PROPS_DEVICE - * USB_CFG_DESCR_PROPS_CONFIGURATION - * USB_CFG_DESCR_PROPS_STRINGS - * USB_CFG_DESCR_PROPS_STRING_0 - * USB_CFG_DESCR_PROPS_STRING_VENDOR - * USB_CFG_DESCR_PROPS_STRING_PRODUCT - * USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER - * USB_CFG_DESCR_PROPS_HID - * USB_CFG_DESCR_PROPS_HID_REPORT - * USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver) - * - * Note about string descriptors: String descriptors are not just strings, they - * are Unicode strings prefixed with a 2 byte header. Example: - * int serialNumberDescriptor[] = { - * USB_STRING_DESCRIPTOR_HEADER(6), - * 'S', 'e', 'r', 'i', 'a', 'l' - * }; - */ - -#define USB_CFG_DESCR_PROPS_DEVICE 0 -#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC -//#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 -#define USB_CFG_DESCR_PROPS_STRINGS 0 -#define USB_CFG_DESCR_PROPS_STRING_0 0 -#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 -#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 -#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 -//#define USB_CFG_DESCR_PROPS_HID USB_PROP_IS_DYNAMIC -#define USB_CFG_DESCR_PROPS_HID 0 -#define USB_CFG_DESCR_PROPS_HID_REPORT USB_PROP_IS_DYNAMIC -//#define USB_CFG_DESCR_PROPS_HID_REPORT 0 -#define USB_CFG_DESCR_PROPS_UNKNOWN 0 - -/* ----------------------- Optional MCU Description ------------------------ */ - -/* The following configurations have working defaults in usbdrv.h. You - * usually don't need to set them explicitly. Only if you want to run - * the driver on a device which is not yet supported or with a compiler - * which is not fully supported (such as IAR C) or if you use a differnt - * interrupt than INT0, you may have to define some of these. - */ -/* #define USB_INTR_CFG MCUCR */ -/* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */ -/* #define USB_INTR_CFG_CLR 0 */ -/* #define USB_INTR_ENABLE GIMSK */ -/* #define USB_INTR_ENABLE_BIT INT0 */ -/* #define USB_INTR_PENDING GIFR */ -/* #define USB_INTR_PENDING_BIT INTF0 */ -/* #define USB_INTR_VECTOR INT0_vect */ - -#endif /* __usbconfig_h_included__ */ From a4bf46f9b1d0a0be0cecb2cd0f0d941aa7c71bd3 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 6 Jul 2016 22:48:19 -0400 Subject: [PATCH 7/7] default keymap, reset sorted out for now, added serial to makefile --- keyboards/atreus/Makefile | 1 + keyboards/lets_split/Makefile | 3 +- keyboards/lets_split/config.h | 6 +- keyboards/lets_split/keymaps/default/keymap.c | 200 ++++++++++++++++-- keyboards/lets_split/lets_split.c | 26 +-- keyboards/lets_split/lets_split.h | 8 +- quantum/quantum.c | 2 +- tmk_core/common/avr/bootloader.c | 54 +++-- 8 files changed, 241 insertions(+), 59 deletions(-) diff --git a/keyboards/atreus/Makefile b/keyboards/atreus/Makefile index 72b694faac..95ee1d4d7b 100644 --- a/keyboards/atreus/Makefile +++ b/keyboards/atreus/Makefile @@ -5,6 +5,7 @@ ifdef TEENSY2 ATRUES_UPLOAD_COMMAND = teensy_loader_cli -w -mmcu=$(MCU) $(TARGET).hex else OPT_DEFS += -DATREUS_ASTAR + OPT_DEFS += -DCATERINA_BOOTLOADER ATRUES_UPLOAD_COMMAND = while [ ! -r $(USB) ]; do sleep 1; done; \ avrdude -p $(MCU) -c avr109 -U flash:w:$(TARGET).hex -P $(USB) endif diff --git a/keyboards/lets_split/Makefile b/keyboards/lets_split/Makefile index d8e283896e..b9f07636be 100644 --- a/keyboards/lets_split/Makefile +++ b/keyboards/lets_split/Makefile @@ -1,6 +1,7 @@ SRC += matrix.c \ i2c.c \ - split_util.c + split_util.c \ + serial.c # MCU name #MCU = at90usb1287 diff --git a/keyboards/lets_split/config.h b/keyboards/lets_split/config.h index 5937ca44e2..6f90997ab4 100644 --- a/keyboards/lets_split/config.h +++ b/keyboards/lets_split/config.h @@ -37,7 +37,9 @@ along with this program. If not, see . #define MATRIX_ROW_PINS { B5, B4, E6, D7 } #define MATRIX_COL_PINS { F4, F5, F6, F7, B1, B3 } -#define USE_I2C +#define CATERINA_BOOTLOADER + +// #define USE_I2C // #define EE_HANDS @@ -51,7 +53,7 @@ along with this program. If not, see . //#define MATRIX_HAS_GHOST /* number of backlight levels */ -#define BACKLIGHT_LEVELS 3 +// #define BACKLIGHT_LEVELS 3 /* Set 0 if debouncing isn't needed */ #define DEBOUNCING_DELAY 5 diff --git a/keyboards/lets_split/keymaps/default/keymap.c b/keyboards/lets_split/keymaps/default/keymap.c index 01e3593c22..0d2d94b672 100644 --- a/keyboards/lets_split/keymaps/default/keymap.c +++ b/keyboards/lets_split/keymaps/default/keymap.c @@ -1,11 +1,27 @@ #include "lets_split.h" #include "action_layer.h" +#include "eeconfig.h" -#define BASE 0 +extern keymap_config_t keymap_config; -enum preonic_keycodes { - KC_IDK = SAFE_RANGE, - PM_RESET +// Each layer gets a name for readability, which is then used in the keymap matrix below. +// The underscores don't mean anything - you can have a layer called STUFF or any other name. +// Layer names don't all need to be of the same length, obviously, and you can also skip them +// entirely and just use numbers. +#define _QWERTY 0 +#define _COLEMAK 1 +#define _DVORAK 2 +#define _LOWER 3 +#define _RAISE 4 +#define _ADJUST 16 + +enum custom_keycodes { + QWERTY = SAFE_RANGE, + COLEMAK, + DVORAK, + LOWER, + RAISE, + ADJUST, }; // Fillers to make layering more clear @@ -14,29 +30,185 @@ enum preonic_keycodes { const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { -[BASE] = KEYMAP( - KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC, \ - KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, \ - KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT, \ - KC_IDK, KC_LCTL, KC_LALT, KC_LGUI, PM_RESET,KC_SPC, KC_SPC, PM_RESET,KC_LEFT, KC_DOWN, KC_UP, KC_RGHT \ +/* Qwerty + * ,-----------------------------------------------------------------------------------. + * | Tab | Q | W | E | R | T | Y | U | I | O | P | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Esc | A | S | D | F | G | H | J | K | L | ; | " | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | Shift| Z | X | C | V | B | N | M | , | . | / |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * |Adjust| Ctrl | Alt | GUI |Lower |Space |Space |Raise | Left | Down | Up |Right | + * `-----------------------------------------------------------------------------------' + */ +[_QWERTY] = KEYMAP( \ + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC, \ + KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, \ + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT , \ + ADJUST, KC_LCTL, KC_LALT, KC_LGUI, LOWER, KC_SPC, KC_SPC, RAISE, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT \ +), + +/* Colemak + * ,-----------------------------------------------------------------------------------. + * | Tab | Q | W | F | P | G | J | L | U | Y | ; | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Esc | A | R | S | T | D | H | N | E | I | O | " | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | Shift| Z | X | C | V | B | K | M | , | . | / |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * |Adjust| Ctrl | Alt | GUI |Lower |Space |Space |Raise | Left | Down | Up |Right | + * `-----------------------------------------------------------------------------------' + */ +[_COLEMAK] = KEYMAP( \ + KC_TAB, KC_Q, KC_W, KC_F, KC_P, KC_G, KC_J, KC_L, KC_U, KC_Y, KC_SCLN, KC_BSPC, \ + KC_ESC, KC_A, KC_R, KC_S, KC_T, KC_D, KC_H, KC_N, KC_E, KC_I, KC_O, KC_QUOT, \ + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_K, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT , \ + ADJUST, KC_LCTL, KC_LALT, KC_LGUI, LOWER, KC_SPC, KC_SPC, RAISE, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT \ +), + +/* Dvorak + * ,-----------------------------------------------------------------------------------. + * | Tab | " | , | . | P | Y | F | G | C | R | L | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Esc | A | O | E | U | I | D | H | T | N | S | / | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | Shift| ; | Q | J | K | X | B | M | W | V | Z |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * |Adjust| Ctrl | Alt | GUI |Lower |Space |Space |Raise | Left | Down | Up |Right | + * `-----------------------------------------------------------------------------------' + */ +[_DVORAK] = KEYMAP( \ + KC_TAB, KC_QUOT, KC_COMM, KC_DOT, KC_P, KC_Y, KC_F, KC_G, KC_C, KC_R, KC_L, KC_BSPC, \ + KC_ESC, KC_A, KC_O, KC_E, KC_U, KC_I, KC_D, KC_H, KC_T, KC_N, KC_S, KC_SLSH, \ + KC_LSFT, KC_SCLN, KC_Q, KC_J, KC_K, KC_X, KC_B, KC_M, KC_W, KC_V, KC_Z, KC_ENT , \ + ADJUST, KC_LCTL, KC_LALT, KC_LGUI, LOWER, KC_SPC, KC_SPC, RAISE, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT \ +), + +/* Lower + * ,-----------------------------------------------------------------------------------. + * | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Del | F1 | F2 | F3 | F4 | F5 | F6 | _ | + | | \ | | | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | | F7 | F8 | F9 | F10 | F11 | F12 |ISO ~ |ISO | | | |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | | | | | | | | Next | Vol- | Vol+ | Play | + * `-----------------------------------------------------------------------------------' + */ +[_LOWER] = KEYMAP( \ + KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC, \ + KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE, \ + _______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12,S(KC_NUHS),S(KC_NUBS),_______, _______, _______, \ + _______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY \ +), + +/* Raise + * ,-----------------------------------------------------------------------------------. + * | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Del | F1 | F2 | F3 | F4 | F5 | F6 | - | = | [ | ] | \ | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | | F7 | F8 | F9 | F10 | F11 | F12 |ISO # |ISO / | | |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | | | | | | | | Next | Vol- | Vol+ | Play | + * `-----------------------------------------------------------------------------------' + */ +[_RAISE] = KEYMAP( \ + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC, \ + KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS, \ + _______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_NUHS, KC_NUBS, _______, _______, _______, \ + _______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY \ +), + +/* Adjust (Lower + Raise) + * ,-----------------------------------------------------------------------------------. + * | | Reset| | | | | | | | | | Del | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | | | |Aud on|Audoff|AGnorm|AGswap|Qwerty|Colemk|Dvorak| | | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | | | | | | | | | | | | | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | | | | | | | | | | | | + * `-----------------------------------------------------------------------------------' + */ +[_ADJUST] = KEYMAP( \ + _______, RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_DEL, \ + _______, _______, _______, AU_ON, AU_OFF, AG_NORM, AG_SWAP, QWERTY, COLEMAK, DVORAK, _______, _______, \ + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \ + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \ ) + }; +#ifdef AUDIO_ENABLE +float tone_qwerty[][2] = SONG(QWERTY_SOUND); +float tone_dvorak[][2] = SONG(DVORAK_SOUND); +float tone_colemak[][2] = SONG(COLEMAK_SOUND); +#endif + +void persistant_default_layer_set(uint16_t default_layer) { + eeconfig_update_default_layer(default_layer); + default_layer_set(default_layer); +} + bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { - case KC_IDK: + case QWERTY: if (record->event.pressed) { - SEND_STRING("IDK. "); + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_qwerty, false, 0); + #endif + persistant_default_layer_set(1UL<<_QWERTY); } return false; break; - case PM_RESET: + case COLEMAK: if (record->event.pressed) { - promicro_bootloader_jmp(true); + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_colemak, false, 0); + #endif + persistant_default_layer_set(1UL<<_COLEMAK); + } + return false; + break; + case DVORAK: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_dvorak, false, 0); + #endif + persistant_default_layer_set(1UL<<_DVORAK); + } + return false; + break; + case LOWER: + if (record->event.pressed) { + layer_on(_LOWER); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_LOWER); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } + return false; + break; + case RAISE: + if (record->event.pressed) { + layer_on(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } + return false; + break; + case ADJUST: + if (record->event.pressed) { + layer_on(_ADJUST); + } else { + layer_off(_ADJUST); } return false; break; } return true; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/keyboards/lets_split/lets_split.c b/keyboards/lets_split/lets_split.c index 1859dc20a7..574c116a75 100644 --- a/keyboards/lets_split/lets_split.c +++ b/keyboards/lets_split/lets_split.c @@ -23,26 +23,8 @@ void matrix_init_kb(void) { matrix_init_user(); }; -void promicro_bootloader_jmp(bool program) { - - #ifdef AUDIO_ENABLE - PLAY_NOTE_ARRAY(tone_goodbye, false, 0); - _delay_ms(150); - stop_all_notes(); - #endif - - uint16_t *const bootKeyPtr = (uint16_t *)0x0800; - - // Value used by Caterina bootloader use to determine whether to run the - // sketch or the bootloader programmer. - uint16_t bootKey = program ? 0x7777 : 0; - - *bootKeyPtr = bootKey; - - // setup watchdog timeout - wdt_enable(WDTO_60MS); - - while(1) {} // wait for watchdog timer to trigger +void shutdown_user(void) { + PLAY_NOTE_ARRAY(tone_goodbye, false, 0); + _delay_ms(150); + stop_all_notes(); } - - diff --git a/keyboards/lets_split/lets_split.h b/keyboards/lets_split/lets_split.h index e59aed5921..fe7ae07679 100644 --- a/keyboards/lets_split/lets_split.h +++ b/keyboards/lets_split/lets_split.h @@ -1,5 +1,7 @@ +#ifndef LETS_SPLIT_H +#define LETS_SPLIT_H + #include "quantum.h" -#include void promicro_bootloader_jmp(bool program); @@ -18,4 +20,6 @@ void promicro_bootloader_jmp(bool program); { k50, k51, k52, k53, k54, k55 }, \ { k60, k61, k62, k63, k64, k65 }, \ { k70, k71, k72, k73, k74, k75 } \ - } \ No newline at end of file + } + +#endif \ No newline at end of file diff --git a/quantum/quantum.c b/quantum/quantum.c index d59bd5a3f8..d8e43a4655 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -89,7 +89,7 @@ bool process_record_quantum(keyrecord_t *record) { shutdown_user(); #endif wait_ms(250); - #ifdef ATREUS_ASTAR + #ifdef CATERINA_BOOTLOADER *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific #endif bootloader_jump(); diff --git a/tmk_core/common/avr/bootloader.c b/tmk_core/common/avr/bootloader.c index 7c744e8c79..fb9bf2d1c3 100644 --- a/tmk_core/common/avr/bootloader.c +++ b/tmk_core/common/avr/bootloader.c @@ -73,27 +73,47 @@ uint32_t reset_key __attribute__ ((section (".noinit"))); /* initialize MCU status by watchdog reset */ void bootloader_jump(void) { -#ifdef PROTOCOL_LUFA - USB_Disable(); - cli(); - _delay_ms(2000); -#endif + #ifndef CATERINA_BOOTLOADER -#ifdef PROTOCOL_PJRC - cli(); - UDCON = 1; - USBCON = (1<