diff options
author | Jack Humbert <jack.humb@gmail.com> | 2015-10-26 16:32:37 -0400 |
---|---|---|
committer | Jack Humbert <jack.humb@gmail.com> | 2015-10-26 16:32:37 -0400 |
commit | 35a81f5b8b081e1607a7c04489b01f551c3213cc (patch) | |
tree | 4671909bd5ac7c3ca7afaf60fb6a70106f5090dc | |
parent | 46e7fb2d3ccd699c0a1b1fd9d02860b1f2a44141 (diff) |
added ergodox
-rw-r--r-- | keyboard/ergodox/Makefile | 139 | ||||
-rw-r--r-- | keyboard/ergodox/README.md | 56 | ||||
-rw-r--r-- | keyboard/ergodox/backlight.c | 61 | ||||
-rw-r--r-- | keyboard/ergodox/config.h | 88 | ||||
-rw-r--r-- | keyboard/ergodox/ergodox.c | 121 | ||||
-rw-r--r-- | keyboard/ergodox/ergodox.h | 145 | ||||
-rw-r--r-- | keyboard/ergodox/i2cmaster.h | 178 | ||||
-rw-r--r-- | keyboard/ergodox/keymaps/keymap_default.c | 76 | ||||
-rw-r--r-- | keyboard/ergodox/matrix.c | 405 | ||||
-rw-r--r-- | keyboard/ergodox/twimaster.c | 208 | ||||
-rw-r--r-- | keyboard/planck/config.h | 69 | ||||
-rw-r--r-- | keyboard/planck/config_definitions.h | 51 | ||||
-rw-r--r-- | keyboard/planck/planck.c | 6 | ||||
-rw-r--r-- | quantum.mk | 7 | ||||
-rw-r--r-- | quantum/config_common.h | 116 | ||||
-rw-r--r-- | quantum/keymap_common.c | 19 | ||||
-rw-r--r-- | quantum/matrix.c | 10 |
17 files changed, 1627 insertions, 128 deletions
diff --git a/keyboard/ergodox/Makefile b/keyboard/ergodox/Makefile new file mode 100644 index 0000000000..f71d096783 --- /dev/null +++ b/keyboard/ergodox/Makefile @@ -0,0 +1,139 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device. +# Please customize your programmer settings(PROGRAM_CMD) +# +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +# make dfu = Download the hex file to the device, using dfu-programmer (must +# have dfu-programmer installed). +# +# make flip = Download the hex file to the device, using Atmel FLIP (must +# have Atmel FLIP installed). +# +# make dfu-ee = Download the eeprom file to the device, using dfu-programmer +# (must have dfu-programmer installed). +# +# make flip-ee = Download the eeprom file to the device, using Atmel FLIP +# (must have Atmel FLIP installed). +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = ergodox + + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# # project specific files +SRC = ergodox.c \ + twimaster.c \ + backlight.c + +ifdef KEYMAP + SRC := keymaps/keymap_$(KEYMAP).c $(SRC) +else + SRC := keymaps/keymap_default.c $(SRC) +endif + +CONFIG_H = config.h + +# 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 +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +# SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +# NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA +# BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality +# MIDI_ENABLE = YES # MIDI controls +# UNICODE_ENABLE = YES # Unicode +# BLUETOOTH_ENABLE = yes # Enable Bluetooth with the Adafruit EZ-Key HID + + +# Optimize size but this may cause error "relocation truncated to fit" +#EXTRALDFLAGS = -Wl,--relax + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/quantum.mk + diff --git a/keyboard/ergodox/README.md b/keyboard/ergodox/README.md new file mode 100644 index 0000000000..bbbc73515b --- /dev/null +++ b/keyboard/ergodox/README.md @@ -0,0 +1,56 @@ +# TMK Generic + +* I'm not sure what the Magic + H does. + Is this a menu that will pop up regardless of what platform and program is open? + + Yes, this is sort of debugging. + Use PJRC's [hid_listen](https://www.pjrc.com/teensy/hid_listen.html) to see debug messages. + +# TMK/Ergodox specific + +* I would like to configure my leds to indicate the active layer. + I read that can be done, but I haven't seen an example for this firmware. + Can someone please post an example or a link? + + TMK for Ergodox have support for seven (!) led's: + - three on right + - three on left (see http://geekhack.org/index.php?topic=22780.msg873819#msg873819 for more details) + - Teensy onboard led as well + + Any of these leds can be used as layer indicator or NumLock/CapsLock/ScrollLock led. + + [Here is example](https://github.com/cub-uanic/tmk_keyboard/blob/cub_layout/keyboard/ergodox/matrix.c#L121-167) + how you can assign some meaning to each led. + In this code only left leds are used to show layers, but you can + [change `led_set()`](https://github.com/cub-uanic/tmk_keyboard/blob/cub_layout/keyboard/ergodox/led.c) + and do anything you want with all leds. + +# Firmware + +Q: Where to get binaries? +A: + +Q: Where to get sources? +A: + +Q: How to compile? +A: + + +# Layouts + +description of layouts in base firmware binaries + + +# Things TO-DO + +- [ ] Flash NumLock led only when "numpad" layer is active +- [ ] Command (in terms of IS_COMMAND) to switch to no-leds mode +- [ ] Increase count of ACTION keys +- [ ] Fix command_state() onboard led: it should flash only when kbd in some specific mode (CONSOLE || MOUSE) +- [ ] ergodox_blink_all_leds() should save current state of leds, and restore after blink. initial state of all leds == off +- [ ] add support for pseudo-backlight (reversed LEDs) + docs/photo +- [ ] command to debug all LEDs (on/off/blink) +- [ ] proper (in-core) implementation of DEBUG_MATRIX_SCAN_RATE (non-Ergodox specific) +- [ ] proper (in-core) support for per-layer fn_actions[] + diff --git a/keyboard/ergodox/backlight.c b/keyboard/ergodox/backlight.c new file mode 100644 index 0000000000..f69364b2af --- /dev/null +++ b/keyboard/ergodox/backlight.c @@ -0,0 +1,61 @@ + +#include <avr/io.h> +#include "backlight.h" + +#define CHANNEL OCR1C + +void backlight_init_ports() +{ + + // Setup PB7 as output and output low. + DDRB |= (1<<7); + PORTB &= ~(1<<7); + + // Use full 16-bit resolution. + ICR1 = 0xFFFF; + + // I could write a wall of text here to explain... but TL;DW + // Go read the ATmega32u4 datasheet. + // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on + + // Pin PB7 = OCR1C (Timer 1, Channel C) + // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 + // (i.e. start high, go low when counter matches.) + // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 + // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 + + TCCR1A = _BV(COM1C1) | _BV(WGM11); // = 0b00001010; + TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; + + backlight_init(); +} + +void backlight_set(uint8_t level) +{ + if ( level == 0 ) + { + // Turn off PWM control on PB7, revert to output low. + TCCR1A &= ~(_BV(COM1C1)); + CHANNEL = 0x0; + // Prevent backlight blink on lowest level + PORTB &= ~(_BV(PORTB7)); + } + else if ( level == BACKLIGHT_LEVELS ) + { + // Prevent backlight blink on lowest level + PORTB &= ~(_BV(PORTB7)); + // Turn on PWM control of PB7 + TCCR1A |= _BV(COM1C1); + // Set the brightness + CHANNEL = 0xFFFF; + } + else + { + // Prevent backlight blink on lowest level + PORTB &= ~(_BV(PORTB7)); + // Turn on PWM control of PB7 + TCCR1A |= _BV(COM1C1); + // Set the brightness + CHANNEL = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2)); + } +}
\ No newline at end of file diff --git a/keyboard/ergodox/config.h b/keyboard/ergodox/config.h new file mode 100644 index 0000000000..c8eaae6146 --- /dev/null +++ b/keyboard/ergodox/config.h @@ -0,0 +1,88 @@ +/* +Copyright 2012 Jun Wako <wakojun@gmail.com> +Copyright 2013 Oleg Kostyuk <cub.uanic@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 0x1307 +#define DEVICE_VER 0x0001 +#define MANUFACTURER ErgoDox EZ +#define PRODUCT ErgoDox EZ +#define DESCRIPTION t.m.k. keyboard firmware for Ergodox + +/* key matrix size */ +#define MATRIX_ROWS 14 +#define MATRIX_COLS 6 + +#define MOUSEKEY_DELAY 100 +#define MOUSEKEY_INTERVAL 20 +#define MOUSEKEY_MAX_SPEED 3 +#define MOUSEKEY_TIME_TO_MAX 10 + +#define COLS (int []){ F1, F0, B0, C7, F4, F5, F6, F7, D4, D6, B4, D7 } +#define ROWS (int []){ D0, D5, B5, B6 } + +/* 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 DEBOUNCE 2 +#define TAPPING_TERM 230 +#define TAPPING_TOGGLE 2 + +/* 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_LCTL) | MOD_BIT(KC_RCTL)) || \ + keyboard_report->mods == (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)) \ +) + +/* + * 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 +//#define DEBUG_MATRIX_SCAN_RATE + +#endif diff --git a/keyboard/ergodox/ergodox.c b/keyboard/ergodox/ergodox.c new file mode 100644 index 0000000000..38e9b3a8af --- /dev/null +++ b/keyboard/ergodox/ergodox.c @@ -0,0 +1,121 @@ +#include "ergodox.h" +#include "i2cmaster.h" + +bool i2c_initialized = 0; +uint8_t mcp23018_status = 0x20; + +bool ergodox_left_led_1 = 0; // left top +bool ergodox_left_led_2 = 0; // left middle +bool ergodox_left_led_3 = 0; // left bottom + +void * matrix_init_user(void) { + +}; + +void * matrix_scan_user(void) { + +}; + +void * matrix_init_kb(void) { + // keyboard LEDs (see "PWM on ports OC1(A|B|C)" in "teensy-2-0.md") + TCCR1A = 0b10101001; // set and configure fast PWM + TCCR1B = 0b00001001; // set and configure fast PWM + + // (tied to Vcc for hardware convenience) + DDRB &= ~(1<<4); // set B(4) as input + PORTB &= ~(1<<4); // set B(4) internal pull-up disabled + + // unused pins - C7, D4, D5, D7, E6 + // set as input with internal pull-ip enabled + DDRC &= ~(1<<7); + DDRD &= ~(1<<7 | 1<<5 | 1<<4); + DDRE &= ~(1<<6); + PORTC |= (1<<7); + PORTD |= (1<<7 | 1<<5 | 1<<4); + PORTE |= (1<<6); + + ergodox_blink_all_leds(); + + if (matrix_init_user) { + (*matrix_init_user)(); + } +}; + +void * matrix_scan_kb(void) { + + if (matrix_scan_user) { + (*matrix_scan_user)(); + } +}; + + +void ergodox_blink_all_leds(void) +{ + ergodox_led_all_off(); + ergodox_led_all_set(LED_BRIGHTNESS_HI); + ergodox_led_all_on(); + _delay_ms(333); + ergodox_led_all_off(); +} + +uint8_t init_mcp23018(void) { + mcp23018_status = 0x20; + + // I2C subsystem + if (i2c_initialized == 0) { + i2c_init(); // on pins D(1,0) + i2c_initialized++; + _delay_ms(1000); + } + + // set pin direction + // - unused : input : 1 + // - input : input : 1 + // - driving : output : 0 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(IODIRA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b00000000); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b00111111); if (mcp23018_status) goto out; + i2c_stop(); + + // set pull-up + // - unused : on : 1 + // - input : on : 1 + // - driving : off : 0 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPPUA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b00000000); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b00111111); if (mcp23018_status) goto out; + +out: + i2c_stop(); + + if (!mcp23018_status) mcp23018_status = ergodox_left_leds_update(); + + return mcp23018_status; +} + +uint8_t ergodox_left_leds_update(void) { + if (mcp23018_status) { // if there was an error + return mcp23018_status; + } + + // set logical value (doesn't matter on inputs) + // - unused : hi-Z : 1 + // - input : hi-Z : 1 + // - driving : hi-Z : 1 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(OLATA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b11111111 + & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT) + ); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b11111111 + & ~(ergodox_left_led_2<<LEFT_LED_2_SHIFT) + & ~(ergodox_left_led_1<<LEFT_LED_1_SHIFT) + ); if (mcp23018_status) goto out; + +out: + i2c_stop(); + return mcp23018_status; +} + diff --git a/keyboard/ergodox/ergodox.h b/keyboard/ergodox/ergodox.h new file mode 100644 index 0000000000..9d0691dfe2 --- /dev/null +++ b/keyboard/ergodox/ergodox.h @@ -0,0 +1,145 @@ +#ifndef PLANCK_H +#define PLANCK_H + +#include "matrix.h" +#include "keymap_common.h" +#include "backlight.h" +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <avr/io.h> +#include "i2cmaster.h" +#include <util/delay.h> + +#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) +#define CPU_16MHz 0x00 + +// I2C aliases and register addresses (see "mcp23018.md") +#define I2C_ADDR 0b0100000 +#define I2C_ADDR_WRITE ( (I2C_ADDR<<1) | I2C_WRITE ) +#define I2C_ADDR_READ ( (I2C_ADDR<<1) | I2C_READ ) +#define IODIRA 0x00 // i/o direction register +#define IODIRB 0x01 +#define GPPUA 0x0C // GPIO pull-up resistor register +#define GPPUB 0x0D +#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT) +#define GPIOB 0x13 +#define OLATA 0x14 // output latch register +#define OLATB 0x15 + +extern uint8_t mcp23018_status; + +void init_ergodox(void); +void ergodox_blink_all_leds(void); +uint8_t init_mcp23018(void); +uint8_t ergodox_left_leds_update(void); + +#define LED_BRIGHTNESS_LO 31 +#define LED_BRIGHTNESS_HI 255 + +#define LEFT_LED_1_SHIFT 7 // in MCP23018 port B +#define LEFT_LED_2_SHIFT 6 // in MCP23018 port B +#define LEFT_LED_3_SHIFT 7 // in MCP23018 port A + +extern bool ergodox_left_led_1; // left top +extern bool ergodox_left_led_2; // left middle +extern bool ergodox_left_led_3; // left bottom + +inline void ergodox_board_led_on(void) { DDRD |= (1<<6); PORTD |= (1<<6); } +inline void ergodox_right_led_1_on(void) { DDRB |= (1<<5); PORTB |= (1<<5); } +inline void ergodox_right_led_2_on(void) { DDRB |= (1<<6); PORTB |= (1<<6); } +inline void ergodox_right_led_3_on(void) { DDRB |= (1<<7); PORTB |= (1<<7); } +inline void ergodox_left_led_1_on(void) { ergodox_left_led_1 = 1; } +inline void ergodox_left_led_2_on(void) { ergodox_left_led_2 = 1; } +inline void ergodox_left_led_3_on(void) { ergodox_left_led_3 = 1; } + +inline void ergodox_board_led_off(void) { DDRD &= ~(1<<6); PORTD &= ~(1<<6); } +inline void ergodox_right_led_1_off(void) { DDRB &= ~(1<<5); PORTB &= ~(1<<5); } +inline void ergodox_right_led_2_off(void) { DDRB &= ~(1<<6); PORTB &= ~(1<<6); } +inline void ergodox_right_led_3_off(void) { DDRB &= ~(1<<7); PORTB &= ~(1<<7); } +inline void ergodox_left_led_1_off(void) { ergodox_left_led_1 = 0; } +inline void ergodox_left_led_2_off(void) { ergodox_left_led_2 = 0; } +inline void ergodox_left_led_3_off(void) { ergodox_left_led_3 = 0; } + +inline void ergodox_led_all_on(void) +{ + ergodox_board_led_on(); + ergodox_right_led_1_on(); + ergodox_right_led_2_on(); + ergodox_right_led_3_on(); + ergodox_left_led_1_on(); + ergodox_left_led_2_on(); + ergodox_left_led_3_on(); + ergodox_left_leds_update(); +} + +inline void ergodox_led_all_off(void) +{ + ergodox_board_led_off(); + ergodox_right_led_1_off(); + ergodox_right_led_2_off(); + ergodox_right_led_3_off(); + ergodox_left_led_1_off(); + ergodox_left_led_2_off(); + ergodox_left_led_3_off(); + ergodox_left_leds_update(); +} + +inline void ergodox_right_led_1_set(uint8_t n) { OCR1A = n; } +inline void ergodox_right_led_2_set(uint8_t n) { OCR1B = n; } +inline void ergodox_right_led_3_set(uint8_t n) { OCR1C = n; } + +inline void ergodox_led_all_set(uint8_t n) +{ + ergodox_right_led_1_set(n); + ergodox_right_led_2_set(n); + ergodox_right_led_3_set(n); +} + +#define KEYMAP( \ + \ + /* left hand, spatial positions */ \ + k00,k01,k02,k03,k04,k05,k06, \ + k10,k11,k12,k13,k14,k15,k16, \ + k20,k21,k22,k23,k24,k25, \ + k30,k31,k32,k33,k34,k35,k36, \ + k40,k41,k42,k43,k44, \ + k55,k56, \ + k54, \ + k53,k52,k51, \ + \ + /* right hand, spatial positions */ \ + k07,k08,k09,k0A,k0B,k0C,k0D, \ + k17,k18,k19,k1A,k1B,k1C,k1D, \ + k28,k29,k2A,k2B,k2C,k2D, \ + k37,k38,k39,k3A,k3B,k3C,k3D, \ + k49,k4A,k4B,k4C,k4D, \ + k57,k58, \ + k59, \ + k5C,k5B,k5A ) \ + \ + /* matrix positions */ \ + { \ + { k00, k10, k20, k30, k40, KC_NO }, \ + { k01, k11, k21, k31, k41, k51 }, \ + { k02, k12, k22, k32, k42, k52 }, \ + { k03, k13, k23, k33, k43, k53 }, \ + { k04, k14, k24, k34, k44, k54 }, \ + { k05, k15, k25, k35, KC_NO, k55 }, \ + { k06, k16, KC_NO, k36, KC_NO, k56 }, \ + \ + { k07, k17, KC_NO, k37,KC_NO, k57 }, \ + { k08, k18, k28, k38,KC_NO, k58 }, \ + { k09, k19, k29, k39, k49, k59 }, \ + { k0A, k1A, k2A, k3A, k4A, k5A }, \ + { k0B, k1B, k2B, k3B, k4B, k5B }, \ + { k0C, k1C, k2C, k3C, k4C, k5C }, \ + { k0D, k1D, k2D, k3D, k4D, KC_NO } \ + } + +void * matrix_init_user(void); +void * matrix_scan_user(void); + + + +#endif
\ No newline at end of file diff --git a/keyboard/ergodox/i2cmaster.h b/keyboard/ergodox/i2cmaster.h new file mode 100644 index 0000000000..3917b9e6c0 --- /dev/null +++ b/keyboard/ergodox/i2cmaster.h @@ -0,0 +1,178 @@ +#ifndef _I2CMASTER_H +#define _I2CMASTER_H 1 +/************************************************************************* +* Title: C include file for the I2C master interface +* (i2cmaster.S or twimaster.c) +* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury +* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $ +* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 +* Target: any AVR device +* Usage: see Doxygen manual +**************************************************************************/ + +#ifdef DOXYGEN +/** + @defgroup pfleury_ic2master I2C Master library + @code #include <i2cmaster.h> @endcode + + @brief I2C (TWI) Master Software Library + + Basic routines for communicating with I2C slave devices. This single master + implementation is limited to one bus master on the I2C bus. + + This I2c library is implemented as a compact assembler software implementation of the I2C protocol + which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c). + Since the API for these two implementations is exactly the same, an application can be linked either against the + software I2C implementation or the hardware I2C implementation. + + Use 4.7k pull-up resistor on the SDA and SCL pin. + + Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module + i2cmaster.S to your target when using the software I2C implementation ! + + Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion. + + @note + The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted + to GNU assembler and AVR-GCC C call interface. + Replaced the incorrect quarter period delays found in AVR300 with + half period delays. + + @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + + @par API Usage Example + The following code shows typical usage of this library, see example test_i2cmaster.c + + @code + + #include <i2cmaster.h> + + + #define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet + + int main(void) + { + unsigned char ret; + + i2c_init(); // initialize I2C library + + // write 0x75 to EEPROM address 5 (Byte Write) + i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode + i2c_write(0x05); // write address = 5 + i2c_write(0x75); // write value 0x75 to EEPROM + i2c_stop(); // set stop conditon = release bus + + + // read previously written value back from EEPROM address 5 + i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode + + i2c_write(0x05); // write address = 5 + i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode + + ret = i2c_readNak(); // read one byte from EEPROM + i2c_stop(); + + for(;;); + } + @endcode + +*/ +#endif /* DOXYGEN */ + +/**@{*/ + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" +#endif + +#include <avr/io.h> + +/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */ +#define I2C_READ 1 + +/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */ +#define I2C_WRITE 0 + + +/** + @brief initialize the I2C master interace. Need to be called only once + @param void + @return none + */ +extern void i2c_init(void); + + +/** + @brief Terminates the data transfer and releases the I2C bus + @param void + @return none + */ +extern void i2c_stop(void); + + +/** + @brief Issues a start condition and sends address and transfer direction + + @param addr address and transfer direction of I2C device + @retval 0 device accessible + @retval 1 failed to access device + */ +extern unsigned char i2c_start(unsigned char addr); + + +/** + @brief Issues a repeated start condition and sends address and transfer direction + + @param addr address and transfer direction of I2C device + @retval 0 device accessible + @retval 1 failed to access device + */ +extern unsigned char i2c_rep_start(unsigned char addr); + + +/** + @brief Issues a start condition and sends address and transfer direction + + If device is busy, use ack polling to wait until device ready + @param addr address and transfer direction of I2C device + @return none + */ +extern void i2c_start_wait(unsigned char addr); + + +/** + @brief Send one byte to I2C device + @param data byte to be transfered + @retval 0 write successful + @retval 1 write failed + */ +extern unsigned char i2c_write(unsigned char data); + + +/** + @brief read one byte from the I2C device, request more data from device + @return byte read from I2C device + */ +extern unsigned char i2c_readAck(void); + +/** + @brief read one byte from the I2C device, read is followed by a stop condition + @return byte read from I2C device + */ +extern unsigned char i2c_readNak(void); + +/** + @brief read one byte from the I2C device + + Implemented as a macro, which calls either i2c_readAck or i2c_readNak + + @param ack 1 send ack, request more data from device<br> + 0 send nak, read is followed by a stop condition + @return byte read from I2C device + */ +extern unsigned char i2c_read(unsigned char ack); +#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak(); + + +/**@}*/ +#endif diff --git a/keyboard/ergodox/keymaps/keymap_default.c b/keyboard/ergodox/keymaps/keymap_default.c new file mode 100644 index 0000000000..7b54b481ae --- /dev/null +++ b/keyboard/ergodox/keymaps/keymap_default.c @@ -0,0 +1,76 @@ +#include "ergodox.h" +#include "debug.h" + +#define DEFAULT_LAYER 0 +#define COLEMAK_LAYER 1 +#define DVORAK_LAYER 2 +#define LOWER_LAYER 1 +#define RAISE_LAYER 4 + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +[DEFAULT_LAYER] = KEYMAP( // layer 0 : default + // left hand + KC_EQL, KC_1, KC_2, KC_3, KC_4, KC_5, KC_ESC, + KC_BSLS,KC_Q, KC_W, KC_E, KC_R, KC_T, KC_FN2, + KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, + KC_LSFT,KC_Z, KC_X, KC_C, KC_V, KC_B, KC_FN1, + KC_LGUI,KC_GRV, KC_BSLS,KC_LEFT,KC_RGHT, + KC_LCTL,KC_LALT, + KC_HOME, + KC_BSPC,KC_DEL, KC_END, + // right hand + KC_FN3, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, + KC_LBRC,KC_Y, KC_U, KC_I, KC_O, KC_P, KC_RBRC, + KC_H, KC_J, KC_K, KC_L, KC_SCLN,KC_QUOT, + KC_FN1, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH,KC_RSFT, + KC_LEFT,KC_DOWN,KC_UP, KC_RGHT,KC_RGUI, + KC_RALT,KC_RCTL, + KC_PGUP, + KC_PGDN,KC_ENT, KC_SPC + ), +[LOWER_LAYER] = KEYMAP( // layer 0 : default + // left hand + KC_EQL, KC_1, KC_2, KC_3, LALT(KC_TAB), KC_5, KC_ESC, + KC_BSLS,KC_Q, S(KC_W), KC_E, KC_R, KC_T, KC_FN2, + KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, + KC_LSFT,KC_Z, KC_X, KC_C, KC_V, KC_B, KC_FN1, + KC_LGUI,KC_GRV, KC_BSLS,KC_LEFT,KC_RGHT, + KC_LCTL,KC_LALT, + KC_HOME, + KC_BSPC,KC_DEL, KC_END, + // right hand + KC_FN3, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, + KC_LBRC,KC_Y, KC_U, KC_I, KC_O, KC_P, KC_RBRC, + KC_H, KC_J, KC_K, KC_L, KC_SCLN,KC_QUOT, + KC_FN1, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH,KC_RSFT, + KC_LEFT,KC_DOWN,KC_UP, KC_RGHT,KC_RGUI, + KC_RALT,KC_RCTL, + KC_PGUP, + KC_PGDN,KC_ENT, KC_SPC + ) +}; + +const uint16_t PROGMEM fn_actions[] = { + + [1] = ACTION_LAYER_MOMENTARY(LOWER_LAYER), // to RAISE + [2] = ACTION_LAYER_MOMENTARY(LOWER_LAYER), // to LOWER + + [3] = ACTION_DEFAULT_LAYER_SET(DEFAULT_LAYER), + [4] = ACTION_DEFAULT_LAYER_SET(COLEMAK_LAYER), + [5] = ACTION_DEFAULT_LAYER_SET(DVORAK_LAYER), +}; + +const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) +{ + // MACRODOWN only works in this function + switch(id) { + case 0: + if (record->event.pressed) { + register_code(KC_RSFT); + } else { + unregister_code(KC_RSFT); + } + break; + } + return MACRO_NONE; +}; diff --git a/keyboard/ergodox/matrix.c b/keyboard/ergodox/matrix.c new file mode 100644 index 0000000000..cc10e29410 --- /dev/null +++ b/keyboard/ergodox/matrix.c @@ -0,0 +1,405 @@ +/* +Copyright 2013 Oleg Kostyuk <cub.uanic@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 <util/delay.h> +#include "action_layer.h" +#include "print.h" +#include "debug.h" +#include "util.h" +#include "matrix.h" +#include "ergodox.h" +#include "i2cmaster.h" +#ifdef DEBUG_MATRIX_SCAN_RATE +#include "timer.h" +#endif + +#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(uint8_t row); +static void init_cols(void); +static void unselect_rows(); +static void select_row(uint8_t row); + +static uint8_t mcp23018_reset_loop; + +#ifdef DEBUG_MATRIX_SCAN_RATE +uint32_t matrix_timer; +uint32_t matrix_scan_count; +#endif + + +__attribute__ ((weak)) +void * matrix_init_kb(void) { +}; + +__attribute__ ((weak)) +void * matrix_scan_kb(void) { +}; + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + // initialize row and col + + mcp23018_status = init_mcp23018(); + + + 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; + } + +#ifdef DEBUG_MATRIX_SCAN_RATE + matrix_timer = timer_read32(); + matrix_scan_count = 0; +#endif + + if (matrix_init_kb) { + (*matrix_init_kb)(); + } + +} + +uint8_t matrix_scan(void) +{ + if (mcp23018_status) { // if there was an error + if (++mcp23018_reset_loop == 0) { + // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans + // this will be approx bit more frequent than once per second + print("trying to reset mcp23018\n"); + mcp23018_status = init_mcp23018(); + if (mcp23018_status) { + print("left side not responding\n"); + } else { + print("left side attached\n"); + ergodox_blink_all_leds(); + } + } + } + +#ifdef DEBUG_MATRIX_SCAN_RATE + matrix_scan_count++; + + uint32_t timer_now = timer_read32(); + if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) { + print("matrix scan frequency: "); + pdec(matrix_scan_count); + print("\n"); + + matrix_timer = timer_now; + matrix_scan_count = 0; + } +#endif + +#ifdef KEYMAP_CUB + uint8_t layer = biton32(layer_state); + + ergodox_board_led_off(); + ergodox_left_led_1_off(); + ergodox_left_led_2_off(); + ergodox_left_led_3_off(); + switch (layer) { + case 1: + // all + ergodox_left_led_1_on(); + ergodox_left_led_2_on(); + ergodox_left_led_3_on(); + break; + case 2: + // blue + ergodox_left_led_2_on(); + break; + case 8: + // blue and green + ergodox_left_led_2_on(); + // break missed intentionally + case 3: + // green + ergodox_left_led_3_on(); + break; + case 6: + ergodox_board_led_on(); + // break missed intentionally + case 4: + case 5: + case 7: + // white + ergodox_left_led_1_on(); + break; + case 9: + // white+green + ergodox_left_led_1_on(); + ergodox_left_led_3_on(); + break; + default: + // none + break; + } + + mcp23018_status = ergodox_left_leds_update(); +#endif + +#ifdef KEYMAP_SIMON + uint8_t layer = biton32(layer_state); + + ergodox_board_led_off(); + switch (layer) { + case 0: +// none + + break; + default: + ergodox_board_led_on(); + break; + } +#endif + + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + select_row(i); + matrix_row_t cols = read_cols(i); + 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]; + } + } + } + + + if (matrix_scan_kb) { + (*matrix_scan_kb)(); + } + + 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<<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; +} + +/* Column pin configuration + * + * Teensy + * col: 0 1 2 3 4 5 + * pin: F0 F1 F4 F5 F6 F7 + * + * MCP23018 + * col: 0 1 2 3 4 5 + * pin: B5 B4 B3 B2 B1 B0 + */ +static void init_cols(void) +{ + // init on mcp23018 + // not needed, already done as part of init_mcp23018() + + // init on teensy + // Input with pull-up(DDR:0, PORT:1) + DDRF &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); + PORTF |= (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); +} + +static matrix_row_t read_cols(uint8_t row) +{ + if (row < 7) { + if (mcp23018_status) { // if there was an error + return 0; + } else { + uint8_t data = 0; + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPIOB); if (mcp23018_status) goto out; + mcp23018_status = i2c_start(I2C_ADDR_READ); if (mcp23018_status) goto out; + data = i2c_readNak(); + data = ~data; + out: + i2c_stop(); + return data; + } + } else { + _delay_us(30); // without this wait read unstable value. + // read from teensy + return + (PINF&(1<<0) ? 0 : (1<<0)) | + (PINF&(1<<1) ? 0 : (1<<1)) | + (PINF&(1<<4) ? 0 : (1<<2)) | + (PINF&(1<<5) ? 0 : (1<<3)) | + (PINF&(1<<6) ? 0 : (1<<4)) | + (PINF&(1<<7) ? 0 : (1<<5)) ; + } +} + +/* Row pin configuration + * + * Teensy + * row: 7 8 9 10 11 12 13 + * pin: B0 B1 B2 B3 D2 D3 C6 + * + * MCP23018 + * row: 0 1 2 3 4 5 6 + * pin: A0 A1 A2 A3 A4 A5 A6 + */ +static void unselect_rows(void) +{ + // unselect on mcp23018 + if (mcp23018_status) { // if there was an error + // do nothing + } else { + // set all rows hi-Z : 1 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPIOA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write( 0xFF + & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT) + ); if (mcp23018_status) goto out; + out: + i2c_stop(); + } + + // unselect on teensy + // Hi-Z(DDR:0, PORT:0) to unselect + DDRB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); + PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); + DDRD &= ~(1<<2 | 1<<3); + PORTD &= ~(1<<2 | 1<<3); + DDRC &= ~(1<<6); + PORTC &= ~(1<<6); +} + +static void select_row(uint8_t row) +{ + if (row < 7) { + // select on mcp23018 + if (mcp23018_status) { // if there was an error + // do nothing + } else { + // set active row low : 0 + // set other rows hi-Z : 1 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPIOA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write( 0xFF & ~(1<<row) + & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT) + ); if (mcp23018_status) goto out; + out: + i2c_stop(); + } + } else { + // select on teensy + // Output low(DDR:1, PORT:0) to select + switch (row) { + case 7: + DDRB |= (1<<0); + PORTB &= ~(1<<0); + break; + case 8: + DDRB |= (1<<1); + PORTB &= ~(1<<1); + break; + case 9: + DDRB |= (1<<2); + PORTB &= ~(1<<2); + break; + case 10: + DDRB |= (1<<3); + PORTB &= ~(1<<3); + break; + case 11: + DDRD |= (1<<2); + PORTD &= ~(1<<3); + break; + case 12: + DDRD |= (1<<3); + PORTD &= ~(1<<3); + break; + case 13: + DDRC |= (1<<6); + PORTC &= ~(1<<6); + break; + } + } +} + diff --git a/keyboard/ergodox/twimaster.c b/keyboard/ergodox/twimaster.c new file mode 100644 index 0000000000..f91c08e6e4 --- /dev/null +++ b/keyboard/ergodox/twimaster.c @@ -0,0 +1,208 @@ +/************************************************************************* +* Title: I2C master library using hardware TWI interface +* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury +* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $ +* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 +* Target: any AVR device with hardware TWI +* Usage: API compatible with I2C Software Library i2cmaster.h +**************************************************************************/ +#include <inttypes.h> +#include <compat/twi.h> + +#include <i2cmaster.h> + + +/* define CPU frequency in Mhz here if not defined in Makefile */ +#ifndef F_CPU +#define F_CPU 16000000UL +#endif + +/* I2C clock in Hz */ +#define SCL_CLOCK 400000L + + +/************************************************************************* + Initialization of the I2C bus interface. Need to be called only once +*************************************************************************/ +void i2c_init(void) +{ + /* initialize TWI clock + * minimal values in Bit Rate Register (TWBR) and minimal Prescaler + * bits in the TWI Status Register should give us maximal possible + * I2C bus speed - about 444 kHz + * + * for more details, see 20.5.2 in ATmega16/32 secification + */ + + TWSR = 0; /* no prescaler */ + TWBR = 10; /* must be >= 10 for stable operation */ + +}/* i2c_init */ + + +/************************************************************************* + Issues a start condition and sends address and transfer direction. + return 0 = device accessible, 1= failed to access device +*************************************************************************/ +unsigned char i2c_start(unsigned char address) +{ + uint8_t twst; + + // send START condition + TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); + + // wait until transmission completed + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits. + twst = TW_STATUS & 0xF8; + if ( (twst != TW_START) && (twst != TW_REP_START)) return 1; + + // send device address + TWDR = address; + TWCR = (1<<TWINT) | (1<<TWEN); + + // wail until transmission completed and ACK/NACK has been received + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits. + twst = TW_STATUS & 0xF8; + if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1; + + return 0; + +}/* i2c_start */ + + +/************************************************************************* + Issues a start condition and sends address and transfer direction. + If device is busy, use ack polling to wait until device is ready + + Input: address and transfer direction of I2C device +*************************************************************************/ +void i2c_start_wait(unsigned char address) +{ + uint8_t twst; + + + while ( 1 ) + { + // send START condition + TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); + + // wait until transmission completed + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits. + twst = TW_STATUS & 0xF8; + if ( (twst != TW_START) && (twst != TW_REP_START)) continue; + + // send device address + TWDR = address; + TWCR = (1<<TWINT) | (1<<TWEN); + + // wail until transmission completed + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits. + twst = TW_STATUS & 0xF8; + if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) + { + /* device busy, send stop condition to terminate write operation */ + TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); + + // wait until stop condition is executed and bus released + while(TWCR & (1<<TWSTO)); + + continue; + } + //if( twst != TW_MT_SLA_ACK) return 1; + break; + } + +}/* i2c_start_wait */ + + +/************************************************************************* + Issues a repeated start condition and sends address and transfer direction + + Input: address and transfer direction of I2C device + + Return: 0 device accessible + 1 failed to access device +*************************************************************************/ +unsigned char i2c_rep_start(unsigned char address) +{ + return i2c_start( address ); + +}/* i2c_rep_start */ + + +/************************************************************************* + Terminates the data transfer and releases the I2C bus +*************************************************************************/ +void i2c_stop(void) +{ + /* send stop condition */ + TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); + + // wait until stop condition is executed and bus released + while(TWCR & (1<<TWSTO)); + +}/* i2c_stop */ + + +/************************************************************************* + Send one byte to I2C device + + Input: byte to be transfered + Return: 0 write successful + 1 write failed +*************************************************************************/ +unsigned char i2c_write( unsigned char data ) +{ + uint8_t twst; + + // send data to the previously addressed device + TWDR = data; + TWCR = (1<<TWINT) | (1<<TWEN); + + // wait until transmission completed + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits + twst = TW_STATUS & 0xF8; + if( twst != TW_MT_DATA_ACK) return 1; + return 0; + +}/* i2c_write */ + + +/************************************************************************* + Read one byte from the I2C device, request more data from device + + Return: byte read from I2C device +*************************************************************************/ +unsigned char i2c_readAck(void) +{ + TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); + while(!(TWCR & (1<<TWINT))); + + return TWDR; + +}/* i2c_readAck */ + + +/************************************************************************* + Read one byte from the I2C device, read is followed by a stop condition + + Return: byte read from I2C device +*************************************************************************/ +unsigned char i2c_readNak(void) +{ + TWCR = (1<<TWINT) | (1<<TWEN); + while(!(TWCR & (1<<TWINT))); + + return TWDR; + +}/* i2c_readNak */ diff --git a/keyboard/planck/config.h b/keyboard/planck/config.h index cc3a1741a2..a4c711db82 100644 --- a/keyboard/planck/config.h +++ b/keyboard/planck/config.h @@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #ifndef CONFIG_H #define CONFIG_H -#include "config_definitions.h" +#include "config_common.h" /* USB Device descriptor parameter */ #define VENDOR_ID 0xFEED @@ -58,73 +58,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ ) -#ifdef BLUETOOTH_ENABLE -#ifdef __AVR_ATmega32U4__ - #define SERIAL_UART_BAUD 9600 - #define SERIAL_UART_DATA UDR1 - #define SERIAL_UART_UBRR ((F_CPU/(16UL*SERIAL_UART_BAUD))-1) - #define SERIAL_UART_RXD_VECT USART1_RX_vect - #define SERIAL_UART_TXD_READY (UCSR1A&(1<<UDRE1)) - #define SERIAL_UART_INIT() do { \ - UBRR1L = (uint8_t) SERIAL_UART_UBRR; /* baud rate */ \ - UBRR1H = (uint8_t) (SERIAL_UART_UBRR>>8); /* baud rate */ \ - UCSR1B = (1<<TXEN1); /* TX: enable */ \ - UCSR1C = (0<<UPM11) | (0<<UPM10) | /* parity: none(00), even(01), odd(11) */ \ - (0<<UCSZ12) | (1<<UCSZ11) | (1<<UCSZ10); /* data-8bit(011) */ \ - sei(); \ - } while(0) -#else -# error "USART configuration is needed." -#endif - - -// I'm fairly sure these aren't needed, but oh well - Jack - -/* - * PS/2 Interrupt configuration - */ -#ifdef PS2_USE_INT -/* uses INT1 for clock line(ATMega32U4) */ -#define PS2_CLOCK_PORT PORTD -#define PS2_CLOCK_PIN PIND -#define PS2_CLOCK_DDR DDRD -#define PS2_CLOCK_BIT 1 - -#define PS2_DATA_PORT PORTD -#define PS2_DATA_PIN PIND -#define PS2_DATA_DDR DDRD -#define PS2_DATA_BIT 0 - -#define PS2_INT_INIT() do { \ - EICRA |= ((1<<ISC11) | \ - (0<<ISC10)); \ -} while (0) -#define PS2_INT_ON() do { \ - EIMSK |= (1<<INT1); \ -} while (0) -#define PS2_INT_OFF() do { \ - EIMSK &= ~(1<<INT1); \ -} while (0) -#define PS2_INT_VECT INT1_vect -#endif - -/* - * PS/2 Busywait configuration - */ -#ifdef PS2_USE_BUSYWAIT -#define PS2_CLOCK_PORT PORTD -#define PS2_CLOCK_PIN PIND -#define PS2_CLOCK_DDR DDRD -#define PS2_CLOCK_BIT 1 - -#define PS2_DATA_PORT PORTD -#define PS2_DATA_PIN PIND -#define PS2_DATA_DDR DDRD -#define PS2_DATA_BIT 0 -#endif - -#endif - /* * Feature disable options * These options are also useful to firmware size reduction. diff --git a/keyboard/planck/config_definitions.h b/keyboard/planck/config_definitions.h deleted file mode 100644 index 2ac3112651..0000000000 --- a/keyboard/planck/config_definitions.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef CONFIG_DEFINITIONS_H -#define CONFIG_DEFINITIONS_H - -#define B0 0x20 -#define B1 0x21 -#define B2 0x22 -#define B3 0x23 -#define B4 0x24 -#define B5 0x25 -#define B6 0x26 -#define B7 0x27 -#define C0 0x30 -#define C1 0x31 -#define C2 0x32 -#define C3 0x33 -#define C4 0x34 -#define C5 0x35 -#define C6 0x36 -#define C7 0x37 -#define D0 0x40 -#define D1 0x41 -#define D2 0x42 -#define D3 0x43 -#define D4 0x44 -#define D5 0x45 -#define D6 0x46 -#define D7 0x47 -#define E0 0x50 -#define E1 0x51 -#define E2 0x52 -#define E3 0x53 -#define E4 0x54 -#define E5 0x55 -#define E6 0x56 -#define E7 0x57 -#define F0 0x60 -#define F1 0x61 -#define F2 0x62 -#define F3 0x63 -#define F4 0x64 -#define F5 0x65 -#define F6 0x66 -#define F7 0x67 - -#define COL2ROW 0x0 -#define ROW2COL 0x1 - - - -#endif - diff --git a/keyboard/planck/planck.c b/keyboard/planck/planck.c index 9809a824cb..b62862af04 100644 --- a/keyboard/planck/planck.c +++ b/keyboard/planck/planck.c @@ -1,14 +1,16 @@ #include "planck.h" +__attribute__ ((weak)) void * matrix_init_user(void) { }; +__attribute__ ((weak)) void * matrix_scan_user(void) { }; -void *matrix_init_kb(void) { +void * matrix_init_kb(void) { #ifdef BACKLIGHT_ENABLE backlight_init_ports(); #endif @@ -22,7 +24,7 @@ void *matrix_init_kb(void) { } }; -void *matrix_scan_kb(void) { +void * matrix_scan_kb(void) { if (matrix_scan_user) { (*matrix_scan_user)(); } diff --git a/quantum.mk b/quantum.mk index 1637284047..c68bce8ff0 100644 --- a/quantum.mk +++ b/quantum.mk @@ -42,9 +42,12 @@ QUANTUM_DIR = $(TOP_DIR)/quantum # # project specific files SRC += $(QUANTUM_DIR)/keymap_common.c \ - $(QUANTUM_DIR)/matrix.c \ $(QUANTUM_DIR)/led.c +ifndef CUSTOM_MATRIX + SRC += $(QUANTUM_DIR)/matrix.c +endif + ifdef MIDI_ENABLE SRC += $(QUANTUM_DIR)/keymap_midi.c \ $(QUANTUM_DIR)/beeps.c @@ -58,8 +61,6 @@ endif #EXTRALDFLAGS = -Wl,--relax # Search Path -VPATH += $(TARGET_DIR) -VPATH += $(TOP_DIR) VPATH += $(QUANTUM_DIR) include $(TOP_DIR)/protocol/lufa.mk diff --git a/quantum/config_common.h b/quantum/config_common.h new file mode 100644 index 0000000000..da53fce89b --- /dev/null +++ b/quantum/config_common.h @@ -0,0 +1,116 @@ +#ifndef CONFIG_DEFINITIONS_H +#define CONFIG_DEFINITIONS_H + +#define B0 0x20 +#define B1 0x21 +#define B2 0x22 +#define B3 0x23 +#define B4 0x24 +#define B5 0x25 +#define B6 0x26 +#define B7 0x27 +#define C0 0x30 +#define C1 0x31 +#define C2 0x32 +#define C3 0x33 +#define C4 0x34 +#define C5 0x35 +#define C6 0x36 +#define C7 0x37 +#define D0 0x40 +#define D1 0x41 +#define D2 0x42 +#define D3 0x43 +#define D4 0x44 +#define D5 0x45 +#define D6 0x46 +#define D7 0x47 +#define E0 0x50 +#define E1 0x51 +#define E2 0x52 +#define E3 0x53 +#define E4 0x54 +#define E5 0x55 +#define E6 0x56 +#define E7 0x57 +#define F0 0x60 +#define F1 0x61 +#define F2 0x62 +#define F3 0x63 +#define F4 0x64 +#define F5 0x65 +#define F6 0x66 +#define F7 0x67 + +#define COL2ROW 0x0 +#define ROW2COL 0x1 + +#ifdef BLUETOOTH_ENABLE +#ifdef __AVR_ATmega32U4__ + #define SERIAL_UART_BAUD 9600 + #define SERIAL_UART_DATA UDR1 + #define SERIAL_UART_UBRR ((F_CPU/(16UL*SERIAL_UART_BAUD))-1) + #define SERIAL_UART_RXD_VECT USART1_RX_vect + #define SERIAL_UART_TXD_READY (UCSR1A&(1<<UDRE1)) + #define SERIAL_UART_INIT() do { \ + UBRR1L = (uint8_t) SERIAL_UART_UBRR; /* baud rate */ \ + UBRR1H = (uint8_t) (SERIAL_UART_UBRR>>8); /* baud rate */ \ + UCSR1B = (1<<TXEN1); /* TX: enable */ \ + UCSR1C = (0<<UPM11) | (0<<UPM10) | /* parity: none(00), even(01), odd(11) */ \ + (0<<UCSZ12) | (1<<UCSZ11) | (1<<UCSZ10); /* data-8bit(011) */ \ + sei(); \ + } while(0) +#else +# error "USART configuration is needed." +#endif + + +// I'm fairly sure these aren't needed, but oh well - Jack + +/* + * PS/2 Interrupt configuration + */ +#ifdef PS2_USE_INT +/* uses INT1 for clock line(ATMega32U4) */ +#define PS2_CLOCK_PORT PORTD +#define PS2_CLOCK_PIN PIND +#define PS2_CLOCK_DDR DDRD +#define PS2_CLOCK_BIT 1 + +#define PS2_DATA_PORT PORTD +#define PS2_DATA_PIN PIND +#define PS2_DATA_DDR DDRD +#define PS2_DATA_BIT 0 + +#define PS2_INT_INIT() do { \ + EICRA |= ((1<<ISC11) | \ + (0<<ISC10)); \ +} while (0) +#define PS2_INT_ON() do { \ + EIMSK |= (1<<INT1); \ +} while (0) +#define PS2_INT_OFF() do { \ + EIMSK &= ~(1<<INT1); \ +} while (0) +#define PS2_INT_VECT INT1_vect +#endif + +/* + * PS/2 Busywait configuration + */ +#ifdef PS2_USE_BUSYWAIT +#define PS2_CLOCK_PORT PORTD +#define PS2_CLOCK_PIN PIND +#define PS2_CLOCK_DDR DDRD +#define PS2_CLOCK_BIT 1 + +#define PS2_DATA_PORT PORTD +#define PS2_DATA_PIN PIND +#define PS2_DATA_DDR DDRD +#define PS2_DATA_BIT 0 +#endif + +#endif + +#endif + diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c index 66cf2883c7..c9e1494fd9 100644 --- a/quantum/keymap_common.c +++ b/quantum/keymap_common.c @@ -37,15 +37,18 @@ action_t action_for_key(uint8_t layer, keypos_t key) // Has a modifier action_t action; // Split it up - action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); + action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key return action; } else if (keycode >= 0x2000 && keycode < 0x3000) { - // Is a shortcut for function layer, pull last 12bits + // Is a shortcut for function layer, pull last 12bits + // This means we have 4,096 FN macros at our disposal return keymap_func_to_action(keycode & 0xFFF); } else if (keycode >= 0x3000 && keycode < 0x4000) { + // When the code starts with 3, it's an action macro. action_t action; action.code = ACTION_MACRO(keycode & 0xFF); return action; +#ifdef BACKLIGHT_ENABLE } else if (keycode >= BL_0 & keycode <= BL_15) { action_t action; action.code = ACTION_BACKLIGHT_LEVEL(keycode & 0x000F); @@ -66,10 +69,12 @@ action_t action_for_key(uint8_t layer, keypos_t key) action_t action; action.code = ACTION_BACKLIGHT_STEP(); return action; - } else if (keycode == RESET) { +#endif + } else if (keycode == RESET) { // RESET is 0x5000, which is why this is here bootloader_jump(); return; - } else if (keycode == DEBUG) { + } else if (keycode == DEBUG) { // DEBUG is 0x5001 + // TODO: Does this actually work? print("\nDEBUG: enabled.\n"); debug_enable = true; return; @@ -79,15 +84,21 @@ action_t action_for_key(uint8_t layer, keypos_t key) action_t action; action.code = ACTION_LAYER_SET(layer, when); return action; +#ifdef MIDI_ENABLE } else if (keycode >= 0x6000 && keycode < 0x7000) { action_t action; action.code = ACTION_FUNCTION_OPT(keycode & 0xFF, (keycode & 0x0F00) >> 8); return action; +#endif +#ifdef UNICODE_ENABLE } else if (keycode >= 0x8000) { action_t action; uint16_t unicode = keycode & ~(0x8000); action.code = ACTION_FUNCTION_OPT(unicode & 0xFF, (unicode & 0xFF00) >> 8); return action; +#endif + } else { + } switch (keycode) { diff --git a/quantum/matrix.c b/quantum/matrix.c index 97642a4a4e..95bf4c0973 100644 --- a/quantum/matrix.c +++ b/quantum/matrix.c @@ -47,6 +47,16 @@ static void init_cols(void); static void unselect_rows(void); static void select_row(uint8_t row); +__attribute__ ((weak)) +void * matrix_init_kb(void) { + +}; + +__attribute__ ((weak)) +void * matrix_scan_kb(void) { + +}; + inline uint8_t matrix_rows(void) { |