Browse Source

merge from master

titmlb
Jack Humbert 5 years ago
parent
commit
4987042369
5422 changed files with 196481 additions and 69481 deletions
  1. +26
    -0
      .clang-format
  2. +1
    -1
      .editorconfig
  3. +16
    -15
      .github/ISSUE_TEMPLATE/bug_report.md
  4. +8
    -8
      .github/ISSUE_TEMPLATE/feature_request.md
  5. +3
    -3
      .github/ISSUE_TEMPLATE/other_issues.md
  6. +15
    -13
      .github/PULL_REQUEST_TEMPLATE.md
  7. +2
    -0
      .gitignore
  8. +8
    -2
      .travis.yml
  9. +1
    -1
      Dockerfile
  10. +18
    -10
      Makefile
  11. +19
    -14
      Vagrantfile
  12. +31
    -1
      build_keyboard.mk
  13. +9
    -0
      build_layout.mk
  14. +0
    -1
      common.mk
  15. +97
    -8
      common_features.mk
  16. +8
    -4
      docs/_summary.md
  17. +81
    -10
      docs/config_options.md
  18. +37
    -3
      docs/contributing.md
  19. +155
    -50
      docs/custom_quantum_functions.md
  20. +29
    -6
      docs/faq_build.md
  21. +2
    -2
      docs/faq_keymap.md
  22. +121
    -41
      docs/feature_advanced_keycodes.md
  23. +33
    -8
      docs/feature_audio.md
  24. +51
    -2
      docs/feature_backlight.md
  25. +3
    -1
      docs/feature_bootmagic.md
  26. +1
    -2
      docs/feature_combo.md
  27. +33
    -32
      docs/feature_command.md
  28. +42
    -0
      docs/feature_debounce_type.md
  29. +12
    -8
      docs/feature_encoders.md
  30. +9
    -1
      docs/feature_grave_esc.md
  31. +147
    -0
      docs/feature_haptic_feedback.md
  32. +29
    -0
      docs/feature_layouts.md
  33. +101
    -4
      docs/feature_leader_key.md
  34. +90
    -0
      docs/feature_led_matrix.md
  35. +100
    -44
      docs/feature_macros.md
  36. +90
    -52
      docs/feature_mouse_keys.md
  37. +274
    -0
      docs/feature_oled_driver.md
  38. +306
    -152
      docs/feature_rgb_matrix.md
  39. +157
    -23
      docs/feature_rgblight.md
  40. +59
    -0
      docs/feature_space_cadet.md
  41. +0
    -33
      docs/feature_space_cadet_shift.md
  42. +0
    -31
      docs/feature_space_cadet_shift_enter.md
  43. +90
    -29
      docs/feature_tap_dance.md
  44. +135
    -54
      docs/feature_unicode.md
  45. +39
    -15
      docs/feature_userspace.md
  46. +30
    -0
      docs/feature_velocikey.md
  47. +2
    -0
      docs/features.md
  48. +20
    -1
      docs/flashing.md
  49. +11
    -5
      docs/getting_started_build_tools.md
  50. +19
    -9
      docs/getting_started_make_guide.md
  51. +23
    -14
      docs/hand_wire.md
  52. +39
    -9
      docs/hardware_avr.md
  53. +3
    -3
      docs/hardware_drivers.md
  54. +82
    -69
      docs/hardware_keyboard_guidelines.md
  55. +1
    -1
      docs/how_keyboards_work.md
  56. +12
    -8
      docs/i2c_driver.md
  57. +3
    -3
      docs/internals_gpio_control.md
  58. +6
    -1
      docs/isp_flashing_guide.md
  59. +258
    -265
      docs/keycodes.md
  60. +50
    -50
      docs/keycodes_basic.md
  61. +4
    -60
      docs/keymap.md
  62. +8
    -3
      docs/newbs.md
  63. +105
    -0
      docs/newbs_building_firmware_configurator.md
  64. +71
    -4
      docs/newbs_flashing.md
  65. +8
    -3
      docs/newbs_getting_started.md
  66. +11
    -1
      docs/newbs_testing_debugging.md
  67. +0
    -0
      docs/other_eclipse.md
  68. +117
    -0
      docs/other_vscode.md
  69. +21
    -9
      docs/porting_your_keyboard_to_qmk_(arm_and_other_chibios_cpus).md
  70. +73
    -0
      docs/reference_info_json.md
  71. +38
    -34
      docs/understanding_qmk.md
  72. +32
    -0
      docs/zh-cn/README.md
  73. +106
    -0
      docs/zh-cn/_summary.md
  74. +54
    -0
      docs/zh-cn/getting_started_introduction.md
  75. +163
    -0
      docs/zh-cn/newbs_best_practices.md
  76. +81
    -0
      docs/zh-cn/newbs_building_firmware.md
  77. +307
    -0
      docs/zh-cn/newbs_flashing.md
  78. +102
    -0
      docs/zh-cn/newbs_getting_started.md
  79. +15
    -0
      docs/zh-cn/newbs_learn_more_resources.md
  80. +43
    -0
      docs/zh-cn/newbs_testing_debugging.md
  81. +30
    -19
      drivers/arm/i2c_master.c
  82. +23
    -7
      drivers/arm/i2c_master.h
  83. +101
    -0
      drivers/avr/apa102.c
  84. +46
    -0
      drivers/avr/apa102.h
  85. +80
    -91
      drivers/avr/i2c_master.c
  86. +4
    -4
      drivers/avr/i2c_master.h
  87. +15
    -12
      drivers/avr/i2c_slave.c
  88. +4
    -9
      drivers/avr/i2c_slave.h
  89. +27
    -2
      drivers/avr/ws2812.c
  90. +4
    -1
      drivers/avr/ws2812.h
  91. +12
    -12
      drivers/haptic/DRV2605L.c
  92. +18
    -8
      drivers/haptic/DRV2605L.h
  93. +248
    -0
      drivers/haptic/haptic.c
  94. +82
    -0
      drivers/haptic/haptic.h
  95. +109
    -0
      drivers/haptic/solenoid.c
  96. +54
    -0
      drivers/haptic/solenoid.h
  97. +246
    -0
      drivers/issi/is31fl3731-simple.c
  98. +210
    -0
      drivers/issi/is31fl3731-simple.h
  99. +1
    -1
      drivers/issi/is31fl3733.c
  100. +252
    -0
      drivers/issi/is31fl3737.c

+ 26
- 0
.clang-format View File

@ -0,0 +1,26 @@
---
BasedOnStyle: Google
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: 'true'
AlignConsecutiveDeclarations: 'true'
AlignOperands: 'true'
AllowAllParametersOfDeclarationOnNextLine: 'false'
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: 'false'
BinPackArguments: 'true'
BinPackParameters: 'true'
ColumnLimit: '1000'
IndentCaseLabels: 'true'
IndentPPDirectives: AfterHash
IndentWidth: '2'
MaxEmptyLinesToKeep: '1'
PointerAlignment: Right
SortIncludes: 'false'
SpaceBeforeAssignmentOperators: 'true'
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: 'false'
TabWidth: '4'
UseTab: Never
...

+ 1
- 1
.editorconfig View File

@ -5,7 +5,7 @@ root = true
[*]
indent_style = space
indent_size = 2
indent_size = 4
# We recommend you to keep these unchanged
charset = utf-8


+ 16
- 15
.github/ISSUE_TEMPLATE/bug_report.md View File

@ -2,30 +2,31 @@
name: Bug report
about: Create a report to help us improve the QMK Firmware
---
<!-- Provide a general summary of the bug in the Title above -->
<!-- Provide a general summary of the bug in the title above. -->
<!-- This template is entirely option and can be removed, but is here to help both you and us. -->
<!-- This text and anything on lines wrapped like this one will not show up in the final text. This text is to help us and you. -->
<!--- This template is entirely optional and can be removed, but is here to help both you and us. -->
<!--- Anything on lines wrapped in comments like these will not show up in the final text. -->
**Describe the bug**
## Describe the Bug
<!-- A clear and concise description of what the bug is. -->
**System Information**
## System Information
- Keyboard:
- Revision (if applicable):
- Operating System:
- avr-gcc version:
<!-- Run `avr-gcc --version` to find out -->
- arm gcc version:
<!-- Run `arm-none-eabi-gcc --version` to find out -->
- Operating system:
- AVR GCC version:
<!-- Run `avr-gcc --version` to find this out. -->
- ARM GCC version:
<!-- Run `arm-none-eabi-gcc --version` to find this out. -->
- QMK Firmware version:
<!-- You can run `git describe --abbrev=0 --tags` to find this out -->
<!-- Run `git describe --abbrev=0 --tags` to find this out. -->
- Any keyboard related software installed?
- [ ] Auto Hot Key
- [ ] AutoHotKey
- [ ] Karabiner
- [ ] Other
- [ ] Other:
**Additional context**
## Additional Context
<!-- Add any other context about the problem here. -->
<!-- Add any other relevant information about the problem here. -->

+ 8
- 8
.github/ISSUE_TEMPLATE/feature_request.md View File

@ -2,18 +2,18 @@
name: Feature request
about: Suggest a new feature or changes to existing features
---
<!--- Provide a general summary of the changes you want in the Title above -->
<!--- Provide a general summary of the changes you want in the title above. -->
<!-- This template is entirely option and can be removed, but is here to help both you and us. -->
<!-- This text and anything on lines wrapped like this one will not show up in the final text. This text is to help us and you. -->
<!--- This template is entirely optional and can be removed, but is here to help both you and us. -->
<!--- Anything on lines wrapped in comments like these will not show up in the final text. -->
## Feature Request Type
- [ ] Core Functionality
- [ ] Add-on hardware support (e.g. audio, RGB, OLED screen, etc.)
- [ ] Alteration (enhancement/optimization) of existing Feature(s)
- [ ] Core functionality
- [ ] Add-on hardware support (eg. audio, RGB, OLED screen, etc.)
- [ ] Alteration (enhancement/optimization) of existing feature(s)
- [ ] New behavior
## Description
## Description
<!-- A few sentences describing what it is that you'd like to see. Additional information (such as links to spec sheets, licensing info, other related issues or PR's, etc) would be helpful. -->
<!-- A few sentences describing what it is that you'd like to see in QMK. Additional information (such as links to spec sheets, licensing info, other related issues or PRs, etc) would be helpful. -->

+ 3
- 3
.github/ISSUE_TEMPLATE/other_issues.md View File

@ -2,8 +2,8 @@
name: Other issues
about: Anything else that doesn't fall into the above categories.
---
<!--- Provide a general summary of the changes you want in the Title above -->
<!--- Provide a general summary of the changes you want in the title above. -->
<!-- This text and anything on lines wrapped like this one will not show up in the final text. This text is to help us and you. -->
<!--- Anything on lines wrapped in comments like these will not show up in the final text. -->
<!-- Please check https://docs.qmk.fm/#/support for additional resources first. If that doesn't answer your question, check the bug report option, as that may be more appropriate. -->
<!-- Please check https://docs.qmk.fm/#/support for additional resources first. If that doesn't answer your question, choose the bug report template instead, as that may be more appropriate. -->

+ 15
- 13
.github/PULL_REQUEST_TEMPLATE.md View File

@ -1,32 +1,34 @@
<!--- Provide a general summary of your changes in the Title above -->
<!--- Provide a general summary of your changes in the title above. -->
<!--- This template is entirely option and can be removed, but is here to help both you and us. -->
<!--- This text and anything on lines wrapped like this one will not show up in the final text. This text is to help us and you. -->
<!--- This template is entirely optional and can be removed, but is here to help both you and us. -->
<!--- Anything on lines wrapped in comments like these will not show up in the final text. -->
## Description
<!--- Describe your changes in detail -->
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
<!--- Describe your changes in detail here. -->
## Types of Changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply. -->
- [ ] Core
- [ ] Bugfix
- [ ] New Feature
- [ ] Enhancement/Optimization
- [ ] New feature
- [ ] Enhancement/optimization
- [ ] Keyboard (addition or update)
- [ ] Keymap/Layout/Userspace (addition or update)
- [ ] Keymap/layout/userspace (addition or update)
- [ ] Documentation
## Issues Fixed or Closed by this PR
## Issues Fixed or Closed by This PR
*
## Checklist:
## Checklist
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document. (https://docs.qmk.fm/#/contributing)
- [ ] I have read the [**CONTRIBUTING** document](https://docs.qmk.fm/#/contributing).
- [ ] I have added tests to cover my changes.
- [ ] I have tested the changes and verified that they work and don't break anything (as well as I can manage).

+ 2
- 0
.gitignore View File

@ -1,3 +1,4 @@
.history/
.dep
*.o
*.bin
@ -53,6 +54,7 @@ util/Win_Check_Output.txt
.vscode/tasks.json
.vscode/last.sql
.vscode/temp.sql
.vscode/ipch/
.stfolder
.tags


+ 8
- 2
.travis.yml View File

@ -10,16 +10,22 @@ branches:
env:
global:
- secure: vBTSL34BDPxDilKUuTXqU4CJ26Pv5hogD2nghatkxSQkI1/jbdnLj/DQdPUrMJFDIY6TK3AltsBx72MaMsLQ1JO/Ou24IeHINHXzUC1FlS9yQa48cpxnhX5kzXNyGs3oa0qaFbvnr7RgYRWtmD52n4bIZuSuW+xpBv05x2OCizdT2ZonH33nATaHGFasxROm4qYZ241VfzcUv766V6RVHgL4x9V08warugs+RENVkfzxxwhk3NmkrISabze0gSVJLHBPHxroZC6EUcf/ocobcuDrCwFqtEt90i7pNIAFUE7gZsN2uE75LmpzAWin21G7lLPcPL2k4FJVd8an1HiP2WmscJU6U89fOfMb2viObnKcCzebozBCmKGtHEuXZo9FcReOx49AnQSpmESJGs+q2dL/FApkTjQiyT4J6O5dJpoww0/r57Wx0cmmqjETKBb5rSgXM51Etk3wO09mvcPHsEwrT7qH8r9XWdyCDoEn7FCLX3/LYnf/D4SmZ633YPl5gv3v9XEwxR5+04akjgnvWDSNIaDbWBdxHNb7l4pMc+WR1bwCyMyA7KXj0RrftEGOrm9ZRLe6BkbT4cycA+j77nbPOMcyZChliV9pPQos+4TOJoTzcK2L8yWVoY409aDNVuAjdP6Yum0R2maBGl/etLmIMpJC35C5/lZ+dUNjJAM=
- MAKEFLAGS="-j3 --output-sync"
before_install:
- wget http://ww1.microchip.com/downloads/en/DeviceDoc/avr8-gnu-toolchain-3.5.4.1709-linux.any.x86_64.tar.gz || wget http://qmk.fm/avr8-gnu-toolchain-3.5.4.1709-linux.any.x86_64.tar.gz
# Need DFU > .5 for dfu-suffix
- sudo add-apt-repository --yes ppa:tormodvolden/ppa
- sudo apt-get update -qq
install:
- tar -zxf avr8-gnu-toolchain-3.5.4.1709-linux.any.x86_64.tar.gz
- export PATH="$PATH:$TRAVIS_BUILD_DIR/avr8-gnu-toolchain-linux_x86_64/bin"
- npm install -g moxygen
- sudo apt-get -y --force-yes install dfu-util
before_script:
- avr-gcc --version
script:
- make test:all AUTOGEN=false
- git rev-parse --short HEAD
- bash util/travis_test.sh
- bash util/travis_build.sh
- bash util/travis_docs.sh
addons:
@ -33,7 +39,7 @@ addons:
- diffutils
- dos2unix
- doxygen
after_success:
after_success:
bash util/travis_compiled_push.sh
notifications:
webhooks:


+ 1
- 1
Dockerfile View File

@ -1,4 +1,4 @@
FROM debian
FROM debian:9
RUN apt-get update && apt-get install --no-install-recommends -y \
avr-libc \


+ 18
- 10
Makefile View File

@ -112,23 +112,29 @@ $(eval $(call GET_KEYBOARDS))
# Only consider folders with makefiles, to prevent errors in case there are extra folders
#KEYBOARDS += $(patsubst $(ROOD_DIR)/keyboards/%/rules.mk,%,$(wildcard $(ROOT_DIR)/keyboards/*/*/rules.mk))
.PHONY: list-keyboards
list-keyboards:
echo $(KEYBOARDS)
exit 0
define PRINT_KEYBOARD
$(info $(PRINTING_KEYBOARD))
endef
.PHONY: generate-keyboards-file
generate-keyboards-file:
$(foreach PRINTING_KEYBOARD,$(KEYBOARDS),$(eval $(call PRINT_KEYBOARD)))
exit 0
.PHONY: clean
clean:
echo -n 'Deleting .build ... '
echo -n 'Deleting .build/ ... '
rm -rf $(BUILD_DIR)
echo 'done'
exit 0
echo 'done.'
.PHONY: distclean
distclean: clean
echo -n 'Deleting *.bin and *.hex ... '
rm -f *.bin *.hex
echo 'done.'
#Compatibility with the old make variables, anything you specify directly on the command line
# always overrides the detected folders
@ -530,9 +536,9 @@ endef
cmp $(ROOT_DIR)/Makefile $(ROOT_DIR)/Makefile >/dev/null 2>&1; if [ $$? -gt 0 ]; then printf "$(MSG_NO_CMP)"; exit 1; fi;
# Check if the submodules are dirty, and display a warning if they are
ifndef SKIP_GIT
if [ ! -e lib/chibios ]; then git submodule sync lib/chibios && git submodule update --init lib/chibios; fi
if [ ! -e lib/chibios-contrib ]; then git submodule sync lib/chibios-contrib && git submodule update --init lib/chibios-contrib; fi
if [ ! -e lib/ugfx ]; then git submodule sync lib/ugfx && git submodule update --init lib/ugfx; fi
if [ ! -e lib/chibios ]; then git submodule sync lib/chibios && git submodule update --depth 1 --init lib/chibios; fi
if [ ! -e lib/chibios-contrib ]; then git submodule sync lib/chibios-contrib && git submodule update --depth 1 --init lib/chibios-contrib; fi
if [ ! -e lib/ugfx ]; then git submodule sync lib/ugfx && git submodule update --depth 1 --init lib/ugfx; fi
git submodule status --recursive 2>/dev/null | \
while IFS= read -r x; do \
case "$$x" in \
@ -548,9 +554,10 @@ endif
# it has to be there to allow parallel execution of the submake
# This always tries to compile everything, even if error occurs in the middle
# But we return the error code at the end, to trigger travis failures
$(foreach COMMAND,$(COMMANDS),$(RUN_COMMAND))
# The sort at this point is to remove duplicates
$(foreach COMMAND,$(sort $(COMMANDS)),$(RUN_COMMAND))
if [ -f $(ERROR_FILE) ]; then printf "$(MSG_ERRORS)" & exit 1; fi;
$(foreach TEST,$(TESTS),$(RUN_TEST))
$(foreach TEST,$(sort $(TESTS)),$(RUN_TEST))
if [ -f $(ERROR_FILE) ]; then printf "$(MSG_ERRORS)" & exit 1; fi;
# These no longer work because of the colon system
@ -576,6 +583,7 @@ lib/%:
git submodule sync $?
git submodule update --init $?
.PHONY: git-submodule
git-submodule:
git submodule sync --recursive
git submodule update --init --recursive --progress


+ 19
- 14
Vagrantfile View File

@ -2,8 +2,11 @@
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
# VMware/Virtualbox 64 bit
config.vm.box = "phusion/ubuntu-14.04-amd64"
# define a name instead of just 'default'
config.vm.define "qmk_firmware"
# VMware/Virtualbox ( and also Hyperv/Parallels) 64 bit
config.vm.box = "generic/debian9"
# This section allows you to customize the Virtualbox VM
# settings, ie showing the GUI or upping the memory
@ -15,13 +18,16 @@ Vagrant.configure(2) do |config|
# your Teensy via the VM rather than your host OS
#vb.customize ['modifyvm', :id, '--usb', 'on']
#vb.customize ['usbfilter', 'add', '0',
# '--target', :id,
# '--name', 'teensy',
# '--vendorid', '0x16c0',
# '--productid','0x0478'
# ]
# '--target', :id,
# '--name', 'teensy',
# '--vendorid', '0x16c0',
# '--productid','0x0478'
# ]
# Customize the amount of memory on the VM:
vb.memory = "512"
# Uncomment the below lines if you have time sync
# issues with make and incremental builds
#vb.customize [ "guestproperty", "set", :id, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-threshold", 1000 ]
end
# This section allows you to customize the VMware VM
@ -49,26 +55,25 @@ Vagrant.configure(2) do |config|
# image, you'll need to: chmod -R a+rw .
config.vm.provider "docker" do |docker, override|
override.vm.box = nil
docker.image = "jesselang/debian-vagrant:jessie"
docker.image = "jesselang/debian-vagrant:stretch"
docker.has_ssh = true
end
# This script ensures the required packages for AVR programming are installed
# It also ensures the system always gets the latest updates when powered on
# If this causes issues you can run a 'vagrant destroy' and then
# add a # before ,args: and run 'vagrant up' to get a working
# add a # before ,run: (or change "always" to "once") and run 'vagrant up' to get a working
# non-updated box and then attempt to troubleshoot or open a Github issue
config.vm.provision "shell", run: "always", path: "./util/qmk_install.sh", args: "-update"
config.vm.provision "shell", inline: "/bin/sh -c 'yes | /vagrant/util/qmk_install.sh'", run: "always"
config.vm.post_up_message = <<-EOT
Log into the VM using 'vagrant ssh'. QMK directory synchronized with host is
located at /vagrant
To compile the .hex files use make command inside this directory.
To compile the .hex files use make command inside this directory, e.g.
cd /vagrant
make <keyboard>:default
QMK's make format recently changed to use folder locations and colons:
make project_folder:keymap[:target]
Examples:
make planck/rev4:default:dfu
make planck:default


+ 31
- 1
build_keyboard.mk View File

@ -35,6 +35,10 @@ $(error MASTER does not have a valid value(left/right))
endif
endif
ifdef SKIP_VERSION
OPT_DEFS += -DSKIP_VERSION
endif
# Determine which subfolders exist.
KEYBOARD_FOLDER_PATH_1 := $(KEYBOARD)
KEYBOARD_FOLDER_PATH_2 := $(patsubst %/,%,$(dir $(KEYBOARD_FOLDER_PATH_1)))
@ -131,6 +135,10 @@ ifeq ($(strip $(CONVERT_TO_PROTON_C)), yes)
OPT_DEFS += -DCONVERT_TO_PROTON_C
endif
ifneq ($(FORCE_LAYOUT),)
TARGET := $(TARGET)_$(FORCE_LAYOUT)
endif
include quantum/mcu_selection.mk
ifdef MCU_FAMILY
@ -272,6 +280,23 @@ ifneq ("$(wildcard $(KEYBOARD_PATH_1)/config.h)","")
CONFIG_H += $(KEYBOARD_PATH_1)/config.h
endif
POST_CONFIG_H :=
ifneq ("$(wildcard $(KEYBOARD_PATH_1)/post_config.h)","")
POST_CONFIG_H += $(KEYBOARD_PATH_1)/post_config.h
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_2)/post_config.h)","")
POST_CONFIG_H += $(KEYBOARD_PATH_2)/post_config.h
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_3)/post_config.h)","")
POST_CONFIG_H += $(KEYBOARD_PATH_3)/post_config.h
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_4)/post_config.h)","")
POST_CONFIG_H += $(KEYBOARD_PATH_4)/post_config.h
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/post_config.h)","")
POST_CONFIG_H += $(KEYBOARD_PATH_5)/post_config.h
endif
# Save the defines and includes here, so we don't include any keymap specific ones
PROJECT_DEFS := $(OPT_DEFS)
PROJECT_INC := $(VPATH) $(EXTRAINCDIRS) $(KEYBOARD_PATHS)
@ -308,15 +333,17 @@ SRC += $(KEYBOARD_SRC) \
# Search Path
VPATH += $(KEYMAP_PATH)
VPATH += $(USER_PATH)
VPATH += $(KEYBOARD_PATHS)
VPATH += $(COMMON_VPATH)
VPATH += $(USER_PATH)
include common_features.mk
include $(TMK_PATH)/protocol.mk
include $(TMK_PATH)/common.mk
include bootloader.mk
SRC += $(patsubst %.c,%.clib,$(LIB_SRC))
SRC += $(patsubst %.c,%.clib,$(QUANTUM_LIB_SRC))
SRC += $(TMK_COMMON_SRC)
OPT_DEFS += $(TMK_COMMON_DEFS)
EXTRALDFLAGS += $(TMK_COMMON_LDFLAGS)
@ -345,6 +372,7 @@ ifeq ($(strip $(VISUALIZER_ENABLE)), yes)
include $(VISUALIZER_PATH)/visualizer.mk
endif
CONFIG_H += $(POST_CONFIG_H)
ALL_CONFIGS := $(PROJECT_CONFIG) $(CONFIG_H)
OUTPUTS := $(KEYMAP_OUTPUT) $(KEYBOARD_OUTPUT)
@ -363,5 +391,7 @@ $(KEYBOARD_OUTPUT)_CONFIG := $(PROJECT_CONFIG)
# Default target.
all: build check-size
build: elf cpfirmware
check-size: build
include show_options.mk
include $(TMK_PATH)/rules.mk

+ 9
- 0
build_layout.mk View File

@ -15,4 +15,13 @@ define SEARCH_LAYOUTS
$$(foreach LAYOUTS_REPO,$$(LAYOUTS_REPOS),$$(eval $$(call SEARCH_LAYOUTS_REPO)))
endef
ifneq ($(FORCE_LAYOUT),)
ifneq (,$(findstring $(FORCE_LAYOUT),$(LAYOUTS)))
$(info Forcing layout: $(FORCE_LAYOUT))
LAYOUTS := $(FORCE_LAYOUT)
else
$(error Forced layout does not exist)
endif
endif
$(foreach LAYOUT,$(LAYOUTS),$(eval $(call SEARCH_LAYOUTS)))

+ 0
- 1
common.mk View File

@ -21,5 +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 += $(QUANTUM_PATH)/split_common
COMMON_VPATH += $(DRIVER_PATH)

+ 97
- 8
common_features.mk View File

@ -103,7 +103,9 @@ ifeq ($(strip $(UNICODE_COMMON)), yes)
endif
ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
POST_CONFIG_H += $(QUANTUM_DIR)/rgblight_post_config.h
OPT_DEFS += -DRGBLIGHT_ENABLE
SRC += $(QUANTUM_DIR)/color.c
SRC += $(QUANTUM_DIR)/rgblight.c
CIE1931_CURVE = yes
LED_BREATHING_TABLE = yes
@ -114,8 +116,28 @@ ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
endif
endif
VALID_MATRIX_TYPES := yes IS31FL3731 IS31FL3733 IS31FL3737 WS2812 custom
LED_MATRIX_ENABLE ?= no
ifneq ($(strip $(LED_MATRIX_ENABLE)), no)
ifeq ($(filter $(LED_MATRIX_ENABLE),$(VALID_MATRIX_TYPES)),)
$(error LED_MATRIX_ENABLE="$(LED_MATRIX_ENABLE)" is not a valid matrix type)
else
OPT_DEFS += -DLED_MATRIX_ENABLE -DBACKLIGHT_ENABLE -DBACKLIGHT_CUSTOM_DRIVER
SRC += $(QUANTUM_DIR)/led_matrix.c
SRC += $(QUANTUM_DIR)/led_matrix_drivers.c
endif
endif
ifeq ($(strip $(LED_MATRIX_ENABLE)), IS31FL3731)
OPT_DEFS += -DIS31FL3731
COMMON_VPATH += $(DRIVER_PATH)/issi
SRC += is31fl3731-simple.c
SRC += i2c_master.c
endif
RGB_MATRIX_ENABLE ?= no
VALID_MATRIX_TYPES := yes IS31FL3731 IS31FL3733 custom
ifneq ($(strip $(RGB_MATRIX_ENABLE)), no)
ifeq ($(filter $(RGB_MATRIX_ENABLE),$(VALID_MATRIX_TYPES)),)
$(error RGB_MATRIX_ENABLE="$(RGB_MATRIX_ENABLE)" is not a valid matrix type)
@ -132,19 +154,39 @@ ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
endif
ifeq ($(strip $(RGB_MATRIX_ENABLE)), IS31FL3731)
OPT_DEFS += -DIS31FL3731
OPT_DEFS += -DIS31FL3731 -DSTM32_I2C -DHAL_USE_I2C=TRUE
COMMON_VPATH += $(DRIVER_PATH)/issi
SRC += is31fl3731.c
SRC += i2c_master.c
endif
ifeq ($(strip $(RGB_MATRIX_ENABLE)), IS31FL3733)
OPT_DEFS += -DIS31FL3733
OPT_DEFS += -DIS31FL3733 -DSTM32_I2C -DHAL_USE_I2C=TRUE
COMMON_VPATH += $(DRIVER_PATH)/issi
SRC += is31fl3733.c
SRC += i2c_master.c
endif
ifeq ($(strip $(RGB_MATRIX_ENABLE)), IS31FL3737)
OPT_DEFS += -DIS31FL3737 -DSTM32_I2C -DHAL_USE_I2C=TRUE
COMMON_VPATH += $(DRIVER_PATH)/issi
SRC += is31fl3737.c
SRC += i2c_master.c
endif
ifeq ($(strip $(RGB_MATRIX_ENABLE)), WS2812)
OPT_DEFS += -DWS2812
SRC += ws2812.c
endif
ifeq ($(strip $(RGB_MATRIX_CUSTOM_KB)), yes)
OPT_DEFS += -DRGB_MATRIX_CUSTOM_KB
endif
ifeq ($(strip $(RGB_MATRIX_CUSTOM_USER)), yes)
OPT_DEFS += -DRGB_MATRIX_CUSTOM_USER
endif
ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
OPT_DEFS += -DTAP_DANCE_ENABLE
SRC += $(QUANTUM_DIR)/process_keycode/process_tap_dance.c
@ -191,7 +233,7 @@ ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
ifeq ($(strip $(VISUALIZER_ENABLE)), yes)
CIE1931_CURVE = yes
endif
ifeq ($(strip $(BACKLIGHT_CUSTOM_DRIVER)), yes)
ifeq ($(strip $(BACKLIGHT_CUSTOM_DRIVER)), yes)
OPT_DEFS += -DBACKLIGHT_CUSTOM_DRIVER
endif
endif
@ -227,16 +269,31 @@ endif
ifeq ($(strip $(HAPTIC_ENABLE)), DRV2605L)
COMMON_VPATH += $(DRIVER_PATH)/haptic
SRC += haptic.c
SRC += DRV2605L.c
SRC += i2c_master.c
OPT_DEFS += -DHAPTIC_ENABLE
OPT_DEFS += -DDRV2605L
endif
ifeq ($(strip $(HAPTIC_ENABLE)), SOLENOID)
COMMON_VPATH += $(DRIVER_PATH)/haptic
SRC += haptic.c
SRC += solenoid.c
OPT_DEFS += -DHAPTIC_ENABLE
OPT_DEFS += -DSOLENOID_ENABLE
endif
ifeq ($(strip $(HD44780_ENABLE)), yes)
SRC += drivers/avr/hd44780.c
OPT_DEFS += -DHD44780_ENABLE
endif
ifeq ($(strip $(VELOCIKEY_ENABLE)), yes)
OPT_DEFS += -DVELOCIKEY_ENABLE
SRC += $(QUANTUM_DIR)/velocikey.c
endif
ifeq ($(strip $(DYNAMIC_KEYMAP_ENABLE)), yes)
OPT_DEFS += -DDYNAMIC_KEYMAP_ENABLE
SRC += $(QUANTUM_DIR)/dynamic_keymap.c
@ -254,6 +311,7 @@ QUANTUM_SRC:= \
$(QUANTUM_DIR)/keymap_common.c \
$(QUANTUM_DIR)/keycode_config.c
# Include the standard or split matrix code if needed
ifneq ($(strip $(CUSTOM_MATRIX)), yes)
ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/matrix.c
@ -262,10 +320,41 @@ ifneq ($(strip $(CUSTOM_MATRIX)), yes)
endif
endif
DEBOUNCE_DIR:= $(QUANTUM_DIR)/debounce
# Debounce Modules. Set DEBOUNCE_TYPE=custom if including one manually.
DEBOUNCE_TYPE?= sym_g
ifneq ($(strip $(DEBOUNCE_TYPE)), custom)
QUANTUM_SRC += $(DEBOUNCE_DIR)/$(strip $(DEBOUNCE_TYPE)).c
endif
ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
POST_CONFIG_H += $(QUANTUM_DIR)/split_common/post_config.h
OPT_DEFS += -DSPLIT_KEYBOARD
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \
$(QUANTUM_DIR)/split_common/split_util.c \
$(QUANTUM_DIR)/split_common/i2c.c \
$(QUANTUM_DIR)/split_common/serial.c
# Include files used by all split keyboards
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_util.c
# Determine which (if any) transport files are required
ifneq ($(strip $(SPLIT_TRANSPORT)), custom)
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/transport.c
# Functions added via QUANTUM_LIB_SRC are only included in the final binary if they're called.
# Unused functions are pruned away, which is why we can add multiple drivers here without bloat.
QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/serial.c \
i2c_master.c \
i2c_slave.c
endif
COMMON_VPATH += $(QUANTUM_PATH)/split_common
endif
ifeq ($(strip $(OLED_DRIVER_ENABLE)), yes)
OPT_DEFS += -DOLED_DRIVER_ENABLE
COMMON_VPATH += $(DRIVER_PATH)/oled
QUANTUM_LIB_SRC += i2c_master.c
SRC += oled_driver.c
endif
SPACE_CADET_ENABLE ?= yes
ifeq ($(strip $(SPACE_CADET_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/process_keycode/process_space_cadet.c
OPT_DEFS += -DSPACE_CADET_ENABLE
endif

+ 8
- 4
docs/_summary.md View File

@ -3,7 +3,7 @@
* [Building Your First Firmware](newbs_building_firmware.md)
* [Flashing Firmware](newbs_flashing.md)
* [Testing and Debugging](newbs_testing_debugging.md)
* [Best Practices](newbs_best_practices.md)
* [Git Best Practices](newbs_best_practices.md)
* [Learning Resources](newbs_learn_more_resources.md)
* [QMK Basics](README.md)
@ -40,6 +40,7 @@
* [Unit Testing](unit_testing.md)
* [Useful Functions](ref_functions.md)
* [Configurator Support](reference_configurator_support.md)
* [info.json Format](reference_info_json.md)
* [Features](features.md)
* [Basic Keycodes](keycodes_basic.md)
@ -59,15 +60,16 @@
* [Key Lock](feature_key_lock.md)
* [Layouts](feature_layouts.md)
* [Leader Key](feature_leader_key.md)
* [LED Matrix](feature_led_matrix.md)
* [Macros](feature_macros.md)
* [Mouse Keys](feature_mouse_keys.md)
* [OLED Driver](feature_oled_driver)
* [One Shot Keys](feature_advanced_keycodes.md#one-shot-keys)
* [Pointing Device](feature_pointing_device.md)
* [PS/2 Mouse](feature_ps2_mouse.md)
* [RGB Lighting](feature_rgblight.md)
* [RGB Matrix](feature_rgb_matrix.md)
* [Space Cadet Shift](feature_space_cadet_shift.md)
* [Space Cadet Shift Enter](feature_space_cadet_shift_enter.md)
* [Space Cadet](feature_space_cadet.md)
* [Stenography](feature_stenography.md)
* [Swap Hands](feature_swap_hands.md)
* [Tap Dance](feature_tap_dance.md)
@ -75,6 +77,7 @@
* [Thermal Printer](feature_thermal_printer.md)
* [Unicode](feature_unicode.md)
* [Userspace](feature_userspace.md)
* [Velocikey](feature_velocikey.md)
* For Makers and Modders
* [Hand Wiring Guide](hand_wire.md)
@ -89,7 +92,8 @@
* [Understanding QMK](understanding_qmk.md)
* Other Topics
* [Using Eclipse with QMK](eclipse.md)
* [Using Eclipse with QMK](other_eclipse.md)
* [Using VSCode with QMK](other_vscode.md)
* [Support](support.md)
* QMK Internals (In Progress)


+ 81
- 10
docs/config_options.md View File

@ -59,6 +59,8 @@ This is a C header file that is one of the first things included, and will persi
* define is matrix has ghost (unlikely)
* `#define DIODE_DIRECTION COL2ROW`
* COL2ROW or ROW2COL - how your matrix is configured. COL2ROW means the black mark on your diode is facing to the rows, and between the switch and the rows.
* `#define DIRECT_PINS { { F1, F0, B0, C7 }, { F4, F5, F6, F7 } }`
* pins mapped to rows and columns, from left to right. Defines a matrix where each switch is connected to a separate pin and ground.
* `#define AUDIO_VOICES`
* turns on the alternate audio voices (to cycle through)
* `#define C4_AUDIO`
@ -68,11 +70,11 @@ This is a C header file that is one of the first things included, and will persi
* `#define C6_AUDIO`
* enables audio on pin C6
* `#define B5_AUDIO`
* enables audio on pin B5 (duophony is enables if one of B[5-7]_AUDIO is enabled along with one of C[4-6]_AUDIO)
* enables audio on pin B5 (duophony is enables if one of B[5-7]\_AUDIO is enabled along with one of C[4-6]\_AUDIO)
* `#define B6_AUDIO`
* enables audio on pin B6 (duophony is enables if one of B[5-7]_AUDIO is enabled along with one of C[4-6]_AUDIO)
* enables audio on pin B6 (duophony is enables if one of B[5-7]\_AUDIO is enabled along with one of C[4-6]\_AUDIO)
* `#define B7_AUDIO`
* enables audio on pin B7 (duophony is enables if one of B[5-7]_AUDIO is enabled along with one of C[4-6]_AUDIO)
* enables audio on pin B7 (duophony is enables if one of B[5-7]\_AUDIO is enabled along with one of C[4-6]\_AUDIO)
* `#define BACKLIGHT_PIN B7`
* pin of the backlight - B5, B6, B7 use PWM, others use softPWM
* `#define BACKLIGHT_LEVELS 3`
@ -87,7 +89,7 @@ This is a C header file that is one of the first things included, and will persi
* mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap
* `#define LOCKING_RESYNC_ENABLE`
* tries to keep switch state consistent with keyboard LED state
* `#define IS_COMMAND() ( keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) )`
* `#define IS_COMMAND() (get_mods() == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)))`
* key combination that allows the use of magic commands (useful for debugging)
* `#define USB_MAX_POWER_CONSUMPTION`
* sets the maximum power (in mA) over USB for the device (default: 500)
@ -109,9 +111,9 @@ If you define these options you will disable the associated feature, which can s
* `#define NO_ACTION_ONESHOT`
* disable one-shot modifiers
* `#define NO_ACTION_MACRO`
* disable all macro handling
* disable old style macro handling: MACRO() & action_get_macro
* `#define NO_ACTION_FUNCTION`
* disable the action function (deprecated)
* disable calling of action_function() from the fn_actions array (deprecated)
## Features That Can Be Enabled
@ -126,6 +128,8 @@ If you define these options you will enable the associated feature, which may in
* `#define TAPPING_TERM 200`
* how long before a tap becomes a hold, if set above 500, a key tapped during the tapping term will turn it into a hold too
* `#define TAPPING_TERM_PER_KEY`
* enables handling for per key `TAPPING_TERM` settings
* `#define RETRO_TAPPING`
* tap anyway, even after TAPPING_TERM, if there was no other key interruption between press and release
* See [Retro Tapping](feature_advanced_keycodes.md#retro-tapping) for details
@ -143,6 +147,11 @@ If you define these options you will enable the associated feature, which may in
* Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle)
* `#define LEADER_TIMEOUT 300`
* how long before the leader key times out
* If you're having issues finishing the sequence before it times out, you may need to increase the timeout setting. Or you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped.
* `#define LEADER_PER_KEY_TIMING`
* sets the timer for leader key chords to run on each key press rather than overall
* `#define LEADER_KEY_STRICT_KEY_PROCESSING`
* Disables keycode filtering for Mod-Tap and Layer-Tap keycodes. Eg, if you enable this, you would need to specify `MT(MOD_CTL, KC_A)` if you want to use `KC_A`.
* `#define ONESHOT_TIMEOUT 300`
* how long before oneshot times out
* `#define ONESHOT_TAP_TOGGLE 2`
@ -160,15 +169,23 @@ If you define these options you will enable the associated feature, which may in
* Set this to the number of combos that you're using in the [Combo](feature_combo.md) feature.
* `#define COMBO_TERM 200`
* how long for the Combo keys to be detected. Defaults to `TAPPING_TERM` if not defined.
* `#define TAP_CODE_DELAY 100`
* Sets the delay between `register_code` and `unregister_code`, if you're having issues with it registering properly (common on VUSB boards). The value is in milliseconds.
## RGB Light Configuration
* `#define RGB_DI_PIN D7`
* pin the DI on the ws2812 is hooked-up to
* pin the DI on the WS2812 is hooked-up to
* `#define RGBLIGHT_ANIMATIONS`
* run RGB animations
* `#define RGBLED_NUM 15`
* `#define RGBLED_NUM 12`
* number of LEDs
* `#define RGBLIGHT_SPLIT`
* Needed if both halves of the board have RGB LEDs wired directly to the RGB output pin on the controllers instead of passing the output of the left half to the input of the right half
* `#define RGBLED_SPLIT { 6, 6 }`
* number of LEDs connected that are directly wired to `RGB_DI_PIN` on each half of a split keyboard
* First value indicates number of LEDs for left half, second value is for the right half
* When RGBLED_SPLIT is defined, RGBLIGHT_SPLIT is implicitly defined.
* `#define RGBLIGHT_HUE_STEP 12`
* units to step when in/decreasing hue
* `#define RGBLIGHT_SAT_STEP 25`
@ -190,12 +207,58 @@ If you define these options you will enable the associated feature, which may in
Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk
* `SPLIT_TRANSPORT = custom`
* Allows replacing the standard split communication routines with a custom one. ARM based split keyboards must use this at present.
### Setting Handedness
One thing to remember, the side that the USB port is plugged into is always the master half. The side not plugged into USB is the slave.
There are a few different ways to set handedness for split keyboards (listed in order of precedence):
1. Set `SPLIT_HAND_PIN`: Reads a pin to determine handedness. If pin is high, it's the left side, if low, the half is determined to be the right side
2. Set `EE_HANDS` and flash `eeprom-lefthand.eep`/`eeprom-righthand.eep` to each half
* For boards with DFU bootloader you can use `:dfu-split-left`/`:dfu-split-right` to flash these EEPROM files
* For boards with Caterina bootloader (like stock Pro Micros), use `:avrdude-split-left`/`:avrdude-split-right`
3. Set `MASTER_RIGHT`: Half that is plugged into the USB port is determined to be the master and right half (inverse of the default)
4. Default: The side that is plugged into the USB port is the master half and is assumed to be the left half. The slave side is the right half
#### Defines for handedness
* `#define SPLIT_HAND_PIN B7`
* For using high/low pin to determine handedness, low = right hand, high = left hand. Replace 'B7' with the pin you are using. This is optional and you can still use the EEHANDS method or MASTER_LEFT / MASTER_RIGHT defines like the stock Let's Split uses.
* For using high/low pin to determine handedness, low = right hand, high = left hand. Replace `B7` with the pin you are using. This is optional, and if you leave `SPLIT_HAND_PIN` undefined, then you can still use the EE_HANDS method or MASTER_LEFT / MASTER_RIGHT defines like the stock Let's Split uses.
* `#define EE_HANDS` (only works if `SPLIT_HAND_PIN` is not defined)
* Reads the handedness value stored in the EEPROM after `eeprom-lefthand.eep`/`eeprom-righthand.eep` has been flashed to their respective halves.
* `#define MASTER_RIGHT`
* Master half is defined to be the right half.
### Other Options
* `#define USE_I2C`
* For using I2C instead of Serial (defaults to serial)
* `#define SOFT_SERIAL_PIN D0`
* When using serial, define this. `D0` or `D1`,`D2`,`D3`,`E6`.
* `#define MATRIX_ROW_PINS_RIGHT { <row pins> }`
* `#define MATRIX_COL_PINS_RIGHT { <col pins> }`
* If you want to specify a different pinout for the right half than the left half, you can define `MATRIX_ROW_PINS_RIGHT`/`MATRIX_COL_PINS_RIGHT`. Currently, the size of `MATRIX_ROW_PINS` must be the same as `MATRIX_ROW_PINS_RIGHT` and likewise for the definition of columns.
* `#define RGBLED_SPLIT { 6, 6 }`
* See [RGB Light Configuration](#rgb-light-configuration)
* `#define SELECT_SOFT_SERIAL_SPEED <speed>` (default speed is 1)
* Sets the protocol speed when using serial communication
* Speeds:
* 0: about 189kbps (Experimental only)
* 1: about 137kbps (default)
* 2: about 75kbps
* 3: about 39kbps
* 4: about 26kbps
* 5: about 20kbps
# The `rules.mk` File
This is a [make](https://www.gnu.org/software/make/manual/make.html) file that is included by the top-level `Makefile`. It is used to set some information about the MCU that we will be compiling for as well as enabling and disabling certain features.
@ -247,6 +310,8 @@ Use these to enable or disable building certain features. The more you have enab
* Enable the audio subsystem.
* `RGBLIGHT_ENABLE`
* Enable keyboard underlight functionality
* `LEADER_ENABLE`
* Enable leader key chording
* `MIDI_ENABLE`
* MIDI controls
* `UNICODE_ENABLE`
@ -257,10 +322,16 @@ Use these to enable or disable building certain features. The more you have enab
* Current options are AdafruitEzKey, AdafruitBLE, RN42
* `SPLIT_KEYBOARD`
* Enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common
* `CUSTOM_MATRIX`
* Allows replacing the standard matrix scanning routine with a custom one.
* `DEBOUNCE_TYPE`
* Allows replacing the standard key debouncing routine with an alternative or custom one.
* `WAIT_FOR_USB`
* Forces the keyboard to wait for a USB connection to be established before it starts up
* `NO_USB_STARTUP_CHECK`
* Disables usb suspend check after keyboard startup. Usually the keyboard waits for the host to wake it up before any tasks are performed. This is useful for split keyboards as one half will not get a wakeup call but must send commands to the master.
* `LINK_TIME_OPTIMIZATION_ENABLE`
= Enables Link Time Optimization (`LTO`) when compiling the keyboard. This makes the process take longer, but can significantly reduce the compiled size (and since the firmware is small, the added time is not noticable). However, this will automatically disable the old Macros and Functions features automatically, as these break when `LTO` is enabled. It does this by automatically defining `NO_ACTION_MACRO` and `NO_ACTION_FUNCTION`
## USB Endpoint Limitations


+ 37
- 3
docs/contributing.md View File

@ -56,7 +56,7 @@ Never made an open source contribution before? Wondering how contributions work
Most of our style is pretty easy to pick up on, but right now it's not entirely consistent. You should match the style of the code surrounding your change, but if that code is inconsistent or unclear use the following guidelines:
* We indent using two spaces (soft tabs)
* We indent using four (4) spaces (soft tabs)
* We use a modified One True Brace Style
* Opening Brace: At the end of the same line as the statement that opens the block
* Closing Brace: Lined up with the first character of the statement that opens the block
@ -71,6 +71,14 @@ Most of our style is pretty easy to pick up on, but right now it's not entirely
* If you not sure if a comment is obvious, go ahead and include it.
* In general we don't wrap lines, they can be as long as needed. If you do choose to wrap lines please do not wrap any wider than 76 columns.
* We use `#pragma once` at the start of header files rather than old-style include guards (`#ifndef THIS_FILE_H`, `#define THIS_FILE_H`, ..., `#endif`)
* We accept both forms of preprocessor if's: `#ifdef DEFINED` and `#if defined(DEFINED)`
* If you are not sure which to prefer use the `#if defined(DEFINED)` form.
* Do not change existing code from one style to the other, except when moving to a multiple condition `#if`.
* Do not put whitespace between `#` and `if`.
* When deciding how (or if) to indent directives keep these points in mind:
* Readability is more important than consistency.
* Follow the file's existing style. If the file is mixed follow the style that makes sense for the section you are modifying.
* When choosing to indent you can follow the indention level of the surrounding C code, or preprocessor directives can have their own indent level. Choose the style that best communicates the intent of your code.
Here is an example for easy reference:
@ -91,6 +99,18 @@ int foo(void) {
}
```
# Auto-formatting with clang-format
[Clang-format](https://clang.llvm.org/docs/ClangFormat.html) is part of LLVM and can automatically format your code for you, because ain't nobody got time to do it manually. We supply a configuration file for it that applies most of the coding conventions listed above. It will only change whitespace and newlines, so you will still have to remember to include optional braces yourself.
Use the [full LLVM installer](http://llvm.org/builds/) to get clang-format on Windows, or use `sudo apt install clang-format` on Ubuntu.
If you run it from the command-line, pass `-style=file` as an option and it will automatically find the .clang-format configuration file in the QMK root directory.
If you use VSCode, the standard C/C++ plugin supports clang-format, alternatively there is a [separate extension](https://marketplace.visualstudio.com/items?itemName=LLVMExtensions.ClangFormat) for it.
Some things (like LAYOUT macros) are destroyed by clang-format, so either don't run it on those files, or wrap the sensitive code in `// clang-format off` and `// clang-format on`.
# General Guidelines
We have a few different types of changes in QMK, each requiring a different level of rigor. We'd like you to keep the following guidelines in mind no matter what type of change you're making.
@ -117,6 +137,20 @@ Documentation is one of the easiest ways to get started contributing to QMK. Fin
You'll find all our documentation in the `qmk_firmware/docs` directory, or if you'd rather use a web based workflow you can click "Suggest An Edit" at the top of each page on http://docs.qmk.fm/.
When providing code examples in your documentation, try to observe naming conventions used elsewhere in the docs. For example, standardizing enums as `my_layers` or `my_keycodes` for consistency:
```c
enum my_layers {
_FIRST_LAYER,
_SECOND_LAYER
};
enum my_keycodes {
FIRST_LAYER = SAFE_RANGE,
SECOND_LAYER
};
```
## Keymaps
Most first-time QMK contributors start with their personal keymaps. We try to keep keymap standards pretty casual (keymaps, after all, reflect the personality of their creators) but we do ask that you follow these guidelines to make it easier for others to discover and learn from your keymap.
@ -125,7 +159,7 @@ Most first-time QMK contributors start with their personal keymaps. We try to ke
* All Keymap PR's are squashed, so if you care about how your commits are squashed you should do it yourself
* Do not lump features in with keymap PR's. Submit the feature first and then a second PR for the keymap.
* Do not include `Makefile`s in your keymap folder (they're no longer used)
* Update copyrights in file headers (look for `REPLACE_WITH_YOUR_NAME `)
* Update copyrights in file headers (look for `%YOUR_NAME%`)
## Keyboards
@ -138,7 +172,7 @@ We also ask that you follow these guidelines:
* Do not lump core features in with new keyboards. Submit the feature first and then submit a separate PR for the keyboard.
* Name `.c`/`.h` file after the immediate parent folder, eg `/keyboards/<kb1>/<kb2>/<kb2>.[ch]`
* Do not include `Makefile`s in your keyboard folder (they're no longer used)
* Update copyrights in file headers (look for `REPLACE_WITH_YOUR_NAME `)
* Update copyrights in file headers (look for `%YOUR_NAME%`)
## Quantum/TMK Core


+ 155
- 50
docs/custom_quantum_functions.md View File

@ -90,7 +90,7 @@ keyrecord_t record {
# LED Control
This allows you to control the 5 LED's defined as part of the USB Keyboard spec. It will be called when the state of one of those 5 LEDs changes.
QMK provides methods to read the 5 LEDs defined as part of the HID spec:
* `USB_LED_NUM_LOCK`
* `USB_LED_CAPS_LOCK`
@ -98,34 +98,47 @@ This allows you to control the 5 LED's defined as part of the USB Keyboard spec.
* `USB_LED_COMPOSE`
* `USB_LED_KANA`
These five constants correspond to the positional bits of the host LED state.
There are two ways to get the host LED state:
* by implementing `led_set_user()`
* by calling `host_keyboard_leds()`
## `led_set_user()`
This function will be called when the state of one of those 5 LEDs changes. It receives the LED state as a parameter.
Use the `IS_LED_ON(usb_led, led_name)` and `IS_LED_OFF(usb_led, led_name)` macros to check the LED status.
!> `host_keyboard_leds()` may already reflect a new value before `led_set_user()` is called.
### Example `led_set_user()` Implementation
```c
void led_set_user(uint8_t usb_led) {
if (usb_led & (1<<USB_LED_NUM_LOCK)) {
PORTB |= (1<<0);
if (IS_LED_ON(usb_led, USB_LED_NUM_LOCK)) {
writePinLow(B0);
} else {
PORTB &= ~(1<<0);
writePinHigh(B0);
}
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
PORTB |= (1<<1);
if (IS_LED_ON(usb_led, USB_LED_CAPS_LOCK)) {
writePinLow(B1);
} else {
PORTB &= ~(1<<1);
writePinHigh(B1);
}
if (usb_led & (1<<USB_LED_SCROLL_LOCK)) {
PORTB |= (1<<2);
if (IS_LED_ON(usb_led, USB_LED_SCROLL_LOCK)) {
writePinLow(B2);
} else {
PORTB &= ~(1<<2);
writePinHigh(B2);
}
if (usb_led & (1<<USB_LED_COMPOSE)) {
PORTB |= (1<<3);
if (IS_LED_ON(usb_led, USB_LED_COMPOSE)) {
writePinLow(B3);
} else {
PORTB &= ~(1<<3);
writePinHigh(B3);
}
if (usb_led & (1<<USB_LED_KANA)) {
PORTB |= (1<<4);
if (IS_LED_ON(usb_led, USB_LED_KANA)) {
writePinLow(B4);
} else {
PORTB &= ~(1<<4);
writePinHigh(B4);
}
}
```
@ -135,32 +148,103 @@ void led_set_user(uint8_t usb_led) {
* Keyboard/Revision: `void led_set_kb(uint8_t usb_led)`
* Keymap: `void led_set_user(uint8_t usb_led)`
## `host_keyboard_leds()`
Call this function to get the last received LED state. This is useful for reading the LED state outside `led_set_*`, e.g. in [`matrix_scan_user()`](#matrix-scanning-code).
For convenience, you can use the `IS_HOST_LED_ON(led_name)` and `IS_HOST_LED_OFF(led_name)` macros instead of calling and checking `host_keyboard_leds()` directly.
## Setting Physical LED State
Some keyboard implementations provide convenience methods for setting the state of the physical LEDs.
### Ergodox Boards
The Ergodox implementations provide `ergodox_right_led_1`/`2`/`3_on`/`off()` to turn individual LEDs on or off, as well as `ergodox_right_led_on`/`off(uint8_t led)` to turn them on or off by their index.
In addition, it is possible to specify the brightness level of all LEDs with `ergodox_led_all_set(uint8_t n)`; of individual LEDs with `ergodox_right_led_1`/`2`/`3_set(uint8_t n)`; or by index with `ergodox_right_led_set(uint8_t led, uint8_t n)`.
Ergodox boards also define `LED_BRIGHTNESS_LO` for the lowest brightness and `LED_BRIGHTNESS_HI` for the highest brightness (which is the default).
# Keyboard Initialization Code
There are several steps in the keyboard initialization process. Depending on what you want to do, it will influence which function you should use.
These are the three main initialization functions, listed in the order that they're called.
* `keyboard_pre_init_*` - Happens before most anything is started. Good for hardware setup that you want running very early.
* `matrix_init_*` - Happens midway through the firmware's startup process. Hardware is initialized, but features may not be yet.
* `keyboard_post_init_*` - Happens at the end of the firmware's startup process. This is where you'd want to put "customization" code, for the most part.
!> For most people, the `keyboard_post_init_user` function is what you want to call. For instance, this is where you want to set up things for RGB Underglow.
# Matrix Initialization Code
## Keyboard Pre Initialization code
Before a keyboard can be used the hardware must be initialized. QMK handles initialization of the keyboard matrix itself, but if you have other hardware like LED's or i&#xb2;c controllers you will need to set up that hardware before it can be used.
This runs very early during startup, even before the USB has been started.
Shortly after this, the matrix is initialized.
### Example `matrix_init_user()` Implementation
For most users, this shouldn't be used, as it's primarily for hardware oriented initialization.
This example, at the keyboard level, sets up B1, B2, and B3 as LED pins.
However, if you have hardware stuff that you need initialized, this is the best place for it (such as initializing LED pins).
### Example `keyboard_pre_init_user()` Implementation
This example, at the keyboard level, sets up B0, B1, B2, B3, and B4 as LED pins.
```c
void matrix_init_user(void) {
// Call the keymap level matrix init.
void keyboard_pre_init_user(void) {
// Call the keyboard pre init code.
// Set our LED pins as output
DDRB |= (1<<1);
DDRB |= (1<<2);
DDRB |= (1<<3);
setPinOutput(B0);
setPinOutput(B1);
setPinOutput(B2);
setPinOutput(B3);
setPinOutput(B4);
}
```
### `keyboard_pre_init_*` Function Documentation
* Keyboard/Revision: `void keyboard_pre_init_kb(void)`
* Keymap: `void keyboard_pre_init_user(void)`
## Matrix Initialization Code
This is called when the matrix is initialized, and after some of the hardware has been set up, but before many of the features have been initialized.
This is useful for setting up stuff that you may need elsewhere, but isn't hardware related nor is dependant on where it's started.
### `matrix_init_*` Function Documentation
* Keyboard/Revision: `void matrix_init_kb(void)`
* Keymap: `void matrix_init_user(void)`
## Keyboard Post Initialization code
This is ran as the very last task in the keyboard initialization process. This is useful if you want to make changes to certain features, as they should be initialized by this point.
### Example `keyboard_post_init_user()` Implementation
This example, running after everything else has initialized, sets up the rgb underglow configuration.
```c
void keyboard_post_init_user(void) {
// Call the post init code.
rgblight_enable_noeeprom(); // enables Rgb, without saving settings
rgblight_sethsv_noeeprom(180, 255, 255); // sets the color to teal/cyan without saving
rgblight_mode_noeeprom(RGBLIGHT_MODE_BREATHING + 3); // sets mode to Fast breathing without saving
}
```
### `keyboard_post_init_*` Function Documentation
* Keyboard/Revision: `void keyboard_post_init_kb(void)`
* Keymap: `void keyboard_post_init_user(void)`
# Matrix Scanning Code
Whenever possible you should customize your keyboard by using `process_record_*()` and hooking into events that way, to ensure that your code does not have a negative performance impact on your keyboard. However, in rare cases it is necessary to hook into the matrix scanning. Be extremely careful with the performance of code in these functions, as it will be called at least 10 times per second.
@ -176,7 +260,7 @@ This example has been deliberately omitted. You should understand enough about Q
This function gets called at every matrix scan, which is basically as often as the MCU can handle. Be careful what you put here, as it will get run a lot.
You should use this function if you need custom matrix scanning code. It can also be used for custom status output (such as LED's or a display) or other functionality that you want to trigger regularly even when the user isn't typing.
You should use this function if you need custom matrix scanning code. It can also be used for custom status output (such as LEDs or a display) or other functionality that you want to trigger regularly even when the user isn't typing.
# Keyboard Idling/Wake Code
@ -188,22 +272,18 @@ This is controlled by two functions: `suspend_power_down_*` and `suspend_wakeup_
### Example suspend_power_down_user() and suspend_wakeup_init_user() Implementation
This example, at the keyboard level, sets up B1, B2, and B3 as LED pins.
```c
void suspend_power_down_user(void)
{
void suspend_power_down_user(void) {
rgb_matrix_set_suspend_state(true);
}
void suspend_wakeup_init_user(void)
{
void suspend_wakeup_init_user(void) {
rgb_matrix_set_suspend_state(false);
}
```
### `keyboard_init_*` Function Documentation
### Keyboard suspend/wake Function Documentation
* Keyboard/Revision: `void suspend_power_down_kb(void)` and `void suspend_wakeup_init_user(void)`
* Keymap: `void suspend_power_down_kb(void)` and `void suspend_wakeup_init_user(void)`
@ -240,9 +320,10 @@ uint32_t layer_state_set_user(uint32_t state) {
```
### `layer_state_set_*` Function Documentation
* Keyboard/Revision: `void uint32_t layer_state_set_kb(uint32_t state)`
* Keyboard/Revision: `uint32_t layer_state_set_kb(uint32_t state)`
* Keymap: `uint32_t layer_state_set_user(uint32_t state)`
The `state` is the bitmask of the active layers, as explained in the [Keymap Overview](keymap.md#keymap-layer-status)
@ -256,13 +337,13 @@ Keep in mind that EEPROM has a limited number of writes. While this is very high
* If you don't understand the example, then you may want to avoid using this feature, as it is rather complicated.
### Example Implementation
### Example Implementation
This is an example of how to add settings, and read and write it. We're using the user keymap for the example here. This is a complex function, and has a lot going on. In fact, it uses a lot of the above functions to work!
In your keymap.c file, add this to the top:
```
```c
typedef union {
uint32_t raw;
struct {
@ -275,11 +356,11 @@ user_config_t user_config;
This sets up a 32 bit structure that we can store settings with in memory, and write to the EEPROM. Using this removes the need to define variables, since they're defined in this structure. Remember that `bool` (boolean) values use 1 bit, `uint8_t` uses 8 bits, `uint16_t` uses up 16 bits. You can mix and match, but changing the order can cause issues, as it will change the values that are read and written.
We're using `rgb_layer_change`, for the `layer_state_set_*` function, and use `matrix_init_user` and `process_record_user` to configure everything.
We're using `rgb_layer_change`, for the `layer_state_set_*` function, and use `keyboard_post_init_user` and `process_record_user` to configure everything.
Now, using the `matrix_init_user` code above, you want to add `eeconfig_read_user()` to it, to populate the structure you've just created. And you can then immediately use this structure to control functionality in your keymap. And It should look like:
```
void matrix_init_user(void) {
Now, using the `keyboard_post_init_user` code above, you want to add `eeconfig_read_user()` to it, to populate the structure you've just created. And you can then immediately use this structure to control functionality in your keymap. And It should look like:
```c
void keyboard_post_init_user(void) {
// Call the keymap level matrix init.
// Read the user config from EEPROM
@ -295,7 +376,7 @@ void matrix_init_user(void) {
```
The above function will use the EEPROM config immediately after reading it, to set the default layer's RGB color. The "raw" value of it is converted in a usable structure based on the "union" that you created above.
```
```c
uint32_t layer_state_set_user(uint32_t state) {
switch (biton32(state)) {
case _RAISE:
@ -317,8 +398,8 @@ uint32_t layer_state_set_user(uint32_t state) {
return state;
}
```
This will cause the RGB underglow to be changed ONLY if the value was enabled. Now to configure this value, create a new keycode for `process_record_user` called `RGB_LYR` and `EPRM`. Additionally, we want to make sure that if you use the normal RGB codes, that it turns off Using the example above, make it look this:
```
This will cause the RGB underglow to be changed ONLY if the value was enabled. Now to configure this value, create a new keycode for `process_record_user` called `RGB_LYR`. Additionally, we want to make sure that if you use the normal RGB codes, that it turns off Using the example above, make it look this:
```c
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
@ -335,11 +416,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
PLAY_NOTE_ARRAY(tone_qwerty);
}
return true; // Let QMK send the enter press/release events
case EPRM:
if (record->event.pressed) {
eeconfig_init(); // resets the EEPROM to default
}
return false;
case RGB_LYR: // This allows me to use underglow as layer indication, or as normal
if (record->event.pressed) {
user_config.rgb_layer_change ^= 1; // Toggles the status
@ -362,10 +438,11 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
}
```
And lastly, you want to add the `eeconfig_init_user` function, so that when the EEPROM is reset, you can specify default values, and even custom actions. For example, if you want to set rgb layer indication by default, and save the default valued.
And lastly, you want to add the `eeconfig_init_user` function, so that when the EEPROM is reset, you can specify default values, and even custom actions. To force an EEPROM reset, use the `EEP_RST` keycode or [Bootmagic](feature_bootmagic.md) functionallity. For example, if you want to set rgb layer indication by default, and save the default valued.
```
```c
void eeconfig_init_user(void) { // EEPROM is getting reset!
user_config.raw = 0;
user_config.rgb_layer_change = true; // We want this enabled by default
eeconfig_update_user(user_config.raw); // Write default value to EEPROM now
@ -384,3 +461,31 @@ And you're done. The RGB layer indication will only work if you want it to. And
* Keymap: `void eeconfig_init_user(void)`, `uint32_t eeconfig_read_user(void)` and `void eeconfig_update_user(uint32_t val)`
The `val` is the value of the data that you want to write to EEPROM. And the `eeconfig_read_*` function return a 32 bit (DWORD) value from the EEPROM.
# Custom Tapping Term
By default, the tapping term is defined globally, and is not configurable by key. For most users, this is perfectly fine. But in come cases, dual function keys would be greatly improved by different timeouts than `LT` keys, or because some keys may be easier to hold than others. Instead of using custom key codes for each, this allows for per key configurable `TAPPING_TERM`.
To enable this functionality, you need to add `#define TAPPING_TERM_PER_KEY` to your `config.h`, first.
## Example `get_tapping_term` Implementation
To change the `TAPPING TERM` based on the keycode, you'd want to add something like the following to your `keymap.c` file:
```c
uint16_t get_tapping_term(uint16_t keycode) {
switch (keycode) {
case SFT_T(KC_SPC):
return TAPPING_TERM + 1250;
case LT(1, KC_GRV):
return 130;
default:
return TAPPING_TERM;
}
}
```
### `get_tapping_term` Function Documentation
Unlike many of the other functions here, there isn't a need (or even reason) to have a quantum or keyboard level function. Only a user level function is useful here, so no need to mark it as such.

+ 29
- 6
docs/faq_build.md View File

@ -15,7 +15,7 @@ or just:
$ sudo make <keyboard>:<keymap>:dfu
Note that running `make` with `sudo` is generally *not* a good idea, and you should use one of the former methods, if possible.
Note that running `make` with `sudo` is generally ***not*** a good idea, and you should use one of the former methods, if possible.
### Linux `udev` Rules
On Linux, you'll need proper privileges to access the MCU. You can either use
@ -36,14 +36,29 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff0", MODE:="066
# tmk keyboard products https://github.com/tmk/tmk_keyboard
SUBSYSTEMS=="usb", ATTRS{idVendor}=="feed", MODE:="0666"
```
**/etc/udev/rules.d/54-input-club-keyboard.rules:**
```
# Input Club keyboard bootloader
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1c11", MODE:="0666"
```
### Serial device is not detected in bootloader mode on Linux
Make sure your kernel has appropriate support for your device. If your device uses USB ACM, such as
Pro Micro (Atmega32u4), make sure to include `CONFIG_USB_ACM=y`. Other devices may require `USB_SERIAL` and any of its sub options.
## Unknown Device for DFU Bootloader
If you're using Windows to flash your keyboard, and you are running into issues, check the Device Manager. If you see an "Unknown Device" when the keyboard is in "bootloader mode", then you may have a driver issue.
If you're using Windows to flash your keyboard, and you are running into issues, check the Device Manager. If you see an "Unknown Device" when the keyboard is in "bootloader mode", then you may have a driver issue.
Re-running the installation script for MSYS2 may help (eg run `./util/qmk_install.sh` from MSYS2/WSL) or reinstalling the QMK Toolbox may fix the issue.
Re-running the installation script for MSYS2 may help (eg run `./util/qmk_install.sh` from MSYS2/WSL) or reinstalling the QMK Toolbox may fix the issue.
If that doesn't work, then you may need to grab the [Zadig Utility](https://zadig.akeo.ie/). Download this, find the device in question, and select the `WinUSB` option, and hit "Reinstall driver". Once you've done that, try flashing your board, again. If that doesn't work, try all of the options, until one works.
?> There isn't a best option for which driver should be used here. Some options work better on some systems than others. libUSB and WinUSB seem to be the best options here.
If the bootloader doesn't show up in the list for devices, you may need to enable the "List all devices" option in the `Options` menu, and then find the bootloader in question.
If that doesn't work, then you may need to grab the [Zadig Utility](https://zadig.akeo.ie/). Download this, find the device in question, and select the `WinUS(libusb-1.0)` option, and hit "Reinstall driver". Once you've done that, try flashing your board, again.
## WINAVR is Obsolete
It is no longer recommended and may cause some problem.
@ -98,9 +113,9 @@ OPT_DEFS += -DBOOTLOADER_SIZE=2048
```
## `avr-gcc: internal compiler error: Abort trap: 6 (program cc1)` on MacOS
This is an issue with updating on brew, causing symlinks that avr-gcc depend on getting mangled.
This is an issue with updating on brew, causing symlinks that avr-gcc depend on getting mangled.
The solution is to remove and reinstall all affected modules.
The solution is to remove and reinstall all affected modules.
```
brew rm avr-gcc
@ -128,3 +143,11 @@ brew uninstall --force avr-gcc
brew install avr-gcc@7
brew link --force avr-gcc@7
```
### I just flashed my keyboard and it does nothing/keypresses don't register - it's also ARM (rev6 planck, clueboard 60, hs60v2, etc...) (Feb 2019)
Due to how EEPROM works on ARM based chips, saved settings may no longer be valid. This affects the default layers, and *may*, under certain circumstances we are still figuring out, make the keyboard unusable. Resetting the EEPROM will correct this.
[Planck rev6 reset EEPROM](https://cdn.discordapp.com/attachments/473506116718952450/539284620861243409/planck_rev6_default.bin) can be used to force an eeprom reset. After flashing this image, flash your normal firmware again which should restore your keyboard to _normal_ working order.
[Preonic rev3 reset EEPROM](https://cdn.discordapp.com/attachments/473506116718952450/537849497313738762/preonic_rev3_default.bin)
If bootmagic is enabled in any form, you should be able to do this too (see [Bootmagic docs](feature_bootmagic.md) and keyboard info for specifics on how to do this).

+ 2
- 2
docs/faq_keymap.md View File

@ -151,13 +151,13 @@ This turns right modifier keys into arrow keys when the keys are tapped while st
*/
const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* 0: qwerty */
[0] = KEYMAP( \
[0] = LAYOUT( \
ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, NUHS,BSPC, \
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, \
LCTL,A, S, D, F, G, H, J, K, L, SCLN,QUOT,ENT, \
LSFT,NUBS,Z, X, C, V, B, N, M, COMM,DOT, SLSH,FN0, ESC, \
FN4, LGUI,LALT, SPC, APP, FN2, FN1, FN3),
[1] = KEYMAP( \
[1] = LAYOUT( \
GRV, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, TRNS,TRNS, \
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,\
TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS, \


+ 121
- 41
docs/feature_advanced_keycodes.md View File

@ -11,21 +11,21 @@ People often define custom names using `#define`. For example:
#define ALT_TAB LALT(KC_TAB)
```
This will allow you to use `FN_CAPS` and `ALT_TAB` in your `KEYMAP()`, keeping it more readable.
This will allow you to use `FN_CAPS` and `ALT_TAB` in your keymap, keeping it more readable.
## Caveats
Currently, `LT()` and `MT()` are limited to the [Basic Keycode set](keycodes_basic.md), meaning you can't use keycodes like `LCTL()`, `KC_TILD`, or anything greater than `0xFF`. Modifiers specified as part of a Layer Tap or Mod Tap's keycode will be ignored.
Currently, `LT()` and `MT()` are limited to the [Basic Keycode set](keycodes_basic.md), meaning you can't use keycodes like `LCTL()`, `KC_TILD`, or anything greater than `0xFF`. Modifiers specified as part of a Layer Tap or Mod Tap's keycode will be ignored. If you need to apply modifiers to your tapped keycode, [Tap Dance](https://github.com/qmk/qmk_firmware/blob/master/docs/feature_tap_dance.md#example-5-using-tap-dance-for-advanced-mod-tap-and-layer-tap-keys) can be used to accomplish this.
Additionally, if at least one right-handed modifier is specified in a Mod Tap or Layer Tap, it will cause all modifiers specified to become right-handed, so it is not possible to mix and match the two.
# Switching and Toggling Layers
These functions allow you to activate layers in various ways. Note that layers are not generally independent layouts -- multiple layers can be activated at once, and it's typical for layers to use `KC_TRNS` to allow keypresses to pass through to lower layers. For a detailed explanation of layers, see [Keymap Overview](keymap.md#keymap-and-layers)
These functions allow you to activate layers in various ways. Note that layers are not generally independent layouts -- multiple layers can be activated at once, and it's typical for layers to use `KC_TRNS` to allow keypresses to pass through to lower layers. For a detailed explanation of layers, see [Keymap Overview](keymap.md#keymap-and-layers). When using momentary layer switching with MO(), LM(), TT(), or LT(), make sure to leave the key on the above layers transparent or it may not work as intended.
* `DF(layer)` - switches the default layer. The default layer is the always-active base layer that other layers stack on top of. See below for more about the default layer. This might be used to switch from QWERTY to Dvorak layout. (Note that this is a temporary switch that only persists until the keyboard loses power. To modify the default layer in a persistent way requires deeper customization, such as calling the `set_single_persistent_default_layer` function inside of [process_record_user](custom_quantum_functions.md#programming-the-behavior-of-any-keycode).)
* `MO(layer)` - momentarily activates *layer*. As soon as you let go of the key, the layer is deactivated.
* `LM(layer, mod)` - Momentarily activates *layer* (like `MO`), but with modifier(s) *mod* active. Only supports layers 0-15 and the left modifiers.
* `LM(layer, mod)` - Momentarily activates *layer* (like `MO`), but with modifier(s) *mod* active. Only supports layers 0-15 and the left modifiers: `MOD_LCTL`, `MOD_LSFT`, `MOD_LALT`, `MOD_LGUI` (note the use of `MOD_` constants instead of `KC_`). These modifiers can be combined using bitwise OR, e.g. `LM(_RAISE, MOD_LCTL | MOD_LALT)`.
* `LT(layer, kc)` - momentarily activates *layer* when held, and sends *kc* when tapped. Only supports layers 0-15.
* `OSL(layer)` - momentarily activates *layer* until the next key is pressed. See [One Shot Keys](#one-shot-keys) for details and additional functionality.
* `TG(layer)` - toggles *layer*, activating it if it's inactive and vice versa
@ -60,21 +60,21 @@ Sometimes, you might want to switch between layers in a macro or as part of a ta
These allow you to combine a modifier with a keycode. When pressed, the keydown event for the modifier, then `kc` will be sent. On release, the keyup event for `kc`, then the modifier will be sent.
|Key |Aliases |Description |
|----------|----------------------|----------------------------------------------------|
|`LCTL(kc)`| |Hold Left Control and press `kc` |
|`LSFT(kc)`|`S(kc)` |Hold Left Shift and press `kc` |
|`LALT(kc)`| |Hold Left Alt and press `kc` |
|`LGUI(kc)`|`LCMD(kc)`, `LWIN(kc)`|Hold Left GUI and press `kc` |
|`RCTL(kc)`| |Hold Right Control and press `kc` |
|`RSFT(kc)`| |Hold Right Shift and press `kc` |
|`RALT(kc)`|`ALGR(kc)` |Hold Right Alt and press `kc` |
|`RGUI(kc)`|`RCMD(kc)`, `LWIN(kc)`|Hold Right GUI and press `kc` |
|`HYPR(kc)`| |Hold Left Control, Shift, Alt and GUI and press `kc`|
|`MEH(kc)` | |Hold Left Control, Shift and Alt and press `kc` |
|`LCAG(kc)`| |Hold Left Control, Alt and GUI and press `kc` |
|`SGUI(kc)`|`SCMD(kc)`, `SWIN(kc)`|Hold Left Shift and GUI and press `kc` |
|`LCA(kc)` | |Hold Left Control and Alt and press `kc` |
|Key |Aliases |Description |
|----------|-------------------------------|----------------------------------------------------|
|`LCTL(kc)`|`C(kc)` |Hold Left Control and press `kc` |
|`LSFT(kc)`|`S(kc)` |Hold Left Shift and press `kc` |
|`LALT(kc)`|`A(kc)` |Hold Left Alt and press `kc` |
|`LGUI(kc)`|`G(kc)`, `LCMD(kc)`, `LWIN(kc)`|Hold Left GUI and press `kc` |
|`RCTL(kc)`| |Hold Right Control and press `kc` |
|`RSFT(kc)`| |Hold Right Shift and press `kc` |
|`RALT(kc)`|`ALGR(kc)` |Hold Right Alt and press `kc` |
|`RGUI(kc)`|`RCMD(kc)`, `LWIN(kc)` |Hold Right GUI and press `kc` |
|`SGUI(kc)`|`SCMD(kc)`, `SWIN(kc)` |Hold Left Shift and GUI and press `kc` |
|`LCA(kc)` | |Hold Left Control and Alt and press `kc` |
|`LCAG(kc)`| |Hold Left Control, Alt and GUI and press `kc` |
|`MEH(kc)` | |Hold Left Control, Shift and Alt and press `kc` |
|`HYPR(kc)`| |Hold Left Control, Shift, Alt and GUI and press `kc`|
You can also chain them, for example `LCTL(LALT(KC_DEL))` makes a key that sends Control+Alt+Delete with a single keypress.
@ -107,23 +107,23 @@ This key would activate Left Control and Left Shift when held, and send Escape w
For convenience, QMK includes some Mod-Tap shortcuts to make common combinations more compact in your keymap:
|Key |Aliases |Description |
|------------|---------------------------------------|-------------------------------------------------------|
|`LCTL_T(kc)`|`CTL_T(kc)` |Left Control when held, `kc` when tapped |
|`RCTL_T(kc)`| |Right Control when held, `kc` when tapped |
|`LSFT_T(kc)`|`SFT_T(kc)` |Left Shift when held, `kc` when tapped |
|`RSFT_T(kc)`| |Right Shift when held, `kc` when tapped |
|`LALT_T(kc)`|`ALT_T(kc)` |Left Alt when held, `kc` when tapped |
|`RALT_T(kc)`|`ALGR_T(kc)` |Right Alt when held, `kc` when tapped |
|`LGUI_T(kc)`|`LCMD_T(kc)`, `RWIN_T(kc)`, `GUI_T(kc)`|Left GUI when held, `kc` when tapped |
|`RGUI_T(kc)`|`RCMD_T(kc)`, `RWIN_T(kc)` |Right GUI when held, `kc` when tapped |
|`C_S_T(kc)` | |Left Control and Shift when held, `kc` when tapped |
|`MEH_T(kc)` | |Left Control, Shift and Alt when held, `kc` when tapped|
|`LCAG_T(kc)`| |Left Control, Alt and GUI when held, `kc` when tapped |
|`RCAG_T(kc)`| |Right Control, Alt and GUI when held, `kc` when tapped |
|`ALL_T(kc)` | |Left Control, Shift, Alt and GUI when held, `kc` when tapped - more info [here](http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/)|
|`SGUI_T(kc)`|`SCMD_T(kc)`, `SWIN_T(kc)` |Left Shift and GUI when held, `kc` when tapped |
|`LCA_T(kc)` | |Left Control and Alt when held, `kc` when tapped |
|Key |Aliases |Description |
|------------|-----------------------------------------------------------------|-------------------------------------------------------|
|`LCTL_T(kc)`|`CTL_T(kc)` |Left Control when held, `kc` when tapped |
|`LSFT_T(kc)`|`SFT_T(kc)` |Left Shift when held, `kc` when tapped |
|`LALT_T(kc)`|`ALT_T(kc)` |Left Alt when held, `kc` when tapped |
|`LGUI_T(kc)`|`LCMD_T(kc)`, `LWIN_T(kc)`, `GUI_T(kc)`, `CMD_T(kc)`, `WIN_T(kc)`|Left GUI when held, `kc` when tapped |
|`RCTL_T(kc)`| |Right Control when held, `kc` when tapped |
|`RSFT_T(kc)`| |Right Shift when held, `kc` when tapped |
|`RALT_T(kc)`|`ALGR_T(kc)` |Right Alt when held, `kc` when tapped |
|`RGUI_T(kc)`|`RCMD_T(kc)`, `RWIN_T(kc)` |Right GUI when held, `kc` when tapped |
|`SGUI_T(kc)`|`SCMD_T(kc)`, `SWIN_T(kc)` |Left Shift and GUI when held, `kc` when tapped |
|`LCA_T(kc)` | |Left Control and Alt when held, `kc` when tapped |
|`LCAG_T(kc)`| |Left Control, Alt and GUI when held, `kc` when tapped |
|`RCAG_T(kc)`| |Right Control, Alt and GUI when held, `kc` when tapped |
|`C_S_T(kc)` | |Left Control and Shift when held, `kc` when tapped |
|`MEH_T(kc)` | |Left Control, Shift and Alt when held, `kc` when tapped|
|`HYPR_T(kc)`|`ALL_T(kc)` |Left Control, Shift, Alt and GUI when held, `kc` when tapped - more info [here](http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/)|
## Caveats
@ -146,7 +146,7 @@ Additionally, hitting keys five times in a short period will lock that key. This
You can control the behavior of one shot keys by defining these in `config.h`:
```c
#define ONESHOT_TAP_TOGGLE 5 /* Tapping this number of times holds the key until tapped this number of times again. */
#define ONESHOT_TAP_TOGGLE 5 /* Tapping this number of times holds the key until tapped once again. */
#define ONESHOT_TIMEOUT 5000 /* Time (in ms) before the one shot key is released */
```
@ -161,8 +161,88 @@ For one shot mods, you need to call `set_oneshot_mods(MOD)` to set it, or `clear
!> If you're having issues with OSM translating over Remote Desktop Connection, this can be fixed by opening the settings, going to the "Local Resources" tap, and in the keyboard section, change the drop down to "On this Computer". This will fix the issue and allow OSM to function properly over Remote Desktop.
## Callbacks
# Permissive Hold
When you'd like to perform custom logic when pressing a one shot key, there are several callbacks you can choose to implement. You could indicate changes in one shot keys by flashing an LED or making a sound, for example.
There is a callback for `OSM(mod)`. It is called whenever the state of any one shot modifier key is changed: when it toggles on, but also when it is toggled off. You can use it like this:
```c
void oneshot_mods_changed_user(uint8_t mods) {
if (mods & MOD_MASK_SHIFT) {
println("Oneshot mods SHIFT");
}
if (mods & MOD_MASK_CTRL) {
println("Oneshot mods CTRL");
}
if (mods & MOD_MASK_ALT) {
println("Oneshot mods ALT");
}
if (mods & MOD_MASK_GUI) {
println("Oneshot mods GUI");
}
if (!mods) {
println("Oneshot mods off");
}
}
```
The `mods` argument contains the active mods after the change, so it reflects the current state.
When you use One Shot Tap Toggle (by adding `#define ONESHOT_TAP_TOGGLE 2` in your `config.h` file), you may lock a modifier key by pressing it the specified amount of times. There's a callback for that, too:
```c
void oneshot_locked_mods_changed_user(uint8_t mods) {
if (mods & MOD_MASK_SHIFT) {
println("Oneshot locked mods SHIFT");
}
if (mods & MOD_MASK_CTRL) {
println("Oneshot locked mods CTRL");
}
if (mods & MOD_MASK_ALT) {
println("Oneshot locked mods ALT");
}
if (mods & MOD_MASK_GUI) {
println("Oneshot locked mods GUI");
}
if (!mods) {
println("Oneshot locked mods off");
}
}
```
Last, there is also a callback for the `OSL(layer)` one shot key:
```c
void oneshot_layer_changed_user(uint8_t layer) {
if (layer == 1) {
println("Oneshot layer 1 on");
}
if (!layer) {
println("Oneshot layer off");
}
}
```
If any one shot layer is switched off, `layer` will be zero. When you're looking to do something on any layer change instead of one shot layer changes, `layer_state_set_user` is a better callback to use.
If you are making your own keyboard, there are also `_kb` equivalent functions:
```c
void oneshot_locked_mods_changed_kb(uint8_t mods);
void oneshot_mods_changed_kb(uint8_t mods);
void oneshot_layer_changed_kb(uint8_t layer);
```
As with any callback, be sure to call the `_user` variant to allow for further customizability.
# Tap-Hold Configuration Options
While Tap-Hold options are fantastic, they are not without their issues. We have tried to configure them with reasonal defaults, but that may still cause issues for some people.
These options let you modify the behavior of the Tap-Hold keys.
## Permissive Hold
As of [PR#1359](https://github.com/qmk/qmk_firmware/pull/1359/), there is a new `config.h` option:
@ -185,7 +265,7 @@ Normally, if you do all this within the `TAPPING_TERM` (default: 200ms) this wil
?> If you have `Ignore Mod Tap Interrupt` enabled, as well, this will modify how both work. The regular key has the modifier added if the first key is released first or if both keys are held longer than the `TAPPING_TERM`.
# Ignore Mod Tap Interrupt
## Ignore Mod Tap Interrupt
To enable this setting, add this to your `config.h`:
@ -211,7 +291,7 @@ Normally, this would send `X` (`SHIFT`+`x`). With `Ignore Mod Tap Interrupt` ena
?> If you have `Permissive Hold` enabled, as well, this will modify how both work. The regular key has the modifier added if the first key is released first or if both keys are held longer than the `TAPPING_TERM`.
# Tapping Force Hold
## Tapping Force Hold
To enable `tapping force hold`, add the following to your `config.h`:
@ -235,7 +315,7 @@ With `TAPPING_FORCE_HOLD`, the second press will be interpreted as a Shift, allo
!> `TAPPING_FORCE_HOLD` will break anything that uses tapping toggles (Such as the `TT` layer keycode, and the One Shot Tapping Toggle).
# Retro Tapping
## Retro Tapping
To enable `retro tapping`, add the following to your `config.h`:


+ 33
- 8
docs/feature_audio.md View File

@ -61,9 +61,11 @@ It's advised that you wrap all audio features in `#ifdef AUDIO_ENABLE` / `#endif
The available keycodes for audio are:
* `AU_ON` - Turn audio mode on
* `AU_OFF` - Turn audio mode off
* `AU_TOG` - Toggle audio mode
* `AU_ON` - Turn Audio Feature on
* `AU_OFF` - Turn Audio Feature off
* `AU_TOG` - Toggle Audio Feature state
!> These keycodes turn all of the audio functionality on and off. Turning it off means that audio feedback, audio clicky, music mode, etc. are disabled, completely.
## ARM Audio Volume
@ -98,6 +100,16 @@ In music mode, the following keycodes work differently, and don't pass through:
* `KC_UP` - speed-up playback
* `KC_DOWN` - slow-down playback
The pitch standard (`PITCH_STANDARD_A`) is 440.0f by default - to change this, add something like this to your `config.h`:
#define PITCH_STANDARD_A 432.0f
You can completely disable Music Mode as well. This is useful, if you're pressed for space on your controller. To disable it, add this to your `config.h`:
#define NO_MUSIC_MODE
### Music Mask
By default, `MUSIC_MASK` is set to `keycode < 0xFF` which means keycodes less than `0xFF` are turned into notes, and don't output anything. You can change this by defining this in your `config.h` like this:
#define MUSIC_MASK keycode != KC_NO
@ -118,13 +130,26 @@ For a more advanced way to control which keycodes should still be processed, you
Things that return false are not part of the mask, and are always processed.
The pitch standard (`PITCH_STANDARD_A`) is 440.0f by default - to change this, add something like this to your `config.h`:
### Music Map
#define PITCH_STANDARD_A 432.0f
By default, the Music Mode uses the columns and row to determine the scale for the keys. For a board that uses a rectangular matrix that matches the keyboard layout, this is just fine. However, for boards that use a more complicated matrix (such as the Planck Rev6, or many split keyboards) this would result in a very skewed experience.
You can completely disable Music Mode as well. This is useful, if you're pressed for space on your controller. To disable it, add this to your `config.h`:
However, the Music Map option allows you to remap the scaling for the music mode, so it fits the layout, and is more natural.
#define NO_MUSIC_MODE
To enable this feature, add `#define MUSIC_MAP` to your `config.h` file, and then you will want to add a `uint8_t music_map` to your keyboard's `c` file, or your `keymap.c`.
```c
const uint8_t music_map[MATRIX_ROWS][MATRIX_COLS] = LAYOUT_ortho_4x12(
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
);
```
You will want to use whichever `LAYOUT` macro that your keyboard uses here. This maps it to the correct key location. Start in the bottom left of the keyboard layout, and move to the right, and then upwards. Fill in all the entries until you have a complete matrix.
You can look at the [Planck Keyboard](https://github.com/qmk/qmk_firmware/blob/e9ace1487887c1f8b4a7e8e6d87c322988bec9ce/keyboards/planck/planck.c#L24-L29) as an example of how to implement this.
## Audio Click
@ -158,7 +183,7 @@ You can configure the default, min and max frequencies, the stepping and built i
## MIDI Functionality
This is still a WIP, but check out `quantum/keymap_midi.c` to see what's happening. Enable from the Makefile.
This is still a WIP, but check out `quantum/process_keycode/process_midi.c` to see what's happening. Enable from the Makefile.
## Audio Keycodes


+ 51
- 2
docs/feature_backlight.md View File

@ -30,7 +30,31 @@ You should then be able to use the keycodes below to change the backlight level.
This feature is distinct from both the [RGB underglow](feature_rgblight.md) and [RGB matrix](feature_rgb_matrix.md) features as it usually allows for only a single colour per switch, though you can obviously use multiple different coloured LEDs on a keyboard.
Hardware PWM is only supported on certain pins of the MCU, so if the backlighting is not connected to one of them, a software implementation will be used, and backlight breathing will not be available. Currently the supported pins are `B5`, `B6`, `B7`, and `C6`.
Hardware PWM is only supported on certain pins of the MCU, so if the backlighting is not connected to one of them, a software PWM implementation triggered by hardware timer interrupts will be used.
Hardware PWM is supported according to the following table:
| Backlight Pin | Hardware timer |
|---------------|----------------|
|`B5` | Timer 1 |
|`B6` | Timer 1 |
|`B7` | Timer 1 |
|`C6` | Timer 3 |
| other | Software PWM |
The [audio feature](feature_audio.md) also uses hardware timers. Please refer to the following table to know what hardware timer the software PWM will use depending on the audio configuration:
| Audio Pin(s) | Audio Timer | Software PWM Timer |
|--------------|-------------|--------------------|
| `C4` | Timer 3 | Timer 1 |
| `C5` | Timer 3 | Timer 1 |
| `C6` | Timer 3 | Timer 1 |
| `B5` | Timer 1 | Timer 3 |
| `B6` | Timer 1 | Timer 3 |
| `B7` | Timer 1 | Timer 3 |
| `Bx` & `Cx` | Timer 1 & 3 | None |
When all timers are in use for [audio](feature_audio.md), the backlight software PWM will not use a hardware timer, but instead will be triggered during the matrix scan. In this case the backlight doesn't support breathing and might show lighting artifacts (for instance flickering), because the PWM computation might not be called with enough timing precision.
## Configuration
@ -39,10 +63,26 @@ To change the behaviour of the backlighting, `#define` these in your `config.h`:
|Define |Default |Description |
|---------------------|-------------|-------------------------------------------------------------------------------------------------------------|
|`BACKLIGHT_PIN` |`B7` |The pin that controls the LEDs. Unless you are designing your own keyboard, you shouldn't need to change this|
|`BACKLIGHT_PINS` |*Not defined*|experimental: see below for more information|
|`BACKLIGHT_LEVELS` |`3` |The number of brightness levels (maximum 15 excluding off) |
|`BACKLIGHT_BREATHING`|*Not defined*|Enable backlight breathing, if hardware PWM is used |
|`BACKLIGHT_CAPS_LOCK`|*Not defined*|Enable Caps Lock indicator using backlight (for keyboards without dedicated LED) |
|`BACKLIGHT_BREATHING`|*Not defined*|Enable backlight breathing, if supported |
|`BREATHING_PERIOD` |`6` |The length of one backlight "breath" in seconds |
## Multiple backlight pins
Most keyboards have only one backlight pin which control all backlight LEDs (especially if the backlight is connected to an hardware PWM pin).
In software PWM, it is possible to define multiple backlight pins. All those pins will be turned on and off at the same time during the PWM duty cycle.
This feature allows to set for instance the Caps Lock LED (or any other controllable LED) brightness at the same level as the other LEDs of the backlight. This is useful if you have mapped LCTRL in place of Caps Lock and you need the Caps Lock LED to be part of the backlight instead of being activated when Caps Lock is on.
To activate multiple backlight pins, you need to add something like this to your user `config.h`:
~~~c
#define BACKLIGHT_LED_COUNT 2
#undef BACKLIGHT_PIN
#define BACKLIGHT_PINS { F5, B2 }
~~~
## Hardware PWM Implementation
When using the supported pins for backlighting, QMK will use a hardware timer configured to output a PWM signal. This timer will count up to `ICRx` (by default `0xFFFF`) before resetting to 0.
@ -52,6 +92,15 @@ In this way `OCRxx` essentially controls the duty cycle of the LEDs, and thus th
The breathing effect is achieved by registering an interrupt handler for `TIMER1_OVF_vect` that is called whenever the counter resets, roughly 244 times per second.
In this handler, the value of an incrementing counter is mapped onto a precomputed brightness curve. To turn off breathing, the interrupt handler is simply disabled, and the brightness reset to the level stored in EEPROM.
## Software PWM Implementation
When `BACKLIGHT_PIN` is not set to a hardware backlight pin, QMK will use a hardware timer configured to trigger software interrupts. This time will count up to `ICRx` (by default `0xFFFF`) before resetting to 0.
When resetting to 0, the CPU will fire an OVF (overflow) interrupt that will turn the LEDs on, starting the duty cycle.
The desired brightness is calculated and stored in the `OCRxx` register. When the counter reaches this value, the CPU will fire a Compare Output match interrupt, which will turn the LEDs off.
In this way `OCRxx` essentially controls the duty cycle of the LEDs, and thus the brightness, where `0x0000` is completely off and `0xFFFF` is completely on.
The breathing effect is the same as in the hardware PWM implementation.
## Backlight Functions
|Function |Description |


+ 3
- 1
docs/feature_bootmagic.md View File

@ -127,7 +127,9 @@ Additionally, you may want to specify which key to use. This is especially usef
By default, these are set to 0 and 0, which is usually the "ESC" key on a majority of keyboards.
And to trigger the bootloader, you hold this key down when plugging the keyboard in. Just the single key.
And to trigger the bootloader, you hold this key down when plugging the keyboard in. Just the single key.
!> Using bootmagic lite will **always reset** the EEPROM, so you will lose any settings that have been saved.
## Advanced Bootmagic Lite


+ 1
- 2
docs/feature_combo.md View File

@ -19,7 +19,6 @@ combo_t key_combos[COMBO_COUNT] = {COMBO(test_combo, KC_ESC)};
This will send "Escape" if you hit the A and B keys.
!> This method only supports [basic keycodes](keycodes_basic.md). See the examples for more control.
!> You cannot reuse (share) keys in combos. Each key should only belong to a single combo.
## Examples
@ -29,7 +28,7 @@ If you want to add a list, then you'd use something like this:
enum combos {
AB_ESC,
JK_TAB
}
};
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM jk_combo[] = {KC_J, KC_K, COMBO_END};


+ 33
- 32
docs/feature_command.md View File

@ -16,35 +16,36 @@ To use Command, hold down the key combination defined by the `IS_COMMAND()` macr
If you would like to change the key assignments for Command, `#define` these in your `config.h` at either the keyboard or keymap level. All keycode assignments here must omit the `KC_` prefix.
|Define |Default |Description |
|------------------------------------|--------------------------------------------------------------------------------------|------------------------------------------------|
|`IS_COMMAND()` |<code>(keyboard_report->mods == (MOD_BIT(KC_LSHIFT) &#124; MOD_BIT(KC_RSHIFT)))</code>|The key combination to activate Command |
|`MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS` |`true` |Set default layer with the Function row |
|`MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS` |`true` |Set default layer with the number keys |
|`MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM`|`false` |Set default layer with `MAGIC_KEY_LAYER0..9` |
|`MAGIC_KEY_DEBUG` |`D` |Toggle debugging over serial |
|`MAGIC_KEY_DEBUG_MATRIX` |`X` |Toggle key matrix debugging |
|`MAGIC_KEY_DEBUG_KBD` |`K` |Toggle keyboard debugging |
|`MAGIC_KEY_DEBUG_MOUSE` |`M` |Toggle mouse debugging |
|`MAGIC_KEY_CONSOLE` |`C` |Enable the Command console |
|`MAGIC_KEY_VERSION` |`V` |Print the running QMK version to the console |
|`MAGIC_KEY_STATUS` |`S` |Print the current keyboard status to the console|
|`MAGIC_KEY_HELP1` |`H` |Print Command help to the console |
|`MAGIC_KEY_HELP2` |`SLASH` |Print Command help to the console (alternate) |
|`MAGIC_KEY_LAYER0` |`0` |Make layer 0 the default layer |
|`MAGIC_KEY_LAYER1` |`1` |Make layer 1 the default layer |
|`MAGIC_KEY_LAYER2` |`2` |Make layer 2 the default layer |
|`MAGIC_KEY_LAYER3` |`3` |Make layer 3 the default layer |
|`MAGIC_KEY_LAYER4` |`4` |Make layer 4 the default layer |
|`MAGIC_KEY_LAYER5` |`5` |Make layer 5 the default layer |
|`MAGIC_KEY_LAYER6` |`6` |Make layer 6 the default layer |
|`MAGIC_KEY_LAYER7` |`7` |Make layer 7 the default layer |
|`MAGIC_KEY_LAYER8` |`8` |Make layer 8 the default layer |
|`MAGIC_KEY_LAYER9` |`9` |Make layer 9 the default layer |
|`MAGIC_KEY_LAYER0_ALT1` |`ESC` |Make layer 0 the default layer (alternate) |
|`MAGIC_KEY_LAYER0_ALT2` |`GRAVE` |Make layer 0 the default layer (alternate) |
|`MAGIC_KEY_BOOTLOADER` |`PAUSE` |Enter the bootloader |
|`MAGIC_KEY_LOCK` |`CAPS` |Lock the keyboard so nothing can be typed |
|`MAGIC_KEY_EEPROM` |`E` |Clear the EEPROM |
|`MAGIC_KEY_NKRO` |`N` |Toggle N-Key Rollover (NKRO) |
|`MAGIC_KEY_SLEEP_LED` |`Z` |Toggle LED when computer is sleeping |
|Define |Default |Description |
|------------------------------------|---------------------------------------------------------------------------|------------------------------------------------|
|`IS_COMMAND()` |<code>(get_mods() == (MOD_BIT(KC_LSHIFT) &#124; MOD_BIT(KC_RSHIFT)))</code>|The key combination to activate Command |
|`MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS` |`true` |Set default layer with the Function row |
|`MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS` |`true` |Set default layer with the number keys |
|`MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM`|`false` |Set default layer with `MAGIC_KEY_LAYER0..9` |
|`MAGIC_KEY_DEBUG` |`D` |Toggle debugging over serial |
|`MAGIC_KEY_DEBUG_MATRIX` |`X` |Toggle key matrix debugging |
|`MAGIC_KEY_DEBUG_KBD` |`K` |Toggle keyboard debugging |
|`MAGIC_KEY_DEBUG_MOUSE` |`M` |Toggle mouse debugging |
|`MAGIC_KEY_CONSOLE` |`C` |Enable the Command console |
|`MAGIC_KEY_VERSION` |`V` |Print the running QMK version to the console |
|`MAGIC_KEY_STATUS` |`S` |Print the current keyboard status to the console|
|`MAGIC_KEY_HELP` |`H` |Print Command help to the console |
|`MAGIC_KEY_HELP_ALT` |`SLASH` |Print Command help to the console (alternate) |
|`MAGIC_KEY_LAYER0` |`0` |Make layer 0 the default layer |
|`MAGIC_KEY_LAYER0_ALT` |`GRAVE` |Make layer 0 the default layer (alternate) |
|`MAGIC_KEY_LAYER1` |`1` |Make layer 1 the default layer |
|`MAGIC_KEY_LAYER2` |`2` |Make layer 2 the default layer |
|`MAGIC_KEY_LAYER3` |`3` |Make layer 3 the default layer |
|`MAGIC_KEY_LAYER4` |`4` |Make layer 4 the default layer |
|`MAGIC_KEY_LAYER5` |`5` |Make layer 5 the default layer |
|`MAGIC_KEY_LAYER6` |`6` |Make layer 6 the default layer |
|`MAGIC_KEY_LAYER7` |`7` |Make layer 7 the default layer |
|`MAGIC_KEY_LAYER8` |`8` |Make layer 8 the default layer |
|`MAGIC_KEY_LAYER9` |`9` |Make layer 9 the default layer |
|`MAGIC_KEY_BOOTLOADER` |`B` |Jump to bootloader |
|`MAGIC_KEY_BOOTLOADER_ALT` |`ESC` |Jump to bootloader (alternate) |
|`MAGIC_KEY_LOCK` |`CAPS` |Lock the keyboard so nothing can be typed |
|`MAGIC_KEY_EEPROM` |`E` |Print stored EEPROM config to the console |
|`MAGIC_KEY_EEPROM_CLEAR` |`BSPACE` |Clear the EEPROM |
|`MAGIC_KEY_NKRO` |`N` |Toggle N-Key Rollover (NKRO) |
|`MAGIC_KEY_SLEEP_LED` |`Z` |Toggle LED when computer is sleeping |

+ 42
- 0
docs/feature_debounce_type.md View File

@ -0,0 +1,42 @@
# Debounce algorithm
QMK supports multiple debounce algorithms through its debounce API.
The logic for which debounce method called is below. It checks various defines that you have set in rules.mk
```
DEBOUNCE_DIR:= $(QUANTUM_DIR)/debounce
DEBOUNCE_TYPE?= sym_g
ifneq ($(strip $(DEBOUNCE_TYPE)), custom)
QUANTUM_SRC += $(DEBOUNCE_DIR)/$(strip $(DEBOUNCE_TYPE)).c
endif
```
# Debounce selection
| DEBOUNCE_TYPE | Description | What else is needed |
| ------------- | --------------------------------------------------- | ----------------------------- |
| Not defined | Use the default algorithm, currently sym_g | Nothing |
| custom | Use your own debounce.c | ```SRC += debounce.c``` add your own debounce.c and implement necessary functions |
| anything_else | Use another algorithm from quantum/debounce/* | Nothing |
**Regarding split keyboards**:
The debounce code is compatible with split keyboards.
# Use your own debouncing code
* Set ```DEBOUNCE_TYPE = custom ```.
* Add ```SRC += debounce.c```
* Add your own ```debounce.c```. Look at current implementations in ```quantum/debounce``` for examples.
* Debouncing occurs after every raw matrix scan.
* Use num_rows rather than MATRIX_ROWS, so that split keyboards are supported correctly.
# Changing between included debouncing methods
You can either use your own code, by including your own debounce.c, or switch to another included one.
Included debounce methods are:
* eager_pr - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE_DELAY``` milliseconds of no further input for that row.
For use in keyboards where refreshing ```NUM_KEYS``` 8-bit counters is computationally expensive / low scan rate, and fingers usually only hit one row at a time. This could be
appropriate for the ErgoDox models; the matrix is rotated 90°, and hence its "rows" are really columns, and each finger only hits a single "row" at a time in normal use.
* eager_pk - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE_DELAY``` milliseconds of no further input for that key
* sym_g - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE_DELAY``` milliseconds of no changes has occured, all input changes are pushed.

+ 12
- 8
docs/feature_encoders.md View File

@ -32,15 +32,19 @@ The callback functions can be inserted into your `<keyboard>.c`:
or `keymap.c`:
void encoder_update_user(uint8_t index, bool clockwise) {
if (index == 0) {
if (clockwise) {
register_code(KC_PGDN);
unregister_code(KC_PGDN);
} else {
register_code(KC_PGUP);
unregister_code(KC_PGUP);
}
if (index == 0) { /* First encoder */
if (clockwise) {
tap_code(KC_PGDN);
} else {
tap_code(KC_PGUP);
}
} else if (index == 1) { /* Second encoder
if (clockwise) {
tap_code(KC_UP);
} else {
tap_code(KC_DOWN);
}
}
}
## Hardware


+ 9
- 1
docs/feature_grave_esc.md View File

@ -4,7 +4,11 @@ If you're using a 60% keyboard, or any other layout with no F-row, you will have
## Usage
Replace the `KC_GRAVE` key in your keymap (usually to the left of the `1` key) with `KC_GESC`. When pressed it will behave like `KC_ESC`, but with Shift or GUI held it will send `KC_GRAVE`.
Replace the `KC_GRAVE` key in your keymap (usually to the left of the `1` key) with `KC_GESC`. Most of the time this key will output `KC_ESC` when pressed. However, when Shift or GUI are held down it will output `KC_GRV` instead.
## What Your OS Sees
If Mary presses GESC on her keyboard, the OS will see an KC_ESC character. Now if Mary holds Shift down and presses GESC it will output `~`, or a shifted backtick. Now if she holds GUI/CMD/WIN, it will output a simple <code>&#96;</code> character.
## Keycodes
@ -12,6 +16,10 @@ Replace the `KC_GRAVE` key in your keymap (usually to the left of the `1` key) w
|---------|-----------|------------------------------------------------------------------|
|`KC_GESC`|`GRAVE_ESC`|Escape when pressed, <code>&#96;</code> when Shift or GUI are held|
### Caveats
On macOS, Command+<code>&#96;</code> is by default mapped to "Move focus to next window" so it will not output a backtick. Additionally, Terminal always recognises this shortcut to cycle between windows, even if the shortcut is changed in the Keyboard preferences.
## Configuration
There are several possible key combinations this will break, among them Control+Shift+Escape on Windows and Command+Option+Escape on macOS. To work around this, you can `#define` these options in your `config.h`:


+ 147
- 0
docs/feature_haptic_feedback.md View File

@ -0,0 +1,147 @@
# Haptic Feedback
## Haptic feedback rules.mk options
The following options are currently available for haptic feedback in `rule.mk`:
`HAPTIC_ENABLE += DRV2605L`
`HAPTIC_ENABLE += SOLENOID`
## Known Supported Hardware
| Name | Description |
|--------------------|-------------------------------------------------|
| [LV061228B-L65-A](https://www.digikey.com/product-detail/en/jinlong-machinery-electronics-inc/LV061228B-L65-A/1670-1050-ND/7732325) | z-axis 2v LRA |
| [Mini Motor Disc](https://www.adafruit.com/product/1201) | small 2-5v ERM |
## Haptic Keycodes
Not all keycodes below will work depending on which haptic mechanism you have chosen.
| Name | Description |
|-----------|-------------------------------------------------------|
|`HPT_ON` | Turn haptic feedback on |
|`HPT_OFF` | Turn haptic feedback on |
|`HPT_TOG` | Toggle haptic feedback on/off |
|`HPT_RST` | Reset haptic feedback config to default |
|`HPT_FBK` | Toggle feedback to occur on keypress, release or both |
|`HPT_BUZ` | Toggle solenoid buzz on/off |
|`HPT_MODI` | Go to next DRV2605L waveform |
|`HPT_MODD` | Go to previous DRV2605L waveform |
|`HPT_DWLI` | Increase Solenoid dwell time |
|`HPT_DWLD` | Decrease Solenoid dwell time |
### Solenoids
First you will need a build a circuit to drive the solenoid through a mosfet as most MCU will not be able to provide the current needed to drive the coil in the solenoid.
[Wiring diagram provided by Adafruit](https://playground.arduino.cc/uploads/Learning/solenoid_driver.pdf)
Select a pin that has PWM for the signal pin
```
#define SOLENOID_PIN *pin*
```
Beware that some pins may be powered during bootloader (ie. A13 on the STM32F303 chip) and will result in the solenoid kept in the on state through the whole flashing process. This may overheat and damage the solenoid. If you find that the pin the solenoid is connected to is triggering the solenoid during bootloader/DFU, select another pin.
### DRV2605L
DRV2605L is controlled over i2c protocol, and has to be connected to the SDA and SCL pins, these varies depending on the MCU in use.
#### Feedback motor setup
This driver supports 2 different feedback motors. Set the following in your `config.h` based on which motor you have selected.
##### ERM
Eccentric Rotating Mass vibration motors (ERM) is motor with a off-set weight attached so when drive signal is attached, the off-set weight spins and causes a sinusoidal wave that translate into vibrations.
```
#define FB_ERM_LRA 0
#define FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */
#define FB_LOOPGAIN 1 /* For Low:0, Medium:1, High:2, Very High:3 */
/* Please refer to your datasheet for the optimal setting for your specific motor. */
#define RATED_VOLTAGE 3
#define V_PEAK 5
```
##### LRA
Linear resonant actuators (LRA, also know as a linear vibrator) works different from a ERM. A LRA has a weight and magnet suspended by springs and a voice coil. When the drive signal is applied, the weight would be vibrate on a single axis (side to side or up and down). Since the weight is attached to a spring, there is a resonance effect at a specific frequency. This frequency is where the LRA will operate the most efficiently. Refer to the motor's datasheet for the recommanded range for this frequency.
```
#define FB_ERM_LRA 1
#define FB_BRAKEFACTOR 3 /* For 1x:0, 2x:1, 3x:2, 4x:3, 6x:4, 8x:5, 16x:6, Disable Braking:7 */
#define FB_LOOPGAIN 1 /* For Low:0, Medium:1, High:2, Very High:3 */
/* Please refer to your datasheet for the optimal setting for your specific motor. */
#define RATED_VOLTAGE 2
#define V_PEAK 2.8
#define V_RMS 2.0
#define V_PEAK 2.1
#define F_LRA 205 /* resonance freq */
```
#### DRV2605L waveform library
DRV2605L comes with preloaded library of various waveform sequences that can be called and played. If writing a macro, these waveforms can be played using `DRV_pulse(*sequence name or number*)`
List of waveform sequences from the datasheet:
|seq# | Sequence name |seq# | Sequence name |seq# |Sequence name |
|-----|---------------------|-----|-----------------------------------|-----|--------------------------------------|
| 1 | strong_click | 43 | lg_dblclick_med_60 | 85 | transition_rampup_med_smooth2 |
| 2 | strong_click_60 | 44 | lg_dblsharp_tick | 86 | transition_rampup_short_smooth1 |
| 3 | strong_click_30 | 45 | lg_dblsharp_tick_80 | 87 | transition_rampup_short_smooth2 |
| 4 | sharp_click | 46 | lg_dblsharp_tick_60 | 88 | transition_rampup_long_sharp1 |
| 5 | sharp_click_60 | 47 | buzz | 89 | transition_rampup_long_sharp2 |
| 6 | sharp_click_30 | 48 | buzz_80 | 90 | transition_rampup_med_sharp1 |
| 7 | soft_bump | 49 | buzz_60 | 91 | transition_rampup_med_sharp2 |
| 8 | soft_bump_60 | 50 | buzz_40 | 92 | transition_rampup_short_sharp1 |
| 9 | soft_bump_30 | 51 | buzz_20 | 93 | transition_rampup_short_sharp2 |
| 10 | dbl_click | 52 | pulsing_strong | 94 | transition_rampdown_long_smooth1_50 |
| 11 | dbl_click_60 | 53 | pulsing_strong_80 | 95 | transition_rampdown_long_smooth2_50 |
| 12 | trp_click | 54 | pulsing_medium | 96 | transition_rampdown_med_smooth1_50 |
| 13 | soft_fuzz | 55 | pulsing_medium_80 | 97 | transition_rampdown_med_smooth2_50 |
| 14 | strong_buzz | 56 | pulsing_sharp | 98 | transition_rampdown_short_smooth1_50 |
| 15 | alert_750ms | 57 | pulsing_sharp_80 | 99 | transition_rampdown_short_smooth2_50 |
| 16 | alert_1000ms | 58 | transition_click | 100 | transition_rampdown_long_sharp1_50 |
| 17 | strong_click1 | 59 | transition_click_80 | 101 | transition_rampdown_long_sharp2_50 |
| 18 | strong_click2_80 | 60 | transition_click_60 | 102 | transition_rampdown_med_sharp1_50 |
| 19 | strong_click3_60 | 61 | transition_click_40 | 103 | transition_rampdown_med_sharp2_50 |
| 20 | strong_click4_30 | 62 | transition_click_20 | 104 | transition_rampdown_short_sharp1_50 |
| 21 | medium_click1 | 63 | transition_click_10 | 105 | transition_rampdown_short_sharp2_50 |
| 22 | medium_click2_80 | 64 | transition_hum | 106 | transition_rampup_long_smooth1_50 |
| 23 | medium_click3_60 | 65 | transition_hum_80 | 107 | transition_rampup_long_smooth2_50 |
| 24 | sharp_tick1 | 66 | transition_hum_60 | 108 | transition_rampup_med_smooth1_50 |
| 25 | sharp_tick2_80 | 67 | transition_hum_40 | 109 | transition_rampup_med_smooth2_50 |
| 26 | sharp_tick3_60 | 68 | transition_hum_20 | 110 | transition_rampup_short_smooth1_50 |
| 27 | sh_dblclick_str | 69 | transition_hum_10 | 111 | transition_rampup_short_smooth2_50 |
| 28 | sh_dblclick_str_80 | 70 | transition_rampdown_long_smooth1 | 112 | transition_rampup_long_sharp1_50 |
| 29 | sh_dblclick_str_60 | 71 | transition_rampdown_long_smooth2 | 113 | transition_rampup_long_sharp2_50 |
| 30 | sh_dblclick_str_30 | 72 | transition_rampdown_med_smooth1 | 114 | transition_rampup_med_sharp1_50 |
| 31 | sh_dblclick_med | 73 | transition_rampdown_med_smooth2 | 115 | transition_rampup_med_sharp2_50 |
| 32 | sh_dblclick_med_80 | 74 | transition_rampdown_short_smooth1 | 116 | transition_rampup_short_sharp1_50 |
| 33 | sh_dblclick_med_60 | 75 | transition_rampdown_short_smooth2 | 117 | transition_rampup_short_sharp2_50 |
| 34 | sh_dblsharp_tick | 76 | transition_rampdown_long_sharp1 | 118 | long_buzz_for_programmatic_stopping |
| 35 | sh_dblsharp_tick_80 | 77 | transition_rampdown_long_sharp2 | 119 | smooth_hum1_50 |
| 36 | sh_dblsharp_tick_60 | 78 | transition_rampdown_med_sharp1 | 120 | smooth_hum2_40 |
| 37 | lg_dblclick_str | 79 | transition_rampdown_med_sharp2 | 121 | smooth_hum3_30 |
| 38 | lg_dblclick_str_80 | 80 | transition_rampdown_short_sharp1 | 122 | smooth_hum4_20 |
| 39 | lg_dblclick_str_60 | 81 | transition_rampdown_short_sharp2 | 123 | smooth_hum5_10 |
| 40 | lg_dblclick_str_30 | 82 | transition_rampup_long_smooth1 | | |
| 41 | lg_dblclick_med | 83 | transition_rampup_long_smooth2 | | |
| 42 | lg_dblclick_med_80 | 84 | transition_rampup_med_smooth1 | | |
### Optional DRV2605L defines
```
#define DRV_GREETING *sequence name or number*
```
If haptic feedback is enabled, the keyboard will vibrate to a specific sqeuence during startup. That can be selected using the following define:
```
#define DRV_MODE_DEFAULT *sequence name or number*
```
This will set what sequence HPT_RST will set as the active mode. If not defined, mode will be set to 1 when HPT_RST is pressed.

+ 29
- 0
docs/feature_layouts.md View File

@ -51,6 +51,35 @@ The folder name must be added to the keyboard's `rules.mk`:
but the `LAYOUT_<layout>` variable must be defined in `<folder>.h` as well.
## Building a Keymap
You should be able to build the keyboard keymap with a command in this format:
make <keyboard>:<layout>
### Conflicting layouts
When a keyboard supports multiple layout options,
LAYOUTS = ortho_4x4 ortho_4x12
And a layout exists for both options,
```
layouts/
+ community/
| + ortho_4x4/
| | + <layout>/
| | | + ...
| + ortho_4x12/
| | + <layout>/
| | | + ...
| + ...
```
The FORCE_LAYOUT argument can be used to specify which layout to build
make <keyboard>:<layout> FORCE_LAYOUT=ortho_4x4
make <keyboard>:<layout> FORCE_LAYOUT=ortho_4x12
## Tips for Making Layouts Keyboard-Agnostic
### Includes


+ 101
- 4
docs/feature_leader_key.md View File

@ -5,10 +5,11 @@ If you've ever used Vim, you know what a Leader key is. If not, you're about to
That's what `KC_LEAD` does. Here's an example:
1. Pick a key on your keyboard you want to use as the Leader key. Assign it the keycode `KC_LEAD`. This key would be dedicated just for this -- it's a single action key, can't be used for anything else.
2. Include the line `#define LEADER_TIMEOUT 300` in your config.h. The 300 there is 300ms -- that's how long you have for the sequence of keys following the leader. You can tweak this value for comfort, of course.
3. Within your `matrix_scan_user` function, do something like this:
2. Include the line `#define LEADER_TIMEOUT 300` in your `config.h`. This sets the timeout for the `KC_LEAD` key. Specifically, when you press the `KC_LEAD` key, you only have a certain amount of time to complete the Leader Key sequence. The `300` here sets that to 300ms, and you can increase this value to give you more time to hit the sequence. But any keys pressed during this timeout are intercepted and not sent, so you may want to keep this value low. .
* By default, this timeout is how long after pressing `KC_LEAD` to complete your entire sequence. This may be very low for some people. So you may want to increase this timeout. Optionally, you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped. This allows you to maintain a low value here, but still be able to use the longer sequences. To enable this option, add `#define LEADER_PER_KEY_TIMING` to your `config.h`.
3. Within your `matrix_scan_user` function, add something like this:
```
```c
LEADER_EXTERNS();
void matrix_scan_user(void) {
@ -44,6 +45,102 @@ Each of these accepts one or more keycodes as arguments. This is an important po
To add support for Leader Key you simply need to add a single line to your keymap's `rules.mk`:
```
```make
LEADER_ENABLE = yes
```
## Per Key Timing on Leader keys
Rather than relying on an incredibly high timeout for long leader key strings or those of us without 200wpm typing skills, we can enable per key timing to ensure that each key pressed provides us with more time to finish our stroke. This is incredibly helpful with leader key emulation of tap dance (read: multiple taps of the same key like C, C, C).
In order to enable this, place this in your `config.h`:
```c
#define LEADER_PER_KEY_TIMING
```
After this, it's recommended that you lower your `LEADER_TIMEOUT` to something less that 300ms.
```c
#define LEADER_TIMEOUT 250
```
Now, something like this won't seem impossible to do without a 1000MS leader key timeout:
```c
SEQ_THREE_KEYS(KC_C, KC_C, KC_C) {
SEND_STRING("Per key timing is great!!!");
}
```
## Strict Key Processing
By default, the Leader Key feature will filter the keycode out of [`Mod-Tap`](feature_advanced_keycodes.md#mod-tap) and [`Layer Tap`](feature_advanced_keycodes.md#switching-and-toggling-layers) functions when checking for the Leader sequences. That means if you're using `LT(3, KC_A)`, it will pick this up as `KC_A` for the sequence, rather than `LT(3, KC_A)`, giving a more expected behavior for newer users.
While, this may be fine for most, if you want to specify the whole keycode (eg, `LT(3, KC_A)` from the example above) in the sequence, you can enable this by added `#define LEADER_KEY_STRICT_KEY_PROCESSING` to your `config.h` file. This well then disable the filtering, and you'll need to specify the whole keycode.
## Customization
The Leader Key feature has some additional customization to how the Leader Key feature works. It has two functions that can be called at certain parts of the process. Namely `leader_start()` and `leader_end()`.
The `leader_start()` function is called when you tap the `KC_LEAD` key, and the `leader_end()` function is called when either the leader sequence is completed, or the leader timeout is hit.
You can add these functions to your code (`keymap.c` usually) to add feedback to the Leader sequences (such as beeping or playing music).
```c
void leader_start(void) {
// sequence started
}
void leader_end(void) {
// sequence ended (no success/failuer detection)
}
```
### Example
This example will play the Mario "One Up" sound when you hit `KC_LEAD` to start the Leader Sequence, and will play "All Star" if it completes successfully or "Rick Roll" you if it fails.
```c
bool did_leader_succeed;
#ifdef AUDIO_ENABLE
float leader_start[][2] = SONG(ONE_UP_SOUND );
float leader_succeed[][2] = SONG(ALL_STAR);
float leader_fail[][2] = SONG(RICK_ROLL);
#endif
LEADER_EXTERNS();
void matrix_scan_user(void) {
LEADER_DICTIONARY() {
did_leader_succeed = leading = false;
SEQ_ONE_KEY(KC_E) {
// Anything you can do in a macro.
SEND_STRING(SS_LCTRL(SS_LSFT("t")));
did_leader_succeed = true;
} else
SEQ_TWO_KEYS(KC_E, KC_D) {
SEND_STRING(SS_LGUI("r")"cmd"SS_TAP(KC_ENTER)SS_LCTRL("c"));
did_leader_succeed = true;
}
leader_end();
}
}
void leader_start(void) {
#ifdef AUDIO_ENABLE
PLAY_SONG(leader_start);
#endif
}
void leader_end(void) {
if (did_leader_succeed) {
#ifdef AUDIO_ENABLE
PLAY_SONG(leader_succeed);
#endif
} else {
#ifdef AUDIO_ENABLE
PLAY_SONG(leader_fail);
#endif
}
}
```

+ 90
- 0
docs/feature_led_matrix.md View File

@ -0,0 +1,90 @@
# LED Matrix Lighting
This feature allows you to use LED matrices driven by external drivers. It hooks into the backlight system so you can use the same keycodes as backlighting to control it.
If you want to use RGB LED's you should use the [RGB Matrix Subsystem](feature_rgb_matrix.md) instead.
## Driver configuration
### IS31FL3731
There is basic support for addressable LED matrix lighting with the I2C IS31FL3731 RGB controller. To enable it, add this to your `rules.mk`:
LED_MATRIX_ENABLE = IS31FL3731
You can use between 1 and 4 IS31FL3731 IC's. Do not specify `LED_DRIVER_ADDR_<N>` defines for IC's that are not present on your keyboard. You can define the following items in `config.h`:
| Variable | Description | Default |
|----------|-------------|---------|
| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages | 100 |
| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
| `LED_DRIVER_COUNT` | (Required) How many LED driver IC's are present | |
| `LED_DRIVER_LED_COUNT` | (Required) How many LED lights are present across all drivers | |
| `LED_DRIVER_ADDR_1` | (Required) Address for the first LED driver | |
| `LED_DRIVER_ADDR_2` | (Optional) Address for the second LED driver | |
| `LED_DRIVER_ADDR_3` | (Optional) Address for the third LED driver | |
| `LED_DRIVER_ADDR_4` | (Optional) Address for the fourth LED driver | |
Here is an example using 2 drivers.
// 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 LED_DRIVER_ADDR_1 0b1110100
#define LED_DRIVER_ADDR_2 0b1110110
#define LED_DRIVER_COUNT 2
#define LED_DRIVER_1_LED_COUNT 25
#define LED_DRIVER_2_LED_COUNT 24
#define LED_DRIVER_LED_COUNT LED_DRIVER_1_LED_TOTAL + LED_DRIVER_2_LED_TOTAL
Currently only 2 drivers are supported, but it would be trivial to support all 4 combinations.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
/* Refer to IS31 manual for these locations
* driver
* | LED address
* | | */
{0, C3_3},
....
}
Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](http://www.issi.com/WW/pdf/31FL3731.pdf) and the header file `drivers/issi/is31fl3731-simple.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` ).
## Keycodes
All LED matrix keycodes are currently shared with the [backlight system](feature_backlight.md).
## LED Matrix Effects
Currently no LED matrix effects have been created.
## Custom layer effects
Custom layer effects can be done by defining this in your `<keyboard>.c`:
void led_matrix_indicators_kb(void) {
led_matrix_set_index_value(index, value);
}
A similar function works in the keymap as `led_matrix_indicators_user`.
## Suspended state
To use the suspend feature, add this to your `<keyboard>.c`:
void suspend_power_down_kb(void)
{
led_matrix_set_suspend_state(true);
}
void suspend_wakeup_init_kb(void)
{
led_matrix_set_suspend_state(false);
}

+ 100
- 44
docs/feature_macros.md View File

@ -146,9 +146,102 @@ send_string(my_str);
SEND_STRING(".."SS_TAP(X_END));
```
## The Old Way: `MACRO()` & `action_get_macro`
?> This is inherited from TMK, and hasn't been updated - it's recommend that you use `SEND_STRING` and `process_record_user` instead.
## Advanced Macro Functions
There are some functions you may find useful in macro-writing. Keep in mind that while you can write some fairly advanced code within a macro, if your functionality gets too complex you may want to define a custom keycode instead. Macros are meant to be simple.
### `record->event.pressed`
This is a boolean value that can be tested to see if the switch is being pressed or released. An example of this is
```c
if (record->event.pressed) {
// on keydown
} else {
// on keyup
}
```
### `register_code(<kc>);`
This sends the `<kc>` keydown event to the computer. Some examples would be `KC_ESC`, `KC_C`, `KC_4`, and even modifiers such as `KC_LSFT` and `KC_LGUI`.
### `unregister_code(<kc>);`
Parallel to `register_code` function, this sends the `<kc>` keyup event to the computer. If you don't use this, the key will be held down until it's sent.
### `tap_code(<kc>);`
This will send `register_code(<kc>)` and then `unregister_code(<kc>)`. This is useful if you want to send both the press and release events ("tap" the key, rather than hold it).
If you're having issues with taps (un)registering, you can add a delay between the register and unregister events by setting `#define TAP_CODE_DELAY 100` in your `config.h` file. The value is in milliseconds.
### `register_code16(<kc>);`, `unregister_code16(<kc>);` and `tap_code16(<kc>);`
These functions work similar to their regular counterparts, but allow you to use modded keycodes (with Shift, Alt, Control, and/or GUI applied to them).
Eg, you could use `register_code16(S(KC_5));` instead of registering the mod, then registering the keycode.
### `clear_keyboard();`
This will clear all mods and keys currently pressed.
### `clear_mods();`
This will clear all mods currently pressed.
### `clear_keyboard_but_mods();`
This will clear all keys besides the mods currently pressed.
## Advanced Example:
### Super ALT↯TAB
This macro will register `KC_LALT` and tap `KC_TAB`, then wait for 1000ms. If the key is tapped again, it will send another `KC_TAB`; if there is no tap, `KC_LALT` will be unregistered, thus allowing you to cycle through windows.
```c
bool is_alt_tab_active = false; # ADD this near the begining of keymap.c
uint16_t alt_tab_timer = 0; # we will be using them soon.
enum custom_keycodes { # Make sure have the awesome keycode ready
ALT_TAB = SAFE_RANGE,
};
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) { # This will do most of the grunt work with the keycodes.
case ALT_TAB:
if (record->event.pressed) {
if (!is_alt_tab_active) {
is_alt_tab_active = true;
register_code(KC_LALT);
}
alt_tab_timer = timer_read();
register_code(KC_TAB);
} else {
unregister_code(KC_TAB);
}
break;
}
return true;
}
void matrix_scan_user(void) { # The very important timer.
if (is_alt_tab_active) {
if (timer_elapsed(alt_tab_timer) > 1000) {
unregister_code16(LALT(KC_TAB));
is_alt_tab_active = false;
}
}
}
```
---
## **(DEPRECATED)** The Old Way: `MACRO()` & `action_get_macro`
!> This is inherited from TMK, and hasn't been updated - it's recommended that you use `SEND_STRING` and `process_record_user` instead.
By default QMK assumes you don't have any macros. To define your macros you create an `action_get_macro()` function. For example:
@ -183,11 +276,11 @@ A macro can include the following commands:
### Mapping a Macro to a Key
Use the `M()` function within your `KEYMAP()` to call a macro. For example, here is the keymap for a 2-key keyboard:
Use the `M()` function within your keymap to call a macro. For example, here is the keymap for a 2-key keyboard:
```c
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = KEYMAP(
[0] = LAYOUT(
M(0), M(1)
),
};
@ -216,53 +309,16 @@ If you have a bunch of macros you want to refer to from your keymap while keepin
#define M_BYE M(1)
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = KEYMAP(
[0] = LAYOUT(
M_HI, M_BYE
),
};
```
## Advanced Macro Functions
There are some functions you may find useful in macro-writing. Keep in mind that while you can write some fairly advanced code within a macro if your functionality gets too complex you may want to define a custom keycode instead. Macros are meant to be simple.
### `record->event.pressed`
This is a boolean value that can be tested to see if the switch is being pressed or released. An example of this is
```c
if (record->event.pressed) {
// on keydown
} else {
// on keyup
}
```
### `register_code(<kc>);`
This sends the `<kc>` keydown event to the computer. Some examples would be `KC_ESC`, `KC_C`, `KC_4`, and even modifiers such as `KC_LSFT` and `KC_LGUI`.
### `unregister_code(<kc>);`
Parallel to `register_code` function, this sends the `<kc>` keyup event to the computer. If you don't use this, the key will be held down until it's sent.
### `tap_code(<kc>);`
This will send `register_code(<kc>)` and then `unregister_code(<kc>)`. This is useful if you want to send both the press and release events ("tap" the key, rather than hold it).
### `clear_keyboard();`
This will clear all mods and keys currently pressed.
### `clear_mods();`
This will clear all mods currently pressed.
### `clear_keyboard_but_mods();`
This will clear all keys besides the mods currently pressed.
## Advanced Example:
## Advanced Example: Single-Key Copy/Paste
### Single-Key Copy/Paste
This example defines a macro which sends `Ctrl-C` when pressed down, and `Ctrl-V` when released.


+ 90
- 52
docs/feature_mouse_keys.md View File

@ -1,81 +1,119 @@
# Mousekeys
# Mouse keys
Mouse keys is a feature that allows you to emulate a mouse using your keyboard. You can move the pointer at different speeds, press 5 buttons and scroll in 8 directions.
Mousekeys is a feature that allows you to emulate a mouse using your keyboard. You can move the pointer around, click up to 5 buttons, and even scroll in all 4 directions. QMK uses the same algorithm as the X Window System MouseKeysAccel feature. You can read more about it [on Wikipedia](https://en.wikipedia.org/wiki/Mouse_keys).
## Adding mouse keys to your keyboard
## Adding Mousekeys to a Keymap
To use mouse keys, you must at least enable mouse keys support and map mouse actions to keys on your keyboard.
There are two steps to adding Mousekeys support to your keyboard. You must enable support in the `rules.mk` file and you must map mouse actions to keys on your keyboard.
### Enabling mouse keys
### Adding Mousekeys Support in the `rules.mk`
To enable mouse keys, add the following line to your keymap’s `rules.mk`:
To add support for Mousekeys you simply need to add a single line to your keymap's `rules.mk`:
```
```c
MOUSEKEY_ENABLE = yes
```
You can see an example here: https://github.com/qmk/qmk_firmware/blob/master/keyboards/clueboard/66/keymaps/mouse_keys/rules.mk
### Mapping mouse actions
### Mapping Mouse Actions to Keyboard Keys
In your keymap you can use the following keycodes to map key presses to mouse actions:
You can use these keycodes within your keymap to map button presses to mouse actions:
|Key |Aliases |Description |
|----------------|---------|-----------------|
|`KC_MS_UP` |`KC_MS_U`|Move cursor up |
|`KC_MS_DOWN` |`KC_MS_D`|Move cursor down |
|`KC_MS_LEFT` |`KC_MS_L`|Move cursor left |
|`KC_MS_RIGHT` |`KC_MS_R`|Move cursor right|
|`KC_MS_BTN1` |`KC_BTN1`|Press button 1 |
|`KC_MS_BTN2` |`KC_BTN2`|Press button 2 |
|`KC_MS_BTN3` |`KC_BTN3`|Press button 3 |
|`KC_MS_BTN4` |`KC_BTN4`|Press button 4 |
|`KC_MS_BTN5` |`KC_BTN5`|Press button 5 |
|`KC_MS_WH_UP` |`KC_WH_U`|Move wheel up |
|`KC_MS_WH_DOWN` |`KC_WH_D`|Move wheel down |
|`KC_MS_WH_LEFT` |`KC_WH_L`|Move wheel left |
|`KC_MS_WH_RIGHT`|`KC_WH_R`|Move wheel right |
|`KC_MS_ACCEL0` |`KC_ACL0`|Set speed to 0 |
|`KC_MS_ACCEL1` |`KC_ACL1`|Set speed to 1 |
|`KC_MS_ACCEL2` |`KC_ACL2`|Set speed to 2 |
|Key |Aliases |Description |
|----------------|---------|---------------------------|
|`KC_MS_UP` |`KC_MS_U`|Mouse Cursor Up |
|`KC_MS_DOWN` |`KC_MS_D`|Mouse Cursor Down |
|`KC_MS_LEFT` |`KC_MS_L`|Mouse Cursor Left |
|`KC_MS_RIGHT` |`KC_MS_R`|Mouse Cursor Right |
|`KC_MS_BTN1` |`KC_BTN1`|Mouse Button 1 |
|`KC_MS_BTN2` |`KC_BTN2`|Mouse Button 2 |
|`KC_MS_BTN3` |`KC_BTN3`|Mouse Button 3 |
|`KC_MS_BTN4` |`KC_BTN4`|Mouse Button 4 |
|`KC_MS_BTN5` |`KC_BTN5`|Mouse Button 5 |
|`KC_MS_WH_UP` |`KC_WH_U`|Mouse Wheel Up |
|`KC_MS_WH_DOWN` |`KC_WH_D`|Mouse Wheel Down |
|`KC_MS_WH_LEFT` |`KC_WH_L`|Mouse Wheel Left |
|`KC_MS_WH_RIGHT`|`KC_WH_R`|Mouse Wheel Right |
|`KC_MS_ACCEL0` |`KC_ACL0`|Set mouse acceleration to 0|
|`KC_MS_ACCEL1` |`KC_ACL1`|Set mouse acceleration to 1|
|`KC_MS_ACCEL2` |`KC_ACL2`|Set mouse acceleration to 2|
## Configuring mouse keys
You can see an example in the `_ML` here: https://github.com/qmk/qmk_firmware/blob/master/keyboards/clueboard/66/keymaps/mouse_keys/keymap.c#L46
Mouse keys supports two different modes to move the cursor:
## Configuring the Behavior of Mousekeys
* **Accelerated (default):** Holding movement keys accelerates the cursor until it reaches its maximum speed.
* **Constant:** Holding movement keys moves the cursor at constant speeds.
The default speed for controlling the mouse with the keyboard is intentionally slow. You can adjust these parameters by adding these settings to your keymap's `config.h` file. All times are specified in milliseconds (ms).
The same principle applies to scrolling.
```
#define MOUSEKEY_DELAY 300
#define MOUSEKEY_INTERVAL 50
#define MOUSEKEY_MAX_SPEED 10
#define MOUSEKEY_TIME_TO_MAX 20
#define MOUSEKEY_WHEEL_MAX_SPEED 8
#define MOUSEKEY_WHEEL_TIME_TO_MAX 40
```
Configuration options that are times, intervals or delays are given in milliseconds. Scroll speed is given as multiples of the default scroll step. For example, a scroll speed of 8 means that each scroll action covers 8 times the length of the default scroll step as defined by your operating system or application.
### Accelerated mode
This is the default mode. You can adjust the cursor and scrolling acceleration using the following settings in your keymap’s `config.h` file:
### `MOUSEKEY_DELAY`
|Define |Default|Description |
|----------------------------|-------|---------------------------------------------------------|
|`MOUSEKEY_DELAY` |300 |Delay between pressing a movement key and cursor movement|
|`MOUSEKEY_INTERVAL` |50 |Time between cursor movements |
|`MOUSEKEY_MAX_SPEED` |10 |Maximum cursor speed at which acceleration stops |
|`MOUSEKEY_TIME_TO_MAX` |20 |Time until maximum cursor speed is reached |
|`MOUSEKEY_WHEEL_MAX_SPEED` |8 |Maximum number of scroll steps per scroll action |
|`MOUSEKEY_WHEEL_TIME_TO_MAX`|40 |Time until maximum scroll speed is reached |
When one of the mouse movement buttons is pressed this setting is used to define the delay between that button press and the mouse cursor moving. Some people find that small movements are impossible if this setting is too low, while settings that are too high feel sluggish.
Tips:
### `MOUSEKEY_INTERVAL`
* Setting `MOUSEKEY_DELAY` too low makes the cursor unresponsive. Setting it too high makes small movements difficult.
* For smoother cursor movements, lower the value of `MOUSEKEY_INTERVAL`. If the refresh rate of your display is 60Hz, you could set it to `16` (1/60). As this raises the cursor speed significantly, you may want to lower `MOUSEKEY_MAX_SPEED`.
* Setting `MOUSEKEY_TIME_TO_MAX` or `MOUSEKEY_WHEEL_TIME_TO_MAX` to `0` will disable acceleration for the cursor or scrolling respectively. This way you can make one of them constant while keeping the other accelerated, which is not possible in constant speed mode.
When a movement key is held down this specifies how long to wait between each movement report. Lower settings will translate into an effectively higher mouse speed.
Cursor acceleration uses the same algorithm as the X Window System MouseKeysAccel feature. You can read more about it [on Wikipedia](https://en.wikipedia.org/wiki/Mouse_keys).
### `MOUSEKEY_MAX_SPEED`
### Constant mode
As a movement key is held down the speed of the mouse cursor will increase until it reaches `MOUSEKEY_MAX_SPEED`.
In this mode you can define multiple different speeds for both the cursor and the mouse wheel. There is no acceleration. `KC_ACL0`, `KC_ACL1` and `KC_ACL2` change the cursor and scroll speed to their respective setting.
### `MOUSEKEY_TIME_TO_MAX`
You can choose whether speed selection is momentary or tap-to-select:
How long you want to hold down a movement key for until `MOUSEKEY_MAX_SPEED` is reached. This controls how quickly your cursor will accelerate.
* **Momentary:** The chosen speed is only active while you hold the respective key. When the key is raised, mouse keys returns to the unmodified speed.
* **Tap-to-select:** The chosen speed is activated when you press the respective key and remains active even after the key has been raised. The default speed is that of `KC_ACL1`. There is no unmodified speed.
### `MOUSEKEY_WHEEL_MAX_SPEED`
The default speeds from slowest to fastest are as follows:
The top speed for scrolling movements.
* **Momentary:** `KC_ACL0` < `KC_ACL1` < *unmodified* < `KC_ACL2`
* **Tap-to-select:** `KC_ACL0` < `KC_ACL1` < `KC_ACL2`
### `MOUSEKEY_WHEEL_TIME_TO_MAX`
To use constant speed mode, you must at least define `MK_3_SPEED` in your keymap’s `config.h` file:
```c
#define MK_3_SPEED
```
To enable momentary mode, also define `MK_MOMENTARY_ACCEL`:
```c
#define MK_MOMENTARY_ACCEL
```
How long you want to hold down a scroll key for until `MOUSEKEY_WHEEL_MAX_SPEED` is reached. This controls how quickly your scrolling will accelerate.
Use the following settings if you want to adjust cursor movement or scrolling:
|Define |Default |Description |
|---------------------|-------------|-------------------------------------------|
|`MK_3_SPEED` |*Not defined*|Enable constant cursor speeds |
|`MK_MOMENTARY_ACCEL` |*Not defined*|Enable momentary speed selection |
|`MK_C_OFFSET_UNMOD` |16 |Cursor offset per movement (unmodified) |
|`MK_C_INTERVAL_UNMOD`|16 |Time between cursor movements (unmodified) |
|`MK_C_OFFSET_0` |1 |Cursor offset per movement (`KC_ACL0`) |
|`MK_C_INTERVAL_0` |32 |Time between cursor movements (`KC_ACL0`) |
|`MK_C_OFFSET_1` |4 |Cursor offset per movement (`KC_ACL1`) |
|`MK_C_INTERVAL_1` |16 |Time between cursor movements (`KC_ACL1`) |
|`MK_C_OFFSET_2` |32 |Cursor offset per movement (`KC_ACL2`) |
|`MK_C_INTERVAL_2` |16 |Time between cursor movements (`KC_ACL2`) |
|`MK_W_OFFSET_UNMOD` |1 |Scroll steps per scroll action (unmodified)|
|`MK_W_INTERVAL_UNMOD`|40 |Time between scroll steps (unmodified) |
|`MK_W_OFFSET_0` |1 |Scroll steps per scroll action (`KC_ACL0`) |
|`MK_W_INTERVAL_0` |360 |Time between scroll steps (`KC_ACL0`) |
|`MK_W_OFFSET_1` |1 |Scroll steps per scroll action (`KC_ACL1`) |
|`MK_W_INTERVAL_1` |120 |Time between scroll steps (`KC_ACL1`) |
|`MK_W_OFFSET_2` |1 |Scroll steps per scroll action (`KC_ACL2`) |
|`MK_W_INTERVAL_2` |20 |Time between scroll steps (`KC_ACL2`) |

+ 274
- 0
docs/feature_oled_driver.md View File

@ -0,0 +1,274 @@
# OLED Driver
## OLED Supported Hardware
128x32 OLED modules using SSD1306 driver IC over I2C. Supported on AVR based keyboards. Possible but untested hardware includes ARM based keyboards and other sized OLED modules using SSD1306 over I2C, such as 128x64.
!> Warning: This OLED Driver currently uses the new i2c_master driver from split common code. If your split keyboard uses i2c to communication between sides this driver could cause an address conflict (serial is fine). Please contact your keyboard vendor and ask them to migrate to the latest split common code to fix this.
## Usage
To enable the OLED feature, there are three steps. First, when compiling your keyboard, you'll need to set `OLED_DRIVER_ENABLE=yes` in `rules.mk`, e.g.:
```
OLED_DRIVER_ENABLE = yes
```
This enables the feature and the `OLED_DRIVER_ENABLE` define. Then in your `keymap.c` file, you will need to implement the user task call, e.g:
```C++
#ifdef OLED_DRIVER_ENABLE
void oled_task_user(void) {
// Host Keyboard Layer Status
oled_write_P(PSTR("Layer: "), false);
switch (biton32(layer_state)) {
case _QWERTY:
oled_write_P(PSTR("Default\n"), false);
break;
case _FN:
oled_write_P(PSTR("FN\n"), false);
break;
case _ADJ:
oled_write_P(PSTR("ADJ\n"), false);
break;
default:
// Or use the write_ln shortcut over adding '\n' to the end of your string
oled_write_ln_P(PSTR("Undefined"), false);
}
// Host Keyboard LED Status
uint8_t led_usb_state = host_keyboard_leds();
oled_write_P(led_usb_state & (1<<USB_LED_NUM_LOCK) ? PSTR("NUMLCK ") : PSTR(" "), false);
oled_write_P(led_usb_state & (1<<USB_LED_CAPS_LOCK) ? PSTR("CAPLCK ") : PSTR(" "), false);
oled_write_P(led_usb_state & (1<<USB_LED_SCROLL_LOCK) ? PSTR("SCRLCK ") : PSTR(" "), false);
}
#endif
```
## Logo Example
In the default font, ranges in the font file are reserved for a QMK Logo. To Render this logo to the oled screen, use the following code example:
```C++
static void render_logo(void) {
static const char PROGMEM qmk_logo[] = {
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0};
oled_write_P(qmk_logo, false);
}
```
## Other Examples
In split keyboards, it is very common to have two OLED displays that each render different content and oriented flipped differently. You can do this by switching which content to render by using the return from `is_keyboard_master()` or `is_keyboard_left()` found in `split_util.h`, e.g:
```C++
#ifdef OLED_DRIVER_ENABLE
oled_rotation_t oled_init_user(oled_rotation_t rotation) {
if (!is_keyboard_master())
return OLED_ROTATION_180; // flips the display 180 degrees if offhand
return rotation;
}
void oled_task_user(void) {
if (is_keyboard_master()) {
render_status(); // Renders the current keyboard state (layer, lock, caps, scroll, etc)
} else {
render_logo(); // Renders a statuc logo
oled_scroll_left(); // Turns on scrolling
}
}
#endif
```
## Basic Configuration
|Define |Default |Description |
|-----------------------|---------------|------------------------------------------------|
|`OLED_DISPLAY_ADDRESS` |`0x3C` |The i2c address of the OLED Display |
|`OLED_FONT_H` |`"glcdfont.c"` |The font code file to use for custom fonts |
|`OLED_FONT_START` |`0` |The starting characer index for custom fonts |
|`OLED_FONT_END` |`224` |The ending characer index for custom fonts |
|`OLED_FONT_WIDTH` |`6` |The font width |
|`OLED_FONT_HEIGHT` |`8` |The font height (untested) |
|`OLED_DISABLE_TIMEOUT` |*Not defined* |Disables the built in OLED timeout feature. Useful when implementing custom timeout rules.|
## 128x64 & Custom sized OLED Displays
The default display size for this feature is 128x32 and all necessary defines are precalculated with that in mind. We have added a define, `OLED_DISPLAY_128X64`, to switch all the values to be used in a 128x64 display, as well as added a custom define, `OLED_DISPLAY_CUSTOM`, that allows you to provide the necessary values to the driver.
|Define |Default |Description |
|-----------------------|---------------|-----------------------------------------------------------------|
|`OLED_DISPLAY_128X64` |*Not defined* |Changes the display defines for use with 128x64 displays. |
|`OLED_DISPLAY_CUSTOM` |*Not defined* |Changes the display defines for use with custom displays.<br />Requires user to implement the below defines. |
|`OLED_DISPLAY_WIDTH` |`128` |The width of the OLED display. |
|`OLED_DISPLAY_HEIGHT` |`32` |The height of the OLED display. |
|`OLED_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br />`(OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)`|
|`OLED_BLOCK_TYPE` |`uint16_t` |The unsigned integer type to use for dirty rendering.|
|`OLED_BLOCK_COUNT` |`16` |The number of blocks the display is divided into for dirty rendering.<br />`(sizeof(OLED_BLOCK_TYPE) * 8)`|
|`OLED_BLOCK_SIZE` |`32` |The size of each block for dirty rendering<br />`(OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)`|
|`OLED_SOURCE_MAP` |`{ 0, ... N }` |Precalculated source array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
|`OLED_TARGET_MAP` |`{ 24, ... N }`|Precalculated target array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
### 90 Degree Rotation - Technical Mumbo Jumbo
```C
// OLED Rotation enum values are flags
typedef enum {
OLED_ROTATION_0 = 0,
OLED_ROTATION_90 = 1,
OLED_ROTATION_180 = 2,
OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180
} oled_rotation_t;
```
OLED displays driven by SSD1306 drivers only natively support in hard ware 0 degree and 180 degree rendering. This feature is done in software and not free. Using this feature will increase the time to calculate what data to send over i2c to the OLED. If you are strapped for cycles, this can cause keycodes to not register. In testing however, the rendering time on an `atmega32u4` board only went from 2ms to 5ms and keycodes not registering was only noticed once we hit 15ms.
90 Degree Rotated Rendering is achieved by using bitwise operations to rotate each 8 block of memory and uses two precalculated arrays to remap buffer memory to OLED memory. The memory map defines are precalculated for remap performance and are calculated based on the OLED Height, Width, and Block Size. For example, in the 128x32 implementation with a `uint8_t` block type, we have a 64 byte block size. This gives us eight 8 byte blocks that need to be rotated and rendered. The OLED renders horizontally two 8 byte blocks before moving down a page, e.g:
| | | | | | |
|---|---|---|---|---|---|
| 0 | 1 | | | | |
| 2 | 3 | | | | |
| 4 | 5 | | | | |
| 6 | 7 | | | | |
However the local buffer is stored as if it was Height x Width display instead of Width x Height, e.g:
| | | | | | |
|---|---|---|---|---|---|
| 3 | 7 | | | | |
| 2 | 6 | | | | |
| 1 | 5 | | | | |
| 0 | 4 | | | | |
So those precalculated arrays just index the memory offsets in the order in which each one iterates its data.
## OLED API
```C++
// OLED Rotation enum values are flags
typedef enum {
OLED_ROTATION_0 = 0,
OLED_ROTATION_90 = 1,
OLED_ROTATION_180 = 2,
OLED_ROTATION_270 = 3, // OLED_ROTATION_90 | OLED_ROTATION_180
} oled_rotation_t;
// Initialize the OLED display, rotating the rendered output based on the define passed in.
// Returns true if the OLED was initialized successfully
bool oled_init(oled_rotation_t rotation);
// Called at the start of oled_init, weak function overridable by the user
// rotation - the value passed into oled_init
// Return new oled_rotation_t if you want to override default rotation
oled_rotation_t oled_init_user(oled_rotation_t rotation);
// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
void oled_clear(void);
// Renders the dirty chunks of the buffer to OLED display
void oled_render(void);
// Moves cursor to character position indicated by column and line, wraps if out of bounds
// Max column denoted by 'oled_max_chars()' and max lines by 'oled_max_lines()' functions
void oled_set_cursor(uint8_t col, uint8_t line);
// Advances the cursor to the next page, writing ' ' if true
// Wraps to the begining when out of bounds
void oled_advance_page(bool clearPageRemainder);
// Moves the cursor forward 1 character length
// Advance page if there is not enough room for the next character
// Wraps to the begining when out of bounds
void oled_advance_char(void);
// Writes a single character to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
// Main handler that writes character data to the display buffer
void oled_write_char(const char data, bool invert);
// Writes a string to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
void oled_write(const char *data, bool invert);
// Writes a string to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
void oled_write_ln(const char *data, bool invert);
// Writes a PROGMEM string to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
// Remapped to call 'void oled_write(const char *data, bool invert);' on ARM
void oled_write_P(const char *data, bool invert);
// Writes a PROGMEM string to the buffer at current cursor position
// Advances the cursor while writing, inverts the pixels if true
// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
// Remapped to call 'void oled_write_ln(const char *data, bool invert);' on ARM
void oled_write_ln_P(const char *data, bool invert);
// Can be used to manually turn on the screen if it is off
// Returns true if the screen was on or turns on
bool oled_on(void);
// Can be used to manually turn off the screen if it is on
// Returns true if the screen was off or turns off
bool oled_off(void);
// Basically it's oled_render, but with timeout management and oled_task_user calling!
void oled_task(void);
// Called at the start of oled_task, weak function overridable by the user
void oled_task_user(void);
// Scrolls the entire display right
// Returns true if the screen was scrolling or starts scrolling
// NOTE: display contents cannot be changed while scrolling
bool oled_scroll_right(void);
// Scrolls the entire display left
// Returns true if the screen was scrolling or starts scrolling
// NOTE: display contents cannot be changed while scrolling
bool oled_scroll_left(void);
// Turns off display scrolling
// Returns true if the screen was not scrolling or stops scrolling
bool oled_scroll_off(void);
// Returns the maximum number of characters that will fit on a line
uint8_t oled_max_chars(void);
// Returns the maximum number of lines that will fit on the OLED
uint8_t oled_max_lines(void);
```
## SSD1306.h driver conversion guide
|Old API |Recommended New API |
|---------------------------|-----------------------------------|
|`struct CharacterMatrix` |*removed - delete all references* |
|`iota_gfx_init` |`oled_init` |
|`iota_gfx_on` |`oled_on` |
|`iota_gfx_off` |`oled_off` |
|`iota_gfx_flush` |`oled_render` |
|`iota_gfx_write_char` |`oled_write_char` |
|`iota_gfx_write` |`oled_write` |
|`iota_gfx_write_P` |`oled_write_P` |
|`iota_gfx_clear_screen` |`oled_clear` |
|`matrix_clear` |*removed - delete all references* |
|`matrix_write_char_inner` |`oled_write_char` |
|`matrix_write_char` |`oled_write_char` |
|`matrix_write` |`oled_write` |
|`matrix_write_ln` |`oled_write_ln` |
|`matrix_write_P` |`oled_write_P` |
|`matrix_write_ln_P` |`oled_write_ln_P` |
|`matrix_render` |`oled_render` |
|`iota_gfx_task` |`oled_task` |
|`iota_gfx_task_user` |`oled_task_user` |

+ 306
- 152
docs/feature_rgb_matrix.md View File

@ -1,217 +1,371 @@
# RGB Matrix Lighting
## Driver configuration
This feature allows you to use RGB LED matrices driven by external drivers. It hooks into the RGBLIGHT system so you can use the same keycodes as RGBLIGHT to control it.
If you want to use single color LED's you should use the [LED Matrix Subsystem](feature_led_matrix.md) instead.
## Driver configuration
---
### IS31FL3731
There is basic support for addressable RGB matrix lighting with the I2C IS31FL3731 RGB controller. To enable it, add this to your `rules.mk`:
RGB_MATRIX_ENABLE = IS31FL3731
```C
RGB_MATRIX_ENABLE = IS31FL3731
```
Configure the hardware via your `config.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 DRIVER_ADDR_1 0b1110100
#define DRIVER_ADDR_2 0b1110110
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 25
#define DRIVER_2_LED_TOTAL 24
#define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL
```C
// 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 DRIVER_ADDR_1 0b1110100
#define DRIVER_ADDR_2 0b1110110
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 25
#define DRIVER_2_LED_TOTAL 24
#define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL
```
Currently only 2 drivers are supported, but it would be trivial to support all 4 combinations.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, C1_3, C2_3, C3_3},
....
}
```C
const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, C1_3, C2_3, C3_3},
....
}
```
Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](http://www.issi.com/WW/pdf/31FL3731.pdf) and the header file `drivers/issi/is31fl3731.h`. The `driver` is the index of the driver you defined in your `config.h` (`0` or `1` right now).
### IS31FL3733
---
### IS31FL3733/IS31FL3737
!> For the IS31FL3737, replace all instances of `IS31FL3733` below with `IS31FL3737`.
There is basic support for addressable RGB matrix lighting with the I2C IS31FL3733 RGB controller. To enable it, add this to your `rules.mk`:
RGB_MATRIX_ENABLE = IS31FL3733
```C
RGB_MATRIX_ENABLE = IS31FL3733
```
Configure the hardware via your `config.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:
// 00 <-> GND
// 01 <-> SCL
// 10 <-> SDA
// 11 <-> VCC
// ADDR1 represents A1:A0 of the 7-bit address.
// ADDR2 represents A3:A2 of the 7-bit address.
// The result is: 0b101(ADDR2)(ADDR1)
#define DRIVER_ADDR_1 0b1010000
#define DRIVER_ADDR_2 0b1010000 // this is here for compliancy reasons.
#define DRIVER_COUNT 1
#define DRIVER_1_LED_TOTAL 64
#define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL
```C
// 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:
// 00 <-> GND
// 01 <-> SCL
// 10 <-> SDA
// 11 <-> VCC
// ADDR1 represents A1:A0 of the 7-bit address.
// ADDR2 represents A3:A2 of the 7-bit address.
// The result is: 0b101(ADDR2)(ADDR1)
#define DRIVER_ADDR_1 0b1010000
#define DRIVER_ADDR_2 0b1010000 // this is here for compliancy reasons.
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 64
#define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL
```
Currently only a single drivers is supported, but it would be trivial to support all 4 combinations. For now define `DRIVER_ADDR_2` as `DRIVER_ADDR_1`
Define these arrays listing all the LEDs in your `<keyboard>.c`:
const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, B_1, A_1, C_1},
....
}
```C
const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, B_1, A_1, C_1},
....
}
```
Where `X_Y` is the location of the LED in the matrix defined by [the datasheet](http://www.issi.com/WW/pdf/31FL3733.pdf) and the header file `drivers/issi/is31fl3733.h`. The `driver` is the index of the driver you defined in your `config.h` (Only `0` right now).
From this point forward the configuration is the same for all the drivers.
---
const rgb_led g_rgb_leds[DRIVER_LED_TOTAL] = {
/* {row | col << 4}
* | {x=0..224, y=0..64}
* | | modifier
* | | | */
{{0|(0<<4)}, {20.36*0, 21.33*0}, 1},
{{0|(1<<4)}, {20.36*1, 21.33*0}, 1},
....
}
### WS2812 (AVR only)
The format for the matrix position used in this array is `{row | (col << 4)}`. The `x` is between (inclusive) 0-224, and `y` is between (inclusive) 0-64. The easiest way to calculate these positions is:
There is basic support for addressable RGB matrix lighting with a WS2811/WS2812{a,b,c} addressable LED strand. To enable it, add this to your `rules.mk`:
x = 224 / ( NUMBER_OF_ROWS - 1 ) * ROW_POSITION
y = 64 / (NUMBER_OF_COLS - 1 ) * COL_POSITION
```C
RGB_MATRIX_ENABLE = WS2812
```
Where all variables are decimels/floats.
Configure the hardware via your `config.h`:
`modifier` is a boolean, whether or not a certain key is considered a modifier (used in some effects).
```C
// The pin connected to the data pin of the LEDs
#define RGB_DI_PIN D7
// The number of LEDs connected
#define DRIVER_LED_TOTAL 70
```
## Keycodes
---
All RGB keycodes are currently shared with the RGBLIGHT system:
From this point forward the configuration is the same for all the drivers. The struct rgb_led array tells the system for each led, what key electrical matrix it represents, what the physical position is on the board, and if the led is for a modifier key or not. Here is a brief example:
* `RGB_TOG` - toggle
* `RGB_MOD` - cycle through modes
* `RGB_HUI` - increase hue
* `RGB_HUD` - decrease hue
* `RGB_SAI` - increase saturation
* `RGB_SAD` - decrease saturation
* `RGB_VAI` - increase value
* `RGB_VAD` - decrease value
* `RGB_SPI` - increase speed effect (no EEPROM support)
* `RGB_SPD` - decrease speed effect (no EEPROM support)
```C
rgb_led g_rgb_leds[DRIVER_LED_TOTAL] = {
/* {row | col << 4}
* | {x=0..224, y=0..64}
* | | flags
* | | | */
{{0|(0<<4)}, {20.36*0, 21.33*0}, 1},
{{0|(1<<4)}, {20.36*1, 21.33*0}, 4},
....
}
```
The first part, `{row | col << 4}`, tells the system what key this LED represents by using the key's electrical matrix row & col. The second part, `{x=0..224, y=0..64}` represents the LED's physical position on the keyboard. The `x` is between (inclusive) 0-224, and `y` is between (inclusive) 0-64 as the effects are based on this range. The easiest way to calculate these positions is imagine your keyboard is a grid, and the top left of the keyboard represents x, y coordinate 0, 0 and the bottom right of your keyboard represents 224, 64. Using this as a basis, you can use the following formula to calculate the physical position:
* `RGB_MODE_*` keycodes will generally work, but are not currently mapped to the correct effects for the RGB Matrix system
```C
x = 224 / (NUMBER_OF_COLS - 1) * COL_POSITION
y = 64 / (NUMBER_OF_ROWS - 1) * ROW_POSITION
```
## RGB Matrix Effects
Where NUMBER_OF_COLS, NUMBER_OF_ROWS, COL_POSITION, & ROW_POSITION are all based on the physical layout of your keyboard, not the electrical layout.
These are the effects that are currently available:
enum rgb_matrix_effects {
RGB_MATRIX_SOLID_COLOR = 1,
RGB_MATRIX_ALPHAS_MODS,
RGB_MATRIX_DUAL_BEACON,
RGB_MATRIX_GRADIENT_UP_DOWN,
RGB_MATRIX_RAINDROPS,
RGB_MATRIX_CYCLE_ALL,
RGB_MATRIX_CYCLE_LEFT_RIGHT,
RGB_MATRIX_CYCLE_UP_DOWN,
RGB_MATRIX_RAINBOW_BEACON,
RGB_MATRIX_RAINBOW_PINWHEELS,
RGB_MATRIX_RAINBOW_MOVING_CHEVRON,
RGB_MATRIX_JELLYBEAN_RAINDROPS,
RGB_MATRIX_DIGITAL_RAIN,
#ifdef RGB_MATRIX_KEYPRESSES
RGB_MATRIX_SOLID_REACTIVE,
RGB_MATRIX_SPLASH,
RGB_MATRIX_MULTISPLASH,
RGB_MATRIX_SOLID_SPLASH,
RGB_MATRIX_SOLID_MULTISPLASH,
#endif
RGB_MATRIX_EFFECT_MAX
};
You can disable a single effect by defining `DISABLE_[EFFECT_NAME]` in your `config.h`:
`flags` is a bitmask, whether or not a certain LEDs is of a certain type. It is recommended that LEDs are set to only 1 type.
## Flags
|Define |Description |
|---------------------------------------------------|--------------------------------------------|
|`#define DISABLE_RGB_MATRIX_ALPHAS_MODS` |Disables `RGB_MATRIX_ALPHAS_MODS` |
|`#define DISABLE_RGB_MATRIX_DUAL_BEACON` |Disables `RGB_MATRIX_DUAL_BEACON` |
|`#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN` |Disables `RGB_MATRIX_GRADIENT_UP_DOWN` |
|`#define DISABLE_RGB_MATRIX_RAINDROPS` |Disables `RGB_MATRIX_RAINDROPS` |
|`#define DISABLE_RGB_MATRIX_CYCLE_ALL` |Disables `RGB_MATRIX_CYCLE_ALL` |
|`#define DISABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT` |Disables `RGB_MATRIX_CYCLE_LEFT_RIGHT` |
|`#define DISABLE_RGB_MATRIX_CYCLE_UP_DOWN` |Disables `RGB_MATRIX_CYCLE_UP_DOWN` |
|`#define DISABLE_RGB_MATRIX_RAINBOW_BEACON` |Disables `RGB_MATRIX_RAINBOW_BEACON` |
|`#define DISABLE_RGB_MATRIX_RAINBOW_PINWHEELS` |Disables `RGB_MATRIX_RAINBOW_PINWHEELS` |
|`#define DISABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON`|Disables `RGB_MATRIX_RAINBOW_MOVING_CHEVRON`|
|`#define DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS` |Disables `RGB_MATRIX_JELLYBEAN_RAINDROPS` |
|`#define DISABLE_RGB_MATRIX_DIGITAL_RAIN` |Disables `RGB_MATRIX_DIGITAL_RAIN` |
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE` |Disables `RGB_MATRIX_SOLID_REACTIVE` |
|`#define DISABLE_RGB_MATRIX_SPLASH` |Disables `RGB_MATRIX_SPLASH` |
|`#define DISABLE_RGB_MATRIX_MULTISPLASH` |Disables `RGB_MATRIX_MULTISPLASH` |
|`#define DISABLE_RGB_MATRIX_SOLID_SPLASH` |Disables `RGB_MATRIX_SOLID_SPLASH` |
|`#define DISABLE_RGB_MATRIX_SOLID_MULTISPLASH` |Disables `RGB_MATRIX_SOLID_MULTISPLASH` |
|Define |Description |
|------------------------------------|-------------------------------------------|
|`#define HAS_FLAGS(bits, flags)` |Returns true if `bits` has all `flags` set.|
|`#define HAS_ANY_FLAGS(bits, flags)`|Returns true if `bits` has any `flags` set.|
|`#define LED_FLAG_NONE 0x00` |If thes LED has no flags. |
|`#define LED_FLAG_ALL 0xFF` |If thes LED has all flags. |
|`#define LED_FLAG_MODIFIER 0x01` |If the Key for this LED is a modifier. |
|`#define LED_FLAG_UNDERGLOW 0x02` |If the LED is for underglow. |
|`#define LED_FLAG_KEYLIGHT 0x04` |If the LED is for key backlight. |
## Keycodes
## Custom layer effects
All RGB keycodes are currently shared with the RGBLIGHT system:
Custom layer effects can be done by defining this in your `<keyboard>.c`:
* `RGB_TOG` - toggle
* `RGB_MOD` - cycle through modes
* `RGB_HUI` - increase hue
* `RGB_HUD` - decrease hue
* `RGB_SAI` - increase saturation
* `RGB_SAD` - decrease saturation
* `RGB_VAI` - increase value
* `RGB_VAD` - decrease value
* `RGB_SPI` - increase speed effect (no EEPROM support)
* `RGB_SPD` - decrease speed effect (no EEPROM support)
* `RGB_MODE_*` keycodes will generally work, but are not currently mapped to the correct effects for the RGB Matrix system
void rgb_matrix_indicators_kb(void) {
rgb_matrix_set_color(index, red, green, blue);
}
## RGB Matrix Effects
All effects have been configured to support current configuration values (Hue, Saturation, Value, & Speed) unless otherwise noted below. These are the effects that are currently available:
```C
enum rgb_matrix_effects {
RGB_MATRIX_NONE = 0,
RGB_MATRIX_SOLID_COLOR = 1, // Static single hue, no speed support
RGB_MATRIX_ALPHAS_MODS, // Static dual hue, speed is hue for secondary hue
RGB_MATRIX_GRADIENT_UP_DOWN, // Static gradient top to bottom, speed controls how much gradient changes
RGB_MATRIX_BREATHING, // Single hue brightness cycling animation
RGB_MATRIX_CYCLE_ALL, // Full keyboard solid hue cycling through full gradient
RGB_MATRIX_CYCLE_LEFT_RIGHT, // Full gradient scrolling left to right
RGB_MATRIX_CYCLE_UP_DOWN, // Full gradient scrolling top to bottom
RGB_MATRIX_RAINBOW_MOVING_CHEVRON, // Full gradent Chevron shapped scrolling left to right
RGB_MATRIX_DUAL_BEACON, // Full gradient spinning around center of keyboard
RGB_MATRIX_RAINBOW_BEACON, // Full tighter gradient spinning around center of keyboard
RGB_MATRIX_RAINBOW_PINWHEELS, // Full dual gradients spinning two halfs of keyboard
RGB_MATRIX_RAINDROPS, // Randomly changes a single key's hue
RGB_MATRIX_JELLYBEAN_RAINDROPS, // Randomly changes a single key's hue and saturation
RGB_MATRIX_DIGITAL_RAIN, // That famous computer simulation
#if defined(RGB_MATRIX_KEYPRESSES) || defined(RGB_MATRIX_KEYRELEASES)
RGB_MATRIX_SOLID_REACTIVE_SIMPLE, // Pulses keys hit to hue & value then fades value out
RGB_MATRIX_SOLID_REACTIVE, // Static single hue, pulses keys hit to shifted hue then fades to current hue
RGB_MATRIX_SOLID_REACTIVE_WIDE // Hue & value pulse near a single key hit then fades value out
RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE // Hue & value pulse near multiple key hits then fades value out
RGB_MATRIX_SOLID_REACTIVE_CROSS // Hue & value pulse the same column and row of a single key hit then fades value out
RGB_MATRIX_SOLID_REACTIVE_MULTICROSS // Hue & value pulse the same column and row of multiple key hits then fades value out
RGB_MATRIX_SOLID_REACTIVE_NEXUS // Hue & value pulse away on the same column and row of a single key hit then fades value out
RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS // Hue & value pulse away on the same column and row of multiple key hits then fades value out
RGB_MATRIX_SPLASH, // Full gradient & value pulse away from a single key hit then fades value out
RGB_MATRIX_MULTISPLASH, // Full gradient & value pulse away from multiple key hits then fades value out
RGB_MATRIX_SOLID_SPLASH, // Hue & value pulse away from a single key hit then fades value out
RGB_MATRIX_SOLID_MULTISPLASH, // Hue & value pulse away from multiple key hits then fades value out
#endif
RGB_MATRIX_EFFECT_MAX
};
```
You can disable a single effect by defining `DISABLE_[EFFECT_NAME]` in your `config.h`:
|Define |Description |
|-------------------------------------------------------|-----------------------------------------------|
|`#define DISABLE_RGB_MATRIX_ALPHAS_MODS` |Disables `RGB_MATRIX_ALPHAS_MODS` |
|`#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN` |Disables `RGB_MATRIX_GRADIENT_UP_DOWN` |
|`#define DISABLE_RGB_MATRIX_BREATHING` |Disables `RGB_MATRIX_BREATHING` |
|`#define DISABLE_RGB_MATRIX_CYCLE_ALL` |Disables `RGB_MATRIX_CYCLE_ALL` |
|`#define DISABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT` |Disables `RGB_MATRIX_CYCLE_LEFT_RIGHT` |
|`#define DISABLE_RGB_MATRIX_CYCLE_UP_DOWN` |Disables `RGB_MATRIX_CYCLE_UP_DOWN` |
|`#define DISABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON` |Disables `RGB_MATRIX_RAINBOW_MOVING_CHEVRON` |
|`#define DISABLE_RGB_MATRIX_DUAL_BEACON` |Disables `RGB_MATRIX_DUAL_BEACON` |
|`#define DISABLE_RGB_MATRIX_RAINBOW_BEACON` |Disables `RGB_MATRIX_RAINBOW_BEACON` |
|`#define DISABLE_RGB_MATRIX_RAINBOW_PINWHEELS` |Disables `RGB_MATRIX_RAINBOW_PINWHEELS` |
|`#define DISABLE_RGB_MATRIX_RAINDROPS` |Disables `RGB_MATRIX_RAINDROPS` |
|`#define DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS` |Disables `RGB_MATRIX_JELLYBEAN_RAINDROPS` |
|`#define DISABLE_RGB_MATRIX_DIGITAL_RAIN` |Disables `RGB_MATRIX_DIGITAL_RAIN` |
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE` |Disables `RGB_MATRIX_SOLID_REACTIVE` |
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE` |Disables `RGB_MATRIX_SOLID_REACTIVE_SIMPLE` |
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE` |Disables `RGB_MATRIX_SOLID_REACTIVE_WIDE` |
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE` |Disables `RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE` |
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS` |Disables `RGB_MATRIX_SOLID_REACTIVE_CROSS` |
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS` |Disables `RGB_MATRIX_SOLID_REACTIVE_MULTICROSS`|
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS` |Disables `RGB_MATRIX_SOLID_REACTIVE_NEXUS` |
|`#define DISABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS` |Disables `RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS`|
|`#define DISABLE_RGB_MATRIX_SPLASH` |Disables `RGB_MATRIX_SPLASH` |
|`#define DISABLE_RGB_MATRIX_MULTISPLASH` |Disables `RGB_MATRIX_MULTISPLASH` |
|`#define DISABLE_RGB_MATRIX_SOLID_SPLASH` |Disables `RGB_MATRIX_SOLID_SPLASH` |
|`#define DISABLE_RGB_MATRIX_SOLID_MULTISPLASH` |Disables `RGB_MATRIX_SOLID_MULTISPLASH` |
## Custom RGB Matrix Effects
By setting `RGB_MATRIX_CUSTOM_USER` (and/or `RGB_MATRIX_CUSTOM_KB`) in `rule.mk`, new effects can be defined directly from userspace, without having to edit any QMK core files.
To declare new effects, create a new `rgb_matrix_user/kb.inc` that looks something like this:
`rgb_matrix_user.inc` should go in the root of the keymap directory.
`rgb_matrix_kb.inc` should go in the root of the keyboard directory.
```C
// !!! DO NOT ADD #pragma once !!! //
// Step 1.
// Declare custom effects using the RGB_MATRIX_EFFECT macro
// (note the lack of semicolon after the macro!)
RGB_MATRIX_EFFECT(my_cool_effect)
RGB_MATRIX_EFFECT(my_cool_effect2)
// Step 2.
// Define effects inside the `RGB_MATRIX_CUSTOM_EFFECT_IMPLS` ifdef block
#ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
// e.g: A simple effect, self-contained within a single method
static bool my_cool_effect(effect_params_t* params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
for (uint8_t i = led_min; i < led_max; i++) {
rgb_matrix_set_color(i, 0xff, 0xff, 0x00);
}
return led_max < DRIVER_LED_TOTAL;
}
// e.g: A more complex effect, relying on external methods and state, with
// dedicated init and run methods
static uint8_t some_global_state;
static void my_cool_effect2_complex_init(effect_params_t* params) {
some_global_state = 1;
}
static bool my_cool_effect2_complex_run(effect_params_t* params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
for (uint8_t i = led_min; i < led_max; i++) {
rgb_matrix_set_color(i, 0xff, some_global_state++, 0xff);
}
return led_max < DRIVER_LED_TOTAL;
}
static bool my_cool_effect2(effect_params_t* params) {
if (params->init) my_cool_effect2_complex_init(params);
return my_cool_effect2_complex_run(params);
}
#endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
```
For inspiration and examples, check out the built-in effects under `quantum/rgb_matrix_animation/`
## Colors
These are shorthands to popular colors. The `RGB` ones can be passed to the `setrgb` functions, while the `HSV` ones to the `sethsv` functions.
|RGB |HSV |
|-------------------|-------------------|
|`RGB_WHITE` |`HSV_WHITE` |
|`RGB_RED` |`HSV_RED` |
|`RGB_CORAL` |`HSV_CORAL` |
|`RGB_ORANGE` |`HSV_ORANGE` |
|`RGB_GOLDENROD` |`HSV_GOLDENROD` |
|`RGB_GOLD` |`HSV_GOLD` |
|`RGB_YELLOW` |`HSV_YELLOW` |
|`RGB_CHARTREUSE` |`HSV_CHARTREUSE` |
|`RGB_GREEN` |`HSV_GREEN` |
|`RGB_SPRINGGREEN` |`HSV_SPRINGGREEN` |
|`RGB_TURQUOISE` |`HSV_TURQUOISE` |
|`RGB_TEAL` |`HSV_TEAL` |
|`RGB_CYAN` |`HSV_CYAN` |
|`RGB_AZURE` |`HSV_AZURE` |
|`RGB_BLUE` |`HSV_BLUE` |
|`RGB_PURPLE` |`HSV_PURPLE` |
|`RGB_MAGENTA` |`HSV_MAGENTA` |
|`RGB_PINK` |`HSV_PINK` |
These are defined in [`rgblight_list.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/rgblight_list.h). Feel free to add to this list!
A similar function works in the keymap as `rgb_matrix_indicators_user`.
## Additional `config.h` Options
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses (will slow down matrix scan by a lot)
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (not recommened)
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
#define RGB_MATRIX_SKIP_FRAMES 1 // number of frames to skip when displaying animations (0 is full effect) if not defined defaults to 1
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
```C
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
#define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
```
## EEPROM storage
The EEPROM for it is currently shared with the RGBLIGHT system (it's generally assumed only one RGB would be used at a time), but could be configured to use its own 32bit address with:
#define EECONFIG_RGB_MATRIX (uint32_t *)16
```C
#define EECONFIG_RGB_MATRIX (uint32_t *)28
```
Where `16` is an unused index from `eeconfig.h`.
Where `28` is an unused index from `eeconfig.h`.
## Suspended state
To use the suspend feature, add this to your `<keyboard>.c`:
void suspend_power_down_kb(void)
{
rgb_matrix_set_suspend_state(true);
}
void suspend_wakeup_init_kb(void)
{
rgb_matrix_set_suspend_state(false);
}
```C
void suspend_power_down_kb(void)
{
rgb_matrix_set_suspend_state(true);
}
void suspend_wakeup_init_kb(void)
{
rgb_matrix_set_suspend_state(false);
}
```

+ 157
- 23
docs/feature_rgblight.md View File

@ -23,10 +23,11 @@ RGBLIGHT_ENABLE = yes
At minimum you must define the data pin your LED strip is connected to, and the number of LEDs in the strip, in your `config.h`. If your keyboard has onboard RGB LEDs, and you are simply creating a keymap, you usually won't need to modify these.
|Define |Description |
|------------|---------------------------------------------|
|`RGB_DI_PIN`|The pin connected to the data pin of the LEDs|
|`RGBLED_NUM`|The number of LEDs connected |
|Define |Description |
|---------------|---------------------------------------------------------------------------------------------------------|
|`RGB_DI_PIN` |The pin connected to the data pin of the LEDs |
|`RGBLED_NUM` |The number of LEDs connected |
|`RGBLED_SPLIT` |(Optional) For split keyboards, the number of LEDs connected on each half directly wired to `RGB_DI_PIN` |
Then you should be able to use the keycodes below to change the RGB lighting to your liking.
@ -74,6 +75,7 @@ Your RGB lighting can be configured by placing these `#define`s in your `config.
|`RGBLIGHT_VAL_STEP` |`17` |The number of steps to increment the brightness by |
|`RGBLIGHT_LIMIT_VAL` |`255` |The maximum brightness level |
|`RGBLIGHT_SLEEP` |*Not defined*|If defined, the RGB lighting will be switched off when the host goes to sleep|
|`RGBLIGHT_SPLIT` |*Not defined*|If defined, synchronization functionality for split keyboards is added|
## Animations
@ -112,7 +114,7 @@ The following options can be used to tweak the various animations:
|`RGBLIGHT_EFFECT_RGB_TEST` |*Not defined*|If defined, enable RGB test animation mode. |
|`RGBLIGHT_EFFECT_ALTERNATING` |*Not defined*|If defined, enable alternating animation mode. |
|`RGBLIGHT_ANIMATIONS` |*Not defined*|If defined, enables all additional animation modes |
|`RGBLIGHT_EFFECT_BREATHE_CENTER` |`1.85` |Used to calculate the curve for the breathing animation. Valid values are 1.0 to 2.7 |
|`RGBLIGHT_EFFECT_BREATHE_CENTER` |*Not defined*|If defined, used to calculate the curve for the breathing animation. Valid values are 1.0 to 2.7 |
|`RGBLIGHT_EFFECT_BREATHE_MAX` |`255` |The maximum brightness for the breathing mode. Valid values are 1 to 255 |
|`RGBLIGHT_EFFECT_SNAKE_LENGTH` |`4` |The number of LEDs to light up for the "Snake" animation |
|`RGBLIGHT_EFFECT_KNIGHT_LENGTH` |`3` |The number of LEDs to light up for the "Knight" animation |
@ -124,6 +126,8 @@ The following options can be used to tweak the various animations:
You can also modify the speeds that the different modes animate at:
Here is a quick demo on Youtube (with NPKC KC60) (https://www.youtube.com/watch?v=VKrpPAHlisY).
```c
// How long (in milliseconds) to wait between animation steps for each of the "Solid color breathing" animations
const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
@ -141,29 +145,159 @@ const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31};
// These control which hues are selected for each of the "Static gradient" modes
const uint16_t RGBLED_GRADIENT_RANGES[] PROGMEM = {360, 240, 180, 120, 90};
const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64};
```
## Functions
If you need to change your RGB lighting in code, for example in a macro to change the color whenever you switch layers, QMK provides a set of functions to assist you. See [`rgblight.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/rgblight.h) for the full list, but the most commonly used functions include:
|Function |Description |
|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|`rgblight_enable()` |Turn LEDs on, based on their previous state |
|`rgblight_enable_noeeprom()` |Turn LEDs on, based on their previous state (not written to EEPROM) |
|`rgblight_disable()` |Turn LEDs off |
|`rgblight_disable_noeeprom()` |Turn LEDs off (not written to EEPROM) |
|`rgblight_mode(x)` |Set the mode, if RGB animations are enabled |
|`rgblight_mode_noeeprom(x)` |Set the mode, if RGB animations are enabled (not written to EEPROM) |
|`rgblight_setrgb(r, g, b)` |Set all LEDs to the given RGB value where `r`/`g`/`b` are between 0 and 255 (not written to EEPROM) |
|`rgblight_setrgb_at(r, g, b, led)` |Set a single LED to the given RGB value, where `r`/`g`/`b` are between 0 and 255 and `led` is between 0 and `RGBLED_NUM` (not written to EEPROM) |
|`rgblight_sethsv(h, s, v)` |Set all LEDs to the given HSV value where `h` is between 0 and 360 and `s`/`v` are between 0 and 255 |
|`rgblight_sethsv_noeeprom(h, s, v)`|Set all LEDs to the given HSV value where `h` is between 0 and 360 and `s`/`v` are between 0 and 255 (not written to EEPROM) |
|`rgblight_sethsv_at(h, s, v, led)` |Set a single LED to the given HSV value, where `h` is between 0 and 360, `s`/`v` are between 0 and 255, and `led` is between 0 and `RGBLED_NUM` (not written to EEPROM)|
Additionally, [`rgblight_list.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/rgblight_list.h) defines several predefined shortcuts for various colors. Feel free to add to this list!
## Hardware Modification
|Function |Description |
|--------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
|`rgblight_enable()` |Turn LEDs on, based on their previous state |
|`rgblight_enable_noeeprom()` |Turn LEDs on, based on their previous state (not written to EEPROM) |
|`rgblight_disable()` |Turn LEDs off |
|`rgblight_disable_noeeprom()` |Turn LEDs off (not written to EEPROM) |
|`rgblight_mode(x)` |Set the mode, if RGB animations are enabled |
|`rgblight_mode_noeeprom(x)` |Set the mode, if RGB animations are enabled (not written to EEPROM) |
|`rgblight_setrgb(r, g, b)` |Set all LEDs to the given RGB value where `r`/`g`/`b` are between 0 and 255 (not written to EEPROM) |
|`rgblight_setrgb_at(r, g, b, led)` |Set a single LED to the given RGB value, where `r`/`g`/`b` are between 0 and 255 and `led` is between 0 and `RGBLED_NUM` (not written to EEPROM) |
|`rgblight_setrgb_range(r, g, b, start, end)`|Set a continuous range of LEDs to the given RGB value, where `r`/`g`/`b` are between 0 and 255 and `start`(included) and `stop`(excluded) are between 0 and `RGBLED_NUM` (not written to EEPROM)|
|`rgblight_setrgb_master(r, g, b)` |Set the LEDs on the master side to the given RGB value, where `r`/`g`/`b` are between 0 and 255 (not written to EEPROM) |
|`rgblight_setrgb_slave(r, g, b)` |Set the LEDs on the slave side to the given RGB value, where `r`/`g`/`b` are between 0 and 255 (not written to EEPROM) |
|`rgblight_sethsv(h, s, v)` |Set all LEDs to the given HSV value where `h` is between 0 and 360 and `s`/`v` are between 0 and 255 |
|`rgblight_sethsv_noeeprom(h, s, v)` |Set all LEDs to the given HSV value where `h` is between 0 and 360 and `s`/`v` are between 0 and 255 (not written to EEPROM) |
|`rgblight_sethsv_at(h, s, v, led)` |Set a single LED to the given HSV value, where `h` is between 0 and 360, `s`/`v` are between 0 and 255, and `led` is between 0 and `RGBLED_NUM` (not written to EEPROM)|
|`rgblight_sethsv_range(h, s, v, start, end)`|Set a continuous range of LEDs to the given HSV value, where `h` is between 0 and 360, `s`/`v` are between 0 and 255, and `start`(included) and `stop`(excluded) are between 0 and `RGBLED_NUM` (not written to EEPROM)|
|`rgblight_sethsv_master(h, s, v)` |Set the LEDs on the master side to the given HSV value, where `h` is between 0 and 360, `s`/`v` are between 0 and 255 (not written to EEPROM) |
|`rgblight_sethsv_slave(h, s, v)` |Set the LEDs on the slave side to the given HSV value, where `h` is between 0 and 360, `s`/`v` are between 0 and 255 (not written to EEPROM) |
|`rgblight_toggle()` |Toggle all LEDs between on and off |
|`rgblight_toggle_noeeprom()` |Toggle all LEDs between on and off (not written to EEPROM) |
|`rgblight_step()` |Change the mode to the next RGB animation in the list of enabled RGB animations |
|`rgblight_step_noeeprom()` |Change the mode to the next RGB animation in the list of enabled RGB animations (not written to EEPROM) |
|`rgblight_step_reverse()` |Change the mode to the previous RGB animation in the list of enabled RGB animations |
|`rgblight_step_reverse_noeeprom()` |Change the mode to the previous RGB animation in the list of enabled RGB animations (not written to EEPROM) |
|`rgblight_increase_hue()` |Increase the hue for all LEDs. This wraps around at maximum hue |
|`rgblight_increase_hue_noeeprom()` |Increase the hue for all LEDs. This wraps around at maximum hue (not written to EEPROM) |
|`rgblight_decrease_hue()` |Decrease the hue for all LEDs. This wraps around at minimum hue |
|`rgblight_decrease_hue_noeeprom()` |Decrease the hue for all LEDs. This wraps around at minimum hue (not written to EEPROM) |
|`rgblight_increase_sat()` |Increase the saturation for all LEDs. This wraps around at maximum saturation |
|`rgblight_increase_sat_noeeprom()` |Increase the saturation for all LEDs. This wraps around at maximum saturation (not written to EEPROM) |
|`rgblight_decrease_sat()` |Decrease the saturation for all LEDs. This wraps around at minimum saturation |
|`rgblight_decrease_sat_noeeprom()` |Decrease the saturation for all LEDs. This wraps around at minimum saturation (not written to EEPROM) |
|`rgblight_increase_val()` |Increase the value for all LEDs. This wraps around at maximum value |
|`rgblight_increase_val_noeeprom()` |Increase the value for all LEDs. This wraps around at maximum value (not written to EEPROM) |
|`rgblight_decrease_val()` |Decrease the value for all LEDs. This wraps around at minimum value |
|`rgblight_decrease_val_noeeprom()` |Decrease the value for all LEDs. This wraps around at minimum value (not written to EEPROM) |
|`rgblight_set_clipping_range(pos, num)` |Set clipping Range |
## Colors
These are shorthands to popular colors. The `RGB` ones can be passed to the `setrgb` functions, while the `HSV` ones to the `sethsv` functions.
|RGB |HSV |
|-------------------|-------------------|
|`RGB_WHITE` |`HSV_WHITE` |
|`RGB_RED` |`HSV_RED` |
|`RGB_CORAL` |`HSV_CORAL` |
|`RGB_ORANGE` |`HSV_ORANGE` |
|`RGB_GOLDENROD` |`HSV_GOLDENROD` |
|`RGB_GOLD` |`HSV_GOLD` |
|`RGB_YELLOW` |`HSV_YELLOW` |
|`RGB_CHARTREUSE` |`HSV_CHARTREUSE` |
|`RGB_GREEN` |`HSV_GREEN` |
|`RGB_SPRINGGREEN` |`HSV_SPRINGGREEN` |
|`RGB_TURQUOISE` |`HSV_TURQUOISE` |
|`RGB_TEAL` |`HSV_TEAL` |
|`RGB_CYAN` |`HSV_CYAN` |
|`RGB_AZURE` |`HSV_AZURE` |
|`RGB_BLUE` |`HSV_BLUE` |
|`RGB_PURPLE` |`HSV_PURPLE` |
|`RGB_MAGENTA` |`HSV_MAGENTA` |
|`RGB_PINK` |`HSV_PINK` |
```c
rgblight_setrgb(RGB_ORANGE);
rgblight_sethsv_noeeprom(HSV_GREEN);
rgblight_setrgb_at(RGB_GOLD, 3);
rgblight_sethsv_range(HSV_WHITE, 0, 6);
```
These are defined in [`rgblight_list.h`](https://github.com/qmk/qmk_firmware/blob/master/quantum/rgblight_list.h). Feel free to add to this list!
## Changing the order of the LEDs
If you want to make the logical order of LEDs different from the electrical connection order, you can do this by defining the `RGBLIGHT_LED_MAP` macro in your `config.h`.
Normally, the contents of the LED buffer are output to the LEDs in the same order.
<img src="https://user-images.githubusercontent.com/2170248/55743718-01866c80-5a6e-11e9-8134-25419928327a.JPG" alt="simple dicrect" width="50%"/>
By defining `RGBLIGHT_LED_MAP` as in the example below, you can specify the LED with addressing in reverse order of the electrical connection order.
```c
// config.h
#define RGBLED_NUM 4
#define RGBLIGHT_LED_MAP { 3, 2, 1, 0 }
```
<img src="https://user-images.githubusercontent.com/2170248/55743725-08ad7a80-5a6e-11e9-83ed-126a2b0209fc.JPG" alt="simple mapped" width="50%"/>
For keyboards that use the RGB LEDs as a backlight for each key, you can also define it as in the example below.
```c
// config.h
#define RGBLED_NUM 30
/* RGB LED Conversion macro from physical array to electric array */
#define LED_LAYOUT( \
L00, L01, L02, L03, L04, L05, \
L10, L11, L12, L13, L14, L15, \
L20, L21, L22, L23, L24, L25, \
L30, L31, L32, L33, L34, L35, \
L40, L41, L42, L43, L44, L45 ) \
{ \
L05, L04, L03, L02, L01, L00, \
L10, L11, L12, L13, L14, L15, \
L25, L24, L23, L22, L21, L20, \
L30, L31, L32, L33, L34, L35, \
L46, L45, L44, L43, L42, L41 \
}
/* RGB LED logical order map */
/* Top->Bottom, Right->Left */
#define RGBLIGHT_LED_MAP LED_LAYOUT( \
25, 20, 15, 10, 5, 0, \
26, 21, 16, 11, 6, 1, \
27, 22, 17, 12, 7, 2, \
28, 23, 18, 13, 8, 3, \
29, 24, 19, 14, 9, 4 )
```
## Clipping Range
Using the `rgblight_set_clipping_range()` function, you can prepare more buffers than the actual number of LEDs, and output some of the buffers to the LEDs. This is useful if you want the split keyboard to treat left and right LEDs as logically contiguous.
You can set the Clipping Range by executing the following code.
```c
// some soruce
rgblight_set_clipping_range(3, 4);
```
<img src="https://user-images.githubusercontent.com/2170248/55743785-2bd82a00-5a6e-11e9-9d4b-1b4ffaf4932b.JPG" alt="clip direct" width="70%"/>
In addition to setting the Clipping Range, you can use `RGBLIGHT_LED_MAP` together.
```c
// config.h
#define RGBLED_NUM 8
#define RGBLIGHT_LED_MAP { 7, 6, 5, 4, 3, 2, 1, 0 }
// some soruce
rgblight_set_clipping_range(3, 4);
```
<img src="https://user-images.githubusercontent.com/2170248/55743747-119e4c00-5a6e-11e9-91e5-013203ffae8a.JPG" alt="clip mapped" width="70%"/>
If your keyboard lacks onboard underglow LEDs, you may often be able to solder on an RGB LED strip yourself. You will need to find an unused pin to wire to the data pin of your LED strip. Some keyboards may break out unused pins from the MCU to make soldering easier. The other two pins, VCC and GND, must also be connected to the appropriate power pins.

+ 59
- 0
docs/feature_space_cadet.md View File

@ -0,0 +1,59 @@
# Space Cadet: The Future, Built In
Steve Losh described the [Space Cadet Shift](http://stevelosh.com/blog/2012/10/a-modern-space-cadet/) quite well. Essentially, when you tap Left Shift on its own, you get an opening parenthesis; tap Right Shift on its own and you get the closing one. When held, the Shift keys function as normal. Yes, it's as cool as it sounds, and now even cooler supporting Control and Alt as well!
## Usage
Firstly, in your keymap, do one of the following:
- Replace the Left Shift key with `KC_LSPO` (Left Shift, Parenthesis Open), and Right Shift with `KC_RSPC` (Right Shift, Parenthesis Close).
- Replace the Left Control key with `KC_LCPO` (Left Control, Parenthesis Open), and Right Control with `KC_RCPC` (Right Control, Parenthesis Close).
- Replace the Left Alt key with `KC_LAPO` (Left Alt, Parenthesis Open), and Right Alt with `KC_RAPC` (Right Alt, Parenthesis Close).
- Replace any Shift key in your keymap with `KC_SFTENT` (Right Shift, Enter).
## Keycodes
|Keycode |Description |
|-----------|-------------------------------------------|
|`KC_LSPO` |Left Shift when held, `(` when tapped |
|`KC_RSPC` |Right Shift when held, `)` when tapped |
|`KC_LCPO` |Left Control when held, `(` when tapped |
|`KC_RCPC` |Right Control when held, `)` when tapped |
|`KC_LAPO` |Left Alt when held, `(` when tapped |
|`KC_RAPC` |Right Alt when held, `)` when tapped |
|`KC_SFTENT`|Right Shift when held, `Enter` when tapped |
## Caveats
Space Cadet's functionality can conflict with the default Command functionality when both Shift keys are held at the same time. See the [Command feature](feature_command.md) for info on how to change it, or make sure that Command is disabled in your `rules.mk` with:
```make
COMMAND_ENABLE = no
```
## Configuration
By default Space Cadet assumes a US ANSI layout, but if your layout uses different keys for parentheses, you can redefine them in your `config.h`. In addition, you can redefine the modifier to send on tap, or even send no modifier at all. The new configuration defines bundle all options up into a single define of 3 key codes in this order: the `Modifier` when held or when used with other keys, the `Tap Modifer` sent when tapped (no modifier if `KC_TRNS`), finally the `Keycode` sent when tapped. Now keep in mind, mods from other keys will still apply to the `Keycode` if say `KC_RSFT` is held while tapping `KC_LSPO` key with `KC_TRNS` as the `Tap Modifer`.
|Define |Default |Description |
|----------------|-------------------------------|---------------------------------------------------------------------------------|
|`LSPO_KEYS` |`KC_LSFT, LSPO_MOD, LSPO_KEY` |Send `KC_LSFT` when held, the mod and key defined by `LSPO_MOD` and `LSPO_KEY`. |
|`RSPC_KEYS` |`KC_RSFT, RSPC_MOD, RSPC_KEY` |Send `KC_RSFT` when held, the mod and key defined by `RSPC_MOD` and `RSPC_KEY`. |
|`LCPO_KEYS` |`KC_LCTL, KC_LCTL, KC_9` |Send `KC_LCTL` when held, the mod `KC_LCTL` with the key `KC_9` when tapped. |
|`RCPO_KEYS` |`KC_RCTL, KC_RCTL, KC_0` |Send `KC_RCTL` when held, the mod `KC_RCTL` with the key `KC_0` when tapped. |
|`LAPO_KEYS` |`KC_LALT, KC_LALT, KC_9` |Send `KC_LALT` when held, the mod `KC_LALT` with the key `KC_9` when tapped. |
|`RAPO_KEYS` |`KC_RALT, KC_RALT, KC_0` |Send `KC_RALT` when held, the mod `KC_RALT` with the key `KC_0` when tapped. |
|`SFTENT_KEYS` |`KC_RSFT, KC_TRNS, SFTENT_KEY` |Send `KC_RSFT` when held, no mod with the key `SFTENT_KEY` when tapped. |
## Obsolete Configuration
These defines are used in the above defines internally to support backwards compatibility, so you may continue to use them, however the above defines open up a larger range of flexibility than before. As an example, say you want to not send any modifier when you tap just `KC_LSPO`, with the old defines you had an all or nothing choice of using the `DISABLE_SPACE_CADET_MODIFIER` define. Now you can define that key as: `#define KC_LSPO_KEYS KC_LSFT, KC_TRNS, KC_9`. This tells the system to set Left Shift if held or used with other keys, then on tap send no modifier (transparent) with the `KC_9`
|Define |Default |Description |
|------------------------------|-------------|------------------------------------------------------------------|
|`LSPO_KEY` |`KC_9` |The keycode to send when Left Shift is tapped |
|`RSPC_KEY` |`KC_0` |The keycode to send when Right Shift is tapped |
|`LSPO_MOD` |`KC_LSFT` |The modifier to apply to `LSPO_KEY` |
|`RSPC_MOD` |`KC_RSFT` |The modifier to apply to `RSPC_KEY` |
|`SFTENT_KEY` |`KC_ENT` |The keycode to send when the Shift key is tapped |
|`DISABLE_SPACE_CADET_MODIFIER`|*Not defined*|If defined, prevent the Space Cadet from applying a modifier |

+ 0
- 33
docs/feature_space_cadet_shift.md View File

@ -1,33 +0,0 @@
# Space Cadet Shift: The Future, Built In
Steve Losh described the [Space Cadet Shift](http://stevelosh.com/blog/2012/10/a-modern-space-cadet/) quite well. Essentially, when you tap Left Shift on its own, you get an opening parenthesis; tap Right Shift on its own and you get the closing one. When held, the Shift keys function as normal. Yes, it's as cool as it sounds.
## Usage
Replace the Left Shift key in your keymap with `KC_LSPO` (Left Shift, Parenthesis Open), and Right Shift with `KC_RSPC` (Right Shift, Parenthesis Close).
## Keycodes
|Keycode |Description |
|---------|--------------------------------------|
|`KC_LSPO`|Left Shift when held, `(` when tapped |
|`KC_RSPC`|Right Shift when held, `)` when tapped|
## Caveats
Space Cadet's functionality can conflict with the default Command functionality when both Shift keys are held at the same time. Make sure that Command is disabled in your `rules.mk` with:
```make
COMMAND_ENABLE = no
```
## Configuration
By default Space Cadet assumes a US ANSI layout, but if your layout uses different keys for parentheses, you can redefine them in your `config.h`.
You can also disable the rollover, allowing you to use the opposite Shift key to cancel the Space Cadet state in the event of an erroneous press, instead of emitting a pair of parentheses when the keys are released.
|Define |Default |Description |
|------------------------------|-------------|------------------------------------------------------------|
|`LSPO_KEY` |`KC_9` |The keycode to send when Left Shift is tapped |
|`RSPC_KEY` |`KC_0` |The keycode to send when Right Shift is tapped |
|`DISABLE_SPACE_CADET_ROLLOVER`|*Not defined*|If defined, use the opposite Shift key to cancel Space Cadet|

+ 0
- 31
docs/feature_space_cadet_shift_enter.md View File

@ -1,31 +0,0 @@
# Space Cadet Shift Enter
Based on the [Space Cadet Shift](feature_space_cadet_shift.md) feature. Tap the Shift key on its own, and it behaves like Enter. When held, the Shift functions as normal.
## Usage
Replace any Shift key in your keymap with `KC_SFTENT` (Shift, Enter), and you're done.
## Keycodes
|Keycode |Description |
|-----------|----------------------------------------|
|`KC_SFTENT`|Right Shift when held, Enter when tapped|
## Caveats
As with Space Cadet Shift, this feature may conflict with Command, so it should be disabled in your `rules.mk` with:
```make
COMMAND_ENABLE = no
```
This feature also uses the same timers as Space Cadet Shift, so using them in tandem may produce strange results.
## Configuration
By default Space Cadet assumes a US ANSI layout, but if you'd like to use a different key for Enter, you can redefine it in your `config.h`:
|Define |Default |Description |
|------------|--------|------------------------------------------------|
|`SFTENT_KEY`|`KC_ENT`|The keycode to send when the Shift key is tapped|

+ 90
- 29
docs/feature_tap_dance.md View File

@ -185,29 +185,11 @@ Below is a specific example:
## Setup
You will need a few things that can be used for 'Quad Function Tap-Dance'. The suggested setup is to create a user directory for yourself. This directory will contain rules.mk `<your_name>.c` and `<your_name>.h`. This directory should be called `<your_name>`, and located in the top level `users` directory. There should already be a few examples to look at there.
You will need a few things that can be used for 'Quad Function Tap-Dance'.
### In `/qmk_firmware/users/<your_name>/rules.mk`
You'll need to add these to the top of your `keymap.c` file, before your keymap.
Put the following:
```c
TAP_DANCE_ENABLE = yes
SRC += your_name.c
```
Pretty simple. It is a nice way to keep some rules common on all your keymaps.
### In `/qmk_firmware/users/<your_name>/<your_name>.h`
You will need a few things in this file:
```c
#pragma once
#include "quantum.h"
#include "process_keycode/process_tap_dance.h"
typedef struct {
bool is_press_action;
int state;
@ -234,18 +216,12 @@ int cur_dance (qk_tap_dance_state_t *state);
//for the x tap dance. Put it here so it can be used in any keymap
void x_finished (qk_tap_dance_state_t *state, void *user_data);
void x_reset (qk_tap_dance_state_t *state, void *user_data);
```
### In `/qmk_firmware/users/<your_name>/<your_name>.c`
```
And then in your user's `.c` file you implement the functions above:
Now, at the bottom of your `keymap.c` file, you'll need to add the following:
```c
#include "<your_name>.h"
#include "quantum.h"
#include "action.h"
#include "process_keycode/process_tap_dance.h"
/* Return an integer that corresponds to what kind of tap dance should be executed.
*
* How to figure out tap dance state: interrupted and pressed.
@ -335,4 +311,89 @@ qk_tap_dance_action_t tap_dance_actions[] = {
};
```
And then simply use `TD(X_CTL)` anywhere in your keymap after including `<your_name>.h`.
And then simply use `TD(X_CTL)` anywhere in your keymap.
If you want to implement this in your userspace, then you may want to check out how [DanielGGordon](https://github.com/qmk/qmk_firmware/tree/master/users/gordon) has implemented this in their userspace.
### Example 5: Using tap dance for advanced mod-tap and layer-tap keys
Tap dance can be used to emulate `MT()` and `LT()` behavior when the tapped code is not a basic keycode. This is useful to send tapped keycodes that normally require `Shift`, such as parentheses or curly braces—or other modified keycodes, such as `Control + X`.
Below your layers and custom keycodes, add the following:
```c
// tapdance keycodes
enum td_keycodes {
ALT_LP // Our example key: `LALT` when held, `(` when tapped. Add additional keycodes for each tapdance.
};
// define a type containing as many tapdance states as you need
typedef enum {
SINGLE_TAP,
SINGLE_HOLD,
DOUBLE_SINGLE_TAP
} td_state_t;
// create a global instance of the tapdance state type
static td_state_t td_state;
// declare your tapdance functions:
// function to determine the current tapdance state
int cur_dance (qk_tap_dance_state_t *state);
// `finished` and `reset` functions for each tapdance keycode
void altlp_finished (qk_tap_dance_state_t *state, void *user_data);
void altlp_reset (qk_tap_dance_state_t *state, void *user_data);
```
Below your `LAYOUT`, define each of the tapdance functions:
```c
// determine the tapdance state to return
int cur_dance (qk_tap_dance_state_t *state) {
if (state->count == 1) {
if (state->interrupted || !state->pressed) { return SINGLE_TAP; }
else { return SINGLE_HOLD; }
}
if (state->count == 2) { return DOUBLE_SINGLE_TAP; }
else { return 3; } // any number higher than the maximum state value you return above
}
// handle the possible states for each tapdance keycode you define:
void altlp_finished (qk_tap_dance_state_t *state, void *user_data) {
td_state = cur_dance(state);
switch (td_state) {
case SINGLE_TAP:
register_code16(KC_LPRN);
break;
case SINGLE_HOLD:
register_mods(MOD_BIT(KC_LALT)); // for a layer-tap key, use `layer_on(_MY_LAYER)` here
break;
case DOUBLE_SINGLE_TAP: // allow nesting of 2 parens `((` within tapping term
tap_code16(KC_LPRN);
register_code16(KC_LPRN);
}
}
void altlp_reset (qk_tap_dance_state_t *state, void *user_data) {
switch (td_state) {
case SINGLE_TAP:
unregister_code16(KC_LPRN);
break;
case SINGLE_HOLD:
unregister_mods(MOD_BIT(KC_LALT)); // for a layer-tap key, use `layer_off(_MY_LAYER)` here
break;
case DOUBLE_SINGLE_TAP:
unregister_code16(KC_LPRN);
}
}
// define `ACTION_TAP_DANCE_FN_ADVANCED()` for each tapdance keycode, passing in `finished` and `reset` functions
qk_tap_dance_action_t tap_dance_actions[] = {
[ALT_LP] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, altlp_finished, altlp_reset)
};
```
Wrap each tapdance keycode in `TD()` when including it in your keymap, e.g. `TD(ALT_LP)`.

+ 135
- 54
docs/feature_unicode.md View File

@ -1,94 +1,175 @@
# Unicode Support
There are three Unicode keymap definition method available in QMK:
There are three Unicode keymap definition methods available in QMK:
## UNICODE_ENABLE
## `UNICODE_ENABLE`
Supports Unicode input up to 0xFFFF. The keycode function is `UC(n)` in keymap file, where *n* is a 4 digit hexadecimal.
Supports Unicode up to `0x7FFF`. This covers characters for most modern languages, as well as symbols, but it doesn't cover emoji. The keycode function is `UC(c)` in the keymap, where _c_ is the code point's number (preferably hexadecimal, up to 4 digits long). For example: `UC(0x45B)`, `UC(0x30C4)`.
## UNICODEMAP_ENABLE
## `UNICODEMAP_ENABLE`
Supports Unicode up to 0xFFFFFFFF. You need to maintain a separate mapping table `const uint32_t PROGMEM unicode_map[] = {...}` in your keymap file. The keycode function is `X(n)` where *n* is the array index of the mapping table.
Supports Unicode up to `0x10FFFF` (all possible code points). You need to maintain a separate mapping table `const uint32_t PROGMEM unicode_map[] = {...}` in your keymap file. The keycode function is `X(i)`, where _i_ is an array index into the mapping table. The table may contain at most 16384 entries.
And you may want to have an enum to make reference easier. So you'd want to add something like this to your keymap:
You may want to have an enum to make referencing easier. So, you could add something like this to your keymap file:
```c
enum unicode_name {
BANG, // ‽
IRONY, // ⸮
SNEK // snke 🐍
enum unicode_names {
BANG,
IRONY,
SNEK,
};
const uint32_t PROGMEM unicode_map[] = {
[BANG] = 0x0203D, // ‽
[IRONY] = 0x02E2E, // ⸮
[SNEK] = 0x1F40D // snke 🐍
}:
[BANG] = 0x203D, // ‽
[IRONY] = 0x2E2E, // ⸮
[SNEK] = 0x1F40D, // 🐍
};
```
Make sure that the order for both matches.
Then you can use `X(BANG)`, `X(SNEK)` etc. in your keymap.
### Lower and Upper Case
Characters often come in lower and upper case pairs, for example: å, Å. To make inputting these characters easier, you can use `XP(i, j)` in your keymap, where _i_ and _j_ are the mapping table indices of the lower and upper case character, respectively. If you're holding down Shift or have Caps Lock turned on when you press the key, the second (upper case) character will be inserted; otherwise, the first (lower case) version will appear.
## UCIS_ENABLE
This is most useful when creating a keymap for an international layout with special characters. Instead of having to put the lower and upper case versions of a character on separate keys, you can have them both on the same key by using `XP`. This blends Unicode keys in with regular alphas.
Supports Unicode up to 0xFFFFFFFF. As with `UNICODE_MAP`, you may want to maintain a mapping table in your keymap file. However, there is no keycodes for this feature, you will have to add a keycode or function to call `qk_ucis_start()`. Once you've run that, you can just type the text for your unicode, and then hit space or enter to complete it, or ESC to cancel it. And if it matches an entry in your table, it will automatically "backspace" the trigger word (from your table) and then will input the unicode sequence.
Due to keycode size constraints, _i_ and _j_ can each only refer to one of the first 128 characters in your `unicode_map`. In other words, 0 ≤ _i_ ≤ 127 and 0 ≤ _j_ ≤ 127. This is enough for most use cases, but if you'd like to customize the index calculation, you can override the [`unicodemap_index()`](https://github.com/qmk/qmk_firmware/blob/71f640d47ee12c862c798e1f56392853c7b1c1a8/quantum/process_keycode/process_unicodemap.c#L40) function. This also allows you to, say, check Ctrl instead of Shift/Caps.
For instance, you would need to have a table like this in your keymap:
## `UCIS_ENABLE`
Supports Unicode up to `0x10FFFF` (all possible code points). As with `UNICODEMAP`, you need to maintain a mapping table in your keymap file. However, there are no built-in keycodes for this feature — you have to add a keycode or function that calls `qk_ucis_start()`. Once this function has been called, you can type the corresponding mnemonic for your character, then hit Space or Enter to complete it, or Esc to cancel. If the mnemonic matches an entry in your table, the typed text will automatically be erased and the corresponding Unicode character inserted.
For instance, you could define a table like this in your keymap file:
```c
const qk_ucis_symbol_t ucis_symbol_table[] = UCIS_TABLE
(
UCIS_SYM("poop", 0x1f4a9),
UCIS_SYM("rofl", 0x1f923),
UCIS_SYM("kiss", 0x1f619)
const qk_ucis_symbol_t ucis_symbol_table[] = UCIS_TABLE(
UCIS_SYM("poop", 0x1F4A9), // 💩
UCIS_SYM("rofl", 0x1F923), // 🤣
UCIS_SYM("kiss", 0x1F619) // 😙
);
```
You run the function, and then type "rofl" and hit enter, it should backspace remove "rofl" and input the `0x1f923` unicode.
To use it, call `qk_ucis_start()`, then type "rofl" and hit Enter. QMK should erase the "rofl" text and insert the laughing emoji.
### Customization
There are several functions that you can add to your keymap to customize the functionality of this feature.
There are several functions that you can define in your keymap to customize the functionality of this feature.
* `void qk_ucis_start_user(void)` – This runs when you call the "start" function, and can be used to provide feedback. By default, it types out a keyboard emoji.
* `void qk_ucis_success(uint8_t symbol_index)` – This runs when the input has matched something and has completed. By default, it doesn't do anything.
* `void qk_ucis_symbol_fallback (void)` – This runs when the input doesn't match anything. By default, it falls back to trying that input as a Unicode code.
You can find the default implementations of these functions in [`process_ucis.c`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_ucis.c).
## Input Modes
Unicode input in QMK works by inputting a sequence of characters to the OS, sort of like a macro. Unfortunately, the way this is done differs for each platform. Specifically, each platform requires a different combination of keys to trigger Unicode input. Therefore, a corresponding input mode has to be set in QMK.
The following input modes are available:
* **`UC_OSX`**: macOS built-in Unicode hex input. Supports code points up to `0xFFFF` (`0x10FFFF` with `UNICODEMAP`).
To enable, go to _System Preferences > Keyboard > Input Sources_, add _Unicode Hex Input_ to the list (it's under _Other_), then activate it from the input dropdown in the Menu Bar.
By default, this mode uses the left Option key (`KC_LALT`) for Unicode input, but this can be changed by defining [`UNICODE_KEY_OSX`](#input-key-configuration) with another keycode.
!> Using the _Unicode Hex Input_ input source may disable some Option based shortcuts, such as Option + Left Arrow and Option + Right Arrow.
* **`UC_LNX`**: Linux built-in IBus Unicode input. Supports code points up to `0x10FFFF` (all possible code points).
Enabled by default and works almost anywhere on IBus-enabled distros. Without IBus, this mode works under GTK apps, but rarely anywhere else.
By default, this mode uses Ctrl+Shift+U (`LCTL(LSFT(KC_U))`) to start Unicode input, but this can be changed by defining [`UNICODE_KEY_LNX`](#input-key-configuration) with another keycode. This might be required for IBus versions ≥1.5.15, where Ctrl+Shift+U behavior is consolidated into Ctrl+Shift+E.
* **`UC_WIN`**: _(not recommended)_ Windows built-in hex numpad Unicode input. Supports code points up to `0xFFFF`.
To enable, create a registry key under `HKEY_CURRENT_USER\Control Panel\Input Method\EnableHexNumpad` of type `REG_SZ` called `EnableHexNumpad` and set its value to `1`. This can be done from the Command Prompt by running `reg add "HKCU\Control Panel\Input Method" -v EnableHexNumpad -t REG_SZ -d 1` with administrator privileges. Reboot afterwards.
This mode is not recommended because of reliability and compatibility issues; use the `UC_WINC` mode instead.
* **`UC_BSD`**: _(non implemented)_ Unicode input under BSD. Not implemented at this time. If you're a BSD user and want to help add support for it, please [open an issue on GitHub](https://github.com/qmk/qmk_firmware/issues).
* **`UC_WINC`**: Windows Unicode input using [WinCompose](https://github.com/samhocevar/wincompose). As of v0.9.0, supports code points up to `0x10FFFF` (all possible code points).
To enable, install the [latest release](https://github.com/samhocevar/wincompose/releases/latest). Once installed, WinCompose will automatically run on startup. Works reliably under all version of Windows supported by the app.
By default, this mode uses right Alt (`KC_RALT`) as the Compose key, but this can be changed in the WinCompose settings and by defining [`UNICODE_KEY_WINC`](#input-key-configuration) with another keycode.
### Switching Input Modes
There are two ways to set the input mode for Unicode: by keycode or by function. Keep in mind that both methods write to persistent storage (EEPROM), and are loaded each time the keyboard starts. So once you've set it the first time, you don't need to set it again unless you want to change it, or you've reset the EEPROM settings.
* `void qk_ucis_start_user(void)` - This runs when you run the "start" function, and can be used to provide feedback. By default, it types out a keyboard emoji.
* `void qk_ucis_success(uint8_t symbol_index)` - This runs when the unicode input has matched something, and has completed. Default doesn't do anything.
* `void qk_ucis_symbol_fallback (void)` - This runs if the input text doesn't match anything. The default function falls back to trying that input as a unicode code.
You can switch the input mode at any time by using one of the following keycodes. The easiest way is to add the ones you use to your keymap.
The default code for these are:
|Keycode |Alias |Input Mode |Description |
|----------------------|---------|------------|--------------------------------------------------------------|
|`UNICODE_MODE_FORWARD`|`UC_MOD` |Next in list|[Cycle](#input-mode-cycling) through selected modes |
|`UNICODE_MODE_REVERSE`|`UC_RMOD`|Prev in list|[Cycle](#input-mode-cycling) through selected modes in reverse|
|`UNICODE_MODE_OSX` |`UC_M_OS`|`UC_OSX` |Switch to macOS input |
|`UNICODE_MODE_LNX` |`UC_M_LN`|`UC_LNX` |Switch to Linux input |
|`UNICODE_MODE_WIN` |`UC_M_WI`|`UC_WIN` |Switch to Windows input |
|`UNICODE_MODE_BSD` |`UC_M_BS`|`UC_BSD` |Switch to BSD input (not implemented) |
|`UNICODE_MODE_WINC` |`UC_M_WC`|`UC_WINC` |Switch to Windows input using WinCompose |
You can also switch the input mode by calling `set_unicode_input_mode(x)` in your code, where _x_ is one of the above input mode constants (e.g. `UC_LNX`). Since the function only needs to be called once, it's recommended that you do it in `eeconfig_init_user()` (or a similar function). For example:
```c
void qk_ucis_start_user(void) { // outputs keyboard emoji
unicode_input_start();
register_hex(0x2328);
unicode_input_finish();
void eeconfig_init_user(void) {
set_unicode_input_mode(UC_LNX);
}
```
void qk_ucis_success(uint8_t symbol_index) {
}
### Audio Feedback
void qk_ucis_symbol_fallback (void) { // falls back to manual unicode entry
for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) {
uint8_t code = qk_ucis_state.codes[i];
register_code(code);
unregister_code(code);
wait_ms(UNICODE_TYPE_DELAY);
}
}
If you have the [Audio feature](feature_audio.md) enabled on the board, you can set melodies to be played when you press the above keys. That way you can have some audio feedback when switching input modes.
For instance, you can add these definitions to your `config.h` file:
```c
#define UNICODE_SONG_OSX COIN_SOUND
#define UNICODE_SONG_LNX UNICODE_LINUX
#define UNICODE_SONG_BSD MARIO_GAMEOVER
#define UNICODE_SONG_WIN UNICODE_WINDOWS
#define UNICODE_SONG_WINC UNICODE_WINDOWS
```
## Unicode Input methods
### Additional Customization
Because Unicode is a large and versatile feature, there are a number of options you can customize to make it work better on your system.
#### Start and Finish Input Functions
The functions for starting and finishing Unicode input on your platform can be overridden locally. Possible uses include customizing input mode behavior if you don't use the default keys, or adding extra visual/audio feedback to Unicode input.
* `void unicode_input_start(void)` – This sends the initial sequence that tells your platform to enter Unicode input mode. For example, it presses Ctrl+Shift+U on Linux and holds the Option key on macOS.
* `void unicode_input_finish(void)` – This is called to exit Unicode input mode, for example by pressing Space or releasing the Option key.
Unicode input in QMK works by inputting a sequence of characters to the OS,
sort of like macro. Unfortunately, each OS has different ideas on how Unicode is input.
You can find the default implementations of these functions in [`process_unicode_common.c`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_unicode_common.c).
This is the current list of Unicode input method in QMK:
#### Input Key Configuration
* __UC_OSX__: MacOS Unicode Hex Input support. Works only up to 0xFFFF. Disabled by default. To enable: go to System Preferences -> Keyboard -> Input Sources, and enable Unicode Hex.
* __UC_OSX_RALT__: Same as UC_OSX, but sends the Right Alt key for unicode input
* __UC_LNX__: Unicode input method under Linux. Works up to 0xFFFFF. Should work almost anywhere on ibus enabled distros. Without ibus, this works under GTK apps, but rarely anywhere else.
* __UC_WIN__: (not recommended) Windows built-in Unicode input. To enable: create registry key under `HKEY_CURRENT_USER\Control Panel\Input Method\EnableHexNumpad` of type `REG_SZ` called `EnableHexNumpad`, set its value to 1, and reboot. This method is not recommended because of reliability and compatibility issue, use WinCompose method below instead.
* __UC_WINC__: Windows Unicode input using WinCompose. Requires [WinCompose](https://github.com/samhocevar/wincompose). Works reliably under many (all?) variations of Windows.
You can customize the keys used to trigger Unicode input for macOS, Linux and WinCompose by adding corresponding defines to your `config.h`. The default values match the platforms' default settings, so you shouldn't need to change this unless Unicode input isn't working, or you want to use a different key (e.g. in order to free up left or right Alt).
|Define |Type |Default |Example |
|------------------|----------|------------------|-------------------------------------------|
|`UNICODE_KEY_OSX` |`uint8_t` |`KC_LALT` |`#define UNICODE_KEY_OSX KC_RALT` |
|`UNICODE_KEY_LNX` |`uint16_t`|`LCTL(LSFT(KC_U))`|`#define UNICODE_KEY_LNX LCTL(LSFT(KC_E))`|
|`UNICODE_KEY_WINC`|`uint8_t` |`KC_RALT` |`#define UNICODE_KEY_WINC KC_RGUI` |
#### Input Mode Cycling
You can choose which input modes are available for cycling through. By default, this is disabled. If you want to enable it, limiting it to just the modes you use makes sense. Note that the values in the list are comma-delimited.
```c
#define UNICODE_SELECTED_MODES UC_OSX, UC_LNX, UC_WIN, UC_WINC
```
You can cycle through the selected modes by using the `UC_MOD`/`UC_RMOD` keycodes, or by calling `cycle_unicode_input_mode(offset)` in your code (`offset` is how many modes to move forward by, so +1 corresponds to `UC_MOD`).
By default, when the keyboard boots, it will initialize the input mode to the last one you used. You can disable this and make it start with the first mode in the list every time by adding the following to your `config.h`:
```c
#define UNICODE_CYCLE_PERSIST false
```
At some point, you need to call `set_unicode_input_mode(x)` to set the correct unicode method. This sets the method that is used to send the unicode, and stores it in EEPROM, so you only need to call this once.
!> Using `UNICODE_SELECTED_MODES` means you don't have to initially set the input mode in `matrix_init_user()` (or a similar function); the Unicode system will do that for you on startup. This has the added benefit of avoiding unnecessary writes to EEPROM.
## `send_unicode_hex_string`
@ -123,7 +204,7 @@ AutoHotkey inserts the Text right of `Send, ` when this combination is pressed.
### US International
If you enable the US International layout on the system, it will use punctuation to accent the characters.
If you enable the US International layout on the system, it will use punctuation to accent the characters.
For instance, typing "`a" will result in à.


+ 39
- 15
docs/feature_userspace.md View File

@ -201,27 +201,51 @@ bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case KC_MAKE:
if (!record->event.pressed) {
SEND_STRING("make " QMK_KEYBOARD ":" QMK_KEYMAP
#if (defined(BOOTLOADER_DFU) || defined(BOOTLOADER_LUFA_DFU) || defined(BOOTLOADER_QMK_DFU))
":dfu "
#elif defined(BOOTLOADER_HALFKAY)
":teensy "
#elif defined(BOOTLOADER_CATERINA)
":avrdude "
#endif
SS_TAP(X_ENTER));
}
return false;
break;
case KC_MAKE: // Compiles the firmware, and adds the flash command based on keyboard bootloader
if (!record->event.pressed) {
uint8_t temp_mod = get_mods();
uint8_t temp_osm = get_oneshot_mods();
clear_mods(); clear_oneshot_mods();
SEND_STRING("make " QMK_KEYBOARD ":" QMK_KEYMAP);
#ifndef FLASH_BOOTLOADER
if ( (temp_mod | temp_osm) & MOD_MASK_SHIFT )
#endif
{ //
#if defined(__arm__) // only run for ARM boards
SEND_STRING(":dfu-util");
#elif defined(BOOTLOADER_DFU) // only run for DFU boards
SEND_STRING(":dfu");
#elif defined(BOOTLOADER_HALFKAY) // only run for teensy boards
SEND_STRING(":teensy");
#elif defined(BOOTLOADER_CATERINA) // only run for Pro Micros
SEND_STRING(":avrdude");
#endif // bootloader options
}
if ( (temp_mod | temp_osm) & MOD_MASK_CTRL) {
SEND_STRING(" -j8 --output-sync");
}
SEND_STRING(SS_TAP(X_ENTER));
set_mods(temp_mod);
}
break;
}
return process_record_keymap(keycode, record);
}
```
For boards that may not have a shift button (such as on a macro pad), we need a way to always include the bootloader option. To do that, add the following to the `rules.mk` in your userspace folder:
```make
ifeq ($(strip $(FLASH_BOOTLOADER)), yes)
OPT_DEFS += -DFLASH_BOOTLOADER
endif
```
This will add a new `KC_MAKE` keycode that can be used in any of your keymaps. And this keycode will output `make <keyboard>:<keymap>`, making frequent compiling easier. And this will work with any keyboard and any keymap as it will output the current boards info, so that you don't have to type this out every time.
Additionally, this should flash the newly compiled firmware automatically, using the correct utility, based on the bootloader settings (or default to just generating the HEX file). However, it should be noted that this may not work on all systems. AVRDUDE doesn't work on WSL, namely (and will dump the HEX in the ".build" folder instead).
Also, holding `shift` will add the appropriate flashing command (`:dfu`, `:teensy`, `:avrdude`, `:dfu-util`) for a majority of keyboards. Holding `control` will add some commands that will speed up compiling time by processing multiple files at once.
And for the boards that lack a shift key, or that you want to always attempt the flashing part, you can add `FLASH_BOOTLOADER = yes` to the `rules.mk` of that keymap.
?> This should flash the newly compiled firmware automatically, using the correct utility, based on the bootloader settings (or default to just generating the HEX file). However, it should be noted that this may not work on all systems. AVRDUDE doesn't work on WSL, namely. And this doesn't support BootloadHID or mdloader.

+ 30
- 0
docs/feature_velocikey.md View File

@ -0,0 +1,30 @@
# Velocikey
Velocikey is a feature that lets you control the speed of lighting effects (like the Rainbow Swirl effect) with the speed of your typing. The faster you type, the faster the lights will go!
## Usage
For Velocikey to take effect, there are two steps. First, when compiling your keyboard, you'll need to set `VELOCIKEY_ENABLE=yes` in `rules.mk`, e.g.:
```
BOOTMAGIC_ENABLE = no
MOUSEKEY_ENABLE = no
STENO_ENABLE = no
EXTRAKEY_ENABLE = yes
VELOCIKEY_ENABLE = yes
```
Then, while using your keyboard, you need to also turn it on with the VLK_TOG keycode, which toggles the feature on and off.
The following light effects will all be controlled by Velocikey when it is enabled:
- RGB Breathing
- RGB Rainbow Mood
- RGB Rainbow Swirl
- RGB Snake
- RGB Knight
Support for LED breathing effects is planned but not available yet.
As long as Velocikey is enabled, it will control the speed regardless of any other speed setting that your RGB lights are currently on.
## Configuration
Velocikey doesn't currently support any configuration via keyboard settings. If you want to adjust something like the speed increase or decay rate, you would need to edit `velocikey.c` and adjust the values there to achieve the kinds of speeds that you like.

+ 2
- 0
docs/features.md View File

@ -11,11 +11,13 @@ QMK has a staggering number of features for building your keyboard. It can take
* [Combos](feature_combo.md) - Custom actions for multiple key holds.
* [Command](feature_command.md) - Runtime version of bootmagic (Formerly known as "Magic").
* [Dynamic Macros](feature_dynamic_macros.md) - Record and playback macros from the keyboard itself.
* [Encoders](feature_encoders.md) - Rotary encoders!
* [Grave Escape](feature_grave_esc.md) - Lets you use a single key for Esc and Grave.
* [HD44780 LCD Display](feature_hd44780.md) - Support for LCD character displays using the HD44780 standard.
* [Key Lock](feature_key_lock.md) - Lock a key in the "down" state.
* [Layouts](feature_layouts.md) - Use one keymap with any keyboard that supports your layout.
* [Leader Key](feature_leader_key.md) - Tap the leader key followed by a sequence to trigger custom behavior.
* [LED Matrix](feature_led_matrix.md) - LED Matrix single color lights for per key lighting (Single Color, not RGB).
* [Macros](feature_macros.md) - Send multiple key presses when pressing only one physical key.
* [Mouse keys](feature_mouse_keys.md) - Control your mouse pointer from your keyboard.
* [One Shot Keys](feature_advanced_keycodes.md#one-shot-keys) - Sticky Keys, lets hit a key rather than holding it.


+ 20
- 1
docs/flashing.md View File

@ -49,9 +49,18 @@ To generate this bootloader, use the `bootloader` target, eg `make planck/rev4:d
To generate a production-ready .hex file (containing the application and the bootloader), use the `production` target, eg `make planck/rev4:default:production`.
### DFU commands
There are a number of DFU commands that you can use to flash firmware to a DFU device:
* `:dfu` - This is the normal option and waits until a DFU device is available, and then flashes the firmware. This will check every 5 seconds, to see if a DFU device has appeared.
* `:dfu-ee` - This flashes an `eep` file instead of the normal hex. This is uncommon.
* `:dfu-split-left` - This flashes the normal firmware, just like the default option (`:dfu`). However, this also flashes the "Left Side" EEPROM file for split keyboards. _This is ideal for Elite C based split keyboards._
* `:dfu-split-right` - This flashes the normal firmware, just like the default option (`:dfu`). However, this also flashes the "Right Side" EEPROM file for split keyboards. _This is ideal for Elite C based split keyboards._
## Caterina
Arduino boards and their clones use the [Caterina bootloader](https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/bootloaders/caterina) (any keyboard built with a Pro Micro, or clone), and uses the avr109 protocol to communicate through virtual serial. Bootloaders like [A-Star](https://www.pololu.com/docs/0J61/9) are based on Caterina.
Arduino boards and their clones use the [Caterina bootloader](https://github.com/arduino/ArduinoCore-avr/tree/master/bootloaders/caterina) (any keyboard built with a Pro Micro, or clone), and uses the avr109 protocol to communicate through virtual serial. Bootloaders like [A-Star](https://www.pololu.com/docs/0J61/9) are based on Caterina.
To ensure compatibility with the Caterina bootloader, make sure this block is present your `rules.mk`:
@ -84,6 +93,7 @@ or if you want to flash multiple boards, use the following command
When you're done flashing boards, you'll need to hit Ctrl + C or whatever the correct keystroke is for your operating system to break the loop.
## Halfkay
Halfkay is a super-slim protocol developed by PJRC that uses HID, and come on all Teensys (namely the 2.0).
@ -131,3 +141,12 @@ Flashing sequence:
* You will receive a warning about the DFU signature; Just ignore it
4. Reset the device into application mode (may be done automatically)
* If you are building from command line (e.g. `make planck/rev6:default:dfu-util`), make sure that `:leave` is passed to the `DFU_ARGS` variable inside your `rules.mk` (e.g. `DFU_ARGS = -d 0483:df11 -a 0 -s 0x08000000:leave`) so that your device resets after flashing
### STM32 Commands
There are a number of DFU commands that you can use to flash firmware to a STM32 device:
* `:dfu-util` - The default command for flashing to STM32 devices.
* `:dfu-util-wait` - This works like the default command, but it gives you a (configurable) 10 second timeout before it attempts to flash the firmware. You can use `TIME_DELAY=20` from the command line to change the timeout.
* Eg: `make <keyboard>:<keymap>:dfu-util TIME_DELAY=5`
* `:st-link-cli` - This allows you to flash the firmware via ST-LINK's CLI utility, rather than dfu-util.

+ 11
- 5
docs/getting_started_build_tools.md View File

@ -4,7 +4,9 @@ This page describes setting up the build environment for QMK. These instructions
<!-- FIXME: We should have ARM instructions somewhere. -->
Note: If it is your first time here, Check out the "Complete Newbs guide" instead
**Note:** If this is your first time here, check out the [Complete Newbs Guide](newbs.md) page.
Before continuing, double check that your submodules (third-party libraries) are up to date by running `make git-submodule`.
## Linux
@ -41,6 +43,10 @@ Debian / Ubuntu example:
Fedora / Red Hat example:
sudo dnf install gcc unzip wget zip dfu-util dfu-programmer avr-gcc avr-libc binutils-avr32-linux-gnu arm-none-eabi-gcc-cs arm-none-eabi-binutils-cs arm-none-eabi-newlib
Arch / Manjaro example:
pacman -S base-devel gcc unzip wget zip avr-gcc avr-binutils avr-libc dfu-util arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-newlib git dfu-programmer dfu-util
## Nix
@ -123,12 +129,12 @@ If you have trouble and want to ask for help, it is useful to generate a *Win_Ch
## Docker
If this is a bit complex for you, Docker might be the turn-key solution you need. After installing [Docker CE](https://docs.docker.com/install/#supported-platforms), run the following command from the `qmk_firmware` directory to build a keyboard/keymap:
If this is a bit complex for you, Docker might be the turnkey solution you need. After installing [Docker CE](https://docs.docker.com/install/#supported-platforms), run the following command from the `qmk_firmware` directory to build a keyboard/keymap:
```bash
util/docker_build.sh keyboard:keymap
util/docker_build.sh keyboard:keymap
# For example: util/docker_build.sh ergodox_ez:steno
```
This will compile the targeted keyboard/keymap and leave the resulting `.hex` or `.bin` file in the QMK directory for you to flash. If `:keymap` is omitted, the `default` keymap is used. Note that the parameter format is the same as when building with `make`.
This will compile the desired keyboard/keymap and leave the resulting `.hex` or `.bin` file in the QMK directory for you to flash. If `:keymap` is omitted, the `default` keymap is used. Note that the parameter format is the same as when building with `make`.
You can also start the script without any parameters, in which case it will ask you to input the build parameters one by one, which you may find easier to use:
```bash
@ -141,7 +147,7 @@ There is also support for building _and_ flashing the keyboard straight from Doc
util/docker_build.sh keyboard:keymap:target
# For example: util/docker_build.sh planck/rev6:default:dfu-util
```
If you're on Linux, this should work out of the box. On Windows and macOS, it requires [Docker Machine](http://gw.tnode.com/docker/docker-machine-with-usb-support-on-windows-macos/) to be running. This is tedious to set up, so it's not recommended; use QMK Toolbox instead.
If you're on Linux, this should work out of the box. On Windows and macOS, it requires [Docker Machine](http://gw.tnode.com/docker/docker-machine-with-usb-support-on-windows-macos/) to be running. This is tedious to set up, so it's not recommended; use [QMK Toolbox](https://github.com/qmk/qmk_toolbox) instead.
!> Docker for Windows requires [Hyper-V](https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v) to be enabled. This means that it cannot work on versions of Windows which don't have Hyper-V, such as Windows 7, Windows 8 and **Windows 10 Home**.


+ 19
- 9
docs/getting_started_make_guide.md View File

@ -93,19 +93,17 @@ This enables MIDI sending and receiving with your keyboard. To enter MIDI send m
`UNICODE_ENABLE`
This allows you to send unicode symbols via `UC(<unicode>)` in your keymap. Only codes up to 0x7FFF are currently supported.
This allows you to send Unicode characters using `UC(<code point>)` in your keymap. Code points up to `0x7FFF` are supported. This covers characters for most modern languages, as well as symbols, but it doesn't cover emoji.
`UNICODEMAP_ENABLE`
This allows sending unicode symbols using `X(<unicode>)` in your keymap. Codes
up to 0xFFFFFFFF are supported, including emojis. You will need to maintain
a separate mapping table in your keymap file.
This allows you to send Unicode characters using `X(<map index>)` in your keymap. You will need to maintain a mapping table in your keymap file. All possible code points (up to `0x10FFFF`) are supported.
Known limitations:
- Under Mac OS, only codes up to 0xFFFF are supported.
- Under Linux ibus, only codes up to 0xFFFFF are supported (but anything important is still under this limit for now).
`UCIS_ENABLE`
Characters out of range supported by the OS will be ignored.
This allows you to send Unicode characters by inputting a mnemonic corresponding to the character you want to send. You will need to maintain a mapping table in your keymap file. All possible code points (up to `0x10FFFF`) are supported.
For further details, as well as limitations, see the [Unicode page](feature_unicode.md).
`BLUETOOTH_ENABLE`
@ -117,7 +115,7 @@ This allows you output audio on the C6 pin (needs abstracting). See the [audio p
`FAUXCLICKY_ENABLE`
Uses buzzer to emulate clicky switches. A cheap imitation of the Cherry blue switches. By default, uses the C6 pin, same as AUDIO_ENABLE.
Uses buzzer to emulate clicky switches. A cheap imitation of the Cherry blue switches. By default, uses the C6 pin, same as `AUDIO_ENABLE`.
`VARIABLE_TRACE`
@ -137,6 +135,18 @@ This enables [key lock](feature_key_lock.md). This consumes an additional 260 by
This enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common
`SPLIT_TRANSPORT`
As there is no standard split communication driver for ARM-based split keyboards yet, `SPLIT_TRANSPORT = custom` must be used for these. It will prevent the standard split keyboard communication code (which is AVR-specific) from being included, allowing a custom implementation to be used.
`CUSTOM_MATRIX`
Lets you replace the default matrix scanning routine with your own code. You will need to provide your own implementations of matrix_init() and matrix_scan().
`DEBOUNCE_TYPE`
Lets you replace the default key debouncing routine with an alternative one. If `custom` you will need to provide your own implementation.
## Customizing Makefile Options on a Per-Keymap Basis
If your keymap directory has a file called `rules.mk` any options you set in that file will take precedence over other `rules.mk` options for your particular keyboard.


+ 23
- 14
docs/hand_wire.md View File

@ -185,21 +185,30 @@ When you're done with the columns, start with the rows in the same process, from
As you move along, be sure that the Teensy is staying in place - recutting and soldering the wires is a pain!
## Additional guides
If you're more of a visual learner, or want some additional tips and something more to follow along, these two visual step by step guides may be helpful:
- [BrownFox's step by step guide](https://deskthority.net/viewtopic.php?f=7&t=6050)
- [Cribbit's modern hand wiring guide](https://geekhack.org/index.php?topic=87689.0)
# Getting Some Basic Firmware Set Up
From here, you should have a working keyboard once you program a firmware. Before we attach the Teensy permanently to the keyboard, let's quickly get some firmware loaded onto the Teensy so we can test each keyswitch.
To start out, download [the firmware](https://github.com/qmk/qmk_firmware/) - we'll be using my (Jack's) fork of TMK called QMK/Quantum. We'll be doing a lot from the Terminal/command prompt, so get that open, along with a decent text editor like [Sublime Text](http://www.sublimetext.com/).
To start out, download [the firmware](https://github.com/qmk/qmk_firmware/) - we'll be using my (Jack's) fork of TMK called QMK/Quantum. We'll be doing a lot from the Terminal/command prompt, so get that open, along with a decent text editor like [Sublime Text](http://www.sublimetext.com/) (paid) or [Visual Studio Code](https://code.visualstudio.com) (free).
The first thing we're going to do is create a new project using the script in the root directory of the firmware. In your terminal, run this command with `<project_name>` replaced by the name of your project - it'll need to be different from any other project in the `keyboards/` folder:
The first thing we're going to do is create a new keyboard. In your terminal, run this command, which will ask you some questions and generate a basic keyboard project:
```
util/new_project.sh <project_name>
./util/new_keyboard.sh
```
You'll want to navigate to the `keyboards/<project_name>/` folder by typing, like the print-out from the script specifies:
cd keyboards/<project_name>
```
cd keyboards/<project_name>
```
### `config.h`
@ -209,7 +218,7 @@ Farther down are `MATRIX_ROW_PINS` and `MATRIX_COL_PINS`. Change their definitio
### `<project_name>.h`
The next file you'll want to look at is `<project_name>.h`. You're going to want to rewrite the `KEYMAP` definition - the format and syntax here is extremely important, so pay attention to how things are setup. The first half of the definition are considered the arguments - this is the format that you'll be following in your keymap later on, so you'll want to have as many k*xy* variables here as you do keys. The second half is the part that the firmware actually looks at, and will contain gaps depending on how you wired your matrix.
The next file you'll want to look at is `<project_name>.h`. You're going to want to rewrite the `LAYOUT` definition - the format and syntax here is extremely important, so pay attention to how things are setup. The first half of the definition are considered the arguments - this is the format that you'll be following in your keymap later on, so you'll want to have as many k*xy* variables here as you do keys. The second half is the part that the firmware actually looks at, and will contain gaps depending on how you wired your matrix.
We'll dive into how this will work with the following example. Say we have a keyboard like this:
@ -231,10 +240,10 @@ This can be described by saying the top row is 3 1u keys, and the bottom row is
└─────┴─────┘
```
The middle column is unused on the bottom row in this example. Our `KEYMAP` definition would look like this:
The middle column is unused on the bottom row in this example. Our `LAYOUT` definition would look like this:
```
#define KEYMAP( \
#define LAYOUT( \
k00, k01, k02, \
k10, k11, \
) \
@ -256,10 +265,10 @@ Let's say that instead, we wired our keyboard like this (a fair thing to do):
└─────┴─────┘
```
This would require our `KEYMAP` definition to look like this:
This would require our `LAYOUT` definition to look like this:
```
#define KEYMAP( \
#define LAYOUT( \
k00, k01, k02, \
k10, k11, \
) \
@ -269,7 +278,7 @@ This would require our `KEYMAP` definition to look like this:
}
```
Notice how the `k11` and `KC_NO` switched places to represent the wiring, and the unused final column on the bottom row. Sometimes it'll make more sense to put a keyswitch on a particular column, but in the end, it won't matter, as long as all of them are accounted for. You can use this process to write out the `KEYMAP` for your entire keyboard - be sure to remember that your keyboard is actually backwards when looking at the underside of it.
Notice how the `k11` and `KC_NO` switched places to represent the wiring, and the unused final column on the bottom row. Sometimes it'll make more sense to put a keyswitch on a particular column, but in the end, it won't matter, as long as all of them are accounted for. You can use this process to write out the `LAYOUT` for your entire keyboard - be sure to remember that your keyboard is actually backwards when looking at the underside of it.
### `keymaps/<variant>/default.c`
@ -291,7 +300,7 @@ This can be accomplished by using the following `keymaps` definition:
```
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = KEYMAP( /* Base */
[0] = LAYOUT( /* Base */
KC_A, KC_1, KC_H, \
KC_TAB, KC_SPC \
),
@ -300,7 +309,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
Note that the layout of the keycodes is similar to the physical layout of our keyboard - this make it much easier to see what's going on. A lot of the keycodes should be fairly obvious, but for a full list of them, check out [Keycodes](keycodes.md) - there are also a lot of aliases to condense your keymap file.
It's also important to use the `KEYMAP` function we defined earlier - this is what allows the firmware to associate our intended readable keymap with the actual wiring.
It's also important to use the `LAYOUT` function we defined earlier - this is what allows the firmware to associate our intended readable keymap with the actual wiring.
## Compiling Your Firmware
@ -319,7 +328,7 @@ Carefully flip your keyboard over, open up a new text document, and try typing -
2. Check the solder joints on the diode - if the diode is loose, part of your row may register, while the other may not.
3. Check the solder joints on the columns - if your column wiring is loose, part or all of the column may not work.
4. Check the solder joints on both sides of the wires going to/from the Teensy - the wires need to be fully soldered and connect to both sides.
5. Check the <project_name>.h file for errors and incorrectly placed `KC_NO`s - if you're unsure where they should be, instead duplicate a k*xy* variable.
5. Check the `<project_name>.h` file for errors and incorrectly placed `KC_NO`s - if you're unsure where they should be, instead duplicate a k*xy* variable.
6. Check to make sure you actually compiled the firmware and flashed the Teensy correctly. Unless you got error messages in the terminal, or a pop-up during flashing, you probably did everything correctly.
If you've done all of these things, keep in mind that sometimes you might have had multiple things affecting the keyswitch, so it doesn't hurt to test the keyswitch by shorting it out at the end.
@ -328,4 +337,4 @@ If you've done all of these things, keep in mind that sometimes you might have h
Now that you have a working board, it's time to get things in their permanent positions. I've often used liberal amounts of hot glue to secure and insulate things, so if that's your style, start spreading that stuff like butter. Otherwise, double-sided tape is always an elegant solution, and electrical tape is a distant second. Due to the nature of these builds, a lot of this part is up to you and how you planned (or didn't plan) things out.
There are a lot of possibilities inside the firmware - explore [docs.qmk.fm](http://docs.qmk.fm) for a full feature list, and dive into the different project (Planck, Clueboard, Ergodox EZ, etc) to see how people use all of them. You can always stop by [the OLKB subreddit for help!](http://reddit.com/r/olkb)
There are a lot of possibilities inside the firmware - explore [docs.qmk.fm](http://docs.qmk.fm) for a full feature list, and dive into the different keyboards (Planck, Clueboard, Ergodox EZ, etc) to see how people use all of them. You can always stop by [the OLKB subreddit for help!](http://reddit.com/r/olkb)

+ 39
- 9
docs/hardware_avr.md View File

@ -6,14 +6,26 @@ If you have not yet you should read the [Keyboard Guidelines](hardware_keyboard_
## Adding Your AVR Keyboard to QMK
QMK has a number of features to simplify working with AVR keyboards. For most keyboards you don't have to write a single line of code. To get started run the `util/new_project.sh` script:
```bash
$ util/new_project.sh my_awesome_keyboard
######################################################
# /keyboards/my_awesome_keyboard project created. To start
# working on things, cd into keyboards/my_awesome_keyboard
######################################################
QMK has a number of features to simplify working with AVR keyboards. For most keyboards you don't have to write a single line of code. To get started, run the `util/new_keyboard.sh` script:
```
$ ./util/new_keyboard.sh
Generating a new QMK keyboard directory
Keyboard Name: mycoolkb
Keyboard Type [avr]:
Your Name [John Smith]:
Copying base template files... done
Copying avr template files... done
Renaming keyboard files... done
Replacing %KEYBOARD% with mycoolkb... done
Replacing %YOUR_NAME% with John Smith... done
Created a new keyboard called mycoolkb.
To start working on things, cd into keyboards/mycoolkb,
or open the directory in your favourite text editor.
```
This will create all the files needed to support your new keyboard, and populate the settings with default values. Now you just need to customize it for your keyboard.
@ -87,12 +99,30 @@ Once you've defined the size of your matrix you need to define which pins on you
The number of `MATRIX_ROW_PINS` entries must be the same as the number you assigned to `MATRIX_ROWS`, and likewise for `MATRIX_COL_PINS` and `MATRIX_COLS`. You do not have to specify `UNUSED_PINS`, but you can if you want to document what pins are open.
Finally, you can specify the direction your diodes point. This can be `COL2ROW`, `ROW2COL`, or `CUSTOM_MATRIX`.
Finally, you can specify the direction your diodes point. This can be `COL2ROW` or `ROW2COL`.
```c
#define DIODE_DIRECTION COL2ROW
```
#### Direct Pin Matrix
To configure a keyboard where each switch is connected to a separate pin and ground instead of sharing row and column pins, use `DIRECT_PINS`. The mapping defines the pins of each switch in rows and columns, from left to right. Must conform to the sizes within `MATRIX_ROWS` and `MATRIX_COLS`, use `NO_PIN` to fill in blank spaces. Overrides the behaviour of `DIODE_DIRECTION`, `MATRIX_ROW_PINS` and `MATRIX_COL_PINS`.
```c
// #define MATRIX_ROW_PINS { D0, D5 }
// #define MATRIX_COL_PINS { F1, F0, B0 }
#define DIRECT_PINS { \
{ F1, E6, B0, B2, B3 }, \
{ F5, F0, B1, B7, D2 }, \
{ F6, F7, C7, D5, D3 }, \
{ B5, C6, B6, NO_PIN, NO_PIN } \
}
#define UNUSED_PINS
/* COL2ROW, ROW2COL */
//#define DIODE_DIRECTION
```
### Backlight Configuration
By default QMK supports backlighting on pins `B5`, `B6`, and `B7`. If you are using one of those you can simply enable it here. For more details see the [Backlight Documentation](feature_backlight.md).


+ 3
- 3
docs/hardware_drivers.md View File

@ -14,9 +14,9 @@ QMK is used on a lot of different hardware. While support for the most common MC
Support for addressing pins on the ProMicro by their Arduino name rather than their AVR name. This needs to be better documented, if you are trying to do this and reading the code doesn't help please [open an issue](https://github.com/qmk/qmk_firmware/issues/new) and we can help you through the process.
## SSD1306 (AVR Only)
## SSD1306 OLED Driver
Support for SSD1306 based OLED displays. This needs to be better documented, if you are trying to do this and reading the code doesn't help please [open an issue](https://github.com/qmk/qmk_firmware/issues/new) and we can help you through the process.
Support for SSD1306 based OLED displays. For more information see the [OLED Driver Feature](feature_oled_driver.md) page.
## uGFX
@ -32,4 +32,4 @@ Support for up to 2 drivers. Each driver impliments 2 charlieplex matrices to in
## IS31FL3733
Support for up to a single driver with room for expansion. Each driver can control 192 individual LEDs or 64 RGB LEDs. For more information on how to setup the driver see the [RGB Matrix](feature_rgb_matrix.md) page.
Support for up to a single driver with room for expansion. Each driver can control 192 individual LEDs or 64 RGB LEDs. For more information on how to setup the driver see the [RGB Matrix](feature_rgb_matrix.md) page.

+ 82
- 69
docs/hardware_keyboard_guidelines.md View File

@ -1,107 +1,120 @@
# QMK Keyboard Guidelines
We welcome all keyboard projects into QMK, but ask that you try to stick to a couple guidelines that help us keep things organised and consistent.
Since starting, QMK has grown by leaps and bounds thanks to people like you who contribute to creating and maintaining our community keyboards. As we've grown we've discovered some patterns that work well, and ask that you conform to them to make it easier for other people to benefit from your hard work.
## Naming Your Keyboard/Project
All names should be lowercase alphanumeric, and separated by an underscore (`_`), but not begin with one. Your directory and your `.h` and `.c` files should have exactly the same name. All folders should follow the same format. `test`, `keyboard`, and `all` are reserved by make and are not a valid name for a keyboard.
All keyboard names are in lower case, consisting only of letters, numbers, and underscore (`_`). Names may not begin with an underscore. Forward slash (`/`) is used as a sub-folder separation character.
## `readme.md`
The names `test`, `keyboard`, and `all` are reserved for make commands and may not be used as a keyboard or subfolder name.
All projects need to have a `readme.md` file that explains what the keyboard is, who made it, where it is available, and links to more information. Please follow the [published template](documentation_templates.md#keyboard-readmemd-template).
Valid Examples:
## Image/Hardware Files
* `412_64`
* `chimera_ortho`
* `clueboard/66/rev3`
* `planck`
* `v60_type_r`
In an effort to keep the repo size down, we're no longer accepting images of any format in the repo, with few exceptions. Hosting them elsewhere (imgur) and linking them in the `readme.md` is the preferred method.
## Sub-folders
Any sort of hardware file (plate, case, pcb) can't be stored in qmk_firmware, but we have the [qmk.fm repo](https://github.com/qmk/qmk.fm) where such files (as well as in-depth info) can be stored and viewed on [qmk.fm](http://qmk.fm). Downloadable files are stored in `/<keyboard>/` (name follows the same format as above) which are served at `http://qmk.fm/<keyboard>/`, and pages are generated from `/_pages/<keyboard>/` which are served at the same location (.md files are generated into .html files through Jekyll). Check out the `lets_split` directory for an example.
QMK uses sub-folders both for organization and to share code between revisions of the same keyboard. You can nest folders up to 4 levels deep:
## Keyboard Defaults
qmk_firmware/keyboards/top_folder/sub_1/sub_2/sub_3/sub_4
Given the amount of functionality that QMK exposes it's very easy to confuse new users. When putting together the default firmware for your keyboard we recommend limiting your enabled features and options to the minimal set needed to support your hardware. Recommendations for specific features follow.
If a sub-folder has a `rules.mk` file it will be considered a compilable keyboard. It will be available in QMK Configurator and tested with `make all`. If you are using a folder to organize several keyboards from the same maker you should not have a `rules.mk` file.
### Bootmagic and Command
Example:
[Bootmagic](feature_bootmagic.md) and [Command](feature_command.md) are two related features that allow a user to control their keyboard in non-obvious ways. We recommend you think long and hard about if you're going to enable either feature, and how you will expose this functionality. Keep in mind that users who want this functionality can enable it in their personal keymaps without affecting all the novice users who may be using your keyboard as their first programmable board.
Clueboard uses sub-folders for both purposes, organization and keyboard revisions.
By far the most common problem new users encounter is accidentally triggering Bootmagic while they're plugging in their keyboard. They're holding the keyboard by the bottom, unknowingly pressing in alt and spacebar, and then they find that these keys have been swapped on them. We recommend leaving this feature disabled by default, but if you do turn it on consider setting `BOOTMAGIC_KEY_SALT` to a key that is hard to press while plugging your keyboard in.
* [`qmk_firmware`](https://github.com/qmk/qmk_firmware/tree/master)
* [`keyboards`](https://github.com/qmk/qmk_firmware/tree/master/keyboards)
* [`clueboard`](https://github.com/qmk/qmk_firmware/tree/master/keyboards/clueboard) &larr; This is the organization folder, there's no `rules.mk` file
* [`60`](https://github.com/qmk/qmk_firmware/tree/master/keyboards/clueboard/60) &larr; This is a compilable keyboard, it has a `rules.mk` file
* [`66`](https://github.com/qmk/qmk_firmware/tree/master/keyboards/clueboard/66) &larr; This is also compilable- it uses `DEFAULT_FOLDER` to specify `rev3` as the default revision
* [`rev1`](https://github.com/qmk/qmk_firmware/tree/master/keyboards/clueboard/66/rev1) &larr; compilable: `make clueboard/66/rev1`
* [`rev2`](https://github.com/qmk/qmk_firmware/tree/master/keyboards/clueboard/66/rev2) &larr; compilable: `make clueboard/66/rev2`
* [`rev3`](https://github.com/qmk/qmk_firmware/tree/master/keyboards/clueboard/66/rev3) &larr; compilable: `make clueboard/66/rev3` or `make clueboard/66`
If your keyboard does not have 2 shift keys you should provide a working default for `IS_COMMAND`, even when you have set `COMMAND_ENABLE = no`. This will give your users a default to conform to if they do enable Command.
## Keyboard Folder Structure
## Custom Keyboard Programming
Your keyboard should be located in `qmk_firmware/keyboards/` and the folder name should be your keyboard's name as described in the previous section. Inside this folder should be several files:
As documented on [Customizing Functionality](custom_quantum_functions.md) you can define custom functions for your keyboard. Please keep in mind that your users may want to customize that behavior as well, and make it possible for them to do that. If you are providing a custom function, for example `process_record_kb()`, make sure that your function calls the `_user()` version of the call too. You should also take into account the return value of the `_user()` version, and only run your custom code if the user returns `true`.
* `readme.md`
* `info.json`
* `config.h`
* `rules.mk`
* `<keyboard_name>.c`
* `<keyboard_name>.h`
### `readme.md`
All projects need to have a `readme.md` file that explains what the keyboard is, who made it and where it's available. If applicable, it should also contain links to more information, such as the maker's website. Please follow the [published template](documentation_templates.md#keyboard-readmemd-template).
### `info.json`
This file is used by the [QMK API](https://github.com/qmk/qmk_api). It contains the information [QMK Configurator](https://config.qmk.fm/) needs to display a representation of your keyboard. You can also set metadata here. For more information see the [reference page](reference_info_json.md).
### `config.h`
All projects need to have a `config.h` file that sets things like the matrix size, product name, USB VID/PID, description and other settings. In general, use this file to set essential information and defaults for your keyboard that will always work.
## Keyboard Metadata
### `rules.mk`
As QMK grows so does the ecosystem surrounding QMK. To make it easier for projects in that ecosystem to tie into QMK as we make changes we are developing a metadata system to expose information about keyboards in QMK.
The presence of this file means that the folder is a keyboard target and can be used in `make` commands. This is where you setup the build environment for your keyboard and configure the default set of features.
You can create `info.json` files at every level under `qmk_firmware/keyboards/<name>` to specify this metadata. These files are combined, with more specific files overriding keys in less specific files. This means you do not need to duplicate your metadata information. For example, `qmk_firmware/keyboards/clueboard/info.json` specifies `manufacturer` and `maintainer`, while `qmk_firmware/keyboards/clueboard/66/info.json` specifies more specific information about Clueboard 66%.
### `<keyboard_name.c>`
### `info.json` Format
This is where you will write custom code for your keyboard. Typically you will write code to initialize and interface with the hardware in your keyboard. If your keyboard consists of only a key matrix with no LEDs, speakers, or other auxillary hardware this file can be blank.
The `info.json` file is a JSON formatted dictionary with the following keys available to be set. You do not have to set all of them, merely the keys that apply to your keyboard.
The following functions are typically defined in this file:
* `keyboard_name`
* A free-form text string describing the keyboard.
* Example: `Clueboard 66%`
* `url`
* A URL to the keyboard's product page, [QMK.fm/keyboards](https://qmk.fm/keyboards) page, or other page describing information about the keyboard.
* `maintainer`
* GitHub username of the maintainer, or `qmk` for community maintained boards
* `width`
* Width of the board in Key Units
* `height`
* Height of the board in Key Units
* `layouts`
* Physical Layout representations. See the next section for more detail.
* `void matrix_init_kb(void)`
* `void matrix_scan_kb(void)`
* `bool process_record_kb(uint16_t keycode, keyrecord_t *record)`
* `void led_set_kb(uint8_t usb_led)`
#### Layout Format
### `<keyboard_name.h>`
Within our `info.json` file the `layouts` portion of the dictionary contains several nested dictionaries. The outer layer consists of QMK layout macros, for example `LAYOUT_ansi` or `LAYOUT_iso`. Within each layout macro are keys for `width`, `height`, and `key_count`, each of which should be self-explanatory.
This file is used to define the matrix for your keyboard. You should define at least one C macro which translates an array into a matrix representing the physical switch matrix for your keyboard. If it's possible to build your keyboard with multiple layouts you should define additional macros.
* `width`
* Optional: The width of the layout in Key Units
* `height`
* Optional: The height of the layout in Key Units
* `key_count`
* **Required**: The number of keys in this layout
* `layout`
* A list of Key Dictionaries describing the physical layout. See the next section for more details.
If you have only a single layout you should call this macro `LAYOUT`.
#### Key Dictionary Format
When defining multiple layouts you should have a base layout, named `LAYOUT_all`, that supports all possible switch positions on your matrix, even if that layout is impossible to build physically. This is the macro you should use in your `default` keymap. You should then have additional keymaps named `default_<layout>` that use your other layout macros. This will make it easier for people to use the layouts you define.
Each Key Dictionary in a layout describes the physical properties of a key. If you are familiar with the Raw Code for <http://keyboard-layout-editor.com> you will find many of the concepts the same. We re-use the same key names and layout choices wherever possible, but unlike keyboard-layout-editor each key is stateless, inheriting no properties from the keys that came before it.
Layout macro names are entirely lowercase, except for the word `LAYOUT` at the front.
All key positions and rotations are specified in relation to the top-left corner of the keyboard, and the top-left corner of each key.
As an example, if you have a 60% PCB that supports ANSI and ISO you might define the following layouts and keymaps:
* `X`
* **Required**: The absolute position of the key in the horizontal axis, in Key Units.
* `Y`
* **Required**: The absolute position of the key in the vertical axis, in Key Units.
* `W`
* The width of the key, in Key Units. Ignored if `ks` is provided. Default: `1`
* `H`
* The height of the key, in Key Units. Ignored if `ks` is provided. Default: `1`
* `R`
* How many degrees clockwise to rotate the key.
* `RX`
* The absolute position of the point to rotate the key around in the horizontal axis. Default: `x`
* `RY`
* The absolute position of the point to rotate the key around in the vertical axis. Default: `y`
* `KS`
* Key Shape: define a polygon by providing a list of points, in Key Units.
* **Important**: These are relative to the top-left of the key, not absolute.
* Example ISO Enter: `[ [0,0], [1.5,0], [1.5,2], [0.25,2], [0.25,1], [0,1], [0,0] ]`
| Layout Name | Keymap Name | Description |
|-------------|-------------|-------------|
| LAYOUT_all | default | A layout that supports both ISO and ANSI |
| LAYOUT_ansi | default_ansi | An ANSI layout |
| LAYOUT_iso | default_iso | An ISO layout |
### How is the Metadata Exposed?
## Image/Hardware Files
In an effort to keep the repo size down we're no longer accepting binary files of any format, with few exceptions. Hosting them elsewhere (such as <https://imgur.com>) and linking them in the `readme.md` is preferred.
Hardware files (such as plates, cases, pcb) can be contributed to the [qmk.fm repo](https://github.com/qmk/qmk.fm) and they will be made available on [qmk.fm](http://qmk.fm). Downloadable files are stored in `/<keyboard>/` (name follows the same format as above) which are served at `http://qmk.fm/<keyboard>/`, and pages are generated from `/_pages/<keyboard>/` which are served at the same location (.md files are generated into .html files through Jekyll). Check out the `lets_split` folder for an example.
## Keyboard Defaults
Given the amount of functionality that QMK exposes it's very easy to confuse new users. When putting together the default firmware for your keyboard we recommend limiting your enabled features and options to the minimal set needed to support your hardware. Recommendations for specific features follow.
### Bootmagic and Command
[Bootmagic](feature_bootmagic.md) and [Command](feature_command.md) are two related features that allow a user to control their keyboard in non-obvious ways. We recommend you think long and hard about if you're going to enable either feature, and how you will expose this functionality. Keep in mind that users who want this functionality can enable it in their personal keymaps without affecting all the novice users who may be using your keyboard as their first programmable board.
By far the most common problem new users encounter is accidentally triggering Bootmagic while they're plugging in their keyboard. They're holding the keyboard by the bottom, unknowingly pressing in alt and spacebar, and then they find that these keys have been swapped on them. We recommend leaving this feature disabled by default, but if you do turn it on consider setting `BOOTMAGIC_KEY_SALT` to a key that is hard to press while plugging your keyboard in.
This metadata is primarily used in two ways:
If your keyboard does not have 2 shift keys you should provide a working default for `IS_COMMAND`, even when you have set `COMMAND_ENABLE = no`. This will give your users a default to conform to if they do enable Command.
* To allow web-based configurators to dynamically generate UI
* To support the new `make keyboard:keymap:qmk` target, which bundles this metadata up with the firmware to allow QMK Toolbox to be smarter.
## Custom Keyboard Programming
Configurator authors can see the [QMK Compiler](https://docs.compile.qmk.fm/api_docs.html) docs for more information on using the JSON API.
As documented on [Customizing Functionality](custom_quantum_functions.md) you can define custom functions for your keyboard. Please keep in mind that your users may want to customize that behavior as well, and make it possible for them to do that. If you are providing a custom function, for example `process_record_kb()`, make sure that your function calls the `_user()` version of the call too. You should also take into account the return value of the `_user()` version, and only run your custom code if the user returns `true`.
## Non-Production/Handwired Projects


+ 1
- 1
docs/how_keyboards_work.md View File

@ -12,7 +12,7 @@ place:
``` text
+------+ +-----+ +----------+ +----------+ +----+
| User |-------->| Key |------>| Firmware |----->| USB wire |---->| OS |
+------+ +-----+ +----------+ +----------+ |----+
+------+ +-----+ +----------+ +----------+ +----+
```
This scheme is a very simple view of what's going on, and more details follow


+ 12
- 8
docs/i2c_driver.md View File

@ -12,7 +12,7 @@ The I2C Master drivers used in QMK have a set of common functions to allow porta
|`uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);` |Receive data over I2C. Address is the 7-bit slave address without the direction. Saves number of bytes specified by `length` in `data` array. Returns status of transaction. |
|`uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);` |Same as the `i2c_transmit` function but `regaddr` sets where in the slave the data will be written. |
|`uint8_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);` |Same as the `i2c_receive` function but `regaddr` sets from where in the slave the data will be read. |
|`uint8_t i2c_stop(uint16_t timeout);` |Stops the I2C driver. |
|`uint8_t i2c_stop(void);` |Ends an I2C transaction. |
### Function Return
@ -33,8 +33,8 @@ The following defines can be used to configure the I2C master driver.
|Variable |Description |Default|
|------------------|---------------------------------------------------|-------|
|`#F_SCL` |Clock frequency in Hz |400KHz |
|`#Prescaler` |Divides master clock to aid in I2C clock selection |1 |
|`F_SCL` |Clock frequency in Hz |400KHz |
|`Prescaler` |Divides master clock to aid in I2C clock selection |1 |
AVRs usually have set GPIO which turn into I2C pins, therefore no further configuration is required.
@ -63,20 +63,24 @@ Lastly, we need to assign the correct GPIO pins depending on the I2C hardware dr
By default the I2C1 hardware driver is assumed to be used. If another hardware driver is used, `#define I2C_DRIVER I2CDX` should be added to the `config.h` file with X being the number of hardware driver used. For example is I2C3 is enabled, the `config.h` file should contain `#define I2C_DRIVER I2CD3`. This aligns the QMK I2C driver with the Chibios I2C driver.
STM32 MCUs allows a variety of pins to be configured as I2C pins depending on the hardware driver used. By default B6 and B7 are set to I2C.
STM32 MCUs allows a variety of pins to be configured as I2C pins depending on the hardware driver used. By default B6 and B7 are set to I2C. You can use these defines to set your i2c pins:
This can be changed by declaring the `i2c_init` function which intentionally has a weak attribute. Please consult the datasheet of your MCU for the available GPIO configurations. The following is an example initialization function:
| Variable | Description | Default |
|-------------|----------------------------------------------|---------|
| `I2C1_BANK` | The bank of pins (`GPIOA`, `GPIOB`, `GPIOC`) | `GPIOB` |
| `I2C1_SCL` | The pin number for the SCL pin (0-9) | `6` |
| `I2C1_SDA` | The pin number for the SDA pin (0-9) | `7` |
You can also overload the `void i2c_init(void)` function, which has a weak attribute. If you do this the configuration variables above will not be used. Please consult the datasheet of your MCU for the available GPIO configurations. The following is an example initialization function:
```C
void i2c_init(void)
{
setPinInput(B6); // Try releasing special pins for a short time
setPinInput(B7);
chThdSleepMilliseconds(10); // Wait for the release to happen
wait_ms(10); // Wait for the release to happen
palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP); // Set B6 to I2C function
palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP); // Set B7 to I2C function
}
```

+ 3
- 3
docs/internals_gpio_control.md View File

@ -1,6 +1,6 @@
# GPIO Control
QMK has a GPIO control abstraction layer which is micro-controller agnostic. This is done to allow easy access to pin control across different platforms.
QMK has a GPIO control abstraction layer which is microcontroller agnostic. This is done to allow easy access to pin control across different platforms.
## Functions
@ -17,7 +17,7 @@ The following functions can provide basic control of GPIOs and are found in `qua
|`writePin(pin, level)`|Set pin level, assuming it is an output |
|`readPin(pin)` |Returns the level of the pin |
## Advance settings
## Advanced Settings
Each micro-controller can have multiple advance settings regarding its GPIO. This abstraction layer does not limit the use of architecture specific functions. Advance users should consult the datasheet of there desired device and include any needed libraries. For AVR the standard avr/io.h library is used and for STM32 the Chibios [PAL library](http://chibios.sourceforge.net/docs3/hal/group___p_a_l.html) is used.
Each microcontroller can have multiple advanced settings regarding its GPIO. This abstraction layer does not limit the use of architecture-specific functions. Advanced users should consult the datasheet of their desired device and include any needed libraries. For AVR, the standard avr/io.h library is used; for STM32, the ChibiOS [PAL library](http://chibios.sourceforge.net/docs3/hal/group___p_a_l.html) is used.

+ 6
- 1
docs/isp_flashing_guide.md View File

@ -53,7 +53,7 @@ This is pretty straight-forward - we'll be connecting like-things to like-things
The only difference between the .hex files below is which pin is connected to RESET. You can use them on other boards as well, as long as you're aware of the pins being used. If for some reason neither of these pins are available, [create an issue](https://github.com/qmk/qmk_firmware/issues/new), and we can generate one for you!
* Teensy 2.0: [`util/teensy_2.0_ISP_B0.hex`](https://github.com/qmk/qmk_firmware/blob/master/util/teensy_2.0_ISP_B0.hex) (`B0`)
* Pro Micro: [`util/pro_micro_ISP_B6_10.hex`](https://github.com/qmk/qmk_firmware/blob/master/util/pro_mico_ISP_B6_10.hex) (`B6/10`)
* Pro Micro: [`util/pro_micro_ISP_B6_10.hex`](https://github.com/qmk/qmk_firmware/blob/master/util/pro_micro_ISP_B6_10.hex) (`B6/10`)
**Flash your Teenys/Pro Micro with one of these and continue - you won't need the file after flashing your ISP device.**
@ -63,6 +63,7 @@ If you just want to get things back to normal, you can flash only a bootloader f
* [`atmega32u4`](https://github.com/qmk/qmk_firmware/blob/master/util/bootloader_atmega32u4_1_0_0.hex) - Most keyboards, Planck Rev 1-5, Preonic Rev 1-2
* [`at90usb1286`](https://github.com/qmk/qmk_firmware/blob/master/util/bootloader_at90usb128x_1_0_1.hex) - Planck Light Rev 1
* [`atmega32a`](https://github.com/qmk/qmk_firmware/blob/master/util/bootloader_atmega32a_1_0_0.hex) - jj40
If you're not sure what your board uses, look in the `rules.mk` file for the keyboard in QMK. The `MCU =` line will have the value you need. It may differ between different versions of the board.
@ -113,6 +114,10 @@ Since our keyboard uses an `atmega32u4` (common), that is the chip we'll specify
avrdude -c avrisp -P COM3 -p atmega32u4 -U flash:w:main.hex:i
If your board uses an `atmega32a` (e.g. on a jj40), the command is this (the extra code at the end sets the fuses correctly):
avrdude -c avrisp -P COM3 -p atmega32 -U flash:w:main.hex:i -U hfuse:w:0xD0:m -U lfuse:w:0x0F:m
You should see a couple of progress bars, then you should see:
avrdude: verifying ...


+ 258
- 265
docs/keycodes.md View File

@ -6,205 +6,205 @@ This is a reference only. Each group of keys links to the page documenting their
## [Basic Keycodes](keycodes_basic.md)
|Key |Aliases |Description |
|-----------------------|--------------------|-----------------------------------------------|
|`KC_NO` |`XXXXXXX` |Ignore this key (NOOP) |
|`KC_TRANSPARENT` |`KC_TRNS`, `_______`|Use the next lowest non-transparent key |
|`KC_A` | |`a` and `A` |
|`KC_B` | |`b` and `B` |
|`KC_C` | |`c` and `C` |
|`KC_D` | |`d` and `D` |
|`KC_E` | |`e` and `E` |
|`KC_F` | |`f` and `F` |
|`KC_G` | |`g` and `G` |
|`KC_H` | |`h` and `H` |
|`KC_I` | |`i` and `I` |
|`KC_J` | |`j` and `J` |
|`KC_K` | |`k` and `K` |
|`KC_L` | |`l` and `L` |
|`KC_M` | |`m` and `M` |
|`KC_N` | |`n` and `N` |
|`KC_O` | |`o` and `O` |
|`KC_P` | |`p` and `P` |
|`KC_Q` | |`q` and `Q` |
|`KC_R` | |`r` and `R` |
|`KC_S` | |`s` and `S` |
|`KC_T` | |`t` and `T` |
|`KC_U` | |`u` and `U` |
|`KC_V` | |`v` and `V` |
|`KC_W` | |`w` and `W` |
|`KC_X` | |`x` and `X` |
|`KC_Y` | |`y` and `Y` |
|`KC_Z` | |`z` and `Z` |
|`KC_1` | |`1` and `!` |
|`KC_2` | |`2` and `@` |
|`KC_3` | |`3` and `#` |
|`KC_4` | |`4` and `$` |
|`KC_5` | |`5` and `%` |
|`KC_6` | |`6` and `^` |
|`KC_7` | |`7` and `&` |
|`KC_8` | |`8` and `*` |
|`KC_9` | |`9` and `(` |
|`KC_0` | |`0` and `)` |
|`KC_ENTER` |`KC_ENT` |Return (Enter) |
|`KC_ESCAPE` |`KC_ESC` |Escape |
|`KC_BSPACE` |`KC_BSPC` |Delete (Backspace) |
|`KC_TAB` | |Tab |
|`KC_SPACE` |`KC_SPC` |Spacebar |
|`KC_MINUS` |`KC_MINS` |`-` and `_` |
|`KC_EQUAL` |`KC_EQL` |`=` and `+` |
|`KC_LBRACKET` |`KC_LBRC` |`[` and `{` |
|`KC_RBRACKET` |`KC_RBRC` |`]` and `}` |
|`KC_BSLASH` |`KC_BSLS` |`\` and <code>&#124;</code> |
|`KC_NONUS_HASH` |`KC_NUHS` |Non-US `#` and `~` |
|`KC_SCOLON` |`KC_SCLN` |`;` and `:` |
|`KC_QUOTE` |`KC_QUOT` |`'` and `"` |
|`KC_GRAVE` |`KC_GRV`, `KC_ZKHK` |<code>&#96;</code> and `~`, JIS Zenkaku/Hankaku|
|`KC_COMMA` |`KC_COMM` |`,` and `<` |
|`KC_DOT` | |`.` and `>` |
|`KC_SLASH` |`KC_SLSH` |`/` and `?` |
|`KC_CAPSLOCK` |`KC_CLCK`, `KC_CAPS`|Caps Lock |
|`KC_F1` | |F1 |
|`KC_F2` | |F2 |
|`KC_F3` | |F3 |
|`KC_F4` | |F4 |
|`KC_F5` | |F5 |
|`KC_F6` | |F6 |
|`KC_F7` | |F7 |
|`KC_F8` | |F8 |
|`KC_F9` | |F9 |
|`KC_F10` | |F10 |
|`KC_F11` | |F11 |
|`KC_F12` | |F12 |
|`KC_PSCREEN` |`KC_PSCR` |Print Screen |
|`KC_SCROLLLOCK` |`KC_SLCK` |Scroll Lock |
|`KC_PAUSE` |`KC_PAUS`, `KC_BRK` |Pause |
|`KC_INSERT` |`KC_INS` |Insert |
|`KC_HOME` | |Home |
|`KC_PGUP` | |Page Up |
|`KC_DELETE` |`KC_DEL` |Forward Delete |
|`KC_END` | |End |
|`KC_PGDOWN` |`KC_PGDN` |Page Down |
|`KC_RIGHT` |`KC_RGHT` |Right Arrow |
|`KC_LEFT` | |Left Arrow |
|`KC_DOWN` | |Down Arrow |
|`KC_UP` | |Up Arrow |
|`KC_NUMLOCK` |`KC_NLCK` |Keypad Num Lock and Clear |
|`KC_KP_SLASH` |`KC_PSLS` |Keypad `/` |
|`KC_KP_ASTERISK` |`KC_PAST` |Keypad `*` |
|`KC_KP_MINUS` |`KC_PMNS` |Keypad `-` |
|`KC_KP_PLUS` |`KC_PPLS` |Keypad `+` |
|`KC_KP_ENTER` |`KC_PENT` |Keypad Enter |
|`KC_KP_1` |`KC_P1` |Keypad `1` and End |
|`KC_KP_2` |`KC_P2` |Keypad `2` and Down Arrow |
|`KC_KP_3` |`KC_P3` |Keypad `3` and Page Down |
|`KC_KP_4` |`KC_P4` |Keypad `4` and Left Arrow |
|`KC_KP_5` |`KC_P5` |Keypad `5` |
|`KC_KP_6` |`KC_P6` |Keypad `6` and Right Arrow |
|`KC_KP_7` |`KC_P7` |Keypad `7` and Home |
|`KC_KP_8` |`KC_P8` |Keypad `8` and Up Arrow |
|`KC_KP_9` |`KC_P9` |Keypad `9` and Page Up |
|`KC_KP_0` |`KC_P0` |Keypad `0` and Insert |
|`KC_KP_DOT` |`KC_PDOT` |Keypad `.` and Delete |
|`KC_NONUS_BSLASH` |`KC_NUBS` |Non-US `\` and <code>&#124;</code> |
|`KC_APPLICATION` |`KC_APP` |Application (Windows Menu Key) |
|`KC_POWER` | |System Power (macOS) |
|`KC_KP_EQUAL` |`KC_PEQL` |Keypad `=` |
|`KC_F13` | |F13 |
|`KC_F14` | |F14 |
|`KC_F15` | |F15 |
|`KC_F16` | |F16 |
|`KC_F17` | |F17 |
|`KC_F18` | |F18 |
|`KC_F19` | |F19 |
|`KC_F20` | |F20 |
|`KC_F21` | |F21 |
|`KC_F22` | |F22 |
|`KC_F23` | |F23 |
|`KC_F24` | |F24 |
|`KC_EXECUTE` |`KC_EXEC` |Execute |
|`KC_HELP` | |Help |
|`KC_MENU` | |Menu |
|`KC_SELECT` |`KC_SLCT` |Select |
|`KC_STOP` | |Stop |
|`KC_AGAIN` |`KC_AGIN` |Again |
|`KC_UNDO` | |Undo |
|`KC_CUT` | |Cut |
|`KC_COPY` | |Copy |
|`KC_PASTE` |`KC_PSTE` |Paste |
|`KC_FIND` | |Find |
|`KC__MUTE` | |Mute (macOS) |
|`KC__VOLUP` | |Volume Up (macOS) |
|`KC__VOLDOWN` | |Volume Down (macOS) |
|`KC_LOCKING_CAPS` |`KC_LCAP` |Locking Caps Lock |
|`KC_LOCKING_NUM` |`KC_LNUM` |Locking Num Lock |
|`KC_LOCKING_SCROLL` |`KC_LSCR` |Locking Scroll Lock |
|`KC_KP_COMMA` |`KC_PCMM` |Keypad `,` |
|`KC_KP_EQUAL_AS400` | |Keypad `=` on AS/400 keyboards |
|`KC_INT1` |`KC_RO` |JIS `\` and `_` |
|`KC_INT2` |`KC_KANA` |JIS Katakana/Hiragana |
|`KC_INT3` |`KC_JYEN` |JIS `¥` and <code>&#124;</code> |
|`KC_INT4` |`KC_HENK` |JIS Henkan |
|`KC_INT5` |`KC_MHEN` |JIS Muhenkan |
|`KC_INT6` | |JIS Numpad `,` |
|`KC_INT7` | |International 7 |
|`KC_INT8` | |International 8 |
|`KC_INT9` | |International 9 |
|`KC_LANG1` |`KC_HAEN` |Hangul/English |
|`KC_LANG2` |`KC_HANJ` |Hanja |
|`KC_LANG3` | |JIS Katakana |
|`KC_LANG4` | |JIS Hiragana |
|`KC_LANG5` | |JIS Zenkaku/Hankaku |
|`KC_LANG6` | |Language 6 |
|`KC_LANG7` | |Language 7 |
|`KC_LANG8` | |Language 8 |
|`KC_LANG9` | |Language 9 |
|`KC_ALT_ERASE` |`KC_ERAS` |Alternate Erase |
|`KC_SYSREQ` | |SysReq/Attention |
|`KC_CANCEL` | |Cancel |
|`KC_CLEAR` |`KC_CLR` |Clear |
|`KC_PRIOR` | |Prior |
|`KC_RETURN` | |Return |
|`KC_SEPARATOR` | |Separator |
|`KC_OUT` | |Out |
|`KC_OPER` | |Oper |
|`KC_CLEAR_AGAIN` | |Clear/Again |
|`KC_CRSEL` | |CrSel/Props |
|`KC_EXSEL` | |ExSel |
|`KC_LCTRL` |`KC_LCTL` |Left Control |
|`KC_LSHIFT` |`KC_LSFT` |Left Shift |
|`KC_LALT` | |Left Alt |
|`KC_LGUI` |`KC_LCMD`, `KC_LWIN`|Left GUI (Windows/Command/Meta key) |
|`KC_RCTRL` |`KC_RCTL` |Right Control |
|`KC_RSHIFT` |`KC_RSFT` |Right Shift |
|`KC_RALT` |`KC_ALGR` |Right Alt (AltGr) |
|`KC_RGUI` |`KC_RCMD`, `KC_RWIN`|Right GUI (Windows/Command/Meta key) |
|`KC_SYSTEM_POWER` |`KC_PWR` |System Power Down |
|`KC_SYSTEM_SLEEP` |`KC_SLEP` |System Sleep |
|`KC_SYSTEM_WAKE` |`KC_WAKE` |System Wake |
|`KC_AUDIO_MUTE` |`KC_MUTE` |Mute |
|`KC_AUDIO_VOL_UP` |`KC_VOLU` |Volume Up |
|`KC_AUDIO_VOL_DOWN` |`KC_VOLD` |Volume Down |
|`KC_MEDIA_NEXT_TRACK` |`KC_MNXT` |Next Track (Windows) |
|`KC_MEDIA_PREV_TRACK` |`KC_MPRV` |Previous Track (Windows) |
|`KC_MEDIA_STOP` |`KC_MSTP` |Stop Track (Windows) |
|`KC_MEDIA_PLAY_PAUSE` |`KC_MPLY` |Play/Pause Track |
|`KC_MEDIA_SELECT` |`KC_MSEL` |Launch Media Player (Windows) |
|`KC_MEDIA_EJECT` |`KC_EJCT` |Eject (macOS) |
|`KC_MAIL` | |Launch Mail (Windows) |
|`KC_CALCULATOR` |`KC_CALC` |Launch Calculator (Windows) |
|`KC_MY_COMPUTER` |`KC_MYCM` |Launch My Computer (Windows) |
|`KC_WWW_SEARCH` |`KC_WSCH` |Browser Search (Windows) |
|`KC_WWW_HOME` |`KC_WHOM` |Browser Home (Windows) |
|`KC_WWW_BACK` |`KC_WBAK` |Browser Back (Windows) |
|`KC_WWW_FORWARD` |`KC_WFWD` |Browser Forward (Windows) |
|`KC_WWW_STOP` |`KC_WSTP` |Browser Stop (Windows) |
|`KC_WWW_REFRESH` |`KC_WREF` |Browser Refresh (Windows) |
|`KC_WWW_FAVORITES` |`KC_WFAV` |Browser Favorites (Windows) |
|`KC_MEDIA_FAST_FORWARD`|`KC_MFFD` |Next Track (macOS) |
|`KC_MEDIA_REWIND` |`KC_MRWD` |Previous Track (macOS) |
|`KC_BRIGHTNESS_UP` |`KC_BRIU` |Brightness Up |
|`KC_BRIGHTNESS_DOWN` |`KC_BRID` |Brightness Down |
|Key |Aliases |Description |
|-----------------------|------------------------------|-----------------------------------------------|
|`KC_NO` |`XXXXXXX` |Ignore this key (NOOP) |
|`KC_TRANSPARENT` |`KC_TRNS`, `_______` |Use the next lowest non-transparent key |
|`KC_A` | |`a` and `A` |
|`KC_B` | |`b` and `B` |
|`KC_C` | |`c` and `C` |
|`KC_D` | |`d` and `D` |
|`KC_E` | |`e` and `E` |
|`KC_F` | |`f` and `F` |
|`KC_G` | |`g` and `G` |
|`KC_H` | |`h` and `H` |
|`KC_I` | |`i` and `I` |
|`KC_J` | |`j` and `J` |
|`KC_K` | |`k` and `K` |
|`KC_L` | |`l` and `L` |
|`KC_M` | |`m` and `M` |
|`KC_N` | |`n` and `N` |
|`KC_O` | |`o` and `O` |
|`KC_P` | |`p` and `P` |
|`KC_Q` | |`q` and `Q` |
|`KC_R` | |`r` and `R` |
|`KC_S` | |`s` and `S` |
|`KC_T` | |`t` and `T` |
|`KC_U` | |`u` and `U` |
|`KC_V` | |`v` and `V` |
|`KC_W` | |`w` and `W` |
|`KC_X` | |`x` and `X` |
|`KC_Y` | |`y` and `Y` |
|`KC_Z` | |`z` and `Z` |
|`KC_1` | |`1` and `!` |
|`KC_2` | |`2` and `@` |
|`KC_3` | |`3` and `#` |
|`KC_4` | |`4` and `$` |
|`KC_5` | |`5` and `%` |
|`KC_6` | |`6` and `^` |
|`KC_7` | |`7` and `&` |
|`KC_8` | |`8` and `*` |
|`KC_9` | |`9` and `(` |
|`KC_0` | |`0` and `)` |
|`KC_ENTER` |`KC_ENT` |Return (Enter) |
|`KC_ESCAPE` |`KC_ESC` |Escape |
|`KC_BSPACE` |`KC_BSPC` |Delete (Backspace) |
|`KC_TAB` | |Tab |
|`KC_SPACE` |`KC_SPC` |Spacebar |
|`KC_MINUS` |`KC_MINS` |`-` and `_` |
|`KC_EQUAL` |`KC_EQL` |`=` and `+` |
|`KC_LBRACKET` |`KC_LBRC` |`[` and `{` |
|`KC_RBRACKET` |`KC_RBRC` |`]` and `}` |
|`KC_BSLASH` |`KC_BSLS` |`\` and <code>&#124;</code> |
|`KC_NONUS_HASH` |`KC_NUHS` |Non-US `#` and `~` |
|`KC_SCOLON` |`KC_SCLN` |`;` and `:` |
|`KC_QUOTE` |`KC_QUOT` |`'` and `"` |
|`KC_GRAVE` |`KC_GRV`, `KC_ZKHK` |<code>&#96;</code> and `~`, JIS Zenkaku/Hankaku|
|`KC_COMMA` |`KC_COMM` |`,` and `<` |
|`KC_DOT` | |`.` and `>` |
|`KC_SLASH` |`KC_SLSH` |`/` and `?` |
|`KC_CAPSLOCK` |`KC_CLCK`, `KC_CAPS` |Caps Lock |
|`KC_F1` | |F1 |
|`KC_F2` | |F2 |
|`KC_F3` | |F3 |
|`KC_F4` | |F4 |
|`KC_F5` | |F5 |
|`KC_F6` | |F6 |
|`KC_F7` | |F7 |
|`KC_F8` | |F8 |
|`KC_F9` | |F9 |
|`KC_F10` | |F10 |
|`KC_F11` | |F11 |
|`KC_F12` | |F12 |
|`KC_PSCREEN` |`KC_PSCR` |Print Screen |
|`KC_SCROLLLOCK` |`KC_SLCK`, `KC_BRMD` |Scroll Lock, Brightness Down (macOS) |
|`KC_PAUSE` |`KC_PAUS`, `KC_BRK`, `KC_BRMU`|Pause, Brightness Up (macOS) |
|`KC_INSERT` |`KC_INS` |Insert |
|`KC_HOME` | |Home |
|`KC_PGUP` | |Page Up |
|`KC_DELETE` |`KC_DEL` |Forward Delete |
|`KC_END` | |End |
|`KC_PGDOWN` |`KC_PGDN` |Page Down |
|`KC_RIGHT` |`KC_RGHT` |Right Arrow |
|`KC_LEFT` | |Left Arrow |
|`KC_DOWN` | |Down Arrow |
|`KC_UP` | |Up Arrow |
|`KC_NUMLOCK` |`KC_NLCK` |Keypad Num Lock and Clear |
|`KC_KP_SLASH` |`KC_PSLS` |Keypad `/` |
|`KC_KP_ASTERISK` |`KC_PAST` |Keypad `*` |
|`KC_KP_MINUS` |`KC_PMNS` |Keypad `-` |
|`KC_KP_PLUS` |`KC_PPLS` |Keypad `+` |
|`KC_KP_ENTER` |`KC_PENT` |Keypad Enter |
|`KC_KP_1` |`KC_P1` |Keypad `1` and End |
|`KC_KP_2` |`KC_P2` |Keypad `2` and Down Arrow |
|`KC_KP_3` |`KC_P3` |Keypad `3` and Page Down |
|`KC_KP_4` |`KC_P4` |Keypad `4` and Left Arrow |
|`KC_KP_5` |`KC_P5` |Keypad `5` |
|`KC_KP_6` |`KC_P6` |Keypad `6` and Right Arrow |
|`KC_KP_7` |`KC_P7` |Keypad `7` and Home |
|`KC_KP_8` |`KC_P8` |Keypad `8` and Up Arrow |
|`KC_KP_9` |`KC_P9` |Keypad `9` and Page Up |
|`KC_KP_0` |`KC_P0` |Keypad `0` and Insert |
|`KC_KP_DOT` |`KC_PDOT` |Keypad `.` and Delete |
|`KC_NONUS_BSLASH` |`KC_NUBS` |Non-US `\` and <code>&#124;</code> |
|`KC_APPLICATION` |`KC_APP` |Application (Windows Menu Key) |
|`KC_POWER` | |System Power (macOS) |
|`KC_KP_EQUAL` |`KC_PEQL` |Keypad `=` |
|`KC_F13` | |F13 |
|`KC_F14` | |F14 |
|`KC_F15` | |F15 |
|`KC_F16` | |F16 |
|`KC_F17` | |F17 |
|`KC_F18` | |F18 |
|`KC_F19` | |F19 |
|`KC_F20` | |F20 |
|`KC_F21` | |F21 |
|`KC_F22` | |F22 |
|`KC_F23` | |F23 |
|`KC_F24` | |F24 |
|`KC_EXECUTE` |`KC_EXEC` |Execute |
|`KC_HELP` | |Help |
|`KC_MENU` | |Menu |
|`KC_SELECT` |`KC_SLCT` |Select |
|`KC_STOP` | |Stop |
|`KC_AGAIN` |`KC_AGIN` |Again |
|`KC_UNDO` | |Undo |
|`KC_CUT` | |Cut |
|`KC_COPY` | |Copy |
|`KC_PASTE` |`KC_PSTE` |Paste |
|`KC_FIND` | |Find |
|`KC__MUTE` | |Mute (macOS) |
|`KC__VOLUP` | |Volume Up (macOS) |
|`KC__VOLDOWN` | |Volume Down (macOS) |
|`KC_LOCKING_CAPS` |`KC_LCAP` |Locking Caps Lock |
|`KC_LOCKING_NUM` |`KC_LNUM` |Locking Num Lock |
|`KC_LOCKING_SCROLL` |`KC_LSCR` |Locking Scroll Lock |
|`KC_KP_COMMA` |`KC_PCMM` |Keypad `,` |
|`KC_KP_EQUAL_AS400` | |Keypad `=` on AS/400 keyboards |
|`KC_INT1` |`KC_RO` |JIS `\` and `_` |
|`KC_INT2` |`KC_KANA` |JIS Katakana/Hiragana |
|`KC_INT3` |`KC_JYEN` |JIS `¥` and <code>&#124;</code> |
|`KC_INT4` |`KC_HENK` |JIS Henkan |
|`KC_INT5` |`KC_MHEN` |JIS Muhenkan |
|`KC_INT6` | |JIS Numpad `,` |
|`KC_INT7` | |International 7 |
|`KC_INT8` | |International 8 |
|`KC_INT9` | |International 9 |
|`KC_LANG1` |`KC_HAEN` |Hangul/English |
|`KC_LANG2` |`KC_HANJ` |Hanja |
|`KC_LANG3` | |JIS Katakana |
|`KC_LANG4` | |JIS Hiragana |
|`KC_LANG5` | |JIS Zenkaku/Hankaku |
|`KC_LANG6` | |Language 6 |
|`KC_LANG7` | |Language 7 |
|`KC_LANG8` | |Language 8 |
|`KC_LANG9` | |Language 9 |
|`KC_ALT_ERASE` |`KC_ERAS` |Alternate Erase |
|`KC_SYSREQ` | |SysReq/Attention |
|`KC_CANCEL` | |Cancel |
|`KC_CLEAR` |`KC_CLR` |Clear |
|`KC_PRIOR` | |Prior |
|`KC_RETURN` | |Return |
|`KC_SEPARATOR` | |Separator |
|`KC_OUT` | |Out |
|`KC_OPER` | |Oper |
|`KC_CLEAR_AGAIN` | |Clear/Again |
|`KC_CRSEL` | |CrSel/Props |
|`KC_EXSEL` | |ExSel |
|`KC_LCTRL` |`KC_LCTL` |Left Control |
|`KC_LSHIFT` |`KC_LSFT` |Left Shift |
|`KC_LALT` | |Left Alt |
|`KC_LGUI` |`KC_LCMD`, `KC_LWIN` |Left GUI (Windows/Command/Meta key) |
|`KC_RCTRL` |`KC_RCTL` |Right Control |
|`KC_RSHIFT` |`KC_RSFT` |Right Shift |
|`KC_RALT` |`KC_ALGR` |Right Alt (AltGr) |
|`KC_RGUI` |`KC_RCMD`, `KC_RWIN` |Right GUI (Windows/Command/Meta key) |
|`KC_SYSTEM_POWER` |`KC_PWR` |System Power Down |
|`KC_SYSTEM_SLEEP` |`KC_SLEP` |System Sleep |
|`KC_SYSTEM_WAKE` |`KC_WAKE` |System Wake |
|`KC_AUDIO_MUTE` |`KC_MUTE` |Mute |
|`KC_AUDIO_VOL_UP` |`KC_VOLU` |Volume Up |
|`KC_AUDIO_VOL_DOWN` |`KC_VOLD` |Volume Down |
|`KC_MEDIA_NEXT_TRACK` |`KC_MNXT` |Next Track (Windows) |
|`KC_MEDIA_PREV_TRACK` |`KC_MPRV` |Previous Track (Windows) |
|`KC_MEDIA_STOP` |`KC_MSTP` |Stop Track (Windows) |
|`KC_MEDIA_PLAY_PAUSE` |`KC_MPLY` |Play/Pause Track |
|`KC_MEDIA_SELECT` |`KC_MSEL` |Launch Media Player (Windows) |
|`KC_MEDIA_EJECT` |`KC_EJCT` |Eject (macOS) |
|`KC_MAIL` | |Launch Mail (Windows) |
|`KC_CALCULATOR` |`KC_CALC` |Launch Calculator (Windows) |
|`KC_MY_COMPUTER` |`KC_MYCM` |Launch My Computer (Windows) |
|`KC_WWW_SEARCH` |`KC_WSCH` |Browser Search (Windows) |
|`KC_WWW_HOME` |`KC_WHOM` |Browser Home (Windows) |
|`KC_WWW_BACK` |`KC_WBAK` |Browser Back (Windows) |
|`KC_WWW_FORWARD` |`KC_WFWD` |Browser Forward (Windows) |
|`KC_WWW_STOP` |`KC_WSTP` |Browser Stop (Windows) |
|`KC_WWW_REFRESH` |`KC_WREF` |Browser Refresh (Windows) |
|`KC_WWW_FAVORITES` |`KC_WFAV` |Browser Favorites (Windows) |
|`KC_MEDIA_FAST_FORWARD`|`KC_MFFD` |Next Track (macOS) |
|`KC_MEDIA_REWIND` |`KC_MRWD` |Previous Track (macOS) |
|`KC_BRIGHTNESS_UP` |`KC_BRIU` |Brightness Up |
|`KC_BRIGHTNESS_DOWN` |`KC_BRID` |Brightness Down |
## [Quantum Keycodes](quantum_keycodes.md#qmk-keycodes)
@ -226,9 +226,9 @@ This is a reference only. Each group of keys links to the page documenting their
|Key |Aliases |Description |
|----------------|---------|----------------------------------|
|`AU_ON` | |Audio mode on |
|`AU_OFF` | |Audio mode off |
|`AU_TOG` | |Toggles Audio mode |
|`AU_ON` | |Turns on Audio Feature |
|`AU_OFF` | |Turns off Audio Feature |
|`AU_TOG` | |Toggles Audio state |
|`CLICKY_TOGGLE` |`CK_TOGG`|Toggles Audio clicky mode |
|`CLICKY_UP` |`CK_UP` |Increases frequency of the clicks |
|`CLICKY_DOWN` |`CK_DOWN`|Decreases frequency of the clicks |
@ -238,8 +238,6 @@ This is a reference only. Each group of keys links to the page documenting their
|`MU_TOG` | |Toggles Music Mode |
|`MU_MOD` | |Cycles through the music modes |
## [Backlighting](feature_backlight.md)
|Key |Description |
@ -285,18 +283,18 @@ This is a reference only. Each group of keys links to the page documenting their
|`OUT_USB` |USB only |
|`OUT_BT` |Bluetooth only |
## [Layer Switching](feature_advanced_keycodes.md#switching-and-toggling-layers)
|Key |Description |
|-----------------|---------------------------------------------------------------------|
|`DF(layer)` |Switches the default layer |
|`MO(layer)` |Momentarily activates layer, switches off when you let go |
|`LM(layer, mod)` |As `MO(layer)` but with `mod` active |
|`LT(layer, kc)` |Momentarily activates layer if held, sends kc if tapped |
|`TG(layer)` |Toggles the layer (enables it if no active, and vise versa) |
|`TO(layer)` |Activates layer and deactivates all other layers |
|`TT(layer)` |Momentarily activates layer if held, toggles it if tapped repeatedly |
|Key |Description |
|----------------|----------------------------------------------------------------------------------|
|`DF(layer)` |Set the base (default) layer |
|`MO(layer)` |Momentarily turn on `layer` when pressed (requires `KC_TRNS` on destination layer)|
|`OSL(layer)` |Momentarily activates `layer` until a key is pressed. See [One Shot Keys](https://docs.qmk.fm/#/feature_advanced_keycodes?id=one-shot-keys) for details. |
|`LM(layer, mod)`|Momentarily turn on `layer` (like MO) with `mod` active as well. Where `mod` is a mods_bit. Mods can be viewed [here](https://docs.qmk.fm/#/feature_advanced_keycodes?id=mod-tap). Example Implementation: `LM(LAYER_1, MOD_LALT)`|
|`LT(layer, kc)` |Turn on `layer` when held, `kc` when tapped |
|`TG(layer)` |Toggle `layer` on or off |
|`TO(layer)` |Turn on `layer` when pressed |
|`TT(layer)` |Normally acts like MO unless it's tapped multiple times, which toggles `layer` on |
## [Mouse Keys](feature_mouse_keys.md)
@ -321,43 +319,43 @@ This is a reference only. Each group of keys links to the page documenting their
## [Modifiers](feature_advanced_keycodes.md#modifier-keys)
|Key |Aliases |Description |
|----------|----------------------|----------------------------------------------------|
|`KC_HYPR` | |Hold Left Control, Shift, Alt and GUI |
|`KC_MEH` | |Hold Left Control, Shift and Alt |
|`LCTL(kc)`| |Hold Left Control and press `kc` |
|`LSFT(kc)`|`S(kc)` |Hold Left Shift and press `kc` |
|`LALT(kc)`| |Hold Left Alt and press `kc` |
|`LGUI(kc)`|`LCMD(kc)`, `LWIN(kc)`|Hold Left GUI and press `kc` |
|`RCTL(kc)`| |Hold Right Control and press `kc` |
|`RSFT(kc)`| |Hold Right Shift and press `kc` |
|`RALT(kc)`|`ALGR(kc)` |Hold Right Alt and press `kc` |
|`RGUI(kc)`|`RCMD(kc)`, `LWIN(kc)`|Hold Right GUI and press `kc` |
|`HYPR(kc)`| |Hold Left Control, Shift, Alt and GUI and press `kc`|
|`MEH(kc)` | |Hold Left Control, Shift and Alt and press `kc` |
|`LCAG(kc)`| |Hold Left Control, Alt and GUI and press `kc` |
|`SGUI(kc)`|`SCMD(kc)`, `SWIN(kc)`|Hold Left Shift and GUI and press `kc` |
|`LCA(kc)` | |Hold Left Control and Alt and press `kc` |
|Key |Aliases |Description |
|----------|-------------------------------|----------------------------------------------------|
|`LCTL(kc)`|`C(kc)` |Hold Left Control and press `kc` |
|`LSFT(kc)`|`S(kc)` |Hold Left Shift and press `kc` |
|`LALT(kc)`|`A(kc)` |Hold Left Alt and press `kc` |
|`LGUI(kc)`|`G(kc)`, `LCMD(kc)`, `LWIN(kc)`|Hold Left GUI and press `kc` |
|`RCTL(kc)`| |Hold Right Control and press `kc` |
|`RSFT(kc)`| |Hold Right Shift and press `kc` |
|`RALT(kc)`|`ALGR(kc)` |Hold Right Alt and press `kc` |
|`RGUI(kc)`|`RCMD(kc)`, `LWIN(kc)` |Hold Right GUI and press `kc` |
|`SGUI(kc)`|`SCMD(kc)`, `SWIN(kc)` |Hold Left Shift and GUI and press `kc` |
|`LCA(kc)` | |Hold Left Control and Alt and press `kc` |
|`LCAG(kc)`| |Hold Left Control, Alt and GUI and press `kc` |
|`MEH(kc)` | |Hold Left Control, Shift and Alt and press `kc` |
|`HYPR(kc)`| |Hold Left Control, Shift, Alt and GUI and press `kc`|
|`KC_MEH` | |Left Control, Shift and Alt |
|`KC_HYPR` | |Left Control, Shift, Alt and GUI |
## [Mod-Tap Keys](feature_advanced_keycodes.md#mod-tap)
|Key |Aliases |Description |
|------------|---------------------------------------|-------------------------------------------------------|
|`LCTL_T(kc)`|`CTL_T(kc)` |Left Control when held, `kc` when tapped |
|`RCTL_T(kc)`| |Right Control when held, `kc` when tapped |
|`LSFT_T(kc)`|`SFT_T(kc)` |Left Shift when held, `kc` when tapped |
|`RSFT_T(kc)`| |Right Shift when held, `kc` when tapped |
|`LALT_T(kc)`|`ALT_T(kc)` |Left Alt when held, `kc` when tapped |
|`RALT_T(kc)`|`ALGR_T(kc)` |Right Alt when held, `kc` when tapped |
|`LGUI_T(kc)`|`LCMD_T(kc)`, `RWIN_T(kc)`, `GUI_T(kc)`|Left GUI when held, `kc` when tapped |
|`RGUI_T(kc)`|`RCMD_T(kc)`, `RWIN_T(kc)` |Right GUI when held, `kc` when tapped |
|`C_S_T(kc)` | |Left Control and Shift when held, `kc` when tapped |
|`MEH_T(kc)` | |Left Control, Shift and Alt when held, `kc` when tapped|
|`LCAG_T(kc)`| |Left Control, Alt and GUI when held, `kc` when tapped |
|`RCAG_T(kc)`| |Right Control, Alt and GUI when held, `kc` when tapped |
|`ALL_T(kc)` | |Left Control, Shift, Alt and GUI when held, `kc` when tapped - more info [here](http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/)|
|`SGUI_T(kc)`|`SCMD_T(kc)`, `SWIN_T(kc)` |Left Shift and GUI when held, `kc` when tapped |
|`LCA_T(kc)` | |Left Control and Alt when held, `kc` when tapped |
|Key |Aliases |Description |
|------------|-----------------------------------------------------------------|-------------------------------------------------------|
|`LCTL_T(kc)`|`CTL_T(kc)` |Left Control when held, `kc` when tapped |
|`LSFT_T(kc)`|`SFT_T(kc)` |Left Shift when held, `kc` when tapped |
|`LALT_T(kc)`|`ALT_T(kc)` |Left Alt when held, `kc` when tapped |
|`LGUI_T(kc)`|`LCMD_T(kc)`, `LWIN_T(kc)`, `GUI_T(kc)`, `CMD_T(kc)`, `WIN_T(kc)`|Left GUI when held, `kc` when tapped |
|`RCTL_T(kc)`| |Right Control when held, `kc` when tapped |
|`RSFT_T(kc)`| |Right Shift when held, `kc` when tapped |
|`RALT_T(kc)`|`ALGR_T(kc)` |Right Alt when held, `kc` when tapped |
|`RGUI_T(kc)`|`RCMD_T(kc)`, `RWIN_T(kc)` |Right GUI when held, `kc` when tapped |
|`SGUI_T(kc)`|`SCMD_T(kc)`, `SWIN_T(kc)` |Left Shift and GUI when held, `kc` when tapped |
|`LCA_T(kc)` | |Left Control and Alt when held, `kc` when tapped |
|`LCAG_T(kc)`| |Left Control, Alt and GUI when held, `kc` when tapped |
|`RCAG_T(kc)`| |Right Control, Alt and GUI when held, `kc` when tapped |
|`C_S_T(kc)` | |Left Control and Shift when held, `kc` when tapped |
|`MEH_T(kc)` | |Left Control, Shift and Alt when held, `kc` when tapped|
|`HYPR_T(kc)`|`ALL_T(kc)` |Left Control, Shift, Alt and GUI when held, `kc` when tapped - more info [here](http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/)|
## [RGB Lighting](feature_rgblight.md)
@ -431,18 +429,6 @@ This is a reference only. Each group of keys links to the page documenting their
|`KC_RIGHT_ANGLE_BRACKET`|`KC_RABK`, `KC_GT` |`>` |
|`KC_QUESTION` |`KC_QUES` |`?` |
## [Switching and Toggling Layers](feature_advanced_keycodes.md#switching-and-toggling-layers)
|Key |Description |
|----------------|----------------------------------------------------------------------------------|
|`LT(layer, kc)` |Turn on `layer` when held, `kc` when tapped |
|`TO(layer)` |Turn on `layer` when pressed |
|`MO(layer)` |Momentarily turn on `layer` when pressed (requires `KC_TRNS` on destination layer)|
|`DF(layer)` |Set the base (default) layer |
|`TG(layer)` |Toggle `layer` on or off |
|`TT(layer)` |Normally acts like MO unless it's tapped multiple times, which toggles `layer` on |
|`LM(layer, mod)`|Momentarily turn on `layer` (like MO) with `mod` active as well. |
## [One Shot Keys](feature_advanced_keycodes.md#one-shot-keys)
|Key |Description |
@ -450,7 +436,6 @@ This is a reference only. Each group of keys links to the page documenting their
|`OSM(mod)` |Hold `mod` for one keypress |
|`OSL(layer)`|Switch to `layer` for one keypress|
## [Swap Hands](feature_swap_hands.md)
|Key |Description |
@ -465,7 +450,15 @@ This is a reference only. Each group of keys links to the page documenting their
## [Unicode Support](feature_unicode.md)
|Key |Aliases| |
|------------|-------|-------------------------------------------------|
|`UNICODE(n)`|`UC(n)`|Send Unicode character `n` |
|`X(n)` | |Send Unicode character `n` via a different method|
|Key |Aliases |Description |
|----------------------|---------|----------------------------------------------------------------|
|`UC(c)` | |Send Unicode code point `c` |
|`X(i)` | |Send Unicode code point at index `i` in `unicode_map` |
|`XP(i, j)` | |Send Unicode code point at index `i`, or `j` if Shift/Caps is on|
|`UNICODE_MODE_FORWARD`|`UC_MOD` |Cycle through selected input modes |
|`UNICODE_MODE_REVERSE`|`UC_RMOD`|Cycle through selected input modes in reverse |
|`UNICODE_MODE_OSX` |`UC_M_OS`|Switch to macOS input |
|`UNICODE_MODE_LNX` |`UC_M_LN`|Switch to Linux input |
|`UNICODE_MODE_WIN` |`UC_M_WI`|Switch to Windows input |
|`UNICODE_MODE_BSD` |`UC_M_BS`|Switch to BSD input (not implemented) |
|`UNICODE_MODE_WINC` |`UC_M_WC`|Switch to Windows input using WinCompose |

+ 50
- 50
docs/keycodes_basic.md View File

@ -97,14 +97,14 @@ The basic set of keycodes are based on the [HID Keyboard/Keypad Usage Page (0x07
## Lock Keys
|Key |Aliases |Description |
|-------------------|--------------------|-------------------------|
|`KC_CAPSLOCK` |`KC_CLCK`, `KC_CAPS`|Caps Lock |
|`KC_SCROLLLOCK` |`KC_SLCK` |Scroll Lock |
|`KC_NUMLOCK` |`KC_NLCK` |Keypad Num Lock and Clear|
|`KC_LOCKING_CAPS` |`KC_LCAP` |Locking Caps Lock |
|`KC_LOCKING_NUM` |`KC_LNUM` |Locking Num Lock |
|`KC_LOCKING_SCROLL`|`KC_LSCR` |Locking Scroll Lock |
|Key |Aliases |Description |
|-------------------|--------------------|------------------------------------|
|`KC_CAPSLOCK` |`KC_CLCK`, `KC_CAPS`|Caps Lock |
|`KC_SCROLLLOCK` |`KC_SLCK`, `KC_BRMD`|Scroll Lock, Brightness Down (macOS)|
|`KC_NUMLOCK` |`KC_NLCK` |Keypad Num Lock and Clear |
|`KC_LOCKING_CAPS` |`KC_LCAP` |Locking Caps Lock |
|`KC_LOCKING_NUM` |`KC_LNUM` |Locking Num Lock |
|`KC_LOCKING_SCROLL`|`KC_LSCR` |Locking Scroll Lock |
## Modifiers
@ -144,48 +144,48 @@ The basic set of keycodes are based on the [HID Keyboard/Keypad Usage Page (0x07
## Commands
|Key |Aliases |Description |
|------------------|-------------------|------------------------------|
|`KC_PSCREEN` |`KC_PSCR` |Print Screen |
|`KC_PAUSE` |`KC_PAUS`, `KC_BRK`|Pause |
|`KC_INSERT` |`KC_INS` |Insert |
|`KC_HOME` | |Home |
|`KC_PGUP` | |Page Up |
|`KC_DELETE` |`KC_DEL` |Forward Delete |
|`KC_END` | |End |
|`KC_PGDOWN` |`KC_PGDN` |Page Down |
|`KC_RIGHT` |`KC_RGHT` |Right Arrow |
|`KC_LEFT` | |Left Arrow |
|`KC_DOWN` | |Down Arrow |
|`KC_UP` | |Up Arrow |
|`KC_APPLICATION` |`KC_APP` |Application (Windows Menu Key)|
|`KC_POWER` | |System Power (macOS/Linux) |
|`KC_EXECUTE` |`KC_EXEC` |Execute |
|`KC_HELP` | |Help |
|`KC_MENU` | |Menu |
|`KC_SELECT` |`KC_SLCT` |Select |
|`KC_STOP` | |Stop |
|`KC_AGAIN` |`KC_AGIN` |Again |
|`KC_UNDO` | |Undo |
|`KC_CUT` | |Cut |
|`KC_COPY` | |Copy |
|`KC_PASTE` |`KC_PSTE` |Paste |
|`KC_FIND` | |Find |
|`KC__MUTE` | |Mute (macOS) |
|`KC__VOLUP` | |Volume Up (macOS) |
|`KC__VOLDOWN` | |Volume Down (macOS) |
|`KC_ALT_ERASE` |`KC_ERAS` |Alternate Erase |
|`KC_SYSREQ` | |SysReq/Attention |
|`KC_CANCEL` | |Cancel |
|`KC_CLEAR` |`KC_CLR` |Clear |
|`KC_PRIOR` | |Prior |
|`KC_RETURN` | |Return |
|`KC_SEPARATOR` | |Separator |
|`KC_OUT` | |Out |
|`KC_OPER` | |Oper |
|`KC_CLEAR_AGAIN` | |Clear/Again |
|`KC_CRSEL` | |CrSel/Props |
|`KC_EXSEL` | |ExSel |
|Key |Aliases |Description |
|------------------|------------------------------|------------------------------|
|`KC_PSCREEN` |`KC_PSCR` |Print Screen |
|`KC_PAUSE` |`KC_PAUS`, `KC_BRK`, `KC_BRMU`|Pause, Brightness Up (macOS) |
|`KC_INSERT` |`KC_INS` |Insert |
|`KC_HOME` | |Home |
|`KC_PGUP` | |Page Up |
|`KC_DELETE` |`KC_DEL` |Forward Delete |
|`KC_END` | |End |
|`KC_PGDOWN` |`KC_PGDN` |Page Down |
|`KC_RIGHT` |`KC_RGHT` |Right Arrow |
|`KC_LEFT` | |Left Arrow |
|`KC_DOWN` | |Down Arrow |
|`KC_UP` | |Up Arrow |
|`KC_APPLICATION` |`KC_APP` |Application (Windows Menu Key)|
|`KC_POWER` | |System Power (macOS/Linux) |
|`KC_EXECUTE` |`KC_EXEC` |Execute |
|`KC_HELP` | |Help |
|`KC_MENU` | |Menu |
|`KC_SELECT` |`KC_SLCT` |Select |
|`KC_STOP` | |Stop |
|`KC_AGAIN` |`KC_AGIN` |Again |
|`KC_UNDO` | |Undo |
|`KC_CUT` | |Cut |
|`KC_COPY` | |Copy |
|`KC_PASTE` |`KC_PSTE` |Paste |
|`KC_FIND` | |Find |
|`KC__MUTE` | |Mute (macOS) |
|`KC__VOLUP` | |Volume Up (macOS) |
|`KC__VOLDOWN` | |Volume Down (macOS) |
|`KC_ALT_ERASE` |`KC_ERAS` |Alternate Erase |
|`KC_SYSREQ` | |SysReq/Attention |
|`KC_CANCEL` | |Cancel |
|`KC_CLEAR` |`KC_CLR` |Clear |
|`KC_PRIOR` | |Prior |
|`KC_RETURN` | |Return |
|`KC_SEPARATOR` | |Separator |
|`KC_OUT` | |Out |
|`KC_OPER` | |Oper |
|`KC_CLEAR_AGAIN` | |Clear/Again |
|`KC_CRSEL` | |CrSel/Props |
|`KC_EXSEL` | |ExSel |
## Media Keys


+ 4
- 60
docs/keymap.md View File

@ -1,6 +1,6 @@
# Keymap Overview
QMK keymaps are defined inside a C source file. The data structure is an array of arrays. The outer array is a list of layer arrays while the inner layer array is a list of keys. Most keyboards define a `KEYMAP()` macro to help you create this array of arrays.
QMK keymaps are defined inside a C source file. The data structure is an array of arrays. The outer array is a list of layer arrays while the inner layer array is a list of keys. Most keyboards define a `LAYOUT()` macro to help you create this array of arrays.
## Keymap and Layers
@ -119,7 +119,7 @@ The main part of this file is the `keymaps[]` definition. This is where you list
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
After this you'll find a list of KEYMAP() macros. A KEYMAP() is simply a list of keys to define a single layer. Typically you'll have one or more "base layers" (such as QWERTY, Dvorak, or Colemak) and then you'll layer on top of that one or more "function" layers. Due to the way layers are processed you can't overlay a "lower" layer on top of a "higher" layer.
After this you'll find a list of LAYOUT() macros. A LAYOUT() is simply a list of keys to define a single layer. Typically you'll have one or more "base layers" (such as QWERTY, Dvorak, or Colemak) and then you'll layer on top of that one or more "function" layers. Due to the way layers are processed you can't overlay a "lower" layer on top of a "higher" layer.
`keymaps[][MATRIX_ROWS][MATRIX_COLS]` in QMK holds the 16 bit action code (sometimes referred as the quantum keycode) in it. For the keycode representing typical keys, its high byte is 0 and its low byte is the USB HID usage ID for keyboard.
@ -131,7 +131,7 @@ Here is an example of the Clueboard's base layer:
/* Keymap _BL: Base Layer (Default Layer)
*/
[_BL] = KEYMAP(
[_BL] = LAYOUT(
F(0), KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_GRV, KC_BSPC, KC_PGUP, \
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, \
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT, \
@ -149,7 +149,7 @@ Some interesting things to note about this:
Our function layer is, from a code point of view, no different from the base layer. Conceptually, however, you will build that layer as an overlay, not a replacement. For many people this distinction does not matter, but as you build more complicated layering setups it matters more and more.
[_FL] = KEYMAP(
[_FL] = LAYOUT(
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, KC_DEL, BL_STEP, \
_______, _______, _______,_______,_______,_______,_______,_______,KC_PSCR,KC_SLCK, KC_PAUS, _______, _______, _______, _______, \
_______, _______, MO(_CL),_______,_______,_______,_______,_______,_______,_______, _______, _______, _______, _______, \
@ -161,62 +161,6 @@ Some interesting things to note:
* We have used our `_______` definition to turn `KC_TRNS` into `_______`. This makes it easier to spot the keys that have changed on this layer.
* While in this layer if you press one of the `_______` keys it will activate the key in the next lowest active layer.
### Custom Functions
At the bottom of the file we've defined a single custom function. This function defines a key that sends `KC_ESC` when pressed without modifiers and `KC_GRAVE` when modifiers are held. There are a couple pieces that need to be in place for this to work, and we will go over both of them.
#### `fn_actions[]`
We define the `fn_actions[]` array to point to custom functions. `F(N)` in a keymap will call element N of that array. For the Clueboard's that looks like this:
const uint16_t PROGMEM fn_actions[] = {
[0] = ACTION_FUNCTION(0), // Calls action_function()
};
In this case we've instructed QMK to call the `ACTION_FUNCTION` callback, which we will define in the next section.
> This `fn_actions[]` interface is mostly for backward compatibility. In QMK, you don't need to use `fn_actions[]`. You can directly use `ACTION_FUNCTION(N)` or any other action code value itself normally generated by the macro in `keymaps[][MATRIX_ROWS][MATRIX_COLS]`. N in `F(N)` can only be 0 to 31. Use of the action code directly in `keymaps` unlocks this limitation.
You can get a full list of Action Functions in [action_code.h](https://github.com/qmk/qmk_firmware/blob/master/tmk_core/common/action_code.h).
#### `action_function()`
To actually handle the keypress event we define an `action_function()`. This function will be called when the key is pressed, and then again when the key is released. We have to handle both situations within our code, as well as determining whether to send/release `KC_ESC` or `KC_GRAVE`.
void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) {
static uint8_t mods_pressed;
switch (id) {
case 0:
/* Handle the combined Grave/Esc key
*/
mods_pressed = get_mods()&GRAVE_MODS; // Check to see what mods are pressed
if (record->event.pressed) {
/* The key is being pressed.
*/
if (mods_pressed) {
add_key(KC_GRV);
send_keyboard_report();
} else {
add_key(KC_ESC);
send_keyboard_report();
}
} else {
/* The key is being released.
*/
if (mods_pressed) {
del_key(KC_GRV);
send_keyboard_report();
} else {
del_key(KC_ESC);
send_keyboard_report();
}
}
break;
}
}
# Nitty Gritty Details
This should have given you a basic overview for creating your own keymap. For more details see the following resources:


+ 8
- 3
docs/newbs.md View File

@ -6,13 +6,18 @@ Not sure if your keyboard can run QMK? If it's a mechanical keyboard you built y
## Overview
There are 5 main sections to this guide:
There are 7 main sections to this guide:
* [Getting Started](newbs_getting_started.md)
* [Building Your First Firmware](newbs_building_firmware.md)
* [Building Your First Firmware using the command line](newbs_building_firmware.md)
* [Building Your First Firmware using the online GUI](newbs_building_firmware_configurator.md)
* [Flashing Firmware](newbs_flashing.md)
* [Testing and Debugging](newbs_testing_debugging.md)
* [Best Practices](newbs_best_practices.md)
* [Git Best Practices](newbs_best_practices.md)
* [Learn More with these Resources](newbs_learn_more_resources.md)
This guide is focused on helping someone who has never compiled software before. It makes choices and recommendations based on that viewpoint. There are alternative methods for many of these procedures, and we support most of those alternatives. If you have any doubt about how to accomplish a task you can [ask us for guidance](getting_started_getting_help.md).
## Additional Resources
* [Thomas Baart's QMK Basics Blog](https://thomasbaart.nl/category/mechanical-keyboards/firmware/qmk/qmk-basics/) – A user-created blog covering the basics of how to use QMK Firmware, as seen from a new user's perspective.

+ 105
- 0
docs/newbs_building_firmware_configurator.md View File

@ -0,0 +1,105 @@
# QMK Configurator
The [QMK Configurator](https://config.qmk.fm) is an online graphical user interface that generates QMK Firmware hex files.
?> **Please follow these steps in order.**
Watch the [Video Tutorial](https://youtu.be/7RH-1pAbjvw)
The QMK Configurator works best with Chrome/Firefox.
!> **Files from other tools such as KLE, or kbfirmware will not be compatible with QMK Configurator. Do not load them, do not import them. QMK Configurator is a DIFFERENT tool. **
## Selecting your keyboard
Click the drop down box and select the keyboard you want to create a keymap for.
?> If your keyboard has several versions, make sure you select the correct one.**
I'll say that again because it's important
!> **MAKE SURE YOU SELECT THE RIGHT VERSION!**
If your keyboard has been advertised to be powered by QMK but is not in the list, chances are a developer hasn't gotten to it yet or we haven't had a chance to merge it in yet. File an issue at [qmk_firmware](https://github.com/qmk/qmk_firmware/issues) requesting to support that particular keyboard, if there is no active [Pull Request](https://github.com/qmk/qmk_firmware/pulls?q=is%3Aopen+is%3Apr+label%3Akeyboard) for it. There are also QMK powered keyboards that are in their manufacturer's own github accounts. Double check for that as well.
## Selecting your keyboard layout
Choose the layout that best represents the keymap you want to create. Some keyboards do not have enough layouts or correct layouts defined yet. They will be supported in the future.
## Keymap Name
Call this keymap what you want.
?> If you are running into issues when compiling, it may be worth changing this name, as it may already exist in the QMK Firmware repo.
## Creating Your Keymap
Keycode Entry is accomplished in 3 ways.
1. Drag and dropping
2. Clicking on an empty spot on the layout and clicking the keycode you desire
3. Clicking on an empty spot on the layout, pressing the physical key on your keyboard.
Hover your mouse over a key and a short blurb will tell you what that keycode does. For a more verbose description please see
[Basic Keycode Reference](https://docs.qmk.fm/#/keycodes_basic)
[Advanced Keycode Reference](https://docs.qmk.fm/#/feature_advanced_keycodes)
In the event that you can't find a layout that supports your keymap, for example three spots for spacebar, or two spots for backspace, or 2 spots for shift etc etc, Fill them ALL up.
### Example:
3 spots for spacebar: Fill them ALL with spacebar
2 spots for backspace: Fill them BOTH with backspace
2 spots for right shift: Fill them BOTH with right shift
1 spot for left shift and 1 spot for iso support: Fill them both with left shift
5 spots, but only 4 keys: Guess and check or ask someone who has done it before.
## Saving Your Keymap for Future Edits
When you're satisfied with your keymap or just want to work on it later, press the `Export Keymap` button. It will save your keymap as the name you chose above appended with .json.
You can then load this .json file in the future by pressing the `Import Keymap` button.
!> **CAUTION:** This is not the same type of .json file used for kbfirmware.com or any other tool. If you try to use this for those tools, or the .json from those tools with QMK Configurator, there is a chance your keyboard will **explode**.
## Generating your firmware file
Press the green `Compile` button.
When the compilation is done, you will be able to press the green `Download Firmware` button.
## Flashing Your Keyboard
Please refer to [Flashing Firmware](newbs_flashing.md)
## Troubleshooting
#### My .json file is not working
If the .json file was generated with QMK Configurator, congratulations you have stumbled upon a bug. File an issue at [qmk_configurator](https://github.com/qmk/qmk_configurator/issues)
If not....how did you miss my big bold message at the top saying not to use other .json files?
#### There are extra spaces in my layout? What do I do?
If you're referring to having three spots for space bar, the best course of action is to just fill them all with space bar. The same can be done for backspace and shifts
#### What is the keycode for.......
Please see
[Basic Keycode Reference](https://docs.qmk.fm/#/keycodes_basic)
[Advanced Keycode Reference](https://docs.qmk.fm/#/feature_advanced_keycodes)
#### It won't compile
Please double check the other layers of your keymap to make sure there are no random keys present.
## Problems and Bugs
We are always accepting customer requests and bug reports. Please file them at [qmk_configurator](https://github.com/qmk/qmk_configurator/issues)

+ 71
- 4
docs/newbs_flashing.md View File

@ -86,7 +86,7 @@ If you know what bootloader that you're using, then when compiling the firmware,
### DFU
For the DFU bootloader, when you're ready to compile and flash your firmware, open up your terminal window and run the built command:
For the DFU bootloader, when you're ready to compile and flash your firmware, open up your terminal window and run the build command:
make <my_keyboard>:<my_keymap>:dfu
@ -131,9 +131,19 @@ If you have any issues with this, you may need to this:
sudo make <my_keyboard>:<my_keymap>:dfu
#### DFU commands
There are a number of DFU commands that you can use to flash firmware to a DFU device:
* `:dfu` - This is the normal option and waits until a DFU device is available, and then flashes the firmware. This will check every 5 seconds, to see if a DFU device has appeared.
* `:dfu-ee` - This flashes an `eep` file instead of the normal hex. This is uncommon.
* `:dfu-split-left` - This flashes the normal firmware, just like the default option (`:dfu`). However, this also flashes the "Left Side" EEPROM file for split keyboards. _This is ideal for Elite C based split keyboards._
* `:dfu-split-right` - This flashes the normal firmware, just like the default option (`:dfu`). However, this also flashes the "Right Side" EEPROM file for split keyboards. _This is ideal for Elite C based split keyboards._
### Caterina
For Arduino boards and their close (such as the SparkFun ProMicro), when you're ready to compile and flash your firmware, open up your terminal window and run the built command:
For Arduino boards and their clones (such as the SparkFun ProMicro), when you're ready to compile and flash your firmware, open up your terminal window and run the build command:
make <my_keyboard>:<my_keymap>:avrdude
@ -199,9 +209,17 @@ If you have any issues with this, you may need to this:
sudo make <my_keyboard>:<my_keymap>:avrdude
Additionally, if you want to flash multiple boards, use the following command:
make <keyboard>:<keymap>:avrdude-loop
When you're done flashing boards, you'll need to hit Ctrl + C or whatever the correct keystroke is for your operating system to break the loop.
## HalfKay
For the PJRC devices (Teensy's), when you're ready to compile and flash your firmware, open up your terminal window and run the built command:
For the PJRC devices (Teensy's), when you're ready to compile and flash your firmware, open up your terminal window and run the build command:
make <my_keyboard>:<my_keymap>:teensy
@ -226,12 +244,61 @@ Waiting for Teensy device...
```
Found HalfKay Bootloader
Read "./.build/ergodox_ez_drashna.hex": 28532 bytes, 88.5% usage
Read "./.build/ergodox_ez_xyverz.hex": 28532 bytes, 88.5% usage
Programming............................................................................................................................................................................
...................................................
Booting
```
## STM32 (ARM)
For a majority of ARM boards (including the Proton C, Planck Rev 6, and Preonic Rev 3), when you're ready to compile and flash your firmware, open up your terminal window and run the build command:
make <my_keyboard>:<my_keymap>:dfu-util
For example, if your keymap is named "xyverz" and you're building a keymap for the Planck Revision 6 keyboard, you'll use this command and then reboot the keyboard to the bootloader (before it finishes compiling):
make planck/rev6:xyverz:dfu-util
Once the firmware finishes compiling, it will output something like this:
```
Linking: .build/planck_rev6_xyverz.elf [OK]
Creating binary load file for flashing: .build/planck_rev6_xyverz.bin [OK]
Creating load file for flashing: .build/planck_rev6_xyverz.hex [OK]
Size after:
text data bss dec hex filename
0 41820 0 41820 a35c .build/planck_rev6_xyverz.hex
Copying planck_rev6_xyverz.bin to qmk_firmware folder [OK]
dfu-util 0.9
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
Invalid DFU suffix signature
A valid DFU suffix will be required in a future dfu-util release!!!
Opening DFU capable USB device...
ID 0483:df11
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuERROR, status = 10
dfuERROR, clearing status
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 2048
DfuSe interface name: "Internal Flash "
Downloading to address = 0x08000000, size = 41824
Download [=========================] 100% 41824 bytes
Download done.
File downloaded successfully
Transitioning to dfuMANIFEST state
```
## Test It Out!


+ 8
- 3
docs/newbs_getting_started.md View File

@ -6,7 +6,10 @@ QMK tries to put a lot of power into your hands by making easy things easy, and
# Getting Started
Before you can build keymaps, you need to install some software and set up your build environment. This only has to be done once no matter how many keyboards you plan to compile firmware for.
Before you can build keymaps, you need to install some software and set up your build environment. This only has to be done once no matter how many keyboards you plan to compile firmware for.
If you would prefer a more graphical user interface approach, please consider using the online [QMK Configurator](https://config.qmk.fm). Please refer to [Building Your First Firmware using the online GUI](newbs_building_firmware_configurator.md).
## Download Software
@ -63,8 +66,10 @@ You will need to install Git. It's very likely that you already have it, but if
Once you have set up your Linux/Unix environment, you are ready to download QMK. We will do this by using Git to "clone" the QMK repository. Open a Terminal or MSYS2 MinGW window and leave it open for the remainder of this guide. Inside that window run these two commands:
git clone https://github.com/qmk/qmk_firmware.git
cd qmk_firmware
```shell
git clone --recurse-submodules https://github.com/qmk/qmk_firmware.git
cd qmk_firmware
```
?> If you already know [how to use GitHub](getting_started_github.md), we recommend that you create and clone your own fork instead. If you don't know what that means, you can safely ignore this message.


+ 11
- 1
docs/newbs_testing_debugging.md View File

@ -15,7 +15,17 @@ Note: These programs are not provided by or endorsed by QMK.
## Debugging With QMK Toolbox
[QMK Toolbox](https://github.com/qmk/qmk_toolbox) will show messages from your keyboard if you have `CONSOLE_ENABLE = yes` in your `rules.mk`. By default the output is very limited, but you can turn on debug mode to increase the amount of debug output. Use the `DEBUG` keycode in your keymap, or use the [Command](feature_command.md) feature to enable debug mode.
[QMK Toolbox](https://github.com/qmk/qmk_toolbox) will show messages from your keyboard if you have `CONSOLE_ENABLE = yes` in your `rules.mk`. By default the output is very limited, but you can turn on debug mode to increase the amount of debug output. Use the `DEBUG` keycode in your keymap, use the [Command](feature_command.md) feature to enable debug mode, or add the following code to your keymap.
```c
void keyboard_post_init_user(void) {
// Customise these values to desired behaviour
debug_enable=true;
debug_matrix=true;
//debug_keyboard=true;
//debug_mouse=true;
}
```
<!-- FIXME: Describe the debugging messages here. -->


docs/eclipse.md → docs/other_eclipse.md View File


+ 117
- 0
docs/other_vscode.md View File

@ -0,0 +1,117 @@
# Setting up Visual Studio Code for QMK Development
[Visual Studio Code](https://code.visualstudio.com/) (VS Code) is an open-source code editor that supports many different programming languages.
Using a full-featured editor such as VS Code provides many advantages over a plain text editor, such as:
* intelligent code completion
* convenient navigation in the code
* refactoring tools
* build automation (no need for the command-line)
* a graphical front end for GIT
* many other tools such as debugging, code formatting, showing call hierarchies etc.
The purpose of this page is to document how to set up VS Code for developing QMK Firmware.
This guide covers how to configure everything needed on Windows and Ubuntu 18.04
# Set up VS Code
Before starting, you will want to make sure that you have all of the build tools set up, and QMK Firmware cloned. Head to the the [Newbs Getting Started Guide](newbs_getting_started.md) to get things set up, if you haven't already.
## Windows
### Prerequisites
* [Git for Windows](https://git-scm.com/download/win) (This link will prompt to save/run the installer)
1. Disable all of the options but `Git LFS (Large File Support)` and `Check daily for Git for Windows updates`.
2. Set the default editor to `Use Visual Studio Code as Git's default editor`
3. Select the `Use Git from Git Bash only` option, since that's the option that you should use here.
4. For the `Choosing HTTPS transport backend`, either option should be fine.
5. Select the `Checkout as-is, commit Unix-style line endings` option. QMK Firmware uses Unix style commits.
6. For the extra options, leave the default options as is.
This software is needed for Git support in VS Code. It may be possible to not include this, but it is much simpler to just use this.
* [Git Credential Manager for Windows](https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases) (Optional)
This software provides better support for Git by providing secure storage for git credentials, MFA and personal access token generation.
This isn't strictly needed, but we would recommend it.
### Installing VS Code
1. Head to [VS Code](https://code.visualstudio.com/) and download the installer
2. Run the installer
This part is super simple. However, there is some configuration that we need to do to ensure things are configured correctly.
### Configuring VS Code
First, we need to set up IntelliSense. This isn't strictly required, but it will make your life a LOT easier. To do this, we need to create the `.vscode/c_cpp_properies.json` file in the QMK Firmware folder, You can do this all manually, but I've done most of the work already.
Grab [this file](https://gist.github.com/drashna/48e2c49ce877be592a1650f91f8473e8) and save it. You may need to edit this file, if you didn't install MSYS2 to the default location, or are using WSL/LxSS.
Once you have saved this file, you will need to reload VS Code, if it was already running.
?> You should see an `extensions.json` and `settings.json` file in the `.vscode` folder, as well.
Now, we will set up the MSYS2 window to show up in VSCode as the integrated terminal. This has a number of advantages. Mostly, you can control+click on errors and jump to those files. This makes debugging much easier. It's also nice, in that you don't have to jump to another window.
1. Click <kbd><kbd>File</kbd> > <kbd>Preferences ></kbd> > <kbd>Settings</kbd> </kbd>
2. Click on the <kbd>{}</kbd> button, in the top right to open the `settings.json` file.
3. Set the file's content to:
```json
{
"terminal.integrated.shell.windows": "C:\\msys64\\usr\\bin\\bash.exe",
"terminal.integrated.env.windows": {
"MSYSTEM": "MINGW64",
"CHERE_INVOKING": "1"
},
"terminal.integrated.shellArgs.windows": [
"--login"
],
"terminal.integrated.cursorStyle": "line"
}
```
If there are settings here already, then just add everything between the first and last curly brackets.
?> If you installed MSYS2 to a different folder, then you'll need to change the path for `terminal.integrated.shell.windows` to the correct path for your system.
4. Hit Ctrl-` (grave) to bring up the terminal.
This should start the terminal in the workspace's folder (so the `qmk_firmware` folder), and then you can compile your keyboard.
## Every other Operating System
1. Head to [VS Code](https://code.visualstudio.com/) and download the installer
2. Run the installer
3. That's it
No, really, that's it. The paths needed are already included when installing the packages, and it is much better about detecting the current workspace files and parsing them for IntelliSense.
## Plugins
There are a number of extensions that you may want to install:
* [Git Extension Pack](https://marketplace.visualstudio.com/items?itemName=donjayamanne.git-extension-pack) -
This installs a bunch of Git related tools that may make using Git with QMK Firmware easier.
* [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) - _[Optional]_ - Helps to keep the code to the QMK Coding Conventions.
* [Bracket Pair Colorizer 2](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2) - _[Optional]_ - This color codes the brackets in your code, to make it easier to reference nested code.
* [Github Markdown Preview](https://marketplace.visualstudio.com/items?itemName=bierner.github-markdown-preview) - _[Optional]_ - Makes the markdown preview in VS Code more like GitHub's.
* [VS Live Share Extension Pack](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare-pack) - _[Optional]_ - This extension allows somebody else to access your workspace (or you to access somebody else's workspace) and help out. This is great if you're having issues and need some help from somebody.
* [VIM Keymap](https://marketplace.visualstudio.com/items?itemName=GiuseppeCesarano.vim-keymap) - _[Optional]_ - For those that prefer VIM style keybindings. There are other options for this, too.
* [Travis CI Status](https://marketplace.visualstudio.com/items?itemName=felixrieseberg.vsc-travis-ci-status) - _[Optional]_ - This shows the current Travis CI status, if you have it set up.
Restart once you've installed any extensions
# Configure VS Code for QMK
1. Click <kbd><kbd>File</kbd> > <kbd>Open Folder</kbd></kbd>
2. Open the QMK Firmware folder that you cloned from GitHub.
3. Click <kbd><kbd>File</kbd> > <kbd>Save Workspace As...</kbd></kbd>
And now you're ready to code QMK Firmware in VS Code

+ 21
- 9
docs/porting_your_keyboard_to_qmk_(arm_and_other_chibios_cpus).md View File

@ -1,14 +1,24 @@
Setting up your ARM based PCB is a little more involved than an Atmel MCU, but is easy enough. Start by using `util/new_project.sh <keyboard>` to create a new project:
Setting up your ARM based PCB is a little more involved than an Atmel MCU, but is easy enough. Start by running `util/new_keyboard.sh`:
```
$ util/new_project.sh simontester
######################################################
# /keyboards/simontester project created. To start
# working on things, cd into keyboards/simontester
######################################################
```
$ ./util/new_keyboard.sh
Generating a new QMK keyboard directory
Keyboard Name: mycoolkb
Keyboard Type [avr]:
Your Name [John Smith]:
Copying base template files... done
Copying avr template files... done
Renaming keyboard files... done
Replacing %KEYBOARD% with mycoolkb... done
Replacing %YOUR_NAME% with John Smith... done
Created a new keyboard called mycoolkb.
To start working on things, cd into keyboards/mycoolkb,
or open the directory in your favourite text editor.
```
# END OF NEW ARM DOC, OLD ATMEL DOC FOLLOWS
@ -22,6 +32,8 @@ The `MATRIX_ROW_PINS` and `MATRIX_COL_PINS` are the pins your MCU uses on each r
For the `DIODE_DIRECTION`, most hand-wiring guides will instruct you to wire the diodes in the `COL2ROW` position, but it's possible that they are in the other - people coming from EasyAVR often use `ROW2COL`. Nothing will function if this is incorrect.
To configure a keyboard where each switch is connected to a separate pin and ground instead of sharing row and column pins, use `DIRECT_PINS`. The mapping defines the pins of each switch in rows and columns, from left to right. Must conform to the sizes within `MATRIX_ROWS` and `MATRIX_COLS`, use `NO_PIN` to fill in blank spaces. Overrides the behaviour of `DIODE_DIRECTION`, `MATRIX_ROW_PINS` and `MATRIX_COL_PINS`.
`BACKLIGHT_PIN` is the pin that your PWM-controlled backlight (if one exists) is hooked-up to. Currently only B5, B6, and B7 are supported.
`BACKLIGHT_BREATHING` is a fancier backlight feature that adds breathing/pulsing/fading effects to the backlight. It uses the same timer as the normal backlight. These breathing effects must be called by code in your keymap.
@ -54,10 +66,10 @@ This is where all of the custom logic for your keyboard goes - you may not need
## `/keyboards/<keyboard>/<keyboard>.h`
Here is where you can (optionally) define your `KEYMAP` function to remap your matrix into a more readable format. With ortholinear boards, this isn't always necessary, but it can help to accommodate the dead spots on your matrix, where there are keys that take up more than one space (2u, staggering, 6.25u, etc). The example shows the difference between the physical keys, and the matrix design:
Here is where you can (optionally) define your `LAYOUT` function to remap your matrix into a more readable format. With ortholinear boards, this isn't always necessary, but it can help to accommodate the dead spots on your matrix, where there are keys that take up more than one space (2u, staggering, 6.25u, etc). The example shows the difference between the physical keys, and the matrix design:
```
#define KEYMAP( \
#define LAYOUT( \
k00, k01, k02, \
k10, k11 \
) \


+ 73
- 0
docs/reference_info_json.md View File

@ -0,0 +1,73 @@
# `info.json`
This file is used by the [QMK API](https://github.com/qmk/qmk_api). It contains the information [QMK Configurator](https://config.qmk.fm/) needs to display a representation of your keyboard. You can also set metadata here.
You can create `info.json` files at every level under `qmk_firmware/keyboards/<name>` to specify this metadata. These files are combined, with more specific files overriding keys in less specific files. This means you do not need to duplicate your metadata information. For example, `qmk_firmware/keyboards/clueboard/info.json` specifies `manufacturer` and `maintainer`, while `qmk_firmware/keyboards/clueboard/66/info.json` specifies more specific information about Clueboard 66%.
## `info.json` Format
The `info.json` file is a JSON formatted dictionary with the following keys available to be set. You do not have to set all of them, merely the keys that apply to your keyboard.
* `keyboard_name`
* A free-form text string describing the keyboard.
* Example: `Clueboard 66%`
* `url`
* A URL to the keyboard's product page, [QMK.fm/keyboards](https://qmk.fm/keyboards) page, or other page describing information about the keyboard.
* `maintainer`
* GitHub username of the maintainer, or `qmk` for community maintained boards
* `width`
* Width of the board in Key Units
* `height`
* Height of the board in Key Units
* `layouts`
* Physical Layout representations. See the next section for more detail.
### Layout Format
Within our `info.json` file the `layouts` portion of the dictionary contains several nested dictionaries. The outer layer consists of QMK layout macros, for example `LAYOUT_ansi` or `LAYOUT_iso`. Within each layout macro are keys for `width`, `height`, and `key_count`, each of which should be self-explanatory.
* `width`
* Optional: The width of the layout in Key Units
* `height`
* Optional: The height of the layout in Key Units
* `key_count`
* **Required**: The number of keys in this layout
* `layout`
* A list of Key Dictionaries describing the physical layout. See the next section for more details.
### Key Dictionary Format
Each Key Dictionary in a layout describes the physical properties of a key. If you are familiar with the Raw Code for <http://keyboard-layout-editor.com> you will find many of the concepts the same. We re-use the same key names and layout choices wherever possible, but unlike keyboard-layout-editor each key is stateless, inheriting no properties from the keys that came before it.
All key positions and rotations are specified in relation to the top-left corner of the keyboard, and the top-left corner of each key.
* `x`
* **Required**: The absolute position of the key in the horizontal axis, in Key Units.
* `y`
* **Required**: The absolute position of the key in the vertical axis, in Key Units.
* `w`
* The width of the key, in Key Units. Ignored if `ks` is provided. Default: `1`
* `h`
* The height of the key, in Key Units. Ignored if `ks` is provided. Default: `1`
* `r`
* How many degrees clockwise to rotate the key.
* `rx`
* The absolute position of the point to rotate the key around in the horizontal axis. Default: `x`
* `ry`
* The absolute position of the point to rotate the key around in the vertical axis. Default: `y`
* `ks`
* Key Shape: define a polygon by providing a list of points, in Key Units.
* **Important**: These are relative to the top-left of the key, not absolute.
* Example ISO Enter: `[ [0,0], [1.5,0], [1.5,2], [0.25,2], [0.25,1], [0,1], [0,0] ]`
* `label`
* What to name this position in the matrix.
* This should usually be the same name as what is silkscreened on the PCB at this location.
## How is the Metadata Exposed?
This metadata is primarily used in two ways:
* To allow web-based configurators to dynamically generate UI
* To support the new `make keyboard:keymap:qmk` target, which bundles this metadata up with the firmware to allow QMK Toolbox to be smarter.
Configurator authors can see the [QMK Compiler](https://docs.api.qmk.fm/using-the-api) docs for more information on using the JSON API.

+ 38
- 34
docs/understanding_qmk.md View File

@ -12,7 +12,7 @@ You can think of QMK as no different from any other computer program. It is star
The reason for this is the different platforms that QMK supports. The most common platform is `lufa`, which runs on AVR processors such at the atmega32u4. We also support `chibios` and `vusb`.
We'll focus on AVR processors for the moment, which use the `lufa` platform. You can find the `main()` function in [tmk_core/protocol/lufa/lufa.c](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/tmk_core/protocol/lufa/lufa.c#L1019). If you browse through that function you'll find that it initializes any hardware that has been configured (including USB to the host) and then it starts the core part of the program with a [`while(1)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/tmk_core/protocol/lufa/lufa.c#L1060). This is [The Main Loop](#the-main-loop).
We'll focus on AVR processors for the moment, which use the `lufa` platform. You can find the `main()` function in [tmk_core/protocol/lufa/lufa.c](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/tmk_core/protocol/lufa/lufa.c#L1028). If you browse through that function you'll find that it initializes any hardware that has been configured (including USB to the host) and then it starts the core part of the program with a [`while(1)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/tmk_core/protocol/lufa/lufa.c#L1069). This is [The Main Loop](#the-main-loop).
## The Main Loop
@ -22,7 +22,7 @@ This section of code is called "The Main Loop" because it's responsible for loop
keyboard_task();
```
This is where all the keyboard specific functionality is dispatched. The source code for `keyboard_task()` can be found in [tmk_core/common/keyboard.c](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/tmk_core/common/keyboard.c#L206), and it is responsible for detecting changes in the matrix and turning status LED's on and off.
This is where all the keyboard specific functionality is dispatched. The source code for `keyboard_task()` can be found in [tmk_core/common/keyboard.c](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/tmk_core/common/keyboard.c#L216), and it is responsible for detecting changes in the matrix and turning status LED's on and off.
Within `keyboard_task()` you'll find code to handle:
@ -57,10 +57,10 @@ Matrix Scanning runs many times per second. The exact rate varies but typically
Once we know the state of every switch on our keyboard we have to map that to a keycode. In QMK this is done by making use of C macros to allow us to separate the definition of the physical layout from the definition of keycodes.
At the keyboard level we define a C macro (typically named `KEYMAP()`) which maps our keyboard's matrix to physical keys. Sometimes the matrix does not have a switch in every location, and we can use this macro to pre-populate those with KC_NO, making the keymap definition easier to work with. Here's an example `KEYMAP()` macro for a numpad:
At the keyboard level we define a C macro (typically named `LAYOUT()`) which maps our keyboard's matrix to physical keys. Sometimes the matrix does not have a switch in every location, and we can use this macro to pre-populate those with KC_NO, making the keymap definition easier to work with. Here's an example `LAYOUT()` macro for a numpad:
```c
#define KEYMAP( \
#define LAYOUT( \
k00, k01, k02, k03, \
k10, k11, k12, k13, \
k20, k21, k22, \
@ -75,17 +75,17 @@ At the keyboard level we define a C macro (typically named `KEYMAP()`) which map
}
```
Notice how the second block of our `KEYMAP()` macro matches the Matrix Scanning array above? This macro is what will map the matrix scanning array to keycodes. However, if you look at a 17 key numpad you'll notice that it has 3 places where the matrix could have a switch but doesn't, due to larger keys. We have populated those spaces with `KC_NO` so that our keymap definition doesn't have to.
Notice how the second block of our `LAYOUT()` macro matches the Matrix Scanning array above? This macro is what will map the matrix scanning array to keycodes. However, if you look at a 17 key numpad you'll notice that it has 3 places where the matrix could have a switch but doesn't, due to larger keys. We have populated those spaces with `KC_NO` so that our keymap definition doesn't have to.
You can also use this macro to handle unusual matrix layouts, for example the [Clueboard rev 2](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/keyboards/clueboard/66/rev2/rev2.h). Explaining that is outside the scope of this document.
You can also use this macro to handle unusual matrix layouts, for example the [Clueboard rev 2](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/keyboards/clueboard/66/rev2/rev2.h). Explaining that is outside the scope of this document.
##### Keycode Assignment
At the keymap level we make use of our `KEYMAP()` macro above to map keycodes to physical locations to matrix locations. It looks like this:
At the keymap level we make use of our `LAYOUT()` macro above to map keycodes to physical locations to matrix locations. It looks like this:
```
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = KEYMAP(
[0] = LAYOUT(
KC_NLCK, KC_PSLS, KC_PAST, KC_PMNS, \
KC_P7, KC_P8, KC_P9, KC_PPLS, \
KC_P4, KC_P5, KC_P6, \
@ -94,7 +94,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
}
```
Notice how all of these arguments match up with the first half of the `KEYMAP()` macro from the last section? This is how we take a keycode and map it to our Matrix Scan from earlier.
Notice how all of these arguments match up with the first half of the `LAYOUT()` macro from the last section? This is how we take a keycode and map it to our Matrix Scan from earlier.
##### State Change Detection
@ -130,31 +130,35 @@ Comparing against our keymap we can see that the pressed key is KC_NLCK. From he
##### Process Record
The `process_record()` function itself is deceptively simple, but hidden within is a gateway to overriding functionality at various levels of QMK. The chain of events is listed below, using cluecard whenever we need to look at the keyboard/keymap level functions. Depending on options set in rule.mk or elsewhere, only a subset of the functions below will be included in final firmware.
* [`void process_record(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/08c682c193f43e5d54df990680ae93fc2e06150a/tmk_core/common/action.c#L172)
* [`bool process_record_quantum(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/08c682c193f43e5d54df990680ae93fc2e06150a/quantum/quantum.c#L193)
* [Map this record to a keycode](https://github.com/qmk/qmk_firmware/blob/08c682c193f43e5d54df990680ae93fc2e06150a/quantum/quantum.c#L213)
* [`void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/08c682c193f43e5d54df990680ae93fc2e06150a/quantum/process_keycode/process_tap_dance.c#L115)
* [`bool process_key_lock(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/08c682c193f43e5d54df990680ae93fc2e06150a/quantum/process_keycode/process_key_lock.c#L62)
* [`bool process_clicky(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/08c682c193f43e5d54df990680ae93fc2e06150a/quantum/process_keycode/process_clicky.c#L44)
* [`bool process_record_kb(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/08c682c193f43e5d54df990680ae93fc2e06150a/keyboards/clueboard/card/card.c#L20)
* [`bool process_record_user(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/08c682c193f43e5d54df990680ae93fc2e06150a/keyboards/clueboard/card/keymaps/default/keymap.c#L58)
* [`bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/fdd0f915271f79b104aa5d216566bcc3fd134e85/quantum/rgb_matrix.c#L139)
* [`bool process_midi(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_midi.c#L81)
* [`bool process_audio(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_audio.c#L19)
* [`bool process_steno(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_steno.c#L160)
* [`bool process_music(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_music.c#L114)
* [`bool process_tap_dance(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_tap_dance.c#L136)
* [`bool process_leader(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_leader.c#L38)
* [`bool process_combo(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_combo.c#L115)
* [`bool process_unicode(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_unicode.c#L22)
* [`bool process_ucis(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_ucis.c#L91)
* [`bool process_printer(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_printer.c#L77)
* [`bool process_auto_shift(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_auto_shift.c#L94)
* [`bool process_unicode_map(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_unicodemap.c#L47)
* [`bool process_terminal(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/process_keycode/process_terminal.c#L264)
* [Identify and process quantum specific keycodes](https://github.com/qmk/qmk_firmware/blob/661ca4440cc42f3b60697e98985c44b0571ccfc1/quantum/quantum.c#L287)
The `process_record()` function itself is deceptively simple, but hidden within is a gateway to overriding functionality at various levels of QMK. The chain of events is listed below, using cluecard whenever we need to look at the keyboard/keymap level functions. Depending on options set in `rules.mk` or elsewhere, only a subset of the functions below will be included in final firmware.
* [`void process_record(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/tmk_core/common/action.c#L172)
* [`bool process_record_quantum(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/quantum.c#L206)
* [Map this record to a keycode](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/quantum.c#L226)
* [`void velocikey_accelerate(void)`](https://github.com/qmk/qmk_firmware/blob/c1c5922aae7b60b7c7d13d3769350eed9dda17ab/quantum/velocikey.c#L27)
* [`void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_tap_dance.c#L119)
* [`bool process_key_lock(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_key_lock.c#L62)
* [`bool process_clicky(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_clicky.c#L79)
* [`bool process_haptic(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/2cee371bf125a6ec541dd7c5a809573facc7c456/drivers/haptic/haptic.c#L216)
* [`bool process_record_kb(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/keyboards/clueboard/card/card.c#L20)
* [`bool process_record_user(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/keyboards/clueboard/card/keymaps/default/keymap.c#L58)
* [`bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/rgb_matrix.c#L139)
* [`bool process_midi(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_midi.c#L81)
* [`bool process_audio(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_audio.c#L19)
* [`bool process_steno(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_steno.c#L160)
* [`bool process_music(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_music.c#L114)
* [`bool process_tap_dance(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_tap_dance.c#L141)
* [`bool process_unicode_common(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_unicode_common.c#L169)
calls one of:
* [`bool process_unicode(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_unicode.c#L20)
* [`bool process_unicodemap(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_unicodemap.c#L46)
* [`bool process_ucis(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_ucis.c#L95)
* [`bool process_leader(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_leader.c#L51)
* [`bool process_combo(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_combo.c#L115)
* [`bool process_printer(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_printer.c#L77)
* [`bool process_auto_shift(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_auto_shift.c#L94)
* [`bool process_terminal(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_terminal.c#L264)
* [Identify and process Quantum-specific keycodes](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/quantum.c#L291)
At any step during this chain of events a function (such as `process_record_kb()`) can `return false` to halt all further processing.


+ 32
- 0
docs/zh-cn/README.md View File

@ -0,0 +1,32 @@
# QMK机械键盘固件
[![当前版本](https://img.shields.io/github/tag/qmk/qmk_firmware.svg)](https://github.com/qmk/qmk_firmware/tags)
[![开发状态](https://travis-ci.org/qmk/qmk_firmware.svg?branch=master)](https://travis-ci.org/qmk/qmk_firmware)
[![异议](https://img.shields.io/discord/440868230475677696.svg)](https://discord.gg/Uq7gcHh)
[![文档状态](https://img.shields.io/badge/docs-ready-orange.svg)](https://docs.qmk.fm)
[![GitHub贡献者](https://img.shields.io/github/contributors/qmk/qmk_firmware.svg)](https://github.com/qmk/qmk_firmware/pulse/monthly)
[![GitHub分支](https://img.shields.io/github/forks/qmk/qmk_firmware.svg?style=social&label=Fork)](https://github.com/qmk/qmk_firmware/)
## 什么是 QMK 固件?
QMK (*Quantum Mechanical Keyboard*) 是一个社区维护的开源软件,包括 QMK 固件, QMK 工具箱, qmk.fm网站, 和这些文档。QMK 固件是一个基于[tmk\_keyboard](http://github.com/tmk/tmk_keyboard)的键盘固件,它在爱特梅尔AVR微控制器实现一些有用的功能,确切地说, 是在 [OLKB product line](http://olkb.com), 在 [ErgoDox EZ](http://www.ergodox-ez.com) 键盘, 和 [Clueboard product line](http://clueboard.co/). 上。它被移植到使用ChibiOS的ARM芯片上. 它可以在飞线键盘或定制PCB键盘中发挥功能.
## 如何得到它
如果你打算贡献布局, 键盘, 或者其他QMK特性, 一下是最简单的方法:[从Github获得repo分支](https://github.com/qmk/qmk_firmware#fork-destination-box), 并克隆你的repo到本地进行编辑,推送,然后从你的分支打开 [Pull Request](https://github.com/qmk/qmk_firmware/pulls).
此外, 你也可以直接下载 ([zip](https://github.com/qmk/qmk_firmware/zipball/master), [tar](https://github.com/qmk/qmk_firmware/tarball/master)), 或者从git克隆 (`git@github.com:qmk/qmk_firmware.git`), 或 https (`https://github.com/qmk/qmk_firmware.git`).
## 如何编译
在你能编译之前, 你需要[部署环境](getting_started_build_tools.md) 用于 AVR or/and ARM 开发。完成后, 你可以使用 `make` 命令来编译一个键盘和布局使用以下命令:
make planck/rev4:default
这将建立 `planck`的`rev4` 修订版本并使用 `default`布局。并非所有键盘都有修订版本 (也叫做子项目或文件夹),在此情况下,修订版本可以省略,如下:
make preonic:default
## 如何定制
QMK 有许多 [特性](features.md)来探索,也有很多 [参考文档](http://docs.qmk.fm) 供您发掘。你可以通过修改 [布局](keymap.md)和[键码](keycodes.md)来利用许多特性。

+ 106
- 0
docs/zh-cn/_summary.md View File

@ -0,0 +1,106 @@
* [完全菜鸟指南](newbs.md)
* [入门](newbs_getting_started.md)
* [构建你的第一个固件](newbs_building_firmware.md)
* [刷新固件](newbs_flashing.md)
* [测试和调试](newbs_testing_debugging.md)
* [Git最佳实践](newbs_best_practices.md)
* [学习资源](newbs_learn_more_resources.md)
* [QMK基础](README.md)
* [QMK 简介](getting_started_introduction.md)
* [贡献 QMK](contributing.md)
* [如何使用Github](getting_started_github.md)
* [获得帮助](getting_started_getting_help.md)
* [问题解答](faq.md)
* [一般问题](faq_general.md)
* [构建/编译QMK](faq_build.md)
* [调试/故障排除 QMK](faq_debug.md)
* [键盘布局](faq_keymap.md)
* 详细指南
* [安装构建工具](getting_started_build_tools.md)
* [流浪者指南](getting_started_vagrant.md)
* [构建/编译指令](getting_started_make_guide.md)
* [刷新固件](flashing.md)
* [定制功能](custom_quantum_functions.md)
* [布局概述](keymap.md)
* [硬件](hardware.md)
* [AVR 处理器](hardware_avr.md)
* [驱动](hardware_drivers.md)
* 参考
* [键盘指南](hardware_keyboard_guidelines.md)
* [配置选项](config_options.md)
* [键码](keycodes.md)
* [记录最佳实践](documentation_best_practices.md)
* [文档指南](documentation_templates.md)
* [词汇表](reference_glossary.md)
* [单元测试](unit_testing.md)
* [有用的功能](ref_functions.md)
* [配置器支持](reference_configurator_support.md)
* [info.json 格式](reference_info_json.md)
* [特性](features.md)
* [基本键码](keycodes_basic.md)
* [US ANSI 控制键](keycodes_us_ansi_shifted.md)
* [量子键码](quantum_keycodes.md)
* [高级键码](feature_advanced_keycodes.md)
* [音频](feature_audio.md)
* [自动控制](feature_auto_shift.md)
* [背光](feature_backlight.md)
* [蓝牙](feature_bluetooth.md)
* [Bootmagic](feature_bootmagic.md)
* [组合](feature_combo)
* [命令](feature_command.md)
* [动态宏指令](feature_dynamic_macros.md)
* [编码器](feature_encoders.md)
* [Grave Escape](feature_grave_esc.md)
* [键锁](feature_key_lock.md)
* [](feature_layouts.md)
* [引导键](feature_leader_key.md)
* [LED 阵列](feature_led_matrix.md)
* [宏指令](feature_macros.md)
* [鼠标键](feature_mouse_keys.md)
* [一键功能](feature_advanced_keycodes.md#one-shot-keys)
* [指针设备](feature_pointing_device.md)
* [PS/2 鼠标](feature_ps2_mouse.md)
* [RGB 光](feature_rgblight.md)
* [RGB 矩阵](feature_rgb_matrix.md)
* [空格候补换挡](feature_space_cadet_shift.md)
* [空格候补换挡回车](feature_space_cadet_shift_enter.md)
* [速录机](feature_stenography.md)
* [换手](feature_swap_hands.md)
* [踢踏舞](feature_tap_dance.md)
* [终端](feature_terminal.md)
* [热敏打印机](feature_thermal_printer.md)
* [Unicode](feature_unicode.md)
* [用户空间](feature_userspace.md)
* [速度键](feature_velocikey.md)
* 针对制造者和定制者
* [飞线指南](hand_wire.md)
* [ISP 刷新指南](isp_flashing_guide.md)
* [ARM 调试指南](arm_debugging.md)
* [I2C 驱动](i2c_driver.md)
* [GPIO 控制器](internals_gpio_control.md)
* [Proton C 转换](proton_c_conversion.md)
* 深入了解
* [键盘如何工作](how_keyboards_work.md)
* [理解 QMK](understanding_qmk.md)
* 其他话题
* [使用Eclipse开发QMK](other_eclipse.md)
* [使用VSCode开发QMK](other_vscode.md)
* [支持](support.md)
* QMK 内构 (正在编写)
* [定义](internals_defines.md)
* [输入回调寄存器](internals_input_callback_reg.md)
* [Midi 设备](internals_midi_device.md)
* [Midi 设备设置过程](internals_midi_device_setup_process.md)
* [Midi 工具库](internals_midi_util.md)
* [发送函数](internals_send_functions.md)
* [Sysex 工具](internals_sysex_tools.md)

+ 54
- 0
docs/zh-cn/getting_started_introduction.md View File

@ -0,0 +1,54 @@
# 介绍
本页解释了使用QMK项目所需的基本信息。它假定您能熟练使用Unix shell,但您不熟悉C语言也不熟悉使用make编译。
## 基本QMK结构
QMK是[Jun Wako](https://github.com/tmk)的[tmk_keyboard](https://github.com/tmk/tmk_keyboard)工程的一个分叉。经过更改的TMK原始代码放在`tmk` 文件夹中。 QMK增加的新东西可以在 `quantum` 文件夹中找到。 键盘项目可以在 `handwired`(手动飞线) 和 `keyboard`(PCB键盘)这两个文件夹找到。
### 用户空间结构
在`users`文件夹里面的目录是每个用户的目录。这个文件夹里面放的是用户们在不同键盘都能用到的代码。详见[用户空间特性](feature_userspace.md)
### 键盘项目结构
在`keyboards`文件夹和他的子文件夹`handwired`中就是各个键盘的项目了,比如`qmk_firmware/keyboards/clueboard`。内部结构与如下:
* `keymaps/`: 可以构建的不同布局
* `rules.mk`: 用来设置 "make" 命令默认选项的文件。别直接编辑这个文件,你应该使用具体某个布局的 `rules.mk`.
* `config.h`: 用于设置默认编译选项的文件。别直接编辑这个文件, 你应该使用具体某个布局的 `config.h`.
### 布局结构
在各个布局的文件夹,你能找到以下文件。只有 `keymap.c` 是必要的, 如果其他文件找不到就会直接选择默认选项。
* `config.h`: 配置布局的选项
* `keymap.c`: 布局的全部代码, 必要文件
* `rules.mk`: 使能的QMK特性
* `readme.md`:介绍你的布局,告诉别人怎么使用,附上功能说明。请将图片上传到imgur等图床(译者注:imgur可能已被墙,为了方便国人访问,建议使用国内可以直接访问的图床)。
# `config.h` 文件
有三个重要的`config.h` 位置:
* 键盘 (`/keyboards/<keyboard>/config.h`)
* 用户空间 (`/users/<user>/config.h`)
* 布局 (`/keyboards/<keyboard>/keymaps/<keymap>/config.h`)
构建系统按照上述顺序自动获取配置文件。如果要覆盖由上一个 `config.h` 所做的设置,您需要首先为要更改的设置包含一些样板代码。
```
#pragma once
```
要覆盖上一个 `config.h` 所做的设置,你要先 `#undef` 然后再 `#define` 这个设置.
样板代码和设置看起来像这样:
```
#pragma once
// 像下面那样覆盖设置(MY_SETTING指的是你要覆盖的设置项)!
#undef MY_SETTING
#define MY_SETTING 4
```

+ 163
- 0
docs/zh-cn/newbs_best_practices.md View File

@ -0,0 +1,163 @@
# 最佳实践
## 或者说, "我应如何学会不再担心并开始爱上Git。"
本文档旨在指导新手以最佳方式获得为QMK做出贡献的丝滑体验。我们将介绍为QMK做出贡献的过程,详细介绍使这项任务更容易的一些方法,然后我们将制造一些问题,来教你如何解决它们。
本文假设了一些内容:
1. 一有个GitHub账户, 并[创建qmk_firmware仓库分叉](getting_started_github.md)到你的帐户.
2. 你已经[建立你的构建环境](newbs_getting_started.md?id=environment-setup).
## 你分叉的主分支: 一直在上传,但不要提交
十分推荐您在QMK开发过程中无论开发是否完成都要保持你的 `master` 分支更新,但是 ***一定不要*** 提交。相反,你应该在一个开发分叉中做出你所有修改并在开发时提交pull request。
减少合并冲突的可能性 &mdash; 两个或多个用户同时编辑文件的同一部分的实例 &mdash; 保持 `master` 分支最新,并创建一个新的分支来开始新的开发。
### 更新你的主分支
保持你的 `master` 更新, 推荐你添加QMK Firmware仓库作为Git的远程仓库,想这么做的话, 你可以打开你的Git命令行接口然后输入:
```
git remote add upstream https://github.com/qmk/qmk_firmware.git
```
运行 `git remote -v`, 来确定这个仓库已经添加,以下是回显:
```
$ git remote -v
origin https://github.com/<your_username>/qmk_firmware.git (fetch)
origin https://github.com/<your_username>/qmk_firmware.git (push)
upstream https://github.com/qmk/qmk_firmware.git (fetch)
upstream https://github.com/qmk/qmk_firmware.git (push)
```
现在添加已完成,你可以用`git fetch upstream`来检查仓库的更新. 这会检索branches 和 tags &mdash; 统称为"refs" &mdash; 从QMK仓库, 也就是 `upstream`。我们可以比较我们的分叉和QMK的 `origin` 数据的不同。
要更新你的分叉的主分支,请运行以下命令,在每行之后按Enter键:
```
git checkout master
git fetch upstream
git pull upstream master
git push origin master
```
这回切换到你的`master` 分支, 检索你QMK仓库的refs, 下载当前QMK `master` 分支到你的电脑, 并上传到你的分叉.
### 做改动
你可以输入以下命令来创建一个新的分支来做改动:
```
git checkout -b dev_branch
git push --set-upstream origin dev_branch
```
这回建立一个叫做 `dev_branch`的新分支, 检查一下, 然后想你的分叉保存分支. 使用 `--set-upstream` 参数来告诉git使用你的分叉并且当每次你对你的分支用`git push` 或 `git pull`时要使用`dev_branch`。 它仅需要在第一次push的时候使用;然后你就可以很安全的用 `git push``git pull`, 并不需要其他参数了。
!> 使用 `git push`, 你可以用 `-u` 来代替 `--set-upstream` &mdash; `-u`是`--set-upstream`的简写。
您可以将您的分支命名为您想要的任何名称,但建议将其命名为与您要进行的更改相关的内容。
默认情况下 `git checkout -b` 在已经检出的分支上建立新的分支。您可以将新的分支建立在未检出的现有分支的基础上,方法是将现有分支的名称添加到命令:
```
git checkout -b dev_branch master
```
现在您已经有了一个开发分支,那么就打开您的文本编辑器并进行您需要做的任何更改。建议对您的分支进行许多小的提交;这样,任何引起问题的更改都可以在需要时更容易地跟踪和撤消。要进行更改,编辑并保存任何需要更新的文件,请将它们添加到Git的 *staging area* ,然后将它们提交到您的分支:
```
git add path/to/updated_file
git commit -m "My commit message."
```
` git add`添加已更改到Git的*临时区域*也就是Git的“加载区域”的文件。其中包含使用 `git commit` 命令 *提交* 的并已经保存到仓库的更改。建议您使用描述性的提交消息,这样您就可以一目了然地知道更改了什么。
!> 如果你修改了很多文件,但所有的文件都是同一个更改的一部分,你可以用 `git add .` 来添加当前目录中所有已更改的文件而不是单独添加每个文件.
### 发布更改
最后一步是将更改推送到您的分叉。 输入 `git push`来推送. 现在Git将`dev_branch`的当前状态发布到您的分叉。
## 解决合并冲突
有时,当您在某个分支中的工作需要很长时间才能完成时,其他人所做的更改与您在打开pull request时对该分支所做的更改相冲突。这称为*rebase* 即合并冲突,当多个人编辑同一文件的同一部分时会发生这种情况。
### 重新调整您的更改
*rebase*是Git的一种方法,它获取在某一点上应用的更改,撤销它们,然后将相同的更改应用到另一点。在合并冲突的情况下,您可以重新设置您的分支以获取在创建分支时和当前时间之间的那段时间所做的更改。
运行以下命令来开始:
```
git fetch upstream
git rev-list --left-right --count HEAD...upstream/master
```
这里的`git rev-list` 命令返回当前分支和qmk的主分支之间不同的提交数。我们首先运行`git fetch`,以确保我们有代表upstream仓库的refs。 `git rev-list` 命令的回显有两个数字:
```
$ git rev-list --left-right --count HEAD...upstream/master
7 35
```
第一个数字表示自创建以来当前分支的提交数, 第二个数字是自创建当前分支以来对 `upstream/master` 进行的提交数, 因此, 当前分支中未记录变动。
既然知道当前分支和upstream仓库的当前状态,我们可以开始一个rebase操作:
```
git rebase upstream/master
```
这就是让Git撤销当前分支上的提交,然后根据QMK的主分支重新应用它们。
```
$ git rebase upstream/master
First, rewinding head to replay your work on top of it...
Applying: Commit #1
Using index info to reconstruct a base tree...
M conflicting_file_1.txt
Falling back to patching base and 3-way merge...
Auto-merging conflicting_file_1.txt
CONFLICT (content): Merge conflict in conflicting_file_1.txt
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch' to see the failed patch
Patch failed at 0001 Commit #1
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
```
这告诉我们有一个合并冲突,并给出带有冲突的文件的名称。在文本编辑器中打开冲突的文件,在该文件的某个位置,您会发现如下内容:
```
<<<<<<< HEAD
<p>For help with any issues, email us at support@webhost.us.</p>
=======
<p>Need help? Email support@webhost.us.</p>
>>>>>>> Commit #1
```
`<<<<<<< HEAD`行标记合并冲突的开始, `>>>>>>> Commit #1` 行标记结束, 冲突选项被 `=======`分隔。`HEAD`那端的部分来自文件的qmk master版本,标记有commit消息的部分来自当前的分支持和提交。
因为Git跟踪 *对文件的更改* 而不是直接跟踪文件的内容,所以如果Git在提交之前找不到文件中的文本,它将不知道如何编辑该文件。重新编辑文件将解决冲突。进行更改,然后保存文件。
```
<p>Need help? Email support@webhost.us.</p>
```
现在运行:
```
git add conflicting_file_1.txt
git rebase --continue
```
Git记录对冲突文件的更改,并继续应用来自我们的分支的提交,直到它到达末尾。

+ 81
- 0
docs/zh-cn/newbs_building_firmware.md View File

@ -0,0 +1,81 @@
# 构建第一个固件
现在您已经建立了构建环境,就可以开始构建自定义固件了。对于本指南的这一部分,我们将在3个程序之间切换——文件管理器、文本编辑器和终端窗口。请保持所有3个程序打开,直到您完成并对键盘固件满意。
如果您在按照指南第一部分的操作之后关闭并重新打开了终端窗口,请不要忘记输入“cd qmk_firmware”,来使您的终端位于正确的目录。
## 导航到您的keymaps文件夹
首先导航到键盘的 `keymaps` 文件夹.
?> 如果您使用的是MacOS或Windows,可以使用以下命令轻松地打开keymaps文件夹。
?> macOS:
open keyboards/<keyboard_folder>/keymaps
?> Windows:
start .\\keyboards\\<keyboard_folder>\\keymaps
## 创建`default` 布局副本
打开`keymaps`文件夹后,您将需要创建`default`文件夹的副本。我们强烈建议您将文件夹命名为与Github用户名相同的名称,但您也可以使用任何您想使用的名称,只要它只包含小写字母、数字和下划线字符。
要自动执行此过程,您还可以选择运行`new_keymap.sh`脚本。
导航到`qmk_firmware/util` 目录然后输入以下命令:
```
./new_keymap.sh <keyboard path> <username>
```
例如,一个名字叫ymzcdg的用户要创建1up60hse的布局,他需要输入
```
./new_keymap.sh 1upkeyboards/1up60hse ymzcdg
```
## 在你最钟爱的文本编辑器中打开`keymap.c`
打开你的`keymap.c`. 在这个文件中,您可以找到控制键盘行为的结构。 在你的`keymap.c` 的顶部有一些让布局更易读的define和enum。在靠下的位置你会找到一行和下面这句很像的:
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
从这一行开始便是层列表。这行下面你会看到包括 `LAYOUT``KEYMAP`这两个词的几行, 从这些行开始就是层。在这一行下面是组成该特定层的键的列表。
!> 编辑您的keymap文件时,注意不要添加或删除任何逗号。如果这样做,您将阻止您的固件编译,并且您可能不容易找出多余的或缺少的逗号在哪里。
## 根据您的喜好自定义布局
如何完成这一步骤完全取决于您。改变一直困扰着你的问题,或者完全重做所有的事情。如果您不需要全部图层,可以删除图层,或者将图层总数增加到32个。查看以下文档,了解可以在此处定义的内容:
* [键码](keycodes.md)
* [特性](features.md)
* [问题与解答](faq.md)
?> 当你明白布局是怎么工作时,您也要让每次改变尽可能小。一次改变很大在调试时找出问题会十分困难。
## 构建你的固件
完成对布局的更改后,您就要构建固件了。为此,请返回终端窗口并运行build命令:
make <my_keyboard>:<my_keymap>
例如,如果您的keymap名为“xyverz”,并且您正在为rev5 planck构建一个keymap,那么您将使用此命令:
make planck/rev5:xyverz
在编译过程中,你将看到屏幕上有很多输出,通知您正在编译哪些文件他应该以与下文类似的输出结束:
```
Linking: .build/planck_rev5_xyverz.elf [OK]
Creating load file for flashing: .build/planck_rev5_xyverz.hex [OK]
Copying planck_rev5_xyverz.hex to qmk_firmware folder [OK]
Checking file size of planck_rev5_xyverz.hex [OK]
* File size is fine - 18392/28672
```
## 刷新你的固件
请移步 [Flashing Firmware](newbs_flashing.md) 来继续。

+ 307
- 0
docs/zh-cn/newbs_flashing.md View File

@ -0,0 +1,307 @@
# 刷新你的键盘
现在您已经构建了一个自定义固件文件,那么您就需要刷新键盘了。
## 用QMK工具箱刷新键盘
刷新键盘的最简单方法是使用[QMK 工具箱](https://github.com/qmk/qmk_toolbox/releases).
但是,QMK工具箱目前仅适用于Windows和MacOS。如果您使用的是Linux(或者只是希望从命令行刷新固件),则必须使用 [方法概述](newbs_flashing.md#flash-your-keyboard-from-the-command-line).
### 将文件加载到QMK工具箱中
首先打开QMK工具箱应用程序。您将要在访达或资源管理器中找到固件文件。您的键盘固件可能是两种格式之一`.hex`或`.bin`。qmk会尝试将键盘的相应文件复制到“qmk_firmware”根目录中。
?> 如果您在Windows或MacOS上,可以使用以下命令轻松地在资源管理器或访达中打开当前固件文件夹。
?> Windows:
start .
?> macOS:
open .
固件文件始终遵循此命名格式:
<keyboard_name>_<keymap_name>.{bin,hex}
例如,使用 `default` 布局的 `plank/rev5` 将使用以下名字:
planck_rev5_default.hex
找到固件文件后,将其拖到QMK工具箱中的“Local file”框中,或单击“Open”并导航到固件文件的存储位置。
### 将键盘置于DFU(Bootloader)模式
要刷新自定义固件,您必须将键盘置于特殊的刷新模式。在此模式下,您将无法键入或使用键盘。在写入固件时,不要拔下键盘插头或以其他方式中断刷新过程,这一点非常重要。
不同的键盘有不同的方式进入这种特殊模式。如果您的键盘当前运行的是QMK或TMK,而您没有得到特定的指示,请按顺序尝试以下操作:
* 按住两个shift键并按 `Pause`
* 按住两个shift键并按 `B`
* 拔下键盘插头, 同时按住空格键和 `B` , 插上键盘然后等一会再放开按键
* 按下PCB底部的 `RESET` 物理键
* 找到PCB上标记有 `BOOT0``RESET`的金属点, 在插入PCB的同时短接它们
成功后,您将在QMK工具箱中看到类似以下内容的消息:
```
*** Clueboard - Clueboard 66% HotSwap disconnected -- 0xC1ED:0x2390
*** DFU device connected
```
### 刷新你的键盘
单击QMK工具箱中的 `Flash` 按钮。您将看到类似以下内容的输出:
```
*** Clueboard - Clueboard 66% HotSwap disconnected -- 0xC1ED:0x2390
*** DFU device connected
*** Attempting to flash, please don't remove device
>>> dfu-programmer atmega32u4 erase --force
Erasing flash... Success
Checking memory from 0x0 to 0x6FFF... Empty.
>>> dfu-programmer atmega32u4 flash /Users/skully/qmk_firmware/clueboard_66_hotswap_gen1_skully.hex
Checking memory from 0x0 to 0x55FF... Empty.
0% 100% Programming 0x5600 bytes...
[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] Success
0% 100% Reading 0x7000 bytes...
[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] Success
Validating... Success
0x5600 bytes written into 0x7000 bytes memory (76.79%).
>>> dfu-programmer atmega32u4 reset
*** DFU device disconnected
*** Clueboard - Clueboard 66% HotSwap connected -- 0xC1ED:0x2390
```
## 使用命令行刷新键盘
首先,您需要知道您的键盘使用的是哪个bootloader。通常是以下四个常见的bootloader。Pro-Micro 和 clones 使用 CATERINA, Teensy 使用 Halfkay, OLKB 键盘使用 QMK-DFU, 其他的atmega32u4芯片使用DFU。
您可以在以下文章中了解更多关于bootloader[刷新指令和Bootloader信息](flashing.md)。
如果您知道正在使用的bootloader是哪种,那么在编译固件时,可以向“make”命令里添加一些额外参数,以自动执行刷新过程。
### DFU
对于DFU引导加载程序,当您准备好编译和刷新固件时,打开终端窗口并运行构建命令:
make <my_keyboard>:<my_keymap>:dfu
例如,如果您的布局名为“xyverz”,并且您正在为rev5 planck构建一个布局,那么您可以使用此命令:
make planck/rev5:xyverz:dfu
编译完成后,应输出以下内容:
```
Linking: .build/planck_rev5_xyverz.elf [OK]
Creating load file for flashing: .build/planck_rev5_xyverz.hex [OK]
Copying planck_rev5_xyverz.hex to qmk_firmware folder [OK]
Checking file size of planck_rev5_xyverz.hex
* File size is fine - 18574/28672
```
到了这个时候, 构建脚本将每隔5秒查找一次DFU。它将重复以下操作,直到找到设备或将其取消。
dfu-programmer: no device present.
Error: Bootloader not found. Trying again in 5s.
一旦出现以上回显,您将需要重置控制器。然后,它应该显示与以下类似的输出:
```
*** Attempting to flash, please don't remove device
>>> dfu-programmer atmega32u4 erase --force
Erasing flash... Success
Checking memory from 0x0 to 0x6FFF... Empty.
>>> dfu-programmer atmega32u4 flash /Users/skully/qmk_firmware/clueboard_66_hotswap_gen1_skully.hex
Checking memory from 0x0 to 0x55FF... Empty.
0% 100% Programming 0x5600 bytes...
[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] Success
0% 100% Reading 0x7000 bytes...
[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>] Success
Validating... Success
0x5600 bytes written into 0x7000 bytes memory (76.79%).
>>> dfu-programmer atmega32u4 reset
```
如果您对此有任何问题,您可能需要这样做:
sudo make <my_keyboard>:<my_keymap>:dfu
#### DFU命令
有许多DFU命令可用于将固件下载到DFU设备:
* `:dfu` - 这是正常选项,等待DFU设备可用,然后刷新固件。这将每隔5秒检查一次,以查看是否出现了DFU设备。
* `:dfu-ee` - 这将刷新一个`eep`文件,而不是普通的十六进制文件。这很不常见。
* `:dfu-split-left` - 这将刷新正常固件,就像默认选项 (`:dfu`)一样. 但是,这也会刷新“左侧”EEPROM文件,用于分割键盘。 _这是基于Elite C的键盘的推荐选择。_
* `:dfu-split-right` - 这将刷新正常固件,就像默认选项(`:dfu`). 但是,这也会刷新“右侧”EEPROM文件,用于分割键盘。 _这是基于Elite C的键盘的推荐选择。_
### Caterina
对于Arduino板以及其克隆版来说(比如SparkFun和ProMicro), 准备好编译和刷新固件后,打开终端窗口并运行构建命令:
make <my_keyboard>:<my_keymap>:avrdude
比如, 你的布局叫"xyverz"你要创建一个rev2 Lets Split的布局,你要用以下命令:
make lets_split/rev2:xyverz:avrdude
固件完成编译后,它将输出类似以下的内容:
```
Linking: .build/lets_split_rev2_xyverz.elf [OK]
Creating load file for flashing: .build/lets_split_rev2_xyverz.hex [OK]
Checking file size of lets_split_rev2_xyverz.hex [OK]
* File size is fine - 27938/28672
Detecting USB port, reset your controller now..............
```
此时,复位,然后脚本将检测bootloader,然后刷新固件。输出应该像这样:
```
Detected controller on USB port at /dev/ttyS15
Connecting to programmer: .
Found programmer: Id = "CATERIN"; type = S
Software Version = 1.0; No Hardware Version given.
Programmer supports auto addr increment.
Programmer supports buffered memory access with buffersize=128 bytes.
Programmer supports the following devices:
Device code: 0x44
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude.exe: Device signature = 0x1e9587 (probably m32u4)
avrdude.exe: NOTE: "flash" memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude.exe: erasing chip
avrdude.exe: reading input file "./.build/lets_split_rev2_xyverz.hex"
avrdude.exe: input file ./.build/lets_split_rev2_xyverz.hex auto detected as Intel Hex
avrdude.exe: writing flash (27938 bytes):
Writing | ################################################## | 100% 2.40s
avrdude.exe: 27938 bytes of flash written
avrdude.exe: verifying flash memory against ./.build/lets_split_rev2_xyverz.hex:
avrdude.exe: load data flash data from input file ./.build/lets_split_rev2_xyverz.hex:
avrdude.exe: input file ./.build/lets_split_rev2_xyverz.hex auto detected as Intel Hex
avrdude.exe: input file ./.build/lets_split_rev2_xyverz.hex contains 27938 bytes
avrdude.exe: reading on-chip flash data:
Reading | ################################################## | 100% 0.43s
avrdude.exe: verifying ...
avrdude.exe: 27938 bytes of flash verified
avrdude.exe: safemode: Fuses OK (E:CB, H:D8, L:FF)
avrdude.exe done. Thank you.
```
如果您对此有任何问题,您可能需要这样做:
sudo make <my_keyboard>:<my_keymap>:avrdude
此外,如果要刷新多个板,请使用以下命令:
make <keyboard>:<keymap>:avrdude-loop
当你完成了刷新后,你需要按下ctrl+c或者其他正确的按键来让你的操作系统终止循环。
## HalfKay
对于PJRC设备(Teensy),当您准备好编译和刷新固件时,打开终端窗口并运行构建命令:
make <my_keyboard>:<my_keymap>:teensy
比如, 如果你的布局叫做"xyverz"你想创建Ergodox or Ergodox EZ的布局,你要使用以下命令:
make erdogox_ez:xyverz:teensy
固件完成编译后,它将输出如下内容:
```
Linking: .build/ergodox_ez_xyverz.elf [OK]
Creating load file for flashing: .build/ergodox_ez_xyverz.hex [OK]
Checking file size of ergodox_ez_xyverz.hex [OK]
* File size is fine - 25584/32256
Teensy Loader, Command Line, Version 2.1
Read "./.build/ergodox_ez_xyverz.hex": 25584 bytes, 79.3% usage
Waiting for Teensy device...
(hint: press the reset button)
```
此时,复位键盘。完成后,您将看到如下输出:
```
Found HalfKay Bootloader
Read "./.build/ergodox_ez_xyverz.hex": 28532 bytes, 88.5% usage
Programming............................................................................................................................................................................
...................................................
Booting
```
## STM32 (ARM)
对于大多数ARM板(包括Proton C、Planck Rev 6和Preonic Rev 3),当您准备好编译和刷新固件时,打开终端窗口并运行构建命令:
make <my_keyboard>:<my_keymap>:dfu-util
例如,如果您的keymap被命名为“xyverz”,并且您正在为Planck Revision 6键盘构建一个布局,那么您需要使用以下命令,然后将键盘重新启动到bootloader(在完成编译之前):
make planck/rev6:xyverz:dfu-util
固件完成编译后,它将输出如下内容:
```
Linking: .build/planck_rev6_xyverz.elf [OK]
Creating binary load file for flashing: .build/planck_rev6_xyverz.bin [OK]
Creating load file for flashing: .build/planck_rev6_xyverz.hex [OK]
Size after:
text data bss dec hex filename
0 41820 0 41820 a35c .build/planck_rev6_xyverz.hex
Copying planck_rev6_xyverz.bin to qmk_firmware folder [OK]
dfu-util 0.9
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
Invalid DFU suffix signature
A valid DFU suffix will be required in a future dfu-util release!!!
Opening DFU capable USB device...
ID 0483:df11
Run-time device DFU version 011a
Claiming USB DFU Interface...
Setting Alternate Setting #0 ...
Determining device status: state = dfuERROR, status = 10
dfuERROR, clearing status
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 011a
Device returned transfer size 2048
DfuSe interface name: "Internal Flash "
Downloading to address = 0x08000000, size = 41824
Download [=========================] 100% 41824 bytes
Download done.
File downloaded successfully
Transitioning to dfuMANIFEST state
```
## 试一试吧!
恭喜您! 您的自定义固件已经刷写到您的键盘
试一试,确保一切按你想的方式进行。我们写了[测试和调试](newbs_testing_debugging.md)来完善新手引导。 因此,请前往那里了解如何排除自定义功能的故障。

+ 102
- 0
docs/zh-cn/newbs_getting_started.md View File

@ -0,0 +1,102 @@
# 介绍
你的电脑键盘里面包含一个处理器, 这个处理器和你电脑里面的不太一样。这个处理器负责运行一些特殊的软件,这些软件可以监测按钮按下并将按钮处于按下还是释放状态的数据发送出去。QMK就是这样一种软件,即监测按钮被按下并发送这样的信息到作为主机的计算机上。当你创建了你的布局, 你也就创建了你的键盘运行的的可执行程序。
QMK试图通过使简单的事情变得更简单,使使不可能成为可能来把大量的权力交给你。你不需要懂如何通过程序创建强大的布局——你只需要遵循简单的语法规则。
# 新手上路
在你能创建布局前,你要安装一些软件来建立你的开发环境。无论你想编译多少固件,这个操作都只需要进行一次。
如果您更喜欢图形化界面, 请考虑使用在线工具[QMK配置器](https://config.qmk.fm)。 请参考 [使用在线GUI构建您的第一个固件](newbs_building_firmware_configurator.md)。
## 下载软件
### 文本编辑器
你需要一个可以编辑 **纯文本** 文件的程序。在Windows上你可以用Notepad, 在Linux上使用gedit,这两个都是简单又实用的文本编辑工具。 在macOS上, 请小心使用 “文本编辑” 这个默认软件: 如果你不明确的选择_格式_菜单中的 _制作纯文本_ 的话文本将不会被保存为纯文本。
你也可以下载并安装一个专用编辑器 [Sublime Text](https://www.sublimetext.com/) 或 [VS Code](https://code.visualstudio.com/)。 这大概是跨平台的最好方法了, 这些编辑器是专门为了编辑代码设计的。
?>搞不清用哪种编辑器? Laurence Bradford 写了篇关于编辑器选择的文章 [a great introduction](https://learntocodewith.me/programming/basics/text-editors/)。
### QMK 工具箱
QMK 工具箱 是一种可选的Windows和macOS下的图形化工具,它可以对你的定制键盘进行编程和调试。你可能会发现它就是你能简单的刷新你的键盘固件并查看调试信息的稀世珍宝。
[在这里下载最新发布版本](https://github.com/qmk/qmk_toolbox/releases/latest)
* Windows用户: `qmk_toolbox.exe` (绿色版) 或 `qmk_toolbox_install.exe` (安装版)
* macOS用户: `QMK.Toolbox.app.zip` (绿色版) or `QMK.Toolbox.pkg` (安装版)
## 建立你的环境
我们为了使QMK环境变得更容易建立已竭尽所能。你只需要准备Linux 或 Unix 环境, 然后让QMK安装剩余部分。
?> 如果你从未使用过Linux/Unix的命令行,有一些你需要学习的基础概念和命令,以下资料将教会您使用QMK环境的必要能力:<br>
[必会Linux命令](https://www.guru99.com/must-know-linux-commands.html)<br>
[一些基本的Unix命令](https://www.tjhsst.edu/~dhyatt/superap/unixcmd.html)
### Windows
你需要安装MSYS2和Git.
* 按照以下安装说明进行操作[MSYS2 主页](http://www.msys2.org)。
* 关闭所有打开的MSYS2终端并打开新的MSYS2 MinGW 64-bit终端。
* 使用以下命令安装Git: `pacman -S git`
### macOS
你需要安装Homebrew。按照以下说明进行操作 [Homebrew 主页](https://brew.sh)。
在Homebrew安装完成后, 继续 _同步QMK工程_. 这一步你将会通过运行一个脚本安装其他包。
### Linux
你将需要安装Git.你很有可能已经安装,但若你尚未安装,可以使用以下命令进行安装:
* Debian / Ubuntu / Devuan: `apt-get install git`
* Fedora / Red Hat / CentOS: `yum install git`
* Arch: `pacman -S git`
?> 无论你使用哪种平台,Docker都可以是你的选择[点这里进一步了解](getting_started_build_tools.md#docker)
## 同步QMK工程
当你建立Linux/Unix环境后,你就已经可以下载QMK了.下载时我们可以用Git来 "clone" QMK仓库. 打开一个终端或MSYS2 MinGW 窗口,在阅读剩余的指南时请保持窗口打开。在窗口里面运行以下两句命令:
```shell
git clone --recurse-submodules https://github.com/qmk/qmk_firmware.git
cd qmk_firmware
```
?> 如果您已经知道[如何使用GitHub](getting_started_github.md), 我们推荐您创建您自己的分支并克隆。 如果您不知道这是什么, 您完全可以忽略这句无关紧要的话。
QMK附带一个脚本,可帮助您设置剩余的所需内容.您可以通过输入此命令来运行它:
util/qmk_install.sh
## 测试你的开发环境
现在你的QMK环境已经建立完毕, 你可以为你的键盘创建固件了。开始试着创建键盘的默认固件吧。 你需要使用以下格式的命令创建固件:
make <keyboard>:default
比如, 制作一个Clueboard 66%的固件,需要用:
make clueboard/66/rev3:default
当完成后你要看到一些回显,尾部如下:
```
Linking: .build/clueboard_66_rev3_default.elf [OK]
Creating load file for flashing: .build/clueboard_66_rev3_default.hex [OK]
Copying clueboard_66_rev3_default.hex to qmk_firmware folder [OK]
Checking file size of clueboard_66_rev3_default.hex [OK]
* The firmware size is fine - 26356/28672 (2316 bytes free)
```
# 创建你的布局
现在你可以创建属于你自己的布局了! 请移步 [构建你的第一个固件](newbs_building_firmware.md)来继续。

+ 15
- 0
docs/zh-cn/newbs_learn_more_resources.md View File

@ -0,0 +1,15 @@
# 学习资源
这些资源旨在让QMK社区的新成员更了解新成员文档中提供的信息。
Git 资源:
* [很好的通用教程](https://www.codecademy.com/learn/learn-git)
* [从例子中学习Git游戏](https://learngitbranching.js.org/)
* [了解有关GitHub的更多信息的Git资源](getting_started_github.md)
* [专门针对QMK的Git资源](contributing.md)
命令行资源:
* [超棒的命令行通用教程](https://www.codecademy.com/learn/learn-the-command-line)

+ 43
- 0
docs/zh-cn/newbs_testing_debugging.md View File

@ -0,0 +1,43 @@
# 测试和调试
使用自定义固件刷新键盘后,您就可以测试它了。如果您幸运,一切都会完美运行,但如果没有,这份文件将帮助您找出问题所在。
## 测试
测试键盘通常非常简单。按下每一个键并确保它发送的是您期望的键。甚至有一些程序可以帮助您确保没有任何键失效。
注意:这些程序不是由QMK提供或认可的。
* [Switch Hitter](https://elitekeyboards.com/switchhitter.php) (仅Windows)
* [Keyboard Viewer](https://www.imore.com/how-use-keyboard-viewer-your-mac) (仅Mac)
* [Keyboard Tester](http://www.keyboardtester.com) (网页版)
* [Keyboard Checker](http://keyboardchecker.com) (网页版)
## 使用QMK工具箱进行调试
[QMK工具箱](https://github.com/qmk/qmk_toolbox) 将会在你的`rules.mk`中有`CONSOLE_ENABLE = yes`的时候显示你键盘发来的消息。 默认情况下,输出极为有限,不过您可以打开调试模式来增加输出信息量。使用你键盘布局中的`DEBUG`键码,使用 [命令](feature_command.md) 特性来使能调试模式, 或者向你的布局中添加以下代码。
```c
void keyboard_post_init_user(void) {
// Customise these values to desired behaviour
debug_enable=true;
debug_matrix=true;
//debug_keyboard=true;
//debug_mouse=true;
}
```
<!-- 需要修改之处:这里要添加调试回显。 -->
## 发送您自己的调试消息
有时用[custom code](custom_quantum_functions.md)发送自定义调试信息很有用. 这么做很简单. 首先在你文件头部包含`print.h`:
#include <print.h>
之后,您可以使用一些不同的打印功能:
* `print("string")`: 打印简单字符串.
* `uprintf("%s string", var)`: 打印格式化字符串
* `dprint("string")`: 仅在调试模式使能时打印简单字符串
* `dprintf("%s string", var)`: 仅在调试模式使能时打印格式化字符串

+ 30
- 19
drivers/arm/i2c_master.c View File

@ -42,43 +42,54 @@ static const I2CConfig i2cconfig = {
0
};
static i2c_status_t chibios_to_qmk(const msg_t* status) {
switch (*status) {
case I2C_NO_ERROR:
return I2C_STATUS_SUCCESS;
case I2C_TIMEOUT:
return I2C_STATUS_TIMEOUT;
// I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT
default:
return I2C_STATUS_ERROR;
}
}
__attribute__ ((weak))
void i2c_init(void)
{
//palSetGroupMode(GPIOB, GPIOB_PIN6 | GPIOB_PIN7, 0, PAL_MODE_INPUT);
// Try releasing special pins for a short time
palSetPadMode(GPIOB, 6, PAL_MODE_INPUT);
palSetPadMode(GPIOB, 7, PAL_MODE_INPUT);
palSetPadMode(I2C1_BANK, I2C1_SCL, PAL_MODE_INPUT);
palSetPadMode(I2C1_BANK, I2C1_SDA, PAL_MODE_INPUT);
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);
palSetPadMode(I2C1_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN);
palSetPadMode(I2C1_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN);
//i2cInit(); //This is invoked by halInit() so no need to redo it.
}
// This is usually not needed
uint8_t i2c_start(uint8_t address)
i2c_status_t i2c_start(uint8_t address)
{
i2c_address = address;
i2cStart(&I2C_DRIVER, &i2cconfig);
return 0;
return I2C_STATUS_SUCCESS;
}
uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_address = address;
i2cStart(&I2C_DRIVER, &i2cconfig);
return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, MS2ST(timeout));
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, MS2ST(timeout));
return chibios_to_qmk(&status);
}
uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_address = address;
i2cStart(&I2C_DRIVER, &i2cconfig);
return i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, MS2ST(timeout));
msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, MS2ST(timeout));
return chibios_to_qmk(&status);
}
uint8_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length) {
@ -97,19 +108,19 @@ uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t l
}
complete_packet[0] = regaddr;
return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, MS2ST(timeout));
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, MS2ST(timeout));
return chibios_to_qmk(&status);
}
uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_address = devaddr;
i2cStart(&I2C_DRIVER, &i2cconfig);
return i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), regaddr, 1, data, length, MS2ST(timeout));
msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), regaddr, 1, data, length, MS2ST(timeout));
return chibios_to_qmk(&status);
}
// This is usually not needed. It releases the driver to allow pins to become GPIO again.
uint8_t i2c_stop(uint16_t timeout)
void i2c_stop(void)
{
i2cStop(&I2C_DRIVER);
return 0;
}

+ 23
- 7
drivers/arm/i2c_master.h View File

@ -26,15 +26,31 @@
#include "ch.h"
#include <hal.h>
#ifndef I2C1_BANK
#define I2C1_BANK GPIOB
#endif
#ifndef I2C1_SCL
#define I2C1_SCL 6
#endif
#ifndef I2C1_SDA
#define I2C1_SDA 7
#endif
#ifndef I2C_DRIVER
#define I2C_DRIVER I2CD1
#endif
typedef int16_t i2c_status_t;
#define I2C_STATUS_SUCCESS (0)
#define I2C_STATUS_ERROR (-1)
#define I2C_STATUS_TIMEOUT (-2)
void i2c_init(void);
uint8_t i2c_start(uint8_t address);
uint8_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
uint8_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
uint8_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length);
uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
uint8_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
uint8_t i2c_stop(uint16_t timeout);
i2c_status_t i2c_start(uint8_t address);
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_transmit_receive(uint8_t address, uint8_t * tx_body, uint16_t tx_length, uint8_t * rx_body, uint16_t rx_length);
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t* regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
void i2c_stop(void);

+ 101
- 0
drivers/avr/apa102.c View File

@ -0,0 +1,101 @@
/*
* APA102 lib V1.0a
*
* Controls APA102 RGB-LEDs
* Author: Mikkel (Duckle29 on github)
*
* Dec 22th, 2017 v1.0a Initial Version
*
* 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 "apa102.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#include "debug.h"
// Setleds for standard RGB
void inline apa102_setleds(LED_TYPE *ledarray, uint16_t leds){
apa102_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF), _BV(RGB_CLK_PIN & 0xF));
}
void static inline apa102_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask_DI, uint8_t pinmask_CLK){
pinMode(RGB_DI_PIN, PinDirectionOutput);
pinMode(RGB_CLK_PIN, PinDirectionOutput);
apa102_send_array((uint8_t*)ledarray,leds)
}
void apa102_send_array(uint8_t *data, uint16_t leds){ // Data is struct of 3 bytes. RGB - leds is number of leds in data
apa102_start_frame();
while(leds--){
apa102_send_frame(0xFF000000 | (data->b << 16) | (data->g << 8) | data->r);
data++;
}
apa102_end_frame(leds);
}
void apa102_send_frame(uint32_t frame){
for(uint32_t i=0xFF; i>0;){
apa102_send_byte(frame & i);
i = i << 8;
}
}
void apa102_start_frame(){
apa102_send_frame(0);
}
void apa102_end_frame(uint16_t leds)
{
// This function has been taken from: https://github.com/pololu/apa102-arduino/blob/master/APA102.h
// and adapted. The code is MIT licensed. I think thats compatible?
// We need to send some more bytes to ensure that all the LEDs in the
// chain see their new color and start displaying it.
//
// The data stream seen by the last LED in the chain will be delayed by
// (count - 1) clock edges, because each LED before it inverts the clock
// line and delays the data by one clock edge. Therefore, to make sure
// the last LED actually receives the data we wrote, the number of extra
// edges we send at the end of the frame must be at least (count - 1).
// For the APA102C, that is sufficient.
//
// The SK9822 only updates after it sees 32 zero bits followed by one more
// rising edge. To avoid having the update time depend on the color of
// the last LED, we send a dummy 0xFF byte. (Unfortunately, this means
// that partial updates of the beginning of an LED strip are not possible;
// the LED after the last one you are trying to update will be black.)
// After that, to ensure that the last LED in the chain sees 32 zero bits
// and a rising edge, we need to send at least 65 + (count - 1) edges. It
// is sufficent and simpler to just send (5 + count/16) bytes of zeros.
//
// We are ignoring the specification for the end frame in the APA102/SK9822
// datasheets because it does not actually ensure that all the LEDs will
// start displaying their new colors right away.
apa102_send_byte(0xFF);
for (uint16_t i = 0; i < 5 + leds / 16; i++){
apa102_send_byte(0);
}
}
void apa102_send_byte(uint8_t byte){
uint8_t i;
for (i = 0; i < 8; i++){
digitalWrite(RGB_DI_PIN, !!(byte & (1 << (7-i)));
digitalWrite(RGB_CLK_PIN, PinLevelHigh);
}
}

+ 46
- 0
drivers/avr/apa102.h View File

@ -0,0 +1,46 @@
/*
* 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"
*
* 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/>.
*/
#pragma once
#include <avr/io.h>
#include <avr/interrupt.h>
#include "rgblight_types.h"
/* 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 50s to reset the LEDs
*/
void apa102_setleds (LED_TYPE *ledarray, uint16_t number_of_leds);
void apa102_setleds_pin (LED_TYPE *ledarray, uint16_t number_of_leds,uint8_t pinmask);
void apa102_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds);

+ 80
- 91
drivers/avr/i2c_master.c View File

@ -7,43 +7,56 @@
#include "i2c_master.h"
#include "timer.h"
#include "wait.h"
#ifndef F_SCL
#define F_SCL 400000UL // SCL frequency
# define F_SCL 400000UL // SCL frequency
#endif
#define Prescaler 1
#define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16 ) / 2)
#define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16) / 2)
void i2c_init(void)
{
TWSR = 0; /* no prescaler */
void i2c_init(void) {
TWSR = 0; /* no prescaler */
TWBR = (uint8_t)TWBR_val;
#ifdef __AVR_ATmega32A__
// set pull-up resistors on I2C bus pins
PORTC |= 0b11;
// enable TWI (two-wire interface)
TWCR |= (1 << TWEN);
// enable TWI interrupt and slave address ACK
TWCR |= (1 << TWIE);
TWCR |= (1 << TWEA);
#endif
}
i2c_status_t i2c_start(uint8_t address, uint16_t timeout)
{
i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
// reset TWI control register
TWCR = 0;
// transmit START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
uint16_t timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
}
// check if the start condition was successfully transmitted
if(((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)){ return I2C_STATUS_ERROR; }
if (((TW_STATUS & 0xF8) != TW_START) && ((TW_STATUS & 0xF8) != TW_REP_START)) {
return I2C_STATUS_ERROR;
}
// load slave address into data register
TWDR = address;
// start transmission of address
TWCR = (1<<TWINT) | (1<<TWEN);
TWCR = (1 << TWINT) | (1 << TWEN);
timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
@ -51,38 +64,39 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout)
// 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 I2C_STATUS_ERROR;
if ((twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK)) {
return I2C_STATUS_ERROR;
}
return I2C_STATUS_SUCCESS;
}
i2c_status_t i2c_write(uint8_t data, uint16_t timeout)
{
i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
// load data into data register
TWDR = data;
// start transmission of data
TWCR = (1<<TWINT) | (1<<TWEN);
TWCR = (1 << TWINT) | (1 << TWEN);
uint16_t timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
}
if( (TW_STATUS & 0xF8) != TW_MT_DATA_ACK ){ return I2C_STATUS_ERROR; }
if ((TW_STATUS & 0xF8) != TW_MT_DATA_ACK) {
return I2C_STATUS_ERROR;
}
return I2C_STATUS_SUCCESS;
}
int16_t i2c_read_ack(uint16_t timeout)
{
int16_t i2c_read_ack(uint16_t timeout) {
// start TWI module and acknowledge data after reception
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
uint16_t timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
@ -92,14 +106,12 @@ int16_t i2c_read_ack(uint16_t timeout)
return TWDR;
}
int16_t i2c_read_nack(uint16_t timeout)
{
int16_t i2c_read_nack(uint16_t timeout) {
// start receiving without acknowledging reception
TWCR = (1<<TWINT) | (1<<TWEN);
TWCR = (1 << TWINT) | (1 << TWEN);
uint16_t timeout_timer = timer_read();
while( !(TWCR & (1<<TWINT)) ) {
while (!(TWCR & (1 << TWINT))) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
@ -109,112 +121,89 @@ int16_t i2c_read_nack(uint16_t timeout)
return TWDR;
}
i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
if (status) return status;
for (uint16_t i = 0; i < length; i++) {
for (uint16_t i = 0; i < length && status >= 0; i++) {
status = i2c_write(data[i], timeout);
if (status) return status;
}
status = i2c_stop(timeout);
if (status) return status;
i2c_stop();
return I2C_STATUS_SUCCESS;
return status;
}
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(address | I2C_READ, timeout);
if (status) return status;
for (uint16_t i = 0; i < (length-1); i++) {
for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
status = i2c_read_ack(timeout);
if (status >= 0) {
data[i] = status;
} else {
return status;
}
}
status = i2c_read_nack(timeout);
if (status >= 0 ) {
data[(length-1)] = status;
} else {
return status;
if (status >= 0) {
status = i2c_read_nack(timeout);
if (status >= 0) {
data[(length - 1)] = status;
}
}
status = i2c_stop(timeout);
if (status) return status;
i2c_stop();
return I2C_STATUS_SUCCESS;
return (status < 0) ? status : I2C_STATUS_SUCCESS;
}
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
if (status) return status;
if (status >= 0) {
status = i2c_write(regaddr, timeout);
status = i2c_write(regaddr, timeout);
if (status) return status;
for (uint16_t i = 0; i < length; i++) {
status = i2c_write(data[i], timeout);
if (status) return status;
for (uint16_t i = 0; i < length && status >= 0; i++) {
status = i2c_write(data[i], timeout);
}
}
status = i2c_stop(timeout);
if (status) return status;
i2c_stop();
return I2C_STATUS_SUCCESS;
return status;
}
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)
{
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
i2c_status_t status = i2c_start(devaddr, timeout);
if (status) return status;
if (status < 0) {
goto error;
}
status = i2c_write(regaddr, timeout);
if (status) return status;
if (status < 0) {
goto error;
}
status = i2c_start(devaddr | 0x01, timeout);
if (status) return status;
for (uint16_t i = 0; i < (length-1); i++) {
for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
status = i2c_read_ack(timeout);
if (status >= 0) {
data[i] = status;
} else {
return status;
}
}
status = i2c_read_nack(timeout);
if (status >= 0 ) {
data[(length-1)] = status;
} else {
return status;
if (status >= 0) {
status = i2c_read_nack(timeout);
if (status >= 0) {
data[(length - 1)] = status;
}
}
status = i2c_stop(timeout);
if (status) return status;
error:
i2c_stop();
return I2C_STATUS_SUCCESS;
return (status < 0) ? status : I2C_STATUS_SUCCESS;
}
i2c_status_t i2c_stop(uint16_t timeout)
{
void i2c_stop(void) {
// transmit STOP condition
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
uint16_t timeout_timer = timer_read();
while(TWCR & (1<<TWSTO)) {
if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) {
return I2C_STATUS_TIMEOUT;
}
}
return I2C_STATUS_SUCCESS;
}
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
}

+ 4
- 4
drivers/avr/i2c_master.h View File

@ -22,10 +22,10 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout);
i2c_status_t i2c_write(uint8_t data, uint16_t timeout);
int16_t i2c_read_ack(uint16_t timeout);
int16_t i2c_read_nack(uint16_t timeout);
i2c_status_t i2c_transmit(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
i2c_status_t i2c_stop(uint16_t timeout);
void i2c_stop(void);
#endif // I2C_MASTER_H
#endif // I2C_MASTER_H

+ 15
- 12
drivers/avr/i2c_slave.c View File

@ -9,23 +9,26 @@
#include "i2c_slave.h"
void i2c_init(uint8_t address){
volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
static volatile uint8_t buffer_address;
static volatile bool slave_has_register_set = false;
void i2c_slave_init(uint8_t address){
// load address into TWI address register
TWAR = (address << 1);
TWAR = address;
// set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
TWCR = (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
}
void i2c_stop(void){
void i2c_slave_stop(void){
// clear acknowledge and enable bits
TWCR &= ~((1 << TWEA) | (1 << TWEN));
}
ISR(TWI_vect){
uint8_t ack = 1;
// temporary stores the received data
//uint8_t data;
switch(TW_STATUS){
case TW_SR_SLA_ACK:
// The device is now a slave receiver
@ -38,13 +41,13 @@ ISR(TWI_vect){
if(!slave_has_register_set){
buffer_address = TWDR;
if (buffer_address >= RX_BUFFER_SIZE){ // address out of bounds dont ack
ack = 0;
buffer_address = 0;
if (buffer_address >= I2C_SLAVE_REG_COUNT) { // address out of bounds dont ack
ack = 0;
buffer_address = 0;
}
slave_has_register_set = true; // address has been receaved now fill in buffer
} else {
rxbuffer[buffer_address] = TWDR;
i2c_slave_reg[buffer_address] = TWDR;
buffer_address++;
}
break;
@ -52,7 +55,7 @@ ISR(TWI_vect){
case TW_ST_SLA_ACK:
case TW_ST_DATA_ACK:
// This device is a slave transmitter and master has requested data
TWDR = txbuffer[buffer_address];
TWDR = i2c_slave_reg[buffer_address];
buffer_address++;
break;
@ -63,6 +66,6 @@ ISR(TWI_vect){
break;
}
// Reset i2c state mahcine to be ready for next interrupt
// Reset i2c state machine to be ready for next interrupt
TWCR |= (1 << TWIE) | (1 << TWINT) | (ack << TWEA) | (1 << TWEN);
}

+ 4
- 9
drivers/avr/i2c_slave.h View File

@ -8,16 +8,11 @@
#ifndef I2C_SLAVE_H
#define I2C_SLAVE_H
#define TX_BUFFER_SIZE 30
#define RX_BUFFER_SIZE 30
#define I2C_SLAVE_REG_COUNT 30
volatile uint8_t buffer_address;
static volatile bool slave_has_register_set = false;
volatile uint8_t txbuffer[TX_BUFFER_SIZE];
volatile uint8_t rxbuffer[RX_BUFFER_SIZE];
extern volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
void i2c_init(uint8_t address);
void i2c_stop(void);
ISR(TWI_vect);
void i2c_slave_init(uint8_t address);
void i2c_slave_stop(void);
#endif // I2C_SLAVE_H

+ 27
- 2
drivers/avr/ws2812.c View File

@ -27,6 +27,12 @@
#include <util/delay.h>
#include "debug.h"
#if !defined(LED_ARRAY) && defined(RGB_MATRIX_ENABLE)
// LED color buffer
LED_TYPE led[DRIVER_LED_TOTAL];
#define LED_ARRAY led
#endif
#ifdef RGBW_BB_TWI
// Port for the I2C
@ -128,11 +134,11 @@ unsigned char I2C_Write(unsigned char c)
c <<= 1;
}
I2C_WriteBit(0);
_delay_us(I2C_DELAY);
_delay_us(I2C_DELAY);
// _delay_us(I2C_DELAY);
//return I2C_ReadBit();
return 0;
@ -141,6 +147,25 @@ unsigned char I2C_Write(unsigned char c)
#endif
#ifdef RGB_MATRIX_ENABLE
// Set an led in the buffer to a color
void inline ws2812_setled(int i, uint8_t r, uint8_t g, uint8_t b)
{
led[i].r = r;
led[i].g = g;
led[i].b = b;
}
void ws2812_setled_all (uint8_t r, uint8_t g, uint8_t b)
{
for (int i = 0; i < sizeof(led)/sizeof(led[0]); i++) {
led[i].r = r;
led[i].g = g;
led[i].b = b;
}
}
#endif
// Setleds for standard RGB
void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds)
{


+ 4
- 1
drivers/avr/ws2812.h View File

@ -30,7 +30,6 @@
#include "rgblight_types.h"
/* User Interface
*
* Input:
@ -43,6 +42,10 @@
* - Send out the LED data
* - Wait 50s to reset the LEDs
*/
#ifdef RGB_MATRIX_ENABLE
void ws2812_setled (int index, uint8_t r, uint8_t g, uint8_t b);
void ws2812_setled_all (uint8_t r, uint8_t g, uint8_t b);
#endif
void ws2812_setleds (LED_TYPE *ledarray, uint16_t number_of_leds);
void ws2812_setleds_pin (LED_TYPE *ledarray, uint16_t number_of_leds,uint8_t pinmask);


+ 12
- 12
drivers/haptic/DRV2605L.c View File

@ -21,7 +21,7 @@
#include <math.h>
uint8_t DRV2605L_transfer_buffer[20];
uint8_t DRV2605L_transfer_buffer[2];
uint8_t DRV2605L_tx_register[0];
uint8_t DRV2605L_read_buffer[0];
uint8_t DRV2605L_read_register;
@ -34,6 +34,11 @@ void DRV_write(uint8_t drv_register, uint8_t settings) {
}
uint8_t DRV_read(uint8_t regaddress) {
#ifdef __AVR__
i2c_readReg(DRV2605L_BASE_ADDRESS << 1,
regaddress, DRV2605L_read_buffer, 1, 100);
DRV2605L_read_register = (uint8_t)DRV2605L_read_buffer[0];
#else
DRV2605L_tx_register[0] = regaddress;
if (MSG_OK != i2c_transmit_receive(DRV2605L_BASE_ADDRESS << 1,
DRV2605L_tx_register, 1,
@ -42,14 +47,13 @@ uint8_t DRV_read(uint8_t regaddress) {
printf("err reading reg \n");
}
DRV2605L_read_register = (uint8_t)DRV2605L_read_buffer[0];
#endif
return DRV2605L_read_register;
}
void DRV_init(void)
{
i2c_init();
i2c_start(DRV2605L_BASE_ADDRESS);
/* 0x07 sets DRV2605 into calibration mode */
DRV_write(DRV_MODE,0x07);
@ -104,21 +108,17 @@ void DRV_init(void)
C4_SET.Bits.C4_AUTO_CAL_TIME = AUTO_CAL_TIME;
DRV_write(DRV_CTRL_4, (uint8_t) C4_SET.Byte);
DRV_write(DRV_LIB_SELECTION,LIB_SELECTION);
//start autocalibration
DRV_write(DRV_GO, 0x01);
/* 0x00 sets DRV2605 out of standby and to use internal trigger
* 0x01 sets DRV2605 out of standby and to use external trigger */
DRV_write(DRV_MODE,0x00);
/* 0x06: LRA library */
DRV_write(DRV_WAVEFORM_SEQ_1, 0x01);
/* 0xB9: LRA, 4x brake factor, medium gain, 7.5x back EMF
* 0x39: ERM, 4x brake factor, medium gain, 1.365x back EMF */
/* TODO: setup auto-calibration as part of initiation */
//Play greeting sequence
DRV_write(DRV_GO, 0x00);
DRV_write(DRV_WAVEFORM_SEQ_1, DRV_GREETING);
DRV_write(DRV_GO, 0x01);
}
void DRV_pulse(uint8_t sequence)


+ 18
- 8
drivers/haptic/DRV2605L.h View File

@ -31,13 +31,6 @@
#define FB_LOOPGAIN 1 /* For Low:0, Medium:1, High:2, Very High:3 */
#endif
#ifndef RATED_VOLTAGE
#define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */
#ifndef V_PEAK
#define V_PEAK 2.8
#endif
#endif
/* LRA specific settings */
#if FB_ERM_LRA == 1
#ifndef V_RMS
@ -49,6 +42,16 @@
#ifndef F_LRA
#define F_LRA 205
#endif
#ifndef RATED_VOLTAGE
#define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */
#endif
#endif
#ifndef RATED_VOLTAGE
#define RATED_VOLTAGE 2 /* 2v as safe range in case device voltage is not set */
#endif
#ifndef V_PEAK
#define V_PEAK 2.8
#endif
/* Library Selection */
@ -60,6 +63,13 @@
#endif
#endif
#ifndef DRV_GREETING
#define DRV_GREETING alert_750ms
#endif
#ifndef DRV_MODE_DEFAULT
#define DRV_MODE_DEFAULT strong_click1
#endif
/* Control 1 register settings */
#ifndef DRIVE_TIME
#define DRIVE_TIME 25
@ -162,7 +172,6 @@ void DRV_write(const uint8_t drv_register, const uint8_t settings);
uint8_t DRV_read(const uint8_t regaddress);
void DRV_pulse(const uint8_t sequence);
typedef enum DRV_EFFECT{
clear_sequence = 0,
strong_click = 1,
@ -288,6 +297,7 @@ typedef enum DRV_EFFECT{
smooth_hum3_30 = 121,
smooth_hum4_20 = 122,
smooth_hum5_10 = 123,
drv_effect_max = 124,
} DRV_EFFECT;
/* Register bit array unions */


+ 248
- 0
drivers/haptic/haptic.c View File

@ -0,0 +1,248 @@
/* Copyright 2019 ishtob
* Driver for haptic feedback written for QMK
*
* 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 "haptic.h"
#include "eeconfig.h"
#include "progmem.h"
#include "debug.h"
#ifdef DRV2605L
#include "DRV2605L.h"
#endif
#ifdef SOLENOID_ENABLE
#include "solenoid.h"
#endif
haptic_config_t haptic_config;
void haptic_init(void) {
debug_enable = 1; //Debug is ON!
if (!eeconfig_is_enabled()) {
eeconfig_init();
}
haptic_config.raw = eeconfig_read_haptic();
if (haptic_config.mode < 1){
haptic_config.mode = 1;
}
if (!haptic_config.mode){
dprintf("No haptic config found in eeprom, setting default configs\n");
haptic_reset();
}
#ifdef SOLENOID_ENABLE
solenoid_setup();
dprintf("Solenoid driver initialized\n");
#endif
#ifdef DRV2605L
DRV_init();
dprintf("DRV2605 driver initialized\n");
#endif
eeconfig_debug_haptic();
}
void haptic_task(void) {
#ifdef SOLENOID_ENABLE
solenoid_check();
#endif
}
void eeconfig_debug_haptic(void) {
dprintf("haptic_config eprom\n");
dprintf("haptic_config.enable = %d\n", haptic_config.enable);
dprintf("haptic_config.mode = %d\n", haptic_config.mode);
}
void haptic_enable(void) {
haptic_config.enable = 1;
xprintf("haptic_config.enable = %u\n", haptic_config.enable);
eeconfig_update_haptic(haptic_config.raw);
}
void haptic_disable(void) {
haptic_config.enable = 0;
xprintf("haptic_config.enable = %u\n", haptic_config.enable);
eeconfig_update_haptic(haptic_config.raw);
}
void haptic_toggle(void) {
if (haptic_config.enable) {
haptic_disable();
} else {
haptic_enable();
}
eeconfig_update_haptic(haptic_config.raw);
}
void haptic_feedback_toggle(void){
haptic_config.feedback++;
if (haptic_config.feedback >= HAPTIC_FEEDBACK_MAX)
haptic_config.feedback = KEY_PRESS;
xprintf("haptic_config.feedback = %u\n", !haptic_config.feedback);
eeconfig_update_haptic(haptic_config.raw);
}
void haptic_buzz_toggle(void) {
bool buzz_stat = !haptic_config.buzz;
haptic_config.buzz = buzz_stat;
haptic_set_buzz(buzz_stat);
}
void haptic_mode_increase(void) {
uint8_t mode = haptic_config.mode + 1;
#ifdef DRV2605L
if (haptic_config.mode >= drv_effect_max) {
mode = 1;
}
#endif
haptic_set_mode(mode);
}
void haptic_mode_decrease(void) {
uint8_t mode = haptic_config.mode -1;
#ifdef DRV2605L
if (haptic_config.mode < 1) {
mode = (drv_effect_max - 1);
}
#endif
haptic_set_mode(mode);
}
void haptic_dwell_increase(void) {
uint8_t dwell = haptic_config.dwell + 1;
#ifdef SOLENOID_ENABLE
if (haptic_config.dwell >= SOLENOID_MAX_DWELL) {
dwell = 1;
}
solenoid_set_dwell(dwell);
#endif
haptic_set_dwell(dwell);
}
void haptic_dwell_decrease(void) {
uint8_t dwell = haptic_config.dwell -1;
#ifdef SOLENOID_ENABLE
if (haptic_config.dwell < SOLENOID_MIN_DWELL) {
dwell = SOLENOID_MAX_DWELL;
}
solenoid_set_dwell(dwell);
#endif
haptic_set_dwell(dwell);
}
void haptic_reset(void){
haptic_config.enable = true;
uint8_t feedback = HAPTIC_FEEDBACK_DEFAULT;
haptic_config.feedback = feedback;
#ifdef DRV2605L
uint8_t mode = HAPTIC_MODE_DEFAULT;
haptic_config.mode = mode;
#endif
#ifdef SOLENOID_ENABLE
uint8_t dwell = SOLENOID_DEFAULT_DWELL;
haptic_config.dwell = dwell;
#endif
eeconfig_update_haptic(haptic_config.raw);
xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
xprintf("haptic_config.mode = %u\n", haptic_config.mode);
}
void haptic_set_feedback(uint8_t feedback) {
haptic_config.feedback = feedback;
eeconfig_update_haptic(haptic_config.raw);
xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
}
void haptic_set_mode(uint8_t mode) {
haptic_config.mode = mode;
eeconfig_update_haptic(haptic_config.raw);
xprintf("haptic_config.mode = %u\n", haptic_config.mode);
}
void haptic_set_buzz(uint8_t buzz) {
haptic_config.buzz = buzz;
eeconfig_update_haptic(haptic_config.raw);
xprintf("haptic_config.buzz = %u\n", haptic_config.buzz);
}
void haptic_set_dwell(uint8_t dwell) {
haptic_config.dwell = dwell;
eeconfig_update_haptic(haptic_config.raw);
xprintf("haptic_config.dwell = %u\n", haptic_config.dwell);
}
uint8_t haptic_get_mode(void) {
if (!haptic_config.enable){
return false;
}
return haptic_config.mode;
}
uint8_t haptic_get_feedback(void) {
if (!haptic_config.enable){
return false;
}
return haptic_config.feedback;
}
uint8_t haptic_get_dwell(void) {
if (!haptic_config.enable){
return false;
}
return haptic_config.dwell;
}
void haptic_play(void) {
#ifdef DRV2605L
uint8_t play_eff = 0;
play_eff = haptic_config.mode;
DRV_pulse(play_eff);
#endif
#ifdef SOLENOID_ENABLE
solenoid_fire();
#endif
}
bool process_haptic(uint16_t keycode, keyrecord_t *record) {
if (keycode == HPT_ON && record->event.pressed) { haptic_enable(); }
if (keycode == HPT_OFF && record->event.pressed) { haptic_disable(); }
if (keycode == HPT_TOG && record->event.pressed) { haptic_toggle(); }
if (keycode == HPT_RST && record->event.pressed) { haptic_reset(); }
if (keycode == HPT_FBK && record->event.pressed) { haptic_feedback_toggle(); }
if (keycode == HPT_BUZ && record->event.pressed) { haptic_buzz_toggle(); }
if (keycode == HPT_MODI && record->event.pressed) { haptic_mode_increase(); }
if (keycode == HPT_MODD && record->event.pressed) { haptic_mode_decrease(); }
if (keycode == HPT_DWLI && record->event.pressed) { haptic_dwell_increase(); }
if (keycode == HPT_DWLD && record->event.pressed) { haptic_dwell_decrease(); }
if (haptic_config.enable) {
if ( record->event.pressed ) {
// keypress
if (haptic_config.feedback < 2) {
haptic_play();
}
} else {
//keyrelease
if (haptic_config.feedback > 0) {
haptic_play();
}
}
}
return true;
}
void haptic_shutdown(void) {
#ifdef SOLENOID_ENABLE
solenoid_shutdown();
#endif
}

+ 82
- 0
drivers/haptic/haptic.h View File

@ -0,0 +1,82 @@
/* Copyright 2019 ishtob
* Driver for haptic feedback written for QMK
*
* 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/>.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "quantum.h"
#ifdef DRV2605L
#include "DRV2605L.h"
#endif
#ifndef HAPTIC_FEEDBACK_DEFAULT
#define HAPTIC_FEEDBACK_DEFAULT 0
#endif
#ifndef HAPTIC_MODE_DEFAULT
#define HAPTIC_MODE_DEFAULT DRV_MODE_DEFAULT
#endif
/* EEPROM config settings */
typedef union {
uint32_t raw;
struct {
bool enable :1;
uint8_t feedback :2;
uint8_t mode :7;
bool buzz :1;
uint8_t dwell :7;
uint16_t reserved :16;
};
} haptic_config_t;
typedef enum HAPTIC_FEEDBACK{
KEY_PRESS,
KEY_PRESS_RELEASE,
KEY_RELEASE,
HAPTIC_FEEDBACK_MAX,
} HAPTIC_FEEDBACK;
bool process_haptic(uint16_t keycode, keyrecord_t *record);
void haptic_init(void);
void haptic_task(void);
void eeconfig_debug_haptic(void);
void haptic_enable(void);
void haptic_disable(void);
void haptic_toggle(void);
void haptic_feedback_toggle(void);
void haptic_mode_increase(void);
void haptic_mode_decrease(void);
void haptic_mode(uint8_t mode);
void haptic_reset(void);
void haptic_set_feedback(uint8_t feedback);
void haptic_set_mode(uint8_t mode);
void haptic_set_dwell(uint8_t dwell);
void haptic_set_buzz(uint8_t buzz);
void haptic_buzz_toggle(void);
uint8_t haptic_get_mode(void);
uint8_t haptic_get_feedback(void);
void haptic_dwell_increase(void);
void haptic_dwell_decrease(void);
void haptic_play(void);
void haptic_shutdown(void);

+ 109
- 0
drivers/haptic/solenoid.c View File

@ -0,0 +1,109 @@
/* Copyright 2018 mtdjr - modified by ishtob
* Driver for solenoid written for QMK
*
* 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 <timer.h>
#include "solenoid.h"
#include "haptic.h"
bool solenoid_on = false;
bool solenoid_buzzing = false;
uint16_t solenoid_start = 0;
uint8_t solenoid_dwell = SOLENOID_DEFAULT_DWELL;
extern haptic_config_t haptic_config;
void solenoid_buzz_on(void) {
haptic_set_buzz(1);
}
void solenoid_buzz_off(void) {
haptic_set_buzz(0);
}
void solenoid_set_buzz(int buzz) {
haptic_set_buzz(buzz);
}
void solenoid_dwell_minus(uint8_t solenoid_dwell) {
if (solenoid_dwell > 0) solenoid_dwell--;
}
void solenoid_dwell_plus(uint8_t solenoid_dwell) {
if (solenoid_dwell < SOLENOID_MAX_DWELL) solenoid_dwell++;
}
void solenoid_set_dwell(uint8_t dwell) {
solenoid_dwell = dwell;
}
void solenoid_stop(void) {
writePinLow(SOLENOID_PIN);
solenoid_on = false;
solenoid_buzzing = false;
}
void solenoid_fire(void) {
if (!haptic_config.buzz && solenoid_on) return;
if (haptic_config.buzz && solenoid_buzzing) return;
solenoid_on = true;
solenoid_buzzing = true;
solenoid_start = timer_read();
writePinHigh(SOLENOID_PIN);
}
void solenoid_check(void) {
uint16_t elapsed = 0;
if (!solenoid_on) return;
elapsed = timer_elapsed(solenoid_start);
//Check if it's time to finish this solenoid click cycle
if (elapsed > solenoid_dwell) {
solenoid_stop();
return;
}
//Check whether to buzz the solenoid on and off
if (haptic_config.buzz) {
if (elapsed / SOLENOID_MIN_DWELL % 2 == 0){
if (!solenoid_buzzing) {
solenoid_buzzing = true;
writePinHigh(SOLENOID_PIN);
}
}
else {
if (solenoid_buzzing) {
solenoid_buzzing = false;
writePinLow(SOLENOID_PIN);
}
}
}
}
void solenoid_setup(void) {
setPinOutput(SOLENOID_PIN);
solenoid_fire();
}
void solenoid_shutdown(void) {
writePinLow(SOLENOID_PIN);
}

+ 54
- 0
drivers/haptic/solenoid.h View File

@ -0,0 +1,54 @@
/* Copyright 2018 mtdjr - modified by ishtob
* Driver for solenoid written for QMK
*
* 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/>.
*/
#pragma once
#ifndef SOLENOID_DEFAULT_DWELL
#define SOLENOID_DEFAULT_DWELL 12
#endif
#ifndef SOLENOID_MAX_DWELL
#define SOLENOID_MAX_DWELL 100
#endif
#ifndef SOLENOID_MIN_DWELL
#define SOLENOID_MIN_DWELL 4
#endif
#ifndef SOLENOID_ACTIVE
#define SOLENOID_ACTIVE false
#endif
#ifndef SOLENOID_PIN
#define SOLENOID_PIN F6
#endif
void solenoid_buzz_on(void);
void solenoid_buzz_off(void);
void solenoid_set_buzz(int buzz);
void solenoid_dwell_minus(uint8_t solenoid_dwell);
void solenoid_dwell_plus(uint8_t solenoid_dwell);
void solenoid_set_dwell(uint8_t dwell);
void solenoid_stop(void);
void solenoid_fire(void);
void solenoid_check(void);
void solenoid_setup(void);
void solenoid_shutdown(void);

+ 246
- 0
drivers/issi/is31fl3731-simple.c View File

@ -0,0 +1,246 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2019 Clueboard
*
* 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/>.
*/
#ifdef __AVR__
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#else
#include "wait.h"
#endif
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "is31fl3731-simple.h"
#include "i2c_master.h"
#include "progmem.h"
#include "print.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'
#ifndef ISSI_TIMEOUT
#define ISSI_TIMEOUT 100
#endif
#ifndef ISSI_PERSISTENCE
#define ISSI_PERSISTENCE 0
#endif
// 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[LED_DRIVER_COUNT][144];
bool g_pwm_buffer_update_required = false;
/* There's probably a better way to init this... */
#if LED_DRIVER_COUNT == 1
uint8_t g_led_control_registers[LED_DRIVER_COUNT][18] = {{0}};
#elif LED_DRIVER_COUNT == 2
uint8_t g_led_control_registers[LED_DRIVER_COUNT][18] = {{0}, {0}};
#elif LED_DRIVER_COUNT == 3
uint8_t g_led_control_registers[LED_DRIVER_COUNT][18] = {{0}, {0}, {0}};
#elif LED_DRIVER_COUNT == 4
uint8_t g_led_control_registers[LED_DRIVER_COUNT][18] = {{0}, {0}, {0}, {0}};
#endif
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;
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0) {
break;
}
}
#else
i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT);
#endif
}
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];
}
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) == 0)
break;
}
#else
i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT);
#endif
}
}
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_value(int index, uint8_t value) {
if (index >= 0 && index < LED_DRIVER_LED_COUNT) {
is31_led led = g_is31_leds[index];
// Subtract 0x24 to get the second index of g_pwm_buffer
g_pwm_buffer[led.driver][led.v - 0x24] = value;
g_pwm_buffer_update_required = true;
}
}
void IS31FL3731_set_value_all(uint8_t value) {
for (int i = 0; i < LED_DRIVER_LED_COUNT; i++) {
IS31FL3731_set_value(i, value);
}
}
void IS31FL3731_set_led_control_register(uint8_t index, bool value) {
is31_led led = g_is31_leds[index];
uint8_t control_register = (led.v - 0x24) / 8;
uint8_t bit_value = (led.v - 0x24) % 8;
if (value) {
g_led_control_registers[led.driver][control_register] |= (1 << bit_value);
} else {
g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value);
}
g_led_control_registers_update_required = true;
}
void IS31FL3731_update_pwm_buffers(uint8_t addr, uint8_t index) {
if (g_pwm_buffer_update_required) {
IS31FL3731_write_pwm_buffer(addr, g_pwm_buffer[index]);
g_pwm_buffer_update_required = false;
}
}
void IS31FL3731_update_led_control_registers(uint8_t addr, uint8_t index) {
if (g_led_control_registers_update_required) {
for (int i=0; i<18; i++) {
IS31FL3731_write_register(addr, i, g_led_control_registers[index][i]);
}
}
}

+ 210
- 0
drivers/issi/is31fl3731-simple.h View File

@ -0,0 +1,210 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2019 Clueboard
*
* 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 IS31FL3731_DRIVER_H
#define IS31FL3731_DRIVER_H
typedef struct is31_led {
uint8_t driver:2;
uint8_t v;
} __attribute__((packed)) is31_led;
extern const is31_led g_is31_leds[LED_DRIVER_LED_COUNT];
void IS31FL3731_init(uint8_t addr);
void IS31FL3731_write_register(uint8_t addr, uint8_t reg, uint8_t data);
void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
void IS31FL3731_set_value(int index, uint8_t value);
void IS31FL3731_set_value_all(uint8_t value);
void IS31FL3731_set_led_control_register(uint8_t index, bool value);
// This should not be called from an interrupt
// (eg. from a timer interrupt).
// Call this while idle (in between matrix scans).
// If the buffer is dirty, it will update the driver with the buffer.
void IS31FL3731_update_pwm_buffers(uint8_t addr, uint8_t index);
void IS31FL3731_update_led_control_registers(uint8_t addr, uint8_t index);
#define C1_1 0x24
#define C1_2 0x25
#define C1_3 0x26
#define C1_4 0x27
#define C1_5 0x28
#define C1_6 0x29
#define C1_7 0x2A
#define C1_8 0x2B
#define C1_9 0x2C
#define C1_10 0x2D
#define C1_11 0x2E
#define C1_12 0x2F
#define C1_13 0x30
#define C1_14 0x31
#define C1_15 0x32
#define C1_16 0x33
#define C2_1 0x34
#define C2_2 0x35
#define C2_3 0x36
#define C2_4 0x37
#define C2_5 0x38
#define C2_6 0x39
#define C2_7 0x3A
#define C2_8 0x3B
#define C2_9 0x3C
#define C2_10 0x3D
#define C2_11 0x3E
#define C2_12 0x3F
#define C2_13 0x40
#define C2_14 0x41
#define C2_15 0x42
#define C2_16 0x43
#define C3_1 0x44
#define C3_2 0x45
#define C3_3 0x46
#define C3_4 0x47
#define C3_5 0x48
#define C3_6 0x49
#define C3_7 0x4A
#define C3_8 0x4B
#define C3_9 0x4C
#define C3_10 0x4D
#define C3_11 0x4E
#define C3_12 0x4F
#define C3_13 0x50
#define C3_14 0x51
#define C3_15 0x52
#define C3_16 0x53
#define C4_1 0x54
#define C4_2 0x55
#define C4_3 0x56
#define C4_4 0x57
#define C4_5 0x58
#define C4_6 0x59
#define C4_7 0x5A
#define C4_8 0x5B
#define C4_9 0x5C
#define C4_10 0x5D
#define C4_11 0x5E
#define C4_12 0x5F
#define C4_13 0x60
#define C4_14 0x61
#define C4_15 0x62
#define C4_16 0x63
#define C5_1 0x64
#define C5_2 0x65
#define C5_3 0x66
#define C5_4 0x67
#define C5_5 0x68
#define C5_6 0x69
#define C5_7 0x6A
#define C5_8 0x6B
#define C5_9 0x6C
#define C5_10 0x6D
#define C5_11 0x6E
#define C5_12 0x6F
#define C5_13 0x70
#define C5_14 0x71
#define C5_15 0x72
#define C5_16 0x73
#define C6_1 0x74
#define C6_2 0x75
#define C6_3 0x76
#define C6_4 0x77
#define C6_5 0x78
#define C6_6 0x79
#define C6_7 0x7A
#define C6_8 0x7B
#define C6_9 0x7C
#define C6_10 0x7D
#define C6_11 0x7E
#define C6_12 0x7F
#define C6_13 0x80
#define C6_14 0x81
#define C6_15 0x82
#define C6_16 0x83
#define C7_1 0x84
#define C7_2 0x85
#define C7_3 0x86
#define C7_4 0x87
#define C7_5 0x88
#define C7_6 0x89
#define C7_7 0x8A
#define C7_8 0x8B
#define C7_9 0x8C
#define C7_10 0x8D
#define C7_11 0x8E
#define C7_12 0x8F
#define C7_13 0x90
#define C7_14 0x91
#define C7_15 0x92
#define C7_16 0x93
#define C8_1 0x94
#define C8_2 0x95
#define C8_3 0x96
#define C8_4 0x97
#define C8_5 0x98
#define C8_6 0x99
#define C8_7 0x9A
#define C8_8 0x9B
#define C8_9 0x9C
#define C8_10 0x9D
#define C8_11 0x9E
#define C8_12 0x9F
#define C8_13 0xA0
#define C8_14 0xA1
#define C8_15 0xA2
#define C8_16 0xA3
#define C9_1 0xA4
#define C9_2 0xA5
#define C9_3 0xA6
#define C9_4 0xA7
#define C9_5 0xA8
#define C9_6 0xA9
#define C9_7 0xAA
#define C9_8 0xAB
#define C9_9 0xAC
#define C9_10 0xAD
#define C9_11 0xAE
#define C9_12 0xAF
#define C9_13 0xB0
#define C9_14 0xB1
#define C9_15 0xB2
#define C9_16 0xB3
#endif // IS31FL3731_DRIVER_H

+ 1
- 1
drivers/issi/is31fl3733.c View File

@ -24,10 +24,10 @@
#include "wait.h"
#endif
#include "is31fl3733.h"
#include <string.h>
#include "i2c_master.h"
#include "progmem.h"
#include "rgb_matrix.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)


+ 252
- 0
drivers/issi/is31fl3737.c View File

@ -0,0 +1,252 @@
/* Copyright 2017 Jason Williams
* Copyright 2018 Jack Humbert
* Copyright 2018 Yiancar
*
* 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/>.
*/
#ifdef __AVR__
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
#else
#include "wait.h"
#endif
#include <string.h>
#include "i2c_master.h"
#include "progmem.h"
#include "rgb_matrix.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:
// 00 <-> GND
// 01 <-> SCL
// 10 <-> SDA
// 11 <-> VCC
// ADDR1 represents A1:A0 of the 7-bit address.
// ADDR2 represents A3:A2 of the 7-bit address.
// The result is: 0b101(ADDR2)(ADDR1)
#define ISSI_ADDR_DEFAULT 0x50
#define ISSI_COMMANDREGISTER 0xFD
#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE
#define ISSI_INTERRUPTMASKREGISTER 0xF0
#define ISSI_INTERRUPTSTATUSREGISTER 0xF1
#define ISSI_PAGE_LEDCONTROL 0x00 //PG0
#define ISSI_PAGE_PWM 0x01 //PG1
#define ISSI_PAGE_AUTOBREATH 0x02 //PG2
#define ISSI_PAGE_FUNCTION 0x03 //PG3
#define ISSI_REG_CONFIGURATION 0x00 //PG3
#define ISSI_REG_GLOBALCURRENT 0x01 //PG3
#define ISSI_REG_RESET 0x11// PG3
#define ISSI_REG_SWPULLUP 0x0F //PG3
#define ISSI_REG_CSPULLUP 0x10 //PG3
#ifndef ISSI_TIMEOUT
#define ISSI_TIMEOUT 100
#endif
#ifndef ISSI_PERSISTENCE
#define ISSI_PERSISTENCE 0
#endif
// Transfer buffer for TWITransmitData()
uint8_t g_twi_transfer_buffer[20];
// These buffers match the IS31FL3737 PWM registers.
// The control buffers match the PG0 LED On/Off registers.
// 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 IS31FL3737_write_pwm_buffer() but it's
// probably not worth the extra complexity.
uint8_t g_pwm_buffer[DRIVER_COUNT][192];
bool g_pwm_buffer_update_required = false;
uint8_t g_led_control_registers[DRIVER_COUNT][24] = { { 0 } };
bool g_led_control_registers_update_required = false;
void IS31FL3737_write_register( uint8_t addr, uint8_t reg, uint8_t data )
{
g_twi_transfer_buffer[0] = reg;
g_twi_transfer_buffer[1] = data;
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) == 0)
break;
}
#else
i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT);
#endif
}
void IS31FL3737_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer )
{
// assumes PG1 is already selected
// transmit PWM registers in 12 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 < 192; i += 16 ) {
g_twi_transfer_buffer[0] = i;
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer
for ( int j = 0; j < 16; j++ ) {
g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j];
}
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {
if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) == 0)
break;
}
#else
i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT);
#endif
}
}
void IS31FL3737_init( uint8_t addr )
{
// In order to avoid the LEDs being driven with garbage data
// in the LED driver's PWM registers, shutdown is enabled last.
// Set up the mode and other settings, clear the PWM registers,
// then disable software shutdown.
// Unlock the command register.
IS31FL3737_write_register( addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5 );
// Select PG0
IS31FL3737_write_register( addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL );
// Turn off all LEDs.
for ( int i = 0x00; i <= 0x17; i++ )
{
IS31FL3737_write_register( addr, i, 0x00 );
}
// Unlock the command register.
IS31FL3737_write_register( addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5 );
// Select PG1
IS31FL3737_write_register( addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM );
// Set PWM on all LEDs to 0
// No need to setup Breath registers to PWM as that is the default.
for ( int i = 0x00; i <= 0xBF; i++ )
{
IS31FL3737_write_register( addr, i, 0x00 );
}
// Unlock the command register.
IS31FL3737_write_register( addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5 );
// Select PG3
IS31FL3737_write_register( addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION );
// Set global current to maximum.
IS31FL3737_write_register( addr, ISSI_REG_GLOBALCURRENT, 0xFF );
// Disable software shutdown.
IS31FL3737_write_register( addr, ISSI_REG_CONFIGURATION, 0x01 );
// Wait 10ms to ensure the device has woken up.
#ifdef __AVR__
_delay_ms( 10 );
#else
wait_ms(10);
#endif
}
void IS31FL3737_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];
g_pwm_buffer[led.driver][led.r] = red;
g_pwm_buffer[led.driver][led.g] = green;
g_pwm_buffer[led.driver][led.b] = blue;
g_pwm_buffer_update_required = true;
}
}
void IS31FL3737_set_color_all( uint8_t red, uint8_t green, uint8_t blue )
{
for ( int i = 0; i < DRIVER_LED_TOTAL; i++ )
{
IS31FL3737_set_color( i, red, green, blue );
}
}
void IS31FL3737_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 / 8;
uint8_t control_register_g = led.g / 8;
uint8_t control_register_b = led.b / 8;
uint8_t bit_r = led.r % 8;
uint8_t bit_g = led.g % 8;
uint8_t bit_b = led.b % 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 IS31FL3737_update_pwm_buffers( uint8_t addr1, uint8_t addr2 )
{
if ( g_pwm_buffer_update_required )
{
// Firstly we need to unlock the command register and select PG1
IS31FL3737_write_register( addr1, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5 );
IS31FL3737_write_register( addr1, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM );
IS31FL3737_write_pwm_buffer( addr1, g_pwm_buffer[0] );
//IS31FL3737_write_pwm_buffer( addr2, g_pwm_buffer[1] );
}
g_pwm_buffer_update_required = false;
}
void IS31FL3737_update_led_control_registers( uint8_t addr1, uint8_t addr2 )
{
if ( g_led_control_registers_update_required )
{
// Firstly we need to unlock the command register and select PG0
IS31FL3737_write_register( addr1, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5 );
IS31FL3737_write_register( addr1, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL );
for ( int i=0; i<24; i++ )
{
IS31FL3737_write_register(addr1, i, g_led_control_registers[0][i] );
//IS31FL3737_write_register(addr2, i, g_led_control_registers[1][i] );
}
}
}

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

Loading…
Cancel
Save