Browse Source

kimera: Initial implement for Kimera v5

kimera
Kai Ryu 9 years ago
parent
commit
4ff4331e84

+ 2
- 1
keyboard/kimera/Makefile View File

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

+ 2
- 1
keyboard/kimera/Makefile.pjrc View File

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

keyboard/kimera/Makefile_3300 → keyboard/kimera/Makefile_8M View File

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

+ 7
- 7
keyboard/kimera/backlight.c View File

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

+ 1
- 1
keyboard/kimera/config.h View File

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

+ 178
- 0
keyboard/kimera/i2cmaster.h View File

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

+ 152
- 104
keyboard/kimera/kimera.c View File

@@ -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;
}
}
}

+ 75
- 158
keyboard/kimera/kimera.h View File

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

+ 6
- 5
keyboard/kimera/matrix.c View File

@@ -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)

+ 203
- 0
keyboard/kimera/twimaster.c View File

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