#---------------------------------------------------------------------------- | |||||
# On command line: | |||||
# | |||||
# make all = Make software. | |||||
# | |||||
# make clean = Clean out built project files. | |||||
# | |||||
# make coff = Convert ELF to AVR COFF. | |||||
# | |||||
# make extcoff = Convert ELF to AVR Extended COFF. | |||||
# | |||||
# make program = Download the hex file to the device. | |||||
# Please customize your programmer settings(PROGRAM_CMD) | |||||
# | |||||
# make teensy = Download the hex file to the device, using teensy_loader_cli. | |||||
# (must have teensy_loader_cli installed). | |||||
# | |||||
# make dfu = Download the hex file to the device, using dfu-programmer (must | |||||
# have dfu-programmer installed). | |||||
# | |||||
# make flip = Download the hex file to the device, using Atmel FLIP (must | |||||
# have Atmel FLIP installed). | |||||
# | |||||
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer | |||||
# (must have dfu-programmer installed). | |||||
# | |||||
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP | |||||
# (must have Atmel FLIP installed). | |||||
# | |||||
# make debug = Start either simulavr or avarice as specified for debugging, | |||||
# with avr-gdb or avr-insight as the front end for debugging. | |||||
# | |||||
# make filename.s = Just compile filename.c into the assembler code only. | |||||
# | |||||
# make filename.i = Create a preprocessed source file for use in submitting | |||||
# bug reports to the GCC project. | |||||
# | |||||
# To rebuild project do "make clean" then "make all". | |||||
#---------------------------------------------------------------------------- | |||||
# Target file name (without extension). | |||||
TARGET = ergodone_lufa | |||||
# Directory common source filess exist | |||||
TMK_DIR = ../../tmk_core_custom | |||||
# Directory keyboard dependent files exist | |||||
TARGET_DIR = . | |||||
# project specific files | |||||
SRC = keymap_common.c \ | |||||
matrix.c \ | |||||
led.c \ | |||||
backlight.c \ | |||||
ledmap.c \ | |||||
twimaster.c \ | |||||
expander.c | |||||
ifdef KEYMAP | |||||
SRC := keymap_$(KEYMAP).c $(SRC) | |||||
else | |||||
SRC := keymap_default.c $(SRC) | |||||
endif | |||||
CONFIG_H = config.h | |||||
# MCU name | |||||
#MCU = at90usb1287 | |||||
MCU = atmega32u4 | |||||
# Processor frequency. | |||||
# This will define a symbol, F_CPU, in all source code files equal to the | |||||
# processor frequency in Hz. You can then use this symbol in your source code to | |||||
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done | |||||
# automatically to create a 32-bit value in your source code. | |||||
# | |||||
# This will be an integer division of F_USB below, as it is sourced by | |||||
# F_USB after it has run through any CPU prescalers. Note that this value | |||||
# does not *change* the processor frequency - it should merely be updated to | |||||
# reflect the processor speed set externally so that the code can use accurate | |||||
# software delays. | |||||
F_CPU = 16000000 | |||||
# | |||||
# LUFA specific | |||||
# | |||||
# Target architecture (see library "Board Types" documentation). | |||||
ARCH = AVR8 | |||||
# Input clock frequency. | |||||
# This will define a symbol, F_USB, in all source code files equal to the | |||||
# input clock frequency (before any prescaling is performed) in Hz. This value may | |||||
# differ from F_CPU if prescaling is used on the latter, and is required as the | |||||
# raw input clock is fed directly to the PLL sections of the AVR for high speed | |||||
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' | |||||
# at the end, this will be done automatically to create a 32-bit value in your | |||||
# source code. | |||||
# | |||||
# If no clock division is performed on the input clock inside the AVR (via the | |||||
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. | |||||
F_USB = $(F_CPU) | |||||
# Interrupt driven control endpoint task(+60) | |||||
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT | |||||
# Boot Section Size in *bytes* | |||||
# Teensy halfKay 512 | |||||
# Teensy++ halfKay 1024 | |||||
# Atmel DFU loader 4096 | |||||
# LUFA bootloader 4096 | |||||
# USBaspLoader 2048 | |||||
OPT_DEFS += -DBOOTLOADER_SIZE=4096 | |||||
# PCB Version | |||||
ifdef VER | |||||
OPT_DEFS += -DVER_$(REV) | |||||
endif | |||||
# Additional definitions from command line | |||||
ifdef DEFS | |||||
OPT_DEFS += $(foreach DEF,$(DEFS),-D$(DEF)) | |||||
endif | |||||
# Build Options | |||||
# comment out to disable the options. | |||||
# | |||||
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) | |||||
MOUSEKEY_ENABLE = yes # Mouse keys(+4700) | |||||
EXTRAKEY_ENABLE = yes # Audio control and System control(+450) | |||||
CONSOLE_ENABLE = yes # Console for debug(+400) | |||||
COMMAND_ENABLE = yes # Commands for debug and configuration | |||||
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | |||||
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||||
USB_6KRO_ENABLE = yes # USB 6key Rollover | |||||
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | |||||
#PS2_USE_BUSYWAIT = yes | |||||
BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality | |||||
KEYMAP_IN_EEPROM_ENABLE = yes # External keymap in eeprom | |||||
#KEYMAP_SECTION_ENABLE = yes # Fixed address keymap for keymap editor | |||||
SOFTPWM_LED_ENABLE = yes # Enable SoftPWM to drive backlight | |||||
FADING_LED_ENABLE = yes # Enable fading backlight | |||||
BREATHING_LED_ENABLE = yes # Enable breathing backlight | |||||
LEDMAP_ENABLE = yes # Enable LED mapping | |||||
LEDMAP_IN_EEPROM_ENABLE = yes # Read LED mapping from eeprom | |||||
# Optimize size but this may cause error "relocation truncated to fit" | |||||
#EXTRALDFLAGS = -Wl,--relax | |||||
# Search Path | |||||
VPATH += $(TARGET_DIR) | |||||
VPATH += $(TMK_DIR) | |||||
include $(TMK_DIR)/protocol/lufa.mk | |||||
include $(TMK_DIR)/common.mk | |||||
include $(TMK_DIR)/rules.mk |
#---------------------------------------------------------------------------- | |||||
# On command line: | |||||
# | |||||
# make all = Make software. | |||||
# | |||||
# make clean = Clean out built project files. | |||||
# | |||||
# make coff = Convert ELF to AVR COFF. | |||||
# | |||||
# make extcoff = Convert ELF to AVR Extended COFF. | |||||
# | |||||
# make program = Download the hex file to the device. | |||||
# Please customize your programmer settings(PROGRAM_CMD) | |||||
# | |||||
# make teensy = Download the hex file to the device, using teensy_loader_cli. | |||||
# (must have teensy_loader_cli installed). | |||||
# | |||||
# make dfu = Download the hex file to the device, using dfu-programmer (must | |||||
# have dfu-programmer installed). | |||||
# | |||||
# make flip = Download the hex file to the device, using Atmel FLIP (must | |||||
# have Atmel FLIP installed). | |||||
# | |||||
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer | |||||
# (must have dfu-programmer installed). | |||||
# | |||||
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP | |||||
# (must have Atmel FLIP installed). | |||||
# | |||||
# make debug = Start either simulavr or avarice as specified for debugging, | |||||
# with avr-gdb or avr-insight as the front end for debugging. | |||||
# | |||||
# make filename.s = Just compile filename.c into the assembler code only. | |||||
# | |||||
# make filename.i = Create a preprocessed source file for use in submitting | |||||
# bug reports to the GCC project. | |||||
# | |||||
# To rebuild project do "make clean" then "make all". | |||||
#---------------------------------------------------------------------------- | |||||
# Target file name (without extension). | |||||
TARGET = ergodone_pjrc | |||||
# Directory common source filess exist | |||||
TMK_DIR = ../../tmk_core_custom | |||||
# Directory keyboard dependent files exist | |||||
TARGET_DIR = . | |||||
# project specific files | |||||
SRC = keymap_common.c \ | |||||
matrix.c \ | |||||
led.c \ | |||||
backlight.c \ | |||||
ledmap.c \ | |||||
twimaster.c \ | |||||
expander.c | |||||
ifdef KEYMAP | |||||
SRC := keymap_$(KEYMAP).c $(SRC) | |||||
else | |||||
SRC := keymap_default.c $(SRC) | |||||
endif | |||||
CONFIG_H = config.h | |||||
# MCU name, you MUST set this to match the board you are using | |||||
# type "make clean" after changing this, so all files will be rebuilt | |||||
MCU = atmega32u4 | |||||
#MCU = at90usb1286 | |||||
# Processor frequency. | |||||
# Normally the first thing your program should do is set the clock prescaler, | |||||
# so your program will run at the correct speed. You should also set this | |||||
# variable to same clock speed. The _delay_ms() macro uses this, and many | |||||
# examples use this variable to calculate timings. Do not add a "UL" here. | |||||
F_CPU = 16000000 | |||||
# Boot Section Size in *bytes* | |||||
# Teensy halfKay 512 | |||||
# Atmel DFU loader 4096 | |||||
# LUFA bootloader 4096 | |||||
OPT_DEFS += -DBOOTLOADER_SIZE=4096 | |||||
# PCB Version | |||||
ifdef VER | |||||
OPT_DEFS += -DVER_$(REV) | |||||
endif | |||||
# Additional definitions from command line | |||||
ifdef DEFS | |||||
OPT_DEFS += $(foreach DEF,$(DEFS),-D$(DEF)) | |||||
endif | |||||
# Build Options | |||||
# comment out to disable the options. | |||||
# | |||||
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) | |||||
MOUSEKEY_ENABLE = yes # Mouse keys(+4700) | |||||
EXTRAKEY_ENABLE = yes # Audio control and System control(+450) | |||||
CONSOLE_ENABLE = yes # Console for debug(+400) | |||||
COMMAND_ENABLE = yes # Commands for debug and configuration | |||||
#SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | |||||
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA | |||||
USB_6KRO_ENABLE = yes # USB 6key Rollover | |||||
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | |||||
#PS2_USE_BUSYWAIT = yes | |||||
BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality | |||||
KEYMAP_IN_EEPROM_ENABLE = yes # External keymap in eeprom | |||||
#KEYMAP_SECTION_ENABLE = yes # Fixed address keymap for keymap editor | |||||
SOFTPWM_LED_ENABLE = yes # Enable SoftPWM to drive backlight | |||||
FADING_LED_ENABLE = yes # Enable fading backlight | |||||
BREATHING_LED_ENABLE = yes # Enable breathing backlight | |||||
LEDMAP_ENABLE = yes # Enable LED mapping | |||||
LEDMAP_IN_EEPROM_ENABLE = yes # Read LED mapping from eeprom | |||||
# Search Path | |||||
VPATH += $(TARGET_DIR) | |||||
VPATH += $(TMK_DIR) | |||||
include $(TMK_DIR)/protocol/pjrc.mk | |||||
include $(TMK_DIR)/common.mk | |||||
include $(TMK_DIR)/rules.mk |
/* | |||||
Copyright 2016 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include <avr/io.h> | |||||
#include <avr/interrupt.h> | |||||
#include <avr/pgmspace.h> | |||||
#include "backlight.h" | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
#include "softpwm_led.h" | |||||
#else | |||||
#include "breathing_led.h" | |||||
#endif | |||||
#include "action.h" | |||||
#ifdef BACKLIGHT_ENABLE | |||||
void backlight_enable(void); | |||||
void backlight_disable(void); | |||||
inline void backlight_set_raw(uint8_t raw); | |||||
static const uint8_t backlight_table[] PROGMEM = { | |||||
0, 16, 128, 255 | |||||
}; | |||||
extern backlight_config_t backlight_config; | |||||
uint8_t backlight_brightness; | |||||
/* Backlight pin configuration | |||||
* LED4: PB6 (D10) OC1B | |||||
*/ | |||||
#ifndef SOFTPWM_LED_ENABLE | |||||
void backlight_enable(void) | |||||
{ | |||||
// Turn on PWM | |||||
LED4_DDR |= (1<<LED4_BIT); | |||||
cli(); | |||||
TCCR1A |= ((1<<WGM10) | (1<<COM1B1)); | |||||
TCCR1B |= ((1<<CS11) | (1<<CS10)); | |||||
sei(); | |||||
} | |||||
#endif | |||||
#ifndef SOFTPWM_LED_ENABLE | |||||
void backlight_disable(void) | |||||
{ | |||||
// Turn off PWM | |||||
LED4_DDR &= ~(1<<LED4_BIT); | |||||
cli(); | |||||
TCCR1A &= ~((1<<WGM10) | (1<<COM1B1)); | |||||
TCCR1B &= ~((1<<CS11) | (1<<CS10)); | |||||
sei(); | |||||
LED4_OCR = 0; | |||||
} | |||||
#endif | |||||
void backlight_set(uint8_t level) | |||||
{ | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
softpwm_enable(); | |||||
#endif | |||||
#ifdef BREATHING_LED_ENABLE | |||||
switch (level) { | |||||
case 1: | |||||
case 2: | |||||
case 3: | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
softpwm_led_enable_all(); | |||||
#ifdef FADING_LED_ENABLE | |||||
fading_led_disable_all(); | |||||
#endif | |||||
breathing_led_disable_all(); | |||||
#else | |||||
backlight_enable(); | |||||
breathing_led_disable(); | |||||
#endif | |||||
backlight_brightness = pgm_read_byte(&backlight_table[level]); | |||||
backlight_set_raw(backlight_brightness); | |||||
break; | |||||
case 4: | |||||
case 5: | |||||
case 6: | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
softpwm_led_enable_all(); | |||||
#ifdef FADING_LED_ENABLE | |||||
fading_led_disable_all(); | |||||
#endif | |||||
breathing_led_enable_all(); | |||||
#else | |||||
backlight_enable(); | |||||
breathing_led_enable(); | |||||
#endif | |||||
breathing_led_set_duration(6 - level); | |||||
break; | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
#ifdef FADING_LED_ENABLE | |||||
case 7: | |||||
softpwm_led_enable_all(); | |||||
fading_led_enable_all(); | |||||
breathing_led_disable_all(); | |||||
fading_led_set_direction_all(FADING_LED_FADE_IN); | |||||
fading_led_set_duration(3); | |||||
break; | |||||
case 8: | |||||
softpwm_led_enable_all(); | |||||
fading_led_enable_all(); | |||||
breathing_led_disable_all(); | |||||
fading_led_set_direction_all(FADING_LED_FADE_OUT); | |||||
fading_led_set_duration(3); | |||||
break; | |||||
#endif | |||||
#endif | |||||
case 0: | |||||
default: | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
#ifdef FADING_LED_ENABLE | |||||
fading_led_disable_all(); | |||||
#endif | |||||
breathing_led_disable_all(); | |||||
backlight_brightness = 0; | |||||
backlight_set_raw(backlight_brightness); | |||||
softpwm_led_disable_all(); | |||||
#else | |||||
breathing_led_disable(); | |||||
backlight_disable(); | |||||
#endif | |||||
break; | |||||
} | |||||
#else | |||||
if (level > 0) { | |||||
backlight_enable(); | |||||
backlight_set_raw(pgm_read_byte(&backlight_table[level])); | |||||
} | |||||
else { | |||||
backlight_disable(); | |||||
} | |||||
#endif | |||||
} | |||||
#ifndef SOFTPWM_LED_ENABLE | |||||
#ifdef BREATHING_LED_ENABLE | |||||
void breathing_led_set_raw(uint8_t raw) | |||||
{ | |||||
backlight_set_raw(raw); | |||||
} | |||||
#endif | |||||
#endif | |||||
inline void backlight_set_raw(uint8_t raw) | |||||
{ | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
softpwm_led_set_all(raw); | |||||
#else | |||||
#endif | |||||
} | |||||
#ifndef LEDMAP_ENABLE | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
void softpwm_led_init(void) | |||||
{ | |||||
} | |||||
void softpwm_led_on(uint8_t index) | |||||
{ | |||||
} | |||||
void softpwm_led_off(uint8_t index) | |||||
{ | |||||
} | |||||
#endif | |||||
#endif | |||||
#ifdef SOFTPWM_LED_ENABLE | |||||
#ifdef FADING_LED_ENABLE | |||||
void action_keyevent(keyevent_t event) | |||||
{ | |||||
if (backlight_config.enable) { | |||||
if (backlight_config.level == 7) { | |||||
if (event.pressed) { | |||||
fading_led_set_delay_all(64); | |||||
softpwm_led_decrease_all(32); | |||||
} | |||||
} | |||||
if (backlight_config.level == 8) { | |||||
if (event.pressed) { | |||||
fading_led_set_delay_all(64); | |||||
softpwm_led_increase_all(32); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
#endif | |||||
#endif | |||||
#endif |
/* | |||||
Copyright 2016 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef CONFIG_H | |||||
#define CONFIG_H | |||||
/* USB Device descriptor parameter */ | |||||
#define VENDOR_ID 0x1209 | |||||
#define PRODUCT_ID 0x2333 | |||||
#ifdef VER_PROTOTYPE | |||||
#define DEVICE_VER 0x0300 | |||||
#else | |||||
#define DEVICE_VER 0x0301 | |||||
#endif | |||||
#define MANUFACTURER K.T.E.C. | |||||
#define PRODUCT ErgoDone | |||||
#define DESCRIPTION t.m.k. keyboard firmware for ErgoDone | |||||
/* key matrix size */ | |||||
#define MATRIX_ROWS 6 | |||||
#define MATRIX_COLS 14 | |||||
/* keymap in eeprom */ | |||||
#define FN_ACTIONS_COUNT 32 | |||||
#define KEYMAPS_COUNT 3 | |||||
#define EECONFIG_KEYMAP_IN_EEPROM 17 | |||||
/* define if matrix has ghost */ | |||||
//#define MATRIX_HAS_GHOST | |||||
/* Set 0 if debouncing isn't needed */ | |||||
#define DEBOUNCE 5 | |||||
/* number of backlight levels */ | |||||
#ifdef BREATHING_LED_ENABLE | |||||
#ifdef FADING_LED_ENABLE | |||||
#define BACKLIGHT_LEVELS 8 | |||||
#else | |||||
#define BACKLIGHT_LEVELS 6 | |||||
#endif | |||||
#else | |||||
#define BACKLIGHT_LEVELS 3 | |||||
#endif | |||||
/* number of leds */ | |||||
#define LED_COUNT 5 | |||||
/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ | |||||
#define LOCKING_SUPPORT_ENABLE | |||||
/* Locking resynchronize hack */ | |||||
#define LOCKING_RESYNC_ENABLE | |||||
/* key combination for command */ | |||||
#define IS_COMMAND() ( \ | |||||
keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ | |||||
) | |||||
/* for debug */ | |||||
//#define SUART_OUT_PORT PORTF | |||||
//#define SUART_OUT_BIT 5 | |||||
//#define SUART_IN_PIN PINF | |||||
//#define SUART_IN_BIT 6 | |||||
/* | |||||
* Feature disable options | |||||
* These options are also useful to firmware size reduction. | |||||
*/ | |||||
/* disable debug print */ | |||||
//#define NO_DEBUG | |||||
/* disable print */ | |||||
//#define NO_PRINT | |||||
/* disable action features */ | |||||
//#define NO_ACTION_LAYER | |||||
//#define NO_ACTION_TAPPING | |||||
//#define NO_ACTION_ONESHOT | |||||
//#define NO_ACTION_MACRO | |||||
//#define NO_ACTION_FUNCTION | |||||
//#define NO_SUSPEND_POWER_DOWN | |||||
#endif |
/* | |||||
Copyright 2016 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include <stdbool.h> | |||||
#include "action.h" | |||||
#include "i2cmaster.h" | |||||
#include "expander.h" | |||||
#include "debug.h" | |||||
static uint8_t expander_status = 0; | |||||
static uint8_t expander_input = 0; | |||||
void expander_config(void); | |||||
uint8_t expander_write(uint8_t reg, uint8_t data); | |||||
uint8_t expander_read(uint8_t reg, uint8_t *data); | |||||
void expander_init(void) | |||||
{ | |||||
i2c_init(); | |||||
expander_scan(); | |||||
} | |||||
void expander_scan(void) | |||||
{ | |||||
dprintf("expander status: %d ... ", expander_status); | |||||
uint8_t ret = i2c_start(EXPANDER_ADDR | I2C_WRITE); | |||||
if (ret == 0) { | |||||
i2c_stop(); | |||||
if (expander_status == 0) { | |||||
dprintf("attached\n"); | |||||
expander_status = 1; | |||||
expander_config(); | |||||
clear_keyboard(); | |||||
} | |||||
} | |||||
else { | |||||
if (expander_status == 1) { | |||||
dprintf("detached\n"); | |||||
expander_status = 0; | |||||
clear_keyboard(); | |||||
} | |||||
} | |||||
dprintf("%d\n", expander_status); | |||||
} | |||||
void expander_read_cols(void) | |||||
{ | |||||
expander_read(EXPANDER_REG_GPIOA, &expander_input); | |||||
} | |||||
uint8_t expander_get_col(uint8_t col) | |||||
{ | |||||
if (col > 4) { | |||||
col++; | |||||
} | |||||
return expander_input & (1<<col) ? 1 : 0; | |||||
} | |||||
matrix_row_t expander_read_row(void) | |||||
{ | |||||
expander_read_cols(); | |||||
/* make cols */ | |||||
matrix_row_t cols = 0; | |||||
for (uint8_t col = 0; col < MATRIX_COLS; col++) { | |||||
if (expander_get_col(col)) { | |||||
cols |= (1UL << col); | |||||
} | |||||
} | |||||
return cols; | |||||
} | |||||
void expander_unselect_rows(void) | |||||
{ | |||||
expander_write(EXPANDER_REG_IODIRB, 0xFF); | |||||
} | |||||
void expander_select_row(uint8_t row) | |||||
{ | |||||
expander_write(EXPANDER_REG_IODIRB, ~(1<<(row+1))); | |||||
} | |||||
void expander_config(void) | |||||
{ | |||||
expander_write(EXPANDER_REG_IPOLA, 0xFF); | |||||
expander_write(EXPANDER_REG_GPPUA, 0xFF); | |||||
expander_write(EXPANDER_REG_IODIRB, 0xFF); | |||||
} | |||||
uint8_t expander_write(uint8_t reg, uint8_t data) | |||||
{ | |||||
if (expander_status == 0) { | |||||
return 0; | |||||
} | |||||
uint8_t ret; | |||||
ret = i2c_start(EXPANDER_ADDR | I2C_WRITE); | |||||
if (ret) goto stop; | |||||
ret = i2c_write(reg); | |||||
if (ret) goto stop; | |||||
ret = i2c_write(data); | |||||
stop: | |||||
i2c_stop(); | |||||
return ret; | |||||
} | |||||
uint8_t expander_read(uint8_t reg, uint8_t *data) | |||||
{ | |||||
if (expander_status == 0) { | |||||
return 0; | |||||
} | |||||
uint8_t ret; | |||||
ret = i2c_start(EXPANDER_ADDR | I2C_WRITE); | |||||
if (ret) goto stop; | |||||
ret = i2c_write(reg); | |||||
if (ret) goto stop; | |||||
ret = i2c_rep_start(EXPANDER_ADDR | I2C_READ); | |||||
if (ret) goto stop; | |||||
*data = i2c_readNak(); | |||||
stop: | |||||
i2c_stop(); | |||||
return ret; | |||||
} |
/* | |||||
Copyright 2016 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef EXPANDER_H | |||||
#define EXPANDER_H | |||||
#include <stdint.h> | |||||
#include "matrix.h" | |||||
#define MCP23017 | |||||
#define MCP23017_A0 0 | |||||
#define MCP23017_A1 0 | |||||
#define MCP23017_A2 0 | |||||
#ifdef MCP23017 | |||||
#define EXPANDER_ADDR ((0x20|(MCP23017_A0<<0)|(MCP23017_A1<<1)|(MCP23017_A2<<2)) << 1) | |||||
enum EXPANDER_REG_BANK0 { | |||||
EXPANDER_REG_IODIRA = 0, | |||||
EXPANDER_REG_IODIRB, | |||||
EXPANDER_REG_IPOLA, | |||||
EXPANDER_REG_IPOLB, | |||||
EXPANDER_REG_GPINTENA, | |||||
EXPANDER_REG_GPINTENB, | |||||
EXPANDER_REG_DEFVALA, | |||||
EXPANDER_REG_DEFVALB, | |||||
EXPANDER_REG_INTCONA, | |||||
EXPANDER_REG_INTCONB, | |||||
EXPANDER_REG_IOCONA, | |||||
EXPANDER_REG_IOCONB, | |||||
EXPANDER_REG_GPPUA, | |||||
EXPANDER_REG_GPPUB, | |||||
EXPANDER_REG_INTFA, | |||||
EXPANDER_REG_INTFB, | |||||
EXPANDER_REG_INTCAPA, | |||||
EXPANDER_REG_INTCAPB, | |||||
EXPANDER_REG_GPIOA, | |||||
EXPANDER_REG_GPIOB, | |||||
EXPANDER_REG_OLATA, | |||||
EXPANDER_REG_OLATB | |||||
}; | |||||
#endif | |||||
void expander_init(void); | |||||
void expander_scan(void); | |||||
void expander_read_cols(void); | |||||
uint8_t expander_get_col(uint8_t col); | |||||
matrix_row_t expander_read_row(void); | |||||
void expander_unselect_rows(void); | |||||
void expander_select_row(uint8_t row); | |||||
#endif |
#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 |
/* | |||||
Copyright 2014 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include <avr/pgmspace.h> | |||||
#include "keymap.h" | |||||
#include "keymap_in_eeprom.h" | |||||
#include "keymap_common.h" | |||||
/* translates key to keycode */ | |||||
uint8_t keymap_key_to_keycode(uint8_t layer, keypos_t key) | |||||
{ | |||||
/* xprintf("Layer: %d, Row: %d, Col: %d, ", layer, key.row, key.col); */ | |||||
#ifndef KEYMAP_IN_EEPROM_ENABLE | |||||
return pgm_read_byte(&keymaps[(layer)][(key.row) * matrix_cols() + (key.col)]); | |||||
#else | |||||
return eeconfig_read_keymap_key(layer, key.row, key.col); | |||||
#endif | |||||
} | |||||
/* translates Fn keycode to action */ | |||||
action_t keymap_fn_to_action(uint8_t keycode) | |||||
{ | |||||
return (action_t) { | |||||
#ifndef KEYMAP_IN_EEPROM_ENABLE | |||||
.code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) | |||||
#else | |||||
.code = eeconfig_read_keymap_fn_action(FN_INDEX(keycode)) | |||||
#endif | |||||
}; | |||||
} | |||||
#ifdef KEYMAP_IN_EEPROM_ENABLE | |||||
const uint8_t* keymaps_pointer(void) { | |||||
return (const uint8_t*)keymaps; | |||||
} | |||||
const uint16_t* fn_actions_pointer(void) { | |||||
return fn_actions; | |||||
} | |||||
#endif |
/* | |||||
Copyright 2014 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef KEYMAP_COMMON_H | |||||
#define KEYMAP_COMMON_H | |||||
#include <stdint.h> | |||||
extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; | |||||
extern const uint16_t fn_actions[]; | |||||
#define KEYMAP( \ | |||||
K0A, K0B, K0C, K0D, K0E, K0F, K0G, K0H, K0J, K0K, K0L, K0M, K0N, K0P, \ | |||||
K1A, K1B, K1C, K1D, K1E, K1F, K1G, K1H, K1J, K1K, K1L, K1M, K1N, K1P, \ | |||||
K2A, K2B, K2C, K2D, K2E, K2F, K2J, K2K, K2L, K2M, K2N, K2P, \ | |||||
K3A, K3B, K3C, K3D, K3E, K3F, K3G, K3H, K3J, K3K, K3L, K3M, K3N, K3P, \ | |||||
K4A, K4B, K4C, K4D, K4E, K4K, K4L, K4M, K4N, K4P, \ | |||||
K5F, K5G, K5H, K5J, \ | |||||
K5E, K5K, \ | |||||
K5D, K5C, K5B, K5N, K5M, K5L \ | |||||
) { \ | |||||
{ KC_##K0A, KC_##K0B, KC_##K0C, KC_##K0D, KC_##K0E, KC_##K0F, KC_##K0G, KC_##K0H, KC_##K0J, KC_##K0K, KC_##K0L, KC_##K0M, KC_##K0N, KC_##K0P }, \ | |||||
{ KC_##K1A, KC_##K1B, KC_##K1C, KC_##K1D, KC_##K1E, KC_##K1F, KC_##K1G, KC_##K1H, KC_##K1J, KC_##K1K, KC_##K1L, KC_##K1M, KC_##K1N, KC_##K1P }, \ | |||||
{ KC_##K2A, KC_##K2B, KC_##K2C, KC_##K2D, KC_##K2E, KC_##K2F, KC_NO, KC_NO, KC_##K2J, KC_##K2K, KC_##K2L, KC_##K2M, KC_##K2N, KC_##K2P }, \ | |||||
{ KC_##K3A, KC_##K3B, KC_##K3C, KC_##K3D, KC_##K3E, KC_##K3F, KC_##K3G, KC_##K3H, KC_##K3J, KC_##K3K, KC_##K3L, KC_##K3M, KC_##K3N, KC_##K3P }, \ | |||||
{ KC_##K4A, KC_##K4B, KC_##K4C, KC_##K4D, KC_##K4E, KC_NO, KC_NO, KC_NO, KC_NO, KC_##K4K, KC_##K4L, KC_##K4M, KC_##K4N, KC_##K4P }, \ | |||||
{ KC_NO, KC_##K5B, KC_##K5C, KC_##K5D, KC_##K5E, KC_##K5F, KC_##K5G, KC_##K5H, KC_##K5J, KC_##K5K, KC_##K5L, KC_##K5M, KC_##K5N, KC_NO } \ | |||||
} | |||||
#endif |
/* | |||||
Copyright 2016 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include <avr/pgmspace.h> | |||||
#include "keycode.h" | |||||
#include "action.h" | |||||
#include "keymap_common.h" | |||||
// Default | |||||
#ifdef KEYMAP_SECTION_ENABLE | |||||
const uint8_t keymaps[KEYMAPS_COUNT][MATRIX_ROWS][MATRIX_COLS] __attribute__ ((section (".keymap.keymaps"))) = { | |||||
#else | |||||
const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS] PROGMEM = { | |||||
#endif | |||||
/* Keymap 0: Default Layer | |||||
* ,-----------------------------. ,-----------------------------. | |||||
* | `| 1| 2| 3| 4| 5| -| | =| 6| 7| 8| 9| 0| '| | |||||
* |-----+---+---+---+---+-------| |---+---+---+---+---+---+-----| | |||||
* |Tab | Q| W| E| R| T| | | | Y| U| I| O| P| \| | |||||
* |-----+---+---+---+---|---| Fn| | Fn|---+---+---+---+---+-----| | |||||
* |Caps | A| S| D| F| G|---| |---| H| J| K| L| ;|Retur| | |||||
* |-----+---+---+---+---|---| | | |---+---+---+---+---+-----| | |||||
* |Shift| Z| X| C| V| B| Fn| | Fn| N| M| ,| .| /|Shift| | |||||
* `-----+---+---+---+---+-------' `-------+---+---+---+---+-----' | |||||
* |Ctr|Gui|Alt|Lef|Rig| ,-------. ,-------. | Up|Dow| [| ]|Ctr| | |||||
* `-------------------' |Esc|Ins| |Del|Alt| `-------------------' | |||||
* ,---+---+---| |---+---+---. | |||||
* | | |Hom| |PgU| | | | |||||
* |Spc|BS |---| |---|Tab|Ent| | |||||
* | | |End| |PgD| | | | |||||
* `-----------' `-----------' | |||||
*/ | |||||
KEYMAP( | |||||
GRV, 1, 2, 3, 4, 5, MINS, EQL, 6, 7, 8, 9, 0, QUOT, \ | |||||
TAB, Q, W, E, R, T, FN0, FN1, Y, U, I, O, P, BSLS, \ | |||||
CAPS,A, S, D, F, G, H, J, K, L, SCLN,ENT, \ | |||||
LSFT,Z, X, C, V, B, FN2, FN3, N, M, COMM,DOT, SLSH,RSFT, \ | |||||
LCTL,LGUI,LALT,LEFT,RGHT, UP, DOWN,LBRC,RBRC,RCTL, \ | |||||
ESC, INS, DEL, RALT, \ | |||||
HOME, PGUP, \ | |||||
SPC, BSPC,END, PGDN,TAB, ENT ), | |||||
/* Keymap 1: Fn Layer | |||||
* ,-----------------------------. ,-----------------------------. | |||||
* | |F1 |F2 |F3 |F4 |F5 | | | |F6 |F7 |F8 |F9 |F10| | | |||||
* |-----+---+---+---+---+-------| |---+---+---+---+---+---+-----| | |||||
* | | | | | | | | | | | | | | | | | |||||
* |-----+---+---+---+---|---| | | |---+---+---+---+---+-----| | |||||
* | | | | | | |---| |---| | | | | | | | |||||
* |-----+---+---+---+---|---| | | |---+---+---+---+---+-----| | |||||
* | | | | | | | | | | | | | | | | | |||||
* `-----+---+---+---+---+-------' `-------+---+---+---+---+-----' | |||||
* | | | | | | ,-------. ,-------. | | | | | | | |||||
* `-------------------' | | | | | | `-------------------' | |||||
* ,---+---+---| |---+---+---. | |||||
* | | | | | | | | | |||||
* | | |---| |---| | | | |||||
* | | | | | | | | | |||||
* `-----------' `-----------' | |||||
*/ | |||||
KEYMAP( | |||||
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ | |||||
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ | |||||
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ | |||||
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \ | |||||
TRNS,TRNS,TRNS,TRNS,TRNS, TRNS,TRNS,TRNS,TRNS,TRNS, \ | |||||
TRNS,TRNS, TRNS,TRNS, \ | |||||
TRNS, TRNS, \ | |||||
TRNS,TRNS,TRNS, TRNS,TRNS,TRNS ) | |||||
}; | |||||
/* | |||||
* Fn action definition | |||||
*/ | |||||
#ifdef KEYMAP_SECTION_ENABLE | |||||
const uint16_t fn_actions[FN_ACTIONS_COUNT] __attribute__ ((section (".keymap.fn_actions"))) = { | |||||
#else | |||||
const uint16_t fn_actions[] PROGMEM = { | |||||
#endif | |||||
[0] = ACTION_LAYER_MOMENTARY(1), | |||||
[1] = ACTION_LAYER_MOMENTARY(1), | |||||
[2] = ACTION_LAYER_MOMENTARY(1), | |||||
[3] = ACTION_LAYER_MOMENTARY(1) | |||||
}; | |||||
#ifdef KEYMAP_IN_EEPROM_ENABLE | |||||
uint16_t keys_count(void) { | |||||
return sizeof(keymaps) / sizeof(keymaps[0]) * MATRIX_ROWS * MATRIX_COLS; | |||||
} | |||||
uint16_t fn_actions_count(void) { | |||||
return sizeof(fn_actions) / sizeof(fn_actions[0]); | |||||
} | |||||
#endif |
/* | |||||
Copyright 2016 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include <avr/io.h> | |||||
#include "stdint.h" | |||||
#include "led.h" | |||||
#ifndef LEDMAP_ENABLE | |||||
void led_set(uint8_t usb_led) | |||||
{ | |||||
if (usb_led & (1<<USB_LED_NUM_LOCK)) { | |||||
// output high | |||||
DDRB |= (1<<PB5); | |||||
PORTB |= (1<<PB5); | |||||
} else { | |||||
// Hi-Z | |||||
DDRB &= ~(1<<PB5); | |||||
PORTB &= ~(1<<PB5); | |||||
} | |||||
if (usb_led & (1<<USB_LED_CAPS_LOCK)) { | |||||
// output high | |||||
DDRB |= (1<<PB6); | |||||
PORTB |= (1<<PB6); | |||||
} else { | |||||
// Hi-Z | |||||
DDRB &= ~(1<<PB6); | |||||
PORTB &= ~(1<<PB6); | |||||
} | |||||
if (usb_led & (1<<USB_LED_SCROLL_LOCK)) { | |||||
// output high | |||||
DDRB |= (1<<PB3); | |||||
PORTB |= (1<<PB3); | |||||
} else { | |||||
// Hi-Z | |||||
DDRB &= ~(1<<PB3); | |||||
PORTB &= ~(1<<PB3); | |||||
} | |||||
} | |||||
#endif |
/* | |||||
Copyright 2016 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include <avr/pgmspace.h> | |||||
#include "ledmap.h" | |||||
#ifdef LEDMAP_ENABLE | |||||
static const uint16_t ledmaps[LED_COUNT] PROGMEM = { | |||||
[0] = LEDMAP_NUM_LOCK, // LED_A - PB5 | |||||
[1] = LEDMAP_CAPS_LOCK, // LED_B - PB6 | |||||
[2] = LEDMAP_SCROLL_LOCK, // LED_C - PB3 | |||||
[3] = LEDMAP_LAYER(1), // RX - PB0 | |||||
[4] = LEDMAP_LAYER(2), // TX - PD5 | |||||
}; | |||||
ledmap_t ledmap_get_code(uint8_t index) | |||||
{ | |||||
return (ledmap_t) { .code = pgm_read_word(&ledmaps[index]) }; | |||||
} | |||||
void ledmap_led_init(void) | |||||
{ | |||||
DDRB |= (1<<PB5 | 1<<PB6 | 1<<PB3); | |||||
PORTB &= ~(1<<PB5 | 1<<PB6 | 1<<PB3); | |||||
DDRB |= (1<<PB0); | |||||
PORTB |= (1<<PB0); | |||||
DDRD |= (1<<PD5); | |||||
PORTD |= (1<<PD5); | |||||
} | |||||
void ledmap_led_on(uint8_t index) | |||||
{ | |||||
switch (index) { | |||||
case 0: | |||||
PORTB |= (1<<PB5); | |||||
break; | |||||
case 1: | |||||
PORTB |= (1<<PB6); | |||||
break; | |||||
case 2: | |||||
PORTB |= (1<<PB3); | |||||
break; | |||||
case 3: | |||||
PORTB &= ~(1<<PB0); | |||||
break; | |||||
case 4: | |||||
PORTD &= ~(1<<PD5); | |||||
break; | |||||
} | |||||
} | |||||
void ledmap_led_off(uint8_t index) | |||||
{ | |||||
switch (index) { | |||||
case 0: | |||||
PORTB &= ~(1<<PB5); | |||||
break; | |||||
case 1: | |||||
PORTB &= ~(1<<PB6); | |||||
break; | |||||
case 2: | |||||
PORTB &= ~(1<<PB3); | |||||
break; | |||||
case 3: | |||||
PORTB |= (1<<PB0); | |||||
break; | |||||
case 4: | |||||
PORTD |= (1<<PD5); | |||||
break; | |||||
} | |||||
} | |||||
#endif |
/* | |||||
Copyright 2016 Kai Ryu <[email protected]> | |||||
This program is free software: you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
/* | |||||
* scan matrix | |||||
*/ | |||||
#include <stdint.h> | |||||
#include <stdbool.h> | |||||
#include <avr/io.h> | |||||
#include <util/delay.h> | |||||
#include "debug.h" | |||||
#include "util.h" | |||||
#include "matrix.h" | |||||
#include "expander.h" | |||||
#include "keymap_in_eeprom.h" | |||||
#include "timer.h" | |||||
#ifndef DEBOUNCE | |||||
# define DEBOUNCE 5 | |||||
#endif | |||||
/* matrix state(1:on, 0:off) */ | |||||
static matrix_row_t matrix[MATRIX_ROWS]; | |||||
#define IMPROVED_DEBOUNCE 1 | |||||
#if IMPROVED_DEBOUNCE | |||||
#define DEBOUNCE_MASK ((1 << DEBOUNCE) - 1) | |||||
static uint8_t matrix_current_row; | |||||
static uint16_t matrix_row_timestamp[MATRIX_ROWS]; | |||||
static uint8_t matrix_debouncing[MATRIX_ROWS][MATRIX_COLS]; | |||||
#else | |||||
static uint8_t debouncing = DEBOUNCE; | |||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS]; | |||||
static matrix_row_t read_row(void); | |||||
#endif | |||||
static uint16_t matrix_scan_timestamp; | |||||
static void read_cols(void); | |||||
static uint8_t get_col(uint8_t col); | |||||
static void init_cols(void); | |||||
static void unselect_rows(void); | |||||
static void select_row(uint8_t row); | |||||
inline | |||||
uint8_t matrix_rows(void) | |||||
{ | |||||
return MATRIX_ROWS; | |||||
} | |||||
inline | |||||
uint8_t matrix_cols(void) | |||||
{ | |||||
return MATRIX_COLS; | |||||
} | |||||
void matrix_init(void) | |||||
{ | |||||
// disable JTAG | |||||
MCUCR = (1<<JTD); | |||||
MCUCR = (1<<JTD); | |||||
timer_init(); | |||||
_delay_ms(1); | |||||
matrix_scan_timestamp = timer_read(); | |||||
// initialize row and col | |||||
unselect_rows(); | |||||
init_cols(); | |||||
// initialize matrix state: all keys off | |||||
#if IMPROVED_DEBOUNCE | |||||
for (uint8_t i = 0; i < matrix_rows(); i++) { | |||||
matrix[i] = 0; | |||||
matrix_current_row = 0; | |||||
matrix_row_timestamp[i] = timer_read(); | |||||
for (uint8_t j = 0; j < matrix_cols(); j++) { | |||||
matrix_debouncing[i][j] = 0; | |||||
} | |||||
} | |||||
#else | |||||
for (uint8_t i=0; i < matrix_rows(); i++) { | |||||
matrix[i] = 0; | |||||
matrix_debouncing[i] = 0; | |||||
} | |||||
#endif | |||||
} | |||||
uint8_t matrix_scan(void) | |||||
{ | |||||
if (timer_elapsed(matrix_scan_timestamp) >= 1000) { | |||||
dprintf("======== 1s task ========\n"); | |||||
dprintf("Scan: %u\n", matrix_scan_timestamp); | |||||
matrix_scan_timestamp = timer_read(); | |||||
expander_scan(); | |||||
dprintf("=========================\n"); | |||||
} | |||||
#if IMPROVED_DEBOUNCE | |||||
uint16_t elapsed = timer_elapsed(matrix_row_timestamp[matrix_current_row]); | |||||
if (elapsed >= 1) { | |||||
matrix_row_timestamp[matrix_current_row] = timer_read(); | |||||
select_row(matrix_current_row); | |||||
_delay_us(30); | |||||
read_cols(); | |||||
for (uint8_t i = 0; i < matrix_cols(); i++) { | |||||
uint8_t *debounce = &matrix_debouncing[matrix_current_row][i]; | |||||
uint8_t col = get_col(i); | |||||
uint8_t count = elapsed; | |||||
do { | |||||
*debounce <<= 1; | |||||
*debounce |= col; | |||||
} while (--count); | |||||
matrix_row_t *row = &matrix[matrix_current_row]; | |||||
matrix_row_t mask = ((matrix_row_t)1 << i); | |||||
switch (*debounce & DEBOUNCE_MASK) { | |||||
case DEBOUNCE_MASK: | |||||
#if DEBOUNCE > 1 | |||||
case (DEBOUNCE_MASK >> 1): | |||||
#if DEBOUNCE > 2 | |||||
case (DEBOUNCE_MASK >> 2): | |||||
#if DEBOUNCE > 3 | |||||
case (DEBOUNCE_MASK >> 3): | |||||
#if DEBOUNCE > 4 | |||||
case (DEBOUNCE_MASK >> 4): | |||||
#if DEBOUNCE > 5 | |||||
case (DEBOUNCE_MASK >> 5): | |||||
#if DEBOUNCE > 6 | |||||
case (DEBOUNCE_MASK >> 6): | |||||
#if DEBOUNCE > 7 | |||||
case (DEBOUNCE_MASK >> 7): | |||||
#if DEBOUNCE > 8 | |||||
case (DEBOUNCE_MASK >> 8): | |||||
#if DEBOUNCE > 9 | |||||
case (DEBOUNCE_MASK >> 9): | |||||
#if DEBOUNCE > 10 | |||||
case (DEBOUNCE_MASK >> 10): | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
if ((*row & mask) == 0) { | |||||
*row |= mask; | |||||
} | |||||
break; | |||||
#if DEBOUNCE > 1 | |||||
case ((DEBOUNCE_MASK << 1) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 2 | |||||
case ((DEBOUNCE_MASK << 2) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 3 | |||||
case ((DEBOUNCE_MASK << 3) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 4 | |||||
case ((DEBOUNCE_MASK << 4) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 5 | |||||
case ((DEBOUNCE_MASK << 5) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 6 | |||||
case ((DEBOUNCE_MASK << 6) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 7 | |||||
case ((DEBOUNCE_MASK << 7) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 8 | |||||
case ((DEBOUNCE_MASK << 8) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 9 | |||||
case ((DEBOUNCE_MASK << 9) & DEBOUNCE_MASK): | |||||
#if DEBOUNCE > 10 | |||||
case ((DEBOUNCE_MASK << 10) & DEBOUNCE_MASK): | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
#endif | |||||
break; | |||||
case 0: | |||||
if ((*row & mask) != 0) { | |||||
*row &= ~mask; | |||||
} | |||||
break; | |||||
default: | |||||
debug("bounce!: "); | |||||
debug_bin8(*debounce & DEBOUNCE_MASK); | |||||
debug("\n"); | |||||
break; | |||||
} | |||||
} | |||||
unselect_rows(); | |||||
} | |||||
matrix_current_row++; | |||||
if (matrix_current_row >= matrix_rows()) { | |||||
matrix_current_row = 0; | |||||
} | |||||
#else | |||||
for (uint8_t i = 0; i < matrix_rows(); i++) { | |||||
select_row(i); | |||||
_delay_us(30); // without this wait read unstable value. | |||||
matrix_row_t cols = read_row(); | |||||
if (matrix_debouncing[i] != cols) { | |||||
matrix_debouncing[i] = cols; | |||||
if (debouncing) { | |||||
debug("bounce!: "); debug_hex(debouncing); debug("\n"); | |||||
} | |||||
debouncing = DEBOUNCE; | |||||
} | |||||
unselect_rows(); | |||||
} | |||||
if (debouncing) { | |||||
if (--debouncing) { | |||||
_delay_ms(1); | |||||
} else { | |||||
for (uint8_t i = 0; i < matrix_rows(); i++) { | |||||
matrix[i] = matrix_debouncing[i]; | |||||
} | |||||
} | |||||
} | |||||
#endif | |||||
return 1; | |||||
} | |||||
#if IMPROVED_DEBOUNCE | |||||
#else | |||||
bool matrix_is_modified(void) | |||||
{ | |||||
if (debouncing) return false; | |||||
return true; | |||||
} | |||||
#endif | |||||
inline | |||||
bool matrix_is_on(uint8_t row, uint8_t col) | |||||
{ | |||||
return (matrix[row] & ((matrix_row_t)1<<col)); | |||||
} | |||||
inline | |||||
matrix_row_t matrix_get_row(uint8_t row) | |||||
{ | |||||
return matrix[row]; | |||||
} | |||||
void matrix_print(void) | |||||
{ | |||||
print("\nr/c 0123456789ABCDEF\n"); | |||||
for (uint8_t row = 0; row < matrix_rows(); row++) { | |||||
phex(row); print(": "); | |||||
print_bin_reverse32(matrix_get_row(row)); | |||||
print("\n"); | |||||
} | |||||
} | |||||
uint8_t matrix_key_count(void) | |||||
{ | |||||
uint8_t count = 0; | |||||
for (uint8_t i = 0; i < matrix_rows(); i++) { | |||||
count += bitpop32(matrix[i]); | |||||
} | |||||
return count; | |||||
} | |||||
/* Column pin configuration | |||||
* col: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 | |||||
* pin: EX EX EX EX EX EX EX D3 D2 D4 C6 D7 E6 B4 | |||||
*/ | |||||
static void init_cols(void) | |||||
{ | |||||
// Input with pull-up(DDR:0, PORT:1) | |||||
DDRE &= ~(1<<PE6); | |||||
PORTE |= (1<<PE6); | |||||
DDRD &= ~(1<<PD2 | 1<<PD3 | 1<<PD4 | 1<<PD7); | |||||
PORTD |= (1<<PD2 | 1<<PD3 | 1<<PD4 | 1<<PD7); | |||||
DDRC &= ~(1<<PC6); | |||||
PORTC |= (1<<PC6); | |||||
DDRB &= ~(1<<PB4); | |||||
PORTB |= (1<<PB4); | |||||
// Init I/O expander | |||||
expander_init(); | |||||
} | |||||
#if !IMPROVED_DEBOUNCE | |||||
static matrix_row_t read_row(void) | |||||
{ | |||||
return expander_read_row() | | |||||
(PIND&(1<<PD3) ? 0 : (1<<7)) | | |||||
(PIND&(1<<PD2) ? 0 : (1<<8)) | | |||||
(PIND&(1<<PD4) ? 0 : (1<<9)) | | |||||
(PINC&(1<<PC6) ? 0 : (1<<10)) | | |||||
(PIND&(1<<PD7) ? 0 : (1<<11)) | | |||||
(PINE&(1<<PE6) ? 0 : (1<<12)) | | |||||
(PINB&(1<<PB4) ? 0 : (1<<13)); | |||||
} | |||||
#endif | |||||
static void read_cols(void) | |||||
{ | |||||
expander_read_cols(); | |||||
} | |||||
static uint8_t get_col(uint8_t col) | |||||
{ | |||||
switch (col) { | |||||
#ifdef VER_PROTOTYPE | |||||
case 0 ... 6: | |||||
return expander_get_col(col); | |||||
case 7: | |||||
return PIND&(1<<PD3) ? 0 : 1; | |||||
case 8: | |||||
return PIND&(1<<PD2) ? 0 : 1; | |||||
case 9: | |||||
return PIND&(1<<PD4) ? 0 : 1; | |||||
case 10: | |||||
return PINC&(1<<PC6) ? 0 : 1; | |||||
case 11: | |||||
return PIND&(1<<PD7) ? 0 : 1; | |||||
case 12: | |||||
return PINE&(1<<PE6) ? 0 : 1; | |||||
case 13: | |||||
return PINB&(1<<PB4) ? 0 : 1; | |||||
#else | |||||
case 0: | |||||
return PINB&(1<<PB4) ? 0 : 1; | |||||
case 1: | |||||
return PINE&(1<<PE6) ? 0 : 1; | |||||
case 2: | |||||
return PIND&(1<<PD7) ? 0 : 1; | |||||
case 3: | |||||
return PINC&(1<<PC6) ? 0 : 1; | |||||
case 4: | |||||
return PIND&(1<<PD4) ? 0 : 1; | |||||
case 5: | |||||
return PIND&(1<<PD2) ? 0 : 1; | |||||
case 6: | |||||
return PIND&(1<<PD3) ? 0 : 1; | |||||
case 7 ... 13: | |||||
return expander_get_col(13 - col); | |||||
#endif | |||||
default: | |||||
return 0; | |||||
} | |||||
} | |||||
/* Row pin configuration | |||||
* row: 0 1 2 3 4 5 | |||||
* pin: F4 F5 F6 F7 B1 B2 | |||||
*/ | |||||
static void unselect_rows(void) | |||||
{ | |||||
// Hi-Z(DDR:0, PORT:0) to unselect | |||||
DDRF &= ~(1<<PF4 | 1<<PF5 | 1<<PF6 | 1<<PF7); | |||||
PORTF &= ~(1<<PF4 | 1<<PF5 | 1<<PF6 | 1<<PF7); | |||||
DDRB &= ~(1<<PB1 | 1<<PB2); | |||||
PORTB &= ~(1<<PB1 | 1<<PB2); | |||||
// I/O expander | |||||
expander_unselect_rows(); | |||||
} | |||||
static void select_row(uint8_t row) | |||||
{ | |||||
// Output low(DDR:1, PORT:0) to select | |||||
switch (row) { | |||||
case 0: | |||||
DDRF |= (1<<PF4); | |||||
PORTF &= ~(1<<PF4); | |||||
break; | |||||
case 1: | |||||
DDRF |= (1<<PF5); | |||||
PORTF &= ~(1<<PF5); | |||||
break; | |||||
case 2: | |||||
DDRF |= (1<<PF6); | |||||
PORTF &= ~(1<<PF6); | |||||
break; | |||||
case 3: | |||||
DDRF |= (1<<PF7); | |||||
PORTF &= ~(1<<PF7); | |||||
break; | |||||
case 4: | |||||
DDRB |= (1<<PB1); | |||||
PORTB &= ~(1<<PB1); | |||||
break; | |||||
case 5: | |||||
DDRB |= (1<<PB2); | |||||
PORTB &= ~(1<<PB2); | |||||
break; | |||||
} | |||||
// I/O expander | |||||
expander_select_row(row); | |||||
} |
/************************************************************************* | |||||
* 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 <util/delay.h> | |||||
#include <i2cmaster.h> | |||||
#include "timer.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 | |||||
#define SCL_DURATION (1000000L/SCL_CLOCK)/2 | |||||
volatile uint8_t i2c_force_stop = 0; | |||||
#define TIMEOUT 3000 | |||||
#define CHECK_FORCE_STOP() if(i2c_force_stop){i2c_force_stop=0;break;} | |||||
#define CHECK_TIMEOUT_PRE() \ | |||||
uint16_t start; \ | |||||
uint8_t once = 1; | |||||
#define CHECK_TIMEOUT_PRE2() \ | |||||
once = 1; | |||||
#define CHECK_TIMEOUT(retval) { \ | |||||
if (once) { \ | |||||
start = timer_read(); \ | |||||
once = 0; \ | |||||
} \ | |||||
else { \ | |||||
if (timer_elapsed(start) >= TIMEOUT) { \ | |||||
i2c_forceStop(); \ | |||||
return retval; \ | |||||
} \ | |||||
} \ | |||||
} | |||||
static void i2c_forceStop(void); | |||||
/************************************************************************* | |||||
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 | |||||
CHECK_TIMEOUT_PRE(); | |||||
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2); }; | |||||
// 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 | |||||
CHECK_TIMEOUT_PRE2(); | |||||
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2); }; | |||||
// 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 | |||||
CHECK_TIMEOUT_PRE(); | |||||
while(TWCR & (1<<TWSTO)) { CHECK_TIMEOUT(); }; | |||||
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 | |||||
CHECK_TIMEOUT_PRE(); | |||||
while(TWCR & (1<<TWSTO)) { CHECK_TIMEOUT(); }; | |||||
}/* 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 | |||||
CHECK_TIMEOUT_PRE(); | |||||
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2) }; | |||||
// 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); | |||||
CHECK_TIMEOUT_PRE(); | |||||
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2); }; | |||||
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); | |||||
CHECK_TIMEOUT_PRE(); | |||||
while(!(TWCR & (1<<TWINT))) { CHECK_TIMEOUT(2); }; | |||||
return TWDR; | |||||
}/* i2c_readNak */ | |||||
void i2c_forceStop(void) | |||||
{ | |||||
xprintf("i2c timeout\n"); | |||||
/* let slave to release SDA */ | |||||
TWCR = 0; | |||||
DDRD |= (1<<PD0); | |||||
DDRD &= ~(1<<PD1); | |||||
_delay_us(30); | |||||
if ((PIND & (1<<PD1)) == 0) { | |||||
for (uint8_t i = 0; i < 9; i++) { | |||||
PORTD &= ~(1<<PD0); | |||||
_delay_us(SCL_DURATION); | |||||
PORTD |= (1<<PD0); | |||||
_delay_us(SCL_DURATION); | |||||
} | |||||
} | |||||
DDRD &= ~(1<<PD0); | |||||
/* send stop condition */ | |||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); | |||||
} |