diff --git a/cpu/nrf5x_common/include/periph_cpu_common.h b/cpu/nrf5x_common/include/periph_cpu_common.h index cad1a919b1..a8d90229b2 100644 --- a/cpu/nrf5x_common/include/periph_cpu_common.h +++ b/cpu/nrf5x_common/include/periph_cpu_common.h @@ -188,6 +188,17 @@ typedef enum { #define NWDT_TIME_UPPER_LIMIT ((UINT32_MAX >> 15) * US_PER_MS + 1) /** @} */ +/** + * @brief Quadrature decoder configuration struct + */ +typedef struct { + gpio_t a_pin; /**< GPIO Pin for phase A */ + gpio_t b_pin; /**< GPIO Pin for phase B */ + gpio_t led_pin; /**< LED GPIO, GPIO_UNDEF to disable */ + uint8_t sample_period; /**< Sample period used, e.g. QDEC_SAMPLEPER_SAMPLEPER_128us */ + bool debounce_filter; /**< Enable/disable debounce filter */ +} qdec_conf_t; + /** * @brief Retrieve the exti(GPIOTE) channel associated with a gpio * diff --git a/cpu/nrf5x_common/periph/qdec.c b/cpu/nrf5x_common/periph/qdec.c new file mode 100644 index 0000000000..79e05f1f02 --- /dev/null +++ b/cpu/nrf5x_common/periph/qdec.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_nrf5x_common + * @ingroup drivers_periph_qdec + * @{ + * + * @file + * @brief Low-level QDEC driver implementation + * + * @author Koen Zandberg + * + * @} + */ +#include + +#include "cpu.h" +#include "periph_conf.h" +#include "periph/qdec.h" +#include "periph/gpio.h" + +#ifdef QDEC_NUMOF + + +/** + * @brief Interrupt context for each configured qdec + */ +static qdec_isr_ctx_t isr_ctx[QDEC_NUMOF]; + +static inline NRF_QDEC_Type* dev(qdec_t qdec) +{ + (void)qdec; + return NRF_QDEC; +} + +static inline const qdec_conf_t* conf(qdec_t qdec) +{ + return &qdec_config[qdec]; +} + +int32_t qdec_init(qdec_t qdec, qdec_mode_t mode, qdec_cb_t cb, void *arg) +{ + (void)mode; + /* Verify parameters */ + assert((qdec < QDEC_NUMOF)); + + /* The nrf5x peripheral counts all edges */ + if (mode != QDEC_X4) { + return -EINVAL; + } + + isr_ctx[qdec].cb = cb; + isr_ctx[qdec].arg = arg; + + if (cb) { + NVIC_EnableIRQ(QDEC_IRQn); + dev(qdec)->INTENSET = QDEC_INTENSET_ACCOF_Msk; + } + else { + NVIC_DisableIRQ(QDEC_IRQn); + dev(qdec)->INTENCLR = QDEC_INTENCLR_ACCOF_Msk; + } + + gpio_init(conf(qdec)->a_pin, GPIO_IN_PU); + gpio_init(conf(qdec)->b_pin, GPIO_IN_PU); + + dev(qdec)->PSEL.A = conf(qdec)->a_pin; + dev(qdec)->PSEL.B = conf(qdec)->b_pin; + + /** Optionally set or disable the LED */ + dev(qdec)->PSEL.LED = gpio_is_valid(conf(qdec)->led_pin) + ? QDEC_PSEL_LED_CONNECT_Msk + : conf(qdec)->led_pin; + + dev(qdec)->DBFEN = conf(qdec)->debounce_filter ? 1 : 0; + + /* Enable the peripheral */ + dev(qdec)->ENABLE = 1; + dev(qdec)->TASKS_START = 1; + return 0; +} + +int32_t qdec_read_and_reset(qdec_t qdec) +{ + /* Read and clear ACC register */ + dev(qdec)->TASKS_RDCLRACC = 1; + return dev(qdec)->ACCREAD; +} + +int32_t qdec_read(qdec_t qdec) +{ + return dev(qdec)->ACC; +} + +void qdec_start(qdec_t qdec) +{ + dev(qdec)->TASKS_START = 1; +} + +void qdec_stop(qdec_t qdec) +{ + dev(qdec)->TASKS_STOP = 1; + while (dev(qdec)->EVENTS_STOPPED == 0) {} + dev(qdec)->EVENTS_STOPPED = 0; +} + +void isr_qdec(void) +{ + qdec_t qdec = QDEC_DEV(0); /* only one available */ + dev(qdec)->EVENTS_ACCOF = 0; + isr_ctx[qdec].cb(isr_ctx[qdec].arg); +} +#endif diff --git a/tests/periph_qdec/Makefile b/tests/periph_qdec/Makefile index 809484b171..fc88216267 100644 --- a/tests/periph_qdec/Makefile +++ b/tests/periph_qdec/Makefile @@ -5,4 +5,7 @@ FEATURES_REQUIRED = periph_qdec USEMODULE += xtimer +# include boards that have are modified to add a qdec peripheral +EXTERNAL_BOARD_DIRS = $(CURDIR)/boards_modded + include $(RIOTBASE)/Makefile.include diff --git a/tests/periph_qdec/boards_modded/nrf52840dk/Kconfig b/tests/periph_qdec/boards_modded/nrf52840dk/Kconfig new file mode 100644 index 0000000000..ae66d3bed9 --- /dev/null +++ b/tests/periph_qdec/boards_modded/nrf52840dk/Kconfig @@ -0,0 +1,21 @@ +# Copyright (c) 2020 HAW Hamburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +config BOARD + default "nrf52840dk" if BOARD_NRF52840DK + +config BOARD_NRF52840DK + bool + default y + select BOARDS_COMMON_NRF52XXXDK + select CPU_MODEL_NRF52840XXAA + select HAS_PERIPH_PWM + select HAS_PERIPH_QDEC + select HAS_PERIPH_USBDEV + select HAS_VDD_LC_FILTER_REG0 + select HAVE_MTD_SPI_NOR + +source "$(RIOTBOARD)/common/nrf52xxxdk/Kconfig" diff --git a/tests/periph_qdec/boards_modded/nrf52840dk/Makefile b/tests/periph_qdec/boards_modded/nrf52840dk/Makefile new file mode 100644 index 0000000000..33d5c8624b --- /dev/null +++ b/tests/periph_qdec/boards_modded/nrf52840dk/Makefile @@ -0,0 +1,6 @@ +# This must be a different name than 'board' as it is implemented by 'native' +MODULE = board_nrf52840dk_qdec + +DIRS += $(RIOTBOARD)/nrf52840dk + +include $(RIOTBASE)/Makefile.base diff --git a/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.dep b/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.dep new file mode 100644 index 0000000000..760b5488a6 --- /dev/null +++ b/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.dep @@ -0,0 +1,4 @@ +# This must be a different name than 'board' as it is implemented by 'native' +USEMODULE += board_nrf52840dk_qdec + +include $(RIOTBOARD)/nrf52840dk/Makefile.dep diff --git a/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.features b/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.features new file mode 100644 index 0000000000..069f6d7f69 --- /dev/null +++ b/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.features @@ -0,0 +1,3 @@ +FEATURES_PROVIDED += periph_qdec + +include $(RIOTBOARD)/nrf52840dk/Makefile.features diff --git a/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.include b/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.include new file mode 100644 index 0000000000..b4f1ce6b40 --- /dev/null +++ b/tests/periph_qdec/boards_modded/nrf52840dk/Makefile.include @@ -0,0 +1 @@ +include $(RIOTBOARD)/nrf52840dk/Makefile.include diff --git a/tests/periph_qdec/boards_modded/nrf52840dk/include/board.h b/tests/periph_qdec/boards_modded/nrf52840dk/include/board.h new file mode 120000 index 0000000000..680fbc3dd5 --- /dev/null +++ b/tests/periph_qdec/boards_modded/nrf52840dk/include/board.h @@ -0,0 +1 @@ +../../../../../boards/nrf52840dk/include/board.h \ No newline at end of file diff --git a/tests/periph_qdec/boards_modded/nrf52840dk/include/periph_conf.h b/tests/periph_qdec/boards_modded/nrf52840dk/include/periph_conf.h new file mode 100644 index 0000000000..9358b30f93 --- /dev/null +++ b/tests/periph_qdec/boards_modded/nrf52840dk/include/periph_conf.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup boards_nrf52840dk_modded + * @{ + * + * @file + * @brief Minimal peripheral set for the nRF52840 DK with quadrature + * decoder enabled + * + * @author Koen Zandberg + * + */ + +#ifndef PERIPH_CONF_H +#define PERIPH_CONF_H + +#include "kernel_defines.h" +#include "periph_conf_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name QDEC configuration + */ +static const qdec_conf_t qdec_config[] = { + { + .a_pin = GPIO_PIN(0, 11), /* Button 1 */ + .b_pin = GPIO_PIN(0, 12), /* Button 2 */ + .led_pin = GPIO_PIN(0, 13), /* And the first LED */ + .sample_period = QDEC_SAMPLEPER_SAMPLEPER_128us, + .debounce_filter = true, + }, +}; +#define QDEC_NUMOF ARRAY_SIZE(qdec_config) +/** @} **/ + +/** + * @name UART configuration + * @{ + */ +static const uart_conf_t uart_config[] = { + { /* Mapped to USB virtual COM port */ + .dev = NRF_UARTE0, + .rx_pin = GPIO_PIN(0,8), + .tx_pin = GPIO_PIN(0,6), +#ifdef MODULE_PERIPH_UART_HW_FC + .rts_pin = GPIO_UNDEF, + .cts_pin = GPIO_UNDEF, +#endif + .irqn = UARTE0_UART0_IRQn, + }, +}; + +#define UART_0_ISR (isr_uart0) + +#define UART_NUMOF ARRAY_SIZE(uart_config) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CONF_H */ +/** @} */