added ergodox
parent
46e7fb2d3c
commit
35a81f5b8b
|
@ -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
|
||||||
|
|
|
@ -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[]
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 */
|
|
@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
#include "config_definitions.h"
|
#include "config_common.h"
|
||||||
|
|
||||||
/* USB Device descriptor parameter */
|
/* USB Device descriptor parameter */
|
||||||
#define VENDOR_ID 0xFEED
|
#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)) \
|
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
|
* Feature disable options
|
||||||
* These options are also useful to firmware size reduction.
|
* These options are also useful to firmware size reduction.
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#include "planck.h"
|
#include "planck.h"
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
void * matrix_init_user(void) {
|
void * matrix_init_user(void) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
void * matrix_scan_user(void) {
|
void * matrix_scan_user(void) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,9 +42,12 @@ QUANTUM_DIR = $(TOP_DIR)/quantum
|
||||||
|
|
||||||
# # project specific files
|
# # project specific files
|
||||||
SRC += $(QUANTUM_DIR)/keymap_common.c \
|
SRC += $(QUANTUM_DIR)/keymap_common.c \
|
||||||
$(QUANTUM_DIR)/matrix.c \
|
|
||||||
$(QUANTUM_DIR)/led.c
|
$(QUANTUM_DIR)/led.c
|
||||||
|
|
||||||
|
ifndef CUSTOM_MATRIX
|
||||||
|
SRC += $(QUANTUM_DIR)/matrix.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef MIDI_ENABLE
|
ifdef MIDI_ENABLE
|
||||||
SRC += $(QUANTUM_DIR)/keymap_midi.c \
|
SRC += $(QUANTUM_DIR)/keymap_midi.c \
|
||||||
$(QUANTUM_DIR)/beeps.c
|
$(QUANTUM_DIR)/beeps.c
|
||||||
|
@ -58,8 +61,6 @@ endif
|
||||||
#EXTRALDFLAGS = -Wl,--relax
|
#EXTRALDFLAGS = -Wl,--relax
|
||||||
|
|
||||||
# Search Path
|
# Search Path
|
||||||
VPATH += $(TARGET_DIR)
|
|
||||||
VPATH += $(TOP_DIR)
|
|
||||||
VPATH += $(QUANTUM_DIR)
|
VPATH += $(QUANTUM_DIR)
|
||||||
|
|
||||||
include $(TOP_DIR)/protocol/lufa.mk
|
include $(TOP_DIR)/protocol/lufa.mk
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -37,15 +37,18 @@ action_t action_for_key(uint8_t layer, keypos_t key)
|
||||||
// Has a modifier
|
// Has a modifier
|
||||||
action_t action;
|
action_t action;
|
||||||
// Split it up
|
// 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;
|
return action;
|
||||||
} else if (keycode >= 0x2000 && keycode < 0x3000) {
|
} 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);
|
return keymap_func_to_action(keycode & 0xFFF);
|
||||||
} else if (keycode >= 0x3000 && keycode < 0x4000) {
|
} else if (keycode >= 0x3000 && keycode < 0x4000) {
|
||||||
|
// When the code starts with 3, it's an action macro.
|
||||||
action_t action;
|
action_t action;
|
||||||
action.code = ACTION_MACRO(keycode & 0xFF);
|
action.code = ACTION_MACRO(keycode & 0xFF);
|
||||||
return action;
|
return action;
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
} else if (keycode >= BL_0 & keycode <= BL_15) {
|
} else if (keycode >= BL_0 & keycode <= BL_15) {
|
||||||
action_t action;
|
action_t action;
|
||||||
action.code = ACTION_BACKLIGHT_LEVEL(keycode & 0x000F);
|
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_t action;
|
||||||
action.code = ACTION_BACKLIGHT_STEP();
|
action.code = ACTION_BACKLIGHT_STEP();
|
||||||
return action;
|
return action;
|
||||||
} else if (keycode == RESET) {
|
#endif
|
||||||
|
} else if (keycode == RESET) { // RESET is 0x5000, which is why this is here
|
||||||
bootloader_jump();
|
bootloader_jump();
|
||||||
return;
|
return;
|
||||||
} else if (keycode == DEBUG) {
|
} else if (keycode == DEBUG) { // DEBUG is 0x5001
|
||||||
|
// TODO: Does this actually work?
|
||||||
print("\nDEBUG: enabled.\n");
|
print("\nDEBUG: enabled.\n");
|
||||||
debug_enable = true;
|
debug_enable = true;
|
||||||
return;
|
return;
|
||||||
|
@ -79,15 +84,21 @@ action_t action_for_key(uint8_t layer, keypos_t key)
|
||||||
action_t action;
|
action_t action;
|
||||||
action.code = ACTION_LAYER_SET(layer, when);
|
action.code = ACTION_LAYER_SET(layer, when);
|
||||||
return action;
|
return action;
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
} else if (keycode >= 0x6000 && keycode < 0x7000) {
|
} else if (keycode >= 0x6000 && keycode < 0x7000) {
|
||||||
action_t action;
|
action_t action;
|
||||||
action.code = ACTION_FUNCTION_OPT(keycode & 0xFF, (keycode & 0x0F00) >> 8);
|
action.code = ACTION_FUNCTION_OPT(keycode & 0xFF, (keycode & 0x0F00) >> 8);
|
||||||
return action;
|
return action;
|
||||||
|
#endif
|
||||||
|
#ifdef UNICODE_ENABLE
|
||||||
} else if (keycode >= 0x8000) {
|
} else if (keycode >= 0x8000) {
|
||||||
action_t action;
|
action_t action;
|
||||||
uint16_t unicode = keycode & ~(0x8000);
|
uint16_t unicode = keycode & ~(0x8000);
|
||||||
action.code = ACTION_FUNCTION_OPT(unicode & 0xFF, (unicode & 0xFF00) >> 8);
|
action.code = ACTION_FUNCTION_OPT(unicode & 0xFF, (unicode & 0xFF00) >> 8);
|
||||||
return action;
|
return action;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (keycode) {
|
switch (keycode) {
|
||||||
|
|
|
@ -47,6 +47,16 @@ static void init_cols(void);
|
||||||
static void unselect_rows(void);
|
static void unselect_rows(void);
|
||||||
static void select_row(uint8_t row);
|
static void select_row(uint8_t row);
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
|
void * matrix_init_kb(void) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__ ((weak))
|
||||||
|
void * matrix_scan_kb(void) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
inline
|
inline
|
||||||
uint8_t matrix_rows(void)
|
uint8_t matrix_rows(void)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue