Compare commits

..

76 Commits

Author SHA1 Message Date
c8e29bc7f1 working led via A3 2018-06-25 00:10:56 -04:00
955ea5c7fb A3 doing fine 2018-06-23 16:49:30 -04:00
11a34b988c A3 doing fine 2018-06-23 16:37:47 -04:00
199285e7e4 A3 doing fine 2018-06-23 16:37:23 -04:00
b92915257f A3 doing interesting stuff 2018-06-23 16:36:16 -04:00
cc45baa811 try out on B10 2018-06-23 02:28:46 -04:00
516ba9eb80 more things to tryy 2018-06-22 19:28:39 -04:00
309bb38c7e some adjustments that didn't work 2018-06-22 12:28:31 -04:00
75f1181ad6 led not working 2018-06-21 21:25:06 -04:00
6f8680db17 adds qwiic_hub 2018-06-20 17:53:54 -04:00
1b7efbc03b Merge branch 'muon_light' of github.com:qmk/qmk_firmware into keymap_folders 2018-06-10 00:28:11 -04:00
e54159d9e8 Merge branch 'muon_light' of github.com:qmk/qmk_firmware into keymap_folders 2018-06-10 00:25:54 -04:00
d01f40edbf workingggg 2018-06-10 00:25:21 -04:00
13f49ad8d9 all a's working 2018-06-09 23:53:26 -04:00
0f89d7efed try sound feedback 2018-06-09 17:57:15 -04:00
2fccc1a064 hooked-up keymap/matrix, compiling, not working 2018-06-09 02:03:32 -04:00
53c518f7d4 start qwiic keyboard impl 2018-06-08 02:07:28 -04:00
bcbc64aed8 fix layouts 2018-06-07 20:54:25 -04:00
459dfa510e rename to proton c 2018-06-07 19:14:19 -04:00
5bb1e7869c update chibios, remove extra files 2018-06-07 19:00:10 -04:00
58c4ba096a update chibios 2018-06-07 18:46:35 -04:00
c8cc9c6aab add i2c slave files 2018-06-07 17:21:35 -04:00
e1e4a51472 add keymap folders 2018-06-07 15:41:19 -04:00
c53a8ead93 inital support for muon 2018-06-06 18:21:51 -04:00
a6afb16c90 fix assembly errors with hal 2018-06-04 00:50:09 -04:00
21665df8eb add encoder docs 2018-06-03 22:59:27 -04:00
ff4a1ae5d2 inital encoder implementation 2018-06-03 21:55:07 -04:00
018a0142d2 arm lines implemented 2018-06-03 18:01:11 -04:00
c1f6f1308b move drivers around 2018-06-01 16:37:15 -04:00
274283420d rev2 working 2018-06-01 14:33:13 -04:00
874f5a5c07 mostly compiling 2018-06-01 11:31:29 -04:00
161c68b48a update twi2c to do standard master stuff 2018-05-31 00:28:37 -04:00
5fad8d774d Merge branch 'handwire' of github.com:qmk/qmk_firmware into planck_rev6 2018-05-30 23:34:21 -04:00
4fdc9badd3 Merge branch 'master' of github.com:qmk/qmk_firmware into planck_rev6 2018-05-30 15:24:45 -04:00
af6107bee8 working example 2018-05-23 01:54:43 -04:00
d233737c95 last commit for glasser code 2018-05-23 00:50:58 -04:00
3e282ab203 update ws2812 driver/config 2018-05-22 21:41:10 -04:00
1c0d85c143 update build includes for chibios 2018-05-22 21:40:38 -04:00
7c19e9fa04 pwm ws driver (not working) 2018-05-18 01:32:24 -04:00
9fccfc8dd5 conditional autio 2018-05-15 11:36:19 -04:00
1cb72a9c59 dont break other revs 2018-05-10 16:17:50 -04:00
82146ecfc0 dont break other revs 2018-05-10 15:54:33 -04:00
4a1984d33e merge from master 2018-05-10 15:01:26 -04:00
676080372c try mouse wheel again 2018-04-24 11:58:36 -04:00
0af7415981 Merge branch 'master' of github.com:qmk/qmk_firmware into planck_rev6 2018-04-15 20:43:39 -04:00
df371458b3 flip direction 2018-04-06 12:36:20 -04:00
e0e5efbead muse working with encoder as control 2018-04-04 16:49:39 -04:00
edb4460e64 start muse implementation 2018-04-04 02:29:52 -04:00
fe72bfa070 adds default encoder res 2018-04-03 21:10:57 -04:00
25642c8840 adds default encoder res 2018-04-03 21:07:18 -04:00
03b1904b2e Merge branch 'master' of github.com:qmk/qmk_firmware into planck_rev6 2018-04-03 21:00:22 -04:00
bb71a988c2 flesh out dip and encoder support 2018-04-03 20:57:11 -04:00
ddee61c9ba adds ws2812 driver for arm 2018-03-25 16:09:40 -04:00
91efe74365 music map init, dip scan added 2018-03-22 01:35:33 -04:00
12a64ff24b initial files for rev 6 with encoder 2018-03-16 03:38:20 -04:00
b034896cd3 update submodule 2018-03-05 20:24:20 -05:00
2bd625b754 bla 2018-03-05 19:58:38 -05:00
da32068f48 update to qwerty 2018-02-26 21:29:07 -05:00
b308d6709e working 2018-02-23 12:09:03 -05:00
123ad0de95 try more stuff 2018-02-23 11:29:30 -05:00
00fc38435f master working 2018-02-22 21:22:47 -05:00
8b5b41bb47 update handwire with arm changes 2018-02-19 22:00:38 -05:00
4bdde668e1 Merge branch 'master' of github.com:qmk/qmk_firmware into handwire 2018-02-19 21:47:46 -05:00
3c0d86eb47 a little progress 2018-02-15 02:06:06 -05:00
f60166c1a1 Merge branch 'master' of github.com:qmk/qmk_firmware into handwire 2018-02-14 15:35:30 -05:00
7d59f83b2e adds matrix i2c swap 2018-02-14 15:35:24 -05:00
be81cd8c98 adds i2c slave implementation 2018-02-10 16:32:05 -05:00
b075df1c87 merge 2018-02-09 13:30:28 -05:00
8a91aa5e6c Merge branch 'master' of github.com:qmk/qmk_firmware into handwire 2018-02-07 17:33:18 -05:00
fae437cfad update matrix 2018-02-07 17:17:39 -05:00
fc91bf4a65 updated matrix and keymap 2018-02-01 14:48:25 -05:00
78ea99d154 start f303 handwire 2018-01-31 13:31:20 -05:00
2165f9d654 get one channel working 2018-01-27 02:05:09 -05:00
31df12c84f chibios stack size inc 2018-01-26 23:56:48 -05:00
d09d9f32bd Merge branch 'master' into arm_audio_fixes 2018-01-26 22:54:57 -05:00
690a08cbbb fix up arm audio implementation 2018-01-15 16:06:49 -05:00
179 changed files with 18013 additions and 3060 deletions

1
.gitmodules vendored
View File

@ -1,6 +1,7 @@
[submodule "lib/chibios"]
path = lib/chibios
url = https://github.com/qmk/ChibiOS
branch = handwire
[submodule "lib/chibios-contrib"]
path = lib/chibios-contrib
url = https://github.com/qmk/ChibiOS-Contrib

View File

@ -67,7 +67,7 @@ $(eval $(call NEXT_PATH_ELEMENT))
# It's really a very simple if else chain, if you squint enough,
# but the makefile syntax makes it very verbose.
# If we are in a subfolder of keyboards
#
#
# *** No longer needed **
#
# ifeq ($(CURRENT_PATH_ELEMENT),keyboards)
@ -320,6 +320,14 @@ define PARSE_KEYBOARD
KEYMAPS += $$(notdir $$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_3)/keymaps/*/.)))
KEYMAPS += $$(notdir $$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_4)/keymaps/*/.)))
KEYMAPS += $$(notdir $$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_5)/keymaps/*/.)))
# get subkeymaps too
KEYMAPS += $$(patsubst $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_1)/keymaps/%,%,$$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_1)/keymaps/*/*/.)))
KEYMAPS += $$(patsubst $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_2)/keymaps/%,%,$$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_2)/keymaps/*/*/.)))
KEYMAPS += $$(patsubst $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_3)/keymaps/%,%,$$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_3)/keymaps/*/*/.)))
KEYMAPS += $$(patsubst $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_4)/keymaps/%,%,$$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_4)/keymaps/*/*/.)))
KEYMAPS += $$(patsubst $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_5)/keymaps/%,%,$$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(KEYBOARD_FOLDER_PATH_5)/keymaps/*/*/.)))
# this might be needed, but in a different form
#KEYMAPS := $$(sort $$(filter-out $$(KEYBOARD_FOLDER_1) $$(KEYBOARD_FOLDER_2) \
$$(KEYBOARD_FOLDER_3) $$(KEYBOARD_FOLDER_4) $$(KEYBOARD_FOLDER_5), $$(KEYMAPS)))
@ -353,9 +361,11 @@ define PARSE_KEYBOARD
LAYOUT_KEYMAPS :=
$$(foreach LAYOUT,$$(KEYBOARD_LAYOUTS),$$(eval LAYOUT_KEYMAPS += $$(notdir $$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/layouts/*/$$(LAYOUT)/*/.)))))
KEYMAPS := $$(sort $$(KEYMAPS) $$(LAYOUT_KEYMAPS))
# $$(eval $$(info $$(KEYMAPS)))
# if the rule after removing the start of it is empty (we haven't specified a kemap or target)
# compile all the keymaps
ifeq ($$(RULE),)
@ -411,7 +421,8 @@ define PARSE_KEYMAP
MAKE_TARGET := $$(patsubst :%,%,$$(RULE))
# We need to generate an unique indentifer to append to the COMMANDS list
CURRENT_KB_UNDER := $$(subst /,_,$$(CURRENT_KB))
COMMAND := COMMAND_KEYBOARD_$$(CURRENT_KB_UNDER)_KEYMAP_$$(CURRENT_KM)
CURRENT_KM_UNDER := $$(subst /,_,$$(CURRENT_KM))
COMMAND := COMMAND_KEYBOARD_$$(CURRENT_KB_UNDER)_KEYMAP_$$(CURRENT_KM_UNDER)
# If we are compiling a keyboard without a subproject, we want to display just the name
# of the keyboard, otherwise keyboard/subproject
KB_SP := $$(CURRENT_KB)

