foobar rgb underglow
This commit is contained in:
parent
02054bf45f
commit
21d8a47e4d
173
keyboard/foobar_rgb/Makefile
Normal file
173
keyboard/foobar_rgb/Makefile
Normal file
@ -0,0 +1,173 @@
|
||||
#----------------------------------------------------------------------------
|
||||
# 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 = foobar
|
||||
|
||||
# Directory common source filess exist
|
||||
TMK_DIR = ../../tmk_core
|
||||
|
||||
# Directory keyboard dependent files exist
|
||||
TARGET_DIR = .
|
||||
|
||||
# project specific files
|
||||
SRC = matrix.c \
|
||||
i2c.c \
|
||||
serial.c \
|
||||
split-util.c \
|
||||
led.c \
|
||||
rgblight.c \
|
||||
light_ws2812.c
|
||||
|
||||
CONFIG_H = config.h
|
||||
|
||||
# MCU name
|
||||
MCU = atmega32u4
|
||||
|
||||
COM_PORT=/dev/ttyACM0
|
||||
PROGRAM_CMD=sleep 3; avrdude -p atmega32u4 -P $(COM_PORT) -c avr109 -U flash:w:$(TARGET).hex
|
||||
|
||||
# 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
|
||||
|
||||
# Changes some bootmagic settings for when the space is on the left half
|
||||
OPT_DEFS += -DSPACE_ON_LEFT_HALF
|
||||
|
||||
# # Use I2C for communication between the halves of the keyboard
|
||||
# OPT_DEFS += -DUSE_I2C
|
||||
|
||||
# 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
|
||||
ACTIONMAP_ENABLE = yes # Use 16bit action codes in keymap instead of 8bit keycodes
|
||||
|
||||
|
||||
ifdef ACTIONMAP_ENABLE
|
||||
KEYMAP_FILE = actionmap
|
||||
else
|
||||
KEYMAP_FILE = keymap
|
||||
SRC := keymap_common.c $(SRC)
|
||||
endif
|
||||
ifdef KEYMAP
|
||||
SRC := $(KEYMAP_FILE)_$(KEYMAP).c $(SRC)
|
||||
else
|
||||
SRC := $(KEYMAP_FILE)_plain.c $(SRC)
|
||||
endif
|
||||
|
||||
|
||||
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
|
||||
#PS2_USE_BUSYWAIT = yes # uses primitive reference code
|
||||
#PS2_USE_INT = yes # uses external interrupt for falling edge of PS/2 clock pin
|
||||
#PS2_USE_USART = yes # uses hardware USART engine for PS/2 signal receive(recomened)
|
||||
|
||||
|
||||
# Search Path
|
||||
VPATH += $(TARGET_DIR)
|
||||
VPATH += $(TMK_DIR)
|
||||
|
||||
# Un comment this line if you want to use pjrc protocol
|
||||
# include $(TMK_DIR)/protocol/pjrc.mk
|
||||
|
||||
include $(TMK_DIR)/protocol/lufa.mk
|
||||
include $(TMK_DIR)/common.mk
|
||||
include $(TMK_DIR)/rules.mk
|
||||
|
||||
|
||||
debug-on: EXTRAFLAGS += -DDEBUG -DDEBUG_ACTION
|
||||
debug-on: all
|
||||
|
||||
debug-off: EXTRAFLAGS += -DNO_DEBUG -DNO_PRINT
|
||||
debug-off: OPT_DEFS := $(filter-out -DCONSOLE_ENABLE,$(OPT_DEFS))
|
||||
debug-off: all
|
||||
|
||||
eeprom-left:
|
||||
sleep 3; avrdude -p atmega32u4 -P $(COM_PORT) -c avr109 -U eeprom:w:eeprom-lefthand.eep
|
||||
|
||||
eeprom-right:
|
||||
sleep 3; avrdude -p atmega32u4 -P $(COM_PORT) -c avr109 -U eeprom:w:eeprom-righthand.eep
|
99
keyboard/foobar_rgb/README.md
Normal file
99
keyboard/foobar_rgb/README.md
Normal file
@ -0,0 +1,99 @@
|
||||
This is a modification of the TMK firmware by ahtn found here https://github.com/ahtn/tmk_keyboard/tree/master/keyboard/split_keyboard
|
||||
|
||||
Custom split keyboard firmware
|
||||
======
|
||||
|
||||
Split keyboard firmware for Arduino Pro Micro or other ATmega32u4
|
||||
based boards.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Some features supported by the firmware:
|
||||
|
||||
* Either half can connect to the computer via USB, or both halves can be used
|
||||
independently.
|
||||
* You only need 3 wires to connect the two halves. Two for VCC and GND and one
|
||||
for serial communication.
|
||||
* Optional support for I2C connection between the two halves if for some
|
||||
reason you require a faster connection between the two halves. Note this
|
||||
requires an extra wire between halves and pull-up resistors on the data lines.
|
||||
|
||||
Required Hardware
|
||||
-----------------
|
||||
|
||||
Apart from diodes and key switches for the keyboard matrix in each half, you
|
||||
will need:
|
||||
|
||||
* 2 Arduino Pro Micro's. You can find theses on aliexpress for ≈3.50USD each.
|
||||
* 2 TRS sockets
|
||||
* 1 TRS cable.
|
||||
|
||||
Alternatively, you can use any sort of cable and socket that has at least 3
|
||||
wires. If you want to use I2C to communicate between halves, you will need a
|
||||
cable with at least 4 wires and 2x 4.7kΩ pull-up resistors
|
||||
|
||||
|
||||
Wiring
|
||||
------
|
||||
|
||||
The 3 wires of the TRS cable need to connect GND, VCC, and digital pin 3 (i.e.
|
||||
`PD0` on the ATmega32u4) between the two Pro Micros.
|
||||
|
||||
Then wire your key matrix to any of the remaining 17 IO pins of the pro micro
|
||||
and modify the `MATRIX_COL_PINS` and `MATRIX_ROW_PINS` in `config.h` accordingly.
|
||||
|
||||
The wiring for serial:
|
||||
|
||||
![serial wiring](imgs/split-keyboard-serial-schematic.png)
|
||||
|
||||
The wiring for i2c:
|
||||
|
||||
![i2c wiring](imgs/split-keyboard-i2c-schematic.png)
|
||||
|
||||
The pull-up resistors may be placed on either half. It is also possible
|
||||
to use 4 resistors and have the pull-ups in both halves, but this is
|
||||
unnecessary in simple use cases.
|
||||
|
||||
Notes on Software Configuration
|
||||
-------------------------------
|
||||
|
||||
Configuring the firmware is similar to any other TMK project. One thing
|
||||
to note is that `MATIX_ROWS` in `config.h` is the total number of rows between
|
||||
the two halves, i.e. if your split keyboard has 4 rows in each half, then
|
||||
`MATRIX_ROWS=8`.
|
||||
|
||||
Also the current implementation assumes a maximum of 8 columns, but it would
|
||||
not be very difficult to adapt it to support more if required.
|
||||
|
||||
|
||||
Flashing
|
||||
--------
|
||||
|
||||
Before you go to flash the program memory for the first time, you will need to
|
||||
EEPROM for the left and right halves. The EEPROM is used to store whether the
|
||||
half is left handed or right handed. This makes it so that the same firmware
|
||||
file will run on both hands instead of having to flash left and right handed
|
||||
versions of the firmware to each half. To flash the EEPROM file for the left
|
||||
half run:
|
||||
```
|
||||
make eeprom-left
|
||||
```
|
||||
and similarly for right half
|
||||
```
|
||||
make eeprom-right
|
||||
```
|
||||
|
||||
After you have flashed the EEPROM for the first time, you then need to program
|
||||
the flash memory:
|
||||
```
|
||||
make program
|
||||
```
|
||||
Note that you need to program both halves, but you have the option of using
|
||||
different keymaps for each half. You could program the left half with a QWERTY
|
||||
layout and the right half with a Colemak layout. Then if you connect the left
|
||||
half to a computer by USB the keyboard will use QWERTY and Colemak when the
|
||||
right half is connected.
|
||||
|
||||
|
35
keyboard/foobar_rgb/actionmap_common.h
Normal file
35
keyboard/foobar_rgb/actionmap_common.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef ACTIONMAP_COMMON_H
|
||||
#define ACTIONMAP_COMMON_H
|
||||
|
||||
#include "rgblight.h"
|
||||
|
||||
enum function_id {
|
||||
RGBLED_TOGGLE,
|
||||
RGBLED_STEP_MODE,
|
||||
RGBLED_INCREASE_HUE,
|
||||
RGBLED_DECREASE_HUE,
|
||||
RGBLED_INCREASE_SAT,
|
||||
RGBLED_DECREASE_SAT,
|
||||
RGBLED_INCREASE_VAL,
|
||||
RGBLED_DECREASE_VAL,
|
||||
};
|
||||
|
||||
#define ACTIONMAP( \
|
||||
K00, K01, K02, K03, K04, \
|
||||
K10, K11, K12, K13, K14, \
|
||||
K20, K21, K22, K23, K24, \
|
||||
\
|
||||
K30, K31, K32, K33, K34, \
|
||||
K40, K41, K42, K43, K44, \
|
||||
K50, K51, K52, K53, K54 \
|
||||
) { \
|
||||
{ AC_##K00, AC_##K01, AC_##K02, AC_##K03, AC_##K04 }, \
|
||||
{ AC_##K10, AC_##K11, AC_##K12, AC_##K13, AC_##K14 }, \
|
||||
{ AC_##K20, AC_##K21, AC_##K22, AC_##K23, AC_##K24 }, \
|
||||
\
|
||||
{ AC_##K34, AC_##K33, AC_##K32, AC_##K31, AC_##K30 }, \
|
||||
{ AC_##K44, AC_##K43, AC_##K42, AC_##K41, AC_##K40 }, \
|
||||
{ AC_##K54, AC_##K53, AC_##K52, AC_##K51, AC_##K50 } \
|
||||
}
|
||||
|
||||
#endif
|
149
keyboard/foobar_rgb/actionmap_plain.c
Normal file
149
keyboard/foobar_rgb/actionmap_plain.c
Normal file
@ -0,0 +1,149 @@
|
||||
#include "actionmap.h"
|
||||
#include "action_code.h"
|
||||
#include "actionmap_common.h"
|
||||
#include "rgblight.h"
|
||||
|
||||
/*
|
||||
* Actions
|
||||
*/
|
||||
#define AC_BLD ACTION_BACKLIGHT_DECREASE()
|
||||
#define AC_BLI ACTION_BACKLIGHT_INCREASE()
|
||||
#define AC_TL1 ACTION_LAYER_TAP_KEY(1, KC_SPACE)
|
||||
#define AC_TL2 ACTION_LAYER_TAP_KEY(2, KC_BSPACE)
|
||||
#define AC_TL3 ACTION_LAYER_TAP_KEY(3, KC_C)
|
||||
#define AC_TL4 ACTION_LAYER_TAP_KEY(4, KC_V)
|
||||
#define AC_TL5 ACTION_LAYER_TAP_KEY(5, KC_B)
|
||||
#define AC_TM1 ACTION_MODS_TAP_KEY(MOD_RSFT, KC_ENT)
|
||||
#define AC_TM2 ACTION_MODS_TAP_KEY(MOD_LCTL, KC_Z)
|
||||
#define AC_TM3 ACTION_MODS_TAP_KEY(MOD_LALT, KC_X)
|
||||
#define AC_TM4 ACTION_MODS_TAP_KEY(MOD_RALT, KC_N)
|
||||
#define AC_TM5 ACTION_MODS_TAP_KEY(MOD_RCTL, KC_M)
|
||||
#define AC_S01 ACTION_MODS_KEY(MOD_LSFT, KC_1)
|
||||
#define AC_S02 ACTION_MODS_KEY(MOD_LSFT, KC_2)
|
||||
#define AC_S03 ACTION_MODS_KEY(MOD_LSFT, KC_3)
|
||||
#define AC_S04 ACTION_MODS_KEY(MOD_LSFT, KC_4)
|
||||
#define AC_S05 ACTION_MODS_KEY(MOD_LSFT, KC_5)
|
||||
#define AC_S06 ACTION_MODS_KEY(MOD_LSFT, KC_6)
|
||||
#define AC_S07 ACTION_MODS_KEY(MOD_LSFT, KC_7)
|
||||
#define AC_S08 ACTION_MODS_KEY(MOD_LSFT, KC_8)
|
||||
#define AC_S09 ACTION_MODS_KEY(MOD_LSFT, KC_9)
|
||||
#define AC_S10 ACTION_MODS_KEY(MOD_LSFT, KC_0)
|
||||
#define AC_S11 ACTION_MODS_KEY(MOD_LSFT, KC_MINS)
|
||||
#define AC_S12 ACTION_MODS_KEY(MOD_LSFT, KC_EQL)
|
||||
#define AC_S13 ACTION_MODS_KEY(MOD_LSFT, KC_LBRC)
|
||||
#define AC_S14 ACTION_MODS_KEY(MOD_LSFT, KC_RBRC)
|
||||
#define AC_S15 ACTION_MODS_KEY(MOD_LSFT, KC_BSLS)
|
||||
#define AC_S16 ACTION_MODS_KEY(MOD_LSFT, KC_COMM)
|
||||
#define AC_S17 ACTION_MODS_KEY(MOD_LSFT, KC_DOT)
|
||||
#define AC_S18 ACTION_MODS_KEY(MOD_LSFT, KC_SLSH)
|
||||
#define AC_S19 ACTION_MODS_KEY(MOD_LSFT, KC_SCLN)
|
||||
#define AC_S20 ACTION_MODS_KEY(MOD_LSFT, KC_QUOT)
|
||||
#define AC_L01 ACTION_FUNCTION(RGBLED_TOGGLE)
|
||||
#define AC_L02 ACTION_FUNCTION(RGBLED_STEP_MODE)
|
||||
#define AC_L03 ACTION_FUNCTION(RGBLED_INCREASE_HUE)
|
||||
#define AC_L04 ACTION_FUNCTION(RGBLED_DECREASE_HUE)
|
||||
#define AC_L05 ACTION_FUNCTION(RGBLED_INCREASE_SAT)
|
||||
#define AC_L06 ACTION_FUNCTION(RGBLED_DECREASE_SAT)
|
||||
#define AC_L07 ACTION_FUNCTION(RGBLED_INCREASE_VAL)
|
||||
#define AC_L08 ACTION_FUNCTION(RGBLED_DECREASE_VAL)
|
||||
|
||||
const action_t PROGMEM actionmaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[0] = ACTIONMAP(
|
||||
Q, W, E, R, T,
|
||||
A, S, D, F, G,
|
||||
TM2, TM3, TL3, TL4, TL2,
|
||||
|
||||
Y, U, I, O, P,
|
||||
H, J, K, L, ESC,
|
||||
TL1, TL5, TM4, TM5, TM1),
|
||||
|
||||
[1] = ACTIONMAP(
|
||||
1, 2, 3, 4, 5,
|
||||
F1, F2, F3, F4, F5,
|
||||
TRNS, TRNS, TRNS, TRNS, DEL,
|
||||
|
||||
6, 7, 8, 9, 0,
|
||||
F6, F7, F8, F9, F10,
|
||||
TRNS, TRNS, TRNS, TRNS, TRNS),
|
||||
|
||||
[2] = ACTIONMAP(
|
||||
S01, S02, S03, S04, S05,
|
||||
F11, F12, TRNS, TRNS, TRNS,
|
||||
TRNS, TRNS, TRNS, TRNS, TRNS,
|
||||
|
||||
S06, S07, S08, S09, S10,
|
||||
TRNS, TRNS, TRNS, TRNS, GRV,
|
||||
TRNS, TRNS, TRNS, TRNS, TRNS),
|
||||
|
||||
[3] = ACTIONMAP(
|
||||
TRNS, TRNS, TRNS, TRNS, TRNS,
|
||||
TAB, TRNS, TRNS, TRNS, TRNS,
|
||||
TRNS, TRNS, TRNS, TRNS, TRNS,
|
||||
|
||||
MINS, EQL, LBRC, RBRC, BSLS,
|
||||
COMM, DOT, SLSH, SCLN, QUOT,
|
||||
TRNS, LEFT, DOWN, UP, RGHT),
|
||||
|
||||
[4] = ACTIONMAP(
|
||||
TRNS, TRNS, TRNS, TRNS, TRNS,
|
||||
TAB, TRNS, TRNS, TRNS, TRNS,
|
||||
TRNS, TRNS, TRNS, TRNS, TRNS,
|
||||
|
||||
S11, S12, S13, S14, S15,
|
||||
S16, S17, S18, S19, S20,
|
||||
TRNS, HOME, PGDN, PGUP, END),
|
||||
|
||||
[5] = ACTIONMAP(
|
||||
CALC, WHOM, MAIL, MYCM, TRNS,
|
||||
L01, L02, L03, L04, L05,
|
||||
TRNS, TRNS, TRNS, TRNS, BTLD,
|
||||
|
||||
TRNS, TRNS, TRNS, TRNS, PSCR,
|
||||
L06, L07, L08, BLD, BLI,
|
||||
TRNS, TRNS, TRNS, TRNS, TRNS),
|
||||
};
|
||||
|
||||
void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) {
|
||||
switch (id) {
|
||||
case RGBLED_TOGGLE:
|
||||
if (record->event.pressed) {
|
||||
rgblight_toggle();
|
||||
}
|
||||
break;
|
||||
case RGBLED_INCREASE_HUE:
|
||||
if (record->event.pressed) {
|
||||
rgblight_increase_hue();
|
||||
}
|
||||
break;
|
||||
case RGBLED_DECREASE_HUE:
|
||||
if (record->event.pressed) {
|
||||
rgblight_decrease_hue();
|
||||
}
|
||||
break;
|
||||
case RGBLED_INCREASE_SAT:
|
||||
if (record->event.pressed) {
|
||||
rgblight_increase_sat();
|
||||
}
|
||||
break;
|
||||
case RGBLED_DECREASE_SAT:
|
||||
if (record->event.pressed) {
|
||||
rgblight_decrease_sat();
|
||||
}
|
||||
break;
|
||||
case RGBLED_INCREASE_VAL:
|
||||
if (record->event.pressed) {
|
||||
rgblight_increase_val();
|
||||
}
|
||||
break;
|
||||
case RGBLED_DECREASE_VAL:
|
||||
if (record->event.pressed) {
|
||||
rgblight_decrease_val();
|
||||
}
|
||||
break;
|
||||
case RGBLED_STEP_MODE:
|
||||
if (record->event.pressed) {
|
||||
rgblight_step();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
129
keyboard/foobar_rgb/config.h
Normal file
129
keyboard/foobar_rgb/config.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright 2012 Jun Wako <wakojun@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 0xFEED
|
||||
#define PRODUCT_ID 0x0A0C
|
||||
#define DEVICE_VER 0x0F00
|
||||
#define MANUFACTURER di0ib
|
||||
#define PRODUCT The foobar Keyboard
|
||||
#define DESCRIPTION A split 30 key keyboard
|
||||
|
||||
/* key matrix size */
|
||||
#define ROWS_PER_HAND 3
|
||||
#define MATRIX_COLS 5
|
||||
|
||||
#define MATRIX_ROWS ROWS_PER_HAND*2
|
||||
|
||||
#define MATRIX_COL_PINS { F6, F7, B1, B3, B2 }
|
||||
#define MATRIX_ROW_PINS { D7, E6, B4 }
|
||||
|
||||
|
||||
/* use i2c instead of serial */
|
||||
//#define USE_I2C
|
||||
|
||||
//#define I2C_WRITE_TEST_CODE
|
||||
|
||||
/* define if matrix has ghost */
|
||||
//#define MATRIX_HAS_GHOST
|
||||
|
||||
/* Set 0 if debouncing isn't needed */
|
||||
#define DEBOUNCE 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
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/* key combination for command */
|
||||
#define IS_COMMAND() ( \
|
||||
keyboard_report->mods == (MOD_BIT(KC_LCTL) | MOD_BIT(KC_LALT) | MOD_BIT(KC_LGUI)) \
|
||||
)
|
||||
|
||||
/* ws2812 RGB LED */
|
||||
#define ws2812_PORTREG PORTB
|
||||
#define ws2812_DDRREG DDRB
|
||||
#define ws2812_pin PB6
|
||||
#define RGBLED_NUM 4 // Number of LEDs
|
||||
#ifndef RGBLIGHT_HUE_STEP
|
||||
#define RGBLIGHT_HUE_STEP 10
|
||||
#endif
|
||||
#ifndef RGBLIGHT_SAT_STEP
|
||||
#define RGBLIGHT_SAT_STEP 17
|
||||
#endif
|
||||
#ifndef RGBLIGHT_VAL_STEP
|
||||
#define RGBLIGHT_VAL_STEP 17
|
||||
#endif
|
||||
|
||||
|
||||
/* boot magic key */
|
||||
#define BOOTMAGIC_KEY_SALT KC_Q
|
||||
|
||||
#ifdef SPACE_ON_LEFT_HALF
|
||||
#define BOOTMAGIC_KEY_DEFAULT_LAYER_0 KC_Z
|
||||
#define BOOTMAGIC_KEY_DEFAULT_LAYER_1 KC_X
|
||||
#define BOOTMAGIC_KEY_DEFAULT_LAYER_2 KC_C
|
||||
#define BOOTMAGIC_HOST_NKRO KC_V
|
||||
#else
|
||||
#define BOOTMAGIC_KEY_DEFAULT_LAYER_0 KC_M
|
||||
#define BOOTMAGIC_KEY_DEFAULT_LAYER_1 KC_COMM
|
||||
#define BOOTMAGIC_KEY_DEFAULT_LAYER_2 KC_DOT
|
||||
#define BOOTMAGIC_HOST_NKRO KC_N
|
||||
#endif
|
||||
|
||||
/* Mousekey settings */
|
||||
#define MOUSEKEY_MOVE_MAX 127 // default 127
|
||||
#define MOUSEKEY_WHEEL_MAX 127 // default 127
|
||||
#define MOUSEKEY_MOVE_DELTA 5 // default 5
|
||||
#define MOUSEKEY_WHEEL_DELTA 1 // default 1
|
||||
#define MOUSEKEY_DELAY 300 // default 300
|
||||
#define MOUSEKEY_INTERVAL 50 // default 50
|
||||
#define MOUSEKEY_MAX_SPEED 5 // default 10
|
||||
#define MOUSEKEY_TIME_TO_MAX 10 // default 20
|
||||
#define MOUSEKEY_WHEEL_MAX_SPEED 8 // default 8
|
||||
#define MOUSEKEY_WHEEL_TIME_TO_MAX 40 // default 40
|
||||
|
||||
/* Action tapping settings */
|
||||
#define TAPPING_TERM 200 // default 200
|
||||
/* #define TAPPING_TOGGLE 2 // default 5 */
|
||||
/* #define ONESHOT_TIMEOUT 5000 // default undefined */
|
||||
#define ONESHOT_TAP_TOGGLE 2
|
||||
|
||||
#endif
|
223
keyboard/foobar_rgb/i2c.c
Normal file
223
keyboard/foobar_rgb/i2c.c
Normal file
@ -0,0 +1,223 @@
|
||||
#include <util/twi.h>
|
||||
#include <avr/io.h>
|
||||
#include <stdlib.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/twi.h>
|
||||
#include <stdbool.h>
|
||||
#include "i2c.h"
|
||||
|
||||
#define I2C_READ 1
|
||||
#define I2C_WRITE 0
|
||||
|
||||
#define I2C_ACK 1
|
||||
#define I2C_NACK 0
|
||||
|
||||
// Limits the amount of we wait for any one i2c transaction.
|
||||
// Since were running SCL line 100kHz (=> 10μs/bit), and each transactions is
|
||||
// 9 bits, a single transaction will take around 90μs to complete.
|
||||
//
|
||||
// (F_CPU/SCL_CLOCK) => # of mcu cycles to transfer a bit
|
||||
// poll loop takes at least 8 clock cycles to execute
|
||||
#define I2C_LOOP_TIMEOUT (9+1)*(F_CPU/SCL_CLOCK)/8
|
||||
|
||||
#define BUFFER_POS_INC() (slave_buffer_pos = (slave_buffer_pos+1)%SLAVE_BUFFER_SIZE)
|
||||
|
||||
static volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE] = {0};
|
||||
|
||||
static volatile uint8_t slave_buffer_pos;
|
||||
static volatile bool slave_has_register_set = false;
|
||||
|
||||
static uint8_t i2c_start(uint8_t address);
|
||||
static void i2c_stop(void);
|
||||
static uint8_t i2c_write(uint8_t data);
|
||||
static uint8_t i2c_read(uint8_t ack);
|
||||
|
||||
// Wait for an i2c operation to finish
|
||||
inline static
|
||||
void i2c_delay(void) {
|
||||
uint16_t lim = 0;
|
||||
while(!(TWCR & (1<<TWINT)) && lim < I2C_LOOP_TIMEOUT)
|
||||
lim++;
|
||||
|
||||
// easier way, but will wait slightly longer
|
||||
// _delay_us(100);
|
||||
}
|
||||
|
||||
// i2c_device_addr: the i2c device to communicate with
|
||||
// addr: the memory address to read from the i2c device
|
||||
// dest: pointer to where read data is saved
|
||||
// len: the number of bytes to read
|
||||
//
|
||||
// NOTE: on error, the data in dest may have been modified
|
||||
bool i2c_master_read(uint8_t i2c_device_addr, uint8_t addr, uint8_t *dest, uint8_t len) {
|
||||
bool err;
|
||||
if (len == 0) return 0;
|
||||
|
||||
err = i2c_start(i2c_device_addr + I2C_WRITE);
|
||||
if (err) return err;
|
||||
err = i2c_write(addr);
|
||||
if (err) return err;
|
||||
|
||||
err = i2c_start(i2c_device_addr + I2C_READ);
|
||||
if (err) return err;
|
||||
|
||||
for (uint8_t i = 0; i < len-1; ++i) {
|
||||
dest[i] = i2c_read(I2C_ACK);
|
||||
}
|
||||
dest[len-1] = i2c_read(I2C_NACK);
|
||||
i2c_stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// i2c_device_addr: the i2c device to communicate with
|
||||
// addr: the memory address at which to write in the i2c device
|
||||
// data: the data to be written
|
||||
// len: the number of bytes to write
|
||||
bool i2c_master_write(uint8_t i2c_device_addr, uint8_t addr, uint8_t *data, uint8_t len) {
|
||||
bool err;
|
||||
|
||||
if (len == 0) return 0;
|
||||
|
||||
err = i2c_start(i2c_device_addr + I2C_WRITE);
|
||||
if (err) return err;
|
||||
err = i2c_write(addr);
|
||||
if (err) return err;
|
||||
|
||||
for (uint8_t i = 0; i < len; ++i) {
|
||||
err = i2c_write(data[i]);
|
||||
if (err) return err;
|
||||
}
|
||||
i2c_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void i2c_slave_write(uint8_t addr, uint8_t data) {
|
||||
i2c_slave_buffer[addr] = data;
|
||||
}
|
||||
|
||||
uint8_t i2c_slave_read(uint8_t addr) {
|
||||
return i2c_slave_buffer[addr];
|
||||
}
|
||||
|
||||
// Setup twi to run at 100kHz
|
||||
void i2c_master_init(void) {
|
||||
// no prescaler
|
||||
TWSR = 0;
|
||||
// Set TWI clock frequency to SCL_CLOCK. Need TWBR>10.
|
||||
// Check datasheets for more info.
|
||||
TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
|
||||
}
|
||||
|
||||
// Start a transaction with the given i2c slave address. The direction of the
|
||||
// transfer is set with I2C_READ and I2C_WRITE.
|
||||
// returns: 0 => success
|
||||
// 1 => error
|
||||
uint8_t i2c_start(uint8_t address) {
|
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
|
||||
|
||||
i2c_delay();
|
||||
|
||||
// check that we started successfully
|
||||
if ( (TW_STATUS != TW_START) && (TW_STATUS != TW_REP_START))
|
||||
return 1;
|
||||
|
||||
TWDR = address;
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
|
||||
i2c_delay();
|
||||
|
||||
if ( (TW_STATUS != TW_MT_SLA_ACK) && (TW_STATUS != TW_MR_SLA_ACK) )
|
||||
return 1; // slave did not acknowledge
|
||||
else
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
|
||||
// Finish the i2c transaction.
|
||||
void i2c_stop(void) {
|
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
|
||||
|
||||
uint16_t lim = 0;
|
||||
while(!(TWCR & (1<<TWSTO)) && lim < I2C_LOOP_TIMEOUT)
|
||||
lim++;
|
||||
}
|
||||
|
||||
// Write one byte to the i2c slave.
|
||||
// returns 0 => slave ACK
|
||||
// 1 => slave NACK
|
||||
uint8_t i2c_write(uint8_t data) {
|
||||
TWDR = data;
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
|
||||
i2c_delay();
|
||||
|
||||
// check if the slave acknowledged us
|
||||
return (TW_STATUS == TW_MT_DATA_ACK) ? 0 : 1;
|
||||
}
|
||||
|
||||
// Read one byte from the i2c slave. If ack=1 the slave is acknowledged,
|
||||
// if ack=0 the acknowledge bit is not set.
|
||||
// returns: byte read from i2c device
|
||||
uint8_t i2c_read(uint8_t ack) {
|
||||
TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA);
|
||||
|
||||
i2c_delay();
|
||||
return TWDR;
|
||||
}
|
||||
|
||||
void i2c_slave_init(uint8_t address) {
|
||||
TWAR = address << 0; // slave i2c address
|
||||
// TWEN - twi enable
|
||||
// TWEA - enable address acknowledgement
|
||||
// TWINT - twi interrupt flag
|
||||
// TWIE - enable the twi interrupt
|
||||
TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
|
||||
}
|
||||
|
||||
ISR(TWI_vect);
|
||||
|
||||
ISR(TWI_vect) {
|
||||
uint8_t ack = 1;
|
||||
switch(TW_STATUS) {
|
||||
case TW_SR_SLA_ACK:
|
||||
// this device has been addressed as a slave receiver
|
||||
slave_has_register_set = false;
|
||||
break;
|
||||
|
||||
case TW_SR_DATA_ACK:
|
||||
// this device has received data as a slave receiver
|
||||
// The first byte that we receive in this transaction sets the location
|
||||
// of the read/write location of the slaves memory that it exposes over
|
||||
// i2c. After that, bytes will be written at slave_buffer_pos, incrementing
|
||||
// slave_buffer_pos after each write.
|
||||
if(!slave_has_register_set) {
|
||||
slave_buffer_pos = TWDR;
|
||||
// don't acknowledge the master if this memory loctaion is out of bounds
|
||||
if ( slave_buffer_pos >= SLAVE_BUFFER_SIZE ) {
|
||||
ack = 0;
|
||||
slave_buffer_pos = 0;
|
||||
}
|
||||
slave_has_register_set = true;
|
||||
} else {
|
||||
i2c_slave_buffer[slave_buffer_pos] = TWDR;
|
||||
BUFFER_POS_INC();
|
||||
}
|
||||
break;
|
||||
|
||||
case TW_ST_SLA_ACK:
|
||||
case TW_ST_DATA_ACK:
|
||||
// master has addressed this device as a slave transmitter and is
|
||||
// requesting data.
|
||||
TWDR = i2c_slave_buffer[slave_buffer_pos];
|
||||
BUFFER_POS_INC();
|
||||
break;
|
||||
|
||||
case TW_BUS_ERROR: // something went wrong, reset twi state
|
||||
TWCR = 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Reset everything, so we are ready for the next TWI interrupt
|
||||
TWCR |= (1<<TWIE) | (1<<TWINT) | (ack<<TWEA) | (1<<TWEN);
|
||||
}
|
21
keyboard/foobar_rgb/i2c.h
Normal file
21
keyboard/foobar_rgb/i2c.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef I2C_H
|
||||
#define I2C_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SLAVE_BUFFER_SIZE 0x40
|
||||
|
||||
// i2c SCL clock frequency
|
||||
#define SCL_CLOCK 100000L
|
||||
|
||||
|
||||
void i2c_master_init(void);
|
||||
void i2c_slave_init(uint8_t address);
|
||||
|
||||
bool i2c_master_write(uint8_t i2c_device_addr, uint8_t addr, uint8_t *dest, uint8_t len);
|
||||
bool i2c_master_read(uint8_t i2c_device_addr, uint8_t addr, uint8_t *data, uint8_t len);
|
||||
|
||||
void i2c_slave_write(uint8_t addr, uint8_t data);
|
||||
uint8_t i2c_slave_read(uint8_t addr);
|
||||
|
||||
#endif
|
BIN
keyboard/foobar_rgb/imgs/split-keyboard-i2c-schematic.png
Normal file
BIN
keyboard/foobar_rgb/imgs/split-keyboard-i2c-schematic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
keyboard/foobar_rgb/imgs/split-keyboard-serial-schematic.png
Normal file
BIN
keyboard/foobar_rgb/imgs/split-keyboard-serial-schematic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
24
keyboard/foobar_rgb/led.c
Normal file
24
keyboard/foobar_rgb/led.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2012 Jun Wako <wakojun@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"
|
||||
|
||||
void led_set(uint8_t usb_led)
|
||||
{
|
||||
}
|
181
keyboard/foobar_rgb/light_ws2812.c
Normal file
181
keyboard/foobar_rgb/light_ws2812.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* light weight WS2812 lib V2.0b
|
||||
*
|
||||
* Controls WS2811/WS2812/WS2812B RGB-LEDs
|
||||
* Author: Tim (cpldcpu@gmail.com)
|
||||
*
|
||||
* Jan 18th, 2014 v2.0b Initial Version
|
||||
* Nov 29th, 2015 v2.3 Added SK6812RGBW support
|
||||
*
|
||||
* License: GNU GPL v2 (see License.txt)
|
||||
*/
|
||||
|
||||
#include "light_ws2812.h"
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#include "debug.h"
|
||||
|
||||
// Setleds for standard RGB
|
||||
void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
|
||||
{
|
||||
ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
|
||||
}
|
||||
|
||||
void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
|
||||
{
|
||||
ws2812_DDRREG |= pinmask; // Enable DDR
|
||||
ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
|
||||
_delay_us(50);
|
||||
}
|
||||
|
||||
// Setleds for SK6812RGBW
|
||||
void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds)
|
||||
{
|
||||
ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
|
||||
ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin));
|
||||
_delay_us(80);
|
||||
}
|
||||
|
||||
void ws2812_sendarray(uint8_t *data,uint16_t datlen)
|
||||
{
|
||||
ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin));
|
||||
}
|
||||
|
||||
/*
|
||||
This routine writes an array of bytes with RGB values to the Dataout pin
|
||||
using the fast 800kHz clockless WS2811/2812 protocol.
|
||||
*/
|
||||
|
||||
// Timing in ns
|
||||
#define w_zeropulse 350
|
||||
#define w_onepulse 900
|
||||
#define w_totalperiod 1250
|
||||
|
||||
// Fixed cycles used by the inner loop
|
||||
#define w_fixedlow 2
|
||||
#define w_fixedhigh 4
|
||||
#define w_fixedtotal 8
|
||||
|
||||
// Insert NOPs to match the timing, if possible
|
||||
#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000)
|
||||
#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000)
|
||||
#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000)
|
||||
|
||||
// w1 - nops between rising edge and falling edge - low
|
||||
#define w1 (w_zerocycles-w_fixedlow)
|
||||
// w2 nops between fe low and fe high
|
||||
#define w2 (w_onecycles-w_fixedhigh-w1)
|
||||
// w3 nops to complete loop
|
||||
#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
|
||||
|
||||
#if w1>0
|
||||
#define w1_nops w1
|
||||
#else
|
||||
#define w1_nops 0
|
||||
#endif
|
||||
|
||||
// The only critical timing parameter is the minimum pulse length of the "0"
|
||||
// Warn or throw error if this timing can not be met with current F_CPU settings.
|
||||
#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
|
||||
#if w_lowtime>550
|
||||
#error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
|
||||
#elif w_lowtime>450
|
||||
#warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
|
||||
#warning "Please consider a higher clockspeed, if possible"
|
||||
#endif
|
||||
|
||||
#if w2>0
|
||||
#define w2_nops w2
|
||||
#else
|
||||
#define w2_nops 0
|
||||
#endif
|
||||
|
||||
#if w3>0
|
||||
#define w3_nops w3
|
||||
#else
|
||||
#define w3_nops 0
|
||||
#endif
|
||||
|
||||
#define w_nop1 "nop \n\t"
|
||||
#define w_nop2 "rjmp .+0 \n\t"
|
||||
#define w_nop4 w_nop2 w_nop2
|
||||
#define w_nop8 w_nop4 w_nop4
|
||||
#define w_nop16 w_nop8 w_nop8
|
||||
|
||||
void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
|
||||
{
|
||||
uint8_t curbyte,ctr,masklo;
|
||||
uint8_t sreg_prev;
|
||||
|
||||
masklo =~maskhi&ws2812_PORTREG;
|
||||
maskhi |= ws2812_PORTREG;
|
||||
sreg_prev=SREG;
|
||||
cli();
|
||||
|
||||
while (datlen--) {
|
||||
curbyte=*data++;
|
||||
|
||||
asm volatile(
|
||||
" ldi %0,8 \n\t"
|
||||
"loop%=: \n\t"
|
||||
" out %2,%3 \n\t" // '1' [01] '0' [01] - re
|
||||
#if (w1_nops&1)
|
||||
w_nop1
|
||||
#endif
|
||||
#if (w1_nops&2)
|
||||
w_nop2
|
||||
#endif
|
||||
#if (w1_nops&4)
|
||||
w_nop4
|
||||
#endif
|
||||
#if (w1_nops&8)
|
||||
w_nop8
|
||||
#endif
|
||||
#if (w1_nops&16)
|
||||
w_nop16
|
||||
#endif
|
||||
" sbrs %1,7 \n\t" // '1' [03] '0' [02]
|
||||
" out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
|
||||
" lsl %1 \n\t" // '1' [04] '0' [04]
|
||||
#if (w2_nops&1)
|
||||
w_nop1
|
||||
#endif
|
||||
#if (w2_nops&2)
|
||||
w_nop2
|
||||
#endif
|
||||
#if (w2_nops&4)
|
||||
w_nop4
|
||||
#endif
|
||||
#if (w2_nops&8)
|
||||
w_nop8
|
||||
#endif
|
||||
#if (w2_nops&16)
|
||||
w_nop16
|
||||
#endif
|
||||
" out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
|
||||
#if (w3_nops&1)
|
||||
w_nop1
|
||||
#endif
|
||||
#if (w3_nops&2)
|
||||
w_nop2
|
||||
#endif
|
||||
#if (w3_nops&4)
|
||||
w_nop4
|
||||
#endif
|
||||
#if (w3_nops&8)
|
||||
w_nop8
|
||||
#endif
|
||||
#if (w3_nops&16)
|
||||
w_nop16
|
||||
#endif
|
||||
|
||||
" dec %0 \n\t" // '1' [+2] '0' [+2]
|
||||
" brne loop%=\n\t" // '1' [+3] '0' [+4]
|
||||
: "=&d" (ctr)
|
||||
: "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
|
||||
);
|
||||
}
|
||||
|
||||
SREG=sreg_prev;
|
||||
}
|
73
keyboard/foobar_rgb/light_ws2812.h
Normal file
73
keyboard/foobar_rgb/light_ws2812.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* light weight WS2812 lib include
|
||||
*
|
||||
* Version 2.3 - Nev 29th 2015
|
||||
* Author: Tim (cpldcpu@gmail.com)
|
||||
*
|
||||
* Please do not change this file! All configuration is handled in "ws2812_config.h"
|
||||
*
|
||||
* License: GNU GPL v2 (see License.txt)
|
||||
+
|
||||
*/
|
||||
|
||||
#ifndef LIGHT_WS2812_H_
|
||||
#define LIGHT_WS2812_H_
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
//#include "ws2812_config.h"
|
||||
|
||||
/*
|
||||
* Structure of the LED array
|
||||
*
|
||||
* cRGB: RGB for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106
|
||||
* cRGBW: RGBW for SK6812RGBW
|
||||
*/
|
||||
|
||||
struct cRGB { uint8_t g; uint8_t r; uint8_t b; };
|
||||
struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;};
|
||||
|
||||
|
||||
|
||||
/* User Interface
|
||||
*
|
||||
* Input:
|
||||
* ledarray: An array of GRB data describing the LED colors
|
||||
* number_of_leds: The number of LEDs to write
|
||||
* pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
|
||||
*
|
||||
* The functions will perform the following actions:
|
||||
* - Set the data-out pin as output
|
||||
* - Send out the LED data
|
||||
* - Wait 50<EFBFBD>s to reset the LEDs
|
||||
*/
|
||||
|
||||
void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds);
|
||||
void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask);
|
||||
void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds);
|
||||
|
||||
/*
|
||||
* Old interface / Internal functions
|
||||
*
|
||||
* The functions take a byte-array and send to the data output as WS2812 bitstream.
|
||||
* The length is the number of bytes to send - three per LED.
|
||||
*/
|
||||
|
||||
void ws2812_sendarray (uint8_t *array,uint16_t length);
|
||||
void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask);
|
||||
|
||||
|
||||
/*
|
||||
* Internal defines
|
||||
*/
|
||||
#ifndef CONCAT
|
||||
#define CONCAT(a, b) a ## b
|
||||
#endif
|
||||
#ifndef CONCAT_EXP
|
||||
#define CONCAT_EXP(a, b) CONCAT(a, b)
|
||||
#endif
|
||||
|
||||
// #define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port)
|
||||
// #define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port)
|
||||
|
||||
#endif /* LIGHT_WS2812_H_ */
|
301
keyboard/foobar_rgb/matrix.c
Normal file
301
keyboard/foobar_rgb/matrix.c
Normal file
@ -0,0 +1,301 @@
|
||||
/*
|
||||
Copyright 2012 Jun Wako <wakojun@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 <avr/wdt.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
#include "print.h"
|
||||
#include "debug.h"
|
||||
#include "util.h"
|
||||
#include "timer.h"
|
||||
#include "matrix.h"
|
||||
#include "i2c.h"
|
||||
#include "serial.h"
|
||||
#include "split-util.h"
|
||||
#include "pro-micro.h"
|
||||
#include "config.h"
|
||||
#include "rgblight.h"
|
||||
|
||||
#include "pin_defs.h"
|
||||
|
||||
#ifndef DEBOUNCE
|
||||
# define DEBOUNCE 5
|
||||
#endif
|
||||
|
||||
#define ERROR_DISCONNECT_COUNT 5
|
||||
|
||||
#define I2C_MATRIX_ADDR 0x00
|
||||
#define I2C_LED_ADDR ROWS_PER_HAND
|
||||
|
||||
static uint8_t debouncing = DEBOUNCE;
|
||||
static uint8_t error_count = 0;
|
||||
|
||||
/* matrix state(1:on, 0:off) */
|
||||
static matrix_row_t matrix[MATRIX_ROWS];
|
||||
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
|
||||
|
||||
static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
|
||||
static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
|
||||
|
||||
static matrix_row_t read_cols(void);
|
||||
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)
|
||||
{
|
||||
// To use PORTF disable JTAG with writing JTD bit twice within four cycles.
|
||||
MCUCR |= (1<<JTD);
|
||||
MCUCR |= (1<<JTD);
|
||||
|
||||
debug_enable = true;
|
||||
debug_matrix = true;
|
||||
debug_mouse = true;
|
||||
// initialize row and col
|
||||
unselect_rows();
|
||||
init_cols();
|
||||
|
||||
TX_RX_LED_INIT;
|
||||
//Turn LEDs off by default
|
||||
RXLED0;
|
||||
TXLED0;
|
||||
|
||||
rgblight_init();
|
||||
|
||||
// initialize matrix state: all keys off
|
||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
||||
matrix[i] = 0;
|
||||
matrix_debouncing[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t _matrix_scan(void)
|
||||
{
|
||||
// Right hand is stored after the left in the matirx so, we need to offset it
|
||||
int offset = isLeftHand ? 0 : (ROWS_PER_HAND);
|
||||
|
||||
for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {
|
||||
select_row(i);
|
||||
_delay_us(30); // without this wait read unstable value.
|
||||
matrix_row_t cols = read_cols();
|
||||
if (matrix_debouncing[i+offset] != cols) {
|
||||
matrix_debouncing[i+offset] = cols;
|
||||
debouncing = DEBOUNCE;
|
||||
}
|
||||
unselect_rows();
|
||||
}
|
||||
|
||||
if (debouncing) {
|
||||
if (--debouncing) {
|
||||
_delay_ms(1);
|
||||
} else {
|
||||
for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {
|
||||
matrix[i+offset] = matrix_debouncing[i+offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get rows from other half over i2c
|
||||
int i2c_transaction(void) {
|
||||
bool err = false;
|
||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
||||
|
||||
err = i2c_master_read(
|
||||
SLAVE_I2C_ADDRESS, // i2c address of other half
|
||||
I2C_MATRIX_ADDR, // read the slaves matrix data
|
||||
matrix+slaveOffset, // store in correct position in master's matrix
|
||||
ROWS_PER_HAND // number of bytes to read
|
||||
);
|
||||
|
||||
#ifdef I2C_WRITE_TEST_CODE
|
||||
// controls the RX led on the slave and toggles it every second
|
||||
uint8_t test_data = (timer_read() / 1000) % 2;
|
||||
|
||||
err |= i2c_master_write(
|
||||
SLAVE_I2C_ADDRESS, // i2c address of other half
|
||||
I2C_LED_ADDR, // address for led control
|
||||
&test_data, // data to send
|
||||
sizeof(test_data) // size of test data
|
||||
);
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int serial_transaction(void) {
|
||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
||||
|
||||
if (serial_update_buffers()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
||||
matrix[slaveOffset+i] = serial_slave_buffer[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t matrix_scan(void)
|
||||
{
|
||||
int ret = _matrix_scan();
|
||||
|
||||
|
||||
|
||||
#ifdef USE_I2C
|
||||
if( i2c_transaction() ) {
|
||||
#else
|
||||
if( serial_transaction() ) {
|
||||
#endif
|
||||
// turn on the indicator led when halves are disconnected
|
||||
TXLED1;
|
||||
|
||||
error_count++;
|
||||
|
||||
if (error_count > ERROR_DISCONNECT_COUNT) {
|
||||
// reset other half if disconnected
|
||||
int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
|
||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
||||
matrix[slaveOffset+i] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// turn off the indicator led on no error
|
||||
TXLED0;
|
||||
error_count = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void matrix_slave_scan(void) {
|
||||
_matrix_scan();
|
||||
|
||||
int offset = (isLeftHand) ? 0 : (MATRIX_ROWS / 2);
|
||||
|
||||
#ifdef USE_I2C
|
||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
||||
i2c_slave_write(I2C_MATRIX_ADDR+i, matrix[offset+i]);
|
||||
}
|
||||
|
||||
#ifdef I2C_WRITE_TEST_CODE
|
||||
// control the pro micro RX LED based on what the
|
||||
// i2c master has sent us
|
||||
uint8_t led_state = i2c_slave_read(I2C_LED_ADDR);
|
||||
if (led_state == 1) {
|
||||
RXLED1;
|
||||
} else if(led_state == 0) {
|
||||
RXLED0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
for (int i = 0; i < ROWS_PER_HAND; ++i) {
|
||||
serial_slave_buffer[i] = matrix[offset+i];
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool matrix_is_modified(void)
|
||||
{
|
||||
if (debouncing) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
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(": ");
|
||||
pbin_reverse16(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 += bitpop16(matrix[i]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void init_cols(void)
|
||||
{
|
||||
for(int x = 0; x < MATRIX_COLS; x++) {
|
||||
_SFR_IO8((col_pins[x] >> 4) + 1) &= ~_BV(col_pins[x] & 0xF);
|
||||
_SFR_IO8((col_pins[x] >> 4) + 2) |= _BV(col_pins[x] & 0xF);
|
||||
}
|
||||
}
|
||||
|
||||
static matrix_row_t read_cols(void)
|
||||
{
|
||||
matrix_row_t result = 0;
|
||||
for(int x = 0; x < MATRIX_COLS; x++) {
|
||||
result |= (_SFR_IO8(col_pins[x] >> 4) & _BV(col_pins[x] & 0xF)) ? 0 : (1 << x);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void unselect_rows(void)
|
||||
{
|
||||
for(int x = 0; x < ROWS_PER_HAND; x++) {
|
||||
_SFR_IO8((row_pins[x] >> 4) + 1) &= ~_BV(row_pins[x] & 0xF);
|
||||
_SFR_IO8((row_pins[x] >> 4) + 2) |= _BV(row_pins[x] & 0xF);
|
||||
}
|
||||
}
|
||||
|
||||
static void select_row(uint8_t row)
|
||||
{
|
||||
_SFR_IO8((row_pins[row] >> 4) + 1) |= _BV(row_pins[row] & 0xF);
|
||||
_SFR_IO8((row_pins[row] >> 4) + 2) &= ~_BV(row_pins[row] & 0xF);
|
||||
}
|
58
keyboard/foobar_rgb/pin_defs.h
Normal file
58
keyboard/foobar_rgb/pin_defs.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef PIN_DEFS_H
|
||||
#define PIN_DEFS_H
|
||||
|
||||
/* diode directions */
|
||||
#define COL2ROW 0
|
||||
#define ROW2COL 1
|
||||
|
||||
/* I/O pins */
|
||||
#define B0 0x30
|
||||
#define B1 0x31
|
||||
#define B2 0x32
|
||||
#define B3 0x33
|
||||
#define B4 0x34
|
||||
#define B5 0x35
|
||||
#define B6 0x36
|
||||
#define B7 0x37
|
||||
#define C0 0x60
|
||||
#define C1 0x61
|
||||
#define C2 0x62
|
||||
#define C3 0x63
|
||||
#define C4 0x64
|
||||
#define C5 0x65
|
||||
#define C6 0x66
|
||||
#define C7 0x67
|
||||
#define D0 0x90
|
||||
#define D1 0x91
|
||||
#define D2 0x92
|
||||
#define D3 0x93
|
||||
#define D4 0x94
|
||||
#define D5 0x95
|
||||
#define D6 0x96
|
||||
#define D7 0x97
|
||||
#define E0 0xC0
|
||||
#define E1 0xC1
|
||||
#define E2 0xC2
|
||||
#define E3 0xC3
|
||||
#define E4 0xC4
|
||||
#define E5 0xC5
|
||||
#define E6 0xC6
|
||||
#define E7 0xC7
|
||||
#define F0 0xF0
|
||||
#define F1 0xF1
|
||||
#define F2 0xF2
|
||||
#define F3 0xF3
|
||||
#define F4 0xF4
|
||||
#define F5 0xF5
|
||||
#define F6 0xF6
|
||||
#define F7 0xF7
|
||||
#define A0 0x00
|
||||
#define A1 0x01
|
||||
#define A2 0x02
|
||||
#define A3 0x03
|
||||
#define A4 0x04
|
||||
#define A5 0x05
|
||||
#define A6 0x06
|
||||
#define A7 0x07
|
||||
|
||||
#endif
|
362
keyboard/foobar_rgb/pro-micro.h
Normal file
362
keyboard/foobar_rgb/pro-micro.h
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
pins_arduino.h - Pin definition functions for Arduino
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2007 David A. Mellis
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// Workaround for wrong definitions in "iom32u4.h".
|
||||
// This should be fixed in the AVR toolchain.
|
||||
#undef UHCON
|
||||
#undef UHINT
|
||||
#undef UHIEN
|
||||
#undef UHADDR
|
||||
#undef UHFNUM
|
||||
#undef UHFNUML
|
||||
#undef UHFNUMH
|
||||
#undef UHFLEN
|
||||
#undef UPINRQX
|
||||
#undef UPINTX
|
||||
#undef UPNUM
|
||||
#undef UPRST
|
||||
#undef UPCONX
|
||||
#undef UPCFG0X
|
||||
#undef UPCFG1X
|
||||
#undef UPSTAX
|
||||
#undef UPCFG2X
|
||||
#undef UPIENX
|
||||
#undef UPDATX
|
||||
#undef TCCR2A
|
||||
#undef WGM20
|
||||
#undef WGM21
|
||||
#undef COM2B0
|
||||
#undef COM2B1
|
||||
#undef COM2A0
|
||||
#undef COM2A1
|
||||
#undef TCCR2B
|
||||
#undef CS20
|
||||
#undef CS21
|
||||
#undef CS22
|
||||
#undef WGM22
|
||||
#undef FOC2B
|
||||
#undef FOC2A
|
||||
#undef TCNT2
|
||||
#undef TCNT2_0
|
||||
#undef TCNT2_1
|
||||
#undef TCNT2_2
|
||||
#undef TCNT2_3
|
||||
#undef TCNT2_4
|
||||
#undef TCNT2_5
|
||||
#undef TCNT2_6
|
||||
#undef TCNT2_7
|
||||
#undef OCR2A
|
||||
#undef OCR2_0
|
||||
#undef OCR2_1
|
||||
#undef OCR2_2
|
||||
#undef OCR2_3
|
||||
#undef OCR2_4
|
||||
#undef OCR2_5
|
||||
#undef OCR2_6
|
||||
#undef OCR2_7
|
||||
#undef OCR2B
|
||||
#undef OCR2_0
|
||||
#undef OCR2_1
|
||||
#undef OCR2_2
|
||||
#undef OCR2_3
|
||||
#undef OCR2_4
|
||||
#undef OCR2_5
|
||||
#undef OCR2_6
|
||||