@ -0,0 +1,3 @@ | |||
ifndef MAKEFILE_INCLUDED | |||
include ../../../Makefile | |||
endif |
@ -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 |
@ -0,0 +1,5 @@ | |||
#include "ergodone.h" | |||
void matrix_init_kb(void) { | |||
matrix_init_user(); | |||
} |
@ -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 |
@ -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; | |||
} |
@ -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 |
@ -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,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); | |||
} | |||
@ -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 |
@ -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 */ |