View File

@ -19,8 +19,9 @@ KEYBOARD_FOLDER_4 := $(notdir $(KEYBOARD_FOLDER_PATH_4))
KEYBOARD_FOLDER_5 := $(notdir $(KEYBOARD_FOLDER_PATH_5))
KEYBOARD_FILESAFE := $(subst /,_,$(KEYBOARD))
KEYMAP_FILESAFE := $(subst /,_,$(KEYMAP))
TARGET ?= $(KEYBOARD_FILESAFE)_$(KEYMAP)
TARGET ?= $(KEYBOARD_FILESAFE)_$(KEYMAP_FILESAFE)
KEYBOARD_OUTPUT := $(BUILD_DIR)/obj_$(KEYBOARD_FILESAFE)
# Force expansion
@ -176,26 +177,44 @@ MAIN_KEYMAP_PATH_3 := $(KEYBOARD_PATH_3)/keymaps/$(KEYMAP)
MAIN_KEYMAP_PATH_4 := $(KEYBOARD_PATH_4)/keymaps/$(KEYMAP)
MAIN_KEYMAP_PATH_5 := $(KEYBOARD_PATH_5)/keymaps/$(KEYMAP)
PARENT_MAIN_KEYMAP_PATH_1 := $(patsubst %/,%,$(dir $(MAIN_KEYMAP_PATH_1)))
PARENT_MAIN_KEYMAP_PATH_2 := $(patsubst %/,%,$(dir $(MAIN_KEYMAP_PATH_2)))
PARENT_MAIN_KEYMAP_PATH_3 := $(patsubst %/,%,$(dir $(MAIN_KEYMAP_PATH_3)))
PARENT_MAIN_KEYMAP_PATH_4 := $(patsubst %/,%,$(dir $(MAIN_KEYMAP_PATH_4)))
PARENT_MAIN_KEYMAP_PATH_5 := $(patsubst %/,%,$(dir $(MAIN_KEYMAP_PATH_5)))
# $(info $(PARENT_MAIN_KEYMAP_PATH_1))
ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_5)/keymap.c)","")
-include $(MAIN_KEYMAP_PATH_5)/rules.mk
KEYMAP_C := $(MAIN_KEYMAP_PATH_5)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_5)
else ifneq ("$(wildcard $(PARENT_MAIN_KEYMAP_PATH_5)/keymap.c)","")
KEYMAP_C := $(PARENT_MAIN_KEYMAP_PATH_5)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_5)
else ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_4)/keymap.c)","")
-include $(MAIN_KEYMAP_PATH_4)/rules.mk
KEYMAP_C := $(MAIN_KEYMAP_PATH_4)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_4)
else ifneq ("$(wildcard $(PARENT_MAIN_KEYMAP_PATH_4)/keymap.c)","")
KEYMAP_C := $(PARENT_MAIN_KEYMAP_PATH_4)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_4)
else ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_3)/keymap.c)","")
-include $(MAIN_KEYMAP_PATH_3)/rules.mk
KEYMAP_C := $(MAIN_KEYMAP_PATH_3)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_3)
else ifneq ("$(wildcard $(PARENT_MAIN_KEYMAP_PATH_3)/keymap.c)","")
KEYMAP_C := $(PARENT_MAIN_KEYMAP_PATH_3)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_3)
else ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_2)/keymap.c)","")
-include $(MAIN_KEYMAP_PATH_2)/rules.mk
KEYMAP_C := $(MAIN_KEYMAP_PATH_2)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_2)
else ifneq ("$(wildcard $(PARENT_MAIN_KEYMAP_PATH_2)/keymap.c)","")
KEYMAP_C := $(PARENT_MAIN_KEYMAP_PATH_2)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_2)
else ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_1)/keymap.c)","")
-include $(MAIN_KEYMAP_PATH_1)/rules.mk
KEYMAP_C := $(MAIN_KEYMAP_PATH_1)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_1)
else ifneq ("$(wildcard $(PARENT_MAIN_KEYMAP_PATH_1)/keymap.c)","")
KEYMAP_C := $(PARENT_MAIN_KEYMAP_PATH_1)/keymap.c
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_1)
else ifneq ($(LAYOUTS),)
include build_layout.mk
else
@ -203,26 +222,34 @@ else
# this state should never be reached
endif
PARENT_KEYMAP_PATH := $(patsubst %/,%,$(dir $(KEYMAP_PATH)))
# User space stuff
ifeq ("$(USER_NAME)","")
USER_NAME := $(KEYMAP)
endif
USER_PATH := users/$(USER_NAME)
-include $(USER_PATH)/rules.mk
ifneq ("$(wildcard $(USER_PATH)/config.h)","")
CONFIG_H += $(USER_PATH)/config.h
endif
# Object files directory
# To put object files in current directory, use a dot (.), do NOT make
# this an empty or blank macro!
KEYMAP_OUTPUT := $(BUILD_DIR)/obj_$(TARGET)
-include $(PARENT_KEYMAP_PATH)/rules.mk
-include $(KEYMAP_PATH)/rules.mk
-include $(USER_PATH)/rules.mk
ifneq ("$(wildcard $(PARENT_KEYMAP_PATH)/config.h)","")
CONFIG_H += $(PARENT_KEYMAP_PATH)/config.h
endif
ifneq ("$(wildcard $(KEYMAP_PATH)/config.h)","")
CONFIG_H += $(KEYMAP_PATH)/config.h
endif
ifneq ("$(wildcard $(USER_PATH)/config.h)","")
CONFIG_H += $(USER_PATH)/config.h
endif
# # project specific files
SRC += $(KEYBOARD_SRC) \
@ -233,6 +260,7 @@ SRC += $(KEYBOARD_SRC) \
#EXTRALDFLAGS = -Wl,--relax
# Search Path
VPATH += $(PARENT_KEYMAP_PATH)
VPATH += $(KEYMAP_PATH)
VPATH += $(KEYBOARD_PATHS)
VPATH += $(COMMON_VPATH)

View File

