diff options
author | Erez Zukerman <ezuk@madmimi.com> | 2015-10-27 00:54:46 +0200 |
---|---|---|
committer | Erez Zukerman <ezuk@madmimi.com> | 2015-10-27 00:54:46 +0200 |
commit | 0c47e8b008ccb6bfbb7051a5c2e4b0031dae0fa5 (patch) | |
tree | 0f883338e928824d1940fe98f23a69d0e4194e20 /keyboard/ergodox_ez | |
parent | cc1c32671eb1eb43a87e55ac4ffa60b15115e48d (diff) |
[Jack & Erez] Comments + tiny updates and cleanup
Diffstat (limited to 'keyboard/ergodox_ez')
-rw-r--r-- | keyboard/ergodox_ez/Makefile | 114 | ||||
-rw-r--r-- | keyboard/ergodox_ez/README.md | 1 | ||||
-rw-r--r-- | keyboard/ergodox_ez/config.h | 87 | ||||
-rw-r--r-- | keyboard/ergodox_ez/ergodox_ez.c | 123 | ||||
-rw-r--r-- | keyboard/ergodox_ez/ergodox_ez.h | 145 | ||||
-rw-r--r-- | keyboard/ergodox_ez/i2cmaster.h | 178 | ||||
-rw-r--r-- | keyboard/ergodox_ez/keymaps/keymap_default.c | 133 | ||||
-rw-r--r-- | keyboard/ergodox_ez/keymaps/keymap_ergodox_ez.c | 211 | ||||
-rw-r--r-- | keyboard/ergodox_ez/matrix.c | 348 | ||||
-rw-r--r-- | keyboard/ergodox_ez/twimaster.c | 208 |
10 files changed, 1548 insertions, 0 deletions
diff --git a/keyboard/ergodox_ez/Makefile b/keyboard/ergodox_ez/Makefile new file mode 100644 index 0000000000..e0d303c9df --- /dev/null +++ b/keyboard/ergodox_ez/Makefile @@ -0,0 +1,114 @@ +#---------------------------------------------------------------------------- +# On command line: +# +# make = Make software. +# +# make clean = Clean out built project files. +# +# That's pretty much all you need. To compile, always go make clean, +# followed by make. +# +# For advanced users only: +# make teensy = Download the hex file to the device, using teensy_loader_cli. +# (must have teensy_loader_cli installed). +# +#---------------------------------------------------------------------------- + +# Target file name (without extension). +TARGET = ergodox_ez + + +# Directory common source filess exist +TOP_DIR = ../.. + +# Directory keyboard dependent files exist +TARGET_DIR = . + +# # project specific files +SRC = ergodox_ez.c \ + twimaster.c + +ifdef KEYMAP + SRC := keymaps/keymap_$(KEYMAP).c $(SRC) +else + SRC := keymaps/keymap_default.c $(SRC) +endif + +CONFIG_H = config.h + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=4096 + + +# Build Options +# comment out to disable the options. +# +BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = yes # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +# SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend +# NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA +# BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality +# MIDI_ENABLE = YES # MIDI controls +# UNICODE_ENABLE = YES # Unicode +# BLUETOOTH_ENABLE = yes # Enable Bluetooth with the Adafruit EZ-Key HID + + +# Optimize size but this may cause error "relocation truncated to fit" +#EXTRALDFLAGS = -Wl,--relax + +# Search Path +VPATH += $(TARGET_DIR) +VPATH += $(TOP_DIR) + +include $(TOP_DIR)/quantum.mk + diff --git a/keyboard/ergodox_ez/README.md b/keyboard/ergodox_ez/README.md new file mode 100644 index 0000000000..f750d8dbec --- /dev/null +++ b/keyboard/ergodox_ez/README.md @@ -0,0 +1 @@ +// TODO: Make up a proper readme for the ErgoDox EZ. diff --git a/keyboard/ergodox_ez/config.h b/keyboard/ergodox_ez/config.h new file mode 100644 index 0000000000..850d245791 --- /dev/null +++ b/keyboard/ergodox_ez/config.h @@ -0,0 +1,87 @@ +/* +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 100 + +/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ +#define LOCKING_SUPPORT_ENABLE +/* Locking resynchronize hack */ +#define LOCKING_RESYNC_ENABLE + +/* key combination for command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LCTL) | MOD_BIT(KC_RCTL)) || \ + keyboard_report->mods == (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)) \ +) + +/* + * Feature disable options + * These options are also useful to firmware size reduction. + */ + +/* disable debug print */ +// #define NO_DEBUG + +/* disable print */ +// #define NO_PRINT + +/* disable action features */ +//#define NO_ACTION_LAYER +//#define NO_ACTION_TAPPING +//#define NO_ACTION_ONESHOT +//#define NO_ACTION_MACRO +//#define NO_ACTION_FUNCTION +//#define DEBUG_MATRIX_SCAN_RATE + +#endif diff --git a/keyboard/ergodox_ez/ergodox_ez.c b/keyboard/ergodox_ez/ergodox_ez.c new file mode 100644 index 0000000000..f7e156b319 --- /dev/null +++ b/keyboard/ergodox_ez/ergodox_ez.c @@ -0,0 +1,123 @@ +#include "ergodox_ez.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 + +__attribute__ ((weak)) +void * matrix_init_user(void) { + +}; + +__attribute__ ((weak)) +void * matrix_scan_user(void) { + +}; + +void * matrix_init_kb(void) { + // keyboard LEDs (see "PWM on ports OC1(A|B|C)" in "teensy-2-0.md") + TCCR1A = 0b10101001; // set and configure fast PWM + TCCR1B = 0b00001001; // set and configure fast PWM + + // (tied to Vcc for hardware convenience) + DDRB &= ~(1<<4); // set B(4) as input + PORTB &= ~(1<<4); // set B(4) internal pull-up disabled + + // unused pins - C7, D4, D5, D7, E6 + // set as input with internal pull-ip enabled + DDRC &= ~(1<<7); + DDRD &= ~(1<<7 | 1<<5 | 1<<4); + DDRE &= ~(1<<6); + PORTC |= (1<<7); + PORTD |= (1<<7 | 1<<5 | 1<<4); + PORTE |= (1<<6); + + ergodox_blink_all_leds(); + + if (matrix_init_user) { + (*matrix_init_user)(); + } +}; + +void * matrix_scan_kb(void) { + + if (matrix_scan_user) { + (*matrix_scan_user)(); + } +}; + + +void ergodox_blink_all_leds(void) +{ + ergodox_led_all_off(); + ergodox_led_all_set(LED_BRIGHTNESS_HI); + ergodox_led_all_on(); + _delay_ms(333); + ergodox_led_all_off(); +} + +uint8_t init_mcp23018(void) { + mcp23018_status = 0x20; + + // I2C subsystem + if (i2c_initialized == 0) { + i2c_init(); // on pins D(1,0) + i2c_initialized++; + _delay_ms(1000); + } + + // set pin direction + // - unused : input : 1 + // - input : input : 1 + // - driving : output : 0 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(IODIRA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b00000000); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b00111111); if (mcp23018_status) goto out; + i2c_stop(); + + // set pull-up + // - unused : on : 1 + // - input : on : 1 + // - driving : off : 0 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPPUA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b00000000); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b00111111); if (mcp23018_status) goto out; + +out: + i2c_stop(); + + if (!mcp23018_status) mcp23018_status = ergodox_left_leds_update(); + + return mcp23018_status; +} + +uint8_t ergodox_left_leds_update(void) { + if (mcp23018_status) { // if there was an error + return mcp23018_status; + } + + // set logical value (doesn't matter on inputs) + // - unused : hi-Z : 1 + // - input : hi-Z : 1 + // - driving : hi-Z : 1 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(OLATA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b11111111 + & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT) + ); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0b11111111 + & ~(ergodox_left_led_2<<LEFT_LED_2_SHIFT) + & ~(ergodox_left_led_1<<LEFT_LED_1_SHIFT) + ); if (mcp23018_status) goto out; + +out: + i2c_stop(); + return mcp23018_status; +} + diff --git a/keyboard/ergodox_ez/ergodox_ez.h b/keyboard/ergodox_ez/ergodox_ez.h new file mode 100644 index 0000000000..9d0691dfe2 --- /dev/null +++ b/keyboard/ergodox_ez/ergodox_ez.h @@ -0,0 +1,145 @@ +#ifndef PLANCK_H +#define PLANCK_H + +#include "matrix.h" +#include "keymap_common.h" +#include "backlight.h" +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <avr/io.h> +#include "i2cmaster.h" +#include <util/delay.h> + +#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) +#define CPU_16MHz 0x00 + +// I2C aliases and register addresses (see "mcp23018.md") +#define I2C_ADDR 0b0100000 +#define I2C_ADDR_WRITE ( (I2C_ADDR<<1) | I2C_WRITE ) +#define I2C_ADDR_READ ( (I2C_ADDR<<1) | I2C_READ ) +#define IODIRA 0x00 // i/o direction register +#define IODIRB 0x01 +#define GPPUA 0x0C // GPIO pull-up resistor register +#define GPPUB 0x0D +#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT) +#define GPIOB 0x13 +#define OLATA 0x14 // output latch register +#define OLATB 0x15 + +extern uint8_t mcp23018_status; + +void init_ergodox(void); +void ergodox_blink_all_leds(void); +uint8_t init_mcp23018(void); +uint8_t ergodox_left_leds_update(void); + +#define LED_BRIGHTNESS_LO 31 +#define LED_BRIGHTNESS_HI 255 + +#define LEFT_LED_1_SHIFT 7 // in MCP23018 port B +#define LEFT_LED_2_SHIFT 6 // in MCP23018 port B +#define LEFT_LED_3_SHIFT 7 // in MCP23018 port A + +extern bool ergodox_left_led_1; // left top +extern bool ergodox_left_led_2; // left middle +extern bool ergodox_left_led_3; // left bottom + +inline void ergodox_board_led_on(void) { DDRD |= (1<<6); PORTD |= (1<<6); } +inline void ergodox_right_led_1_on(void) { DDRB |= (1<<5); PORTB |= (1<<5); } +inline void ergodox_right_led_2_on(void) { DDRB |= (1<<6); PORTB |= (1<<6); } +inline void ergodox_right_led_3_on(void) { DDRB |= (1<<7); PORTB |= (1<<7); } +inline void ergodox_left_led_1_on(void) { ergodox_left_led_1 = 1; } +inline void ergodox_left_led_2_on(void) { ergodox_left_led_2 = 1; } +inline void ergodox_left_led_3_on(void) { ergodox_left_led_3 = 1; } + +inline void ergodox_board_led_off(void) { DDRD &= ~(1<<6); PORTD &= ~(1<<6); } +inline void ergodox_right_led_1_off(void) { DDRB &= ~(1<<5); PORTB &= ~(1<<5); } +inline void ergodox_right_led_2_off(void) { DDRB &= ~(1<<6); PORTB &= ~(1<<6); } +inline void ergodox_right_led_3_off(void) { DDRB &= ~(1<<7); PORTB &= ~(1<<7); } +inline void ergodox_left_led_1_off(void) { ergodox_left_led_1 = 0; } +inline void ergodox_left_led_2_off(void) { ergodox_left_led_2 = 0; } +inline void ergodox_left_led_3_off(void) { ergodox_left_led_3 = 0; } + +inline void ergodox_led_all_on(void) +{ + ergodox_board_led_on(); + ergodox_right_led_1_on(); + ergodox_right_led_2_on(); + ergodox_right_led_3_on(); + ergodox_left_led_1_on(); + ergodox_left_led_2_on(); + ergodox_left_led_3_on(); + ergodox_left_leds_update(); +} + +inline void ergodox_led_all_off(void) +{ + ergodox_board_led_off(); + ergodox_right_led_1_off(); + ergodox_right_led_2_off(); + ergodox_right_led_3_off(); + ergodox_left_led_1_off(); + ergodox_left_led_2_off(); + ergodox_left_led_3_off(); + ergodox_left_leds_update(); +} + +inline void ergodox_right_led_1_set(uint8_t n) { OCR1A = n; } +inline void ergodox_right_led_2_set(uint8_t n) { OCR1B = n; } +inline void ergodox_right_led_3_set(uint8_t n) { OCR1C = n; } + +inline void ergodox_led_all_set(uint8_t n) +{ + ergodox_right_led_1_set(n); + ergodox_right_led_2_set(n); + ergodox_right_led_3_set(n); +} + +#define KEYMAP( \ + \ + /* left hand, spatial positions */ \ + k00,k01,k02,k03,k04,k05,k06, \ + k10,k11,k12,k13,k14,k15,k16, \ + k20,k21,k22,k23,k24,k25, \ + k30,k31,k32,k33,k34,k35,k36, \ + k40,k41,k42,k43,k44, \ + k55,k56, \ + k54, \ + k53,k52,k51, \ + \ + /* right hand, spatial positions */ \ + k07,k08,k09,k0A,k0B,k0C,k0D, \ + k17,k18,k19,k1A,k1B,k1C,k1D, \ + k28,k29,k2A,k2B,k2C,k2D, \ + k37,k38,k39,k3A,k3B,k3C,k3D, \ + k49,k4A,k4B,k4C,k4D, \ + k57,k58, \ + k59, \ + k5C,k5B,k5A ) \ + \ + /* matrix positions */ \ + { \ + { k00, k10, k20, k30, k40, KC_NO }, \ + { k01, k11, k21, k31, k41, k51 }, \ + { k02, k12, k22, k32, k42, k52 }, \ + { k03, k13, k23, k33, k43, k53 }, \ + { k04, k14, k24, k34, k44, k54 }, \ + { k05, k15, k25, k35, KC_NO, k55 }, \ + { k06, k16, KC_NO, k36, KC_NO, k56 }, \ + \ + { k07, k17, KC_NO, k37,KC_NO, k57 }, \ + { k08, k18, k28, k38,KC_NO, k58 }, \ + { k09, k19, k29, k39, k49, k59 }, \ + { k0A, k1A, k2A, k3A, k4A, k5A }, \ + { k0B, k1B, k2B, k3B, k4B, k5B }, \ + { k0C, k1C, k2C, k3C, k4C, k5C }, \ + { k0D, k1D, k2D, k3D, k4D, KC_NO } \ + } + +void * matrix_init_user(void); +void * matrix_scan_user(void); + + + +#endif
\ No newline at end of file diff --git a/keyboard/ergodox_ez/i2cmaster.h b/keyboard/ergodox_ez/i2cmaster.h new file mode 100644 index 0000000000..3917b9e6c0 --- /dev/null +++ b/keyboard/ergodox_ez/i2cmaster.h @@ -0,0 +1,178 @@ +#ifndef _I2CMASTER_H +#define _I2CMASTER_H 1 +/************************************************************************* +* Title: C include file for the I2C master interface +* (i2cmaster.S or twimaster.c) +* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury +* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $ +* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 +* Target: any AVR device +* Usage: see Doxygen manual +**************************************************************************/ + +#ifdef DOXYGEN +/** + @defgroup pfleury_ic2master I2C Master library + @code #include <i2cmaster.h> @endcode + + @brief I2C (TWI) Master Software Library + + Basic routines for communicating with I2C slave devices. This single master + implementation is limited to one bus master on the I2C bus. + + This I2c library is implemented as a compact assembler software implementation of the I2C protocol + which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c). + Since the API for these two implementations is exactly the same, an application can be linked either against the + software I2C implementation or the hardware I2C implementation. + + Use 4.7k pull-up resistor on the SDA and SCL pin. + + Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module + i2cmaster.S to your target when using the software I2C implementation ! + + Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion. + + @note + The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted + to GNU assembler and AVR-GCC C call interface. + Replaced the incorrect quarter period delays found in AVR300 with + half period delays. + + @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + + @par API Usage Example + The following code shows typical usage of this library, see example test_i2cmaster.c + + @code + + #include <i2cmaster.h> + + + #define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet + + int main(void) + { + unsigned char ret; + + i2c_init(); // initialize I2C library + + // write 0x75 to EEPROM address 5 (Byte Write) + i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode + i2c_write(0x05); // write address = 5 + i2c_write(0x75); // write value 0x75 to EEPROM + i2c_stop(); // set stop conditon = release bus + + + // read previously written value back from EEPROM address 5 + i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode + + i2c_write(0x05); // write address = 5 + i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode + + ret = i2c_readNak(); // read one byte from EEPROM + i2c_stop(); + + for(;;); + } + @endcode + +*/ +#endif /* DOXYGEN */ + +/**@{*/ + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" +#endif + +#include <avr/io.h> + +/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */ +#define I2C_READ 1 + +/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */ +#define I2C_WRITE 0 + + +/** + @brief initialize the I2C master interace. Need to be called only once + @param void + @return none + */ +extern void i2c_init(void); + + +/** + @brief Terminates the data transfer and releases the I2C bus + @param void + @return none + */ +extern void i2c_stop(void); + + +/** + @brief Issues a start condition and sends address and transfer direction + + @param addr address and transfer direction of I2C device + @retval 0 device accessible + @retval 1 failed to access device + */ +extern unsigned char i2c_start(unsigned char addr); + + +/** + @brief Issues a repeated start condition and sends address and transfer direction + + @param addr address and transfer direction of I2C device + @retval 0 device accessible + @retval 1 failed to access device + */ +extern unsigned char i2c_rep_start(unsigned char addr); + + +/** + @brief Issues a start condition and sends address and transfer direction + + If device is busy, use ack polling to wait until device ready + @param addr address and transfer direction of I2C device + @return none + */ +extern void i2c_start_wait(unsigned char addr); + + +/** + @brief Send one byte to I2C device + @param data byte to be transfered + @retval 0 write successful + @retval 1 write failed + */ +extern unsigned char i2c_write(unsigned char data); + + +/** + @brief read one byte from the I2C device, request more data from device + @return byte read from I2C device + */ +extern unsigned char i2c_readAck(void); + +/** + @brief read one byte from the I2C device, read is followed by a stop condition + @return byte read from I2C device + */ +extern unsigned char i2c_readNak(void); + +/** + @brief read one byte from the I2C device + + Implemented as a macro, which calls either i2c_readAck or i2c_readNak + + @param ack 1 send ack, request more data from device<br> + 0 send nak, read is followed by a stop condition + @return byte read from I2C device + */ +extern unsigned char i2c_read(unsigned char ack); +#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak(); + + +/**@}*/ +#endif diff --git a/keyboard/ergodox_ez/keymaps/keymap_default.c b/keyboard/ergodox_ez/keymaps/keymap_default.c new file mode 100644 index 0000000000..98cc9c5a6f --- /dev/null +++ b/keyboard/ergodox_ez/keymaps/keymap_default.c @@ -0,0 +1,133 @@ +#include "ergodox_ez.h" +#include "debug.h" +#include "action_layer.h" + +// TODO: Define layer names that make sense for the ErgoDox EZ. +#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; +}; + +// Runs just one time when the keyboard initializes. +void * matrix_init_user(void) { + +}; + +// Runs constantly in the background, in a loop. +void * matrix_scan_user(void) { + 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) { + // TODO: Make this relevant to the ErgoDox EZ. + 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(); +}; diff --git a/keyboard/ergodox_ez/keymaps/keymap_ergodox_ez.c b/keyboard/ergodox_ez/keymaps/keymap_ergodox_ez.c new file mode 100644 index 0000000000..bab16ece53 --- /dev/null +++ b/keyboard/ergodox_ez/keymaps/keymap_ergodox_ez.c @@ -0,0 +1,211 @@ +// TODO: Move all of this stuff into the default keymap, and then get rid of this file. +#include "action_util.h" +#include "action_layer.h" +#define KC_SW0 KC_FN0 +#define DEBUG_ACTION + +static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + + /* Keymap 0: Basic layer + * + * ,--------------------------------------------------. ,--------------------------------------------------. + * | = | 1 | 2 | 3 | 4 | 5 | LEFT | | RIGHT| 6 | 7 | 8 | 9 | 0 | - | + * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| + * | Del | Q | W | E | R | T | Up | | Up | Y | U | I | O | P | \ | + * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| + * | BkSp | A | S | D | F | G |------| |------| H | J | K | L |; / L2| ' | + * |--------+------+------+------+------+------| L1 | | L1 |------+------+------+------+------+--------| + * | LShift |Z/Ctrl| X | C | V | B | | | | N | M | , | . |//Ctrl| RShift | + * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------' + * |Grv/L1| ~L1 | TAB | Left | Right| | Up | Down | [ | ] | ~L1 | + * `----------------------------------' `----------------------------------' + * ,-------------. ,-------------. + * | Rclk | LGui | | Alt |Ctrl/Esc| + * ,------|------|------| |------+--------+------. + * | | | Home | | PgUp | | | + * | Space| Enter|------| |------| Tab |Enter | + * | | | End | | PgDn | | | + * `--------------------' `----------------------' + */ + + + // Basic layer + + KEYMAP( + EQL, 1, 2, 3, 4, 5, LEFT, + DEL, Q, W, E, R, T, UP, + BSPC, A, S, D, F, G, + LSFT, FN29, X, C, V, B, FN1, + FN30, FN4, TAB, LEFT, RIGHT, + + BTN2,LGUI, + HOME, + SPC, ENT, END, + //RIGHT + RIGHT,6, 7, 8, 9, 0, MINS, + UP, Y, U, I, O, P, BSLS, + H, J, K, L, FN31, QUOT, + FN1, N, M, COMM, DOT, FN28, RSFT, + UP, DOWN, LBRC, RBRC, FN4, + LALT, FN27, + PGUP, + PGDN, TAB, ENT + ), + + /* Keymap 1: Symbol Layer + * + * ,--------------------------------------------------. ,--------------------------------------------------. + * | Flash | F1 | F2 | F3 | F4 | F5 | | | | F6 | F7 | F8 | F9 | F10 | F11 | + * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| + * | | ! | @ | { | } | | | | | | Up | 7 | 8 | 9 | * | F12 | + * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| + * | : | # | $ | ( | ) | ` |------| |------| Down | 4 | 5 | 6 | + | | + * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| + * | | % | ^ | [ | ] | ~ | | | | & | 1 | 2 | 3 | \ | | + * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------' + * | | | | | | | | . | 0 | = | | + * `----------------------------------' `----------------------------------' + * ,-------------. ,-------------. + * | | | | | | + * ,------|------|------| |------+------+------. + * | | | | | | | | + * | | |------| |------| | | + * | | | | | | | | + * `--------------------' `--------------------' + */ + // SYMBOLS + KEYMAP( + FN0, F1, F2, F3, F4, F5, TRNS, + TRNS, FN7, FN8, FN23, FN24, FN18, TRNS, + FN22, FN9, FN10, FN15, FN16, GRV, + TRNS, FN11, FN12, LBRC, RBRC, FN17, TRNS, + TRNS, TRNS, TRNS, TRNS, TRNS, + + TRNS, TRNS, + TRNS, + TRNS, TRNS, TRNS, + // right hand + TRNS, F6, F7, F8, F9, F10, F11, + TRNS, UP, 7, 8, 9, FN14, F12, + DOWN, 4, 5, 6, FN26, TRNS, + TRNS, FN13, 1, 2, 3, BSLS, TRNS, + TRNS,DOT, 0, EQL, TRNS, + TRNS, TRNS, + TRNS, + TRNS, TRNS, TRNS + ), + /* Keymap 2: Media and mouse keys + * + * ,--------------------------------------------------. ,--------------------------------------------------. + * | | | | | | | | | | | | | | | | + * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| + * | | | MsUp | | | | | | | | | | | | | + * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| + * | |MsLeft|MsDown|MsRght| | |------| |------| | | | Play | | | + * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| + * | | | | | | | | | | | | Prev | Next | | | + * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------' + * | | | | Lclk | Rclk | |VolUp |VolDn | | | | + * `----------------------------------' `----------------------------------' + * ,-------------. ,-------------. + * | | | | | | + * ,------|------|------| |------+------+------. + * | | | | | | | | + * | | |------| |------| | | + * | | | | | | | | + * `--------------------' `--------------------' + */ + // MEDIA AND MOUSE + KEYMAP( + TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, + TRNS, TRNS, MS_U, TRNS, TRNS, TRNS, TRNS, + TRNS, MS_L, MS_D, MS_R, TRNS, TRNS, + TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, + TRNS, TRNS, TRNS, BTN3, BTN2, + + TRNS, TRNS, + TRNS, + TRNS, TRNS, TRNS, + // right hand + TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, + TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, TRNS, + TRNS, TRNS, TRNS, MPLY, TRNS, TRNS, + TRNS, TRNS, TRNS, MPRV, MNXT, TRNS, TRNS, + VOLU, VOLD, TRNS, TRNS, TRNS, + TRNS, TRNS, + TRNS, + TRNS, TRNS, WBAK + ), +}; + +/* id for user defined functions */ +enum function_id { + TEENSY_KEY, +}; + +/* + * Fn action definition + */ +static const uint16_t PROGMEM fn_actions[] = { + [0] = ACTION_FUNCTION(TEENSY_KEY), // FN0 - Teensy key + [1] = ACTION_LAYER_INVERT(1, ON_RELEASE), // FN1 - Toggle 1 + [2] = ACTION_LAYER_TOGGLE(2), // FN2 - Toggle 2 + [3] = ACTION_LAYER_TOGGLE(3), // FN3 - Toggle 3 + [4] = ACTION_LAYER_TAP_TOGGLE(1), // FN4 - Momentary Layer 1 + [5] = ACTION_LAYER_MOMENTARY(2), // FN5 - Momentary L2 + + // SYMBOLS + ACTION_MODS_KEY(MOD_LSFT, KC_QUOT), // FN6 - " + ACTION_MODS_KEY(MOD_LSFT, KC_1), // FN7 - ! + ACTION_MODS_KEY(MOD_LSFT, KC_2), // FN8 - @ + ACTION_MODS_KEY(MOD_LSFT, KC_3), // FN9 - # + ACTION_MODS_KEY(MOD_LSFT, KC_4), // FN10 - $ + ACTION_MODS_KEY(MOD_LSFT, KC_5), // FN11 - % + ACTION_MODS_KEY(MOD_LSFT, KC_6), // FN12 - ^ + ACTION_MODS_KEY(MOD_LSFT, KC_7), // FN13 - & + ACTION_MODS_KEY(MOD_LSFT, KC_8), // FN14 - * + ACTION_MODS_KEY(MOD_LSFT, KC_9), // FN15 - ( + ACTION_MODS_KEY(MOD_LSFT, KC_0), // FN16 - ) + ACTION_MODS_KEY(MOD_LSFT, KC_GRV), // FN17 - ~ + ACTION_MODS_KEY(MOD_LSFT, KC_BSLS), // FN18 - | + ACTION_MODS_KEY(MOD_LSFT, KC_MINS), // FN19 - _ + ACTION_MODS_KEY(MOD_LSFT, KC_COMM), // FN20 - < + ACTION_MODS_KEY(MOD_LSFT, KC_DOT), // FN21 - > + ACTION_MODS_KEY(MOD_LSFT, KC_SCLN), // FN22 - : + ACTION_MODS_KEY(MOD_LSFT, KC_LBRC), // FN23 - { + ACTION_MODS_KEY(MOD_LSFT, KC_RBRC), // FN24 - } + ACTION_MODS_KEY(MOD_LSFT, KC_SLSH), // FN25 - ? + ACTION_MODS_KEY(MOD_LSFT, KC_EQL), // FN26 - + + + ACTION_MODS_TAP_KEY(MOD_LCTL, KC_ESC), // FN27 - Control/esc on tap + ACTION_MODS_TAP_KEY(MOD_LCTL, KC_SLSH), // FN28 - slash becomes Ctrl when held (right pinky) + ACTION_MODS_TAP_KEY(MOD_LCTL, KC_Z), // FN29 - z becomes Ctrl when held (left pinky) + + // Fancy tapping/toggling + ACTION_LAYER_TAP_KEY(1, KC_GRV), // FN30 - Layer 1 when holding backtick key + ACTION_LAYER_TAP_KEY(2, KC_SCLN), // FN31 - Layer 2 when holding semicolon key + + +}; + +void action_function(keyrecord_t *event, uint8_t id, uint8_t opt) +{ + print("action_function called\n"); + print("id = "); phex(id); print("\n"); + print("opt = "); phex(opt); print("\n"); + if (id == TEENSY_KEY) { + clear_keyboard(); + print("\n\nJump to bootloader... "); + _delay_ms(250); + bootloader_jump(); // should not return + print("not supported.\n"); + } +} + +void * matrix_init_user(void) { + +}; + +void * matrix_scan_user(void) { + +}; diff --git a/keyboard/ergodox_ez/matrix.c b/keyboard/ergodox_ez/matrix.c new file mode 100644 index 0000000000..09380d3083 --- /dev/null +++ b/keyboard/ergodox_ez/matrix.c @@ -0,0 +1,348 @@ +/* + +Note for ErgoDox EZ customizers: Here be dragons! +This is not a file you want to be messing with. +All of the interesting stuff for you is under keymaps/ :) +Love, Erez + +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_ez.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 + + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + select_row(i); + matrix_row_t cols = read_cols(i); + if (matrix_debouncing[i] != cols) { + matrix_debouncing[i] = cols; + if (debouncing) { + debug("bounce!: "); debug_hex(debouncing); debug("\n"); + } + debouncing = DEBOUNCE; + } + unselect_rows(); + } + + if (debouncing) { + if (--debouncing) { + _delay_ms(1); + } else { + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + matrix[i] = matrix_debouncing[i]; + } + } + } + + + if (matrix_scan_kb) { + (*matrix_scan_kb)(); + } + + return 1; +} + +bool matrix_is_modified(void) +{ + if (debouncing) return false; + return true; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & ((matrix_row_t)1<<col)); +} + +inline +matrix_row_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +void matrix_print(void) +{ + print("\nr/c 0123456789ABCDEF\n"); + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + phex(row); print(": "); + pbin_reverse16(matrix_get_row(row)); + print("\n"); + } +} + +uint8_t matrix_key_count(void) +{ + uint8_t count = 0; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + count += bitpop16(matrix[i]); + } + return count; +} + +/* Column pin configuration + * + * Teensy + * col: 0 1 2 3 4 5 + * pin: F0 F1 F4 F5 F6 F7 + * + * MCP23018 + * col: 0 1 2 3 4 5 + * pin: B5 B4 B3 B2 B1 B0 + */ +static void init_cols(void) +{ + // init on mcp23018 + // not needed, already done as part of init_mcp23018() + + // init on teensy + // Input with pull-up(DDR:0, PORT:1) + DDRF &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); + PORTF |= (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); +} + +static matrix_row_t read_cols(uint8_t row) +{ + if (row < 7) { + if (mcp23018_status) { // if there was an error + return 0; + } else { + uint8_t data = 0; + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPIOB); if (mcp23018_status) goto out; + mcp23018_status = i2c_start(I2C_ADDR_READ); if (mcp23018_status) goto out; + data = i2c_readNak(); + data = ~data; + out: + i2c_stop(); + return data; + } + } else { + _delay_us(30); // without this wait read unstable value. + // read from teensy + return + (PINF&(1<<0) ? 0 : (1<<0)) | + (PINF&(1<<1) ? 0 : (1<<1)) | + (PINF&(1<<4) ? 0 : (1<<2)) | + (PINF&(1<<5) ? 0 : (1<<3)) | + (PINF&(1<<6) ? 0 : (1<<4)) | + (PINF&(1<<7) ? 0 : (1<<5)) ; + } +} + +/* Row pin configuration + * + * Teensy + * row: 7 8 9 10 11 12 13 + * pin: B0 B1 B2 B3 D2 D3 C6 + * + * MCP23018 + * row: 0 1 2 3 4 5 6 + * pin: A0 A1 A2 A3 A4 A5 A6 + */ +static void unselect_rows(void) +{ + // unselect on mcp23018 + if (mcp23018_status) { // if there was an error + // do nothing + } else { + // set all rows hi-Z : 1 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPIOA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write( 0xFF + & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT) + ); if (mcp23018_status) goto out; + out: + i2c_stop(); + } + + // unselect on teensy + // Hi-Z(DDR:0, PORT:0) to unselect + DDRB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); + PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); + DDRD &= ~(1<<2 | 1<<3); + PORTD &= ~(1<<2 | 1<<3); + DDRC &= ~(1<<6); + PORTC &= ~(1<<6); +} + +static void select_row(uint8_t row) +{ + if (row < 7) { + // select on mcp23018 + if (mcp23018_status) { // if there was an error + // do nothing + } else { + // set active row low : 0 + // set other rows hi-Z : 1 + mcp23018_status = i2c_start(I2C_ADDR_WRITE); if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPIOA); if (mcp23018_status) goto out; + mcp23018_status = i2c_write( 0xFF & ~(1<<row) + & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT) + ); if (mcp23018_status) goto out; + out: + i2c_stop(); + } + } else { + // select on teensy + // Output low(DDR:1, PORT:0) to select + switch (row) { + case 7: + DDRB |= (1<<0); + PORTB &= ~(1<<0); + break; + case 8: + DDRB |= (1<<1); + PORTB &= ~(1<<1); + break; + case 9: + DDRB |= (1<<2); + PORTB &= ~(1<<2); + break; + case 10: + DDRB |= (1<<3); + PORTB &= ~(1<<3); + break; + case 11: + DDRD |= (1<<2); + PORTD &= ~(1<<3); + break; + case 12: + DDRD |= (1<<3); + PORTD &= ~(1<<3); + break; + case 13: + DDRC |= (1<<6); + PORTC &= ~(1<<6); + break; + } + } +} + diff --git a/keyboard/ergodox_ez/twimaster.c b/keyboard/ergodox_ez/twimaster.c new file mode 100644 index 0000000000..f91c08e6e4 --- /dev/null +++ b/keyboard/ergodox_ez/twimaster.c @@ -0,0 +1,208 @@ +/************************************************************************* +* Title: I2C master library using hardware TWI interface +* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury +* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $ +* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 +* Target: any AVR device with hardware TWI +* Usage: API compatible with I2C Software Library i2cmaster.h +**************************************************************************/ +#include <inttypes.h> +#include <compat/twi.h> + +#include <i2cmaster.h> + + +/* define CPU frequency in Mhz here if not defined in Makefile */ +#ifndef F_CPU +#define F_CPU 16000000UL +#endif + +/* I2C clock in Hz */ +#define SCL_CLOCK 400000L + + +/************************************************************************* + Initialization of the I2C bus interface. Need to be called only once +*************************************************************************/ +void i2c_init(void) +{ + /* initialize TWI clock + * minimal values in Bit Rate Register (TWBR) and minimal Prescaler + * bits in the TWI Status Register should give us maximal possible + * I2C bus speed - about 444 kHz + * + * for more details, see 20.5.2 in ATmega16/32 secification + */ + + TWSR = 0; /* no prescaler */ + TWBR = 10; /* must be >= 10 for stable operation */ + +}/* i2c_init */ + + +/************************************************************************* + Issues a start condition and sends address and transfer direction. + return 0 = device accessible, 1= failed to access device +*************************************************************************/ +unsigned char i2c_start(unsigned char address) +{ + uint8_t twst; + + // send START condition + TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); + + // wait until transmission completed + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits. + twst = TW_STATUS & 0xF8; + if ( (twst != TW_START) && (twst != TW_REP_START)) return 1; + + // send device address + TWDR = address; + TWCR = (1<<TWINT) | (1<<TWEN); + + // wail until transmission completed and ACK/NACK has been received + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits. + twst = TW_STATUS & 0xF8; + if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1; + + return 0; + +}/* i2c_start */ + + +/************************************************************************* + Issues a start condition and sends address and transfer direction. + If device is busy, use ack polling to wait until device is ready + + Input: address and transfer direction of I2C device +*************************************************************************/ +void i2c_start_wait(unsigned char address) +{ + uint8_t twst; + + + while ( 1 ) + { + // send START condition + TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); + + // wait until transmission completed + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits. + twst = TW_STATUS & 0xF8; + if ( (twst != TW_START) && (twst != TW_REP_START)) continue; + + // send device address + TWDR = address; + TWCR = (1<<TWINT) | (1<<TWEN); + + // wail until transmission completed + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits. + twst = TW_STATUS & 0xF8; + if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) + { + /* device busy, send stop condition to terminate write operation */ + TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); + + // wait until stop condition is executed and bus released + while(TWCR & (1<<TWSTO)); + + continue; + } + //if( twst != TW_MT_SLA_ACK) return 1; + break; + } + +}/* i2c_start_wait */ + + +/************************************************************************* + Issues a repeated start condition and sends address and transfer direction + + Input: address and transfer direction of I2C device + + Return: 0 device accessible + 1 failed to access device +*************************************************************************/ +unsigned char i2c_rep_start(unsigned char address) +{ + return i2c_start( address ); + +}/* i2c_rep_start */ + + +/************************************************************************* + Terminates the data transfer and releases the I2C bus +*************************************************************************/ +void i2c_stop(void) +{ + /* send stop condition */ + TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); + + // wait until stop condition is executed and bus released + while(TWCR & (1<<TWSTO)); + +}/* i2c_stop */ + + +/************************************************************************* + Send one byte to I2C device + + Input: byte to be transfered + Return: 0 write successful + 1 write failed +*************************************************************************/ +unsigned char i2c_write( unsigned char data ) +{ + uint8_t twst; + + // send data to the previously addressed device + TWDR = data; + TWCR = (1<<TWINT) | (1<<TWEN); + + // wait until transmission completed + while(!(TWCR & (1<<TWINT))); + + // check value of TWI Status Register. Mask prescaler bits + twst = TW_STATUS & 0xF8; + if( twst != TW_MT_DATA_ACK) return 1; + return 0; + +}/* i2c_write */ + + +/************************************************************************* + Read one byte from the I2C device, request more data from device + + Return: byte read from I2C device +*************************************************************************/ +unsigned char i2c_readAck(void) +{ + TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); + while(!(TWCR & (1<<TWINT))); + + return TWDR; + +}/* i2c_readAck */ + + +/************************************************************************* + Read one byte from the I2C device, read is followed by a stop condition + + Return: byte read from I2C device +*************************************************************************/ +unsigned char i2c_readNak(void) +{ + TWCR = (1<<TWINT) | (1<<TWEN); + while(!(TWCR & (1<<TWINT))); + + return TWDR; + +}/* i2c_readNak */ |