mirror of
https://github.com/apache/nuttx.git
synced 2026-05-21 13:13:08 +08:00
input: add keyboard matrix driver
Add a generic kmatrix lower-half with polling/debounce, STM32 board adapters, Kconfig options, a public API header, and a test example/documentation. Signed-off-by: Felipe Moura <moura.fmo@gmail.com> decouple kbd / keypad. Fix some comments add documentation fix rule issues Update CMakeLists.txt update documentation. improve documentation
This commit is contained in:
committed by
Alan C. Assis
parent
6c37217c36
commit
ef71625ede
@@ -0,0 +1 @@
|
||||
<binary image placeholder>
|
||||
@@ -5,6 +5,7 @@ Input Devices
|
||||
.. toctree::
|
||||
:caption: Supported Drivers
|
||||
|
||||
keypad-keyboard.rst
|
||||
keypad.rst
|
||||
sbutton.rst
|
||||
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
=======================
|
||||
Keyboard/Keypad Drivers
|
||||
=======================
|
||||
|
||||
|
||||
**Keypads vs. Keyboards** Keyboards and keypads are really the same
|
||||
devices for NuttX. A keypad is thought of as simply a keyboard with
|
||||
fewer keys.
|
||||
|
||||
**Special Commands**. In NuttX, a keyboard/keypad driver is simply
|
||||
a character driver that may have an (optional) encoding/decoding
|
||||
layer on the data returned by the character driver. A keyboard may
|
||||
return simple text data (alphabetic, numeric, and punctuation) or
|
||||
control characters (enter, control-C, etc.) when a key is pressed.
|
||||
We can think about this the "normal" keyboard data stream.
|
||||
However, in addition, most keyboards support actions that cannot
|
||||
be represented as text or control data. Such actions include
|
||||
things like cursor controls (home, up arrow, page down, etc.),
|
||||
editing functions (insert, delete, etc.), volume controls, (mute,
|
||||
volume up, etc.) and other special functions. In this case, some
|
||||
special encoding may be required to multiplex the normal text data
|
||||
and special command key press data streams.
|
||||
|
||||
**Key Press and Release Events** Sometimes the time that a key is
|
||||
released is needed by applications as well. Thus, in addition to
|
||||
normal and special key press events, it may also be necessary to
|
||||
encode normal and special key release events.
|
||||
|
||||
**Encoding/Decoding** Layer. An optional encoding/decoding layer
|
||||
can be used with the basic character driver to encode the keyboard
|
||||
events into the text data stream. The function interfaces that
|
||||
comprise that encoding/decoding layer are defined in the header
|
||||
file ``include/nuttx/input/kbd_code.h``. These functions provide
|
||||
a matched set of (a) driver encoding interfaces, and (b)
|
||||
application decoding interfaces.
|
||||
|
||||
#. **Driver Encoding Interfaces**. These are interfaces used by
|
||||
the keyboard/keypad driver to encode keyboard events and data.
|
||||
|
||||
- ``kbd_press()``
|
||||
|
||||
**Function Prototype:**
|
||||
|
||||
**Description:**
|
||||
|
||||
**Input Parameters:**
|
||||
|
||||
- ``ch``: The character to be added to the output stream.
|
||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
||||
the actual low-level put operation.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
- ``kbd_release()``
|
||||
|
||||
**Function Prototype:**
|
||||
|
||||
**Description:**
|
||||
|
||||
**Input Parameters:**
|
||||
|
||||
- ``ch``: The character associated with the key that was
|
||||
released.
|
||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
||||
the actual low-level put operation.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
- ``kbd_specpress()``
|
||||
|
||||
**Function Prototype:**
|
||||
|
||||
**Description:**
|
||||
|
||||
**Input Parameters:**
|
||||
|
||||
- ``keycode``: The command to be added to the output
|
||||
stream. The enumeration ``enum kbd_keycode_e keycode``
|
||||
identifies all commands known to the system.
|
||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
||||
the actual low-level put operation.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
- ``kbd_specrel()``
|
||||
|
||||
**Function Prototype:**
|
||||
|
||||
**Description:**
|
||||
|
||||
**Input Parameters:**
|
||||
|
||||
- ``keycode``: The command to be added to the output
|
||||
stream. The enumeration ``enum kbd_keycode_e keycode``
|
||||
identifies all commands known to the system.
|
||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
||||
the actual low-level put operation.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
#. **Application Decoding Interfaces**. These are user interfaces
|
||||
to decode the values returned by the keyboard/keypad driver.
|
||||
|
||||
- ``kbd_decode()``
|
||||
|
||||
**Function Prototype:**
|
||||
|
||||
**Description:**
|
||||
|
||||
**Input Parameters:**
|
||||
|
||||
- ``stream``: An instance of ``lib_instream_s`` to perform
|
||||
the actual low-level get operation.
|
||||
- ``pch``: The location to save the returned value. This
|
||||
may be either a normal, character code or a special
|
||||
command (i.e., a value from ``enum kbd_getstate_s``.
|
||||
- ``state``: A user provided buffer to support parsing.
|
||||
This structure should be cleared the first time that
|
||||
``kbd_decode()`` is called.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
- ``KBD_PRESS`` (0)**: Indicates the successful receipt
|
||||
of normal, keyboard data. This corresponds to a keypress
|
||||
event. The returned value in ``pch`` is a simple byte of
|
||||
text or control data.
|
||||
- ``KBD_RELEASE`` (1)**: Indicates a key release event.
|
||||
The returned value in ``pch`` is the byte of text or
|
||||
control data corresponding to the released key.
|
||||
- ``KBD_SPECPRESS`` (2)**: Indicates the successful
|
||||
receipt of a special keyboard command. The returned value
|
||||
in ``pch`` is a value from ``enum kbd_getstate_s``.
|
||||
- ``KBD_SPECREL`` (3)**: Indicates a special command key
|
||||
release event. The returned value in ``pch`` is a value
|
||||
from ``enum kbd_getstate_s``.
|
||||
- ``KBD_ERROR`` (``EOF``)**: An error has getting the
|
||||
next character (reported by the ``stream``). Normally
|
||||
indicates the end of file.
|
||||
|
||||
**I/O Streams**. Notice the use of the abstract I/O streams in
|
||||
these interfaces. These stream interfaces are defined in
|
||||
``include/nuttx/streams.h``.
|
||||
|
||||
@@ -1,142 +1,83 @@
|
||||
=======================
|
||||
Keyboard/Keypad Drivers
|
||||
Matrix Keypad (KMATRIX)
|
||||
=======================
|
||||
|
||||
**Keypads vs. Keyboards** Keyboards and keypads are really the
|
||||
same devices for NuttX. A keypad is thought of as simply a
|
||||
keyboard with fewer keys.
|
||||
**What is a Keypad?**
|
||||
A keypad is a small keyboard with a limited set of keys, typically
|
||||
arranged in a matrix. It is commonly used for numeric input, access
|
||||
control, or simple user interfaces.
|
||||
|
||||
**Special Commands**. In NuttX, a keyboard/keypad driver is simply
|
||||
a character driver that may have an (optional) encoding/decoding
|
||||
layer on the data returned by the character driver. A keyboard may
|
||||
return simple text data (alphabetic, numeric, and punctuation) or
|
||||
control characters (enter, control-C, etc.) when a key is pressed.
|
||||
We can think about this the "normal" keyboard data stream.
|
||||
However, in addition, most keyboards support actions that cannot
|
||||
be represented as text or control data. Such actions include
|
||||
things like cursor controls (home, up arrow, page down, etc.),
|
||||
editing functions (insert, delete, etc.), volume controls, (mute,
|
||||
volume up, etc.) and other special functions. In this case, some
|
||||
special encoding may be required to multiplex the normal text data
|
||||
and special command key press data streams.
|
||||
For example, a typical 12-key numeric keypad looks like this:
|
||||
|
||||
**Key Press and Release Events** Sometimes the time that a key is
|
||||
released is needed by applications as well. Thus, in addition to
|
||||
normal and special key press events, it may also be necessary to
|
||||
encode normal and special key release events.
|
||||
.. image:: images/keypad-example.png
|
||||
:alt: Example of a 12-key matrix keypad
|
||||
:align: center
|
||||
:width: 200px
|
||||
|
||||
**Encoding/Decoding** Layer. An optional encoding/decoding layer
|
||||
can be used with the basic character driver to encode the keyboard
|
||||
events into the text data stream. The function interfaces that
|
||||
comprise that encoding/decoding layer are defined in the header
|
||||
file ``include/nuttx/input/kbd_code.h``. These functions provide
|
||||
an matched set of (a) driver encoding interfaces, and (b)
|
||||
application decoding interfaces.
|
||||
**Purpose**. The KMATRIX driver provides a generic keypad
|
||||
implementation for boards that expose a switch matrix through GPIOs.
|
||||
It periodically scans rows and columns, detects state changes with a
|
||||
simple debounce, and emits keyboard events through the common keyboard
|
||||
upper-half. This makes the device available as a character driver
|
||||
(e.g., ``/dev/keypad0``) using the standard keyboard
|
||||
interfaces.
|
||||
|
||||
#. **Driver Encoding Interfaces**. These are interfaces used by
|
||||
the keyboard/keypad driver to encode keyboard events and data.
|
||||
**Why Polling**. This first version uses polling to be broadly usable
|
||||
on any board with available GPIOs, without requiring per-board IRQ
|
||||
wiring, pin interrupt capabilities, or expander-specific interrupt
|
||||
support. Polling also simplifies early bring-up and makes the driver
|
||||
predictable while the keymap and GPIO configuration are validated.
|
||||
Future iterations are expected to add interrupt-driven scanning and
|
||||
I2C expander variants; the GPIO polling path remains a good baseline
|
||||
and fallback.
|
||||
|
||||
- ``kbd_press()``
|
||||
**Driver Overview**. The KMATRIX lower-half scans the matrix and calls
|
||||
``keyboard_event()`` when it detects a press or release. The keyboard
|
||||
upper-half registers the character device at the requested ``devpath``
|
||||
and stores events in a circular buffer. Applications read
|
||||
``struct keyboard_event_s`` from the device or use the optional
|
||||
kbd-codec layer.
|
||||
|
||||
**Function Prototype:**
|
||||
**Board Support**. To support KMATRIX, a board must provide:
|
||||
|
||||
**Description:**
|
||||
#. **GPIO Definitions**
|
||||
|
||||
**Input Parameters:**
|
||||
- Define the row and column GPIOs (arrays of pins).
|
||||
- Provide a keymap array indexed by ``row * ncols + col``.
|
||||
|
||||
- ``ch``: The character to be added to the output stream.
|
||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
||||
the actual low-level put operation.
|
||||
#. **Configuration Callbacks**
|
||||
|
||||
**Returned Value:**
|
||||
- ``config_row(pin)``: Configure a row GPIO as output.
|
||||
- ``config_col(pin)``: Configure a column GPIO as input with pull-up
|
||||
or pull-down consistent with the wiring.
|
||||
- ``row_set(pin, active)``: Drive a row active/inactive. For the
|
||||
STM32F4Discovery example, rows are driven low to activate.
|
||||
- ``col_get(pin)``: Read a column and return ``true`` when pressed.
|
||||
|
||||
- ``kbd_release()``
|
||||
#. **Registration Hook**
|
||||
|
||||
**Function Prototype:**
|
||||
- Implement ``board_kmatrix_initialize(const char *devpath)`` to
|
||||
call ``kmatrix_register(&config, devpath)``.
|
||||
- Invoke the board hook during bring-up (for example,
|
||||
``board_kmatrix_initialize("/dev/keypad0")``).
|
||||
|
||||
**Description:**
|
||||
**Reference Implementation (STM32F4Discovery)**. The current reference
|
||||
is in ``boards/arm/stm32/common/src/stm32_kmatrix_gpio.c``:
|
||||
|
||||
**Input Parameters:**
|
||||
- Rows: ``BOARD_KMATRIX_ROW0..3`` (outputs)
|
||||
- Columns: ``BOARD_KMATRIX_COL0..2`` (inputs with pull-up)
|
||||
- Keymap: 4x3 phone keypad layout
|
||||
- Callbacks: ``km_stm32_config_row``, ``km_stm32_config_col``,
|
||||
``km_stm32_row_set``, ``km_stm32_col_get``
|
||||
- Registration: ``board_kmatrix_initialize()`` calls
|
||||
``kmatrix_register()``
|
||||
|
||||
- ``ch``: The character associated with the key that was
|
||||
released.
|
||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
||||
the actual low-level put operation.
|
||||
**Data Path Summary**.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
- ``kbd_specpress()``
|
||||
|
||||
**Function Prototype:**
|
||||
|
||||
**Description:**
|
||||
|
||||
**Input Parameters:**
|
||||
|
||||
- ``keycode``: The command to be added to the output
|
||||
stream. The enumeration ``enum kbd_keycode_e keycode``
|
||||
identifies all commands known to the system.
|
||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
||||
the actual low-level put operation.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
- ``kbd_specrel()``
|
||||
|
||||
**Function Prototype:**
|
||||
|
||||
**Description:**
|
||||
|
||||
**Input Parameters:**
|
||||
|
||||
- ``keycode``: The command to be added to the output
|
||||
stream. The enumeration ``enum kbd_keycode_e keycode``
|
||||
identifies all commands known to the system.
|
||||
- ``stream``: An instance of ``lib_outstream_s`` to perform
|
||||
the actual low-level put operation.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
#. **Application Decoding Interfaces**. These are user interfaces
|
||||
to decode the values returned by the keyboard/keypad driver.
|
||||
|
||||
- ``kbd_decode()``
|
||||
|
||||
**Function Prototype:**
|
||||
|
||||
**Description:**
|
||||
|
||||
**Input Parameters:**
|
||||
|
||||
- ``stream``: An instance of ``lib_instream_s`` to perform
|
||||
the actual low-level get operation.
|
||||
- ``pch``: The location to save the returned value. This
|
||||
may be either a normal, character code or a special
|
||||
command (i.e., a value from ``enum kbd_getstate_s``.
|
||||
- ``state``: A user provided buffer to support parsing.
|
||||
This structure should be cleared the first time that
|
||||
``kbd_decode()`` is called.
|
||||
|
||||
**Returned Value:**
|
||||
|
||||
- ``KBD_PRESS`` (0)**: Indicates the successful receipt
|
||||
of normal, keyboard data. This corresponds to a keypress
|
||||
event. The returned value in ``pch`` is a simple byte of
|
||||
text or control data.
|
||||
- ``KBD_RELEASE`` (1)**: Indicates a key release event.
|
||||
The returned value in ``pch`` is the byte of text or
|
||||
control data corresponding to the released key.
|
||||
- ``KBD_SPECPRESS`` (2)**: Indicates the successful
|
||||
receipt of a special keyboard command. The returned value
|
||||
in ``pch`` is a value from ``enum kbd_getstate_s``.
|
||||
- ``KBD_SPECREL`` (3)**: Indicates a special command key
|
||||
release event. The returned value in ``pch`` is a value
|
||||
from ``enum kbd_getstate_s``.
|
||||
- ``KBD_ERROR`` (``EOF``)**: An error has getting the
|
||||
next character (reported by the ``stream``). Normally
|
||||
indicates the end of file.
|
||||
|
||||
**I/O Streams**. Notice the use of the abstract I/O streams in
|
||||
these interfaces. These stream interfaces are defined in
|
||||
``include/nuttx/streams.h``.
|
||||
- Board calls ``board_kmatrix_initialize("/dev/keypad0")``
|
||||
- ``kmatrix_register()`` configures GPIOs and calls
|
||||
``keyboard_register(&lower, devpath, buflen)``
|
||||
- The upper-half registers the device node at ``devpath``
|
||||
- ``kmatrix_scan_worker()`` calls ``keyboard_event()`` on press/release
|
||||
- Applications read events from the device node
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
* boards/arm/stm32/common/include/stm32_kmatrix_gpio.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_GPIO_H
|
||||
#define __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_GPIO_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: board_kmatrix_initialize
|
||||
*
|
||||
* Description:
|
||||
* This function is called by application-specific setup logic to
|
||||
* configure the keyboard matrix device.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - The device path, typically "/dev/kbd0"
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int board_kmatrix_initialize(const char *devpath);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_GPIO_H */
|
||||
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
* boards/arm/stm32/common/include/stm32_kmatrix_i2c.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_I2C_H
|
||||
#define __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_I2C_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: board_kmatrix_i2c_initialize
|
||||
*
|
||||
* Description:
|
||||
* This function is called by application-specific setup logic to
|
||||
* configure the keyboard matrix device using an I2C GPIO expander.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - The device path, typically "/dev/kbd0"
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int board_kmatrix_i2c_initialize(const char *devpath);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BOARDS_ARM_STM32_COMMON_INCLUDE_STM32_KMATRIX_I2C_H */
|
||||
@@ -158,4 +158,12 @@ if(CONFIG_INPUT_SBUTTON)
|
||||
list(APPEND SRCS stm32_sbutton.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_KMATRIX)
|
||||
list(APPEND SRCS stm32_kmatrix_gpio.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_KMATRIX_I2C)
|
||||
list(APPEND SRCS stm32_kmatrix_i2c.c)
|
||||
endif()
|
||||
|
||||
target_sources(board PRIVATE ${SRCS})
|
||||
|
||||
@@ -166,6 +166,14 @@ ifeq ($(CONFIG_INPUT_SBUTTON),y)
|
||||
CSRCS += stm32_sbutton.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_KMATRIX),y)
|
||||
CSRCS += stm32_kmatrix_gpio.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_KMATRIX_I2C),y)
|
||||
CSRCS += stm32_kmatrix_i2c.c
|
||||
endif
|
||||
|
||||
DEPPATH += --dep-path src
|
||||
VPATH += :src
|
||||
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
|
||||
|
||||
@@ -0,0 +1,355 @@
|
||||
/****************************************************************************
|
||||
* boards/arm/stm32/common/src/stm32_kmatrix_gpio.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nuttx/board.h>
|
||||
#include <arch/board/board.h>
|
||||
#include <nuttx/input/kmatrix.h>
|
||||
|
||||
#include "stm32.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
typedef uint32_t kmatrix_pin_t;
|
||||
|
||||
struct stm32_kmatrix_gpio_config_s
|
||||
{
|
||||
/* Configuration structure as seen by the kmatrix driver */
|
||||
|
||||
struct kmatrix_config_s config;
|
||||
|
||||
/* Additional private definitions only known to this driver */
|
||||
|
||||
void *arg; /* Argument to pass if needed */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void km_stm32_config_row(kmatrix_pin_t pin);
|
||||
static void km_stm32_config_col(kmatrix_pin_t pin);
|
||||
static void km_stm32_row_set(kmatrix_pin_t pin, bool active);
|
||||
static bool km_stm32_col_get(kmatrix_pin_t pin);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Row and column GPIO pin definitions for 4x3 keypad matrix on
|
||||
* STM32F4Discovery
|
||||
* Rows: PB0-PB3 (outputs)
|
||||
* Columns: PC0-PC2 (inputs with pull-up)
|
||||
*/
|
||||
|
||||
static const kmatrix_pin_t g_km_rows[] =
|
||||
{
|
||||
BOARD_KMATRIX_ROW0,
|
||||
BOARD_KMATRIX_ROW1,
|
||||
BOARD_KMATRIX_ROW2,
|
||||
BOARD_KMATRIX_ROW3,
|
||||
};
|
||||
|
||||
static const kmatrix_pin_t g_km_cols[] =
|
||||
{
|
||||
BOARD_KMATRIX_COL0,
|
||||
BOARD_KMATRIX_COL1,
|
||||
BOARD_KMATRIX_COL2,
|
||||
};
|
||||
|
||||
/* Keymap for 4x3 matrix - Standard phone keypad layout
|
||||
* Rows: 0-3, Columns: 0-2
|
||||
*/
|
||||
|
||||
static const uint32_t g_km_keymap[] =
|
||||
{
|
||||
'1', '2', '3', /* Row 0 */
|
||||
'4', '5', '6', /* Row 1 */
|
||||
'7', '8', '9', /* Row 2 */
|
||||
'*', '0', '#', /* Row 3 */
|
||||
};
|
||||
|
||||
/* A reference to a structure of this type must be passed to the kmatrix
|
||||
* driver. This structure provides information about the configuration
|
||||
* of the keypad matrix and provides GPIO callbacks.
|
||||
*
|
||||
* Memory for this structure is provided by the caller. It is not copied
|
||||
* by the driver and is presumed to persist while the driver is active.
|
||||
*/
|
||||
|
||||
static struct stm32_kmatrix_gpio_config_s g_km_config =
|
||||
{
|
||||
.config =
|
||||
{
|
||||
.nrows = 4,
|
||||
.ncols = 3,
|
||||
.rows = g_km_rows,
|
||||
.cols = g_km_cols,
|
||||
.keymap = g_km_keymap,
|
||||
.poll_interval_ms = CONFIG_INPUT_KMATRIX_POLL_MS,
|
||||
.config_row = km_stm32_config_row,
|
||||
.config_col = km_stm32_config_col,
|
||||
.row_set = km_stm32_row_set,
|
||||
.col_get = km_stm32_col_get,
|
||||
},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: km_stm32_config_row
|
||||
*
|
||||
* Description:
|
||||
* Configure a row GPIO pin as an output
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void km_stm32_config_row(kmatrix_pin_t pin)
|
||||
{
|
||||
iinfo("Configuring row pin as output\n");
|
||||
stm32_configgpio(pin);
|
||||
stm32_gpiowrite(pin, true); /* Initialize to inactive (high) */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: km_stm32_config_col
|
||||
*
|
||||
* Description:
|
||||
* Configure a column GPIO pin as an input with pull-up
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void km_stm32_config_col(kmatrix_pin_t pin)
|
||||
{
|
||||
iinfo("Configuring column pin as input\n");
|
||||
stm32_configgpio(pin);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: km_stm32_row_set
|
||||
*
|
||||
* Description:
|
||||
* Activate or deactivate a row (logic: active=true sets to 0/low to
|
||||
* activate the row, active=false sets to 1/high to deactivate)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void km_stm32_row_set(kmatrix_pin_t pin, bool active)
|
||||
{
|
||||
/* With diodes, we drive rows low to activate.
|
||||
* active=true -> write 0 (low)
|
||||
* active=false -> write 1 (high)
|
||||
*/
|
||||
|
||||
stm32_gpiowrite(pin, active ? 0 : 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: km_stm32_col_get
|
||||
*
|
||||
* Description:
|
||||
* Read the state of a column GPIO pin
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool km_stm32_col_get(kmatrix_pin_t pin)
|
||||
{
|
||||
/* With pull-up resistors:
|
||||
* Key pressed -> column goes low (0) when row is driven low
|
||||
* Key released -> column stays high (1)
|
||||
* Return true when pressed (low), false when released (high)
|
||||
*/
|
||||
|
||||
return !stm32_gpioread(pin);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: board_kmatrix_initialize
|
||||
*
|
||||
* Description:
|
||||
* This function is called by application-specific setup logic to
|
||||
* configure the keyboard matrix device.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - The device path, typically "/dev/keypad0"
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int board_kmatrix_initialize(const char *devpath)
|
||||
{
|
||||
iinfo("Initializing keyboard matrix at %s\n", devpath);
|
||||
|
||||
/* Register the keyboard matrix with the generic driver */
|
||||
|
||||
return kmatrix_register(&g_km_config.config, devpath);
|
||||
}
|
||||
|
||||
int board_kmatrix_diag(int loops, int delay_ms)
|
||||
{
|
||||
int iter = 0;
|
||||
uint8_t last_bits[4] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
const useconds_t pulse_us = 200000;
|
||||
|
||||
iinfo("KMATRIX diag: pin identify pulses (disconnect keypad)\n");
|
||||
for (unsigned int r = 0; r < g_km_config.config.nrows; r++)
|
||||
{
|
||||
iinfo("Pulse ROW%u\n", r + 1);
|
||||
stm32_configgpio(g_km_rows[r]);
|
||||
stm32_gpiowrite(g_km_rows[r], true);
|
||||
usleep(pulse_us);
|
||||
stm32_gpiowrite(g_km_rows[r], false);
|
||||
usleep(pulse_us);
|
||||
stm32_gpiowrite(g_km_rows[r], true);
|
||||
usleep(pulse_us);
|
||||
}
|
||||
|
||||
iinfo("KMATRIX diag: column pulses require BOARD_KMATRIX_COLx_OUT\n");
|
||||
#ifdef BOARD_KMATRIX_COL0_OUT
|
||||
iinfo("Pulse COL1 (output mode)\n");
|
||||
stm32_configgpio(BOARD_KMATRIX_COL0_OUT);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL0_OUT, true);
|
||||
usleep(pulse_us);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL0_OUT, false);
|
||||
usleep(pulse_us);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL0_OUT, true);
|
||||
usleep(pulse_us);
|
||||
#endif
|
||||
|
||||
#ifdef BOARD_KMATRIX_COL1_OUT
|
||||
iinfo("Pulse COL2 (output mode)\n");
|
||||
stm32_configgpio(BOARD_KMATRIX_COL1_OUT);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL1_OUT, true);
|
||||
usleep(pulse_us);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL1_OUT, false);
|
||||
usleep(pulse_us);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL1_OUT, true);
|
||||
usleep(pulse_us);
|
||||
#endif
|
||||
|
||||
#ifdef BOARD_KMATRIX_COL2_OUT
|
||||
iinfo("Pulse COL3 (output mode)\n");
|
||||
stm32_configgpio(BOARD_KMATRIX_COL2_OUT);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL2_OUT, true);
|
||||
usleep(pulse_us);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL2_OUT, false);
|
||||
usleep(pulse_us);
|
||||
stm32_gpiowrite(BOARD_KMATRIX_COL2_OUT, true);
|
||||
usleep(pulse_us);
|
||||
#endif
|
||||
|
||||
for (unsigned int r = 0; r < g_km_config.config.nrows; r++)
|
||||
{
|
||||
km_stm32_config_row(g_km_rows[r]);
|
||||
stm32_gpiowrite(g_km_rows[r], true);
|
||||
}
|
||||
|
||||
for (unsigned int c = 0; c < g_km_config.config.ncols; c++)
|
||||
{
|
||||
km_stm32_config_col(g_km_cols[c]);
|
||||
}
|
||||
|
||||
iinfo("KMATRIX diag: loops=%d delay_ms=%d\n", loops, delay_ms);
|
||||
|
||||
while (loops <= 0 || iter < loops)
|
||||
{
|
||||
for (unsigned int r = 0; r < g_km_config.config.nrows; r++)
|
||||
{
|
||||
for (unsigned int rr = 0; rr < g_km_config.config.nrows; rr++)
|
||||
{
|
||||
stm32_gpiowrite(g_km_rows[rr], true);
|
||||
}
|
||||
|
||||
stm32_gpiowrite(g_km_rows[r], false);
|
||||
usleep(1000);
|
||||
|
||||
if (g_km_config.config.ncols == 3)
|
||||
{
|
||||
bool b0 = stm32_gpioread(g_km_cols[0]);
|
||||
bool b1 = stm32_gpioread(g_km_cols[1]);
|
||||
bool b2 = stm32_gpioread(g_km_cols[2]);
|
||||
uint8_t bits = (b0 ? 1 : 0) |
|
||||
(b1 ? 2 : 0) |
|
||||
(b2 ? 4 : 0);
|
||||
|
||||
if (bits != last_bits[r])
|
||||
{
|
||||
iinfo("ROW=%u COLS(raw)=%d%d%d\n",
|
||||
r + 1, b0 ? 1 : 0, b1 ? 1 : 0, b2 ? 1 : 0);
|
||||
last_bits[r] = bits;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int c = 0; c < g_km_config.config.ncols; c++)
|
||||
{
|
||||
bool pressed = !stm32_gpioread(g_km_cols[c]);
|
||||
if (pressed)
|
||||
{
|
||||
iinfo("ROW=%u COL=%u\n", r + 1, c + 1);
|
||||
while (!stm32_gpioread(g_km_cols[c]))
|
||||
{
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delay_ms > 0)
|
||||
{
|
||||
usleep(delay_ms * 1000);
|
||||
}
|
||||
|
||||
iter++;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/****************************************************************************
|
||||
* boards/arm/stm32/common/src/stm32_kmatrix_i2c.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/input/kmatrix.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
#include <nuttx/ioexpander/ioexpander.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "stm32.h"
|
||||
#include "stm32_i2c.h"
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_MCP23X08
|
||||
# include <nuttx/ioexpander/mcp23x08.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_PCA9538
|
||||
# include <nuttx/ioexpander/pca9538.h>
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
typedef uint32_t kmatrix_pin_t;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Row and column pin definitions for 4x3 keypad matrix via I2C expander
|
||||
*
|
||||
* For MCP23X08/PCA9538 I2C expanders, pins are numbered 0-7.
|
||||
*
|
||||
* Example mapping:
|
||||
* Rows (outputs): Pins 0-3
|
||||
* Columns (inputs): Pins 4-6 (with pull-ups)
|
||||
*/
|
||||
|
||||
static const kmatrix_pin_t g_km_rows[] =
|
||||
{
|
||||
0, 1, 2, 3, /* Row 0-3: Output pins on expander */
|
||||
};
|
||||
|
||||
static const kmatrix_pin_t g_km_cols[] =
|
||||
{
|
||||
4, 5, 6, /* Col 0-2: Input pins on expander (with pull-up) */
|
||||
};
|
||||
|
||||
/* Keymap for 4x3 matrix - Standard phone keypad layout
|
||||
* Rows: 0-3, Columns: 0-2
|
||||
*/
|
||||
|
||||
static const uint32_t g_km_keymap[] =
|
||||
{
|
||||
'1', '2', '3', /* Row 0 */
|
||||
'4', '5', '6', /* Row 1 */
|
||||
'7', '8', '9', /* Row 2 */
|
||||
'*', '0', '#', /* Row 3 */
|
||||
};
|
||||
|
||||
/* Get callbacks from I2C driver */
|
||||
|
||||
extern FAR struct kmatrix_callbacks_s *kmatrix_i2c_get_callbacks(void);
|
||||
|
||||
/* Keyboard matrix configuration structure
|
||||
* Callbacks are set in board_kmatrix_i2c_initialize.
|
||||
*/
|
||||
|
||||
static struct kmatrix_config_s g_km_i2c_config =
|
||||
{
|
||||
.nrows = 4,
|
||||
.ncols = 3,
|
||||
.rows = g_km_rows,
|
||||
.cols = g_km_cols,
|
||||
.keymap = g_km_keymap,
|
||||
.poll_interval_ms = CONFIG_INPUT_KMATRIX_POLL_MS,
|
||||
};
|
||||
|
||||
/* IO expander configuration */
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_MCP23X08
|
||||
static struct mcp23x08_config_s g_mcp23x08_config =
|
||||
{
|
||||
.address = CONFIG_STM32_KMATRIX_I2C_ADDR,
|
||||
.frequency = CONFIG_STM32_KMATRIX_I2C_FREQ,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_PCA9538
|
||||
static struct pca9538_config_s g_pca9538_config =
|
||||
{
|
||||
.address = CONFIG_STM32_KMATRIX_I2C_ADDR,
|
||||
.frequency = CONFIG_STM32_KMATRIX_I2C_FREQ,
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* Name: board_kmatrix_i2c_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize keyboard matrix driver using I2C GPIO expander.
|
||||
* This function is called by stm32_bringup.c during initialization.
|
||||
*
|
||||
* Input Parameters:
|
||||
* devpath - Device path (e.g., "/dev/kbd0")
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; negated errno on failure.
|
||||
*/
|
||||
|
||||
int board_kmatrix_i2c_initialize(const char *devpath)
|
||||
{
|
||||
FAR struct i2c_master_s *i2c;
|
||||
FAR struct ioexpander_dev_s *ioe;
|
||||
FAR struct kmatrix_callbacks_s *callbacks;
|
||||
int ret;
|
||||
|
||||
iinfo("Initializing keyboard matrix via I2C expander\n");
|
||||
|
||||
/* Initialize I2C bus */
|
||||
|
||||
i2c = stm32_i2cbus_initialize(CONFIG_STM32_KMATRIX_I2C_BUS);
|
||||
if (i2c == NULL)
|
||||
{
|
||||
ierr("ERROR: Failed to initialize I2C bus %d\n",
|
||||
CONFIG_STM32_KMATRIX_I2C_BUS);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Initialize IO expander */
|
||||
|
||||
#ifdef CONFIG_IOEXPANDER_MCP23X08
|
||||
ioe = mcp23x08_initialize(i2c, &g_mcp23x08_config);
|
||||
if (ioe == NULL)
|
||||
{
|
||||
ierr("ERROR: Failed to initialize MCP23X08\n");
|
||||
stm32_i2cbus_uninitialize(i2c);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
iinfo("MCP23X08 initialized at 0x%02x\n", CONFIG_STM32_KMATRIX_I2C_ADDR);
|
||||
#elif defined(CONFIG_IOEXPANDER_PCA9538)
|
||||
ioe = pca9538_initialize(i2c, &g_pca9538_config);
|
||||
if (ioe == NULL)
|
||||
{
|
||||
ierr("ERROR: Failed to initialize PCA9538\n");
|
||||
stm32_i2cbus_uninitialize(i2c);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
iinfo("PCA9538 initialized at 0x%02x\n", CONFIG_STM32_KMATRIX_I2C_ADDR);
|
||||
#else
|
||||
# error "No IO expander configured"
|
||||
#endif
|
||||
|
||||
/* Get callbacks from I2C driver */
|
||||
|
||||
callbacks = kmatrix_i2c_get_callbacks();
|
||||
g_km_i2c_config.config_row = callbacks->config_row;
|
||||
g_km_i2c_config.config_col = callbacks->config_col;
|
||||
g_km_i2c_config.row_set = callbacks->row_set;
|
||||
g_km_i2c_config.col_get = callbacks->col_get;
|
||||
|
||||
/* Register keyboard matrix driver */
|
||||
|
||||
ret = kmatrix_i2c_register(ioe, &g_km_i2c_config, devpath);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: Failed to register keyboard matrix: %d\n", ret);
|
||||
stm32_i2cbus_uninitialize(i2c);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iinfo("Keyboard matrix I2C driver registered at %s\n", devpath);
|
||||
return OK;
|
||||
}
|
||||
@@ -120,4 +120,23 @@ config PM_SLEEP_WAKEUP_NSEC
|
||||
Number of additional nanoseconds to wait in PM_SLEEP before going to
|
||||
PM_STANDBY mode.
|
||||
|
||||
if INPUT_KMATRIX_I2C
|
||||
|
||||
config STM32_KMATRIX_I2C_BUS
|
||||
int "I2C Bus Number"
|
||||
default 1
|
||||
---help---
|
||||
I2C bus number to use for the keyboard matrix GPIO expander.
|
||||
Common values: 1 or 2 (depends on available I2C interfaces).
|
||||
|
||||
config STM32_KMATRIX_I2C_ADDR
|
||||
hex "I2C Slave Address of GPIO Expander"
|
||||
default 0x20
|
||||
---help---
|
||||
I2C slave address of the GPIO expander (PCF8574 or MCP23017).
|
||||
PCF8574/MCP23017 default addresses (7-bit):
|
||||
0x20-0x27: varies with A0-A2 pins (default is 0x20)
|
||||
|
||||
endif # INPUT_KMATRIX_I2C
|
||||
|
||||
endif
|
||||
|
||||
@@ -472,4 +472,76 @@
|
||||
|
||||
#define BOARD_XEN1210_PWMTIMER 1
|
||||
|
||||
/* Keyboard Matrix Configuration */
|
||||
|
||||
/* Define keyboard matrix row pins (outputs) */
|
||||
|
||||
#define GPIO_KMATRIX_ROW0 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
|
||||
GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN7)
|
||||
#define GPIO_KMATRIX_ROW1 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
|
||||
GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN8)
|
||||
#define GPIO_KMATRIX_ROW2 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
|
||||
GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN9)
|
||||
#define GPIO_KMATRIX_ROW3 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
|
||||
GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN10)
|
||||
|
||||
/* Row pins as inputs with pull-up for early diagnostics */
|
||||
|
||||
#define GPIO_KMATRIX_ROW0_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
|
||||
GPIO_PORTE|GPIO_PIN7)
|
||||
#define GPIO_KMATRIX_ROW1_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
|
||||
GPIO_PORTE|GPIO_PIN8)
|
||||
#define GPIO_KMATRIX_ROW2_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
|
||||
GPIO_PORTE|GPIO_PIN9)
|
||||
#define GPIO_KMATRIX_ROW3_IN (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
|
||||
GPIO_PORTE|GPIO_PIN10)
|
||||
|
||||
/* Define keyboard matrix column pins (inputs) */
|
||||
|
||||
#define GPIO_KMATRIX_COL0 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
|
||||
GPIO_PORTE|GPIO_PIN11)
|
||||
#define GPIO_KMATRIX_COL1 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
|
||||
GPIO_PORTE|GPIO_PIN13)
|
||||
#define GPIO_KMATRIX_COL2 (GPIO_INPUT|GPIO_PULLUP|GPIO_SPEED_50MHz|\
|
||||
GPIO_PORTE|GPIO_PIN14)
|
||||
|
||||
/* Column pins as outputs for diagnostics only */
|
||||
|
||||
#define GPIO_KMATRIX_COL0_OUT (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
|
||||
GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN11)
|
||||
#define GPIO_KMATRIX_COL1_OUT (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
|
||||
GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN13)
|
||||
#define GPIO_KMATRIX_COL2_OUT (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|\
|
||||
GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN14)
|
||||
|
||||
/* Board-level KMATRIX pin definitions */
|
||||
|
||||
#define BOARD_KMATRIX_ROW0 GPIO_KMATRIX_ROW0
|
||||
#define BOARD_KMATRIX_ROW1 GPIO_KMATRIX_ROW1
|
||||
#define BOARD_KMATRIX_ROW2 GPIO_KMATRIX_ROW2
|
||||
#define BOARD_KMATRIX_ROW3 GPIO_KMATRIX_ROW3
|
||||
|
||||
#define BOARD_KMATRIX_ROW0_IN GPIO_KMATRIX_ROW0_IN
|
||||
#define BOARD_KMATRIX_ROW1_IN GPIO_KMATRIX_ROW1_IN
|
||||
#define BOARD_KMATRIX_ROW2_IN GPIO_KMATRIX_ROW2_IN
|
||||
#define BOARD_KMATRIX_ROW3_IN GPIO_KMATRIX_ROW3_IN
|
||||
|
||||
#define BOARD_KMATRIX_COL0 GPIO_KMATRIX_COL0
|
||||
#define BOARD_KMATRIX_COL1 GPIO_KMATRIX_COL1
|
||||
#define BOARD_KMATRIX_COL2 GPIO_KMATRIX_COL2
|
||||
|
||||
#define BOARD_KMATRIX_COL0_OUT GPIO_KMATRIX_COL0_OUT
|
||||
#define BOARD_KMATRIX_COL1_OUT GPIO_KMATRIX_COL1_OUT
|
||||
#define BOARD_KMATRIX_COL2_OUT GPIO_KMATRIX_COL2_OUT
|
||||
|
||||
#ifdef CONFIG_INPUT_KMATRIX
|
||||
int board_kmatrix_diag(int loops, int delay_ms);
|
||||
#endif
|
||||
|
||||
/* Keyboard Matrix I2C Configuration */
|
||||
|
||||
#define CONFIG_STM32_KMATRIX_I2C_BUS 1 /* I2C1 */
|
||||
#define CONFIG_STM32_KMATRIX_I2C_ADDR 0x20 /* MCP23X08/PCA9538 address */
|
||||
#define CONFIG_STM32_KMATRIX_I2C_FREQ 400000 /* 400 kHz */
|
||||
|
||||
#endif /* __BOARDS_ARM_STM32_STM32F4DISCOVERY_INCLUDE_BOARD_H */
|
||||
|
||||
@@ -102,6 +102,14 @@
|
||||
#include "board_sbutton.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INPUT_KMATRIX
|
||||
#include "stm32_kmatrix_gpio.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INPUT_KMATRIX_I2C
|
||||
#include "stm32_kmatrix_i2c.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SENSORS_ZEROCROSS
|
||||
#include "stm32_zerocross.h"
|
||||
#endif
|
||||
@@ -414,6 +422,27 @@ int stm32_bringup(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INPUT_KMATRIX
|
||||
/* Initialize and register the keyboard matrix driver */
|
||||
|
||||
ret = board_kmatrix_initialize(CONFIG_INPUT_KMATRIX_DEVPATH);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: board_kmatrix_initialize() failed: %d\n", ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INPUT_KMATRIX_I2C
|
||||
/* Initialize and register the keyboard matrix driver via I2C expander */
|
||||
|
||||
ret = board_kmatrix_i2c_initialize("/dev/kbd0");
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: board_kmatrix_i2c_initialize() failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_INPUT_NUNCHUCK
|
||||
/* Register the Nunchuck driver */
|
||||
|
||||
|
||||
@@ -106,6 +106,14 @@ if(CONFIG_INPUT)
|
||||
list(APPEND SRCS keyboard_upper.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_KMATRIX)
|
||||
list(APPEND SRCS kmatrix.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_KMATRIX_I2C)
|
||||
list(APPEND SRCS kmatrix_i2c.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INPUT_SBUTTON)
|
||||
list(APPEND SRCS sbutton.c)
|
||||
endif()
|
||||
|
||||
+67
-1
@@ -723,7 +723,7 @@ config INPUT_SPQ10KBD
|
||||
select I2C
|
||||
---help---
|
||||
Enable the Solder Party Q10 BlackBerry Keyboard support. This
|
||||
exposes itself as a standard keyboard at /dev/kbdN.
|
||||
exposes itself as a standard keyboard at /dev/keypadN.
|
||||
This keyboard exists both as a standalone module and integrated
|
||||
into the Solder Party Keyboard FeatherWing. Information on this
|
||||
can be found at https://www.solder.party/docs/keyboard-pmod/
|
||||
@@ -749,4 +749,70 @@ config SPQ10KBD_NPOLLWAITERS
|
||||
|
||||
endif # INPUT_SPQ10KBD
|
||||
|
||||
config INPUT_KMATRIX
|
||||
bool "Keyboard Matrix Driver"
|
||||
default n
|
||||
select INPUT_KEYBOARD
|
||||
---help---
|
||||
Enable support for keyboard matrix input devices with polling-based
|
||||
scanning. This driver supports NxM key matrices with debounce and
|
||||
anti-ghosting using diodes.
|
||||
|
||||
if INPUT_KMATRIX
|
||||
|
||||
config INPUT_KMATRIX_BUFSIZE
|
||||
int "Keyboard matrix buffer size"
|
||||
default 64
|
||||
---help---
|
||||
Size of the keyboard event buffer for each open file descriptor.
|
||||
|
||||
config INPUT_KMATRIX_POLL_MS
|
||||
int "Polling interval (milliseconds)"
|
||||
default 10
|
||||
---help---
|
||||
Time interval in milliseconds between matrix scans. Smaller values
|
||||
provide lower latency but consume more CPU. Default: 10ms.
|
||||
|
||||
config INPUT_KMATRIX_DEBOUNCE
|
||||
int "Debounce threshold (scan cycles)"
|
||||
default 3
|
||||
---help---
|
||||
Number of consecutive scan cycles a key must maintain the same state
|
||||
before generating a press/release event. Higher values provide more
|
||||
robust debounce but increase latency. Default: 3 cycles.
|
||||
|
||||
config INPUT_KMATRIX_DEVPATH
|
||||
string "Device path"
|
||||
default "/dev/keypad0"
|
||||
---help---
|
||||
Path where the keyboard matrix device will be registered. Default: /dev/keypad0
|
||||
|
||||
config INPUT_KMATRIX_I2C
|
||||
bool "Keyboard Matrix via I2C GPIO Expander"
|
||||
depends on INPUT_KMATRIX && I2C
|
||||
default n
|
||||
---help---
|
||||
Enable keyboard matrix driver using I2C GPIO expander (PCF8574 or MCP23017).
|
||||
Requires I2C support to be enabled.
|
||||
|
||||
if INPUT_KMATRIX_I2C
|
||||
|
||||
config INPUT_KMATRIX_I2C_PCF8574
|
||||
bool "Use PCF8574 I2C Expander"
|
||||
default n
|
||||
---help---
|
||||
Use PCF8574 I2C GPIO expander (8-bit, quasi-bidirectional I/O).
|
||||
This is a simple, low-cost 8-bit I/O expander commonly used in hobbyist projects.
|
||||
|
||||
config INPUT_KMATRIX_I2C_MCP23017
|
||||
bool "Use MCP23017 I2C Expander"
|
||||
default n
|
||||
---help---
|
||||
Use MCP23017 I2C GPIO expander (16-bit, configurable I/O directions).
|
||||
This offers more features and flexibility than PCF8574.
|
||||
|
||||
endif # INPUT_KMATRIX_I2C
|
||||
|
||||
endif # INPUT_KMATRIX
|
||||
|
||||
endif # INPUT
|
||||
|
||||
@@ -126,6 +126,14 @@ ifeq ($(CONFIG_INPUT_SPQ10KBD),y)
|
||||
CSRCS += spq10kbd.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_KMATRIX),y)
|
||||
CSRCS += kmatrix.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_KMATRIX_I2C),y)
|
||||
CSRCS += kmatrix_i2c.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INPUT_GOLDFISH_EVENTS),y)
|
||||
CSRCS += goldfish_events.c
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,362 @@
|
||||
/****************************************************************************
|
||||
* drivers/input/kmatrix.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <nuttx/input/kmatrix.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/input/keyboard.h>
|
||||
#include <nuttx/input/kbd_codec.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct kmatrix_dev_s
|
||||
{
|
||||
FAR const struct kmatrix_config_s *config; /* Board configuration data */
|
||||
|
||||
mutex_t lock; /* Exclusive access to device */
|
||||
struct work_s work; /* Work queue for polling */
|
||||
uint16_t poll_interval; /* Polling interval in milliseconds */
|
||||
|
||||
/* Current and previous state of the matrix (bitfield) */
|
||||
|
||||
FAR uint8_t *state; /* Current state bitmap */
|
||||
FAR uint8_t *debounce; /* Debounce counter */
|
||||
|
||||
/* Keyboard lower-half registration */
|
||||
|
||||
struct keyboard_lowerhalf_s lower;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Static Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void kmatrix_scan_worker(FAR void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_get_state
|
||||
*
|
||||
* Description:
|
||||
* Get the current state of a key at position (row, col)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool kmatrix_get_state(FAR struct kmatrix_dev_s *priv,
|
||||
uint8_t row, uint8_t col)
|
||||
{
|
||||
uint16_t idx = row * priv->config->ncols + col;
|
||||
uint16_t byte_idx = idx / 8;
|
||||
uint8_t bit_idx = idx % 8;
|
||||
|
||||
return (priv->state[byte_idx] >> bit_idx) & 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_set_state
|
||||
*
|
||||
* Description:
|
||||
* Set the current state of a key at position (row, col)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void kmatrix_set_state(FAR struct kmatrix_dev_s *priv,
|
||||
uint8_t row, uint8_t col, bool pressed)
|
||||
{
|
||||
uint16_t idx = row * priv->config->ncols + col;
|
||||
uint16_t byte_idx = idx / 8;
|
||||
uint8_t bit_idx = idx % 8;
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
priv->state[byte_idx] |= (1 << bit_idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->state[byte_idx] &= ~(1 << bit_idx);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_inc_debounce
|
||||
*
|
||||
* Description:
|
||||
* Increment debounce counter for a key
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void kmatrix_inc_debounce(FAR struct kmatrix_dev_s *priv,
|
||||
uint8_t row, uint8_t col)
|
||||
{
|
||||
uint16_t idx = row * priv->config->ncols + col;
|
||||
|
||||
if (priv->debounce[idx] < CONFIG_INPUT_KMATRIX_DEBOUNCE)
|
||||
{
|
||||
priv->debounce[idx]++;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_reset_debounce
|
||||
*
|
||||
* Description:
|
||||
* Reset debounce counter for a key
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void kmatrix_reset_debounce(FAR struct kmatrix_dev_s *priv,
|
||||
uint8_t row, uint8_t col)
|
||||
{
|
||||
uint16_t idx = row * priv->config->ncols + col;
|
||||
|
||||
priv->debounce[idx] = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_scan_worker
|
||||
*
|
||||
* Description:
|
||||
* Periodic worker that scans the keyboard matrix and detects key presses
|
||||
* and releases.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void kmatrix_scan_worker(FAR void *arg)
|
||||
{
|
||||
FAR struct kmatrix_dev_s *priv = (FAR struct kmatrix_dev_s *)arg;
|
||||
uint8_t row;
|
||||
uint8_t col;
|
||||
bool pressed;
|
||||
bool old_state;
|
||||
uint32_t keycode;
|
||||
int ret;
|
||||
|
||||
ret = nxmutex_lock(&priv->lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scan each row */
|
||||
|
||||
for (row = 0; row < priv->config->nrows; row++)
|
||||
{
|
||||
/* Activate this row */
|
||||
|
||||
priv->config->row_set(priv->config->rows[row], true);
|
||||
|
||||
/* Read each column */
|
||||
|
||||
for (col = 0; col < priv->config->ncols; col++)
|
||||
{
|
||||
pressed = priv->config->col_get(priv->config->cols[col]);
|
||||
old_state = kmatrix_get_state(priv, row, col);
|
||||
|
||||
/* Check if state changed */
|
||||
|
||||
if (pressed != old_state)
|
||||
{
|
||||
kmatrix_inc_debounce(priv, row, col);
|
||||
|
||||
/* After debounce threshold is reached, update state */
|
||||
|
||||
if (priv->debounce[row * priv->config->ncols + col] >=
|
||||
CONFIG_INPUT_KMATRIX_DEBOUNCE)
|
||||
{
|
||||
kmatrix_set_state(priv, row, col, pressed);
|
||||
kmatrix_reset_debounce(priv, row, col);
|
||||
|
||||
/* Generate keyboard event */
|
||||
|
||||
keycode = priv->config->keymap[
|
||||
row * priv->config->ncols + col];
|
||||
keyboard_event(&priv->lower, (uint16_t)keycode,
|
||||
pressed ? KEYBOARD_PRESS :
|
||||
KEYBOARD_RELEASE);
|
||||
|
||||
iinfo("Key [%d,%d]: %s (code %lu)\n", row, col,
|
||||
pressed ? "PRESS" : "RELEASE",
|
||||
(unsigned long)keycode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kmatrix_reset_debounce(priv, row, col);
|
||||
}
|
||||
}
|
||||
|
||||
/* Deactivate this row */
|
||||
|
||||
priv->config->row_set(priv->config->rows[row], false);
|
||||
}
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
|
||||
/* Reschedule the worker */
|
||||
|
||||
work_queue(LPWORK, &priv->work, kmatrix_scan_worker, priv,
|
||||
MSEC2TICK(priv->poll_interval));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_register
|
||||
*
|
||||
* Description:
|
||||
* Configure and register a keyboard matrix device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int kmatrix_register(FAR const struct kmatrix_config_s *config,
|
||||
FAR const char *devpath)
|
||||
{
|
||||
FAR struct kmatrix_dev_s *priv;
|
||||
int ret;
|
||||
uint16_t state_size;
|
||||
uint16_t debounce_size;
|
||||
uint16_t keys;
|
||||
|
||||
iinfo("Registering keypad matrix: %dx%d at %s\n", config->nrows,
|
||||
config->ncols, devpath);
|
||||
|
||||
/* Validate configuration */
|
||||
|
||||
DEBUGASSERT(config != NULL);
|
||||
DEBUGASSERT(devpath != NULL);
|
||||
DEBUGASSERT(config->rows != NULL);
|
||||
DEBUGASSERT(config->cols != NULL);
|
||||
DEBUGASSERT(config->keymap != NULL);
|
||||
DEBUGASSERT(config->config_row != NULL);
|
||||
DEBUGASSERT(config->config_col != NULL);
|
||||
DEBUGASSERT(config->row_set != NULL);
|
||||
DEBUGASSERT(config->col_get != NULL);
|
||||
|
||||
/* Allocate driver instance */
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct kmatrix_dev_s));
|
||||
if (!priv)
|
||||
{
|
||||
ierr("ERROR: kmm_zalloc(%zu) failed\n", sizeof(struct kmatrix_dev_s));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Calculate bitmap sizes */
|
||||
|
||||
keys = config->nrows * config->ncols;
|
||||
state_size = (keys + 7) / 8;
|
||||
debounce_size = keys;
|
||||
|
||||
/* Allocate state and debounce bitmaps */
|
||||
|
||||
priv->state = kmm_zalloc(state_size);
|
||||
if (!priv->state)
|
||||
{
|
||||
ierr("ERROR: Failed to allocate state bitmap\n");
|
||||
kmm_free(priv);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->debounce = kmm_zalloc(debounce_size);
|
||||
if (!priv->debounce)
|
||||
{
|
||||
ierr("ERROR: Failed to allocate debounce bitmap\n");
|
||||
kmm_free(priv->state);
|
||||
kmm_free(priv);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Initialize device structure */
|
||||
|
||||
priv->config = config;
|
||||
priv->poll_interval = config->poll_interval_ms > 0 ?
|
||||
config->poll_interval_ms :
|
||||
CONFIG_INPUT_KMATRIX_POLL_MS;
|
||||
|
||||
nxmutex_init(&priv->lock);
|
||||
|
||||
/* Configure all GPIO pins */
|
||||
|
||||
for (int i = 0; i < config->nrows; i++)
|
||||
{
|
||||
config->config_row(config->rows[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < config->ncols; i++)
|
||||
{
|
||||
config->config_col(config->cols[i]);
|
||||
}
|
||||
|
||||
/* Register as keyboard device */
|
||||
|
||||
ret = keyboard_register(&priv->lower, devpath,
|
||||
CONFIG_INPUT_KMATRIX_BUFSIZE);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: keyboard_register() failed: %d\n", ret);
|
||||
goto errout_with_priv;
|
||||
}
|
||||
|
||||
/* Start the scanning worker */
|
||||
|
||||
work_queue(LPWORK, &priv->work, kmatrix_scan_worker, priv,
|
||||
MSEC2TICK(priv->poll_interval));
|
||||
|
||||
iinfo("Keypad matrix registered as %s\n", devpath);
|
||||
return OK;
|
||||
|
||||
errout_with_priv:
|
||||
nxmutex_destroy(&priv->lock);
|
||||
kmm_free(priv->debounce);
|
||||
kmm_free(priv->state);
|
||||
kmm_free(priv);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
/****************************************************************************
|
||||
* drivers/input/kmatrix_i2c.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/input/kmatrix.h>
|
||||
#include <nuttx/ioexpander/ioexpander.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Verify IO expander support is enabled */
|
||||
|
||||
#if !defined(CONFIG_IOEXPANDER_PCA9538) && !defined(CONFIG_IOEXPANDER_MCP23X08)
|
||||
# error "Either CONFIG_IOEXPANDER_PCA9538 or " \
|
||||
"CONFIG_IOEXPANDER_MCP23X08 must be enabled"
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
typedef uint32_t kmatrix_pin_t;
|
||||
|
||||
struct kmatrix_i2c_dev_s
|
||||
{
|
||||
FAR struct ioexpander_dev_s *ioe; /* IO expander device */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void km_i2c_config_row(kmatrix_pin_t pin);
|
||||
static void km_i2c_config_col(kmatrix_pin_t pin);
|
||||
static void km_i2c_row_set(kmatrix_pin_t pin, bool active);
|
||||
static bool km_i2c_col_get(kmatrix_pin_t pin);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Global I2C device instance (simplified - one per board) */
|
||||
|
||||
static struct kmatrix_i2c_dev_s g_km_i2c_dev;
|
||||
|
||||
/****************************************************************************
|
||||
* I2C Keyboard Matrix Callbacks
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* Name: km_i2c_config_row
|
||||
*
|
||||
* Description:
|
||||
* Configure row pins as outputs using IO expander API.
|
||||
*/
|
||||
|
||||
static void km_i2c_config_row(kmatrix_pin_t pin)
|
||||
{
|
||||
int ret;
|
||||
|
||||
iinfo("I2C: Configuring pin %lu as output (row)\n", (unsigned long)pin);
|
||||
|
||||
ret = IOEXP_SETDIRECTION(g_km_i2c_dev.ioe, (uint8_t)pin,
|
||||
IOEXPANDER_DIRECTION_OUT);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: Failed to configure row pin %lu: %d\n",
|
||||
(unsigned long)pin, ret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Name: km_i2c_config_col
|
||||
*
|
||||
* Description:
|
||||
* Configure column pins as inputs with pull-up using IO expander API.
|
||||
*/
|
||||
|
||||
static void km_i2c_config_col(kmatrix_pin_t pin)
|
||||
{
|
||||
int ret;
|
||||
|
||||
iinfo("I2C: Configuring pin %lu as input (column)\n", (unsigned long)pin);
|
||||
|
||||
ret = IOEXP_SETDIRECTION(g_km_i2c_dev.ioe, (uint8_t)pin,
|
||||
IOEXPANDER_DIRECTION_IN_PULLUP);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* PCA9538 does not support IN_PULLUP; fall back to plain input. */
|
||||
|
||||
iinfo("I2C: IN_PULLUP not supported for pin %lu, falling back to IN\n",
|
||||
(unsigned long)pin);
|
||||
|
||||
ret = IOEXP_SETDIRECTION(g_km_i2c_dev.ioe, (uint8_t)pin,
|
||||
IOEXPANDER_DIRECTION_IN);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: Failed to configure col pin %lu: %d\n",
|
||||
(unsigned long)pin, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Name: km_i2c_row_set
|
||||
*
|
||||
* Description:
|
||||
* Control row output (active-low for matrix with diodes).
|
||||
*/
|
||||
|
||||
static void km_i2c_row_set(kmatrix_pin_t pin, bool active)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* For active-low: active=true means write LOW (false) */
|
||||
|
||||
ret = IOEXP_WRITEPIN(g_km_i2c_dev.ioe, (uint8_t)pin, !active);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: Failed to set row pin %lu: %d\n",
|
||||
(unsigned long)pin, ret);
|
||||
}
|
||||
|
||||
iinfo("I2C: Row set pin %lu to %d\n", (unsigned long)pin, active ? 0 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name: km_i2c_col_get
|
||||
*
|
||||
* Description:
|
||||
* Read column input (active-low with pull-up).
|
||||
*/
|
||||
|
||||
static bool km_i2c_col_get(kmatrix_pin_t pin)
|
||||
{
|
||||
bool value;
|
||||
int ret;
|
||||
|
||||
ret = IOEXP_READPIN(g_km_i2c_dev.ioe, (uint8_t)pin, &value);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: Failed to read col pin %lu: %d\n",
|
||||
(unsigned long)pin, ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return inverted: true = active (low), false = inactive (high) */
|
||||
|
||||
bool result = !value;
|
||||
|
||||
iinfo("I2C: Col get pin %lu = %d\n", (unsigned long)pin, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* Name: kmatrix_i2c_get_callbacks
|
||||
*
|
||||
* Description:
|
||||
* Get the I2C callback functions to use in keyboard matrix config.
|
||||
* This is called by board adapters to populate the callbacks.
|
||||
*
|
||||
* Returned Value:
|
||||
* Structure with the callback function pointers.
|
||||
*/
|
||||
|
||||
static struct kmatrix_callbacks_s g_km_i2c_callbacks =
|
||||
{
|
||||
.config_row = km_i2c_config_row,
|
||||
.config_col = km_i2c_config_col,
|
||||
.row_set = km_i2c_row_set,
|
||||
.col_get = km_i2c_col_get,
|
||||
};
|
||||
|
||||
FAR struct kmatrix_callbacks_s *kmatrix_i2c_get_callbacks(void)
|
||||
{
|
||||
return &g_km_i2c_callbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name: kmatrix_i2c_register
|
||||
*
|
||||
* Description:
|
||||
* Register keyboard matrix driver using I2C GPIO expander.
|
||||
* The IO expander device must already be initialized.
|
||||
*
|
||||
* Input Parameters:
|
||||
* ioe_dev - IO expander device (from mcp23x08_initialize or
|
||||
* pca9538_initialize)
|
||||
* config - Keyboard matrix configuration (with callbacks set)
|
||||
* devpath - Device path (e.g., "/dev/kbd0")
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; negated errno on failure.
|
||||
*/
|
||||
|
||||
int kmatrix_i2c_register(FAR struct ioexpander_dev_s *ioe_dev,
|
||||
FAR const struct kmatrix_config_s *config,
|
||||
FAR const char *devpath)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ioe_dev == NULL)
|
||||
{
|
||||
ierr("ERROR: IO expander device is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iinfo("Initializing keyboard matrix via I2C IO expander\n");
|
||||
|
||||
/* Store IO expander device in global for callbacks */
|
||||
|
||||
g_km_i2c_dev.ioe = ioe_dev;
|
||||
|
||||
/* Register the keyboard matrix driver with provided config
|
||||
* (which must have callbacks already set by the board adapter)
|
||||
*/
|
||||
|
||||
ret = kmatrix_register(config, devpath);
|
||||
if (ret < 0)
|
||||
{
|
||||
ierr("ERROR: kmatrix_register failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iinfo("Keyboard matrix I2C driver registered successfully\n");
|
||||
return OK;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/****************************************************************************
|
||||
* include/nuttx/input/kmatrix.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_INPUT_KMATRIX_H
|
||||
#define __INCLUDE_NUTTX_INPUT_KMATRIX_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/input/keyboard.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
typedef uint32_t kmatrix_pin_t;
|
||||
|
||||
/* Keyboard matrix configuration structure passed to kmatrix_register() */
|
||||
|
||||
struct kmatrix_config_s
|
||||
{
|
||||
uint8_t nrows; /* Number of rows */
|
||||
uint8_t ncols; /* Number of columns */
|
||||
FAR const kmatrix_pin_t *rows; /* Array of row GPIO pins */
|
||||
FAR const kmatrix_pin_t *cols; /* Array of column GPIO pins */
|
||||
|
||||
/* Keymap: keycode[row * cols + col] */
|
||||
|
||||
FAR const uint32_t *keymap;
|
||||
uint16_t poll_interval_ms; /* Polling interval in milliseconds */
|
||||
|
||||
/* GPIO callback functions specific to the SoC/board */
|
||||
|
||||
void (*config_row)(kmatrix_pin_t pin);
|
||||
void (*config_col)(kmatrix_pin_t pin);
|
||||
void (*row_set)(kmatrix_pin_t pin, bool active);
|
||||
bool (*col_get)(kmatrix_pin_t pin);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_INPUT_KMATRIX_I2C
|
||||
|
||||
/* Keyboard matrix callback structure for I2C expanders */
|
||||
|
||||
struct kmatrix_callbacks_s
|
||||
{
|
||||
void (*config_row)(kmatrix_pin_t pin);
|
||||
void (*config_col)(kmatrix_pin_t pin);
|
||||
void (*row_set)(kmatrix_pin_t pin, bool active);
|
||||
bool (*col_get)(kmatrix_pin_t pin);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_INPUT_KMATRIX_I2C */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_register
|
||||
*
|
||||
* Description:
|
||||
* Configure and register a keyboard matrix device. This will create the
|
||||
* /dev/keypadN device node and enable keyboard scanning.
|
||||
*
|
||||
* Input Parameters:
|
||||
* config - The keyboard matrix configuration. This structure is not
|
||||
* copied; it must persist for the lifetime of the driver.
|
||||
* devpath - The device path for the /dev/keypadN device.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int kmatrix_register(FAR const struct kmatrix_config_s *config,
|
||||
FAR const char *devpath);
|
||||
|
||||
#ifdef CONFIG_INPUT_KMATRIX_I2C
|
||||
|
||||
/* Forward declaration */
|
||||
|
||||
struct ioexpander_dev_s;
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_i2c_register
|
||||
*
|
||||
* Description:
|
||||
* Register keyboard matrix driver using I2C GPIO expander.
|
||||
* The IO expander device must already be initialized using
|
||||
* mcp23x08_initialize() or pca9538_initialize().
|
||||
*
|
||||
* Input Parameters:
|
||||
* ioe_dev - IO expander device (from mcp23x08_initialize or
|
||||
* pca9538_initialize)
|
||||
* config - The keyboard matrix configuration (with callbacks set)
|
||||
* devpath - The device path for the /dev/keypadN device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero is returned on success. Otherwise, a negated errno value is
|
||||
* returned to indicate the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int kmatrix_i2c_register(FAR struct ioexpander_dev_s *ioe_dev,
|
||||
FAR const struct kmatrix_config_s *config,
|
||||
FAR const char *devpath);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kmatrix_i2c_get_callbacks
|
||||
*
|
||||
* Description:
|
||||
* Get the I2C callback functions to use in keyboard matrix config.
|
||||
* This is called by board adapters to populate the callbacks.
|
||||
*
|
||||
* Returned Value:
|
||||
* Structure with the callback function pointers.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct kmatrix_callbacks_s *kmatrix_i2c_get_callbacks(void);
|
||||
|
||||
#endif /* CONFIG_INPUT_KMATRIX_I2C */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_INPUT_KMATRIX_H */
|
||||
Reference in New Issue
Block a user