@ -3,11 +3,15 @@ LAYOUTS_REPOS := $(patsubst %/,%,$(sort $(dir $(wildcard $(LAYOUTS_PATH)/*/))))
define SEARCH_LAYOUTS_REPO
LAYOUT_KEYMAP_PATH := $$(LAYOUTS_REPO)/$$(LAYOUT)/$$(KEYMAP)
PARENT_LAYOUT_KEYMAP_PATH := $(patsubst %/,%,$(dir $(LAYOUT_KEYMAP_PATH)))
LAYOUT_KEYMAP_C := $$(LAYOUT_KEYMAP_PATH)/keymap.c
PARENT_LAYOUT_KEYMAP_C := $$(PARENT_LAYOUT_KEYMAP_PATH)/keymap.c
ifneq ("$$(wildcard $$(LAYOUT_KEYMAP_C))","")
-include $$(LAYOUT_KEYMAP_PATH)/rules.mk
KEYMAP_C := $$(LAYOUT_KEYMAP_C)
KEYMAP_PATH := $$(LAYOUT_KEYMAP_PATH)
else ifneq ("$$(wildcard $$(PARENT_LAYOUT_KEYMAP_C))","")
KEYMAP_C := $$(PARENT_LAYOUT_KEYMAP_C)
KEYMAP_PATH := $$(LAYOUT_KEYMAP_PATH)
endif
endef
@ -15,4 +19,4 @@ define SEARCH_LAYOUTS
$$(foreach LAYOUTS_REPO,$$(LAYOUTS_REPOS),$$(eval $$(call SEARCH_LAYOUTS_REPO)))
endef
$(foreach LAYOUT,$(LAYOUTS),$(eval $(call SEARCH_LAYOUTS)))
$(foreach LAYOUT,$(LAYOUTS),$(eval $(call SEARCH_LAYOUTS)))

View File

@ -3,16 +3,16 @@ include message.mk
# Directory common source files exist
TOP_DIR = .
TMK_DIR = tmk_core
TMK_PATH = $(TOP_DIR)/$(TMK_DIR)
LIB_PATH = $(TOP_DIR)/lib
TMK_PATH = $(TMK_DIR)
LIB_PATH = lib
QUANTUM_DIR = quantum
QUANTUM_PATH = $(TOP_DIR)/$(QUANTUM_DIR)
QUANTUM_PATH = $(QUANTUM_DIR)
DRIVER_DIR = drivers
DRIVER_PATH = $(TOP_DIR)/$(DRIVER_DIR)
DRIVER_PATH = $(DRIVER_DIR)
BUILD_DIR := $(TOP_DIR)/.build
BUILD_DIR := .build
COMMON_VPATH := $(TOP_DIR)
COMMON_VPATH += $(TMK_PATH)
@ -21,4 +21,4 @@ COMMON_VPATH += $(QUANTUM_PATH)/keymap_extras
COMMON_VPATH += $(QUANTUM_PATH)/audio
COMMON_VPATH += $(QUANTUM_PATH)/process_keycode
COMMON_VPATH += $(QUANTUM_PATH)/api
COMMON_VPATH += $(DRIVER_PATH)
COMMON_VPATH += $(DRIVER_PATH)

View File

@ -20,6 +20,13 @@ SERIAL_SRC += $(wildcard $(SERIAL_PATH)/system/*.c)
SERIAL_DEFS += -DSERIAL_LINK_ENABLE
COMMON_VPATH += $(SERIAL_PATH)
COMMON_VPATH += $(DRIVER_PATH)
ifeq ($(PLATFORM),AVR)
COMMON_VPATH += $(DRIVER_PATH)/avr
else
COMMON_VPATH += $(DRIVER_PATH)/arm
endif
ifeq ($(strip $(API_SYSEX_ENABLE)), yes)
OPT_DEFS += -DAPI_SYSEX_ENABLE
SRC += $(QUANTUM_DIR)/api/api_sysex.c
@ -117,7 +124,7 @@ endif
ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
OPT_DEFS += -DRGB_MATRIX_ENABLE
SRC += is31fl3731.c
SRC += i2c_master.c
I2C_ENABLE = yes
SRC += $(QUANTUM_DIR)/color.c
SRC += $(QUANTUM_DIR)/rgb_matrix.c
CIE1931_CURVE = yes
@ -197,6 +204,25 @@ ifeq ($(strip $(USB_HID_ENABLE)), yes)
include $(TMK_DIR)/protocol/usb_hid.mk
endif
ifeq ($(strip $(I2C_SLAVE_ENABLE)), yes)
I2C_ENABLE = yes
OPT_DEFS += -DI2C_SLAVE_ENABLE
endif
ifeq ($(strip $(ENCODER_ENABLE)), yes)
OPT_DEFS += -DENCODER_ENABLE
SRC += $(QUANTUM_DIR)/encoder.c
endif
ifeq ($(strip $(QWIIC_KEYBOARD_ENABLE)), yes)
SRC += qwiic/qwiic_keyboard.c
OPT_DEFS += -DQWIIC_KEYBOARD_ENABLE
endif
ifeq ($(strip $(I2C_ENABLE)), yes)
SRC += twi2c.c
endif
QUANTUM_SRC:= \
$(QUANTUM_DIR)/quantum.c \
$(QUANTUM_DIR)/keymap_common.c \

View File

@ -34,6 +34,7 @@
* [Bootmagic](feature_bootmagic.md)
* [Command](feature_command.md)
* [Dynamic Macros](feature_dynamic_macros.md)
* [Encoders](feature_encoders.md)
* [Grave Escape](feature_grave_esc.md)
* [Key Lock](feature_key_lock.md)
* [Layouts](feature_layouts.md)

41
docs/feature_encoders.md Normal file
View File

@ -0,0 +1,41 @@
# Encoders
Basic encoders are supported by adding this to your `rules.mk`:
ENCODER_ENABLE = yes
and this to your `config.h`:
#define NUMBER_OF_ENCODERS 1
#define ENCODERS_PAD_A { B12 }
#define ENCODERS_PAD_B { B13 }
Each PAD_A/B variable defines an array so multiple encoders can be defined, e.g.:
#define ENCODERS_PAD_A { encoder1a, encoder2a }
#define ENCODERS_PAD_B { encoder1a, encoder2b }
If your encoder's clockwise directions are incorrect, you can swap the A & B pad definitions.
Additionally, the resolution can be specified in the same file (the default & suggested is 4):
#define ENCODER_RESOLUTION 4
## Callbacks
The callback functions can be inserted into your `<keyboard>.c`:
void encoder_update_kb(uint8_t index, bool clockwise) {
encoder_update_user(index, clockwise);
}
or `keymap.c`:
void encoder_update_user(uint8_t index, bool clockwise) {
}
## Hardware
The A an B lines of the encoders should be wired directly to the MCU, and the C/common lines should be wired to ground.

168
drivers/arm/twi2c.c Normal file
View File

@ -0,0 +1,168 @@
/* Copyright 2018 Jack Humbert
*
* 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 "twi2c.h"
#include <string.h>
#include <hal.h>
#include "chprintf.h"
#include "memstreams.h"
#include "printf.h"
#include "hal_i2cslave.h"
/**
* I2C slave test routine.
*
* To use: Add file to a project, call startComms() with the address of a serial stream
*
* There are two different responses:
* a) A read-only transaction - returns the "Initial Reply" message
* b) A write then read transaction - calls a message processor and returns the generated reply.
* Stretches clock until reply available.
*/
// static const I2CConfig masterI2CConfig = {
// 400000
// };
I2CSlaveMsgCB twi2c_incoming_message_process, twi2c_catch_error, twi2c_clear_after_send;
twi2c_message_received twi2c_message_received_callback;
static uint8_t twi2c_address;
static const I2CConfig i2cconfig = {
STM32_TIMINGR_PRESC(15U) |
STM32_TIMINGR_SCLDEL(4U) | STM32_TIMINGR_SDADEL(2U) |
STM32_TIMINGR_SCLH(15U) | STM32_TIMINGR_SCLL(21U),
0,
0
};
/**
* Track I2C errors
*/
uint8_t gotI2cError = 0;
uint32_t lastI2cErrorFlags = 0;
// Called from ISR to log error
void noteI2cError(uint32_t flags)
{
lastI2cErrorFlags = flags;
gotI2cError = 1;
}
/**
* Generic error handler
*
* Called in interrupt context, so need to watch what we do
*/
void twi2c_catch_error(I2CDriver *i2cp)
{
noteI2cError(i2cp->errors);
}
/**
* Callback after sending of response complete - restores default reply in case polled
*/
void twi2c_clear_after_send(I2CDriver *i2cp)
{
// echoReply.size = 0; // Clear receive message
// i2cSlaveReplyI(i2cp, &initialReply);
}
uint8_t twi2c_start(void) {
i2cStart(&I2C_DRIVER, &i2cconfig);
return 0;
}
void twi2c_init(void) {
palSetGroupMode(GPIOB,6,7, PAL_MODE_INPUT); // Try releasing special pins for a short time
chThdSleepMilliseconds(10);
palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP);
palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP);
// try high drive (from kiibohd)
// I2C_DRIVER.i2c->C2 |= I2Cx_C2_HDRS;
// try glitch fixing (from kiibohd)
// I2C_DRIVER.i2c->FLT = 4;
}
uint8_t twi2c_write(uint8_t data) {
return i2cMasterTransmitTimeout(&I2C_DRIVER, twi2c_address/2, &data, 1, 0, 0, MS2ST(100));
}
uint8_t twi2c_transmit(uint8_t address, uint8_t * data, uint16_t length) {
return i2cMasterTransmitTimeout(&I2C_DRIVER, address/2, data, length, 0, 0, MS2ST(100));
}
uint8_t twi2c_receive(uint8_t address, uint8_t * data, uint16_t length) {
return i2cMasterReceiveTimeout(&I2C_DRIVER, address/2, data, length, MS2ST(100));
}
uint8_t twi2c_incoming_body[50];
uint8_t twi2c_outgoing_body[1024];
// Response to received messages
I2CSlaveMsg twi2c_incoming_message = {
sizeof(twi2c_incoming_body),
twi2c_incoming_body,
NULL,
twi2c_incoming_message_process,
twi2c_catch_error /* Error hook */
};
void twi2c_incoming_message_process(I2CDriver * i2cp) {
size_t len = i2cSlaveBytes(i2cp);
(*twi2c_message_received_callback)(i2cp, twi2c_incoming_body, len);
}
// Response to received messages
I2CSlaveMsg twi2c_outgoing_message = {
sizeof(twi2c_outgoing_body),
twi2c_outgoing_body,
NULL,
twi2c_clear_after_send,
twi2c_catch_error
};
uint8_t twi2c_reply(I2CDriver * i2cp, uint8_t * data, uint16_t length) {
memcpy(twi2c_outgoing_body, data, length);
twi2c_outgoing_message.size = length;
i2cSlaveReplyI(i2cp, &twi2c_outgoing_message);
return 0;
}
uint8_t twi2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length) {
return i2cMasterTransmitTimeout(&I2C_DRIVER, address/2, tx_body, tx_length, rx_body, rx_length, MS2ST(100));
}
uint8_t twi2c_start_listening(uint8_t address, twi2c_message_received callback) {
twi2c_message_received_callback = callback;
I2C_DRIVER.slaveTimeout = MS2ST(100);
i2cSlaveConfigure(&I2C_DRIVER, &twi2c_incoming_message, &twi2c_outgoing_message);
i2cMatchAddress(&I2C_DRIVER, address/2);
return 0;
}
uint8_t twi2c_restart_listening(uint8_t address) {
i2cMatchAddress(&I2C_DRIVER, address/2);
return 0;
}
void twi2c_stop(void) {
i2cUnmatchAll(&I2C_DRIVER);
i2cStop(&I2C_DRIVER);
}

48
drivers/arm/twi2c.h Normal file
View File

@ -0,0 +1,48 @@
/* Copyright 2018 Jack Humbert
*
* 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 TWI2C_H
#define TWI2C_H
#include "ch.h"
#include "hal.h"
#ifndef I2C_DRIVER
#define I2C_DRIVER I2CD1
#endif
#define slaveI2Caddress 0x30 /* Address in our terms - halved by later code */
//#define myOtherI2Caddress 0x19
I2CSlaveMsgCB twi2c_incoming_message_process, twi2c_catch_error, twi2c_clear_after_send;
typedef void (*twi2c_message_received)(I2CDriver *, uint8_t *, uint16_t);
void twi2c_init(void);
uint8_t twi2c_start(void);
uint8_t twi2c_write(uint8_t data);
uint8_t twi2c_read_ack(void);
uint8_t twi2c_read_nack(void);
uint8_t twi2c_transmit(uint8_t address, uint8_t* data, uint16_t length);
uint8_t twi2c_receive(uint8_t address, uint8_t* data, uint16_t length);
uint8_t twi2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length);
uint8_t twi2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length);
void twi2c_stop(void);
uint8_t twi2c_reply(I2CDriver * i2cp, uint8_t * data, uint16_t length);
uint8_t twi2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length);
uint8_t twi2c_start_listening(uint8_t address, twi2c_message_received callback);
uint8_t twi2c_restart_listening(uint8_t address);
#endif

160
drivers/arm/ws2812.c Normal file
View File

@ -0,0 +1,160 @@
/*
* LEDDriver.c
*
* Created on: Aug 26, 2013
* Author: Omri Iluz
*/
#include "ws2812.h"
#include "stdlib.h"
static uint8_t *fb;
static int sLeds;
static stm32_gpio_t *sPort;
static uint32_t sMask;
uint8_t* dma_source;
void setColor(uint8_t color, uint8_t *buf,uint32_t mask){
int i;
for (i=0;i<8;i++){
buf[i]=((color<<i)&0b10000000?0x0:mask);
}
}
void setColorRGB(Color c, uint8_t *buf, uint32_t mask){
setColor(c.G,buf, mask);
setColor(c.R,buf+8, mask);
setColor(c.B,buf+16, mask);
}
/**
* @brief Initialize Led Driver
* @details Initialize the Led Driver based on parameters.
* Following initialization, the frame buffer would automatically be
* exported to the supplied port and pins in the right timing to drive
* a chain of WS2812B controllers
* @note The function assumes the controller is running at 72Mhz
* @note Timing is critical for WS2812. While all timing is done in hardware
* need to verify memory bandwidth is not exhausted to avoid DMA delays
*
* @param[in] leds length of the LED chain controlled by each pin
* @param[in] port which port would be used for output
* @param[in] mask Which pins would be used for output, each pin is a full chain
* @param[out] o_fb initialized frame buffer
*
*/
void ledDriverInit(int leds, stm32_gpio_t *port, uint32_t mask, uint8_t **o_fb) {
sLeds=leds;
sPort=port;
sMask=mask;
palSetGroupMode(port, sMask, 0, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST|PAL_STM32_PUPDR_FLOATING);
// configure pwm timers -
// timer 2 as master, active for data transmission and inactive to disable transmission during reset period (50uS)
// timer 3 as slave, during active time creates a 1.25 uS signal, with duty cycle controlled by frame buffer values
static PWMConfig pwmc2 = {72000000 / 90, /* 800Khz PWM clock frequency. 1/90 of PWMC3 */
(72000000 / 90) * 0.05, /*Total period is 50ms (20FPS), including sLeds cycles + reset length for ws2812b and FB writes */
NULL,
{ {PWM_OUTPUT_ACTIVE_HIGH, NULL},
{PWM_OUTPUT_DISABLED, NULL},
{PWM_OUTPUT_DISABLED, NULL},
{PWM_OUTPUT_DISABLED, NULL}},
TIM_CR2_MMS_2, /* master mode selection */
0, };
/* master mode selection */
static PWMConfig pwmc3 = {72000000,/* 72Mhz PWM clock frequency. */
90, /* 90 cycles period (1.25 uS per period @72Mhz */
NULL,
{ {PWM_OUTPUT_ACTIVE_HIGH, NULL},
{PWM_OUTPUT_ACTIVE_HIGH, NULL},
{PWM_OUTPUT_ACTIVE_HIGH, NULL},
{PWM_OUTPUT_ACTIVE_HIGH, NULL}},
0,
0,
};
dma_source = chHeapAlloc(NULL, 1);
fb = chHeapAlloc(NULL, ((sLeds) * 24)+10);
*o_fb=fb;
int j;
for (j = 0; j < (sLeds) * 24; j++) fb[j] = 0;
dma_source[0] = sMask;
// DMA stream 2, triggered by channel3 pwm signal. if FB indicates, reset output value early to indicate "0" bit to ws2812
dmaStreamAllocate(STM32_DMA1_STREAM2, 10, NULL, NULL);
dmaStreamSetPeripheral(STM32_DMA1_STREAM2, &(sPort->BSRR.H.clear));
dmaStreamSetMemory0(STM32_DMA1_STREAM2, fb);
dmaStreamSetTransactionSize(STM32_DMA1_STREAM2, (sLeds) * 24);
dmaStreamSetMode(
STM32_DMA1_STREAM2,
STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_MINC | STM32_DMA_CR_PSIZE_BYTE
| STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(2));
// DMA stream 3, triggered by pwm update event. output high at beginning of signal
dmaStreamAllocate(STM32_DMA1_STREAM3, 10, NULL, NULL);
dmaStreamSetPeripheral(STM32_DMA1_STREAM3, &(sPort->BSRR.H.set));
dmaStreamSetMemory0(STM32_DMA1_STREAM3, dma_source);
dmaStreamSetTransactionSize(STM32_DMA1_STREAM3, 1);
dmaStreamSetMode(
STM32_DMA1_STREAM3, STM32_DMA_CR_TEIE|
STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_BYTE
| STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3));
// DMA stream 6, triggered by channel1 update event. reset output value late to indicate "1" bit to ws2812.
// always triggers but no affect if dma stream 2 already change output value to 0
dmaStreamAllocate(STM32_DMA1_STREAM6, 10, NULL, NULL);
dmaStreamSetPeripheral(STM32_DMA1_STREAM6, &(sPort->BSRR.H.clear));
dmaStreamSetMemory0(STM32_DMA1_STREAM6, dma_source);
dmaStreamSetTransactionSize(STM32_DMA1_STREAM6, 1);
dmaStreamSetMode(
STM32_DMA1_STREAM6,
STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_BYTE
| STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3));
pwmStart(&PWMD2, &pwmc2);
pwmStart(&PWMD3, &pwmc3);
// set pwm3 as slave, triggerd by pwm2 oc1 event. disables pwmd2 for synchronization.
PWMD3.tim->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_2 | TIM_SMCR_TS_0;
PWMD2.tim->CR1 &= ~TIM_CR1_CEN;
// set pwm values.
// 28 (duty in ticks) / 90 (period in ticks) * 1.25uS (period in S) = 0.39 uS
pwmEnableChannel(&PWMD3, 2, 28);
// 58 (duty in ticks) / 90 (period in ticks) * 1.25uS (period in S) = 0.806 uS
pwmEnableChannel(&PWMD3, 0, 58);
// active during transfer of 90 cycles * sLeds * 24 bytes * 1/90 multiplier
pwmEnableChannel(&PWMD2, 0, 90 * sLeds * 24 / 90);
// stop and reset counters for synchronization
PWMD2.tim->CNT = 0;
// Slave (TIM3) needs to "update" immediately after master (TIM2) start in order to start in sync.
// this initial sync is crucial for the stability of the run
PWMD3.tim->CNT = 89;
PWMD3.tim->DIER |= TIM_DIER_CC3DE | TIM_DIER_CC1DE | TIM_DIER_UDE;
dmaStreamEnable(STM32_DMA1_STREAM3);
dmaStreamEnable(STM32_DMA1_STREAM6);
dmaStreamEnable(STM32_DMA1_STREAM2);
// all systems go! both timers and all channels are configured to resonate
// in complete sync without any need for CPU cycles (only DMA and timers)
// start pwm2 for system to start resonating
PWMD2.tim->CR1 |= TIM_CR1_CEN;
}
void ledDriverWaitCycle(void){
while (PWMD2.tim->CNT < 90 * sLeds * 24 / 90){chThdSleepMicroseconds(1);};
}
void testPatternFB(uint8_t *fb){
int i;
Color tmpC = {rand()%256, rand()%256, rand()%256};
for (i=0;i<sLeds;i++){
setColorRGB(tmpC,fb+24*i, sMask);
}
}
void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds) {
// uint8_t i = 0;
// while (i < number_of_leds) {
// ws2812_write_led(i, ledarray[i].r, ledarray[i].g, ledarray[i].b);
// i++;
// }
}
void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds) {
}

31
drivers/arm/ws2812.h Normal file
View File

@ -0,0 +1,31 @@
/*
* LEDDriver.h
*
* Created on: Aug 26, 2013
* Author: Omri Iluz
*/
#ifndef WS2812_H_
#define WS2812_H_
#include "hal.h"
#include "rgblight_types.h"
#define sign(x) (( x > 0 ) - ( x < 0 ))
typedef struct Color Color;
struct Color {
uint8_t R;
uint8_t G;
uint8_t B;
};
void ledDriverInit(int leds, stm32_gpio_t *port, uint32_t mask, uint8_t **o_fb);
void setColorRGB(Color c, uint8_t *buf, uint32_t mask);
void testPatternFB(uint8_t *fb);
void ledDriverWaitCycle(void);
void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds);
void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds);
#endif /* LEDDRIVER_H_ */

View File

@ -1,22 +0,0 @@
/* Library made by: g4lvanix
* Github repository: https://github.com/g4lvanix/I2C-master-lib
*/
#ifndef I2C_MASTER_H
#define I2C_MASTER_H
#define I2C_READ 0x01
#define I2C_WRITE 0x00
void i2c_init(void);
uint8_t i2c_start(uint8_t address);
uint8_t i2c_write(uint8_t data);
uint8_t i2c_read_ack(void);
uint8_t i2c_read_nack(void);
uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length);
uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length);
uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length);
uint8_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length);
void i2c_stop(void);
#endif // I2C_MASTER_H

