kimera: Initial implement for Kimera v5
This commit is contained in:
parent
754b3e47ea
commit
4ff4331e84
@ -52,6 +52,7 @@ SRC = keymap_common.c \
|
|||||||
matrix.c \
|
matrix.c \
|
||||||
led.c \
|
led.c \
|
||||||
backlight.c \
|
backlight.c \
|
||||||
|
twimaster.c \
|
||||||
kimera.c
|
kimera.c
|
||||||
|
|
||||||
ifdef KEYMAP
|
ifdef KEYMAP
|
||||||
@ -117,7 +118,7 @@ OPT_DEFS += -DBOOTLOADER_SIZE=4096
|
|||||||
ifdef VER
|
ifdef VER
|
||||||
OPT_DEFS += -DKIMERA_$(REV)
|
OPT_DEFS += -DKIMERA_$(REV)
|
||||||
else
|
else
|
||||||
OPT_DEFS += -DKIMERA_V2
|
OPT_DEFS += -DKIMERA_V5
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Additional definitions from command line
|
# Additional definitions from command line
|
||||||
|
@ -52,12 +52,13 @@ SRC = keymap_common.c \
|
|||||||
matrix.c \
|
matrix.c \
|
||||||
led.c \
|
led.c \
|
||||||
backlight.c \
|
backlight.c \
|
||||||
|
twimaster.c \
|
||||||
kimera.c
|
kimera.c
|
||||||
|
|
||||||
ifdef KEYMAP
|
ifdef KEYMAP
|
||||||
SRC := keymap_$(KEYMAP).c $(SRC)
|
SRC := keymap_$(KEYMAP).c $(SRC)
|
||||||
else
|
else
|
||||||
SRC := keymap_poker.c $(SRC)
|
SRC := keymap_default.c $(SRC)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CONFIG_H = config.h
|
CONFIG_H = config.h
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
#----------------------------------------------------------------------------
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
# Target file name (without extension).
|
# Target file name (without extension).
|
||||||
TARGET = kimera_lufa_3300
|
TARGET = kimera_8m_lufa
|
||||||
|
|
||||||
# Directory common source filess exist
|
# Directory common source filess exist
|
||||||
TOP_DIR = ../..
|
TOP_DIR = ../..
|
||||||
@ -52,6 +52,7 @@ SRC = keymap_common.c \
|
|||||||
matrix.c \
|
matrix.c \
|
||||||
led.c \
|
led.c \
|
||||||
backlight.c \
|
backlight.c \
|
||||||
|
twimaster.c \
|
||||||
kimera.c
|
kimera.c
|
||||||
|
|
||||||
ifdef KEYMAP
|
ifdef KEYMAP
|
@ -33,14 +33,14 @@ static const uint8_t backlight_table[] PROGMEM = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Backlight pin configuration
|
/* Backlight pin configuration
|
||||||
* BL: PB5 (D9)
|
* LED4: PB6 (D10) OC1B
|
||||||
*/
|
*/
|
||||||
void backlight_enable(void)
|
void backlight_enable(void)
|
||||||
{
|
{
|
||||||
// Turn on PWM
|
// Turn on PWM
|
||||||
BL_DDR |= (1<<BL_BIT);
|
LED4_DDR |= (1<<LED4_BIT);
|
||||||
cli();
|
cli();
|
||||||
TCCR1A |= ((1<<WGM10) | (1<<COM1A1));
|
TCCR1A |= ((1<<WGM10) | (1<<COM1B1));
|
||||||
TCCR1B |= ((1<<CS11) | (1<<CS10));
|
TCCR1B |= ((1<<CS11) | (1<<CS10));
|
||||||
sei();
|
sei();
|
||||||
}
|
}
|
||||||
@ -48,12 +48,12 @@ void backlight_enable(void)
|
|||||||
void backlight_disable(void)
|
void backlight_disable(void)
|
||||||
{
|
{
|
||||||
// Turn off PWM
|
// Turn off PWM
|
||||||
BL_DDR &= ~(1<<BL_BIT);
|
LED4_DDR &= ~(1<<LED4_BIT);
|
||||||
cli();
|
cli();
|
||||||
TCCR1A &= ~((1<<WGM10) | (1<<COM1A1));
|
TCCR1A &= ~((1<<WGM10) | (1<<COM1B1));
|
||||||
TCCR1B &= ~((1<<CS11) | (1<<CS10));
|
TCCR1B &= ~((1<<CS11) | (1<<CS10));
|
||||||
sei();
|
sei();
|
||||||
BL_OCR = 0;
|
LED4_OCR = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void backlight_set(uint8_t level)
|
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)
|
inline void backlight_set_raw(uint8_t raw)
|
||||||
{
|
{
|
||||||
OCR1A = raw;
|
LED4_OCR = raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,7 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
/* USB Device descriptor parameter */
|
/* USB Device descriptor parameter */
|
||||||
#define VENDOR_ID 0x16c0
|
#define VENDOR_ID 0x16c0
|
||||||
#define PRODUCT_ID 0x27db
|
#define PRODUCT_ID 0x27db
|
||||||
#define DEVICE_VER 0x0001
|
#define DEVICE_VER 0x0005
|
||||||
#define MANUFACTURER kai1103@gmail.com
|
#define MANUFACTURER kai1103@gmail.com
|
||||||
#define PRODUCT Kimera
|
#define PRODUCT Kimera
|
||||||
#define DESCRIPTION t.m.k. keyboard firmware for Kimera
|
#define DESCRIPTION t.m.k. keyboard firmware for Kimera
|
||||||
|
178
keyboard/kimera/i2cmaster.h
Normal file
178
keyboard/kimera/i2cmaster.h
Normal 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 <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
|
@ -20,88 +20,73 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <avr/eeprom.h>
|
#include <avr/eeprom.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
#include "i2cmaster.h"
|
||||||
#include "kimera.h"
|
#include "kimera.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
uint8_t mux_mapping[MUX_COUNT] = {
|
uint8_t row_mapping[PX_COUNT] = {
|
||||||
MUX_FOR_ROW, MUX_FOR_COL, MUX_FOR_COL, MUX_FOR_COL
|
|
||||||
};
|
|
||||||
uint8_t row_mapping[MATRIX_ROWS] = {
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7,
|
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,
|
||||||
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,
|
8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
16, 17, 18, 19, 20, 21, 22, 23,
|
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 row_count = 8;
|
||||||
uint8_t col_max_count = MUX_PORTS * (MUX_COUNT - 1);
|
uint8_t col_count = 24;
|
||||||
uint16_t shift_out_cache = 0;
|
uint8_t data[EXP_COUNT][EXP_PORT_COUNT];
|
||||||
|
|
||||||
void kimera_init(void)
|
void kimera_init(void)
|
||||||
{
|
{
|
||||||
// read config
|
/* read config */
|
||||||
write_matrix_mapping();
|
write_matrix_mapping(); /* debug */
|
||||||
if (read_matrix_mapping()) {
|
if (read_matrix_mapping()) {
|
||||||
write_matrix_mapping();
|
write_matrix_mapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
// init shift out pins
|
/* init i2c */
|
||||||
MOSI_DDR |= (1<<MOSI_BIT);
|
i2c_init();
|
||||||
SCK_DDR |= (1<<SCK_BIT);
|
|
||||||
RCK_DDR |= (1<<RCK_BIT);
|
|
||||||
RCK_PORT |= (1<<RCK_BIT);
|
|
||||||
|
|
||||||
// init spi
|
/* init i/o expander */
|
||||||
SPCR |= ((1<<SPE) | (1<<MSTR));
|
expander_init();
|
||||||
SPSR |= ((1<<SPI2X));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t read_matrix_mapping(void)
|
uint8_t read_matrix_mapping(void)
|
||||||
{
|
{
|
||||||
uint8_t error = 0;
|
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);
|
/* read number of rows and cols */
|
||||||
if (mux_config == 0 || (mux_config & (1<<7))) {
|
row_count = eeprom_read_byte(EECONFIG_ROW_COUNT);
|
||||||
error++;
|
col_count = eeprom_read_byte(EECONFIG_COL_COUNT);
|
||||||
return error;
|
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++;
|
||||||
|
|
||||||
for (uint8_t mux = 0; mux < MUX_COUNT; mux++) {
|
/* read row mapping */
|
||||||
mux_mapping[mux] = mux_config & (1 << mux);
|
uint8_t *mapping = EECONFIG_ROW_COL_MAPPING;
|
||||||
if (mux_mapping[mux] == MUX_FOR_COL) {
|
for (uint8_t i = 0; i < PX_COUNT; i++) {
|
||||||
col_max_count += MUX_PORTS;
|
if (i < row_count) {
|
||||||
|
row_mapping[i] = eeprom_read_byte(mapping++);
|
||||||
|
if (row_mapping[i] >= PX_COUNT) error++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
row_max_count += MUX_PORTS;
|
row_mapping[i] = UNCONFIGURED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((col_max_count == 0) || (row_max_count == 0)) {
|
/* read col mapping*/
|
||||||
error++;
|
for (uint8_t i = 0; i < PX_COUNT; i++) {
|
||||||
}
|
if (i < col_count) {
|
||||||
|
col_mapping[i] = eeprom_read_byte(mapping++);
|
||||||
uint8_t *mapping = EECONFIG_ROW_COL_MAPPING;
|
if (col_mapping[i] >= PX_COUNT) error++;
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
void write_matrix_mapping(void)
|
||||||
{
|
{
|
||||||
uint8_t mux_config = 0;
|
/* write number of rows and cols */
|
||||||
row_max_count = 0;
|
eeprom_write_byte(EECONFIG_ROW_COUNT, row_count);
|
||||||
col_max_count = 0;
|
eeprom_write_byte(EECONFIG_COL_COUNT, col_count);
|
||||||
|
|
||||||
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 row mapping */
|
||||||
uint8_t *mapping = EECONFIG_ROW_COL_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]);
|
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]);
|
eeprom_write_byte(mapping++, col_mapping[col]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shift_out_word(uint16_t data)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
matrix_row_t read_cols(void)
|
matrix_row_t read_cols(void)
|
||||||
{
|
{
|
||||||
|
init_data(0x00);
|
||||||
|
|
||||||
|
/* read all input registers */
|
||||||
|
for (uint8_t exp = 0; exp < EXP_COUNT; exp++) {
|
||||||
|
expander_read_input(exp, data[exp]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make cols */
|
||||||
matrix_row_t cols = 0;
|
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];
|
uint8_t px = col_mapping[col];
|
||||||
if (px != UNCONFIGURED) {
|
if (px != UNCONFIGURED) {
|
||||||
uint8_t mux = PX_TO_MUX(px);
|
if (data[PX_TO_EXP(px)][PX_TO_PORT(px)] & (1 << PX_TO_PIN(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)))) {
|
|
||||||
cols |= (1UL << col);
|
cols |= (1UL << col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,16 +134,109 @@ matrix_row_t read_cols(void)
|
|||||||
|
|
||||||
void unselect_rows(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)
|
void select_row(uint8_t row)
|
||||||
{
|
{
|
||||||
|
/* set selected row to low */
|
||||||
|
init_data(0xFF);
|
||||||
uint8_t px = row_mapping[row];
|
uint8_t px = row_mapping[row];
|
||||||
if (px != UNCONFIGURED) {
|
if (px != UNCONFIGURED) {
|
||||||
uint8_t mux = PX_TO_MUX(px);
|
uint8_t exp = PX_TO_EXP(px);
|
||||||
ZX_PORT &= ~(1 << MUX_TO_ZX_BIT(mux));
|
data[exp][PX_TO_PORT(px)] &= ~(1 << PX_TO_PIN(px));
|
||||||
shift_out_cache = ((MUX_OFF_TO_SHIFT_OUT | PX_TO_SHIFT_OUT(px)) & ~(MUX_INH_TO_SHIFT_OUT(mux)));
|
expander_write_output(exp, data[exp]);
|
||||||
shift_out_word(shift_out_cache);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,188 +23,98 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Pro Micro
|
U1 (Pro Micro)
|
||||||
,----------------.
|
,----------------.
|
||||||
TX --| TX0(PD3) RAW |--
|
TX --| TX0(PD3) RAW |--
|
||||||
RX --| RX1(PD2) GND |--
|
RX --| RX1(PD2) GND |--
|
||||||
--| GND RESET |-- RST
|
--| GND RESET |-- RST
|
||||||
--| GND VCC |--
|
--| GND VCC |--
|
||||||
SDA --| 2(PD1) (PF4)A3 |-- (Z4)
|
SDA --| 2(PD1) (PF4)A3 |--
|
||||||
SCL --| 3(PD0) (PF5)A2 |-- (Z1)
|
SCL --| 3(PD0) (PF5)A2 |--
|
||||||
(RCK) --| 4(PD4) (PF6)A1 |-- (Z2)
|
(INT) --| 4(PD4) (PF6)A1 |--
|
||||||
LED1 --| 5(PC6) (PF7)A0 |-- (Z3)
|
--| 5(PC6) (PF7)A0 |--
|
||||||
LED2 --| 6(PD7) (PB1)15 |-- SCK
|
--| 6(PD7) (PB1)15 |-- SCK
|
||||||
(SJ1) --| 7(PE6) (PB3)14 |-- MISO
|
LED2 --| 7(PE6) (PB3)14 |-- MISO
|
||||||
(SJ2) --| 8(PB4) (PB2)16 |-- MOSI
|
LED1 --| 8(PB4) (PB2)16 |-- MOSI
|
||||||
BL --| 9(PB5) (PB6)10 |-- LED3
|
LED3 --| 9(PB5) (PB6)10 |-- LED4
|
||||||
`----------------'
|
`----------------'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LED1_PORT PORTC
|
#define LED1_PORT PORTB
|
||||||
#define LED1_PIN PINC
|
#define LED1_PIN PINB
|
||||||
#define LED1_DDR DDRC
|
#define LED1_DDR DDRB
|
||||||
#define LED1_BIT PC6
|
#define LED1_BIT PB4
|
||||||
|
|
||||||
#define LED2_PORT PORTD
|
#define LED2_PORT PORTE
|
||||||
#define LED2_PIN PIND
|
#define LED2_PIN PINE
|
||||||
#define LED2_DDR DDRD
|
#define LED2_DDR DDRE
|
||||||
#define LED2_BIT PD7
|
#define LED2_BIT PE6
|
||||||
|
|
||||||
#define LED3_PORT PORTB
|
#define LED3_PORT PORTB
|
||||||
#define LED3_PIN PINB
|
#define LED3_PIN PINB
|
||||||
#define LED3_DDR DDRB
|
#define LED3_DDR DDRB
|
||||||
#define LED3_BIT PB6
|
#define LED3_BIT PB5
|
||||||
|
|
||||||
#define BL_PORT PORTB
|
#define LED4_PORT PORTB
|
||||||
#define BL_PIN PINB
|
#define LED4_PIN PINB
|
||||||
#define BL_DDR DDRB
|
#define LED4_DDR DDRB
|
||||||
#define BL_BIT PB5
|
#define LED4_BIT PB6
|
||||||
#define BL_OCR OCR1A
|
#define LED4_OCR OCR1B
|
||||||
|
|
||||||
#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)))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
IC1 (PCA9555) IC2 (PCA9555)
|
||||||
Shift Register Multiplexer
|
,----------. ,----------.
|
||||||
,----------. ,------------.
|
SDA --| SDA P00 |-- P1 SDA --| SDA P00 |-- P9
|
||||||
MOSI --| SER 0 |----| INH X0~X7 |===============.
|
SCL --| SCL P01 |-- P2 SCL --| SCL P01 |-- P10
|
||||||
SCK --|>SCK 1 |----| C | |
|
INT --| INT P02 |-- P3 INT --| INT P02 |-- P11
|
||||||
RCK --|>RCK 2 |----| B | ,-------------+-------------.
|
| P03 |-- P4 | P03 |-- P12
|
||||||
| 3 |----| A | | | | | | | | |
|
GND --| A0 P04 |-- P5 VCC --| A0 P04 |-- P13
|
||||||
| | `------------' P26 P27 P28 P25 P29 P32 P30 P31
|
SJ1 --| A1 P05 |-- P6 SJ1 --| A1 P05 |-- P14
|
||||||
| | ,------------.
|
SJ2 --| A2 P06 |-- P7 SJ2 --| A2 P06 |-- P15
|
||||||
| 4 |----| C X0~X7 |===============.
|
| P07 |-- P8 | P07 |-- P16
|
||||||
| 5 |----| B | |
|
| | | |
|
||||||
| 6 |----| A | ,-------------+-------------.
|
| P10 |-- P25 | P10 |-- P17
|
||||||
| 7 |----| INH | | | | | | | | |
|
| P11 |-- P26 | P11 |-- P18
|
||||||
| | `------------' P2 P3 P4 P1 P5 P8 P6 P7
|
| P12 |-- P27 | P12 |-- P19
|
||||||
| | ,------------.
|
| P13 |-- P28 | P13 |-- P20
|
||||||
| 8 |----| INH X0~X7 |===============.
|
| P14 |-- P29 | P14 |-- P21
|
||||||
| 9 |----| C | |
|
| P15 |-- P30 | P15 |-- P22
|
||||||
| 10 |----| B | ,-------------+-------------.
|
| P16 |-- P31 | P16 |-- P23
|
||||||
| 11 |----| A | | | | | | | | |
|
| P17 |-- P32 | P17 |-- P24
|
||||||
| | `------------' 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
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MUX_COUNT 4
|
#define EXP_COUNT 2
|
||||||
#define MUX_PORTS 8
|
#define EXP_ADDR(n) ((0x20+(n))<<1)
|
||||||
#define PX_TO_MUX(x) (x>>3) // (x / MUX_PORTS)
|
#define EXP_OUTPUT 0
|
||||||
|
#define EXP_INPUT 1
|
||||||
#if defined(KIMERA_V1)
|
#define EXP_PORT_COUNT 2
|
||||||
|
#define EXP_PIN_PER_PORT 8
|
||||||
enum {
|
enum {
|
||||||
MUX4_INH = 0,
|
EXP_COMM_INPUT_0 = 0,
|
||||||
MUX4_A,
|
EXP_COMM_INPUT_1,
|
||||||
MUX4_B,
|
EXP_COMM_OUTPUT_0,
|
||||||
MUX4_C,
|
EXP_COMM_OUTPUT_1,
|
||||||
MUX1_A,
|
EXP_COMM_INVERSION_0,
|
||||||
MUX1_B,
|
EXP_COMM_INVERSION_1,
|
||||||
MUX1_C,
|
EXP_COMM_CONFIG_0,
|
||||||
MUX1_INH,
|
EXP_COMM_CONFIG_1
|
||||||
MUX2_INH,
|
|
||||||
MUX2_A,
|
|
||||||
MUX2_B,
|
|
||||||
MUX2_C,
|
|
||||||
MUX3_A,
|
|
||||||
MUX3_B,
|
|
||||||
MUX3_C,
|
|
||||||
MUX3_INH
|
|
||||||
};
|
};
|
||||||
#elif defined(KIMERA_V2)
|
#define PX_TO_EXP(x) (((x)>>5<<1)+((((x)>>3)&1)^(((x)>>4)&1)))
|
||||||
enum {
|
#define PX_TO_PORT(x) (((x)>>4)&1)
|
||||||
MUX4_INH = 0,
|
#define PX_TO_PIN(x) ((x)&7)
|
||||||
MUX4_C,
|
#define PX_COUNT (EXP_PIN_PER_PORT * EXP_PORT_COUNT * EXP_COUNT)
|
||||||
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
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef KIMERA_C
|
#ifdef KIMERA_C
|
||||||
#if defined(KIMERA_V1)
|
const uint16_t PROGMEM dummy[] = {
|
||||||
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
|
|
||||||
};
|
};
|
||||||
#endif
|
#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 */
|
/* Matrix Mapping in EEPROM */
|
||||||
|
|
||||||
#define EECONFIG_MUX_MAPPING (uint8_t *)7
|
#define EECONFIG_ROW_COUNT (uint8_t *)7
|
||||||
#define EECONFIG_ROW_COL_MAPPING (uint8_t *)8
|
#define EECONFIG_COL_COUNT (uint8_t *)8
|
||||||
#define MATRIX_MAPPING_SIZE MUX_COUNT * MUX_PORTS
|
#define EECONFIG_ROW_COL_MAPPING (uint8_t *)9
|
||||||
|
|
||||||
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 UNCONFIGURED 0xFF
|
||||||
|
|
||||||
/* Functions */
|
/* Functions */
|
||||||
@ -214,8 +124,15 @@ uint8_t read_matrix_mapping(void);
|
|||||||
void write_matrix_mapping(void);
|
void write_matrix_mapping(void);
|
||||||
void shift_out_word(uint16_t word);
|
void shift_out_word(uint16_t word);
|
||||||
matrix_row_t read_cols(void);
|
matrix_row_t read_cols(void);
|
||||||
void init_cols(void);
|
|
||||||
void unselect_rows(void);
|
void unselect_rows(void);
|
||||||
void select_row(uint8_t row);
|
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
|
#endif
|
||||||
|
@ -38,19 +38,20 @@ static uint8_t debouncing = DEBOUNCE;
|
|||||||
static matrix_row_t matrix[MATRIX_ROWS];
|
static matrix_row_t matrix[MATRIX_ROWS];
|
||||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
||||||
|
|
||||||
extern uint8_t row_max_count;
|
extern uint8_t row_count;
|
||||||
extern uint8_t col_max_count;
|
extern uint8_t col_count;
|
||||||
|
extern uint8_t data[EXP_COUNT][EXP_PORT_COUNT];
|
||||||
|
|
||||||
inline
|
inline
|
||||||
uint8_t matrix_rows(void)
|
uint8_t matrix_rows(void)
|
||||||
{
|
{
|
||||||
return row_max_count;
|
return row_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
uint8_t matrix_cols(void)
|
uint8_t matrix_cols(void)
|
||||||
{
|
{
|
||||||
return col_max_count;
|
return col_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void matrix_init(void)
|
void matrix_init(void)
|
||||||
@ -63,13 +64,13 @@ void matrix_init(void)
|
|||||||
|
|
||||||
// initialize row and col
|
// initialize row and col
|
||||||
unselect_rows();
|
unselect_rows();
|
||||||
init_cols();
|
|
||||||
|
|
||||||
// initialize matrix state: all keys off
|
// initialize matrix state: all keys off
|
||||||
for (uint8_t i=0; i < matrix_rows(); i++) {
|
for (uint8_t i=0; i < matrix_rows(); i++) {
|
||||||
matrix[i] = 0;
|
matrix[i] = 0;
|
||||||
matrix_debouncing[i] = 0;
|
matrix_debouncing[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t matrix_scan(void)
|
uint8_t matrix_scan(void)
|
||||||
|
203
keyboard/kimera/twimaster.c
Normal file
203
keyboard/kimera/twimaster.c
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* 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>
|
||||||
|
#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 */
|
Reference in New Issue
Block a user