From 52107b2ccbf1b5ed29123d77d5cd3bc982fdee2e Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Sun, 10 Jul 2016 21:46:46 +0200 Subject: moved QEI to LLD --- os/hal/ports/NRF5/LLD/hal_pal_lld.h | 4 +- os/hal/ports/NRF5/LLD/hal_qei_lld.c | 284 ++++++++++++++++++++++ os/hal/ports/NRF5/LLD/hal_qei_lld.h | 390 +++++++++++++++++++++++++++++++ os/hal/ports/NRF5/NRF51822/hal_qei_lld.c | 272 --------------------- os/hal/ports/NRF5/NRF51822/hal_qei_lld.h | 390 ------------------------------- os/hal/ports/NRF5/NRF51822/platform.mk | 4 +- os/hal/ports/NRF5/NRF52832/platform.mk | 6 +- os/hal/ports/NRF5/NRF52832/todo.txt | 1 + 8 files changed, 683 insertions(+), 668 deletions(-) create mode 100644 os/hal/ports/NRF5/LLD/hal_qei_lld.c create mode 100644 os/hal/ports/NRF5/LLD/hal_qei_lld.h delete mode 100644 os/hal/ports/NRF5/NRF51822/hal_qei_lld.c delete mode 100644 os/hal/ports/NRF5/NRF51822/hal_qei_lld.h (limited to 'os/hal') diff --git a/os/hal/ports/NRF5/LLD/hal_pal_lld.h b/os/hal/ports/NRF5/LLD/hal_pal_lld.h index 34caa7e..745afd3 100644 --- a/os/hal/ports/NRF5/LLD/hal_pal_lld.h +++ b/os/hal/ports/NRF5/LLD/hal_pal_lld.h @@ -130,10 +130,8 @@ typedef NRF_GPIO_Type *ioportid_t; */ #if NRF_SERIES == 51 #define IOPORT1 NRF_GPIO -#elif NRF_SERIES == 52 -#define IOPORT1 NRF_P0 #else -#error "Unknown NRF_SERIES" +#define IOPORT1 NRF_P0 #endif /*===========================================================================*/ diff --git a/os/hal/ports/NRF5/LLD/hal_qei_lld.c b/os/hal/ports/NRF5/LLD/hal_qei_lld.c new file mode 100644 index 0000000..9044897 --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_qei_lld.c @@ -0,0 +1,284 @@ +/* + ChibiOS - Copyright (C) 2016..2016 Stéphane D'Alu + + Licensed 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. +*/ + +/** + * @file NRF51/hal_qei_lld.c + * @brief NRF51 QEI subsystem low level driver. + * + * @addtogroup QEI + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) + + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief QEID1 driver identifier. + */ +#if NRF5_QEI_USE_QDEC0 || defined(__DOXYGEN__) +QEIDriver QEID1; +#endif + + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Common IRQ handler. + * + * @param[in] qeip pointer to an QEIDriver + */ +static void serve_interrupt(QEIDriver *qeip) { + NRF_QDEC_Type *qdec = qeip->qdec; + +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + /* Accumulator overflowed + */ + if (qdec->EVENTS_ACCOF) { + qdec->EVENTS_ACCOF = 0; + + qeip->overflowed++; + if (qeip->config->overflowed_cb) + qeip->config->overflowed_cb(qeip); + } +#endif + + /* Report ready + */ + if (qdec->EVENTS_REPORTRDY) { + qdec->EVENTS_REPORTRDY = 0; + + /* Read (and clear counters due to shortcut) */ + int16_t acc = ( int16_t)qdec->ACCREAD; + uint16_t accdbl = (uint16_t)qdec->ACCDBLREAD; + + /* Inverse direction if requested */ + if (qeip->config->dirinv) + acc = -acc; // acc is [-1024..+1023], its okay on int16_t + + /* Adjust counter */ + qeiAdjustI(qeip, acc); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if NRF5_QEI_USE_QDEC0 == TRUE +/** + * @brief Quadrature decoder vector (QDEC) + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector88) { + + OSAL_IRQ_PROLOGUE(); + serve_interrupt(&QEID1); + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level QEI driver initialization. + * + * @notapi + */ +void qei_lld_init(void) { + +#if NRF5_QEI_USE_QDEC0 == TRUE + /* Driver initialization.*/ + qeiObjectInit(&QEID1); + QEID1.qdec = NRF_QDEC; +#endif +} + +/** + * @brief Configures and activates the QEI peripheral. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_start(QEIDriver *qeip) { + NRF_QDEC_Type *qdec = qeip->qdec; + const QEIConfig *cfg = qeip->config; + + if (qeip->state == QEI_STOP) { + /* Set Pins */ + palSetLineMode(cfg->phase_a, PAL_MODE_INPUT); + palSetLineMode(cfg->phase_b, PAL_MODE_INPUT); +#if NRF5_QEI_USE_LED == TRUE + if (cfg->led != PAL_NOLINE) { + palSetLineMode(cfg->led, PAL_MODE_INPUT); + } +#endif + + /* Set interrupt masks and enable interrupt */ +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk | + QDEC_INTENSET_ACCOF_Msk; +#else + qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk; +#endif +#if NRF5_QEI_USE_QDEC0 == TRUE + if (&QEID1 == qeip) { + nvicEnableVector(QDEC_IRQn, NRF5_QEI_QDEC0_IRQ_PRIORITY); + } +#endif + + /* Select pin for Phase A and Phase B */ +#if NRF_SERIES == 51 + qdec->PSELA = PAL_PAD(cfg->phase_a); + qdec->PSELB = PAL_PAD(cfg->phase_b); +#else + qdec->PSEL.A = PAL_PAD(cfg->phase_a); + qdec->PSEL.B = PAL_PAD(cfg->phase_b); +#endif + /* Select (optional) pin for LED, and configure it */ +#if NRF5_QEI_USE_LED == TRUE +#if NRF_SERIES == 51 + qdec->PSELLED = PAL_PAD(cfg->led); +#else + qdec->PSEL.LED = PAL_PAD(cfg->led); +#endif + qdec->LEDPOL = ((cfg->led_polarity == QEI_LED_POLARITY_LOW) + ? QDEC_LEDPOL_LEDPOL_ActiveLow + : QDEC_LEDPOL_LEDPOL_ActiveHigh) + << QDEC_LEDPOL_LEDPOL_Pos; + qdec->LEDPRE = cfg->led_warming; +#else +#if NRF_SERIES == 51 + qdec->PSELLED = (uint32_t)-1; +#else + qdec->PSEL.LED = (uint32_t)-1; +#endif +#endif + + /* Set sampling resolution and debouncing */ + qdec->SAMPLEPER = cfg->resolution; + qdec->DBFEN = (cfg->debouncing ? QDEC_DBFEN_DBFEN_Enabled + : QDEC_DBFEN_DBFEN_Disabled) + << QDEC_DBFEN_DBFEN_Pos; + + /* Define minimum sampling before reporting + and create shortcut to clear accumulation */ + qdec->REPORTPER = cfg->report; + qdec->SHORTS = QDEC_SHORTS_REPORTRDY_READCLRACC_Msk; + + /* Enable peripheric */ + qdec->ENABLE = 1; + } + + /* Initially state is stopped, events cleared */ + qdec->TASKS_STOP = 1; + qdec->EVENTS_SAMPLERDY = 0; + qdec->EVENTS_REPORTRDY = 0; + qdec->EVENTS_ACCOF = 0; +} + +/** + * @brief Deactivates the QEI peripheral. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_stop(QEIDriver *qeip) { + + NRF_QDEC_Type *qdec = qeip->qdec; + const QEIConfig *cfg = qeip->config; + + if (qeip->state == QEI_READY) { + qdec->TASKS_STOP = 1; + qdec->ENABLE = 0; + + /* Unset interrupt masks and disable interrupt */ +#if NRF5_QEI_USE_QDEC0 == TRUE + if (&QEID1 == qeip) { + nvicDisableVector(QDEC_IRQn); + } +#endif +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + qdec->INTENCLR = QDEC_INTENCLR_REPORTRDY_Msk | + QDEC_INTENCLR_ACCOF_Msk; +#else + qdec->INTENCLR = QDEC_INTENCLR_REPORTRDY_Msk; +#endif + + /* Return pins to reset state */ + palSetLineMode(cfg->phase_a, PAL_MODE_RESET); + palSetLineMode(cfg->phase_b, PAL_MODE_RESET); +#if NRF5_QEI_USE_LED == TRUE + if (cfg->led != PAL_NOLINE) { + palSetLineMode(cfg->led, PAL_MODE_RESET); + } +#endif + } +} + +/** + * @brief Enables the input capture. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_enable(QEIDriver *qeip) { +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + qeip->overflowed = 0; +#endif + + qeip->qdec->EVENTS_SAMPLERDY = 0; + qeip->qdec->EVENTS_REPORTRDY = 0; + qeip->qdec->EVENTS_ACCOF = 0; + qeip->qdec->TASKS_START = 1; +} + +/** + * @brief Disables the input capture. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_disable(QEIDriver *qeip) { + qeip->qdec->TASKS_STOP = 1; +} + + +#endif /* HAL_USE_QEI */ + +/** @} */ diff --git a/os/hal/ports/NRF5/LLD/hal_qei_lld.h b/os/hal/ports/NRF5/LLD/hal_qei_lld.h new file mode 100644 index 0000000..6328bab --- /dev/null +++ b/os/hal/ports/NRF5/LLD/hal_qei_lld.h @@ -0,0 +1,390 @@ +/* + ChibiOS - Copyright (C) 2016..2016 Stéphane D'Alu + + Licensed 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. +*/ + +/** + * @file NRF51/hal_qei_lld.h + * @brief NRF51 QEI subsystem low level driver header. + * + * @note Not tested with LED pin + * + * @note Pins are configured as input with no pull. + * + * @addtogroup QEI + * @{ + */ + +#ifndef HAL_QEI_LLD_H +#define HAL_QEI_LLD_H + +#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief For LED active on LOW + */ +#define QEI_LED_POLARITY_LOW 0 + +/** + * @brief For LED active on HIGH + */ +#define QEI_LED_POLARITY_HIGH 1 + +/** + * @brief Mininum usable value for defining counter underflow + */ +#define QEI_COUNT_MIN (-2147483648) + +/** + * @brief Maximum usable value for defining counter overflow + */ +#define QEI_COUNT_MAX ( 2147483647) + + + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief LED control enable switch. + * @details If set to @p TRUE the support for LED control + * is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_QEI_USE_LED) || defined(__DOXYGEN__) +#define NRF5_QEI_USE_LED FALSE +#endif + +/** + * @brief Accumulator overflow notification enable switch. + * @details If set to @p TRUE the support for accumulator overflow + * is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_QEI_USE_ACC_OVERFLOWED_CB) || defined(__DOXYGEN__) +#define NRF5_QEI_USE_ACC_OVERFLOWED_CB FALSE +#endif + +/** + * @brief QEID1 driver enable switch. + * @details If set to @p TRUE the support for QEID1 is included. + * @note The default is @p FALSE. + */ +#if !defined(NRF5_QEI_USE_QDEC0) || defined(__DOXYGEN__) +#define NRF5_QEI_USE_QDEC0 FALSE +#endif + +/** + * @brief QEID interrupt priority level setting for QDEC0. + */ +#if !defined(NRF5_QEI_QDEC0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF5_QEI_QDEC0_IRQ_PRIORITY 2 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if NRF5_QEI_USE_QDEC0 == FALSE +#error "Requesting QEI driver, but no QDEC peripheric attached" +#endif + +#if NRF5_QEI_USE_QDEC0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_QEI_QDEC0_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to QDEC0" +#endif + + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief QEI count mode. + */ +typedef enum { + QEI_MODE_QUADRATURE = 0, /**< Quadrature encoder mode. */ +} qeimode_t; + +/** + * @brief QEI resolution. + */ +typedef enum { + QEI_RESOLUTION_128us = 0x00UL, /**< 128us sample period. */ + QEI_RESOLUTION_256us = 0x01UL, /**< 256us sample period. */ + QEI_RESOLUTION_512us = 0x02UL, /**< 512us sample period. */ + QEI_RESOLUTION_1024us = 0x03UL, /**< 1024us sample period. */ + QEI_RESOLUTION_2048us = 0x04UL, /**< 2048us sample period. */ + QEI_RESOLUTION_4096us = 0x05UL, /**< 4096us sample period. */ + QEI_RESOLUTION_8192us = 0x06UL, /**< 8192us sample period. */ + QEI_RESOLUTION_16384us = 0x07UL, /**< 16384us sample period. */ +} qeiresolution_t; + +/** + * @brief Clusters of samples. + */ +typedef enum { + QEI_REPORT_10 = 0x00UL, /**< 10 samples per report. */ + QEI_REPORT_40 = 0x01UL, /**< 40 samples per report. */ + QEI_REPORT_80 = 0x02UL, /**< 80 samples per report. */ + QEI_REPORT_120 = 0x03UL, /**< 120 samples per report. */ + QEI_REPORT_160 = 0x04UL, /**< 160 samples per report. */ + QEI_REPORT_200 = 0x05UL, /**< 200 samples per report. */ + QEI_REPORT_240 = 0x06UL, /**< 240 samples per report. */ + QEI_REPORT_280 = 0x07UL, /**< 280 samples per report. */ +} qeireport_t; + +/** + * @brief QEI direction inversion. + */ +typedef enum { + QEI_DIRINV_FALSE = 0, /**< Do not invert counter direction. */ + QEI_DIRINV_TRUE = 1, /**< Invert counter direction. */ +} qeidirinv_t; + +/** + * @brief QEI counter type. + */ +typedef int32_t qeicnt_t; + +/** + * @brief QEI delta type. + */ +typedef int16_t qeidelta_t; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Count mode. + */ + qeimode_t mode; + /** + * @brief Resolution. + */ + qeiresolution_t resolution; + /** + * @brief Direction inversion. + */ + qeidirinv_t dirinv; + /** + * @brief Handling of counter overflow/underflow + * + * @details When overflow occurs, the counter value is updated + * according to: + * - QEI_OVERFLOW_DISCARD: + * discard the update value, counter doesn't change + * - QEI_OVERFLOW_MINMAX + * counter will be updated to reach min or max + * - QEI_OVERFLOW_WRAP: + * counter value will wrap around + */ + qeioverflow_t overflow; + /** + * @brief Min count value. + * + * @note If min == max, then QEI_COUNT_MIN is used. + */ + qeicnt_t min; + /** + * @brief Max count value. + * + * @note If min == max, then QEI_COUNT_MAX is used. + */ + qeicnt_t max; + /** + * @brief Notify of value change + * + * @note Called from ISR context. + */ + qeicallback_t notify_cb; + /** + * @brief Notify of overflow + * + * @note Overflow notification is performed after + * value changed notification. + * @note Called from ISR context. + */ + void (*overflow_cb)(QEIDriver *qeip, qeidelta_t delta); + /* End of the mandatory fields.*/ + /** + * @brief Line for reading Phase A + */ + ioline_t phase_a; + /** + * @brief Line for reading Phase B + */ + ioline_t phase_b; +#if (NRF5_QEI_USE_LED == TRUE) || defined(__DOXYGEN__) + /** + * @brief Line used to control LED + * + * @note If LED is not controlled by MCU, you need to use the + * PAL_NOLINE value. + */ + ioline_t led; + /** + * @brief Period in µs the LED is switched on prior to sampling. + * + * @details LED warming is expressed in micro-seconds and value + * is [0..511] + * + * @note 31µs is the recommanded default. + * + * @note If debouncing is activated, LED is always on for the + * whole sampling period (aka: resolution) + */ + uint16_t led_warming; + /** + * @brief LED polarity to used (when LED is controlled by MCU) + */ + uint8_t led_polarity; +#endif + /** + * @brief Activate debouncing filter + * + * @note If LED is controlled by MCU, the led_warming is ignored and, + * LED is always on for the whole sampling period (aka: resolution) + */ + bool debouncing; + /** + * @brief Number of samples per report + * + * @details Default to QEI_REPORT_10 + */ + qeireport_t report; +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + /** + * @brief Notify of internal accumulator overflowed + * (ie: MCU discarding samples) + * + * @note Called from ISR context. + */ + qeicallback_t overflowed_cb; +#endif +} QEIConfig; + +/** + * @brief Structure representing an QEI driver. + */ +struct QEIDriver { + /** + * @brief Driver state. + */ + qeistate_t state; + /** + * @brief Last count value. + */ + qeicnt_t last; + /** + * @brief Current configuration data. + */ + const QEIConfig *config; +#if defined(QEI_DRIVER_EXT_FIELDS) + QEI_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Counter + */ + qeicnt_t count; +#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE + /** + * @brief Number of time the MCU discarded updates due to + * accumulator overflow + */ + uint32_t overflowed; +#endif + /** + * @brief Pointer to the QDECx registers block. + */ + NRF_QDEC_Type *qdec; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the counter value. + * + * @param[in] qeip pointer to the @p QEIDriver object + * @return The current counter value. + * + * @notapi + */ +#define qei_lld_get_count(qeip) ((qeip)->count) + + +/** + * @brief Set the counter value. + * + * @param[in] qeip pointer to the @p QEIDriver object + * @param[in] value counter value + * + * @notapi + */ +#define qei_lld_set_count(qeip, value) \ + if ((qeip)->count != ((qeicnt_t)value)) { \ + (qeip)->count = value; \ + if ((qeip)->config->notify_cb) \ + (qeip)->config->notify_cb(qeip); \ + } while(0) + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if NRF5_QEI_USE_QDEC0 && !defined(__DOXYGEN__) +extern QEIDriver QEID1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void qei_lld_init(void); + void qei_lld_start(QEIDriver *qeip); + void qei_lld_stop(QEIDriver *qeip); + void qei_lld_enable(QEIDriver *qeip); + void qei_lld_disable(QEIDriver *qeip); + qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta); +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* To be moved in hal_qei */ +/*===========================================================================*/ + +void qeiSetCount(QEIDriver *qeip, qeicnt_t value); +qeidelta_t qeiAdjust(QEIDriver *qeip, qeidelta_t delta); + +#endif /* HAL_USE_QEI */ + +#endif /* HAL_QEI_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/NRF5/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF5/NRF51822/hal_qei_lld.c deleted file mode 100644 index 9397d5a..0000000 --- a/os/hal/ports/NRF5/NRF51822/hal_qei_lld.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - ChibiOS - Copyright (C) 2016..2016 Stéphane D'Alu - - Licensed 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. -*/ - -/** - * @file NRF51/hal_qei_lld.c - * @brief NRF51 QEI subsystem low level driver. - * - * @addtogroup QEI - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) - - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief QEID1 driver identifier. - */ -#if NRF5_QEI_USE_QDEC0 || defined(__DOXYGEN__) -QEIDriver QEID1; -#endif - - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/** - * @brief Common IRQ handler. - * - * @param[in] qeip pointer to an QEIDriver - */ -static void serve_interrupt(QEIDriver *qeip) { - NRF_QDEC_Type *qdec = qeip->qdec; - -#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE - /* Accumulator overflowed - */ - if (qdec->EVENTS_ACCOF) { - qdec->EVENTS_ACCOF = 0; - - qeip->overflowed++; - if (qeip->config->overflowed_cb) - qeip->config->overflowed_cb(qeip); - } -#endif - - /* Report ready - */ - if (qdec->EVENTS_REPORTRDY) { - qdec->EVENTS_REPORTRDY = 0; - - /* Read (and clear counters due to shortcut) */ - int16_t acc = ( int16_t)qdec->ACCREAD; - uint16_t accdbl = (uint16_t)qdec->ACCDBLREAD; - - /* Inverse direction if requested */ - if (qeip->config->dirinv) - acc = -acc; // acc is [-1024..+1023], its okay on int16_t - - /* Adjust counter */ - qeiAdjustI(qeip, acc); - } -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -#if NRF5_QEI_USE_QDEC0 == TRUE -/** - * @brief Quadrature decoder vector (QDEC) - * - * @isr - */ -OSAL_IRQ_HANDLER(Vector88) { - - OSAL_IRQ_PROLOGUE(); - serve_interrupt(&QEID1); - OSAL_IRQ_EPILOGUE(); -} -#endif - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level QEI driver initialization. - * - * @notapi - */ -void qei_lld_init(void) { - -#if NRF5_QEI_USE_QDEC0 == TRUE - /* Driver initialization.*/ - qeiObjectInit(&QEID1); - QEID1.qdec = NRF_QDEC; -#endif -} - -/** - * @brief Configures and activates the QEI peripheral. - * - * @param[in] qeip pointer to the @p QEIDriver object - * - * @notapi - */ -void qei_lld_start(QEIDriver *qeip) { - NRF_QDEC_Type *qdec = qeip->qdec; - const QEIConfig *cfg = qeip->config; - - if (qeip->state == QEI_STOP) { - /* Set Pins */ - palSetLineMode(cfg->phase_a, PAL_MODE_INPUT); - palSetLineMode(cfg->phase_b, PAL_MODE_INPUT); -#if NRF5_QEI_USE_LED == TRUE - if (cfg->led != PAL_NOLINE) { - palSetLineMode(cfg->led, PAL_MODE_INPUT); - } -#endif - - /* Set interrupt masks and enable interrupt */ -#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE - qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk | - QDEC_INTENSET_ACCOF_Msk; -#else - qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk; -#endif -#if NRF5_QEI_USE_QDEC0 == TRUE - if (&QEID1 == qeip) { - nvicEnableVector(QDEC_IRQn, NRF5_QEI_QDEC0_IRQ_PRIORITY); - } -#endif - - /* Select pin for Phase A and Phase B */ - qdec->PSELA = PAL_PAD(cfg->phase_a); - qdec->PSELB = PAL_PAD(cfg->phase_b); - - /* Select (optional) pin for LED, and configure it */ -#if NRF5_QEI_USE_LED == TRUE - qdec->PSELLED = PAL_PAD(cfg->led); - qdec->LEDPOL = ((cfg->led_polarity == QEI_LED_POLARITY_LOW) - ? QDEC_LEDPOL_LEDPOL_ActiveLow - : QDEC_LEDPOL_LEDPOL_ActiveHigh) - << QDEC_LEDPOL_LEDPOL_Pos; - qdec->LEDPRE = cfg->led_warming; -#else - qdec->PSELLED = (uint32_t)-1; -#endif - - /* Set sampling resolution and debouncing */ - qdec->SAMPLEPER = cfg->resolution; - qdec->DBFEN = (cfg->debouncing ? QDEC_DBFEN_DBFEN_Enabled - : QDEC_DBFEN_DBFEN_Disabled) - << QDEC_DBFEN_DBFEN_Pos; - - /* Define minimum sampling before reporting - and create shortcut to clear accumulation */ - qdec->REPORTPER = cfg->report; - qdec->SHORTS = QDEC_SHORTS_REPORTRDY_READCLRACC_Msk; - - /* Enable peripheric */ - qdec->ENABLE = 1; - } - - /* Initially state is stopped, events cleared */ - qdec->TASKS_STOP = 1; - qdec->EVENTS_SAMPLERDY = 0; - qdec->EVENTS_REPORTRDY = 0; - qdec->EVENTS_ACCOF = 0; -} - -/** - * @brief Deactivates the QEI peripheral. - * - * @param[in] qeip pointer to the @p QEIDriver object - * - * @notapi - */ -void qei_lld_stop(QEIDriver *qeip) { - - NRF_QDEC_Type *qdec = qeip->qdec; - const QEIConfig *cfg = qeip->config; - - if (qeip->state == QEI_READY) { - qdec->TASKS_STOP = 1; - qdec->ENABLE = 0; - - /* Unset interrupt masks and disable interrupt */ -#if NRF5_QEI_USE_QDEC0 == TRUE - if (&QEID1 == qeip) { - nvicDisableVector(QDEC_IRQn); - } -#endif -#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE - qdec->INTENCLR = QDEC_INTENCLR_REPORTRDY_Msk | - QDEC_INTENCLR_ACCOF_Msk; -#else - qdec->INTENCLR = QDEC_INTENCLR_REPORTRDY_Msk; -#endif - - /* Return pins to reset state */ - palSetLineMode(cfg->phase_a, PAL_MODE_RESET); - palSetLineMode(cfg->phase_b, PAL_MODE_RESET); -#if NRF5_QEI_USE_LED == TRUE - if (cfg->led != PAL_NOLINE) { - palSetLineMode(cfg->led, PAL_MODE_RESET); - } -#endif - } -} - -/** - * @brief Enables the input capture. - * - * @param[in] qeip pointer to the @p QEIDriver object - * - * @notapi - */ -void qei_lld_enable(QEIDriver *qeip) { -#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE - qeip->overflowed = 0; -#endif - - qeip->qdec->EVENTS_SAMPLERDY = 0; - qeip->qdec->EVENTS_REPORTRDY = 0; - qeip->qdec->EVENTS_ACCOF = 0; - qeip->qdec->TASKS_START = 1; -} - -/** - * @brief Disables the input capture. - * - * @param[in] qeip pointer to the @p QEIDriver object - * - * @notapi - */ -void qei_lld_disable(QEIDriver *qeip) { - qeip->qdec->TASKS_STOP = 1; -} - - -#endif /* HAL_USE_QEI */ - -/** @} */ diff --git a/os/hal/ports/NRF5/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF5/NRF51822/hal_qei_lld.h deleted file mode 100644 index 6328bab..0000000 --- a/os/hal/ports/NRF5/NRF51822/hal_qei_lld.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - ChibiOS - Copyright (C) 2016..2016 Stéphane D'Alu - - Licensed 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. -*/ - -/** - * @file NRF51/hal_qei_lld.h - * @brief NRF51 QEI subsystem low level driver header. - * - * @note Not tested with LED pin - * - * @note Pins are configured as input with no pull. - * - * @addtogroup QEI - * @{ - */ - -#ifndef HAL_QEI_LLD_H -#define HAL_QEI_LLD_H - -#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/** - * @brief For LED active on LOW - */ -#define QEI_LED_POLARITY_LOW 0 - -/** - * @brief For LED active on HIGH - */ -#define QEI_LED_POLARITY_HIGH 1 - -/** - * @brief Mininum usable value for defining counter underflow - */ -#define QEI_COUNT_MIN (-2147483648) - -/** - * @brief Maximum usable value for defining counter overflow - */ -#define QEI_COUNT_MAX ( 2147483647) - - - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief LED control enable switch. - * @details If set to @p TRUE the support for LED control - * is included. - * @note The default is @p FALSE. - */ -#if !defined(NRF5_QEI_USE_LED) || defined(__DOXYGEN__) -#define NRF5_QEI_USE_LED FALSE -#endif - -/** - * @brief Accumulator overflow notification enable switch. - * @details If set to @p TRUE the support for accumulator overflow - * is included. - * @note The default is @p FALSE. - */ -#if !defined(NRF5_QEI_USE_ACC_OVERFLOWED_CB) || defined(__DOXYGEN__) -#define NRF5_QEI_USE_ACC_OVERFLOWED_CB FALSE -#endif - -/** - * @brief QEID1 driver enable switch. - * @details If set to @p TRUE the support for QEID1 is included. - * @note The default is @p FALSE. - */ -#if !defined(NRF5_QEI_USE_QDEC0) || defined(__DOXYGEN__) -#define NRF5_QEI_USE_QDEC0 FALSE -#endif - -/** - * @brief QEID interrupt priority level setting for QDEC0. - */ -#if !defined(NRF5_QEI_QDEC0_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define NRF5_QEI_QDEC0_IRQ_PRIORITY 2 -#endif -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if NRF5_QEI_USE_QDEC0 == FALSE -#error "Requesting QEI driver, but no QDEC peripheric attached" -#endif - -#if NRF5_QEI_USE_QDEC0 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(NRF5_QEI_QDEC0_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to QDEC0" -#endif - - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief QEI count mode. - */ -typedef enum { - QEI_MODE_QUADRATURE = 0, /**< Quadrature encoder mode. */ -} qeimode_t; - -/** - * @brief QEI resolution. - */ -typedef enum { - QEI_RESOLUTION_128us = 0x00UL, /**< 128us sample period. */ - QEI_RESOLUTION_256us = 0x01UL, /**< 256us sample period. */ - QEI_RESOLUTION_512us = 0x02UL, /**< 512us sample period. */ - QEI_RESOLUTION_1024us = 0x03UL, /**< 1024us sample period. */ - QEI_RESOLUTION_2048us = 0x04UL, /**< 2048us sample period. */ - QEI_RESOLUTION_4096us = 0x05UL, /**< 4096us sample period. */ - QEI_RESOLUTION_8192us = 0x06UL, /**< 8192us sample period. */ - QEI_RESOLUTION_16384us = 0x07UL, /**< 16384us sample period. */ -} qeiresolution_t; - -/** - * @brief Clusters of samples. - */ -typedef enum { - QEI_REPORT_10 = 0x00UL, /**< 10 samples per report. */ - QEI_REPORT_40 = 0x01UL, /**< 40 samples per report. */ - QEI_REPORT_80 = 0x02UL, /**< 80 samples per report. */ - QEI_REPORT_120 = 0x03UL, /**< 120 samples per report. */ - QEI_REPORT_160 = 0x04UL, /**< 160 samples per report. */ - QEI_REPORT_200 = 0x05UL, /**< 200 samples per report. */ - QEI_REPORT_240 = 0x06UL, /**< 240 samples per report. */ - QEI_REPORT_280 = 0x07UL, /**< 280 samples per report. */ -} qeireport_t; - -/** - * @brief QEI direction inversion. - */ -typedef enum { - QEI_DIRINV_FALSE = 0, /**< Do not invert counter direction. */ - QEI_DIRINV_TRUE = 1, /**< Invert counter direction. */ -} qeidirinv_t; - -/** - * @brief QEI counter type. - */ -typedef int32_t qeicnt_t; - -/** - * @brief QEI delta type. - */ -typedef int16_t qeidelta_t; - -/** - * @brief Driver configuration structure. - * @note It could be empty on some architectures. - */ -typedef struct { - /** - * @brief Count mode. - */ - qeimode_t mode; - /** - * @brief Resolution. - */ - qeiresolution_t resolution; - /** - * @brief Direction inversion. - */ - qeidirinv_t dirinv; - /** - * @brief Handling of counter overflow/underflow - * - * @details When overflow occurs, the counter value is updated - * according to: - * - QEI_OVERFLOW_DISCARD: - * discard the update value, counter doesn't change - * - QEI_OVERFLOW_MINMAX - * counter will be updated to reach min or max - * - QEI_OVERFLOW_WRAP: - * counter value will wrap around - */ - qeioverflow_t overflow; - /** - * @brief Min count value. - * - * @note If min == max, then QEI_COUNT_MIN is used. - */ - qeicnt_t min; - /** - * @brief Max count value. - * - * @note If min == max, then QEI_COUNT_MAX is used. - */ - qeicnt_t max; - /** - * @brief Notify of value change - * - * @note Called from ISR context. - */ - qeicallback_t notify_cb; - /** - * @brief Notify of overflow - * - * @note Overflow notification is performed after - * value changed notification. - * @note Called from ISR context. - */ - void (*overflow_cb)(QEIDriver *qeip, qeidelta_t delta); - /* End of the mandatory fields.*/ - /** - * @brief Line for reading Phase A - */ - ioline_t phase_a; - /** - * @brief Line for reading Phase B - */ - ioline_t phase_b; -#if (NRF5_QEI_USE_LED == TRUE) || defined(__DOXYGEN__) - /** - * @brief Line used to control LED - * - * @note If LED is not controlled by MCU, you need to use the - * PAL_NOLINE value. - */ - ioline_t led; - /** - * @brief Period in µs the LED is switched on prior to sampling. - * - * @details LED warming is expressed in micro-seconds and value - * is [0..511] - * - * @note 31µs is the recommanded default. - * - * @note If debouncing is activated, LED is always on for the - * whole sampling period (aka: resolution) - */ - uint16_t led_warming; - /** - * @brief LED polarity to used (when LED is controlled by MCU) - */ - uint8_t led_polarity; -#endif - /** - * @brief Activate debouncing filter - * - * @note If LED is controlled by MCU, the led_warming is ignored and, - * LED is always on for the whole sampling period (aka: resolution) - */ - bool debouncing; - /** - * @brief Number of samples per report - * - * @details Default to QEI_REPORT_10 - */ - qeireport_t report; -#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE - /** - * @brief Notify of internal accumulator overflowed - * (ie: MCU discarding samples) - * - * @note Called from ISR context. - */ - qeicallback_t overflowed_cb; -#endif -} QEIConfig; - -/** - * @brief Structure representing an QEI driver. - */ -struct QEIDriver { - /** - * @brief Driver state. - */ - qeistate_t state; - /** - * @brief Last count value. - */ - qeicnt_t last; - /** - * @brief Current configuration data. - */ - const QEIConfig *config; -#if defined(QEI_DRIVER_EXT_FIELDS) - QEI_DRIVER_EXT_FIELDS -#endif - /* End of the mandatory fields.*/ - /** - * @brief Counter - */ - qeicnt_t count; -#if NRF5_QEI_USE_ACC_OVERFLOWED_CB == TRUE - /** - * @brief Number of time the MCU discarded updates due to - * accumulator overflow - */ - uint32_t overflowed; -#endif - /** - * @brief Pointer to the QDECx registers block. - */ - NRF_QDEC_Type *qdec; -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/** - * @brief Returns the counter value. - * - * @param[in] qeip pointer to the @p QEIDriver object - * @return The current counter value. - * - * @notapi - */ -#define qei_lld_get_count(qeip) ((qeip)->count) - - -/** - * @brief Set the counter value. - * - * @param[in] qeip pointer to the @p QEIDriver object - * @param[in] value counter value - * - * @notapi - */ -#define qei_lld_set_count(qeip, value) \ - if ((qeip)->count != ((qeicnt_t)value)) { \ - (qeip)->count = value; \ - if ((qeip)->config->notify_cb) \ - (qeip)->config->notify_cb(qeip); \ - } while(0) - - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if NRF5_QEI_USE_QDEC0 && !defined(__DOXYGEN__) -extern QEIDriver QEID1; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void qei_lld_init(void); - void qei_lld_start(QEIDriver *qeip); - void qei_lld_stop(QEIDriver *qeip); - void qei_lld_enable(QEIDriver *qeip); - void qei_lld_disable(QEIDriver *qeip); - qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta); -#ifdef __cplusplus -} -#endif - -/*===========================================================================*/ -/* To be moved in hal_qei */ -/*===========================================================================*/ - -void qeiSetCount(QEIDriver *qeip, qeicnt_t value); -qeidelta_t qeiAdjust(QEIDriver *qeip, qeidelta_t delta); - -#endif /* HAL_USE_QEI */ - -#endif /* HAL_QEI_LLD_H */ - -/** @} */ diff --git a/os/hal/ports/NRF5/NRF51822/platform.mk b/os/hal/ports/NRF5/NRF51822/platform.mk index 8631487..a8526b7 100644 --- a/os/hal/ports/NRF5/NRF51822/platform.mk +++ b/os/hal/ports/NRF5/NRF51822/platform.mk @@ -38,7 +38,7 @@ ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),) PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/NRF51822/hal_pwm_lld.c endif ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),) -PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/NRF51822/hal_qei_lld.c +PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_qei_lld.c endif else PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \ @@ -55,7 +55,7 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_wdg_lld.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_rng_lld.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/NRF51822/hal_pwm_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/NRF51822/hal_qei_lld.c + ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_qei_lld.c endif # Required include directories diff --git a/os/hal/ports/NRF5/NRF52832/platform.mk b/os/hal/ports/NRF5/NRF52832/platform.mk index 57ae88d..7ce922f 100644 --- a/os/hal/ports/NRF5/NRF52832/platform.mk +++ b/os/hal/ports/NRF5/NRF52832/platform.mk @@ -21,6 +21,9 @@ endif ifneq ($(findstring HAL_USE_RNG TRUE,$(HALCONF)),) PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_rng_lld.c endif +ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),) +PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_qei_lld.c +endif else PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/NRF52832/hal_lld.c \ @@ -29,7 +32,8 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_st_lld.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_gpt_lld.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_wdg_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_rng_lld.c + ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_rng_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/hal_qei_lld.c endif # Required include directories diff --git a/os/hal/ports/NRF5/NRF52832/todo.txt b/os/hal/ports/NRF5/NRF52832/todo.txt index dc14b72..bc6423a 100644 --- a/os/hal/ports/NRF5/NRF52832/todo.txt +++ b/os/hal/ports/NRF5/NRF52832/todo.txt @@ -4,3 +4,4 @@ https://devzone.nordicsemi.com/question/86564/nrf52-write-buffer/ * implement pin-reset, swo trace, trace pin configuration * implement errata (see system_nrf52.c) +* check GPIO DETECTMODE and LATCH -- cgit v1.2.3