ergodone: Initial working version
This commit is contained in:
parent
70c15dd083
commit
d5a709a057
160
keyboard/ergodone/Makefile
Normal file
160
keyboard/ergodone/Makefile
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# 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
|
127
keyboard/ergodone/Makefile.pjrc
Normal file
127
keyboard/ergodone/Makefile.pjrc
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# 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
|
208
keyboard/ergodone/backlight.c
Normal file
208
keyboard/ergodone/backlight.c
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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
|
100
keyboard/ergodone/config.h
Normal file
100
keyboard/ergodone/config.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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
|
137
keyboard/ergodone/expander.c
Normal file
137
keyboard/ergodone/expander.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
65
keyboard/ergodone/expander.h
Normal file
65
keyboard/ergodone/expander.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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
|
178
keyboard/ergodone/i2cmaster.h
Normal file
178
keyboard/ergodone/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
|
53
keyboard/ergodone/keymap_common.c
Normal file
53
keyboard/ergodone/keymap_common.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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
|
43
keyboard/ergodone/keymap_common.h
Normal file
43
keyboard/ergodone/keymap_common.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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
|
107
keyboard/ergodone/keymap_default.c
Normal file
107
keyboard/ergodone/keymap_default.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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
|
55
keyboard/ergodone/led.c
Normal file
55
keyboard/ergodone/led.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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
|
88
keyboard/ergodone/ledmap.c
Normal file
88
keyboard/ergodone/ledmap.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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
|
415
keyboard/ergodone/matrix.c
Normal file
415
keyboard/ergodone/matrix.c
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 Kai Ryu <kai1103@gmail.com>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
258
keyboard/ergodone/twimaster.c
Normal file
258
keyboard/ergodone/twimaster.c
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* 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 <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);
|
||||||
|
}
|
Reference in New Issue
Block a user