-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18733 from bergzand/pr/driver/matrix_keypad
matrix_keypad: Add matrix-style keypad module
- Loading branch information
Showing
11 changed files
with
566 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
/* | ||
* Copyright (C) 2021 Koen Zandberg | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @defgroup drivers_matrix_keypad Matrix Keypad | ||
* @ingroup drivers_sensors | ||
* @brief Matrix keypad driver for row/column keypads | ||
* | ||
* @{ | ||
* | ||
* @file | ||
* | ||
* @author Koen Zandberg <[email protected]> | ||
* | ||
* This module implements a simple matrix keypad driver where keys are connected | ||
* between GPIO columns and rows. It works best with diodes in series with the | ||
* switches to prevent key ghosting, but it can be used without these diodes. | ||
* @ref CONFIG_MATRIX_KEYPAD_ROWS_USE_OPEN_DRAIN can be enabled when the keypad | ||
* doesn't use diodes in the switches. | ||
* | ||
* The keypad works by configuring the column GPIOs as input with pull-ups. Each | ||
* row is configured as open drain with pull-up. One by one the rows are set to | ||
* pull their output low. For each row the column GPIOs are read and the state | ||
* is checked. When a key is pressed the column GPIO of that switch will read | ||
* low as soon as the row it is on is pulled low. | ||
* | ||
* The debouncing algorithm is a pattern style debounce where the switch must be | ||
* in one position for a number of samples, then a set of "don't care" samples | ||
* and then in the other position for a number of samples. The samples in the | ||
* middle allow for a period where the switch can be either low or high without | ||
* affecting the transition. The exact pattern is determined by | ||
* @ref CONFIG_MATRIX_KEYPAD_DEBOUNCE_PATTERN_BEGIN and | ||
* @ref CONFIG_MATRIX_KEYPAD_DEBOUNCE_PATTERN_END. These are used as mask where | ||
* the switch must be in a determined state. The bits where neither pattern is | ||
* set is used as the "don't care" set of samples. | ||
* | ||
* A full scan of the matrix keypad is done via the @ref matrix_keypad_scan | ||
* function. This function iterates over all rows and columns to update the | ||
* stored history of every pin. | ||
* | ||
* When a state change is detected on a switch, the @ref matrix_keypad_cb_t | ||
* callback is called with the row and column number together with the new state | ||
* of the switch (pressed or not pressed). | ||
*/ | ||
|
||
#ifndef MATRIX_KEYPAD_H | ||
#define MATRIX_KEYPAD_H | ||
|
||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include "periph/gpio.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @brief Maximum number of rows | ||
*/ | ||
#ifndef CONFIG_MATRIX_KEYPAD_NUM_ROWS | ||
#define CONFIG_MATRIX_KEYPAD_NUM_ROWS 2 | ||
#endif | ||
|
||
/** | ||
* @brief Maximum number of columns | ||
*/ | ||
#ifndef CONFIG_MATRIX_KEYPAD_NUM_COLUMNS | ||
#define CONFIG_MATRIX_KEYPAD_NUM_COLUMNS 2 | ||
#endif | ||
|
||
/** | ||
* @brief Debounce pattern high to low bits | ||
* | ||
* This pattern should consist of bits set on the most significant bits of the | ||
* value. The number of bits set determines the number of scans the key must be | ||
* in the current state before a change is processed. | ||
*/ | ||
#ifndef CONFIG_MATRIX_KEYPAD_DEBOUNCE_PATTERN_BEGIN | ||
#define CONFIG_MATRIX_KEYPAD_DEBOUNCE_PATTERN_BEGIN 0xC0 | ||
#endif | ||
|
||
/** | ||
* @brief Debounce pattern low to high bits | ||
* | ||
* This pattern should consist of bits set on the least significant bits of the | ||
* value. The number of bits set determines the number of scans the key must be | ||
* in the next state before a change is processed. | ||
*/ | ||
#ifndef CONFIG_MATRIX_KEYPAD_DEBOUNCE_PATTERN_END | ||
#define CONFIG_MATRIX_KEYPAD_DEBOUNCE_PATTERN_END 0x7 | ||
#endif | ||
|
||
/** | ||
* @brief Use open drain GPIO mode | ||
*/ | ||
#ifndef CONFIG_MATRIX_KEYPAD_ROWS_USE_OPEN_DRAIN | ||
#define CONFIG_MATRIX_KEYPAD_ROWS_USE_OPEN_DRAIN 0 | ||
#endif | ||
|
||
/** | ||
* @brief GPIO mode used for the row GPIOs | ||
*/ | ||
#if CONFIG_MATRIX_KEYPAD_ROWS_USE_OPEN_DRAIN | ||
#define MATRIX_KEYPAD_ROWS_GPIO_MODE GPIO_OD_PU | ||
#else | ||
#define MATRIX_KEYPAD_ROWS_GPIO_MODE GPIO_OUT | ||
#endif | ||
|
||
/** | ||
* @brief Debounce pattern mask | ||
*/ | ||
#define MATRIX_KEYPAD_DEBOUNCE_MASK \ | ||
(CONFIG_MATRIX_KEYPAD_DEBOUNCE_PATTERN_BEGIN | CONFIG_MATRIX_KEYPAD_DEBOUNCE_PATTERN_END) | ||
|
||
/** | ||
* @brief Type definition for a full row (all columns) state, variable width | ||
* depending on the number of columns. | ||
*/ | ||
#if CONFIG_MATRIX_KEYPAD_NUM_COLUMNS <= 8 | ||
typedef uint8_t matrix_keypad_state_row_t; | ||
#elif CONFIG_MATRIX_KEYPAD_NUM_COLUMNS <= 16 | ||
typedef uint16_t matrix_keypad_state_row_t; | ||
#elif CONFIG_MATRIX_KEYPAD_NUM_COLUMNS <= 32 | ||
typedef uint32_t matrix_keypad_state_row_t; | ||
#elif CONFIG_MATRIX_KEYPAD_NUM_COLUMNS <= 64 | ||
typedef uint64_t matrix_keypad_state_row_t; | ||
#else | ||
#error Too many columns on matrix keypad. | ||
#endif | ||
|
||
/** | ||
* @brief Device initialization parameters | ||
*/ | ||
typedef struct { | ||
/** | ||
* @brief GPIO pin array for the rows. GPIO_UNDEF is allowed and scanning | ||
* is skipped for these. | ||
*/ | ||
gpio_t rows[CONFIG_MATRIX_KEYPAD_NUM_ROWS]; | ||
/** | ||
* @brief GPIO pin array for the columns. GPIO_UNDEF is allowed and scanning | ||
* is skipped for these. | ||
*/ | ||
gpio_t columns[CONFIG_MATRIX_KEYPAD_NUM_COLUMNS]; | ||
/** | ||
* @brief Delay in microseconds between configuring the row gpio and reading | ||
* out the column. Can be zero to skip the delay. | ||
*/ | ||
uint32_t row2col_delay; | ||
} matrix_keypad_params_t; | ||
|
||
/** | ||
* @brief Callback for key state changes | ||
* | ||
* @param arg callback context | ||
* @param row Row that changed | ||
* @param column Column that changed | ||
* @param state New state of the key, 1 = pressed, 0 = released | ||
*/ | ||
typedef void (*matrix_keypad_cb_t)(void *arg, size_t row, size_t column, bool state); | ||
|
||
/** | ||
* @brief Device descriptor for the driver | ||
*/ | ||
typedef struct { | ||
/** | ||
* @brief Device initialization parameters | ||
*/ | ||
const matrix_keypad_params_t *params; | ||
|
||
/** | ||
* @brief Debounce history | ||
*/ | ||
uint8_t debounce[CONFIG_MATRIX_KEYPAD_NUM_ROWS][CONFIG_MATRIX_KEYPAD_NUM_COLUMNS]; | ||
|
||
/** | ||
* @brief Current button state | ||
*/ | ||
matrix_keypad_state_row_t state[CONFIG_MATRIX_KEYPAD_NUM_ROWS]; | ||
|
||
/** | ||
* @brief callback context | ||
*/ | ||
void *arg; | ||
|
||
/** | ||
* @brief Callback called when a key changes state | ||
*/ | ||
matrix_keypad_cb_t callback; | ||
} matrix_keypad_t; | ||
|
||
/** | ||
* @brief Initialize the given device | ||
* | ||
* @param[inout] dev Device descriptor of the driver | ||
* @param[in] params Initialization parameters | ||
* @param[in] callback Callback to call on state changes | ||
* @param[in] arg Context argument for the callback | ||
* | ||
* @return 0 on success | ||
*/ | ||
int matrix_keypad_init(matrix_keypad_t *dev, | ||
const matrix_keypad_params_t *params, | ||
matrix_keypad_cb_t callback, | ||
void *arg); | ||
|
||
/** | ||
* @brief Scan through the keypad matrix | ||
* | ||
* This updates the state of the device descriptor, calling | ||
* @ref matrix_keypad_cb_t when a key press or release has been detected | ||
* | ||
* @param[inout] dev Device descriptor of the driver | ||
* | ||
* @return Number of keys that changed state | ||
*/ | ||
size_t matrix_keypad_scan(matrix_keypad_t *dev); | ||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* MATRIX_KEYPAD_H */ | ||
/** @} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Copyright (c) 2021 Koen Zandberg | ||
# | ||
# This file is subject to the terms and conditions of the GNU Lesser | ||
# General Public License v2.1. See the file LICENSE in the top level | ||
# directory for more details. | ||
|
||
menuconfig MODULE_MATRIX_KEYPAD | ||
bool "Matrix Keypad" | ||
depends on TEST_KCONFIG | ||
depends on HAS_PERIPH_GPIO | ||
select MODULE_PERIPH_GPIO | ||
|
||
if MODULE_MATRIX_KEYPAD | ||
|
||
config MATRIX_KEYPAD_NUM_ROWS | ||
int "Number of rows on the matrix keypad" | ||
default 2 | ||
|
||
config MATRIX_KEYPAD_NUM_COLUMS | ||
int "Number of columns on the matrix keypad" | ||
default 2 | ||
|
||
config MATRIX_KEYPAD_DEBOUNCE_PATTERN_BEGIN | ||
hex "Bitmask pattern used for initial state of the switch" | ||
default 0xC0 | ||
range 0x00 0xFF | ||
|
||
config MATRIX_KEYPAD_DEBOUNCE_PATTERN_END | ||
hex "Bitmask pattern used for next state of the switch" | ||
default 0x07 | ||
range 0x00 0xFF | ||
|
||
config MATRIX_KEYPAD_ROWS_USE_OPEN_DRAIN | ||
bool "Use open drain output mode for the row GPIOs" | ||
default n | ||
help | ||
This switches the row GPIO mode from plain output mode to output mode | ||
with open drain. This helps to prevent shorts between GPIO pins when | ||
using matrix keypad modules without diodes in the switches. When diodes | ||
are installed with the switches this can safely be set off. | ||
|
||
endif # MODULE_MATRIX_KEYPAD | ||
|
||
config HAVE_MATRIX_KEYPAD | ||
bool | ||
help | ||
Indicates that a matrix-style keypad is present. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include $(RIOTBASE)/Makefile.base |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
FEATURES_REQUIRED += periph_gpio | ||
USEMODULE += ztimer_usec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
USEMODULE_INCLUDES_matrix_keypad := $(LAST_MAKEFILEDIR)/include | ||
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_matrix_keypad) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* Copyright (C) 2021 Koen Zandberg | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup drivers_matrix_keypad | ||
* | ||
* @{ | ||
* @file | ||
* @brief Default configuration | ||
* | ||
* @author Koen Zandberg <[email protected]> | ||
*/ | ||
|
||
#ifndef MATRIX_KEYPAD_PARAMS_H | ||
#define MATRIX_KEYPAD_PARAMS_H | ||
|
||
#include "board.h" | ||
#include "matrix_keypad.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @name Set default configuration parameters | ||
* @{ | ||
*/ | ||
|
||
/** | ||
* @brief Number of configured rows | ||
*/ | ||
#ifndef MATRIX_KEYPAD_PARAM_ROWS | ||
#define MATRIX_KEYPAD_PARAM_ROWS { GPIO_PIN(0, 0), GPIO_PIN(0, 1) } | ||
#endif | ||
|
||
/** | ||
* @brief Number of configured columns | ||
*/ | ||
#ifndef MATRIX_KEYPAD_PARAM_COLUMNS | ||
#define MATRIX_KEYPAD_PARAM_COLUMNS { GPIO_PIN(0, 2), GPIO_PIN(0, 3) } | ||
#endif | ||
|
||
/** | ||
* @brief Delay between switching the row state and reading the columns. | ||
*/ | ||
#ifndef MATRIX_KEYPAD_PARAM_ROW2COL_DELAY | ||
#define MATRIX_KEYPAD_PARAM_ROW2COL_DELAY 1 | ||
#endif | ||
|
||
/** | ||
* @brief Default param configuration | ||
*/ | ||
#ifndef MATRIX_KEYPAD_PARAMS | ||
#define MATRIX_KEYPAD_PARAMS { \ | ||
.rows = MATRIX_KEYPAD_PARAM_ROWS, \ | ||
.columns = MATRIX_KEYPAD_PARAM_COLUMNS, \ | ||
.row2col_delay = MATRIX_KEYPAD_PARAM_ROW2COL_DELAY, \ | ||
} | ||
#endif | ||
/**@}*/ | ||
|
||
/** | ||
* @brief Configuration struct | ||
*/ | ||
static const matrix_keypad_params_t matrix_keypad_params[] = | ||
{ | ||
MATRIX_KEYPAD_PARAMS | ||
}; | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* MATRIX_KEYPAD_PARAMS_H */ | ||
/** @} */ |
Oops, something went wrong.