add support for encoders to core
This commit is contained in:
		
							parent
							
								
									e22c399245
								
							
						
					
					
						commit
						85688e5b52
					
				
					 11 changed files with 166 additions and 29 deletions
				
			
		| 
						 | 
				
			
			@ -219,6 +219,11 @@ ifeq ($(strip $(USB_HID_ENABLE)), yes)
 | 
			
		|||
    include $(TMK_DIR)/protocol/usb_hid.mk
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(strip $(ENCODER_ENABLE)), yes)
 | 
			
		||||
    SRC += $(QUANTUM_DIR)/encoder.c
 | 
			
		||||
    OPT_DEFS += -DENCODER_ENABLE
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(strip $(HD44780_ENABLE)), yes)
 | 
			
		||||
    SRC += drivers/avr/hd44780.c
 | 
			
		||||
    OPT_DEFS += -DHD44780_ENABLE
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,6 +52,7 @@
 | 
			
		|||
  * [Combos](feature_combo)
 | 
			
		||||
  * [Command](feature_command.md)
 | 
			
		||||
  * [Dynamic Macros](feature_dynamic_macros.md)
 | 
			
		||||
  * [Encoders](feature_encoders.md)
 | 
			
		||||
  * [Grave Escape](feature_grave_esc.md)
 | 
			
		||||
  * [Key Lock](feature_key_lock.md)
 | 
			
		||||
  * [Layouts](feature_layouts.md)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,6 +52,7 @@
 | 
			
		|||
  * [Combos](feature_combo)
 | 
			
		||||
  * [Command](feature_command.md)
 | 
			
		||||
  * [Dynamic Macros](feature_dynamic_macros.md)
 | 
			
		||||
  * [Encoders](feature_encoders.md)
 | 
			
		||||
  * [Grave Escape](feature_grave_esc.md)
 | 
			
		||||
  * [Key Lock](feature_key_lock.md)
 | 
			
		||||
  * [Layouts](feature_layouts.md)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										41
									
								
								docs/feature_encoders.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								docs/feature_encoders.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
# Encoders
 | 
			
		||||
 | 
			
		||||
Basic encoders are supported by adding this to your `rules.mk`:
 | 
			
		||||
 | 
			
		||||
    ENCODER_ENABLE = yes
 | 
			
		||||
 | 
			
		||||
and this to your `config.h`:
 | 
			
		||||
 | 
			
		||||
    #define NUMBER_OF_ENCODERS 1
 | 
			
		||||
    #define ENCODERS_PAD_A { B12 }
 | 
			
		||||
    #define ENCODERS_PAD_B { B13 }
 | 
			
		||||
 | 
			
		||||
Each PAD_A/B variable defines an array so multiple encoders can be defined, e.g.:
 | 
			
		||||
 | 
			
		||||
    #define ENCODERS_PAD_A { encoder1a, encoder2a }
 | 
			
		||||
    #define ENCODERS_PAD_B { encoder1a, encoder2b }
 | 
			
		||||
 | 
			
		||||
If your encoder's clockwise directions are incorrect, you can swap the A & B pad definitions.
 | 
			
		||||
 | 
			
		||||
Additionally, the resolution can be specified in the same file (the default & suggested is 4):
 | 
			
		||||
 | 
			
		||||
    #define ENCODER_RESOLUTION 4
 | 
			
		||||
 | 
			
		||||
## Callbacks
 | 
			
		||||
 | 
			
		||||