View File

@ -1,244 +0,0 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
*
* 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 "is31fl3731.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include "i2c_master.h"
#include "progmem.h"
// This is a 7-bit address, that gets left-shifted and bit 0
// set to 0 for write, 1 for read (as per I2C protocol)
// The address will vary depending on your wiring:
// 0b1110100 AD <-> GND
// 0b1110111 AD <-> VCC
// 0b1110101 AD <-> SCL
// 0b1110110 AD <-> SDA
#define ISSI_ADDR_DEFAULT 0x74
#define ISSI_REG_CONFIG 0x00
#define ISSI_REG_CONFIG_PICTUREMODE 0x00
#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08
#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18
#define ISSI_CONF_PICTUREMODE 0x00
#define ISSI_CONF_AUTOFRAMEMODE 0x04
#define ISSI_CONF_AUDIOMODE 0x08
#define ISSI_REG_PICTUREFRAME 0x01
#define ISSI_REG_SHUTDOWN 0x0A
#define ISSI_REG_AUDIOSYNC 0x06
#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine'
// Transfer buffer for TWITransmitData()
uint8_t g_twi_transfer_buffer[20];
// These buffers match the IS31FL3731 PWM registers 0x24-0xB3.
// Storing them like this is optimal for I2C transfers to the registers.
// We could optimize this and take out the unused registers from these
// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[DRIVER_COUNT][144];
bool g_pwm_buffer_update_required = false;
uint8_t g_led_control_registers[DRIVER_COUNT][18] = { { 0 }, { 0 } };
bool g_led_control_registers_update_required = false;
// This is the bit pattern in the LED control registers
// (for matrix A, add one to register for matrix B)
//
// reg - b7 b6 b5 b4 b3 b2 b1 b0
// 0x00 - R08,R07,R06,R05,R04,R03,R02,R01
// 0x02 - G08,G07,G06,G05,G04,G03,G02,R00
// 0x04 - B08,B07,B06,B05,B04,B03,G01,G00
// 0x06 - - , - , - , - , - ,B02,B01,B00
// 0x08 - - , - , - , - , - , - , - , -
// 0x0A - B17,B16,B15, - , - , - , - , -
// 0x0C - G17,G16,B14,B13,B12,B11,B10,B09
// 0x0E - R17,G15,G14,G13,G12,G11,G10,G09
// 0x10 - R16,R15,R14,R13,R12,R11,R10,R09
void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data )
{
g_twi_transfer_buffer[0] = reg;
g_twi_transfer_buffer[1] = data;
//Transmit data until succesful
while(i2c_transmit(addr << 1, g_twi_transfer_buffer,2) != 0);
}
void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer )
{
// assumes bank is already selected
// transmit PWM registers in 9 transfers of 16 bytes
// g_twi_transfer_buffer[] is 20 bytes
// iterate over the pwm_buffer contents at 16 byte intervals
for ( int i = 0; i < 144; i += 16 )
{
// set the first register, e.g. 0x24, 0x34, 0x44, etc.
g_twi_transfer_buffer[0] = 0x24 + i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
for ( int j = 0; j < 16; j++ )
{
g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j];
}
//Transmit buffer until succesful
while(i2c_transmit(addr << 1, g_twi_transfer_buffer,17) != 0);
}
}
void IS31FL3731_init( uint8_t addr )
{
// In order to avoid the LEDs being driven with garbage data
// in the LED driver's PWM registers, first enable software shutdown,
// then set up the mode and other settings, clear the PWM registers,
// then disable software shutdown.
// select "function register" bank
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
// enable software shutdown
IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x00 );
// this delay was copied from other drivers, might not be needed
_delay_ms( 10 );
// picture mode
IS31FL3731_write_register( addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE );
// display frame 0
IS31FL3731_write_register( addr, ISSI_REG_PICTUREFRAME, 0x00 );
// audio sync off
IS31FL3731_write_register( addr, ISSI_REG_AUDIOSYNC, 0x00 );
// select bank 0
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
// turn off all LEDs in the LED control register
for ( int i = 0x00; i <= 0x11; i++ )
{
IS31FL3731_write_register( addr, i, 0x00 );
}
// turn off all LEDs in the blink control register (not really needed)
for ( int i = 0x12; i <= 0x23; i++ )
{
IS31FL3731_write_register( addr, i, 0x00 );
}
// set PWM on all LEDs to 0
for ( int i = 0x24; i <= 0xB3; i++ )
{
IS31FL3731_write_register( addr, i, 0x00 );
}
// select "function register" bank
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
// disable software shutdown
IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x01 );
// select bank 0 and leave it selected.
// most usage after initialization is just writing PWM buffers in bank 0
// as there's not much point in double-buffering
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
}
void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue )
{
if ( index >= 0 && index < DRIVER_LED_TOTAL ) {
is31_led led = g_is31_leds[index];
// Subtract 0x24 to get the second index of g_pwm_buffer
g_pwm_buffer[led.driver][led.r - 0x24] = red;
g_pwm_buffer[led.driver][led.g - 0x24] = green;
g_pwm_buffer[led.driver][led.b - 0x24] = blue;
g_pwm_buffer_update_required = true;
}
}
void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue )
{
for ( int i = 0; i < DRIVER_LED_TOTAL; i++ )
{
IS31FL3731_set_color( i, red, green, blue );
}
}
void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue )
{
is31_led led = g_is31_leds[index];
uint8_t control_register_r = (led.r - 0x24) / 8;
uint8_t control_register_g = (led.g - 0x24) / 8;
uint8_t control_register_b = (led.b - 0x24) / 8;
uint8_t bit_r = (led.r - 0x24) % 8;
uint8_t bit_g = (led.g - 0x24) % 8;
uint8_t bit_b = (led.b - 0x24) % 8;
if ( red ) {
g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
} else {
g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
}
if ( green ) {
g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
} else {
g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
}
if ( blue ) {
g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
} else {
g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
}
g_led_control_registers_update_required = true;
}
void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 )
{
if ( g_pwm_buffer_update_required )
{
IS31FL3731_write_pwm_buffer( addr1, g_pwm_buffer[0] );
IS31FL3731_write_pwm_buffer( addr2, g_pwm_buffer[1] );
}
g_pwm_buffer_update_required = false;
}
void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 )
{
if ( g_led_control_registers_update_required )
{
for ( int i=0; i<18; i++ )
{
IS31FL3731_write_register(addr1, i, g_led_control_registers[0][i] );
IS31FL3731_write_register(addr2, i, g_led_control_registers[1][i] );
}
}
}

122
drivers/avr/i2c_master.c → drivers/avr/twi2c.c Executable file → Normal file
View File

@ -5,44 +5,44 @@
#include <avr/io.h>
#include <util/twi.h>
#include "i2c_master.h"
#include "twi2c.h"
#define F_SCL 400000UL // SCL frequency
#define Prescaler 1
#define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16 ) / 2)
void i2c_init(void)
void twi2c_init(void)
{
TWBR = (uint8_t)TWBR_val;
}
uint8_t i2c_start(uint8_t address)
uint8_t twi2c_start(uint8_t address)
{
// reset TWI control register
TWCR = 0;
// transmit START condition
// transmit START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
// wait for end of transmission
while( !(TWCR & (1<<TWINT)) );
// check if the start condition was successfully transmitted
if((TWSR & 0xF8) != TW_START){ return 1; }
// load slave address into data register
TWDR = address;
// start transmission of address
TWCR = (1<<TWINT) | (1<<TWEN);
// wait for end of transmission
while( !(TWCR & (1<<TWINT)) );
// check if the device has acknowledged the READ / WRITE mode
uint8_t twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
return 0;
}
uint8_t i2c_write(uint8_t data)
uint8_t twi2c_write(uint8_t data)
{
// load data into data register
TWDR = data;
@ -50,26 +50,26 @@ uint8_t i2c_write(uint8_t data)
TWCR = (1<<TWINT) | (1<<TWEN);
// wait for end of transmission
while( !(TWCR & (1<<TWINT)) );
if( (TWSR & 0xF8) != TW_MT_DATA_ACK ){ return 1; }
return 0;
}
uint8_t i2c_read_ack(void)
uint8_t twi2c_read_ack(void)
{
// start TWI module and acknowledge data after reception
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
// wait for end of transmission
while( !(TWCR & (1<<TWINT)) );
// return received data from TWDR
return TWDR;
}
uint8_t i2c_read_nack(void)
uint8_t twi2c_read_nack(void)
{
// start receiving without acknowledging reception
TWCR = (1<<TWINT) | (1<<TWEN);
// wait for end of transmission
@ -78,71 +78,71 @@ uint8_t i2c_read_nack(void)
return TWDR;
}
uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length)
uint8_t twi2c_transmit(uint8_t address, uint8_t* data, uint16_t length)
{
if (i2c_start(address | I2C_WRITE)) return 1;
for (uint16_t i = 0; i < length; i++)
{
if (i2c_write(data[i])) return 1;
}
i2c_stop();
return 0;
}
uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length)
{
if (i2c_start(address | I2C_READ)) return 1;
for (uint16_t i = 0; i < (length-1); i++)
{
data[i] = i2c_read_ack();
}
data[(length-1)] = i2c_read_nack();
i2c_stop();
return 0;
}
uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length)
{
if (i2c_start(devaddr | 0x00)) return 1;
i2c_write(regaddr);
if (twi2c_start(address | I2C_WRITE)) return 1;
for (uint16_t i = 0; i < length; i++)
{
if (i2c_write(data[i])) return 1;
if (twi2c_write(data[i])) return 1;
}
i2c_stop();
twi2c_stop();
return 0;
}
uint8_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length)
uint8_t twi2c_receive(uint8_t address, uint8_t* data, uint16_t length)
{
if (i2c_start(devaddr)) return 1;
i2c_write(regaddr);
if (i2c_start(devaddr | 0x01)) return 1;
if (twi2c_start(address | I2C_READ)) return 1;
for (uint16_t i = 0; i < (length-1); i++)
{
data[i] = i2c_read_ack();
data[i] = twi2c_read_ack();
}
data[(length-1)] = i2c_read_nack();
data[(length-1)] = twi2c_read_nack();
i2c_stop();
twi2c_stop();
return 0;
}
void i2c_stop(void)
uint8_t twi2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length)
{
if (twi2c_start(devaddr | 0x00)) return 1;
twi2c_write(regaddr);
for (uint16_t i = 0; i < length; i++)
{
if (twi2c_write(data[i])) return 1;
}
twi2c_stop();
return 0;
}
uint8_t twi2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length)
{
if (twi2c_start(devaddr)) return 1;
twi2c_write(regaddr);
if (twi2c_start(devaddr | 0x01)) return 1;
for (uint16_t i = 0; i < (length-1); i++)
{
data[i] = twi2c_read_ack();
}
data[(length-1)] = twi2c_read_nack();
twi2c_stop();
return 0;
}
void twi2c_stop(void)
{
// transmit STOP condition
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

22
drivers/avr/twi2c.h Normal file
View File

@ -0,0 +1,22 @@
/* Library made by: g4lvanix
* Github repository: https://github.com/g4lvanix/I2C-master-lib
*/
#ifndef TWI2C_H
#define TWI2C_H
#define I2C_READ 0x01
#define I2C_WRITE 0x00
void twi2c_init(void);
uint8_t twi2c_start(uint8_t address);
uint8_t twi2c_write(uint8_t data);
uint8_t twi2c_read_ack(void);
uint8_t twi2c_read_nack(void);
uint8_t twi2c_transmit(uint8_t address, uint8_t* data, uint16_t length);
uint8_t twi2c_receive(uint8_t address, uint8_t* data, uint16_t length);
uint8_t twi2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length);
uint8_t twi2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length);
void twi2c_stop(void);
#endif // I2C_MASTER_H

