commit
21e443101f
@ -0,0 +1,78 @@ |
||||
SRC += matrix.c \
|
||||
i2c.c \
|
||||
split_util.c \
|
||||
serial.c
|
||||
|
||||
# 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
|
||||
|
||||
CUSTOM_MATRIX = yes
|
||||
|
||||
ifndef QUANTUM_DIR |
||||
include ../../Makefile
|
||||
endif |
@ -0,0 +1,98 @@ |
||||
/*
|
||||
Copyright 2012 Jun Wako <wakojun@gmail.com> |
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#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 */ |
||||
// Rows are doubled-up
|
||||
#define MATRIX_ROWS 8 |
||||
#define MATRIX_COLS 6 |
||||
|
||||
// wiring of each half
|
||||
#define MATRIX_ROW_PINS { B5, B4, E6, D7 } |
||||
#define MATRIX_COL_PINS { F4, F5, F6, F7, B1, B3 } |
||||
|
||||
#define CATERINA_BOOTLOADER |
||||
|
||||
// #define USE_I2C
|
||||
|
||||
// #define EE_HANDS
|
||||
|
||||
#define I2C_MASTER_LEFT |
||||
// #define I2C_MASTER_RIGHT
|
||||
|
||||
/* 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 |
@ -0,0 +1,2 @@ |
||||
:080000000000000000000001F7 |
||||
:00000001FF |
@ -0,0 +1,2 @@ |
||||
:080000000000000000000000F8 |
||||
:00000001FF |
@ -0,0 +1,159 @@ |
||||
#include <util/twi.h> |
||||
#include <avr/io.h> |
||||
#include <stdlib.h> |
||||
#include <avr/interrupt.h> |
||||
#include <util/twi.h> |
||||
#include <stdbool.h> |
||||
#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<<TWINT)) && lim < I2C_LOOP_TIMEOUT) |
||||
lim++; |
||||
|
||||
// easier way, but will wait slightly longer
|
||||
// _delay_us(100);
|
||||
} |
||||
|
||||
// Setup twi to run at 100kHz
|
||||
void i2c_master_init(void) { |
||||
// no prescaler
|
||||
TWSR = 0; |
||||
// Set TWI clock frequency to SCL_CLOCK. Need TWBR>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<<TWINT) | (1<<TWEN) | (1<<TWSTA); |
||||
|
||||
i2c_delay(); |
||||
|
||||
// check that we started successfully
|
||||
if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START)) |
||||
return 1; |
||||
|
||||
TWDR = address; |
||||
TWCR = (1<<TWINT) | (1<<TWEN); |
||||
|
||||
i2c_delay(); |
||||
|
||||
if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) ) |
||||
return 1; // slave did not acknowledge
|
||||
else |
||||
return 0; // success
|
||||
} |
||||
|
||||
|
||||
// Finish the i2c transaction.
|
||||
void i2c_master_stop(void) { |
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); |
||||
|
||||
uint16_t lim = 0; |
||||
while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT) |
||||
lim++; |
||||
} |
||||
|
||||
// Write one byte to the i2c slave.
|
||||
// returns 0 => slave ACK
|
||||
// 1 => slave NACK
|
||||
uint8_t i2c_master_write(uint8_t data) { |
||||
TWDR = data; |
||||
TWCR = (1<<TWINT) | (1<<TWEN); |
||||
|
||||
i2c_delay(); |
||||
|
||||
// check if the slave acknowledged us
|
||||
return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1; |
||||
} |
||||
|
||||
// Read one byte from the i2c slave. If ack=1 the slave is acknowledged,
|
||||
// if ack=0 the acknowledge bit is not set.
|
||||
// returns: byte read from i2c device
|
||||
uint8_t i2c_master_read(int ack) { |
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA); |
||||
|
||||
i2c_delay(); |
||||
return TWDR; |
||||
} |
||||
|
||||
void i2c_reset_state(void) { |
||||
TWCR = 0; |
||||
} |
||||
|
||||
void i2c_slave_init(uint8_t address) { |
||||
TWAR = address << 0; // slave i2c address
|
||||
// TWEN - twi enable
|
||||
// TWEA - enable address acknowledgement
|
||||
// TWINT - twi interrupt flag
|
||||
// TWIE - enable the twi interrupt
|
||||
TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN); |
||||
} |
||||
|
||||
ISR(TWI_vect); |
||||
|
||||
ISR(TWI_vect) { |
||||
uint8_t ack = 1; |
||||
switch(TW_STATUS) { |
||||
case TW_SR_SLA_ACK: |
||||
// this device has been addressed as a slave receiver
|
||||
slave_has_register_set = false; |
||||
break; |
||||
|
||||
case TW_SR_DATA_ACK: |
||||
// this device has received data as a slave receiver
|
||||
// The first byte that we receive in this transaction sets the location
|
||||
// of the read/write location of the slaves memory that it exposes over
|
||||
// i2c. After that, bytes will be written at slave_buffer_pos, incrementing
|
||||
// slave_buffer_pos after each write.
|
||||
if(!slave_has_register_set) { |
||||
slave_buffer_pos = TWDR; |
||||
// don't acknowledge the master if this memory loctaion is out of bounds
|
||||
if ( slave_buffer_pos >= 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<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN); |
||||
} |
@ -0,0 +1,31 @@ |
||||
#ifndef I2C_H |
||||
#define I2C_H |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#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 |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 19 KiB |
@ -0,0 +1,214 @@ |
||||
#include "lets_split.h" |
||||
#include "action_layer.h" |
||||
#include "eeconfig.h" |
||||
|
||||
extern keymap_config_t keymap_config; |
||||
|
||||
// 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
|
||||
#define _______ KC_TRNS |
||||
#define XXXXXXX KC_NO |
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { |
||||
|
||||
/* 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 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) { |
||||
layer_on(_RAISE); |
||||
update_tri_layer(_LOWER, _RAISE, _ADJUST); |
||||
} else { |
||||
layer_off(_RAISE); |
||||
update_tri_layer(_LOWER, _RAISE, _ADJUST); |
||||
} |
||||
return false; |
||||
break; |
||||
case ADJUST: |
||||
if (record->event.pressed) { |
||||
layer_on(_ADJUST); |
||||
} else { |
||||
layer_off(_ADJUST); |
||||
} |
||||
return false; |
||||
break; |
||||
} |
||||
return true; |
||||
} |
@ -0,0 +1,30 @@ |
||||
#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 shutdown_user(void) { |
||||
PLAY_NOTE_ARRAY(tone_goodbye, false, 0); |
||||
_delay_ms(150); |
||||
stop_all_notes(); |
||||
} |
@ -0,0 +1,25 @@ |
||||
#ifndef LETS_SPLIT_H |
||||
#define LETS_SPLIT_H |
||||
|
||||
#include "quantum.h" |
||||
|
||||
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 } \
|
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,311 @@ |
||||
/*
|
||||
Copyright 2012 Jun Wako <wakojun@gmail.com> |
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
/*
|
||||
* scan matrix |
||||
*/ |
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
#include <avr/io.h> |
||||
#include <avr/wdt.h> |
||||
#include <avr/interrupt.h> |
||||
#include <util/delay.h> |
||||
#include "print.h" |
||||
#include "debug.h" |
||||
#include "util.h" |
||||
#include "matrix.h" |
||||
#include "i2c.h" |
||||
#include "serial.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<<col)); |
||||
} |
||||
|
||||
inline |
||||
matrix_row_t matrix_get_row(uint8_t row) |
||||
{ |
||||
return matrix[row]; |
||||
} |
||||
|
||||
void matrix_print(void) |
||||
{ |
||||
print("\nr/c 0123456789ABCDEF\n"); |
||||
for (uint8_t row = 0; row < MATRIX_ROWS; row++) { |
||||
phex(row); print(": "); |
||||
pbin_reverse16(matrix_get_row(row)); |
||||
print("\n"); |
||||
} |
||||
} |
||||
|
||||
uint8_t matrix_key_count(void) |
||||
{ |
||||
uint8_t count = 0; |
||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { |
||||
count += bitpop16(matrix[i]); |
||||
} |
||||
return count; |
||||
} |
||||
|
||||
static void init_cols(void) |
||||
{ |
||||
for(int x = 0; x < MATRIX_COLS; x++) { |
||||
_SFR_IO8((col_pins[x] >> 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); |
||||
} |
@ -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 <avr/pgmspace.h> |
||||
|
||||
// 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 */ |
@ -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: |
||||
|
||||
 |
||||
|
||||
The wiring for i2c: |
||||
|
||||
 |
||||
|
||||
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. |
||||
|
||||
|
@ -0,0 +1,225 @@ |
||||
/*
|
||||
* WARNING: be careful changing this code, it is very timing dependent |
||||
*/ |
||||
|
||||
#ifndef F_CPU |
||||
#define F_CPU 16000000 |
||||
#endif |
||||
|
||||
#include <avr/io.h> |
||||
#include <avr/interrupt.h> |
||||
#include <util/delay.h> |
||||
#include <stdbool.h> |
||||
|
||||
#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; |
||||
} |
@ -0,0 +1,26 @@ |
||||
#ifndef MY_SERIAL_H |
||||
#define MY_SERIAL_H |
||||
|
||||
#include "config.h" |
||||
#include <stdbool.h> |
||||
|
||||
/* 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 |
@ -0,0 +1,76 @@ |
||||
#include <avr/io.h> |
||||
#include <avr/wdt.h> |
||||
#include <avr/power.h> |
||||
#include <avr/interrupt.h> |
||||
#include <util/delay.h> |
||||
#include <avr/eeprom.h> |
||||
#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) { |
||||
#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<<VBUS)); //checks state of VBUS
|
||||
} |
||||
|
||||
void split_keyboard_setup(void) { |
||||
setup_handedness(); |
||||
|
||||
if (has_usb()) { |
||||
keyboard_master_setup(); |
||||
} else { |
||||
keyboard_slave_setup(); |
||||
} |
||||
sei(); |
||||
} |
||||
|
||||
void keyboard_slave_loop(void) { |
||||
matrix_init(); |
||||
|
||||
while (1) { |
||||
matrix_slave_scan(); |
||||
} |
||||
} |
||||
|
||||
// this code runs before the usb and keyboard is initialized
|
||||
void matrix_setup(void) { |
||||
split_keyboard_setup(); |
||||
|
||||
if (!has_usb()) { |
||||
keyboard_slave_loop(); |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
#ifndef SPLIT_KEYBOARD_UTIL_H |
||||
#define SPLIT_KEYBOARD_UTIL_H |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#ifdef EE_HANDS |
||||
#define EECONFIG_BOOTMAGIC_END (uint8_t *)10 |
||||
#define EECONFIG_HANDEDNESS EECONFIG_BOOTMAGIC_END |
||||
#endif |
||||
|
||||
#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 |
Loading…
Reference in new issue