You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by li...@apache.org on 2026/04/12 23:41:58 UTC
(nuttx) branch master updated (a4487813485 -> e274655d1c2)
This is an automated email from the ASF dual-hosted git repository.
linguini pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
from a4487813485 boards/nucleo-c0XX: add qencoder support
new 1513b3e20c2 arch/nrf52|nrf53: add qencoder support
new 83264bac845 boards/nrf52840-dk: add qencoder example
new e274655d1c2 boards/nrf5340-dk: add qencoder example
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
Documentation/platforms/arm/nrf52/index.rst | 8 +-
Documentation/platforms/arm/nrf53/index.rst | 8 +-
arch/arm/src/nrf52/CMakeLists.txt | 4 +
arch/arm/src/nrf52/Kconfig | 21 +
arch/arm/src/nrf52/Make.defs | 4 +
arch/arm/src/nrf52/hardware/nrf52_qdec.h | 242 +++++++++++
arch/arm/src/nrf52/nrf52_qdec.c | 445 ++++++++++++++++++++
.../esp32c3_uid.h => arm/src/nrf52/nrf52_qdec.h} | 32 +-
arch/arm/src/nrf53/CMakeLists.txt | 8 +
arch/arm/src/nrf53/Kconfig | 28 ++
arch/arm/src/nrf53/Make.defs | 4 +
arch/arm/src/nrf53/hardware/nrf53_qdec.h | 215 ++++++++++
arch/arm/src/nrf53/nrf53_qdec.c | 464 +++++++++++++++++++++
.../esp32c3_uid.h => arm/src/nrf53/nrf53_qdec.h} | 32 +-
.../arm/nrf52/nrf52840-dk/configs/jumbo/defconfig | 8 +
boards/arm/nrf52/nrf52840-dk/include/board.h | 5 +
boards/arm/nrf52/nrf52840-dk/src/CMakeLists.txt | 4 +
boards/arm/nrf52/nrf52840-dk/src/Make.defs | 4 +
boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h | 12 +
boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c | 8 +
.../nrf52840-dk/src/nrf52_qencoder.c} | 46 +-
.../{timer_cpuapp => qencoder_cpuapp}/defconfig | 10 +-
boards/arm/nrf53/nrf5340-dk/include/board.h | 5 +
boards/arm/nrf53/nrf5340-dk/src/CMakeLists.txt | 4 +
boards/arm/nrf53/nrf5340-dk/src/Make.defs | 4 +
boards/arm/nrf53/nrf5340-dk/src/nrf5340-dk.h | 12 +
boards/arm/nrf53/nrf5340-dk/src/nrf53_bringup.c | 8 +
.../nrf5340-dk/src/nrf53_qencoder.c} | 46 +-
28 files changed, 1615 insertions(+), 76 deletions(-)
create mode 100644 arch/arm/src/nrf52/hardware/nrf52_qdec.h
create mode 100644 arch/arm/src/nrf52/nrf52_qdec.c
copy arch/{risc-v/src/esp32c3-legacy/esp32c3_uid.h => arm/src/nrf52/nrf52_qdec.h} (78%)
create mode 100644 arch/arm/src/nrf53/hardware/nrf53_qdec.h
create mode 100644 arch/arm/src/nrf53/nrf53_qdec.c
copy arch/{risc-v/src/esp32c3-legacy/esp32c3_uid.h => arm/src/nrf53/nrf53_qdec.h} (78%)
copy boards/arm/{stm32f0l0g0/common/src/board_qencoder.c => nrf52/nrf52840-dk/src/nrf52_qencoder.c} (73%)
copy boards/arm/nrf53/nrf5340-dk/configs/{timer_cpuapp => qencoder_cpuapp}/defconfig (87%)
copy boards/arm/{stm32f0l0g0/common/src/board_qencoder.c => nrf53/nrf5340-dk/src/nrf53_qencoder.c} (73%)
(nuttx) 01/03: arch/nrf52|nrf53: add qencoder support
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
linguini pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 1513b3e20c2387732428d529b9d9046d163e608f
Author: raiden00pl <ra...@railab.me>
AuthorDate: Sat Apr 11 12:30:33 2026 +0200
arch/nrf52|nrf53: add qencoder support
add qencoder support for nrf52 and nrf53
Signed-off-by: raiden00pl <ra...@railab.me>
---
Documentation/platforms/arm/nrf52/index.rst | 8 +-
Documentation/platforms/arm/nrf53/index.rst | 8 +-
arch/arm/src/nrf52/CMakeLists.txt | 4 +
arch/arm/src/nrf52/Kconfig | 21 ++
arch/arm/src/nrf52/Make.defs | 4 +
arch/arm/src/nrf52/hardware/nrf52_qdec.h | 242 +++++++++++++++
arch/arm/src/nrf52/nrf52_qdec.c | 445 ++++++++++++++++++++++++++
arch/arm/src/nrf52/nrf52_qdec.h | 52 ++++
arch/arm/src/nrf53/CMakeLists.txt | 8 +
arch/arm/src/nrf53/Kconfig | 28 ++
arch/arm/src/nrf53/Make.defs | 4 +
arch/arm/src/nrf53/hardware/nrf53_qdec.h | 215 +++++++++++++
arch/arm/src/nrf53/nrf53_qdec.c | 464 ++++++++++++++++++++++++++++
arch/arm/src/nrf53/nrf53_qdec.h | 52 ++++
14 files changed, 1553 insertions(+), 2 deletions(-)
diff --git a/Documentation/platforms/arm/nrf52/index.rst b/Documentation/platforms/arm/nrf52/index.rst
index 5d4bb0144c6..f2fd75315a6 100644
--- a/Documentation/platforms/arm/nrf52/index.rst
+++ b/Documentation/platforms/arm/nrf52/index.rst
@@ -62,7 +62,7 @@ NFCT No
PDM No
PPI Yes
PWM Yes
-QDEC No
+QDEC Yes Quadrature encoder
QSPI Yes
RADIO Yes BLE, IEEE 802.15.4
RNG Yes
@@ -158,6 +158,12 @@ PWM
PWM is supported via standard driver. This means that more advanced features such as
complex sequences or waveform modes are not yet supported.
+QDEC
+----
+
+The QDEC (Quadrature Decoder) peripheral is supported via the standard qencoder driver
+interface. The LED output is not supported now.
+
QSPI
----
diff --git a/Documentation/platforms/arm/nrf53/index.rst b/Documentation/platforms/arm/nrf53/index.rst
index 50ae98fee05..4ea834de622 100644
--- a/Documentation/platforms/arm/nrf53/index.rst
+++ b/Documentation/platforms/arm/nrf53/index.rst
@@ -21,7 +21,7 @@ NFCT No
PDM No
DPPI No
PWM Yes
-QDEC No
+QDEC Yes Quadrature encoder
QSPI Yes
RADIO No
RNG No
@@ -102,6 +102,12 @@ PWM
PWM is supported via standard driver. This means that more advanced features such as
complex sequences or waveform modes are not yet supported.
+QDEC
+----
+
+The QDEC (Quadrature Decoder) peripheral is supported via the standard qencoder driver
+interface. The LED output is not supported now.
+
QSPI
----
diff --git a/arch/arm/src/nrf52/CMakeLists.txt b/arch/arm/src/nrf52/CMakeLists.txt
index 66858f547ee..4fcf2e6fb81 100644
--- a/arch/arm/src/nrf52/CMakeLists.txt
+++ b/arch/arm/src/nrf52/CMakeLists.txt
@@ -132,6 +132,10 @@ if(CONFIG_NRF52_SAADC)
list(APPEND SRCS nrf52_adc.c)
endif()
+if(CONFIG_NRF52_QDEC)
+ list(APPEND SRCS nrf52_qdec.c)
+endif()
+
if(CONFIG_PM)
list(APPEND SRCS nrf52_pminitialize.c)
endif()
diff --git a/arch/arm/src/nrf52/Kconfig b/arch/arm/src/nrf52/Kconfig
index eb2d0847bdb..3c6ac405212 100644
--- a/arch/arm/src/nrf52/Kconfig
+++ b/arch/arm/src/nrf52/Kconfig
@@ -170,6 +170,10 @@ config NRF52_RTC
bool
default n
+config NRF52_QDEC
+ bool
+ default n
+
menu "nRF52 Peripheral Selection"
config NRF52_I2C0_MASTER
@@ -803,6 +807,23 @@ menu "USBDEV Configuration"
endmenu # USBDEV Configuration
+config NRF52_QDEC0
+ bool "Qencoder (QDEC) support"
+ default n
+ select NRF52_QDEC
+ ---help---
+ Enable Qencoder support.
+
+config NRF52_QENCODER_INDEX
+ bool "Enable QDEC index pin support"
+ default n
+ depends on NRF52_GPIOTE && NRF52_QDEC
+ ---help---
+ Enable index/Z channel support for quadrature encoder.
+ Uses a GPIO interrupt to detect index pulses and reset
+ position to configured index value. Requires one GPIOTE
+ channel for interrupt detection.
+
menuconfig NRF52_SOFTDEVICE_CONTROLLER
bool "SoftDevice Controller"
depends on ALLOW_BSDNORDIC_COMPONENTS
diff --git a/arch/arm/src/nrf52/Make.defs b/arch/arm/src/nrf52/Make.defs
index 10118d1753d..a8eb228fdc6 100644
--- a/arch/arm/src/nrf52/Make.defs
+++ b/arch/arm/src/nrf52/Make.defs
@@ -123,6 +123,10 @@ ifeq ($(CONFIG_NRF52_SAADC),y)
CHIP_CSRCS += nrf52_adc.c
endif
+ifeq ($(CONFIG_NRF52_QDEC),y)
+CHIP_CSRCS += nrf52_qdec.c
+endif
+
ifeq ($(CONFIG_PM),y)
CHIP_CSRCS += nrf52_pminitialize.c
endif
diff --git a/arch/arm/src/nrf52/hardware/nrf52_qdec.h b/arch/arm/src/nrf52/hardware/nrf52_qdec.h
new file mode 100644
index 00000000000..2cbe799dc92
--- /dev/null
+++ b/arch/arm/src/nrf52/hardware/nrf52_qdec.h
@@ -0,0 +1,242 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/hardware/nrf52_qdec.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 __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_QDEC_H
+#define __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_QDEC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/nrf52_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+#define NRF52_QDEC_TASKS_START_OFFSET 0x0000 /* Task starting the quadrature decoder */
+#define NRF52_QDEC_TASKS_STOP_OFFSET 0x0004 /* Task stopping the quadrature decoder */
+#define NRF52_QDEC_TASKS_READCLRACC_OFFSET 0x0008 /* Read and clear ACC and ACCDBL */
+#define NRF52_QDEC_TASKS_RDCLRACC_OFFSET 0x000c /* Read and clear ACC */
+#define NRF52_QDEC_TASKS_RDCLRDBL_OFFSET 0x0010 /* Read and clear ACCDBL */
+
+#define NRF52_QDEC_EVENTS_SAMPLERDY_OFFSET 0x0100 /* Event being generated for every new sample value */
+#define NRF52_QDEC_EVENTS_REPORTRDY_OFFSET 0x0104 /* Non-null report ready */
+#define NRF52_QDEC_EVENTS_ACCOF_OFFSET 0x0108 /* ACC or ACCDBL register overflow */
+#define NRF52_QDEC_EVENTS_DBLRDY_OFFSET 0x010c /* Double displacement(s) detected */
+#define NRF52_QDEC_EVENTS_STOPPED_OFFSET 0x0110 /* QDEC has been stopped */
+
+#define NRF52_QDEC_SHORTS_OFFSET 0x0200 /* Shortcut register */
+#define NRF52_QDEC_INTENSET_OFFSET 0x0304 /* Enable interrupt */
+#define NRF52_QDEC_INTENCLR_OFFSET 0x0308 /* Disable interrupt */
+#define NRF52_QDEC_ENABLE_OFFSET 0x0500 /* Enable the quadrature decoder */
+#define NRF52_QDEC_LEDPOL_OFFSET 0x0504 /* LED output pin polarity */
+#define NRF52_QDEC_SAMPLEPER_OFFSET 0x0508 /* Sample period */
+#define NRF52_QDEC_SAMPLE_OFFSET 0x050c /* Motion sample value */
+#define NRF52_QDEC_REPORTPER_OFFSET 0x0510 /* Number of samples to be taken before REPORTRDY and DBLRDY events */
+#define NRF52_QDEC_ACC_OFFSET 0x0514 /* Register accumulating the valid transitions */
+#define NRF52_QDEC_ACCREAD_OFFSET 0x0518 /* Snapshot of the ACC register */
+#define NRF52_QDEC_PSEL_LED_OFFSET 0x051c /* Pin select for LED signal */
+#define NRF52_QDEC_PSEL_A_OFFSET 0x0520 /* Pin select for A signal */
+#define NRF52_QDEC_PSEL_B_OFFSET 0x0524 /* Pin select for B signal */
+#define NRF52_QDEC_DBFEN_OFFSET 0x0528 /* Enable input debounce filters */
+#define NRF52_QDEC_LEDPRE_OFFSET 0x0540 /* Time period the LED is switched ON prior to sampling */
+#define NRF52_QDEC_ACCDBL_OFFSET 0x0544 /* Register accumulating the number of detected double transitions */
+#define NRF52_QDEC_ACCDBLREAD_OFFSET 0x0548 /* Snapshot of the ACCDBL register */
+
+/* Register addresses *******************************************************/
+
+#define NRF52_QDEC_TASKS_START (NRF52_QDEC_BASE + NRF52_QDEC_TASKS_START_OFFSET)
+#define NRF52_QDEC_TASKS_STOP (NRF52_QDEC_BASE + NRF52_QDEC_TASKS_STOP_OFFSET)
+#define NRF52_QDEC_TASKS_READCLRACC (NRF52_QDEC_BASE + NRF52_QDEC_TASKS_READCLRACC_OFFSET)
+#define NRF52_QDEC_TASKS_RDCLRACC (NRF52_QDEC_BASE + NRF52_QDEC_TASKS_RDCLRACC_OFFSET)
+#define NRF52_QDEC_TASKS_RDCLRDBL (NRF52_QDEC_BASE + NRF52_QDEC_TASKS_RDCLRDBL_OFFSET)
+
+#define NRF52_QDEC_EVENTS_SAMPLERDY (NRF52_QDEC_BASE + NRF52_QDEC_EVENTS_SAMPLERDY_OFFSET)
+#define NRF52_QDEC_EVENTS_REPORTRDY (NRF52_QDEC_BASE + NRF52_QDEC_EVENTS_REPORTRDY_OFFSET)
+#define NRF52_QDEC_EVENTS_ACCOF (NRF52_QDEC_BASE + NRF52_QDEC_EVENTS_ACCOF_OFFSET)
+#define NRF52_QDEC_EVENTS_DBLRDY (NRF52_QDEC_BASE + NRF52_QDEC_EVENTS_DBLRDY_OFFSET)
+#define NRF52_QDEC_EVENTS_STOPPED (NRF52_QDEC_BASE + NRF52_QDEC_EVENTS_STOPPED_OFFSET)
+
+#define NRF52_QDEC_SHORTS (NRF52_QDEC_BASE + NRF52_QDEC_SHORTS_OFFSET)
+#define NRF52_QDEC_INTENSET (NRF52_QDEC_BASE + NRF52_QDEC_INTENSET_OFFSET)
+#define NRF52_QDEC_INTENCLR (NRF52_QDEC_BASE + NRF52_QDEC_INTENCLR_OFFSET)
+#define NRF52_QDEC_ENABLE (NRF52_QDEC_BASE + NRF52_QDEC_ENABLE_OFFSET)
+#define NRF52_QDEC_LEDPOL (NRF52_QDEC_BASE + NRF52_QDEC_LEDPOL_OFFSET)
+#define NRF52_QDEC_SAMPLEPER (NRF52_QDEC_BASE + NRF52_QDEC_SAMPLEPER_OFFSET)
+#define NRF52_QDEC_SAMPLE (NRF52_QDEC_BASE + NRF52_QDEC_SAMPLE_OFFSET)
+#define NRF52_QDEC_REPORTPER (NRF52_QDEC_BASE + NRF52_QDEC_REPORTPER_OFFSET)
+#define NRF52_QDEC_ACC (NRF52_QDEC_BASE + NRF52_QDEC_ACC_OFFSET)
+#define NRF52_QDEC_ACCREAD (NRF52_QDEC_BASE + NRF52_QDEC_ACCREAD_OFFSET)
+#define NRF52_QDEC_PSEL_LED (NRF52_QDEC_BASE + NRF52_QDEC_PSEL_LED_OFFSET)
+#define NRF52_QDEC_PSEL_A (NRF52_QDEC_BASE + NRF52_QDEC_PSEL_A_OFFSET)
+#define NRF52_QDEC_PSEL_B (NRF52_QDEC_BASE + NRF52_QDEC_PSEL_B_OFFSET)
+#define NRF52_QDEC_DBFEN (NRF52_QDEC_BASE + NRF52_QDEC_DBFEN_OFFSET)
+#define NRF52_QDEC_LEDPRE (NRF52_QDEC_BASE + NRF52_QDEC_LEDPRE_OFFSET)
+#define NRF52_QDEC_ACCDBL (NRF52_QDEC_BASE + NRF52_QDEC_ACCDBL_OFFSET)
+#define NRF52_QDEC_ACCDBLREAD (NRF52_QDEC_BASE + NRF52_QDEC_ACCDBLREAD_OFFSET)
+
+/* Register Bitfield Definitions ********************************************/
+
+/* TASKS_START Register */
+
+#define QDEC_TASKS_START (1 << 0) /* Bit 0: Start QDEC */
+
+/* TASKS_STOP Register */
+
+#define QDEC_TASKS_STOP (1 << 0) /* Bit 0: Stop QDEC */
+
+/* TASKS_READCLRACC Register */
+
+#define QDEC_TASKS_READCLRACC (1 << 0) /* Bit 0: Read and clear ACC and ACCDBL */
+
+/* TASKS_RDCLRACC Register */
+
+#define QDEC_TASKS_RDCLRACC (1 << 0) /* Bit 0: Read and clear ACC */
+
+/* TASKS_RDCLRDBL Register */
+
+#define QDEC_TASKS_RDCLRDBL (1 << 0) /* Bit 0: Read and clear ACCDBL */
+
+/* EVENTS_SAMPLERDY Register */
+
+#define QDEC_EVENTS_SAMPLERDY (1 << 0) /* Bit 0: Sample ready event */
+
+/* EVENTS_REPORTRDY Register */
+
+#define QDEC_EVENTS_REPORTRDY (1 << 0) /* Bit 0: Report ready event */
+
+/* EVENTS_ACCOF Register */
+
+#define QDEC_EVENTS_ACCOF (1 << 0) /* Bit 0: Accumulator overflow event */
+
+/* EVENTS_DBLRDY Register */
+
+#define QDEC_EVENTS_DBLRDY (1 << 0) /* Bit 0: Double displacement ready event */
+
+/* EVENTS_STOPPED Register */
+
+#define QDEC_EVENTS_STOPPED (1 << 0) /* Bit 0: QDEC stopped event */
+
+/* SHORTS Register */
+
+#define QDEC_SHORTS_REPORTRDY_READCLRACC (1 << 0) /* Bit 0: Shortcut between REPORTRDY event and READCLRACC task */
+#define QDEC_SHORTS_SAMPLERDY_STOP (1 << 1) /* Bit 1: Shortcut between SAMPLERDY event and STOP task */
+#define QDEC_SHORTS_REPORTRDY_RDCLRACC (1 << 2) /* Bit 2: Shortcut between REPORTRDY event and RDCLRACC task */
+#define QDEC_SHORTS_REPORTRDY_STOP (1 << 3) /* Bit 3: Shortcut between REPORTRDY event and STOP task */
+#define QDEC_SHORTS_DBLRDY_RDCLRDBL (1 << 4) /* Bit 4: Shortcut between DBLRDY event and RDCLRDBL task */
+#define QDEC_SHORTS_DBLRDY_STOP (1 << 5) /* Bit 5: Shortcut between DBLRDY event and STOP task */
+#define QDEC_SHORTS_SAMPLERDY_READCLRACC (1 << 6) /* Bit 6: Shortcut between SAMPLERDY event and READCLRACC task */
+
+/* INTENSET/INTENCLR Register */
+
+#define QDEC_INT_SAMPLERDY (1 << 0) /* Bit 0: Interrupt for SAMPLERDY event */
+#define QDEC_INT_REPORTRDY (1 << 1) /* Bit 1: Interrupt for REPORTRDY event */
+#define QDEC_INT_ACCOF (1 << 2) /* Bit 2: Interrupt for ACCOF event */
+#define QDEC_INT_DBLRDY (1 << 3) /* Bit 3: Interrupt for DBLRDY event */
+#define QDEC_INT_STOPPED (1 << 4) /* Bit 4: Interrupt for STOPPED event */
+
+/* ENABLE Register */
+
+#define QDEC_ENABLE_DISABLE (0 << 0) /* Bit 0: Disable QDEC */
+#define QDEC_ENABLE_ENABLE (1 << 0) /* Bit 0: Enable QDEC */
+
+/* LEDPOL Register */
+
+#define QDEC_LEDPOL_ACTIVELOW (0 << 0) /* Bit 0: LED active on output pin low */
+#define QDEC_LEDPOL_ACTIVEHIGH (1 << 0) /* Bit 0: LED active on output pin high */
+
+/* SAMPLEPER Register */
+
+#define QDEC_SAMPLEPER_SHIFT (0) /* Bits 0-3: Sample period */
+#define QDEC_SAMPLEPER_MASK (0xf << QDEC_SAMPLEPER_SHIFT)
+# define QDEC_SAMPLEPER_128US (0 << QDEC_SAMPLEPER_SHIFT) /* 128 us */
+# define QDEC_SAMPLEPER_256US (1 << QDEC_SAMPLEPER_SHIFT) /* 256 us */
+# define QDEC_SAMPLEPER_512US (2 << QDEC_SAMPLEPER_SHIFT) /* 512 us */
+# define QDEC_SAMPLEPER_1024US (3 << QDEC_SAMPLEPER_SHIFT) /* 1024 us */
+# define QDEC_SAMPLEPER_2048US (4 << QDEC_SAMPLEPER_SHIFT) /* 2048 us */
+# define QDEC_SAMPLEPER_4096US (5 << QDEC_SAMPLEPER_SHIFT) /* 4096 us */
+# define QDEC_SAMPLEPER_8192US (6 << QDEC_SAMPLEPER_SHIFT) /* 8192 us */
+# define QDEC_SAMPLEPER_16384US (7 << QDEC_SAMPLEPER_SHIFT) /* 16384 us */
+# define QDEC_SAMPLEPER_32MS (8 << QDEC_SAMPLEPER_SHIFT) /* 32768 us */
+# define QDEC_SAMPLEPER_65MS (9 << QDEC_SAMPLEPER_SHIFT) /* 65536 us */
+# define QDEC_SAMPLEPER_131MS (10 << QDEC_SAMPLEPER_SHIFT) /* 131072 us */
+
+/* SAMPLE Register */
+
+#define QDEC_SAMPLE_MASK (0xffffffff)
+
+/* REPORTPER Register */
+
+#define QDEC_REPORTPER_SHIFT (0) /* Bits 0-3: Report period */
+#define QDEC_REPORTPER_MASK (0xf << QDEC_REPORTPER_SHIFT)
+# define QDEC_REPORTPER_10SMPL (0 << QDEC_REPORTPER_SHIFT) /* 10 samples */
+# define QDEC_REPORTPER_40SMPL (1 << QDEC_REPORTPER_SHIFT) /* 40 samples */
+# define QDEC_REPORTPER_80SMPL (2 << QDEC_REPORTPER_SHIFT) /* 80 samples */
+# define QDEC_REPORTPER_120SMPL (3 << QDEC_REPORTPER_SHIFT) /* 120 samples */
+# define QDEC_REPORTPER_160SMPL (4 << QDEC_REPORTPER_SHIFT) /* 160 samples */
+# define QDEC_REPORTPER_200SMPL (5 << QDEC_REPORTPER_SHIFT) /* 200 samples */
+# define QDEC_REPORTPER_240SMPL (6 << QDEC_REPORTPER_SHIFT) /* 240 samples */
+# define QDEC_REPORTPER_280SMPL (7 << QDEC_REPORTPER_SHIFT) /* 280 samples */
+# define QDEC_REPORTPER_DISABLED (8 << QDEC_REPORTPER_SHIFT) /* Disabled */
+
+/* ACC Register */
+
+#define QDEC_ACC_MASK (0xffffffff)
+
+/* ACCREAD Register */
+
+#define QDEC_ACCREAD_MASK (0xffffffff)
+
+/* PSEL Registers */
+
+#define QDEC_PSEL_PIN_SHIFT (0) /* Bits 0-4: Pin number */
+#define QDEC_PSEL_PIN_MASK (0x1f << QDEC_PSEL_PIN_SHIFT)
+#define QDEC_PSEL_PORT_SHIFT (5) /* Bit 5: Port number */
+#define QDEC_PSEL_PORT_MASK (0x1 << QDEC_PSEL_PORT_SHIFT)
+#define QDEC_PSEL_CONNECT_SHIFT (31) /* Bit 31: Connection */
+#define QDEC_PSEL_CONNECT_MASK (0x1 << QDEC_PSEL_CONNECT_SHIFT)
+# define QDEC_PSEL_CONNECTED (0 << QDEC_PSEL_CONNECT_SHIFT)
+# define QDEC_PSEL_DISCONNECTED (1 << QDEC_PSEL_CONNECT_SHIFT)
+
+/* DBFEN Register */
+
+#define QDEC_DBFEN_DISABLE (0 << 0) /* Bit 0: Debounce input filters disabled */
+#define QDEC_DBFEN_ENABLE (1 << 0) /* Bit 0: Debounce input filters enabled */
+
+/* LEDPRE Register */
+
+#define QDEC_LEDPRE_SHIFT (0) /* Bits 0-8: LED pre time */
+#define QDEC_LEDPRE_MASK (0x1ff << QDEC_LEDPRE_SHIFT)
+
+/* ACCDBL Register */
+
+#define QDEC_ACCDBL_MASK (0xf)
+
+/* ACCDBLREAD Register */
+
+#define QDEC_ACCDBLREAD_MASK (0xf)
+
+#endif /* __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_QDEC_H */
diff --git a/arch/arm/src/nrf52/nrf52_qdec.c b/arch/arm/src/nrf52/nrf52_qdec.c
new file mode 100644
index 00000000000..128f978f99e
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_qdec.c
@@ -0,0 +1,445 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_qdec.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 <stdint.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/sensors/qencoder.h>
+
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "nrf52_gpio.h"
+#include "nrf52_qdec.h"
+
+#include "hardware/nrf52_qdec.h"
+#include "hardware/nrf52_utils.h"
+
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+# include <nuttx/irq.h>
+# include "nrf52_gpiote.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct nrf52_qdec_s
+{
+ const struct qe_ops_s *ops;
+ const struct nrf52_qeconfig_s *config;
+ uint32_t base;
+ uint32_t pin_a;
+ uint32_t pin_b;
+ int32_t position;
+ uint32_t posmax;
+ bool inuse;
+ bool posmax_enabled;
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+ uint16_t index_count;
+ uint32_t pin_index;
+ uint32_t index_pos;
+#endif
+ spinlock_t lock;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline void nrf52_qdec_putreg(struct nrf52_qdec_s *priv,
+ uint32_t offset, uint32_t value);
+static inline uint32_t nrf52_qdec_getreg(struct nrf52_qdec_s *priv,
+ uint32_t offset);
+
+static int nrf52_qdec_setup(struct qe_lowerhalf_s *lower);
+static int nrf52_qdec_shutdown(struct qe_lowerhalf_s *lower);
+static int nrf52_qdec_position(struct qe_lowerhalf_s *lower, int32_t *pos);
+static int nrf52_qdec_setposmax(struct qe_lowerhalf_s *lower, uint32_t pos);
+static int nrf52_qdec_reset(struct qe_lowerhalf_s *lower);
+static int nrf52_qdec_setindex(struct qe_lowerhalf_s *lower, uint32_t pos);
+static int nrf52_qdec_ioctl(struct qe_lowerhalf_s *lower, int cmd,
+ unsigned long arg);
+
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+static int nrf52_qdec_index_interrupt(int irq, void *context, void *arg);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct qe_ops_s g_nrf52_qdecops =
+{
+ .setup = nrf52_qdec_setup,
+ .shutdown = nrf52_qdec_shutdown,
+ .position = nrf52_qdec_position,
+ .setposmax = nrf52_qdec_setposmax,
+ .reset = nrf52_qdec_reset,
+ .setindex = nrf52_qdec_setindex,
+ .ioctl = nrf52_qdec_ioctl,
+};
+
+#ifdef CONFIG_NRF52_QDEC0
+struct nrf52_qdec_s g_nrf52_qdec0 =
+{
+ .ops = &g_nrf52_qdecops,
+ .base = NRF52_QDEC_BASE,
+ .pin_a = BOARD_QDEC0_A_PIN,
+ .pin_b = BOARD_QDEC0_B_PIN,
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+ .pin_index = BOARD_QDEC0_INDEX_PIN,
+#endif
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_qdec_putreg
+ ****************************************************************************/
+
+static inline void nrf52_qdec_putreg(struct nrf52_qdec_s *priv,
+ uint32_t offset, uint32_t value)
+{
+ putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_qdec_getreg
+ ****************************************************************************/
+
+static inline uint32_t nrf52_qdec_getreg(struct nrf52_qdec_s *priv,
+ uint32_t offset)
+{
+ return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_qdec_setup
+ ****************************************************************************/
+
+static int nrf52_qdec_setup(struct qe_lowerhalf_s *lower)
+{
+ struct nrf52_qdec_s *priv = (struct nrf52_qdec_s *)lower;
+ uint32_t pin;
+ uint32_t port;
+ uint32_t regval;
+ irqstate_t flags;
+ int ret;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ if (priv->inuse)
+ {
+ ret = -EBUSY;
+ goto errout;
+ }
+
+ nrf52_gpio_config(priv->pin_a);
+ nrf52_gpio_config(priv->pin_b);
+
+ /* Configure PSEL A */
+
+ pin = GPIO_PIN_DECODE(priv->pin_a);
+ port = GPIO_PORT_DECODE(priv->pin_a);
+ regval = (port << QDEC_PSEL_PORT_SHIFT);
+ regval |= (pin << QDEC_PSEL_PIN_SHIFT);
+ nrf52_qdec_putreg(priv, NRF52_QDEC_PSEL_A_OFFSET, regval);
+
+ /* Configure PSEL B */
+
+ pin = GPIO_PIN_DECODE(priv->pin_b);
+ port = GPIO_PORT_DECODE(priv->pin_b);
+ regval = (port << QDEC_PSEL_PORT_SHIFT);
+ regval |= (pin << QDEC_PSEL_PIN_SHIFT);
+ nrf52_qdec_putreg(priv, NRF52_QDEC_PSEL_B_OFFSET, regval);
+
+ /* Disable LED */
+
+ nrf52_qdec_putreg(priv, NRF52_QDEC_PSEL_LED_OFFSET,
+ QDEC_PSEL_DISCONNECTED);
+
+ /* Configure decoder */
+
+ nrf52_qdec_putreg(priv, NRF52_QDEC_SAMPLEPER_OFFSET,
+ priv->config->sample_period & QDEC_SAMPLEPER_MASK);
+ nrf52_qdec_putreg(priv, NRF52_QDEC_REPORTPER_OFFSET,
+ priv->config->report_period & QDEC_REPORTPER_MASK);
+
+ nrf52_qdec_putreg(priv, NRF52_QDEC_DBFEN_OFFSET,
+ priv->config->enable_debounce ? QDEC_DBFEN_ENABLE :
+ QDEC_DBFEN_DISABLE);
+
+ /* Start decoder */
+
+ nrf52_qdec_putreg(priv, NRF52_QDEC_ENABLE_OFFSET, QDEC_ENABLE_ENABLE);
+ nrf52_qdec_putreg(priv, NRF52_QDEC_TASKS_START_OFFSET, QDEC_TASKS_START);
+
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+ /* Configure Index pin */
+
+ nrf52_gpio_config(priv->pin_index);
+ ret = nrf52_gpiote_set_event(priv->pin_index, true, false,
+ nrf52_qdec_index_interrupt, priv);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to configure index pin interrupt: %d\n", ret);
+ goto errout;
+ }
+#endif
+
+ priv->inuse = true;
+ priv->position = 0;
+ priv->posmax_enabled = false;
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+ priv->index_pos = 0;
+ priv->index_count = 0;
+#endif
+ ret = OK;
+
+errout:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_qdec_shutdown
+ ****************************************************************************/
+
+static int nrf52_qdec_shutdown(struct qe_lowerhalf_s *lower)
+{
+ struct nrf52_qdec_s *priv = (struct nrf52_qdec_s *)lower;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ nrf52_qdec_putreg(priv, NRF52_QDEC_TASKS_STOP_OFFSET, QDEC_TASKS_STOP);
+ nrf52_qdec_putreg(priv, NRF52_QDEC_ENABLE_OFFSET, QDEC_ENABLE_DISABLE);
+
+ nrf52_gpio_unconfig(priv->pin_a);
+ nrf52_gpio_unconfig(priv->pin_b);
+
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+ nrf52_gpiote_set_event(priv->pin_index, false, false, NULL, NULL);
+ nrf52_gpio_unconfig(priv->pin_index);
+#endif
+
+ priv->inuse = false;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_qdec_position
+ ****************************************************************************/
+
+static int nrf52_qdec_position(struct qe_lowerhalf_s *lower, int32_t *pos)
+{
+ struct nrf52_qdec_s *priv = (struct nrf52_qdec_s *)lower;
+ irqstate_t flags;
+ int32_t accread;
+
+ DEBUGASSERT(lower && pos);
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ nrf52_qdec_putreg(priv, NRF52_QDEC_TASKS_RDCLRACC_OFFSET,
+ QDEC_TASKS_RDCLRACC);
+
+ accread = (int32_t)nrf52_qdec_getreg(priv, NRF52_QDEC_ACCREAD_OFFSET);
+
+ priv->position += accread;
+
+ if (priv->posmax_enabled && priv->posmax > 0)
+ {
+ priv->position = priv->position % (int32_t)priv->posmax;
+ if (priv->position < 0)
+ {
+ priv->position += (int32_t)priv->posmax;
+ }
+ }
+
+ *pos = priv->position;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_qdec_setposmax
+ ****************************************************************************/
+
+static int nrf52_qdec_setposmax(struct qe_lowerhalf_s *lower, uint32_t pos)
+{
+ struct nrf52_qdec_s *priv = (struct nrf52_qdec_s *)lower;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ priv->posmax = pos;
+ priv->posmax_enabled = (pos > 0);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_qdec_reset
+ ****************************************************************************/
+
+static int nrf52_qdec_reset(struct qe_lowerhalf_s *lower)
+{
+ struct nrf52_qdec_s *priv = (struct nrf52_qdec_s *)lower;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ nrf52_qdec_putreg(priv, NRF52_QDEC_TASKS_READCLRACC_OFFSET,
+ QDEC_TASKS_READCLRACC);
+
+ priv->position = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_qdec_setindex
+ ****************************************************************************/
+
+static int nrf52_qdec_setindex(struct qe_lowerhalf_s *lower, uint32_t pos)
+{
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+ struct nrf52_qdec_s *priv = (struct nrf52_qdec_s *)lower;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+ priv->index_pos = pos;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return OK;
+#else
+ return -ENOTTY;
+#endif
+}
+
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+
+/****************************************************************************
+ * Name: nrf52_qdec_index_interrupt
+ ****************************************************************************/
+
+static int nrf52_qdec_index_interrupt(int irq, void *context, void *arg)
+{
+ struct nrf52_qdec_s *priv = (struct nrf52_qdec_s *)arg;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ priv->position = priv->index_pos;
+ priv->index_count++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return OK;
+}
+
+#endif
+
+/****************************************************************************
+ * Name: nrf52_qdec_ioctl
+ ****************************************************************************/
+
+static int nrf52_qdec_ioctl(struct qe_lowerhalf_s *lower, int cmd,
+ unsigned long arg)
+{
+#ifdef CONFIG_NRF52_QENCODER_INDEX
+ struct nrf52_qdec_s *priv = (struct nrf52_qdec_s *)lower;
+ struct qe_index_s *index;
+
+ if (cmd == QEIOC_GETINDEX)
+ {
+ index = (struct qe_index_s *)arg;
+ index->qenc_pos = priv->position;
+ index->indx_pos = priv->index_pos;
+ index->indx_cnt = priv->index_count;
+ return OK;
+ }
+#endif
+
+ return -ENOTTY;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_qeinitialize
+ ****************************************************************************/
+
+struct qe_lowerhalf_s *
+nrf52_qeinitialize(int qdec, const struct nrf52_qeconfig_s *config)
+{
+ struct nrf52_qdec_s *priv = NULL;
+
+ DEBUGASSERT(config != NULL);
+
+ switch (qdec)
+ {
+#ifdef CONFIG_NRF52_QDEC0
+ case 0:
+ {
+ priv = &g_nrf52_qdec0;
+ break;
+ }
+#endif
+
+ default:
+ {
+ snerr("ERROR: Invalid QDEC instance: %d\n", qdec);
+ return NULL;
+ }
+ }
+
+ priv->config = config;
+
+ return (struct qe_lowerhalf_s *)priv;
+}
diff --git a/arch/arm/src/nrf52/nrf52_qdec.h b/arch/arm/src/nrf52/nrf52_qdec.h
new file mode 100644
index 00000000000..3dce1dabdc7
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_qdec.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_qdec.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 __ARCH_ARM_SRC_NRF52_NRF52_QENCODER_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_QENCODER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct nrf52_qeconfig_s
+{
+ uint8_t sample_period;
+ uint8_t report_period;
+ bool enable_debounce;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+struct qe_lowerhalf_s;
+struct qe_lowerhalf_s *
+nrf52_qeinitialize(int qdec, const struct nrf52_qeconfig_s *config);
+
+#endif /* __ARCH_ARM_SRC_NRF52_NRF52_QENCODER_H */
diff --git a/arch/arm/src/nrf53/CMakeLists.txt b/arch/arm/src/nrf53/CMakeLists.txt
index 900c52430c1..49d99a0548f 100644
--- a/arch/arm/src/nrf53/CMakeLists.txt
+++ b/arch/arm/src/nrf53/CMakeLists.txt
@@ -107,6 +107,14 @@ if(CONFIG_NRF53_QSPI)
list(APPEND SRCS nrf53_qspi.c)
endif()
+if(CONFIG_NRF53_QDEC)
+ list(APPEND SRCS nrf53_qdec.c)
+endif()
+
+if(CONFIG_SENSORS_QENCODER)
+ list(APPEND SRCS nrf53_qdec.c)
+endif()
+
if(CONFIG_NRF53_SOFTDEVICE_CONTROLLER)
set(NRFXLIB_VER "2.3.0")
diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig
index a629b2d5a23..b951cd9bde1 100644
--- a/arch/arm/src/nrf53/Kconfig
+++ b/arch/arm/src/nrf53/Kconfig
@@ -182,6 +182,10 @@ config NRF53_RTC
bool
default n
+config NRF53_QDEC
+ bool
+ default n
+
menu "nRF53 Peripheral Selection"
config NRF53_GPIOTE
@@ -714,6 +718,30 @@ endif # NRF53_QSPI
endmenu # QSPI Configuration
+config NRF53_QDEC0
+ bool "Qencoder 0 (QDEC0) support"
+ default n
+ select NRF53_QDEC
+ ---help---
+ Enable Qencoder 0 support.
+
+config NRF53_QDEC1
+ bool "Qencoder 1 (QDEC1) support"
+ default n
+ select NRF53_QDEC
+ ---help---
+ Enable Qencoder 1 support.
+
+config NRF53_QENCODER_INDEX
+ bool "Enable QDEC index pin support"
+ default n
+ depends on NRF53_GPIOTE && NRF53_QDEC
+ ---help---
+ Enable index/Z channel support for quadrature encoder.
+ Uses a GPIO interrupt to detect index pulses and reset
+ position to configured index value. Requires one GPIOTE
+ channel for interrupt detection.
+
menuconfig NRF53_SOFTDEVICE_CONTROLLER
bool "SoftDevice Controller"
depends on ALLOW_BSDNORDIC_COMPONENTS
diff --git a/arch/arm/src/nrf53/Make.defs b/arch/arm/src/nrf53/Make.defs
index d91f55b12e6..9a0a63827c3 100644
--- a/arch/arm/src/nrf53/Make.defs
+++ b/arch/arm/src/nrf53/Make.defs
@@ -101,6 +101,10 @@ ifeq ($(CONFIG_NRF53_QSPI),y)
CHIP_CSRCS += nrf53_qspi.c
endif
+ifeq ($(CONFIG_NRF53_QDEC),y)
+CHIP_CSRCS += nrf53_qdec.c
+endif
+
ifeq ($(CONFIG_NRF53_SOFTDEVICE_CONTROLLER),y)
NRFXLIB_UNPACK := sdk-nrfxlib
diff --git a/arch/arm/src/nrf53/hardware/nrf53_qdec.h b/arch/arm/src/nrf53/hardware/nrf53_qdec.h
new file mode 100644
index 00000000000..a2d45933b87
--- /dev/null
+++ b/arch/arm/src/nrf53/hardware/nrf53_qdec.h
@@ -0,0 +1,215 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/hardware/nrf53_qdec.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 __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_QDEC_H
+#define __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_QDEC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/nrf53_memorymap_cpuapp.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* QDEC Base Addresses */
+
+#define NRF53_QDEC0_BASE NRF53_QDEC_BASE /* QDEC0: 0x50033000 */
+#define NRF53_QDEC1_BASE 0x50034000 /* QDEC1: 0x50034000 */
+
+/* Register offsets *********************************************************/
+
+#define NRF53_QDEC_TASKS_START_OFFSET 0x0000 /* Task starting the quadrature decoder */
+#define NRF53_QDEC_TASKS_STOP_OFFSET 0x0004 /* Task stopping the quadrature decoder */
+#define NRF53_QDEC_TASKS_READCLRACC_OFFSET 0x0008 /* Read and clear ACC and ACCDBL */
+#define NRF53_QDEC_TASKS_RDCLRACC_OFFSET 0x000c /* Read and clear ACC */
+#define NRF53_QDEC_TASKS_RDCLRDBL_OFFSET 0x0010 /* Read and clear ACCDBL */
+
+#define NRF53_QDEC_EVENTS_SAMPLERDY_OFFSET 0x0100 /* Event being generated for every new sample value */
+#define NRF53_QDEC_EVENTS_REPORTRDY_OFFSET 0x0104 /* Non-null report ready */
+#define NRF53_QDEC_EVENTS_ACCOF_OFFSET 0x0108 /* ACC or ACCDBL register overflow */
+#define NRF53_QDEC_EVENTS_DBLRDY_OFFSET 0x010c /* Double displacement(s) detected */
+#define NRF53_QDEC_EVENTS_STOPPED_OFFSET 0x0110 /* QDEC has been stopped */
+
+#define NRF53_QDEC_SHORTS_OFFSET 0x0200 /* Shortcut register */
+#define NRF53_QDEC_INTENSET_OFFSET 0x0304 /* Enable interrupt */
+#define NRF53_QDEC_INTENCLR_OFFSET 0x0308 /* Disable interrupt */
+#define NRF53_QDEC_ENABLE_OFFSET 0x0500 /* Enable the quadrature decoder */
+#define NRF53_QDEC_LEDPOL_OFFSET 0x0504 /* LED output pin polarity */
+#define NRF53_QDEC_SAMPLEPER_OFFSET 0x0508 /* Sample period */
+#define NRF53_QDEC_SAMPLE_OFFSET 0x050c /* Motion sample value */
+#define NRF53_QDEC_REPORTPER_OFFSET 0x0510 /* Number of samples to be taken before REPORTRDY and DBLRDY events */
+#define NRF53_QDEC_ACC_OFFSET 0x0514 /* Register accumulating the valid transitions */
+#define NRF53_QDEC_ACCREAD_OFFSET 0x0518 /* Snapshot of the ACC register */
+#define NRF53_QDEC_PSEL_LED_OFFSET 0x051c /* Pin select for LED signal */
+#define NRF53_QDEC_PSEL_A_OFFSET 0x0520 /* Pin select for A signal */
+#define NRF53_QDEC_PSEL_B_OFFSET 0x0524 /* Pin select for B signal */
+#define NRF53_QDEC_DBFEN_OFFSET 0x0528 /* Enable input debounce filters */
+#define NRF53_QDEC_LEDPRE_OFFSET 0x0540 /* Time period the LED is switched ON prior to sampling */
+#define NRF53_QDEC_ACCDBL_OFFSET 0x0544 /* Register accumulating the number of detected double transitions */
+#define NRF53_QDEC_ACCDBLREAD_OFFSET 0x0548 /* Snapshot of the ACCDBL register */
+
+/* Register Bitfield Definitions ********************************************/
+
+/* TASKS_START Register */
+
+#define QDEC_TASKS_START (1 << 0) /* Bit 0: Start QDEC */
+
+/* TASKS_STOP Register */
+
+#define QDEC_TASKS_STOP (1 << 0) /* Bit 0: Stop QDEC */
+
+/* TASKS_READCLRACC Register */
+
+#define QDEC_TASKS_READCLRACC (1 << 0) /* Bit 0: Read and clear ACC and ACCDBL */
+
+/* TASKS_RDCLRACC Register */
+
+#define QDEC_TASKS_RDCLRACC (1 << 0) /* Bit 0: Read and clear ACC */
+
+/* TASKS_RDCLRDBL Register */
+
+#define QDEC_TASKS_RDCLRDBL (1 << 0) /* Bit 0: Read and clear ACCDBL */
+
+/* EVENTS_SAMPLERDY Register */
+
+#define QDEC_EVENTS_SAMPLERDY (1 << 0) /* Bit 0: Sample ready event */
+
+/* EVENTS_REPORTRDY Register */
+
+#define QDEC_EVENTS_REPORTRDY (1 << 0) /* Bit 0: Report ready event */
+
+/* EVENTS_ACCOF Register */
+
+#define QDEC_EVENTS_ACCOF (1 << 0) /* Bit 0: Accumulator overflow event */
+
+/* EVENTS_DBLRDY Register */
+
+#define QDEC_EVENTS_DBLRDY (1 << 0) /* Bit 0: Double displacement ready event */
+
+/* EVENTS_STOPPED Register */
+
+#define QDEC_EVENTS_STOPPED (1 << 0) /* Bit 0: QDEC stopped event */
+
+/* SHORTS Register */
+
+#define QDEC_SHORTS_REPORTRDY_READCLRACC (1 << 0) /* Bit 0: Shortcut between REPORTRDY event and READCLRACC task */
+#define QDEC_SHORTS_SAMPLERDY_STOP (1 << 1) /* Bit 1: Shortcut between SAMPLERDY event and STOP task */
+#define QDEC_SHORTS_REPORTRDY_RDCLRACC (1 << 2) /* Bit 2: Shortcut between REPORTRDY event and RDCLRACC task */
+#define QDEC_SHORTS_REPORTRDY_STOP (1 << 3) /* Bit 3: Shortcut between REPORTRDY event and STOP task */
+#define QDEC_SHORTS_DBLRDY_RDCLRDBL (1 << 4) /* Bit 4: Shortcut between DBLRDY event and RDCLRDBL task */
+#define QDEC_SHORTS_DBLRDY_STOP (1 << 5) /* Bit 5: Shortcut between DBLRDY event and STOP task */
+#define QDEC_SHORTS_SAMPLERDY_READCLRACC (1 << 6) /* Bit 6: Shortcut between SAMPLERDY event and READCLRACC task */
+
+/* INTENSET/INTENCLR Register */
+
+#define QDEC_INT_SAMPLERDY (1 << 0) /* Bit 0: Interrupt for SAMPLERDY event */
+#define QDEC_INT_REPORTRDY (1 << 1) /* Bit 1: Interrupt for REPORTRDY event */
+#define QDEC_INT_ACCOF (1 << 2) /* Bit 2: Interrupt for ACCOF event */
+#define QDEC_INT_DBLRDY (1 << 3) /* Bit 3: Interrupt for DBLRDY event */
+#define QDEC_INT_STOPPED (1 << 4) /* Bit 4: Interrupt for STOPPED event */
+
+/* ENABLE Register */
+
+#define QDEC_ENABLE_DISABLE (0 << 0) /* Bit 0: Disable QDEC */
+#define QDEC_ENABLE_ENABLE (1 << 0) /* Bit 0: Enable QDEC */
+
+/* LEDPOL Register */
+
+#define QDEC_LEDPOL_ACTIVELOW (0 << 0) /* Bit 0: LED active on output pin low */
+#define QDEC_LEDPOL_ACTIVEHIGH (1 << 0) /* Bit 0: LED active on output pin high */
+
+/* SAMPLEPER Register */
+
+#define QDEC_SAMPLEPER_SHIFT (0) /* Bits 0-3: Sample period */
+#define QDEC_SAMPLEPER_MASK (0xf << QDEC_SAMPLEPER_SHIFT)
+# define QDEC_SAMPLEPER_128US (0 << QDEC_SAMPLEPER_SHIFT) /* 128 us */
+# define QDEC_SAMPLEPER_256US (1 << QDEC_SAMPLEPER_SHIFT) /* 256 us */
+# define QDEC_SAMPLEPER_512US (2 << QDEC_SAMPLEPER_SHIFT) /* 512 us */
+# define QDEC_SAMPLEPER_1024US (3 << QDEC_SAMPLEPER_SHIFT) /* 1024 us */
+# define QDEC_SAMPLEPER_2048US (4 << QDEC_SAMPLEPER_SHIFT) /* 2048 us */
+# define QDEC_SAMPLEPER_4096US (5 << QDEC_SAMPLEPER_SHIFT) /* 4096 us */
+# define QDEC_SAMPLEPER_8192US (6 << QDEC_SAMPLEPER_SHIFT) /* 8192 us */
+# define QDEC_SAMPLEPER_16384US (7 << QDEC_SAMPLEPER_SHIFT) /* 16384 us */
+# define QDEC_SAMPLEPER_32MS (8 << QDEC_SAMPLEPER_SHIFT) /* 32768 us */
+# define QDEC_SAMPLEPER_65MS (9 << QDEC_SAMPLEPER_SHIFT) /* 65536 us */
+# define QDEC_SAMPLEPER_131MS (10 << QDEC_SAMPLEPER_SHIFT) /* 131072 us */
+
+/* SAMPLE Register */
+
+#define QDEC_SAMPLE_MASK (0xffffffff)
+
+/* REPORTPER Register */
+
+#define QDEC_REPORTPER_SHIFT (0) /* Bits 0-3: Report period */
+#define QDEC_REPORTPER_MASK (0xf << QDEC_REPORTPER_SHIFT)
+# define QDEC_REPORTPER_10SMPL (0 << QDEC_REPORTPER_SHIFT) /* 10 samples */
+# define QDEC_REPORTPER_40SMPL (1 << QDEC_REPORTPER_SHIFT) /* 40 samples */
+# define QDEC_REPORTPER_80SMPL (2 << QDEC_REPORTPER_SHIFT) /* 80 samples */
+# define QDEC_REPORTPER_120SMPL (3 << QDEC_REPORTPER_SHIFT) /* 120 samples */
+# define QDEC_REPORTPER_160SMPL (4 << QDEC_REPORTPER_SHIFT) /* 160 samples */
+# define QDEC_REPORTPER_200SMPL (5 << QDEC_REPORTPER_SHIFT) /* 200 samples */
+# define QDEC_REPORTPER_240SMPL (6 << QDEC_REPORTPER_SHIFT) /* 240 samples */
+# define QDEC_REPORTPER_280SMPL (7 << QDEC_REPORTPER_SHIFT) /* 280 samples */
+# define QDEC_REPORTPER_DISABLED (8 << QDEC_REPORTPER_SHIFT) /* Disabled */
+
+/* ACC Register */
+
+#define QDEC_ACC_MASK (0xffffffff)
+
+/* ACCREAD Register */
+
+#define QDEC_ACCREAD_MASK (0xffffffff)
+
+/* PSEL Registers */
+
+#define QDEC_PSEL_PIN_SHIFT (0) /* Bits 0-4: Pin number */
+#define QDEC_PSEL_PIN_MASK (0x1f << QDEC_PSEL_PIN_SHIFT)
+#define QDEC_PSEL_PORT_SHIFT (5) /* Bit 5: Port number */
+#define QDEC_PSEL_PORT_MASK (0x1 << QDEC_PSEL_PORT_SHIFT)
+#define QDEC_PSEL_CONNECT_SHIFT (31) /* Bit 31: Connection */
+#define QDEC_PSEL_CONNECT_MASK (0x1 << QDEC_PSEL_CONNECT_SHIFT)
+# define QDEC_PSEL_CONNECTED (0 << QDEC_PSEL_CONNECT_SHIFT)
+# define QDEC_PSEL_DISCONNECTED (1 << QDEC_PSEL_CONNECT_SHIFT)
+
+/* DBFEN Register */
+
+#define QDEC_DBFEN_DISABLE (0 << 0) /* Bit 0: Debounce input filters disabled */
+#define QDEC_DBFEN_ENABLE (1 << 0) /* Bit 0: Debounce input filters enabled */
+
+/* LEDPRE Register */
+
+#define QDEC_LEDPRE_SHIFT (0) /* Bits 0-8: LED pre time */
+#define QDEC_LEDPRE_MASK (0x1ff << QDEC_LEDPRE_SHIFT)
+
+/* ACCDBL Register */
+
+#define QDEC_ACCDBL_MASK (0xf)
+
+/* ACCDBLREAD Register */
+
+#define QDEC_ACCDBLREAD_MASK (0xf)
+
+#endif /* __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_QDEC_H */
diff --git a/arch/arm/src/nrf53/nrf53_qdec.c b/arch/arm/src/nrf53/nrf53_qdec.c
new file mode 100644
index 00000000000..91c6e3fc43d
--- /dev/null
+++ b/arch/arm/src/nrf53/nrf53_qdec.c
@@ -0,0 +1,464 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/nrf53_qdec.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 <stdint.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/sensors/qencoder.h>
+
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "nrf53_gpio.h"
+#include "nrf53_qdec.h"
+
+#include "hardware/nrf53_qdec.h"
+#include "hardware/nrf53_utils.h"
+
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+# include <nuttx/irq.h>
+# include "nrf53_gpiote.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct nrf53_qdec_s
+{
+ const struct qe_ops_s *ops;
+ const struct nrf53_qeconfig_s *config;
+ uint32_t base;
+ uint32_t pin_a;
+ uint32_t pin_b;
+ int32_t position;
+ uint32_t posmax;
+ bool inuse;
+ bool posmax_enabled;
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+ uint16_t index_count;
+ uint32_t pin_index;
+ uint32_t index_pos;
+#endif
+ spinlock_t lock;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline void nrf53_qdec_putreg(struct nrf53_qdec_s *priv,
+ uint32_t offset, uint32_t value);
+static inline uint32_t nrf53_qdec_getreg(struct nrf53_qdec_s *priv,
+ uint32_t offset);
+
+static int nrf53_qdec_setup(struct qe_lowerhalf_s *lower);
+static int nrf53_qdec_shutdown(struct qe_lowerhalf_s *lower);
+static int nrf53_qdec_position(struct qe_lowerhalf_s *lower, int32_t *pos);
+static int nrf53_qdec_setposmax(struct qe_lowerhalf_s *lower, uint32_t pos);
+static int nrf53_qdec_reset(struct qe_lowerhalf_s *lower);
+static int nrf53_qdec_setindex(struct qe_lowerhalf_s *lower, uint32_t pos);
+static int nrf53_qdec_ioctl(struct qe_lowerhalf_s *lower, int cmd,
+ unsigned long arg);
+
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+static int nrf53_qdec_index_interrupt(int irq, void *context, void *arg);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct qe_ops_s g_nrf53_qdecops =
+{
+ .setup = nrf53_qdec_setup,
+ .shutdown = nrf53_qdec_shutdown,
+ .position = nrf53_qdec_position,
+ .setposmax = nrf53_qdec_setposmax,
+ .reset = nrf53_qdec_reset,
+ .setindex = nrf53_qdec_setindex,
+ .ioctl = nrf53_qdec_ioctl,
+};
+
+#ifdef CONFIG_NRF53_QDEC0
+struct nrf53_qdec_s g_nrf53_qdec0 =
+{
+ .ops = &g_nrf53_qdecops,
+ .base = NRF53_QDEC0_BASE,
+ .pin_a = BOARD_QDEC0_A_PIN,
+ .pin_b = BOARD_QDEC0_B_PIN,
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+ .pin_index = BOARD_QDEC0_INDEX_PIN,
+#endif
+};
+#endif
+
+#ifdef CONFIG_NRF53_QDEC1
+struct nrf53_qdec_s g_nrf53_qdec1 =
+{
+ .ops = &g_nrf53_qdecops,
+ .base = NRF53_QDEC1_BASE,
+ .pin_a = BOARD_QDEC1_A_PIN,
+ .pin_b = BOARD_QDEC1_B_PIN,
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+ .pin_index = BOARD_QDEC1_INDEX_PIN,
+#endif
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_qdec_putreg
+ ****************************************************************************/
+
+static inline void nrf53_qdec_putreg(struct nrf53_qdec_s *priv,
+ uint32_t offset, uint32_t value)
+{
+ putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf53_qdec_getreg
+ ****************************************************************************/
+
+static inline uint32_t nrf53_qdec_getreg(struct nrf53_qdec_s *priv,
+ uint32_t offset)
+{
+ return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf53_qdec_setup
+ ****************************************************************************/
+
+static int nrf53_qdec_setup(struct qe_lowerhalf_s *lower)
+{
+ struct nrf53_qdec_s *priv = (struct nrf53_qdec_s *)lower;
+ uint32_t pin;
+ uint32_t port;
+ uint32_t regval;
+ irqstate_t flags;
+ int ret;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ if (priv->inuse)
+ {
+ ret = -EBUSY;
+ goto errout;
+ }
+
+ nrf53_gpio_config(priv->pin_a);
+ nrf53_gpio_config(priv->pin_b);
+
+ /* Configure PSEL A */
+
+ pin = GPIO_PIN_DECODE(priv->pin_a);
+ port = GPIO_PORT_DECODE(priv->pin_a);
+ regval = (port << QDEC_PSEL_PORT_SHIFT);
+ regval |= (pin << QDEC_PSEL_PIN_SHIFT);
+ nrf53_qdec_putreg(priv, NRF53_QDEC_PSEL_A_OFFSET, regval);
+
+ /* Configure PSEL B */
+
+ pin = GPIO_PIN_DECODE(priv->pin_b);
+ port = GPIO_PORT_DECODE(priv->pin_b);
+ regval = (port << QDEC_PSEL_PORT_SHIFT);
+ regval |= (pin << QDEC_PSEL_PIN_SHIFT);
+ nrf53_qdec_putreg(priv, NRF53_QDEC_PSEL_B_OFFSET, regval);
+
+ /* Disable LED */
+
+ nrf53_qdec_putreg(priv, NRF53_QDEC_PSEL_LED_OFFSET,
+ QDEC_PSEL_DISCONNECTED);
+
+ /* Configure decoder */
+
+ nrf53_qdec_putreg(priv, NRF53_QDEC_SAMPLEPER_OFFSET,
+ priv->config->sample_period & QDEC_SAMPLEPER_MASK);
+ nrf53_qdec_putreg(priv, NRF53_QDEC_REPORTPER_OFFSET,
+ priv->config->report_period & QDEC_REPORTPER_MASK);
+
+ nrf53_qdec_putreg(priv, NRF53_QDEC_DBFEN_OFFSET,
+ priv->config->enable_debounce ? QDEC_DBFEN_ENABLE :
+ QDEC_DBFEN_DISABLE);
+
+ /* Start decoder */
+
+ nrf53_qdec_putreg(priv, NRF53_QDEC_ENABLE_OFFSET, QDEC_ENABLE_ENABLE);
+ nrf53_qdec_putreg(priv, NRF53_QDEC_TASKS_START_OFFSET, QDEC_TASKS_START);
+
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+ nrf53_gpio_config(priv->pin_index);
+ ret = nrf53_gpiote_set_event(priv->pin_index, true, false,
+ nrf53_qdec_index_interrupt, priv);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to configure index pin interrupt: %d\n", ret);
+ goto errout;
+ }
+#endif
+
+ priv->inuse = true;
+ priv->position = 0;
+ priv->posmax_enabled = false;
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+ priv->index_pos = 0;
+ priv->index_count = 0;
+#endif
+ ret = OK;
+
+errout:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_qdec_shutdown
+ ****************************************************************************/
+
+static int nrf53_qdec_shutdown(struct qe_lowerhalf_s *lower)
+{
+ struct nrf53_qdec_s *priv = (struct nrf53_qdec_s *)lower;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ nrf53_qdec_putreg(priv, NRF53_QDEC_TASKS_STOP_OFFSET, QDEC_TASKS_STOP);
+ nrf53_qdec_putreg(priv, NRF53_QDEC_ENABLE_OFFSET, QDEC_ENABLE_DISABLE);
+
+ nrf53_gpio_unconfig(priv->pin_a);
+ nrf53_gpio_unconfig(priv->pin_b);
+
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+ nrf53_gpiote_set_event(priv->pin_index, false, false, NULL, NULL);
+ nrf53_gpio_unconfig(priv->pin_index);
+#endif
+
+ priv->inuse = false;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_qdec_position
+ ****************************************************************************/
+
+static int nrf53_qdec_position(struct qe_lowerhalf_s *lower, int32_t *pos)
+{
+ struct nrf53_qdec_s *priv = (struct nrf53_qdec_s *)lower;
+ irqstate_t flags;
+ int32_t accread;
+
+ DEBUGASSERT(lower && pos);
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ nrf53_qdec_putreg(priv, NRF53_QDEC_TASKS_RDCLRACC_OFFSET,
+ QDEC_TASKS_RDCLRACC);
+
+ accread = (int32_t)nrf53_qdec_getreg(priv, NRF53_QDEC_ACCREAD_OFFSET);
+
+ priv->position += accread;
+
+ if (priv->posmax_enabled && priv->posmax > 0)
+ {
+ priv->position = priv->position % (int32_t)priv->posmax;
+ if (priv->position < 0)
+ {
+ priv->position += (int32_t)priv->posmax;
+ }
+ }
+
+ *pos = priv->position;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_qdec_setposmax
+ ****************************************************************************/
+
+static int nrf53_qdec_setposmax(struct qe_lowerhalf_s *lower, uint32_t pos)
+{
+ struct nrf53_qdec_s *priv = (struct nrf53_qdec_s *)lower;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ priv->posmax = pos;
+ priv->posmax_enabled = (pos > 0);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_qdec_reset
+ ****************************************************************************/
+
+static int nrf53_qdec_reset(struct qe_lowerhalf_s *lower)
+{
+ struct nrf53_qdec_s *priv = (struct nrf53_qdec_s *)lower;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ nrf53_qdec_putreg(priv, NRF53_QDEC_TASKS_READCLRACC_OFFSET,
+ QDEC_TASKS_READCLRACC);
+
+ priv->position = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_qdec_setindex
+ ****************************************************************************/
+
+static int nrf53_qdec_setindex(struct qe_lowerhalf_s *lower, uint32_t pos)
+{
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+ struct nrf53_qdec_s *priv = (struct nrf53_qdec_s *)lower;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+ priv->index_pos = pos;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return OK;
+#else
+ return -ENOTTY;
+#endif
+}
+
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+
+/****************************************************************************
+ * Name: nrf53_qdec_index_interrupt
+ ****************************************************************************/
+
+static int nrf53_qdec_index_interrupt(int irq, void *context, void *arg)
+{
+ struct nrf53_qdec_s *priv = (struct nrf53_qdec_s *)arg;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave(&priv->lock);
+
+ priv->position = priv->index_pos;
+ priv->index_count++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return OK;
+}
+
+#endif
+
+/****************************************************************************
+ * Name: nrf53_qdec_ioctl
+ ****************************************************************************/
+
+static int nrf53_qdec_ioctl(struct qe_lowerhalf_s *lower, int cmd,
+ unsigned long arg)
+{
+#ifdef CONFIG_NRF53_QENCODER_INDEX
+ struct nrf53_qdec_s *priv = (struct nrf53_qdec_s *)lower;
+ struct qe_index_s *index;
+
+ if (cmd == QEIOC_GETINDEX)
+ {
+ index = (struct qe_index_s *)arg;
+ index->qenc_pos = priv->position;
+ index->indx_pos = priv->index_pos;
+ index->indx_cnt = priv->index_count;
+ return OK;
+ }
+#endif
+
+ return -ENOTTY;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_qeinitialize
+ ****************************************************************************/
+
+struct qe_lowerhalf_s *
+nrf53_qeinitialize(int qdec, const struct nrf53_qeconfig_s *config)
+{
+ struct nrf53_qdec_s *priv = NULL;
+
+ DEBUGASSERT(config != NULL);
+
+ switch (qdec)
+ {
+#ifdef CONFIG_NRF53_QDEC0
+ case 0:
+ {
+ priv = &g_nrf53_qdec0;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_NRF53_QDEC1
+ case 1:
+ {
+ priv = &g_nrf53_qdec1;
+ break;
+ }
+#endif
+
+ default:
+ {
+ snerr("ERROR: Invalid QDEC instance: %d\n", qdec);
+ return NULL;
+ }
+ }
+
+ priv->config = config;
+
+ return (struct qe_lowerhalf_s *)priv;
+}
diff --git a/arch/arm/src/nrf53/nrf53_qdec.h b/arch/arm/src/nrf53/nrf53_qdec.h
new file mode 100644
index 00000000000..19b86351175
--- /dev/null
+++ b/arch/arm/src/nrf53/nrf53_qdec.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/nrf53_qdec.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 __ARCH_ARM_SRC_NRF53_NRF53_QENCODER_H
+#define __ARCH_ARM_SRC_NRF53_NRF53_QENCODER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct nrf53_qeconfig_s
+{
+ uint8_t sample_period;
+ uint8_t report_period;
+ bool enable_debounce;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+struct qe_lowerhalf_s;
+struct qe_lowerhalf_s *
+nrf53_qeinitialize(int qdec, const struct nrf53_qeconfig_s *config);
+
+#endif /* __ARCH_ARM_SRC_NRF53_NRF53_QENCODER_H */
(nuttx) 03/03: boards/nrf5340-dk: add qencoder example
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
linguini pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit e274655d1c2e427c553cd6aee7d242c2416a566e
Author: raiden00pl <ra...@railab.me>
AuthorDate: Sat Apr 11 14:27:40 2026 +0200
boards/nrf5340-dk: add qencoder example
add qencoder support and enable qe example for config
Signed-off-by: raiden00pl <ra...@railab.me>
---
.../nrf5340-dk/configs/qencoder_cpuapp/defconfig | 51 +++++++++++++++
boards/arm/nrf53/nrf5340-dk/include/board.h | 5 ++
boards/arm/nrf53/nrf5340-dk/src/CMakeLists.txt | 4 ++
boards/arm/nrf53/nrf5340-dk/src/Make.defs | 4 ++
boards/arm/nrf53/nrf5340-dk/src/nrf5340-dk.h | 12 ++++
boards/arm/nrf53/nrf5340-dk/src/nrf53_bringup.c | 8 +++
boards/arm/nrf53/nrf5340-dk/src/nrf53_qencoder.c | 76 ++++++++++++++++++++++
7 files changed, 160 insertions(+)
diff --git a/boards/arm/nrf53/nrf5340-dk/configs/qencoder_cpuapp/defconfig b/boards/arm/nrf53/nrf5340-dk/configs/qencoder_cpuapp/defconfig
new file mode 100644
index 00000000000..b991e2e4a29
--- /dev/null
+++ b/boards/arm/nrf53/nrf5340-dk/configs/qencoder_cpuapp/defconfig
@@ -0,0 +1,51 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_NSH_DISABLE_IFCONFIG is not set
+# CONFIG_NSH_DISABLE_PS is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="nrf5340-dk"
+CONFIG_ARCH_BOARD_NRF5340_DK=y
+CONFIG_ARCH_CHIP="nrf53"
+CONFIG_ARCH_CHIP_NRF5340=y
+CONFIG_ARCH_CHIP_NRF5340_CPUAPP=y
+CONFIG_ARCH_CHIP_NRF53=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_STDARG_H=y
+CONFIG_BOARD_LOOPSPERMSEC=5500
+CONFIG_BUILTIN=y
+CONFIG_EXAMPLES_QENCODER=y
+CONFIG_EXAMPLES_QENCODER_HAVE_MAXPOS=y
+CONFIG_EXAMPLES_QENCODER_MAXPOS=32
+CONFIG_EXPERIMENTAL=y
+CONFIG_FAT_LCNAMES=y
+CONFIG_FAT_LFN=y
+CONFIG_FS_FAT=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_LINE_MAX=64
+CONFIG_MM_REGIONS=2
+CONFIG_NRF53_QDEC0=y
+CONFIG_NRF53_UART0=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_RAM_SIZE=524288
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_SENSORS=y
+CONFIG_SENSORS_QENCODER=y
+CONFIG_START_DAY=26
+CONFIG_START_MONTH=3
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TASK_NAME_SIZE=0
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/arm/nrf53/nrf5340-dk/include/board.h b/boards/arm/nrf53/nrf5340-dk/include/board.h
index 6b940111ed0..d0f924d99c5 100644
--- a/boards/arm/nrf53/nrf5340-dk/include/board.h
+++ b/boards/arm/nrf53/nrf5340-dk/include/board.h
@@ -179,4 +179,9 @@
#define NRF53_QSPI0_IO3_PIN (GPIO_MCUSEL_PERIP | GPIO_OUTPUT | \
GPIO_PORT0 | GPIO_PIN(16))
+/* QDEC Pins ****************************************************************/
+
+#define BOARD_QDEC0_A_PIN (GPIO_MCUSEL_APP | GPIO_INPUT | GPIO_PORT0 | GPIO_PIN(25))
+#define BOARD_QDEC0_B_PIN (GPIO_MCUSEL_APP | GPIO_INPUT | GPIO_PORT0 | GPIO_PIN(26))
+
#endif /* __BOARDS_ARM_NRF53_NRF5340_DK_INCLUDE_BOARD_H */
diff --git a/boards/arm/nrf53/nrf5340-dk/src/CMakeLists.txt b/boards/arm/nrf53/nrf5340-dk/src/CMakeLists.txt
index f65cbeda9c7..9955186065b 100644
--- a/boards/arm/nrf53/nrf5340-dk/src/CMakeLists.txt
+++ b/boards/arm/nrf53/nrf5340-dk/src/CMakeLists.txt
@@ -64,6 +64,10 @@ if(CONFIG_NRF53_QSPI)
list(APPEND SRCS nrf53_mx25.c)
endif()
+if(CONFIG_NRF53_QDEC)
+ list(APPEND SRCS nrf53_qencoder.c)
+endif()
+
target_sources(board PRIVATE ${SRCS})
if(CONFIG_ARCH_BOARD_COMMON)
diff --git a/boards/arm/nrf53/nrf5340-dk/src/Make.defs b/boards/arm/nrf53/nrf5340-dk/src/Make.defs
index 350dbb62cf6..7f9cc96e158 100644
--- a/boards/arm/nrf53/nrf5340-dk/src/Make.defs
+++ b/boards/arm/nrf53/nrf5340-dk/src/Make.defs
@@ -66,6 +66,10 @@ ifeq ($(CONFIG_NRF53_QSPI),y)
CSRCS += nrf53_mx25.c
endif
+ifeq ($(CONFIG_NRF53_QDEC),y)
+CSRCS += nrf53_qencoder.c
+endif
+
DEPPATH += --dep-path board
VPATH += :board
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board
diff --git a/boards/arm/nrf53/nrf5340-dk/src/nrf5340-dk.h b/boards/arm/nrf53/nrf5340-dk/src/nrf5340-dk.h
index 8a714b4007c..637d953f767 100644
--- a/boards/arm/nrf53/nrf5340-dk/src/nrf5340-dk.h
+++ b/boards/arm/nrf53/nrf5340-dk/src/nrf5340-dk.h
@@ -164,5 +164,17 @@ int nrf53_mx25_initialize(void);
int nrf53_gpio_initialize(void);
#endif
+/****************************************************************************
+ * Name: nrf53_qencoder_initialize
+ *
+ * Description:
+ * Initialize and register the qencoder driver
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NRF53_QDEC
+int nrf53_qencoder_initialize(int devno);
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_ARM_NRF53_NRF5340_DK_SRC_NRF5340_DK_H */
diff --git a/boards/arm/nrf53/nrf5340-dk/src/nrf53_bringup.c b/boards/arm/nrf53/nrf5340-dk/src/nrf53_bringup.c
index 03c64034c5e..ce25793893e 100644
--- a/boards/arm/nrf53/nrf5340-dk/src/nrf53_bringup.c
+++ b/boards/arm/nrf53/nrf5340-dk/src/nrf53_bringup.c
@@ -267,6 +267,14 @@ int nrf53_bringup(void)
}
#endif
+#ifdef CONFIG_NRF53_QDEC0
+ ret = nrf53_qencoder_initialize(0);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to initialize qencoder: %d\n", ret);
+ }
+#endif
+
#ifdef CONFIG_USBMONITOR
/* Start the USB Monitor */
diff --git a/boards/arm/nrf53/nrf5340-dk/src/nrf53_qencoder.c b/boards/arm/nrf53/nrf5340-dk/src/nrf53_qencoder.c
new file mode 100644
index 00000000000..178b8abc5a4
--- /dev/null
+++ b/boards/arm/nrf53/nrf5340-dk/src/nrf53_qencoder.c
@@ -0,0 +1,76 @@
+/****************************************************************************
+ * boards/arm/nrf53/nrf5340-dk/src/nrf53_qencoder.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 <errno.h>
+#include <debug.h>
+
+#include <nuttx/sensors/qencoder.h>
+
+#include "nrf53_qdec.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct nrf53_qeconfig_s g_qe0_config =
+{
+ .sample_period = 0,
+ .report_period = 0,
+ .enable_debounce = false,
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int nrf53_qencoder_initialize(int devno)
+{
+ struct qe_lowerhalf_s *lower;
+ char devpath[12];
+ int ret;
+
+ sninfo("Initializing /dev/qe%d\n", devno);
+
+ lower = nrf53_qeinitialize(devno, &g_qe0_config);
+ if (lower == NULL)
+ {
+ snerr("ERROR: nrf53_qeinitialize failed\n");
+ return -ENODEV;
+ }
+
+ snprintf(devpath, sizeof(devpath), "/dev/qe%d", devno);
+
+ ret = qe_register(devpath, lower);
+ if (ret < 0)
+ {
+ snerr("ERROR: qe_register failed: %d\n", ret);
+ return ret;
+ }
+
+ return OK;
+}
(nuttx) 02/03: boards/nrf52840-dk: add qencoder example
Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
linguini pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 83264bac8450eb64b8ffdf0d66b8a3199f9a04d1
Author: raiden00pl <ra...@railab.me>
AuthorDate: Sat Apr 11 12:51:19 2026 +0200
boards/nrf52840-dk: add qencoder example
add qencoder support and enable qe example for jumbo config
Signed-off-by: raiden00pl <ra...@railab.me>
---
.../arm/nrf52/nrf52840-dk/configs/jumbo/defconfig | 8 +++
boards/arm/nrf52/nrf52840-dk/include/board.h | 5 ++
boards/arm/nrf52/nrf52840-dk/src/CMakeLists.txt | 4 ++
boards/arm/nrf52/nrf52840-dk/src/Make.defs | 4 ++
boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h | 12 ++++
boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c | 8 +++
boards/arm/nrf52/nrf52840-dk/src/nrf52_qencoder.c | 76 ++++++++++++++++++++++
7 files changed, 117 insertions(+)
diff --git a/boards/arm/nrf52/nrf52840-dk/configs/jumbo/defconfig b/boards/arm/nrf52/nrf52840-dk/configs/jumbo/defconfig
index 7d6286b6835..7ed0451d04b 100644
--- a/boards/arm/nrf52/nrf52840-dk/configs/jumbo/defconfig
+++ b/boards/arm/nrf52/nrf52840-dk/configs/jumbo/defconfig
@@ -23,10 +23,15 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_ARCH_STDARG_H=y
CONFIG_BOARD_LOOPSPERMSEC=5500
CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
CONFIG_EXAMPLES_ADC=y
CONFIG_EXAMPLES_ADC_NSAMPLES=4
CONFIG_EXAMPLES_ADC_SWTRIG=y
CONFIG_EXAMPLES_PWM=y
+CONFIG_EXAMPLES_QENCODER=y
+CONFIG_EXAMPLES_QENCODER_HAVE_MAXPOS=y
+CONFIG_EXAMPLES_QENCODER_MAXPOS=32
CONFIG_EXAMPLES_TIMER=y
CONFIG_EXAMPLES_WATCHDOG=y
CONFIG_FAT_LCNAMES=y
@@ -44,6 +49,7 @@ CONFIG_NRF52_PWM0_CH1=y
CONFIG_NRF52_PWM0_CH2=y
CONFIG_NRF52_PWM0_CH3=y
CONFIG_NRF52_PWM_MULTICHAN=y
+CONFIG_NRF52_QDEC0=y
CONFIG_NRF52_QSPI=y
CONFIG_NRF52_SAADC=y
CONFIG_NRF52_TIMER2=y
@@ -62,6 +68,8 @@ CONFIG_RAM_START=0x20000000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_WAITPID=y
+CONFIG_SENSORS=y
+CONFIG_SENSORS_QENCODER=y
CONFIG_START_DAY=26
CONFIG_START_MONTH=3
CONFIG_SYMTAB_ORDEREDBYNAME=y
diff --git a/boards/arm/nrf52/nrf52840-dk/include/board.h b/boards/arm/nrf52/nrf52840-dk/include/board.h
index 9e5d0e0fd4a..a92c149f7df 100644
--- a/boards/arm/nrf52/nrf52840-dk/include/board.h
+++ b/boards/arm/nrf52/nrf52840-dk/include/board.h
@@ -185,4 +185,9 @@
#define NRF52_QSPI0_IO2_PIN (GPIO_OUTPUT | GPIO_PORT0 | GPIO_PIN(22))
#define NRF52_QSPI0_IO3_PIN (GPIO_OUTPUT | GPIO_PORT0 | GPIO_PIN(23))
+/* QDEC Pins ****************************************************************/
+
+#define BOARD_QDEC0_A_PIN (GPIO_INPUT | GPIO_PORT0 | GPIO_PIN(30))
+#define BOARD_QDEC0_B_PIN (GPIO_INPUT | GPIO_PORT0 | GPIO_PIN(31))
+
#endif /* __BOARDS_ARM_NRF52_NRF52840_DK_INCLUDE_BOARD_H */
diff --git a/boards/arm/nrf52/nrf52840-dk/src/CMakeLists.txt b/boards/arm/nrf52/nrf52840-dk/src/CMakeLists.txt
index 15aa13df962..3c970424884 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/CMakeLists.txt
+++ b/boards/arm/nrf52/nrf52840-dk/src/CMakeLists.txt
@@ -84,6 +84,10 @@ if(CONFIG_NRF52_QSPI)
list(APPEND SRCS nrf52_mx25.c)
endif()
+if(CONFIG_NRF52_QDEC)
+ list(APPEND SRCS nrf52_qencoder.c)
+endif()
+
target_sources(board PRIVATE ${SRCS})
if(CONFIG_ARCH_BOARD_COMMON)
diff --git a/boards/arm/nrf52/nrf52840-dk/src/Make.defs b/boards/arm/nrf52/nrf52840-dk/src/Make.defs
index 9dd96ed383a..2de1ad31645 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/Make.defs
+++ b/boards/arm/nrf52/nrf52840-dk/src/Make.defs
@@ -86,6 +86,10 @@ ifeq ($(CONFIG_NRF52_QSPI),y)
CSRCS += nrf52_mx25.c
endif
+ifeq ($(CONFIG_NRF52_QDEC),y)
+CSRCS += nrf52_qencoder.c
+endif
+
DEPPATH += --dep-path board
VPATH += :board
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h b/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
index 8d932f5235c..e7a9a4fe529 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
@@ -215,5 +215,17 @@ int nrf52_mx25_initialize(void);
int nrf52_gpioleds_initialize(void);
#endif
+/****************************************************************************
+ * Name: nrf52_qencoder_initialize
+ *
+ * Description:
+ * Initialize quadrature encoder driver.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SENSORS_QENCODER
+int nrf52_qencoder_initialize(int devno);
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_ARM_NRF52_NRF52840_DK_SRC_NRF52840_DK_H */
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
index 25faf003e1e..cc617cfbbeb 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
@@ -333,6 +333,14 @@ int nrf52_bringup(void)
}
#endif
+#ifdef CONFIG_NRF52_QDEC0
+ ret = nrf52_qencoder_initialize(0);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to initialize qencoder: %d\n", ret);
+ }
+#endif
+
UNUSED(ret);
return OK;
}
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_qencoder.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_qencoder.c
new file mode 100644
index 00000000000..3284c604fa5
--- /dev/null
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_qencoder.c
@@ -0,0 +1,76 @@
+/****************************************************************************
+ * boards/arm/nrf52/nrf52840-dk/src/nrf52_qencoder.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 <errno.h>
+#include <debug.h>
+
+#include <nuttx/sensors/qencoder.h>
+
+#include "nrf52_qdec.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct nrf52_qeconfig_s g_qe0_config =
+{
+ .sample_period = 0,
+ .report_period = 0,
+ .enable_debounce = false,
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int nrf52_qencoder_initialize(int devno)
+{
+ struct qe_lowerhalf_s *lower;
+ char devpath[12];
+ int ret;
+
+ sninfo("Initializing /dev/qe%d\n", devno);
+
+ lower = nrf52_qeinitialize(devno, &g_qe0_config);
+ if (lower == NULL)
+ {
+ snerr("ERROR: nrf52_qeinitialize failed\n");
+ return -ENODEV;
+ }
+
+ snprintf(devpath, sizeof(devpath), "/dev/qe%d", devno);
+
+ ret = qe_register(devpath, lower);
+ if (ret < 0)
+ {
+ snerr("ERROR: qe_register failed: %d\n", ret);
+ return ret;
+ }
+
+ return OK;
+}