244
drivers/is31fl3731.c Normal file
View File

@ -0,0 +1,244 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
*
* 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 "is31fl3731.h"
#include "wait.h"
#include <string.h>
#include "twi2c.h"
#include "progmem.h"
// This is a 7-bit address, that gets left-shifted and bit 0
// set to 0 for write, 1 for read (as per I2C protocol)
// The address will vary depending on your wiring:
// 0b1110100 AD <-> GND
// 0b1110111 AD <-> VCC
// 0b1110101 AD <-> SCL
// 0b1110110 AD <-> SDA
#define ISSI_ADDR_DEFAULT 0x74
#define ISSI_REG_CONFIG 0x00
#define ISSI_REG_CONFIG_PICTUREMODE 0x00
#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08
#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18
#define ISSI_CONF_PICTUREMODE 0x00
#define ISSI_CONF_AUTOFRAMEMODE 0x04
#define ISSI_CONF_AUDIOMODE 0x08
#define ISSI_REG_PICTUREFRAME 0x01
#define ISSI_REG_SHUTDOWN 0x0A
#define ISSI_REG_AUDIOSYNC 0x06
#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine'
// Transfer buffer for TWITransmitData()
uint8_t g_twi_transfer_buffer[20];
// These buffers match the IS31FL3731 PWM registers 0x24-0xB3.
// Storing them like this is optimal for I2C transfers to the registers.
// We could optimize this and take out the unused registers from these
// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[DRIVER_COUNT][144];
bool g_pwm_buffer_update_required = false;
uint8_t g_led_control_registers[DRIVER_COUNT][18] = { { 0 }, { 0 } };
bool g_led_control_registers_update_required = false;
// This is the bit pattern in the LED control registers
// (for matrix A, add one to register for matrix B)
//
// reg - b7 b6 b5 b4 b3 b2 b1 b0
// 0x00 - R08,R07,R06,R05,R04,R03,R02,R01
// 0x02 - G08,G07,G06,G05,G04,G03,G02,R00
// 0x04 - B08,B07,B06,B05,B04,B03,G01,G00
// 0x06 - - , - , - , - , - ,B02,B01,B00
// 0x08 - - , - , - , - , - , - , - , -
// 0x0A - B17,B16,B15, - , - , - , - , -
// 0x0C - G17,G16,B14,B13,B12,B11,B10,B09
// 0x0E - R17,G15,G14,G13,G12,G11,G10,G09
// 0x10 - R16,R15,R14,R13,R12,R11,R10,R09
void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data )
{
g_twi_transfer_buffer[0] = reg;
g_twi_transfer_buffer[1] = data;
//Transmit data until succesful
//while(twi2c_transmit(addr << 1, g_twi_transfer_buffer,2) != 0);
twi2c_transmit(addr << 1, g_twi_transfer_buffer,2);
}
void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer )
{
// assumes bank is already selected
// transmit PWM registers in 9 transfers of 16 bytes
// g_twi_transfer_buffer[] is 20 bytes
// iterate over the pwm_buffer contents at 16 byte intervals
for ( int i = 0; i < 144; i += 16 )
{
// set the first register, e.g. 0x24, 0x34, 0x44, etc.
g_twi_transfer_buffer[0] = 0x24 + i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
for ( int j = 0; j < 16; j++ )
{
g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j];
}
//Transmit buffer until succesful
//while(twi2c_transmit(addr << 1, g_twi_transfer_buffer,17) != 0);
twi2c_transmit(addr << 1, g_twi_transfer_buffer,17);
}
}
void IS31FL3731_init( uint8_t addr )
{
// In order to avoid the LEDs being driven with garbage data
// in the LED driver's PWM registers, first enable software shutdown,
// then set up the mode and other settings, clear the PWM registers,
// then disable software shutdown.
// select "function register" bank
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
// enable software shutdown
IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x00 );
// this delay was copied from other drivers, might not be needed
wait_ms( 10 );
// picture mode
IS31FL3731_write_register( addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE );
// display frame 0
IS31FL3731_write_register( addr, ISSI_REG_PICTUREFRAME, 0x00 );
// audio sync off
IS31FL3731_write_register( addr, ISSI_REG_AUDIOSYNC, 0x00 );
// select bank 0
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
// turn off all LEDs in the LED control register
for ( int i = 0x00; i <= 0x11; i++ )
{
IS31FL3731_write_register( addr, i, 0x00 );
}
// turn off all LEDs in the blink control register (not really needed)
for ( int i = 0x12; i <= 0x23; i++ )
{
IS31FL3731_write_register( addr, i, 0x00 );
}
// set PWM on all LEDs to 0
for ( int i = 0x24; i <= 0xB3; i++ )
{
IS31FL3731_write_register( addr, i, 0x00 );
}
// select "function register" bank
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
// disable software shutdown
IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x01 );
// select bank 0 and leave it selected.
// most usage after initialization is just writing PWM buffers in bank 0
// as there's not much point in double-buffering
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
}
void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue )
{
if ( index >= 0 && index < DRIVER_LED_TOTAL ) {
is31_led led = g_is31_leds[index];
// Subtract 0x24 to get the second index of g_pwm_buffer
g_pwm_buffer[led.driver][led.r - 0x24] = red;
g_pwm_buffer[led.driver][led.g - 0x24] = green;
g_pwm_buffer[led.driver][led.b - 0x24] = blue;
g_pwm_buffer_update_required = true;
}
}
void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue )
{
for ( int i = 0; i < DRIVER_LED_TOTAL; i++ )
{
IS31FL3731_set_color( i, red, green, blue );
}
}
void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue )
{
is31_led led = g_is31_leds[index];
uint8_t control_register_r = (led.r - 0x24) / 8;
uint8_t control_register_g = (led.g - 0x24) / 8;
uint8_t control_register_b = (led.b - 0x24) / 8;
uint8_t bit_r = (led.r - 0x24) % 8;
uint8_t bit_g = (led.g - 0x24) % 8;
uint8_t bit_b = (led.b - 0x24) % 8;
if ( red ) {
g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
} else {
g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
}
if ( green ) {
g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
} else {
g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
}
if ( blue ) {
g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
} else {
g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
}
g_led_control_registers_update_required = true;
}
void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 )
{
if ( g_pwm_buffer_update_required )
{
IS31FL3731_write_pwm_buffer( addr1, g_pwm_buffer[0] );
IS31FL3731_write_pwm_buffer( addr2, g_pwm_buffer[1] );
}
g_pwm_buffer_update_required = false;
}
void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 )
{
if ( g_led_control_registers_update_required )
{
for ( int i=0; i<18; i++ )
{
IS31FL3731_write_register(addr1, i, g_led_control_registers[0][i] );
IS31FL3731_write_register(addr2, i, g_led_control_registers[1][i] );
}
}
}

View File

