@@ -52,6 +52,7 @@ SRC = keymap_common.c \ | |||
matrix.c \ | |||
led.c \ | |||
backlight.c \ | |||
twimaster.c \ | |||
kimera.c | |||
ifdef KEYMAP | |||
@@ -117,7 +118,7 @@ OPT_DEFS += -DBOOTLOADER_SIZE=4096 | |||
ifdef VER | |||
OPT_DEFS += -DKIMERA_$(REV) | |||
else | |||
OPT_DEFS += -DKIMERA_V2 | |||
OPT_DEFS += -DKIMERA_V5 | |||
endif | |||
# Additional definitions from command line |
@@ -52,12 +52,13 @@ SRC = keymap_common.c \ | |||
matrix.c \ | |||
led.c \ | |||
backlight.c \ | |||
twimaster.c \ | |||
kimera.c | |||
ifdef KEYMAP | |||
SRC := keymap_$(KEYMAP).c $(SRC) | |||
else | |||
SRC := keymap_poker.c $(SRC) | |||
SRC := keymap_default.c $(SRC) | |||
endif | |||
CONFIG_H = config.h |
@@ -39,7 +39,7 @@ | |||
#---------------------------------------------------------------------------- | |||
# Target file name (without extension). | |||
TARGET = kimera_lufa_3300 | |||
TARGET = kimera_8m_lufa | |||
# Directory common source filess exist | |||
TOP_DIR = ../.. | |||
@@ -52,6 +52,7 @@ SRC = keymap_common.c \ | |||
matrix.c \ | |||
led.c \ | |||
backlight.c \ | |||
twimaster.c \ | |||
kimera.c | |||
ifdef KEYMAP |
@@ -33,14 +33,14 @@ static const uint8_t backlight_table[] PROGMEM = { | |||
}; | |||
/* Backlight pin configuration | |||
* BL: PB5 (D9) | |||
* LED4: PB6 (D10) OC1B | |||
*/ | |||
void backlight_enable(void) | |||
{ | |||
// Turn on PWM | |||
BL_DDR |= (1<<BL_BIT); | |||
LED4_DDR |= (1<<LED4_BIT); | |||
cli(); | |||
TCCR1A |= ((1<<WGM10) | (1<<COM1A1)); | |||
TCCR1A |= ((1<<WGM10) | (1<<COM1B1)); | |||
TCCR1B |= ((1<<CS11) | (1<<CS10)); | |||
sei(); | |||
} | |||
@@ -48,12 +48,12 @@ void backlight_enable(void) | |||
void backlight_disable(void) | |||
{ | |||
// Turn off PWM | |||
BL_DDR &= ~(1<<BL_BIT); | |||
LED4_DDR &= ~(1<<LED4_BIT); | |||
cli(); | |||
TCCR1A &= ~((1<<WGM10) | (1<<COM1A1)); | |||
TCCR1A &= ~((1<<WGM10) | (1<<COM1B1)); | |||
TCCR1B &= ~((1<<CS11) | (1<<CS10)); | |||
sei(); | |||
BL_OCR = 0; | |||
LED4_OCR = 0; | |||
} | |||
void backlight_set(uint8_t level) | |||
@@ -100,7 +100,7 @@ void breathing_led_set_raw(uint8_t raw) | |||
inline void backlight_set_raw(uint8_t raw) | |||
{ | |||
OCR1A = raw; | |||
LED4_OCR = raw; | |||
} | |||
#endif |
@@ -22,7 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
/* USB Device descriptor parameter */ | |||
#define VENDOR_ID 0x16c0 | |||
#define PRODUCT_ID 0x27db | |||
#define DEVICE_VER 0x0001 | |||
#define DEVICE_VER 0x0005 | |||
#define MANUFACTURER [email protected] | |||
#define PRODUCT Kimera | |||
#define DESCRIPTION t.m.k. keyboard firmware for Kimera |
@@ -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 <[email protected]> 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 [email protected] 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 |
@@ -20,88 +20,73 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include <stdbool.h> | |||
#include <avr/eeprom.h> | |||
#include <util/delay.h> | |||
#include "i2cmaster.h" | |||
#include "kimera.h" | |||
#include "debug.h" | |||
uint8_t mux_mapping[MUX_COUNT] = { | |||
MUX_FOR_ROW, MUX_FOR_COL, MUX_FOR_COL, MUX_FOR_COL | |||
}; | |||
uint8_t row_mapping[MATRIX_ROWS] = { | |||
uint8_t row_mapping[PX_COUNT] = { | |||
0, 1, 2, 3, 4, 5, 6, 7, | |||
UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, | |||
UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, | |||
UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED | |||
}; | |||
uint8_t col_mapping[MATRIX_COLS] = { | |||
uint8_t col_mapping[PX_COUNT] = { | |||
8, 9, 10, 11, 12, 13, 14, 15, | |||
16, 17, 18, 19, 20, 21, 22, 23, | |||
24, 25, 26, 27, 28, 29, 30, 31 | |||
24, 25, 26, 27, 28, 29, 30, 31, | |||
UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED, UNCONFIGURED | |||
}; | |||
uint8_t row_max_count = MUX_PORTS * 1; | |||
uint8_t col_max_count = MUX_PORTS * (MUX_COUNT - 1); | |||
uint16_t shift_out_cache = 0; | |||
uint8_t row_count = 8; | |||
uint8_t col_count = 24; | |||
uint8_t data[EXP_COUNT][EXP_PORT_COUNT]; | |||
void kimera_init(void) | |||
{ | |||
// read config | |||
write_matrix_mapping(); | |||
/* read config */ | |||
write_matrix_mapping(); /* debug */ | |||
if (read_matrix_mapping()) { | |||
write_matrix_mapping(); | |||
} | |||
// init shift out pins | |||
MOSI_DDR |= (1<<MOSI_BIT); | |||
SCK_DDR |= (1<<SCK_BIT); | |||
RCK_DDR |= (1<<RCK_BIT); | |||
RCK_PORT |= (1<<RCK_BIT); | |||
// init spi | |||
SPCR |= ((1<<SPE) | (1<<MSTR)); | |||
SPSR |= ((1<<SPI2X)); | |||
/* init i2c */ | |||
i2c_init(); | |||
/* init i/o expander */ | |||
expander_init(); | |||
} | |||
uint8_t read_matrix_mapping(void) | |||
{ | |||
uint8_t error = 0; | |||
uint8_t mux_config = 0; | |||
row_max_count = 0; | |||
col_max_count = 0; | |||
mux_config = eeprom_read_byte(EECONFIG_MUX_MAPPING); | |||
if (mux_config == 0 || (mux_config & (1<<7))) { | |||
error++; | |||
return error; | |||
} | |||
for (uint8_t mux = 0; mux < MUX_COUNT; mux++) { | |||
mux_mapping[mux] = mux_config & (1 << mux); | |||
if (mux_mapping[mux] == MUX_FOR_COL) { | |||
col_max_count += MUX_PORTS; | |||
/* read number of rows and cols */ | |||
row_count = eeprom_read_byte(EECONFIG_ROW_COUNT); | |||
col_count = eeprom_read_byte(EECONFIG_COL_COUNT); | |||
if (row_count == 0) error++; | |||
if (row_count == UNCONFIGURED) error++; | |||
if (col_count == 0) error++; | |||
if (col_count == UNCONFIGURED) error++; | |||
if (row_count + col_count > PX_COUNT) error++; | |||
/* read row mapping */ | |||
uint8_t *mapping = EECONFIG_ROW_COL_MAPPING; | |||
for (uint8_t i = 0; i < PX_COUNT; i++) { | |||
if (i < row_count) { | |||
row_mapping[i] = eeprom_read_byte(mapping++); | |||
if (row_mapping[i] >= PX_COUNT) error++; | |||
} | |||
else { | |||
row_max_count += MUX_PORTS; | |||
row_mapping[i] = UNCONFIGURED; | |||
} | |||
} | |||
if ((col_max_count == 0) || (row_max_count == 0)) { | |||
error++; | |||
} | |||
uint8_t *mapping = EECONFIG_ROW_COL_MAPPING; | |||
for (uint8_t row = 0; row < row_max_count; row++) { | |||
row_mapping[row] = eeprom_read_byte(mapping++); | |||
if (row_mapping[row] != UNCONFIGURED) { | |||
if (mux_mapping[PX_TO_MUX(row_mapping[row])] != MUX_FOR_ROW) { | |||
row_mapping[row] = UNCONFIGURED; | |||
error++; | |||
} | |||
/* read col mapping*/ | |||
for (uint8_t i = 0; i < PX_COUNT; i++) { | |||
if (i < col_count) { | |||
col_mapping[i] = eeprom_read_byte(mapping++); | |||
if (col_mapping[i] >= PX_COUNT) error++; | |||
} | |||
} | |||
for (uint8_t col = 0; col < col_max_count; col++) { | |||
col_mapping[col] = eeprom_read_byte(mapping++); | |||
if (col_mapping[col] != UNCONFIGURED) { | |||
if (mux_mapping[PX_TO_MUX(col_mapping[col])] != MUX_FOR_COL) { | |||
col_mapping[col] = UNCONFIGURED; | |||
error++; | |||
} | |||
else { | |||
col_mapping[i] = UNCONFIGURED; | |||
} | |||
} | |||
@@ -110,66 +95,36 @@ uint8_t read_matrix_mapping(void) | |||
void write_matrix_mapping(void) | |||
{ | |||
uint8_t mux_config = 0; | |||
row_max_count = 0; | |||
col_max_count = 0; | |||
for (uint8_t mux = 0; mux < MUX_COUNT; mux++) { | |||
mux_config |= (mux_mapping[mux] << mux); | |||
if (mux_mapping[mux] == MUX_FOR_COL) { | |||
col_max_count += MUX_PORTS; | |||
} | |||
else { | |||
row_max_count += MUX_PORTS; | |||
} | |||
} | |||
eeprom_write_byte(EECONFIG_MUX_MAPPING, mux_config); | |||
/* write number of rows and cols */ | |||
eeprom_write_byte(EECONFIG_ROW_COUNT, row_count); | |||
eeprom_write_byte(EECONFIG_COL_COUNT, col_count); | |||
/* write row mapping */ | |||
uint8_t *mapping = EECONFIG_ROW_COL_MAPPING; | |||
for (uint8_t row = 0; row < row_max_count; row++) { | |||
for (uint8_t row = 0; row < row_count; row++) { | |||
eeprom_write_byte(mapping++, row_mapping[row]); | |||
} | |||
for (uint8_t col = 0; col < col_max_count; col++) { | |||
/* write col mapping */ | |||
for (uint8_t col = 0; col < col_count; col++) { | |||
eeprom_write_byte(mapping++, col_mapping[col]); | |||
} | |||
} | |||
void shift_out_word(uint16_t data) | |||
matrix_row_t read_cols(void) | |||
{ | |||
SPDR = ((data>>8) & 0xFF); | |||
while (!(SPSR & (1<<SPIF))); | |||
SPDR = (data & 0xFF); | |||
while (!(SPSR & (1<<SPIF))); | |||
RCK_PORT &= ~(1<<RCK_BIT); | |||
RCK_PORT |= (1<<RCK_BIT); | |||
} | |||
init_data(0x00); | |||
void init_cols(void) | |||
{ | |||
// init mux io pins | |||
for (uint8_t mux = 0; mux < MUX_COUNT; mux++) { | |||
uint8_t bit = MUX_TO_ZX_BIT(mux); | |||
if (mux_mapping[mux] == MUX_FOR_COL) { | |||
ZX_DDR &= ~(1 << bit); | |||
ZX_PORT |= (1 << bit); | |||
} | |||
else { | |||
ZX_DDR |= (1 << bit); | |||
ZX_PORT |= (1 << bit); | |||
} | |||
/* read all input registers */ | |||
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) { | |||
expander_read_input(exp, data[exp]); | |||
} | |||
} | |||
matrix_row_t read_cols(void) | |||
{ | |||
/* make cols */ | |||
matrix_row_t cols = 0; | |||
for (uint8_t col = 0; col < col_max_count; col++) { | |||
for (uint8_t col = 0; col < col_count; col++) { | |||
uint8_t px = col_mapping[col]; | |||
if (px != UNCONFIGURED) { | |||
uint8_t mux = PX_TO_MUX(px); | |||
shift_out_word((shift_out_cache | PX_TO_SHIFT_OUT(px)) & ~(MUX_INH_TO_SHIFT_OUT(mux))); | |||
_delay_us(10); | |||
if (!(ZX_PIN & (1 << MUX_TO_ZX_BIT(mux)))) { | |||
if (data[PX_TO_EXP(px)][PX_TO_PORT(px)] & (1 << PX_TO_PIN(px))) { | |||
cols |= (1UL << col); | |||
} | |||
} | |||
@@ -179,16 +134,109 @@ matrix_row_t read_cols(void) | |||
void unselect_rows(void) | |||
{ | |||
shift_out_word(0); | |||
/* set all output registers to 0xFF */ | |||
init_data(0xFF); | |||
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) { | |||
expander_write_output(exp, data[exp]); | |||
} | |||
} | |||
void select_row(uint8_t row) | |||
{ | |||
/* set selected row to low */ | |||
init_data(0xFF); | |||
uint8_t px = row_mapping[row]; | |||
if (px != UNCONFIGURED) { | |||
uint8_t mux = PX_TO_MUX(px); | |||
ZX_PORT &= ~(1 << MUX_TO_ZX_BIT(mux)); | |||
shift_out_cache = ((MUX_OFF_TO_SHIFT_OUT | PX_TO_SHIFT_OUT(px)) & ~(MUX_INH_TO_SHIFT_OUT(mux))); | |||
shift_out_word(shift_out_cache); | |||
uint8_t exp = PX_TO_EXP(px); | |||
data[exp][PX_TO_PORT(px)] &= ~(1 << PX_TO_PIN(px)); | |||
expander_write_output(exp, data[exp]); | |||
} | |||
} | |||
void expander_init(void) | |||
{ | |||
init_data(0xFF); | |||
/* write inversion register */ | |||
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) { | |||
expander_write_inversion(exp, data[exp]); | |||
} | |||
/* set output bit */ | |||
for (uint8_t row = 0; row < row_count; row++) { | |||
uint8_t px = row_mapping[row]; | |||
if (px != UNCONFIGURED) { | |||
data[PX_TO_EXP(px)][PX_TO_PORT(px)] &= ~(1 << PX_TO_PIN(px)); | |||
} | |||
} | |||
/* write config registers */ | |||
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) { | |||
expander_write_config(exp, data[exp]); | |||
} | |||
} | |||
uint8_t expander_write(uint8_t exp, uint8_t command, uint8_t *data) | |||
{ | |||
uint8_t addr = EXP_ADDR(exp); | |||
uint8_t ret; | |||
ret = i2c_start(addr | I2C_WRITE); | |||
if (ret) goto stop; | |||
ret = i2c_write(command); | |||
if (ret) goto stop; | |||
ret = i2c_write(*data++); | |||
if (ret) goto stop; | |||
ret = i2c_write(*data); | |||
stop: | |||
i2c_stop(); | |||
return ret; | |||
} | |||
uint8_t expander_read(uint8_t exp, uint8_t command, uint8_t *data) | |||
{ | |||
uint8_t addr = EXP_ADDR(exp); | |||
uint8_t ret; | |||
ret = i2c_start(addr | I2C_WRITE); | |||
if (ret) goto stop; | |||
ret = i2c_write(command); | |||
if (ret) goto stop; | |||
ret = i2c_start(addr | I2C_READ); | |||
if (ret) goto stop; | |||
*data++ = i2c_readAck(); | |||
*data = i2c_readNak(); | |||
stop: | |||
i2c_stop(); | |||
return ret; | |||
} | |||
inline | |||
uint8_t expander_write_output(uint8_t exp, uint8_t *data) | |||
{ | |||
return expander_write(exp, EXP_COMM_OUTPUT_0, data); | |||
} | |||
inline | |||
uint8_t expander_write_inversion(uint8_t exp, uint8_t *data) | |||
{ | |||
return expander_write(exp, EXP_COMM_INVERSION_0, data); | |||
} | |||
inline | |||
uint8_t expander_write_config(uint8_t exp, uint8_t *data) | |||
{ | |||
return expander_write(exp, EXP_COMM_CONFIG_0, data); | |||
} | |||
inline | |||
uint8_t expander_read_input(uint8_t exp, uint8_t *data) | |||
{ | |||
return expander_read(exp, EXP_COMM_INPUT_0, data); | |||
} | |||
void init_data(uint8_t value) | |||
{ | |||
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) { | |||
for (uint8_t port = 0; port < EXP_PORT_COUNT; port++) { | |||
data[exp][port] = value; | |||
} | |||
} | |||
} |
@@ -23,189 +23,99 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include "matrix.h" | |||
/* | |||
Pro Micro | |||
U1 (Pro Micro) | |||
,----------------. | |||
TX --| TX0(PD3) RAW |-- | |||
RX --| RX1(PD2) GND |-- | |||
--| GND RESET |-- RST | |||
--| GND VCC |-- | |||
SDA --| 2(PD1) (PF4)A3 |-- (Z4) | |||
SCL --| 3(PD0) (PF5)A2 |-- (Z1) | |||
(RCK) --| 4(PD4) (PF6)A1 |-- (Z2) | |||
LED1 --| 5(PC6) (PF7)A0 |-- (Z3) | |||
LED2 --| 6(PD7) (PB1)15 |-- SCK | |||
(SJ1) --| 7(PE6) (PB3)14 |-- MISO | |||
(SJ2) --| 8(PB4) (PB2)16 |-- MOSI | |||
BL --| 9(PB5) (PB6)10 |-- LED3 | |||
SDA --| 2(PD1) (PF4)A3 |-- | |||
SCL --| 3(PD0) (PF5)A2 |-- | |||
(INT) --| 4(PD4) (PF6)A1 |-- | |||
--| 5(PC6) (PF7)A0 |-- | |||
--| 6(PD7) (PB1)15 |-- SCK | |||
LED2 --| 7(PE6) (PB3)14 |-- MISO | |||
LED1 --| 8(PB4) (PB2)16 |-- MOSI | |||
LED3 --| 9(PB5) (PB6)10 |-- LED4 | |||
`----------------' | |||
*/ | |||
#define LED1_PORT PORTC | |||
#define LED1_PIN PINC | |||
#define LED1_DDR DDRC | |||
#define LED1_BIT PC6 | |||
#define LED1_PORT PORTB | |||
#define LED1_PIN PINB | |||
#define LED1_DDR DDRB | |||
#define LED1_BIT PB4 | |||
#define LED2_PORT PORTD | |||
#define LED2_PIN PIND | |||
#define LED2_DDR DDRD | |||
#define LED2_BIT PD7 | |||
#define LED2_PORT PORTE | |||
#define LED2_PIN PINE | |||
#define LED2_DDR DDRE | |||
#define LED2_BIT PE6 | |||
#define LED3_PORT PORTB | |||
#define LED3_PIN PINB | |||
#define LED3_DDR DDRB | |||
#define LED3_BIT PB6 | |||
#define BL_PORT PORTB | |||
#define BL_PIN PINB | |||
#define BL_DDR DDRB | |||
#define BL_BIT PB5 | |||
#define BL_OCR OCR1A | |||
#define RCK_PORT PORTD | |||
#define RCK_PIN PIND | |||
#define RCK_DDR DDRD | |||
#define RCK_BIT PD4 | |||
#define SCK_PORT PORTB | |||
#define SCK_PIN PINB | |||
#define SCK_DDR DDRB | |||
#define SCK_BIT PB1 | |||
#define MOSI_PORT PORTB | |||
#define MOSI_PIN PINB | |||
#define MOSI_DDR DDRB | |||
#define MOSI_BIT PB2 | |||
#define MISO_PORT PORTB | |||
#define MISO_PIN PINB | |||
#define MISO_DDR DDRB | |||
#define MISO_BIT PB3 | |||
#define ZX_PORT PORTF | |||
#define ZX_PIN PINF | |||
#define ZX_DDR DDRF | |||
#ifdef KIMERA_C | |||
const uint8_t PROGMEM zx_bit[] = { | |||
PF5, PF6, PF7, PF4 | |||
}; | |||
#endif | |||
#define MUX_TO_ZX_BIT(x) (pgm_read_byte(zx_bit + (x))) | |||
#define LED3_BIT PB5 | |||
/* | |||
#define LED4_PORT PORTB | |||
#define LED4_PIN PINB | |||
#define LED4_DDR DDRB | |||
#define LED4_BIT PB6 | |||
#define LED4_OCR OCR1B | |||
Shift Register Multiplexer | |||
,----------. ,------------. | |||
MOSI --| SER 0 |----| INH X0~X7 |===============. | |||
SCK --|>SCK 1 |----| C | | | |||
RCK --|>RCK 2 |----| B | ,-------------+-------------. | |||
| 3 |----| A | | | | | | | | | | |||
| | `------------' P26 P27 P28 P25 P29 P32 P30 P31 | |||
| | ,------------. | |||
| 4 |----| C X0~X7 |===============. | |||
| 5 |----| B | | | |||
| 6 |----| A | ,-------------+-------------. | |||
| 7 |----| INH | | | | | | | | | | |||
| | `------------' P2 P3 P4 P1 P5 P8 P6 P7 | |||
| | ,------------. | |||
| 8 |----| INH X0~X7 |===============. | |||
| 9 |----| C | | | |||
| 10 |----| B | ,-------------+-------------. | |||
| 11 |----| A | | | | | | | | | | |||
| | `------------' P10 P11 P12 P9 P13 P16 P14 P15 | |||
| | ,------------. | |||
| 12 |----| C X0~X7 |===============. | |||
| 13 |----| B | | | |||
| 14 |----| A | ,-------------+-------------. | |||
| 15 |----| INH | | | | | | | | | | |||
`----------' `------------' P18 P19 P20 P17 P21 P24 P22 P23 | |||
/* | |||
IC1 (PCA9555) IC2 (PCA9555) | |||
,----------. ,----------. | |||
SDA --| SDA P00 |-- P1 SDA --| SDA P00 |-- P9 | |||
SCL --| SCL P01 |-- P2 SCL --| SCL P01 |-- P10 | |||
INT --| INT P02 |-- P3 INT --| INT P02 |-- P11 | |||
| P03 |-- P4 | P03 |-- P12 | |||
GND --| A0 P04 |-- P5 VCC --| A0 P04 |-- P13 | |||
SJ1 --| A1 P05 |-- P6 SJ1 --| A1 P05 |-- P14 | |||
SJ2 --| A2 P06 |-- P7 SJ2 --| A2 P06 |-- P15 | |||
| P07 |-- P8 | P07 |-- P16 | |||
| | | | | |||
| P10 |-- P25 | P10 |-- P17 | |||
| P11 |-- P26 | P11 |-- P18 | |||
| P12 |-- P27 | P12 |-- P19 | |||
| P13 |-- P28 | P13 |-- P20 | |||
| P14 |-- P29 | P14 |-- P21 | |||
| P15 |-- P30 | P15 |-- P22 | |||
| P16 |-- P31 | P16 |-- P23 | |||
| P17 |-- P32 | P17 |-- P24 | |||
`----------' `----------' | |||
*/ | |||
#define MUX_COUNT 4 | |||
#define MUX_PORTS 8 | |||
#define PX_TO_MUX(x) (x>>3) // (x / MUX_PORTS) | |||
#if defined(KIMERA_V1) | |||
enum { | |||
MUX4_INH = 0, | |||
MUX4_A, | |||
MUX4_B, | |||
MUX4_C, | |||
MUX1_A, | |||
MUX1_B, | |||
MUX1_C, | |||
MUX1_INH, | |||
MUX2_INH, | |||
MUX2_A, | |||
MUX2_B, | |||
MUX2_C, | |||
MUX3_A, | |||
MUX3_B, | |||
MUX3_C, | |||
MUX3_INH | |||
}; | |||
#elif defined(KIMERA_V2) | |||
#define EXP_COUNT 2 | |||
#define EXP_ADDR(n) ((0x20+(n))<<1) | |||
#define EXP_OUTPUT 0 | |||
#define EXP_INPUT 1 | |||
#define EXP_PORT_COUNT 2 | |||
#define EXP_PIN_PER_PORT 8 | |||
enum { | |||
MUX4_INH = 0, | |||
MUX4_C, | |||
MUX4_B, | |||
MUX4_A, | |||
MUX1_C, | |||
MUX1_B, | |||
MUX1_A, | |||
MUX1_INH, | |||
MUX2_INH, | |||
MUX2_C, | |||
MUX2_B, | |||
MUX2_A, | |||
MUX3_C, | |||
MUX3_B, | |||
MUX3_A, | |||
MUX3_INH | |||
EXP_COMM_INPUT_0 = 0, | |||
EXP_COMM_INPUT_1, | |||
EXP_COMM_OUTPUT_0, | |||
EXP_COMM_OUTPUT_1, | |||
EXP_COMM_INVERSION_0, | |||
EXP_COMM_INVERSION_1, | |||
EXP_COMM_CONFIG_0, | |||
EXP_COMM_CONFIG_1 | |||
}; | |||
#endif | |||
#define PX_TO_EXP(x) (((x)>>5<<1)+((((x)>>3)&1)^(((x)>>4)&1))) | |||
#define PX_TO_PORT(x) (((x)>>4)&1) | |||
#define PX_TO_PIN(x) ((x)&7) | |||
#define PX_COUNT (EXP_PIN_PER_PORT * EXP_PORT_COUNT * EXP_COUNT) | |||
#ifdef KIMERA_C | |||
#if defined(KIMERA_V1) | |||
const uint16_t PROGMEM px_to_shift_out[] = { | |||
3<<MUX1_A, 0<<MUX1_A, 1<<MUX1_A, 2<<MUX1_A, 4<<MUX1_A, 6<<MUX1_A, 7<<MUX1_A, 5<<MUX1_A, | |||
3<<MUX2_A, 0<<MUX2_A, 1<<MUX2_A, 2<<MUX2_A, 4<<MUX2_A, 6<<MUX2_A, 7<<MUX2_A, 5<<MUX2_A, | |||
3<<MUX3_A, 0<<MUX3_A, 1<<MUX3_A, 2<<MUX3_A, 4<<MUX3_A, 6<<MUX3_A, 7<<MUX3_A, 5<<MUX3_A, | |||
3<<MUX4_A, 0<<MUX4_A, 1<<MUX4_A, 2<<MUX4_A, 4<<MUX4_A, 6<<MUX4_A, 7<<MUX4_A, 5<<MUX4_A | |||
}; | |||
#elif defined(KIMERA_V2) | |||
#define R(x) (((x&1)?4:0)|((x&2)?2:0)|((x&4)?1:0)) | |||
const uint16_t PROGMEM px_to_shift_out[] = { | |||
R(3)<<MUX1_C, R(0)<<MUX1_C, R(1)<<MUX1_C, R(2)<<MUX1_C, R(4)<<MUX1_C, R(6)<<MUX1_C, R(7)<<MUX1_C, R(5)<<MUX1_C, | |||
R(3)<<MUX2_C, R(0)<<MUX2_C, R(1)<<MUX2_C, R(2)<<MUX2_C, R(4)<<MUX2_C, R(6)<<MUX2_C, R(7)<<MUX2_C, R(5)<<MUX2_C, | |||
R(3)<<MUX3_C, R(0)<<MUX3_C, R(1)<<MUX3_C, R(2)<<MUX3_C, R(4)<<MUX3_C, R(6)<<MUX3_C, R(7)<<MUX3_C, R(5)<<MUX3_C, | |||
R(3)<<MUX4_C, R(0)<<MUX4_C, R(1)<<MUX4_C, R(2)<<MUX4_C, R(4)<<MUX4_C, R(6)<<MUX4_C, R(7)<<MUX4_C, R(5)<<MUX4_C | |||
const uint16_t PROGMEM dummy[] = { | |||
}; | |||
#endif | |||
const uint16_t PROGMEM mux_inh_to_shift_out[] = { | |||
1<<MUX1_INH, 1<<MUX2_INH, 1<<MUX3_INH, 1<<MUX4_INH | |||
}; | |||
#endif | |||
#define PX_TO_SHIFT_OUT(x) (pgm_read_word(px_to_shift_out + (x))) | |||
#define MUX_INH_TO_SHIFT_OUT(x) (pgm_read_word(mux_inh_to_shift_out + (x))) | |||
#define MUX_OFF_TO_SHIFT_OUT (1<<MUX1_INH | 1<<MUX2_INH | 1<<MUX3_INH | 1<<MUX4_INH) | |||
/* Matrix Mapping in EEPROM */ | |||
#define EECONFIG_MUX_MAPPING (uint8_t *)7 | |||
#define EECONFIG_ROW_COL_MAPPING (uint8_t *)8 | |||
#define MATRIX_MAPPING_SIZE MUX_COUNT * MUX_PORTS | |||
typedef struct { | |||
uint8_t mux_mapping; | |||
uint8_t row_col_mapping; | |||
} matrix_mapping_t; | |||
#define MUX_INPUT 0 | |||
#define MUX_OUTPUT 1 | |||
#define MUX_FOR_COL MUX_INPUT | |||
#define MUX_FOR_ROW MUX_OUTPUT | |||
#define UNCONFIGURED 0xFF | |||
#define EECONFIG_ROW_COUNT (uint8_t *)7 | |||
#define EECONFIG_COL_COUNT (uint8_t *)8 | |||
#define EECONFIG_ROW_COL_MAPPING (uint8_t *)9 | |||
#define UNCONFIGURED 0xFF | |||
/* Functions */ | |||
@@ -214,8 +124,15 @@ uint8_t read_matrix_mapping(void); | |||
void write_matrix_mapping(void); | |||
void shift_out_word(uint16_t word); | |||
matrix_row_t read_cols(void); | |||
void init_cols(void); | |||
void unselect_rows(void); | |||
void select_row(uint8_t row); | |||
void expander_init(void); | |||
uint8_t expander_write(uint8_t exp, uint8_t command, uint8_t *data); | |||
uint8_t expander_read(uint8_t exp, uint8_t command, uint8_t *data); | |||
uint8_t expander_write_output(uint8_t exp, uint8_t *data); | |||
uint8_t expander_write_inversion(uint8_t exp, uint8_t *data); | |||
uint8_t expander_write_config(uint8_t exp, uint8_t *data); | |||
uint8_t expander_read_input(uint8_t exp, uint8_t *data); | |||
void init_data(uint8_t value); | |||
#endif |
@@ -38,19 +38,20 @@ static uint8_t debouncing = DEBOUNCE; | |||
static matrix_row_t matrix[MATRIX_ROWS]; | |||
static matrix_row_t matrix_debouncing[MATRIX_ROWS]; | |||
extern uint8_t row_max_count; | |||
extern uint8_t col_max_count; | |||
extern uint8_t row_count; | |||
extern uint8_t col_count; | |||
extern uint8_t data[EXP_COUNT][EXP_PORT_COUNT]; | |||
inline | |||
uint8_t matrix_rows(void) | |||
{ | |||
return row_max_count; | |||
return row_count; | |||
} | |||
inline | |||
uint8_t matrix_cols(void) | |||
{ | |||
return col_max_count; | |||
return col_count; | |||
} | |||
void matrix_init(void) | |||
@@ -63,13 +64,13 @@ void matrix_init(void) | |||
// initialize row and col | |||
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; | |||
} | |||
} | |||
uint8_t matrix_scan(void) |
@@ -0,0 +1,203 @@ | |||
/************************************************************************* | |||
* Title: I2C master library using hardware TWI interface | |||
* Author: Peter Fleury <[email protected]> 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> | |||
#include "debug.h" | |||
/* define CPU frequency in Mhz here if not defined in Makefile */ | |||
#ifndef F_CPU | |||
#define F_CPU 4000000UL | |||
#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: 100 kHz clock, TWPS = 0 => prescaler = 1 */ | |||
TWSR = 0; /* no prescaler */ | |||
TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* 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 */ |