From 74faaa3e82960cd65719f40dcf860b73120c5002 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 000000000000..247f978f0176 --- /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 000000000000..5b464147d322 --- /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 000000000000..00602394fedc --- /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 000000000000..ee9872303790 --- /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 000000000000..c82b95a37654 --- /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 000000000000..e69de29bb2d1 From acb7d0fe24cac3c5afc1f28af094eba594529d60 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 c82b95a37654..000000000000 --- 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 247f978f0176..d8e283896e83 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 5b464147d322..e68787e0b5d8 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 000000000000..c72789403e55 --- /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 00602394fedc..01e3593c226b 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 ee9872303790..1859dc20a77a 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 000000000000..e59aed59213d --- /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 000000000000..16c2ba0badfb --- /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 000000000000..09e219b7b172 --- /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 000000000000..c394596e0c73 --- /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 000000000000..84e67de113b1 --- /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 000000000000..2043e7b94f90 --- /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 000000000000..d0ca4c717e57 --- /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 71153a5f5837..cee3593eee4e 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 9b7df0480a5f937234f4533c89edd79451aa8a77 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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 Yy9>onw)Hgg6Sq#eBqNc0;l{oH1LK2XbN~PV literal 0 HcmV?d00001 diff --git a/keyboards/lets_split/matrix.c b/keyboards/lets_split/matrix.c index 16c2ba0badfb..1d768c59b32e 100644 --- a/keyboards/lets_split/matrix.c +++ b/keyboards/lets_split/matrix.c @@ -29,6 +29,7 @@ along with this program. If not, see . #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 e69de29bb2d1..73fdb0f789d5 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 000000000000..f439c2f20bf2 --- /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 000000000000..15fe4db7b4c6 --- /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 c394596e0c73..65003a71a46d 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 cf6890d37fdf..6b896679cac4 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 5750fa6ef5ffd430c0f8ed2038e6248384c9e975 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 e68787e0b5d8..5937ca44e2c1 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 7d984f1dcfa5f72241459e7e9befe68d853efef4 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 84e67de113b1..000000000000 --- 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 2043e7b94f90..000000000000 --- 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 41c591ac5960eda502eeb349d8258ed3364e66dc 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 000000000000..a92200b124ae --- /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 000000000000..91a68317045a --- /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 d0ca4c717e57..000000000000 --- 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 befcb9ef4b6da66450a695559df6f1723d6f31d0 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 72b694faac1f..95ee1d4d7b11 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 d8e283896e83..b9f07636be0c 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 5937ca44e2c1..6f90997ab495 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 01e3593c226b..0d2d94b67260 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) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_qwerty, false, 0); + #endif + persistant_default_layer_set(1UL<<_QWERTY); + } + return false; + break; + case COLEMAK: + if (record->event.pressed) { + #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) { - SEND_STRING("IDK. "); + layer_on(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); } return false; break; - case PM_RESET: + case ADJUST: if (record->event.pressed) { - promicro_bootloader_jmp(true); + 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 1859dc20a77a..574c116a7546 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 e59aed59213d..fe7ae076792f 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 d59bd5a3f850..d8e43a4655ed 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 7c744e8c79ec..fb9bf2d1c332 100644 --- a/tmk_core/common/avr/bootloader.c +++ b/tmk_core/common/avr/bootloader.c @@ -73,26 +73,46 @@ 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<