diff options
author | Yu He <yuhe00@gmail.com> | 2017-08-12 16:05:05 +0200 |
---|---|---|
committer | Jack Humbert <jack.humb@gmail.com> | 2017-08-16 17:31:12 -0400 |
commit | 52f4a38cb39e3640e0479b794815eae38a49f503 (patch) | |
tree | de79702f626281ee44f68c6c543db750e09c55de /keyboards/ergodox/ergodone | |
parent | f02430b131961e97e06a8f57719f48fdbe4a2fe8 (diff) | |
download | qmk_firmware-52f4a38cb39e3640e0479b794815eae38a49f503.tar.gz qmk_firmware-52f4a38cb39e3640e0479b794815eae38a49f503.zip |
Add support for the ErgoDone
Diffstat (limited to 'keyboards/ergodox/ergodone')
-rw-r--r-- | keyboards/ergodox/ergodone/Makefile | 3 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/config.h | 49 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/ergodone.c | 5 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/ergodone.h | 54 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/expander.c | 120 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/expander.h | 48 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/i2cmaster.h | 178 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/matrix.c | 295 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/rules.mk | 91 | ||||
-rw-r--r-- | keyboards/ergodox/ergodone/twimaster.c | 208 |
10 files changed, 1051 insertions, 0 deletions
diff --git a/keyboards/ergodox/ergodone/Makefile b/keyboards/ergodox/ergodone/Makefile new file mode 100644 index 0000000000..bd09e5885d --- /dev/null +++ b/keyboards/ergodox/ergodone/Makefile @@ -0,0 +1,3 @@ +ifndef MAKEFILE_INCLUDED + include ../../../Makefile +endif diff --git a/keyboards/ergodox/ergodone/config.h b/keyboards/ergodox/ergodone/config.h new file mode 100644 index 0000000000..80ff47f661 --- /dev/null +++ b/keyboards/ergodox/ergodone/config.h @@ -0,0 +1,49 @@ +#ifndef ERGODOX_ERGODONE_CONFIG_H +#define ERGODOX_ERGODONE_CONFIG_H + +#include "../config.h" + +#include "config_common.h" + +/* USB Device descriptor parameter */ +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x1307 +#define DEVICE_VER 0x0001 +#define MANUFACTURER ErgoDone +#define PRODUCT ErgoDone +#define DESCRIPTION QMK keyboard firmware for ErgoDone + +/* key matrix size */ +#define MATRIX_ROWS 6 +#define MATRIX_COLS 14 + +/* fix space cadet rollover issue */ +#define DISABLE_SPACE_CADET_ROLLOVER + +/* Set 0 if debouncing isn't needed */ +#define DEBOUNCE 5 + +#define PREVENT_STUCK_MODIFIERS + +#define USB_MAX_POWER_CONSUMPTION 500 + +/* + * 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/keyboards/ergodox/ergodone/ergodone.c b/keyboards/ergodox/ergodone/ergodone.c new file mode 100644 index 0000000000..6b8d8a0632 --- /dev/null +++ b/keyboards/ergodox/ergodone/ergodone.c @@ -0,0 +1,5 @@ +#include "ergodone.h" + +void matrix_init_kb(void) { + matrix_init_user(); +} diff --git a/keyboards/ergodox/ergodone/ergodone.h b/keyboards/ergodox/ergodone/ergodone.h new file mode 100644 index 0000000000..21ef9d3e31 --- /dev/null +++ b/keyboards/ergodox/ergodone/ergodone.h @@ -0,0 +1,54 @@ +#ifndef ERGODOX_ERGODONE_H +#define ERGODOX_ERGODONE_H + +#include "quantum.h" +#include <stdint.h> +#include <stdbool.h> + +#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) +#define CPU_16MHz 0x00 + +void init_ergodox(void); + +inline void ergodox_right_led_1_off(void) {} +inline void ergodox_right_led_1_on(void) {} +inline void ergodox_right_led_2_off(void) {} +inline void ergodox_right_led_2_on(void) {} +inline void ergodox_right_led_3_off(void) {} +inline void ergodox_right_led_3_on(void) {} +inline void ergodox_board_led_off(void) {} +inline void ergodox_board_led_on(void) {} + +#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, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B, k0C, k0D }, \ + { k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B, k1C, k1D }, \ + { k20, k21, k22, k23, k24, k25, KC_NO, KC_NO, k28, k29, k2A, k2B, k2C, k2D }, \ + { k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k3A, k3B, k3C, k3D }, \ + { k40, k41, k42, k43, k44, KC_NO, KC_NO, KC_NO, KC_NO, k49, k4A, k4B, k4C, k4D }, \ + { KC_NO, k51, k52, k53, k54, k55, k56, k57, k58, k59, k5A, k5B, k5C, KC_NO } \ + } + +#endif diff --git a/keyboards/ergodox/ergodone/expander.c b/keyboards/ergodox/ergodone/expander.c new file mode 100644 index 0000000000..0c8a2289c5 --- /dev/null +++ b/keyboards/ergodox/ergodone/expander.c @@ -0,0 +1,120 @@ +#include <stdbool.h> +#include "action.h" +#include "i2cmaster.h" +#include "expander.h" +#include "debug.h" + +static uint8_t expander_status = 0; +static uint8_t expander_input = 0; + +void expander_config(void); +uint8_t expander_write(uint8_t reg, uint8_t data); +uint8_t expander_read(uint8_t reg, uint8_t *data); + +void expander_init(void) +{ + i2c_init(); + expander_scan(); +} + +void expander_scan(void) +{ + dprintf("expander status: %d ... ", expander_status); + uint8_t ret = i2c_start(EXPANDER_ADDR | I2C_WRITE); + if (ret == 0) { + i2c_stop(); + if (expander_status == 0) { + dprintf("attached\n"); + expander_status = 1; + expander_config(); + clear_keyboard(); + } + } + else { + if (expander_status == 1) { + dprintf("detached\n"); + expander_status = 0; + clear_keyboard(); + } + } + dprintf("%d\n", expander_status); +} + +void expander_read_cols(void) +{ + expander_read(EXPANDER_REG_GPIOA, &expander_input); +} + +uint8_t expander_get_col(uint8_t col) +{ + if (col > 4) { + col++; + } + return expander_input & (1<<col) ? 1 : 0; +} + +matrix_row_t expander_read_row(void) +{ + expander_read_cols(); + + /* make cols */ + matrix_row_t cols = 0; + for (uint8_t col = 0; col < MATRIX_COLS; col++) { + if (expander_get_col(col)) { + cols |= (1UL << (MATRIX_COLS - 1 - col)); + } + } + + return cols; +} + +void expander_unselect_rows(void) +{ + expander_write(EXPANDER_REG_IODIRB, 0xFF); +} + +void expander_select_row(uint8_t row) +{ + expander_write(EXPANDER_REG_IODIRB, ~(1<<(row+1))); +} + +void expander_config(void) +{ + expander_write(EXPANDER_REG_IPOLA, 0xFF); + expander_write(EXPANDER_REG_GPPUA, 0xFF); + expander_write(EXPANDER_REG_IODIRB, 0xFF); +} + +uint8_t expander_write(uint8_t reg, uint8_t data) +{ + if (expander_status == 0) { + return 0; + } + uint8_t ret; + ret = i2c_start(EXPANDER_ADDR | I2C_WRITE); + if (ret) goto stop; + ret = i2c_write(reg); + if (ret) goto stop; + ret = i2c_write(data); + stop: + i2c_stop(); + return ret; +} + +uint8_t expander_read(uint8_t reg, uint8_t *data) +{ + if (expander_status == 0) { + return 0; + } + uint8_t ret; + ret = i2c_start(EXPANDER_ADDR | I2C_WRITE); + if (ret) goto stop; + ret = i2c_write(reg); + if (ret) goto stop; + ret = i2c_rep_start(EXPANDER_ADDR | I2C_READ); + if (ret) goto stop; + *data = i2c_readNak(); + stop: + i2c_stop(); + return ret; +} diff --git a/keyboards/ergodox/ergodone/expander.h b/keyboards/ergodox/ergodone/expander.h new file mode 100644 index 0000000000..8676fed693 --- /dev/null +++ b/keyboards/ergodox/ergodone/expander.h @@ -0,0 +1,48 @@ +#ifndef EXPANDER_H +#define EXPANDER_H + +#include <stdint.h> +#include "matrix.h" + +#define MCP23017 +#define MCP23017_A0 0 +#define MCP23017_A1 0 +#define MCP23017_A2 0 + +#ifdef MCP23017 +#define EXPANDER_ADDR ((0x20|(MCP23017_A0<<0)|(MCP23017_A1<<1)|(MCP23017_A2<<2)) << 1) +enum EXPANDER_REG_BANK0 { + EXPANDER_REG_IODIRA = 0, + EXPANDER_REG_IODIRB, + EXPANDER_REG_IPOLA, + EXPANDER_REG_IPOLB, + EXPANDER_REG_GPINTENA, + EXPANDER_REG_GPINTENB, + EXPANDER_REG_DEFVALA, + EXPANDER_REG_DEFVALB, + EXPANDER_REG_INTCONA, + EXPANDER_REG_INTCONB, + EXPANDER_REG_IOCONA, + EXPANDER_REG_IOCONB, + EXPANDER_REG_GPPUA, + EXPANDER_REG_GPPUB, + EXPANDER_REG_INTFA, + EXPANDER_REG_INTFB, + EXPANDER_REG_INTCAPA, + EXPANDER_REG_INTCAPB, + EXPANDER_REG_GPIOA, + EXPANDER_REG_GPIOB, + EXPANDER_REG_OLATA, + EXPANDER_REG_OLATB +}; +#endif + +void expander_init(void); +void expander_scan(void); +void expander_read_cols(void); +uint8_t expander_get_col(uint8_t col); +matrix_row_t expander_read_row(void); +void expander_unselect_rows(void); +void expander_select_row(uint8_t row); + +#endif diff --git a/keyboards/ergodox/ergodone/i2cmaster.h b/keyboards/ergodox/ergodone/i2cmaster.h new file mode 100644 index 0000000000..3917b9e6c0 --- /dev/null +++ b/keyboards/ergodox/ergodone/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/keyboards/ergodox/ergodone/matrix.c b/keyboards/ergodox/ergodone/matrix.c new file mode 100644 index 0000000000..2eb8f24ba8 --- /dev/null +++ b/keyboards/ergodox/ergodone/matrix.c @@ -0,0 +1,295 @@ +#include <stdint.h> +#include <stdbool.h> +#include <avr/io.h> +#include "wait.h" +#include "action_layer.h" +#include "print.h" +#include "debug.h" +#include "util.h" +#include "matrix.h" +#include "ergodone.h" +#include "expander.h" +#ifdef DEBUG_MATRIX_SCAN_RATE +#include "timer.h" +#endif + +/* + * This constant define not debouncing time in msecs, but amount of matrix + * scan loops which should be made to get stable debounced results. + * + * On Ergodox matrix scan rate is relatively low, because of slow I2C. + * Now it's only 317 scans/second, or about 3.15 msec/scan. + * According to Cherry specs, debouncing time is 5 msec. + * + * And so, there is no sense to have DEBOUNCE higher than 2. + */ + +#ifndef DEBOUNCE +# define DEBOUNCE 5 +#endif + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; + +// Debouncing: store for each key the number of scans until it's eligible to +// change. When scanning the matrix, ignore any changes in keys that have +// already changed in the last DEBOUNCE scans. +static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS]; + +static matrix_row_t read_cols(uint8_t row); +static void init_cols(void); +static void unselect_rows(void); +static void select_row(uint8_t row); + +#ifdef DEBUG_MATRIX_SCAN_RATE +uint32_t matrix_timer; +uint32_t matrix_scan_count; +#endif + + +__attribute__ ((weak)) +void matrix_init_user(void) {} + +__attribute__ ((weak)) +void matrix_scan_user(void) {} + +__attribute__ ((weak)) +void matrix_init_kb(void) { + matrix_init_user(); +} + +__attribute__ ((weak)) +void matrix_scan_kb(void) { + matrix_scan_user(); +} + +inline +uint8_t matrix_rows(void) +{ + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) +{ + return MATRIX_COLS; +} + +void matrix_init(void) +{ + // disable JTAG + MCUCR = (1<<JTD); + MCUCR = (1<<JTD); + + unselect_rows(); + init_cols(); + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + for (uint8_t j=0; j < MATRIX_COLS; ++j) { + debounce_matrix[i * MATRIX_COLS + j] = 0; + } + } + +#ifdef DEBUG_MATRIX_SCAN_RATE + matrix_timer = timer_read32(); + matrix_scan_count = 0; +#endif + + matrix_init_quantum(); + +} + +void matrix_power_up(void) { + unselect_rows(); + init_cols(); + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + } + +#ifdef DEBUG_MATRIX_SCAN_RATE + matrix_timer = timer_read32(); + matrix_scan_count = 0; +#endif +} + +// Returns a matrix_row_t whose bits are set if the corresponding key should be +// eligible to change in this scan. +matrix_row_t debounce_mask(uint8_t row) { + matrix_row_t result = 0; + for (uint8_t j=0; j < MATRIX_COLS; ++j) { + if (debounce_matrix[row * MATRIX_COLS + j]) { + --debounce_matrix[row * MATRIX_COLS + j]; + } else { + result |= (1 << j); + } + } + return result; +} + +// Report changed keys in the given row. Resets the debounce countdowns +// corresponding to each set bit in 'change' to DEBOUNCE. +void debounce_report(matrix_row_t change, uint8_t row) { + for (uint8_t i = 0; i < MATRIX_COLS; ++i) { + if (change & (1 << i)) { + debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE; + } + } +} + +uint8_t matrix_scan(void) +{ + expander_scan(); + +#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_print(); + + matrix_timer = timer_now; + matrix_scan_count = 0; + } +#endif + + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + select_row(i); + wait_us(30); // without this wait read unstable value. + matrix_row_t mask = debounce_mask(i); + matrix_row_t cols = (read_cols(i) & mask) | (matrix[i] & ~mask); + debounce_report(cols ^ matrix[i], i); + matrix[i] = cols; + + unselect_rows(); + } + + matrix_scan_quantum(); + + return 1; +} + +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 + * + * Pro Micro: 6 5 4 3 2 1 0 + * PD3 PD2 PD4 PC6 PD7 PE6 PB4 + * + * Expander: 13 12 11 10 9 8 7 + */ +static void init_cols(void) +{ + // Pro Micro + DDRE &= ~(1<<PE6); + PORTE |= (1<<PE6); + DDRD &= ~(1<<PD2 | 1<<PD3 | 1<<PD4 | 1<<PD7); + PORTD |= (1<<PD2 | 1<<PD3 | 1<<PD4 | 1<<PD7); + DDRC &= ~(1<<PC6); + PORTC |= (1<<PC6); + DDRB &= ~(1<<PB4); + PORTB |= (1<<PB4); + + // MCP23017 + expander_init(); +} + +static matrix_row_t read_cols(uint8_t row) +{ + return expander_read_row() | + (PIND&(1<<PD3) ? 0 : (1<<6)) | + (PIND&(1<<PD2) ? 0 : (1<<5)) | + (PIND&(1<<PD4) ? 0 : (1<<4)) | + (PINC&(1<<PC6) ? 0 : (1<<3)) | + (PIND&(1<<PD7) ? 0 : (1<<2)) | + (PINE&(1<<PE6) ? 0 : (1<<1)) | + (PINB&(1<<PB4) ? 0 : (1<<0)) ; +} + +/* Row pin configuration + * + * Pro Micro: 0 1 2 3 4 5 + * F4 F5 F6 F7 B1 B2 + * + * Expander: 0 1 2 3 4 5 + */ +static void unselect_rows(void) +{ + // Pro Micro + DDRF &= ~(1<<PF4 | 1<<PF5 | 1<<PF6 | 1<<PF7); + PORTF &= ~(1<<PF4 | 1<<PF5 | 1<<PF6 | 1<<PF7); + DDRB &= ~(1<<PB1 | 1<<PB2); + PORTB &= ~(1<<PB1 | 1<<PB2); + + // Expander + expander_unselect_rows(); +} + +static void select_row(uint8_t row) +{ + // Pro Micro + switch (row) { + case 0: + DDRF |= (1<<PF4); + PORTF &= ~(1<<PF4); + break; + case 1: + DDRF |= (1<<PF5); + PORTF &= ~(1<<PF5); + break; + case 2: + DDRF |= (1<<PF6); + PORTF &= ~(1<<PF6); + break; + case 3: + DDRF |= (1<<PF7); + PORTF &= ~(1<<PF7); + break; + case 4: + DDRB |= (1<<PB1); + PORTB &= ~(1<<PB1); + break; + case 5: + DDRB |= (1<<PB2); + PORTB &= ~(1<<PB2); + break; + } + + expander_select_row(row); +} + diff --git a/keyboards/ergodox/ergodone/rules.mk b/keyboards/ergodox/ergodone/rules.mk new file mode 100644 index 0000000000..e7fd4e0aba --- /dev/null +++ b/keyboards/ergodox/ergodone/rules.mk @@ -0,0 +1,91 @@ +#---------------------------------------------------------------------------- +# 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). +# +#---------------------------------------------------------------------------- + +# # project specific files +SRC = \ + twimaster.c \ + matrix.c \ + expander.c \ + +# MCU name +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 = no # Console for debug(+400) +COMMAND_ENABLE = no # Commands for debug and configuration +SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend +NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA +USB_6KRO_ENABLE = no # USB 6key Rollover +BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality +KEYMAP_IN_EEPROM_ENABLE = no # External keymap in eeprom +KEYMAP_SECTION_ENABLE = no # Fixed address keymap for keymap editor +SOFTPWM_LED_ENABLE = no # Enable SoftPWM to drive backlight +FADING_LED_ENABLE = no # Enable fading backlight +BREATHING_LED_ENABLE = no # Enable breathing backlight +LEDMAP_ENABLE = no # Enable LED mapping +LEDMAP_IN_EEPROM_ENABLE = no # Read LED mapping from eeprom +ONEHAND_ENABLE = no # Disable Onehand +RGBLIGHT_ENABLE = no +MIDI_ENABLE = no diff --git a/keyboards/ergodox/ergodone/twimaster.c b/keyboards/ergodox/ergodone/twimaster.c new file mode 100644 index 0000000000..f91c08e6e4 --- /dev/null +++ b/keyboards/ergodox/ergodone/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 */ |