From e036c19d063c543090d01ea841ac343a48276f6d Mon Sep 17 00:00:00 2001 From: Ryan Date: Mon, 7 Feb 2022 04:02:45 +1100 Subject: [PATCH] Add SN74x138 demultiplexer driver (#16217) --- drivers/gpio/sn74x138.c | 65 +++++++ drivers/gpio/sn74x138.h | 48 +++++ keyboards/evyd13/wasdat/config.h | 10 +- keyboards/evyd13/wasdat/matrix.c | 299 +++++-------------------------- keyboards/evyd13/wasdat/rules.mk | 3 +- 5 files changed, 162 insertions(+), 263 deletions(-) create mode 100644 drivers/gpio/sn74x138.c create mode 100644 drivers/gpio/sn74x138.h diff --git a/drivers/gpio/sn74x138.c b/drivers/gpio/sn74x138.c new file mode 100644 index 0000000000..222e5db56c --- /dev/null +++ b/drivers/gpio/sn74x138.c @@ -0,0 +1,65 @@ +/* Copyright 2022 + * + * 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 . + */ + +#include "sn74x138.h" +#include "gpio.h" + +#define ADDRESS_PIN_COUNT 3 + +#ifndef SN74X138_ADDRESS_PINS +# error sn74x138: no address pins defined! +#endif + +static const pin_t address_pins[ADDRESS_PIN_COUNT] = SN74X138_ADDRESS_PINS; + +void sn74x138_init(void) { + for (int i = 0; i < ADDRESS_PIN_COUNT; i++) { + setPinOutput(address_pins[i]); + writePinLow(address_pins[i]); + } + +#if defined(SN74X138_E1_PIN) + setPinOutput(SN74X138_E1_PIN); + writePinHigh(SN74X138_E1_PIN); +#endif + +#if defined(SN74X138_E2_PIN) + setPinOutput(SN74X138_E2_PIN); + writePinHigh(SN74X138_E2_PIN); +#endif +#if defined(SN74X138_E3_PIN) + setPinOutput(SN74X138_E3_PIN); + writePinLow(SN74X138_E3_PIN); +#endif +} + +void sn74x138_set_enabled(bool enabled) { +#if defined(SN74X138_E1_PIN) + writePin(SN74X138_E1_PIN, !enabled); +#endif +#if defined(SN74X138_E2_PIN) + writePin(SN74X138_E2_PIN, !enabled); +#endif +#if defined(SN74X138_E3_PIN) + writePin(SN74X138_E3_PIN, enabled); +#endif +} + +void sn74x138_set_addr(uint8_t address) { + for (int i = 0; i < ADDRESS_PIN_COUNT; i++) { + writePin(address_pins[i], address & (1 << i)); + } +} diff --git a/drivers/gpio/sn74x138.h b/drivers/gpio/sn74x138.h new file mode 100644 index 0000000000..d4d0b6574d --- /dev/null +++ b/drivers/gpio/sn74x138.h @@ -0,0 +1,48 @@ +/* Copyright 2022 + * + * 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 . + */ + +#pragma once + +#include +#include + +/** + * Driver for 74x138 3-to-8 decoder/demultiplexer with inverting outputs + * https://assets.nexperia.com/documents/data-sheet/74HC_HCT138.pdf + */ + +/** + * Initialize the address and output enable pins. + */ +void sn74x138_init(void); + +/** + * Set the enabled state. + * + * When enabled is true, pulls the E1 and E2 pins low, and the E3 pin high. + * + * \param enabled The enable state to set. + */ +void sn74x138_set_enabled(bool enabled); + +/** + * Set the output pin address. + * + * The selected output pin will be pulled low, while the remaining output pins will be high. + * + * \param address The address to set, from 0 to 7. + */ +void sn74x138_set_addr(uint8_t address); diff --git a/keyboards/evyd13/wasdat/config.h b/keyboards/evyd13/wasdat/config.h index 36bbd30821..38f9fe4bda 100644 --- a/keyboards/evyd13/wasdat/config.h +++ b/keyboards/evyd13/wasdat/config.h @@ -41,22 +41,16 @@ along with this program. If not, see . * */ #define MATRIX_ROW_PINS { D6, D4, F6, F7, F4, F5, F0, F1 } -#define MATRIX_COL_PINS { } +#define MATRIX_COL_PINS { C7, B6, C6, B4, B5, D7, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, D3, B7, B3 } // Columns 6-12 controlled by demux #define UNUSED_PINS -/* COL2ROW, ROW2COL*/ -#define DIODE_DIRECTION ROW2COL +#define SN74X138_ADDRESS_PINS { D2, D1, D0 } // For QMK DFU #define QMK_ESC_OUTPUT D6 #define QMK_ESC_INPUT D7 #define QMK_LED B0 -/* - * Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk, and define SOFT_SERIAL_PIN. - */ -//#define SOFT_SERIAL_PIN D0 // or D1, D2, D3, E6 - #define LED_NUM_LOCK_PIN B2 #define LED_CAPS_LOCK_PIN B0 #define LED_SCROLL_LOCK_PIN B1 diff --git a/keyboards/evyd13/wasdat/matrix.c b/keyboards/evyd13/wasdat/matrix.c index 6dd79b5330..c97dd84694 100644 --- a/keyboards/evyd13/wasdat/matrix.c +++ b/keyboards/evyd13/wasdat/matrix.c @@ -14,268 +14,66 @@ 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 . */ + #include #include -#include "wait.h" -#include "util.h" #include "matrix.h" -#include "debounce.h" #include "quantum.h" +#include "sn74x138.h" -#ifdef DIRECT_PINS -static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS; -#elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW) static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; -//static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; -#endif +static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; -// matrix code - -#ifdef DIRECT_PINS - -static void init_pins(void) { - for (int row = 0; row < MATRIX_ROWS; row++) { - for (int col = 0; col < MATRIX_COLS; col++) { - pin_t pin = direct_pins[row][col]; - if (pin != NO_PIN) { - setPinInputHigh(pin); - } - } - } -} - -static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { - matrix_row_t last_row_value = current_matrix[current_row]; - current_matrix[current_row] = 0; - - for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { - pin_t pin = direct_pins[current_row][col_index]; - if (pin != NO_PIN) { - current_matrix[current_row] |= readPin(pin) ? 0 : (MATRIX_ROW_SHIFTER << col_index); - } - } - - return (last_row_value != current_matrix[current_row]); -} - -#elif (DIODE_DIRECTION == COL2ROW) - -static void select_row(uint8_t row) { - setPinOutput(row_pins[row]); - writePinLow(row_pins[row]); -} - -static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); } - -static void unselect_rows(void) { - for (uint8_t x = 0; x < MATRIX_ROWS; x++) { - setPinInputHigh(row_pins[x]); - } -} - -static void init_pins(void) { - unselect_rows(); - for (uint8_t x = 0; x < MATRIX_COLS; x++) { - setPinInputHigh(col_pins[x]); - } -} - -static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { - // Store last value of row prior to reading - matrix_row_t last_row_value = current_matrix[current_row]; - - // Clear data in matrix row - current_matrix[current_row] = 0; - - // Select row and wait for row selecton to stabilize - select_row(current_row); - wait_us(30); - - // For each col... - for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { - - // Select the col pin to read (active low) - uint8_t pin_state = readPin(col_pins[col_index]); - - // Populate the matrix row with the state of the col pin - current_matrix[current_row] |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index); - } - - // Unselect row - unselect_row(current_row); - - return (last_row_value != current_matrix[current_row]); -} - -#elif (DIODE_DIRECTION == ROW2COL) - -/* Cols 0 - 15 - * col 0: C7 - * col 1: B6 +/* col 0: C7 + * col 1: B6 * col 2: C6 - * col 3: B4 - * col 4: B5 - * col 5: D7 - * These columns use a 74HC237D 3 to 8 bit demultiplexer. - * A0 A1 A2 - * col / pin: PD2 PD1 PD0 - * 6: 1 1 1 - * 7: 0 1 1 - * 8: 1 0 1 - * 9: 0 0 1 - * 10: 1 1 0 - * 11: 0 1 0 - * 12: 1 0 0 - * col 13: D3 - * col 14: B7 - * col 15: B3 + * col 3: B4 + * col 4: B5 + * col 5: D7 + * + * These columns use a 74HC138 3 to 8 bit demultiplexer. + * A2 A1 A0 + * col / pin: PD0 PD1 PD2 + * 6: 1 1 1 + * 7: 1 1 0 + * 8: 1 0 1 + * 9: 1 0 0 + * 10: 0 1 1 + * 11: 0 1 0 + * 12: 0 0 1 + * + * col 13: D3 + * col 14: B7 + * col 15: B3 */ static void select_col(uint8_t col) { - switch (col) { - case 0: - writePinLow(C7); - break; - case 1: - writePinLow(B6); - break; - case 2: - writePinLow(C6); - break; - case 3: - writePinLow(B4); - break; - case 4: - writePinLow(B5); - break; - case 5: - writePinLow(D7); - break; - case 6: - writePinHigh(D0); - writePinHigh(D1); - writePinHigh(D2); - break; - case 7: - writePinHigh(D0); - writePinHigh(D1); - break; - case 8: - writePinHigh(D0); - writePinHigh(D2); - break; - case 9: - writePinHigh(D0); - break; - case 10: - writePinHigh(D1); - writePinHigh(D2); - break; - case 11: - writePinHigh(D1); - break; - case 12: - writePinHigh(D2); - break; - case 13: - writePinLow(D3); - break; - case 14: - writePinLow(B7); - break; - case 15: - writePinLow(B3); - break; + if (col_pins[col] != NO_PIN) { + writePinLow(col_pins[col]); + } else { + sn74x138_set_addr(13 - col); } } static void unselect_col(uint8_t col) { - switch (col) { - case 0: - writePinHigh(C7); - break; - case 1: - writePinHigh(B6); - break; - case 2: - writePinHigh(C6); - break; - case 3: - writePinHigh(B4); - break; - case 4: - writePinHigh(B5); - break; - case 5: - writePinHigh(D7); - break; - case 6: - writePinLow(D0); - writePinLow(D1); - writePinLow(D2); - break; - case 7: - writePinLow(D0); - writePinLow(D1); - break; - case 8: - writePinLow(D0); - writePinLow(D2); - break; - case 9: - writePinLow(D0); - break; - case 10: - writePinLow(D1); - writePinLow(D2); - break; - case 11: - writePinLow(D1); - break; - case 12: - writePinLow(D2); - break; - case 13: - writePinHigh(D3); - break; - case 14: - writePinHigh(B7); - break; - case 15: - writePinHigh(B3); - break; + if (col_pins[col] != NO_PIN) { + setPinOutput(col_pins[col]); + writePinHigh(col_pins[col]); + } else { + sn74x138_set_addr(0); } } static void unselect_cols(void) { - //Native - setPinOutput(D3); - setPinOutput(D7); - writePinHigh(D3); - writePinHigh(D7); + // Native + for (uint8_t x = 0; x < MATRIX_COLS; x++) { + if (col_pins[x] != NO_PIN) { + setPinOutput(col_pins[x]); + writePinHigh(col_pins[x]); + } + } - setPinOutput(C6); - setPinOutput(C7); - writePinHigh(C6); - writePinHigh(C7); - - setPinOutput(B3); - setPinOutput(B4); - setPinOutput(B5); - setPinOutput(B6); - setPinOutput(B7); - writePinHigh(B3); - writePinHigh(B4); - writePinHigh(B5); - writePinHigh(B6); - writePinHigh(B7); - - //Demultiplexer - setPinOutput(D0); - setPinOutput(D1); - setPinOutput(D2); - writePinLow(D0); - writePinLow(D1); - writePinLow(D2); + // Demultiplexer + sn74x138_set_addr(0); } static void init_pins(void) { @@ -288,9 +86,9 @@ static void init_pins(void) { static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { bool matrix_changed = false; - // Select col and wait for col selecton to stabilize + // Select col and wait for col selection to stabilize select_col(current_col); - wait_us(30); + matrix_io_delay(); // For each row... for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) { @@ -318,27 +116,20 @@ static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) return matrix_changed; } -#endif - void matrix_init_custom(void) { // initialize key pins init_pins(); + // initialize demultiplexer + sn74x138_init(); } bool matrix_scan_custom(matrix_row_t current_matrix[]) { bool changed = false; -#if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW) - // Set row, read cols - for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { - changed |= read_cols_on_row(current_matrix, current_row); - } -#elif (DIODE_DIRECTION == ROW2COL) // Set col, read rows for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { changed |= read_rows_on_col(current_matrix, current_col); } -#endif return changed; } diff --git a/keyboards/evyd13/wasdat/rules.mk b/keyboards/evyd13/wasdat/rules.mk index d9f65747fb..bb4261a4fe 100644 --- a/keyboards/evyd13/wasdat/rules.mk +++ b/keyboards/evyd13/wasdat/rules.mk @@ -18,6 +18,7 @@ RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow AUDIO_ENABLE = no # Audio output CUSTOM_MATRIX = lite -SRC += matrix.c +VPATH += drivers/gpio +SRC += matrix.c sn74x138.c LAYOUTS = fullsize_ansi fullsize_iso tkl_ansi tkl_iso