@ -23,7 +23,7 @@
#include <stdbool.h>
typedef struct is31_led {
uint8_t driver:2;
uint8_t driver:2;
uint8_t r;
uint8_t g;
uint8_t b;

View File

@ -0,0 +1,202 @@
/* Copyright 2018 Jack Humbert
*
* 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 "qwiic_keyboard.h"
#include "keymap.h"
#include "matrix.h"
#include "keyboard.h"
#include "twi2c.h"
#include <string.h>
#include "usb_main.h"
#include "usb_driver.h"
#define QWIIC_KEYBOARD_LAYERS 16
#define QWIIC_KEYBOARD_ROWS 8
#define QWIIC_KEYBOARD_COLS 8
#define qwiic_matrix_t uint8_t
#define QWIIC_KEYBOARD_HANDSHAKE_ADDRESS 0b01010100
#define QWIIC_KEYBOARD_LISTENING_ADDRESS_START 0b01010110
#define QWIIC_KEYBOARD_HANDSHAKE_MESSAGE_SIZE (QWIIC_KEYBOARD_LAYERS * QWIIC_KEYBOARD_ROWS * QWIIC_KEYBOARD_COLS)
#define QWIIC_KEYBOARD_MATRIX_MESSAGE_SIZE MATRIX_ROWS
void qwiic_keyboard_write_keymap(uint8_t * pointer);
void qwiic_keyboard_read_keymap(uint8_t * pointer);
bool qwiic_keyboard_master = false;
bool qwiic_keyboard_connected = false;
uint8_t qwiic_keyboard_handshake_message[QWIIC_KEYBOARD_HANDSHAKE_MESSAGE_SIZE] = {0};
uint8_t qwiic_keyboard_matrix_message[QWIIC_KEYBOARD_ROWS] = {0};
twi2c_message_received qwiic_keyboard_message_received_ptr = qwiic_keyboard_message_received;
uint16_t qwiic_keyboard_keymap[QWIIC_KEYBOARD_LAYERS][QWIIC_KEYBOARD_ROWS][QWIIC_KEYBOARD_COLS] = {0};
uint8_t qwiic_keyboard_listening_address = QWIIC_KEYBOARD_LISTENING_ADDRESS_START;
uint8_t qwiic_keyboard_processing_slave = false;
void qwiic_keyboard_init(void) {
twi2c_init();
twi2c_start();
twi2c_start_listening(QWIIC_KEYBOARD_HANDSHAKE_ADDRESS, qwiic_keyboard_message_received_ptr);
}
void qwiic_keyboard_set_master(void) {
twi2c_stop();
twi2c_start();
qwiic_keyboard_master = true;
}
uint8_t command[1] = { 0x00 };
void qwiic_keyboard_task(void) {
if (USB_DRIVER.state == USB_ACTIVE)
qwiic_keyboard_master = true;
else
qwiic_keyboard_master = false;
if (qwiic_keyboard_master) {
if (qwiic_keyboard_connected) {
// send empty message, expecting matrix info
if (MSG_OK == twi2c_transmit_receive(qwiic_keyboard_listening_address,
command, 1,
qwiic_keyboard_matrix_message, QWIIC_KEYBOARD_MATRIX_MESSAGE_SIZE
)) {
// majority of this is pulled from keyboard.c:keyboard_task()
static qwiic_matrix_t matrix_prev[QWIIC_KEYBOARD_ROWS];
qwiic_matrix_t matrix_row = 0;
qwiic_matrix_t matrix_change = 0;
#ifdef QMK_KEYS_PER_SCAN
uint8_t keys_processed = 0;
#endif
qwiic_keyboard_processing_slave = true;
for (uint8_t r = 0; r < QWIIC_KEYBOARD_ROWS; r++) {
matrix_row = qwiic_keyboard_matrix_message[r];
matrix_change = matrix_row ^ matrix_prev[r];
if (matrix_change) {
for (uint8_t c = 0; c < QWIIC_KEYBOARD_COLS; c++) {
if (matrix_change & ((qwiic_matrix_t)1<<c)) {
action_exec((keyevent_t){
.key = (keypos_t){ .row = r, .col = c },
.pressed = (matrix_row & ((qwiic_matrix_t)1<<c)),
.time = (timer_read() | 1) /* time should not be 0 */
});
// record a processed key
matrix_prev[r] ^= ((qwiic_matrix_t)1<<c);
#ifdef QMK_KEYS_PER_SCAN
// only jump out if we have processed "enough" keys.
if (++keys_processed >= QMK_KEYS_PER_SCAN)
#endif
// process a key per task call
goto QWIIC_MATRIX_LOOP_END;
}
}
}
}
// call with pseudo tick event when no real key event.
#ifdef QMK_KEYS_PER_SCAN
// we can get here with some keys processed now.
if (!keys_processed)
#endif
action_exec(TICK);
QWIIC_MATRIX_LOOP_END:
qwiic_keyboard_processing_slave = false;
} else {
// disconnect
// qwiic_keyboard_connected = false;
}
} else { // if not connected
// send new address to listen on, expect back keymap
if (MSG_OK == twi2c_transmit_receive(QWIIC_KEYBOARD_HANDSHAKE_ADDRESS,
&qwiic_keyboard_listening_address, 1,
qwiic_keyboard_handshake_message, QWIIC_KEYBOARD_HANDSHAKE_MESSAGE_SIZE
)) {
qwiic_keyboard_connected = true;
// load keymap into memory
qwiic_keyboard_read_keymap(qwiic_keyboard_handshake_message);
}
}
}
}
float song_one_up[][2] = SONG(ONE_UP_SOUND);
bool first_message = true;
void qwiic_keyboard_message_received(I2CDriver *i2cp, uint8_t * body, uint16_t size) {
if (qwiic_keyboard_connected) {
for (uint8_t row = 0; row < QWIIC_KEYBOARD_ROWS; row++) {
if (row < MATRIX_ROWS) {
qwiic_keyboard_matrix_message[row] = matrix_get_row(row);
} else {
qwiic_keyboard_matrix_message[row] = 0;
}
}
twi2c_reply(i2cp, qwiic_keyboard_matrix_message, QWIIC_KEYBOARD_MATRIX_MESSAGE_SIZE);
if (first_message) {
PLAY_SONG(song_one_up);
first_message = false;
}
} else {
qwiic_keyboard_connected = true;
qwiic_keyboard_master = false;
qwiic_keyboard_listening_address = body[0];
twi2c_restart_listening(qwiic_keyboard_listening_address);
qwiic_keyboard_write_keymap(qwiic_keyboard_handshake_message);
twi2c_reply(i2cp, qwiic_keyboard_handshake_message, QWIIC_KEYBOARD_HANDSHAKE_MESSAGE_SIZE);
}
}
// qwiic_keyboard_message_received_ptr = qwiic_keyboard_message_received;
__attribute__((optimize("O0")))
void qwiic_keyboard_write_keymap(uint8_t * pointer) {
for (uint8_t layer = 0; layer < QWIIC_KEYBOARD_LAYERS; layer++) {
for (uint8_t row = 0; row < QWIIC_KEYBOARD_ROWS; row++) {
for (uint8_t col = 0; col < QWIIC_KEYBOARD_COLS; col++) {
uint16_t keycode = pgm_read_word(&keymaps[layer][row][col]);
*pointer++ = (keycode >> 8);
*pointer++ = (keycode & 0xFF);
}
}
}
}
void qwiic_keyboard_read_keymap(uint8_t * pointer) {
for (uint8_t layer = 0; layer < QWIIC_KEYBOARD_LAYERS; layer++) {
for (uint8_t row = 0; row < QWIIC_KEYBOARD_ROWS; row++) {
for (uint8_t col = 0; col < QWIIC_KEYBOARD_COLS; col++) {
uint16_t keycode = ((*pointer++) << 8);
keycode |= (*pointer++);
qwiic_keyboard_keymap[layer][row][col] = keycode;
}
}
}
}
// overwrite the built-in function - slaves don't need to process keycodes
bool is_keyboard_master(void) {
return qwiic_keyboard_master;
}
// overwrite the built-in function
uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) {
if (qwiic_keyboard_processing_slave) {
// trick the built-in handling to accept our replacement keymap
return qwiic_keyboard_keymap[(layer)][(key.row)][(key.col)];
//return KC_A;
} else {
// Read entire word (16bits)
return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]);
}
}

View File

@ -0,0 +1,26 @@
/* Copyright 2018 Jack Humbert
*
* 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 QWIIC_KEYBOARD_H
#define QWIIC_KEYBOARD_H
#include "quantum.h"
void qwiic_keyboard_init(void);
void qwiic_keyboard_task(void);
void qwiic_keyboard_message_received(I2CDriver *i2cp, uint8_t * body, uint16_t size);
#endif

View File

@ -1,5 +1,5 @@
#ifndef CA66_H
#define CA66_H
#ifndef KB_H
#define KB_H
#include "quantum.h"

View File

@ -25,8 +25,9 @@
/* number of backlight levels */
#define BACKLIGHT_PIN F0
#ifdef BACKLIGHT_PIN
#define BACKLIGHT_LEVELS 3
#endif
/* Set 0 if debouncing isn't needed */
#define DEBOUNCING_DELAY 5

View File

@ -51,6 +51,6 @@ CONSOLE_ENABLE ?= no # Console for debug(+400)
COMMAND_ENABLE ?= no # Commands for debug and configuration
SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend
NKRO_ENABLE ?= yes # USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
BACKLIGHT_ENABLE ?= yes # Enable keyboard backlight functionality
BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality
AUDIO_ENABLE ?= no
RGBLIGHT_ENABLE ?= yes

View File

@ -42,55 +42,24 @@ void backlight_init_ports(void) {
#endif
// for keyboard subdirectory level init functions
// @Override
void matrix_init_kb(void) {
// call user level keymaps, if any
matrix_init_user();
}
#ifdef RGBLIGHT_ENABLE
extern rgblight_config_t rgblight_config;
// custom RGB driver
void rgblight_set(void) {
if (!rgblight_config.enable) {
for (uint8_t i=0; i<RGBLED_NUM; i++) {
led[i].r = 0;
led[i].g = 0;
led[i].b = 0;
if (!rgblight_config.enable) {
for (uint8_t i = 0; i < RGBLED_NUM; i++) {
led[i].r = 0;
led[i].g = 0;
led[i].b = 0;
}
}
}
i2c_init();
i2c_send(0xb0, (uint8_t*)led, 3 * RGBLED_NUM);
}
bool rgb_init = false;
void matrix_scan_kb(void) {
// if LEDs were previously on before poweroff, turn them back on
if (rgb_init == false && rgblight_config.enable) {
i2c_init();
i2c_send(0xb0, (uint8_t*)led, 3 * RGBLED_NUM);
rgb_init = true;
}
rgblight_task();
#else
void matrix_scan_kb(void) {
#endif
matrix_scan_user();
/* Nothing else for now. */
}
__attribute__((weak)) // overridable
void matrix_init_user(void) {
}
__attribute__((weak)) // overridable
__attribute__ ((weak))
void matrix_scan_user(void) {
rgblight_task();
}
#endif

View File

@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "matrix.h"
#ifndef DEBOUNCE
# define DEBOUNCE 5
#define DEBOUNCE 5
#endif
static uint8_t debouncing = DEBOUNCE;
@ -29,9 +29,6 @@ static uint8_t debouncing = DEBOUNCE;
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
void matrix_set_row_status(uint8_t row);
uint8_t bit_reverse(uint8_t x);
void matrix_init(void) {
// all outputs for rows high
DDRB = 0xFF;
@ -50,8 +47,18 @@ void matrix_init(void) {
matrix[row] = 0x00;
matrix_debouncing[row] = 0x00;
}
}
matrix_init_quantum();
void matrix_set_row_status(uint8_t row) {
DDRB = (1 << row);
PORTB = ~(1 << row);
}
uint8_t bit_reverse(uint8_t x) {
x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa);
x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc);
x = ((x >> 4) & 0x0f) | ((x << 4) & 0xf0);
return x;
}
uint8_t matrix_scan(void) {
@ -86,24 +93,11 @@ uint8_t matrix_scan(void) {
}
}
matrix_scan_quantum();
matrix_scan_user();
return 1;
}
// declarations
void matrix_set_row_status(uint8_t row) {
DDRB = (1 << row);
PORTB = ~(1 << row);
}
uint8_t bit_reverse(uint8_t x) {
x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa);
x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc);
x = ((x >> 4) & 0x0f) | ((x << 4) & 0xf0);
return x;
}
inline matrix_row_t matrix_get_row(uint8_t row) {
return matrix[row];
}

View File

@ -1,84 +0,0 @@
/*
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
#include "config_common.h"
/* USB Device descriptor parameter */
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x3060
#define DEVICE_VER 0x0001
#define MANUFACTURER mtdjr
#define PRODUCT Not So MiniDox
#define DESCRIPTION A larger version of the MiniDox
/* key matrix size */
// Rows are doubled-up
#define MATRIX_ROWS 8
#define MATRIX_COLS 6
/* COL2ROW or ROW2COL */
#define DIODE_DIRECTION COL2ROW
// wiring of each half
#define MATRIX_ROW_PINS { D7, E6, B4, B5 }
#define MATRIX_COL_PINS { B6, B2, B3, B1, F7, D4 }
#define USE_SERIAL
//#define EE_HANDS
#define MASTER_LEFT
//#define MASTER_RIGHT
/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST
/* number of backlight levels */
// #define BACKLIGHT_LEVELS 3
/* Set 0 if debouncing isn't needed */
#define DEBOUNCING_DELAY 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)) \
)
/* 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
#endif

View File

@ -1,162 +0,0 @@
#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"
#ifdef USE_I2C
// 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 μC 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)
volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
static volatile uint8_t slave_buffer_pos;
static volatile bool slave_has_register_set = false;
// 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);
}
// 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_master_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_master_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_master_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_master_read(int ack) {
TWCR = (1<<TWINT) | (1<<TWEN) | (ack<<TWEA);
i2c_delay();
return TWDR;
}
void i2c_reset_state(void) {
TWCR = 0;
}
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);
}
#endif

View File

@ -1,49 +0,0 @@
#ifndef I2C_H
#define I2C_H
#include <stdint.h>
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#define I2C_READ 1
#define I2C_WRITE 0
#define I2C_ACK 1
#define I2C_NACK 0
#define SLAVE_BUFFER_SIZE 0x10
// i2c SCL clock frequency
#define SCL_CLOCK 400000L
extern volatile uint8_t i2c_slave_buffer[SLAVE_BUFFER_SIZE];
void i2c_master_init(void);
uint8_t i2c_master_start(uint8_t address);
void i2c_master_stop(void);
uint8_t i2c_master_write(uint8_t data);
uint8_t i2c_master_read(int);
void i2c_reset_state(void);
void i2c_slave_init(uint8_t address);
static inline unsigned char i2c_start_read(unsigned char addr) {
return i2c_master_start((addr << 1) | I2C_READ);
}
static inline unsigned char i2c_start_write(unsigned char addr) {
return i2c_master_start((addr << 1) | I2C_WRITE);
}
// from SSD1306 scrips
extern unsigned char i2c_rep_start(unsigned char addr);
extern void i2c_start_wait(unsigned char addr);
extern unsigned char i2c_readAck(void);
extern unsigned char i2c_readNak(void);
extern unsigned char i2c_read(unsigned char ack);
#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
#endif

View File

@ -1,121 +0,0 @@
#include QMK_KEYBOARD_H
extern keymap_config_t keymap_config;
// Each layer gets a name for readability, which is then used in the keymap matrix below.
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
// Layer names don't all need to be of the same length, obviously, and you can also skip them
// entirely and just use numbers.
#define _QWERTY 0
#define _LOWER 1
#define _RAISE 2
#define _ADJUST 16
enum custom_keycodes {
QWERTY = SAFE_RANGE,
LOWER,
RAISE,
ADJUST,
};
// Fillers to make layering more clear
#define _______ KC_TRNS
#define XXXXXXX KC_NO
#define KC_LOWR LOWER
#define KC_RASE RAISE
#define KC_RST RESET
#define KC_CAD LCTL(LALT(KC_DEL))
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_QWERTY] = LAYOUT(
// ,-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------.
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P,KC_BSPC,
// |-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------|
KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L,KC_SCLN,KC_QUOT,
// |-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------|
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M,KC_COMM, KC_DOT,KC_SLSH, KC_ENT,
// '-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------'
KC_LGUI,KC_LOWR, KC_SPC, KC_SPC,KC_RASE,KC_RALT
// `-------+-------+-------` `-------+-------+-------`
),
[_LOWER] = LAYOUT(
// ,-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------.
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_DEL,
// |-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------|
_______,_______,_______,_______,_______,_______, _______,_______,_______,KC_LCBR,KC_RCBR,KC_BSLS,
// |-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------|
_______,_______,_______,_______,_______,_______, _______,_______,_______,_______,_______,_______,
// '-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------'
_______,_______,_______, _______,_______,_______
// `-------+-------+-------` `-------+-------+-------`
),
[_RAISE] = LAYOUT(
// ,-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------.
KC_GRV,KC_EXLM, KC_AT,KC_HASH, KC_DLR,KC_PERC, KC_CIRC,KC_AMPR,KC_ASTR,KC_LPRN,KC_RPRN, KC_DEL,
// |-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------|
_______,_______,_______,_______,KC_MINS, KC_EQL, _______, KC_UP,_______,KC_LBRC,KC_RBRC,KC_PIPE,
// |-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------|
_______,_______,_______,_______,_______,_______, KC_LEFT,KC_DOWN,KC_RGHT,_______,_______,_______,
// '-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------'
_______,_______,_______, _______,_______,_______
// `-------+-------+-------` `-------+-------+-------`
),
[_ADJUST] = LAYOUT(
// ,-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------.
_______,_______,_______,_______, KC_RST,_______, _______,_______,_______,_______,_______, KC_CAD,
// |-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------|
_______,_______,_______,_______,_______,_______, _______,_______,_______,_______,_______,_______,
// |-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------|
_______,_______,_______,_______,_______,_______, _______,_______,_______,_______,_______,_______,
// '-------+-------+-------+-------+-------+-------. ,-------+-------+-------+-------+-------+-------'
_______,_______,_______, _______,_______,_______
// `-------+-------+-------` `-------+-------+-------`
)
};
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case QWERTY:
if (record->event.pressed) {
set_single_persistent_default_layer(_QWERTY);
}
return false;
break;
case LOWER:
if (record->event.pressed) {
layer_on(_LOWER);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
} else {
layer_off(_LOWER);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
}
return false;
break;
case RAISE:
if (record->event.pressed) {
layer_on(_RAISE);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
} else {
layer_off(_RAISE);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
}
return false;
break;
case ADJUST:
if (record->event.pressed) {
layer_on(_ADJUST);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
} else {
layer_off(_ADJUST);
update_tri_layer(_LOWER, _RAISE, _ADJUST);
}
return false;
break;
}
return true;
}

View File

@ -1,11 +0,0 @@
#ifndef CONFIG_USER_H
#define CONFIG_USER_H
#include QMK_KEYBOARD_CONFIG_H
#define SOLENOID_ENABLE
#define SOLENOID_PIN F6
#undef SOLENOID_ACTIVE
#define SOLENOID_ACTIVE true
#endif

Some files were not shown because too many files have changed in this diff Show More