@ -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 */ |
@ -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 | |||
@ -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 | |||