The callback functions can be inserted into your `<keyboard>.c`:
 | 
			
		||||
 | 
			
		||||
    void encoder_update_kb(uint8_t index, bool clockwise) {
 | 
			
		||||
        encoder_update_user(index, clockwise);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
or `keymap.c`:
 | 
			
		||||
 | 
			
		||||
    void encoder_update_user(uint8_t index, bool clockwise) {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Hardware
 | 
			
		||||
 | 
			
		||||
The A an B lines of the encoders should be wired directly to the MCU, and the C/common lines should be wired to ground.
 | 
			
		||||
| 
						 | 
				
			
			@ -3,6 +3,8 @@
 | 
			
		|||
 | 
			
		||||
#include "quantum.h"
 | 
			
		||||
 | 
			
		||||
#define encoder_update(clockwise) encoder_update_user(uint8_t index, clockwise)
 | 
			
		||||
 | 
			
		||||
#ifdef __AVR__
 | 
			
		||||
#define LAYOUT_planck_mit( \
 | 
			
		||||
	k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0a, k0b, \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,10 @@
 | 
			
		|||
 * #define UNUSED_PINS
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define NUMBER_OF_ENCODERS 1
 | 
			
		||||
#define ENCODERS_PAD_A { B12 }
 | 
			
		||||
#define ENCODERS_PAD_B { B13 }
 | 
			
		||||
 | 
			
		||||
#define MUSIC_MAP
 | 
			
		||||
#undef AUDIO_VOICES
 | 
			
		||||
#undef C6_AUDIO
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,10 +21,6 @@ static matrix_row_t matrix_debouncing[MATRIX_COLS];
 | 
			
		|||
static bool debouncing = false;
 | 
			
		||||
static uint16_t debouncing_time = 0;
 | 
			
		||||
 | 
			
		||||
static uint8_t encoder_state = 0;
 | 
			
		||||
static int8_t encoder_value = 0;
 | 
			
		||||
static int8_t encoder_LUT[] = { 0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0 };
 | 
			
		||||
 | 
			
		||||
static bool dip_switch[4] = {0, 0, 0, 0};
 | 
			
		||||
 | 
			
		||||
__attribute__ ((weak))
 | 
			
		||||
| 
						 | 
				
			
			@ -53,12 +49,6 @@ void matrix_init(void) {
 | 
			
		|||
    palSetPadMode(GPIOA, 10, PAL_MODE_INPUT_PULLUP);
 | 
			
		||||
    palSetPadMode(GPIOB, 9,  PAL_MODE_INPUT_PULLUP);
 | 
			
		||||
 | 
			
		||||
    // encoder setup
 | 
			
		||||
    palSetPadMode(GPIOB, 12, PAL_MODE_INPUT_PULLUP);
 | 
			
		||||
    palSetPadMode(GPIOB, 13, PAL_MODE_INPUT_PULLUP);
 | 
			
		||||
 | 
			
		||||
    encoder_state = (palReadPad(GPIOB, 12) << 0) | (palReadPad(GPIOB, 13) << 1);
 | 
			
		||||
 | 
			
		||||
    // actual matrix setup
 | 
			
		||||
    palSetPadMode(GPIOB, 11, PAL_MODE_OUTPUT_PUSHPULL);
 | 
			
		||||
    palSetPadMode(GPIOB, 10, PAL_MODE_OUTPUT_PUSHPULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -87,15 +77,8 @@ void matrix_init(void) {
 | 
			
		|||
__attribute__ ((weak))
 | 
			
		||||
void dip_update(uint8_t index, bool active) { }
 | 
			
		||||
 | 
			
		||||
__attribute__ ((weak))
 | 
			
		||||
void encoder_update(bool clockwise) { }
 | 
			
		||||
 | 
			
		||||
bool last_dip_switch[4] = {0};
 | 
			
		||||
 | 
			
		||||
#ifndef ENCODER_RESOLUTION
 | 
			
		||||
  #define ENCODER_RESOLUTION 4
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
uint8_t matrix_scan(void) {
 | 
			
		||||
    // dip switch
 | 
			
		||||
    dip_switch[0] = !palReadPad(GPIOB, 14);
 | 
			
		||||
| 
						 | 
				
			
			@ -108,18 +91,6 @@ uint8_t matrix_scan(void) {
 | 
			
		|||
    }
 | 
			
		||||
    memcpy(last_dip_switch, dip_switch, sizeof(&dip_switch));
 | 
			
		||||
 | 
			
		||||
    // encoder on B12 and B13
 | 
			
		||||
    encoder_state <<= 2;
 | 
			
		||||
    encoder_state |= (palReadPad(GPIOB, 12) << 0) | (palReadPad(GPIOB, 13) << 1);
 | 
			
		||||
    encoder_value += encoder_LUT[encoder_state & 0xF];
 | 
			
		||||
    if (encoder_value >= ENCODER_RESOLUTION) {
 | 
			
		||||
        encoder_update(0);
 | 
			
		||||
    }
 | 
			
		||||
    if (encoder_value <= -ENCODER_RESOLUTION) { // direction is arbitrary here, but this clockwise
 | 
			
		||||
        encoder_update(1);
 | 
			
		||||
    }
 | 
			
		||||
    encoder_value %= ENCODER_RESOLUTION;
 | 
			
		||||
 | 
			
		||||
    // actual matrix
 | 
			
		||||
    for (int col = 0; col < MATRIX_COLS; col++) {
 | 
			
		||||
        matrix_row_t data = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,3 +54,4 @@ CUSTOM_MATRIX = yes # Custom matrix file
 | 
			
		|||
AUDIO_ENABLE = yes
 | 
			
		||||
RGBLIGHT_ENABLE = no
 | 
			
		||||
# SERIAL_LINK_ENABLE = yes
 | 
			
		||||
ENCODER_ENABLE = yes
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										70
									
								
								quantum/encoder.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								quantum/encoder.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2018 Jack Humbert <jack.humb@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "encoder.h"
 | 
			
		||||
 | 
			
		||||
#ifndef ENCODER_RESOLUTION
 | 
			
		||||
  #define ENCODER_RESOLUTION 4
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef NUMBER_OF_ENCODERS
 | 
			
		||||
  #error "Number of encoders not defined by NUMBER_OF_ENCODERS"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(ENCODERS_PAD_A) || !defined(ENCODERS_PAD_B)
 | 
			
		||||
  #error "No encoder pads defined by ENCODERS_PAD_A and ENCODERS_PAD_B"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static pin_t encoders_pad_a[NUMBER_OF_ENCODERS] = ENCODERS_PAD_A;
 | 
			
		||||
static pin_t encoders_pad_b[NUMBER_OF_ENCODERS] = ENCODERS_PAD_B;
 | 
			
		||||
 | 
			
		||||
static int8_t encoder_LUT[] = { 0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0 };
 | 
			
		||||
 | 
			
		||||
static uint8_t encoder_state[NUMBER_OF_ENCODERS] = {0};
 | 
			
		||||
static int8_t encoder_value[NUMBER_OF_ENCODERS] = {0};
 | 
			
		||||
 | 
			
		||||
__attribute__ ((weak))
 | 
			
		||||
void encoder_update_user(int8_t index, bool clockwise) { }
 | 
			
		||||
 | 
			
		||||
__attribute__ ((weak))
 | 
			
		||||
void encoder_update_kb(int8_t index, bool clockwise) {
 | 
			
		||||
  encoder_update_user(index, clockwise);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void encoder_init(void) {
 | 
			
		||||
  for (int i = 0; i < NUMBER_OF_ENCODERS; i++) {
 | 
			
		||||
    setPinInputHigh(encoders_pad_a[i]);
 | 
			
		||||
    setPinInputHigh(encoders_pad_b[i]);
 | 
			
		||||
 | 
			
		||||
    encoder_state[i] = (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void encoder_read(void) {
 | 
			
		||||
  for (int i = 0; i < NUMBER_OF_ENCODERS; i++) {
 | 
			
		||||
    encoder_state[i] <<= 2;
 | 
			
		||||
    encoder_state[i] |= (readPin(encoders_pad_a[i]) << 0) | (readPin(encoders_pad_b[i]) << 1);
 | 
			
		||||
    encoder_value[i] += encoder_LUT[encoder_state[i] & 0xF];
 | 
			
		||||
    if (encoder_value[i] >= ENCODER_RESOLUTION) {
 | 
			
		||||
        encoder_update_kb(i, COUNTRECLOCKWISE);
 | 
			
		||||
    }
 | 
			
		||||
    if (encoder_value[i] <= -ENCODER_RESOLUTION) { // direction is arbitrary here, but this clockwise
 | 
			
		||||
        encoder_update_kb(i, CLOCKWISE);
 | 
			
		||||
    }
 | 
			
		||||
    encoder_value[i] %= ENCODER_RESOLUTION;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								quantum/encoder.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								quantum/encoder.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2018 Jack Humbert <jack.humb@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "quantum.h"
 | 
			
		||||
 | 
			
		||||
#define COUNTRECLOCKWISE 0
 | 
			
		||||
#define CLOCKWISE 1
 | 
			
		||||
 | 
			
		||||
void encoder_init(void);
 | 
			
		||||
void encoder_read(void);
 | 
			
		||||
 | 
			
		||||
void encoder_update_kb(int8_t index, bool clockwise);
 | 
			
		||||
void encoder_update_user(int8_t index, bool clockwise);
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +42,11 @@ extern backlight_config_t backlight_config;
 | 
			
		|||
#include "process_midi.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef ENCODER_ENABLE
 | 
			
		||||
#include "encoder.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef AUDIO_ENABLE
 | 
			
		||||
  #ifndef GOODBYE_SONG
 | 
			
		||||
    #define GOODBYE_SONG SONG(GOODBYE_SOUND)
 | 
			
		||||
| 
						 | 
				
			
			@ -957,6 +962,9 @@ void matrix_init_quantum() {
 | 
			
		|||
  #ifdef RGB_MATRIX_ENABLE
 | 
			
		||||
    rgb_matrix_init();
 | 
			
		||||
  #endif
 | 
			
		||||
  #ifdef ENCODER_ENABLE
 | 
			
		||||
    encoder_init();
 | 
			
		||||
  #endif
 | 
			
		||||
  matrix_init_kb();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -991,6 +999,10 @@ void matrix_scan_quantum() {
 | 
			
		|||
    rgb_matrix_task_counter = ((rgb_matrix_task_counter + 1) % (RGB_MATRIX_SKIP_FRAMES + 1));
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #ifdef ENCODER_ENABLE
 | 
			
		||||
    encoder_read();
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  matrix_scan_kb();
 | 
			
		||||
}
 | 
			
		||||
#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue