From b0712b0d99f50318e224df75b62311f4888a7ecf Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Mon, 27 Jun 2016 13:05:35 +0200 Subject: . --- os/hal/boards/NRF51-DK/board.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'os') diff --git a/os/hal/boards/NRF51-DK/board.h b/os/hal/boards/NRF51-DK/board.h index e47240b..67e1724 100644 --- a/os/hal/boards/NRF51-DK/board.h +++ b/os/hal/boards/NRF51-DK/board.h @@ -44,6 +44,16 @@ #define SPI_SS 24 #define I2C_SCL 7 #define I2C_SDA 30 +#define AIN0 26 +#define AIN1 27 +#define AIN2 1 +#define AIN3 2 +#define AIN4 3 +#define AIN5 4 +#define AIN6 5 +#define AIN7 6 +#define AREF0 0 +#define AREF1 6 /* * IO pins assignments. @@ -72,6 +82,16 @@ #define IOPORT1_A3 4U #define IOPORT1_A4 5U #define IOPORT1_A5 6U +#define IOPORT1_AIN0 26U +#define IOPORT1_AIN1 27U +#define IOPORT1_AIN2 1U +#define IOPORT1_AIN3 2U +#define IOPORT1_AIN4 3U +#define IOPORT1_AIN5 4U +#define IOPORT1_AIN6 5U +#define IOPORT1_AIN7 6U +#define IOPORT1_AREF0 0U +#define IOPORT1_AREF1 6U /* * IO lines assignments. @@ -100,6 +120,16 @@ #define LINE_A3 PAL_LINE(IOPORT1, IOPORT1_A3) #define LINE_A4 PAL_LINE(IOPORT1, IOPORT1_A4) #define LINE_A5 PAL_LINE(IOPORT1, IOPORT1_A5) +#define LINE_AIN0 PAL_LINE(IOPORT1, IOPORT1_AIN0) +#define LINE_AIN1 PAL_LINE(IOPORT1, IOPORT1_AIN1) +#define LINE_AIN2 PAL_LINE(IOPORT1, IOPORT1_AIN2) +#define LINE_AIN3 PAL_LINE(IOPORT1, IOPORT1_AIN3) +#define LINE_AIN4 PAL_LINE(IOPORT1, IOPORT1_AIN4) +#define LINE_AIN5 PAL_LINE(IOPORT1, IOPORT1_AIN5) +#define LINE_AIN6 PAL_LINE(IOPORT1, IOPORT1_AIN6) +#define LINE_AIN7 PAL_LINE(IOPORT1, IOPORT1_AIN7) +#define LINE_AREF0 PAL_LINE(IOPORT1, IOPORT1_AREF0) +#define LINE_AREF1 PAL_LINE(IOPORT1, IOPORT1_AREF1) #if !defined(_FROM_ASM_) -- cgit v1.2.3 From 3cdd1360d4e71edabad003f7652a0abc0b1aaad1 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Tue, 28 Jun 2016 21:53:12 +0200 Subject: QEI driver for NRF51 --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 303 +++++++++++++++++++++++++++ os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 334 ++++++++++++++++++++++++++++++ os/hal/ports/NRF51/NRF51822/platform.mk | 6 +- 3 files changed, 642 insertions(+), 1 deletion(-) create mode 100644 os/hal/ports/NRF51/NRF51822/hal_qei_lld.c create mode 100644 os/hal/ports/NRF51/NRF51822/hal_qei_lld.h (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c new file mode 100644 index 0000000..0f8043d --- /dev/null +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -0,0 +1,303 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Martino Migliavacca + + 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 TIMv1/hal_qei_lld.c + * @brief STM32 QEI subsystem low level driver header. + * + * @addtogroup QEI + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) + + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief QEID1 driver identifier. + */ +#if NRF51_QEI_USE_QDEC1 || defined(__DOXYGEN__) +QEIDriver QEID1; +#endif + + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if NRF51_QEI_USE_QDEC1 == TRUE +/** + * @brief Quadrature decoder vector (QDEC) + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector88) { + QEIDriver *qeip = &QEID1; + NRF_QDEC_Type *qdec = qeip->qdec; + + OSAL_IRQ_PROLOGUE(); + + + osalSysLockFromISR(); + + if (qdec->EVENTS_ACCOF) { + qdec->EVENTS_ACCOF = 0; + qeip->overflowed++; + if (qeip->config->overflowed_cb) + qeip->config->overflowed_cb(qeip); + } + + 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 + + // Get boundaries + qeicnt_t min = QEI_COUNT_MIN; + qeicnt_t max = QEI_COUNT_MAX; + if (qeip->config->min != qeip->config->max) { + min = qeip->config->min; + max = qeip->config->max; + } + + // Compute new value + qeidelta_t delta = 0; + qeicnt_t count = qeip->count + acc; + bool overflowed = false; + + // See: https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow + + // Overflow + if ((acc > 0) && (qeip->count > (max - acc))) { + overflowed = true; + switch(qeip->config->overflow) { + case QEI_OVERFLOW_WRAP: + delta = 0; + count = (min + (qeip->count - (max - acc))) - 1; + break; + case QEI_OVERFLOW_DISCARD: + delta = acc; + count = qeip->count; + break; + case QEI_OVERFLOW_MINMAX: + delta = qeip->count - (max - acc); + count = max; + break; + } + + // Underflow + } else if ((acc < 0) && (qeip->count < (min - acc))) { + overflowed = true; + switch(qeip->config->overflow) { + case QEI_OVERFLOW_WRAP: + delta = 0; + count = (max + (qeip->count - (min - acc))) + 1; + break; + case QEI_OVERFLOW_DISCARD: + delta = acc; + count = qeip->count; + break; + case QEI_OVERFLOW_MINMAX: + delta = qeip->count - (min - acc); + count = min; + break; + } + } + + // Set value and notify + if (qeip->count != count) { + qeip->count = count; + if (qeip->config->notify_cb) + qeip->config->notify_cb(qeip); + } + + // Notify for overflow (passing the remaining delta) + if (overflowed && qeip->config->overflow_cb) + qeip->config->overflow_cb(qeip, delta); + } + + + osalSysUnlockFromISR(); + + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level QEI driver initialization. + * + * @notapi + */ +void qei_lld_init(void) { + +#if NRF51_QEI_USE_QDEC1 + /* 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 (cfg->led != PAL_NOLINE) { + palSetLineMode(cfg->led, PAL_MODE_INPUT); + } + + // Set interrupt masks and enable interrupt + qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk | + QDEC_INTENSET_ACCOF_Msk; +#if NRF51_QEI_USE_QDEC1 + if (&QEID1 == qeip) { + nvicEnableVector(QDEC_IRQn, NRF51_QEI_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 + qdec->PSELLED = (cfg->led == PAL_NOLINE) ? (uint32_t)-1 + : 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; + + // 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; +#if NRF51_QEI_USE_QDEC1 + if (&QEID1 == qeip) { + nvicDisableVector(QDEC_IRQn); + } +#endif + qdec->INTENCLR = QDEC_INTENSET_REPORTRDY_Msk | + QDEC_INTENSET_ACCOF_Msk; + } +} + +/** + * @brief Enables the input capture. + * + * @param[in] qeip pointer to the @p QEIDriver object + * + * @notapi + */ +void qei_lld_enable(QEIDriver *qeip) { + qeip->overflowed = 0; + + 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/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h new file mode 100644 index 0000000..f07a60a --- /dev/null +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -0,0 +1,334 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Martino Migliavacca + + 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 TIMv1/hal_qei_lld.h + * @brief STM32 QEI subsystem low level driver header. + * + * @addtogroup QEI + * @{ + */ + +#ifndef HAL_QEI_LLD_H +#define HAL_QEI_LLD_H + +#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) + + + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define QEI_LED_POLARITY_LOW 0 +#define QEI_LED_POLARITY_HIGH 1 + +#define QEI_COUNT_MIN 0 +#define QEI_COUNT_MAX 65535 + + + + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @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(NRF51_QEI_USE_QDEC1) || defined(__DOXYGEN__) +#define NRF51_QEI_USE_QDEC1 FALSE +#endif + +/** + * @brief QEID interrupt priority level setting. + */ +#if !defined(NRF51_QEI_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF51_QEI_IRQ_PRIORITY 2 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if NRF51_QEI_USE_QDEC1 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF51_QEI_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to QDEC1" +#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; + +/** + * + */ +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 Handling of counter overflow/underflow + */ +typedef enum { + QEI_OVERFLOW_WRAP = 0, /**< Counter value will wrap around. */ + QEI_OVERFLOW_DISCARD = 1, /**< Counter doesn't change. */ + QEI_OVERFLOW_MINMAX = 2, /**< Counter will be updated to min or max. */ +} qeioverflow_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 uint16_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 callback is called, the counter value + * is not updated, the decision on how to update is left + * to the callback. + * + * Three implementation are provided + * - 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, the QEI_COUNT_MIN is used as default + */ + qeicnt_t min; + /** + * @brief Max count value. + * + * @note If min == max, the QEI_COUNT_MAX is used as default + */ + qeicnt_t max; + /** + * @brief Notify of value change + */ + qeicallback_t notify_cb; + /** + * @brief Notify of overflow + * + * @note Overflow notification is performed after + * value changed notification. + */ + 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; + /** + * @brief Line to use 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 between 0 and 511 (including boundaries) + * + * @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; + /** + * @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 sample per report + * + * @details Default to QEI_REPORT_10 + */ + qeireport_t report; + /** + * @brief Notify of internal accumulator overflowed + * + * @note MCU has discarded some of the samples. + */ + qeicallback_t overflowed_cb; +} 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.*/ + /** + */ + qeidelta_t delta; + /** + */ + qeicnt_t count; + /** + * @brief Number of time the MCU discarded updates due to + * accumulator overflow + */ + uint32_t overflowed; + /** + * @brief Pointer to the ADCx 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) + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if NRF51_QEI_USE_QDEC1 && !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); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_QEI */ + +#endif /* HAL_QEI_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/NRF51/NRF51822/platform.mk b/os/hal/ports/NRF51/NRF51822/platform.mk index b937e39..ad5b2c4 100644 --- a/os/hal/ports/NRF51/NRF51822/platform.mk +++ b/os/hal/ports/NRF51/NRF51822/platform.mk @@ -37,6 +37,9 @@ endif ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),) PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c endif +ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),) +PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +endif else PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_lld.c \ @@ -51,7 +54,8 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_gpt_lld.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_wdg_lld.c \ ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_rng_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c + ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_pwm_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c endif # Required include directories -- cgit v1.2.3 From 7cb533cd20720b48c882261922cb12b572bcbf9b Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Tue, 28 Jun 2016 22:31:24 +0200 Subject: cleanup --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 92 ++++++++++++++++--------------- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 32 +++++------ 2 files changed, 61 insertions(+), 63 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c index 0f8043d..7d78f1d 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -1,5 +1,5 @@ /* - ChibiOS - Copyright (C) 2006..2016 Martino Migliavacca + 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. @@ -15,8 +15,8 @@ */ /** - * @file TIMv1/hal_qei_lld.c - * @brief STM32 QEI subsystem low level driver header. + * @file NRF51/hal_qei_lld.c + * @brief NRF51 QEI subsystem low level driver header. * * @addtogroup QEI * @{ @@ -31,46 +31,14 @@ /* Driver local definitions. */ /*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief QEID1 driver identifier. - */ -#if NRF51_QEI_USE_QDEC1 || defined(__DOXYGEN__) -QEIDriver QEID1; -#endif - - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -#if NRF51_QEI_USE_QDEC1 == TRUE /** - * @brief Quadrature decoder vector (QDEC) + * @brief Common IRQ handler. * - * @isr + * @param[in] qeip pointer to an QEIDriver */ -OSAL_IRQ_HANDLER(Vector88) { - QEIDriver *qeip = &QEID1; +static void serve_interrupt(QEIDriver *qeip) { NRF_QDEC_Type *qdec = qeip->qdec; - OSAL_IRQ_PROLOGUE(); - - - osalSysLockFromISR(); - if (qdec->EVENTS_ACCOF) { qdec->EVENTS_ACCOF = 0; qeip->overflowed++; @@ -152,10 +120,43 @@ OSAL_IRQ_HANDLER(Vector88) { if (overflowed && qeip->config->overflow_cb) qeip->config->overflow_cb(qeip, delta); } +} - - osalSysUnlockFromISR(); +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief QEID1 driver identifier. + */ +#if NRF51_QEI_USE_QDEC1 || defined(__DOXYGEN__) +QEIDriver QEID1; +#endif + + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if NRF51_QEI_USE_QDEC1 == TRUE +/** + * @brief Quadrature decoder vector (QDEC) + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector88) { + + OSAL_IRQ_PROLOGUE(); + serve_interrupt(&QEID1); OSAL_IRQ_EPILOGUE(); } #endif @@ -263,6 +264,13 @@ void qei_lld_stop(QEIDriver *qeip) { #endif qdec->INTENCLR = QDEC_INTENSET_REPORTRDY_Msk | QDEC_INTENSET_ACCOF_Msk; + + // Return pins to reset state + palSetLineMode(cfg->phase_a, PAL_MODE_RESET); + palSetLineMode(cfg->phase_b, PAL_MODE_RESET); + if (cfg->led != PAL_NOLINE) { + palSetLineMode(cfg->led, PAL_MODE_RESET); + } } } @@ -294,10 +302,6 @@ void qei_lld_disable(QEIDriver *qeip) { } - - - - #endif /* HAL_USE_QEI */ /** @} */ diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index f07a60a..40c751c 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -1,5 +1,5 @@ /* - ChibiOS - Copyright (C) 2006..2016 Martino Migliavacca + 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. @@ -15,8 +15,8 @@ */ /** - * @file TIMv1/hal_qei_lld.h - * @brief STM32 QEI subsystem low level driver header. + * @file NRF51/hal_qei_lld.h + * @brief NRF51 QEI subsystem low level driver header. * * @addtogroup QEI * @{ @@ -28,7 +28,6 @@ #if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) - /*===========================================================================*/ /* Driver constants. */ /*===========================================================================*/ @@ -40,8 +39,6 @@ #define QEI_COUNT_MAX 65535 - - /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ @@ -104,7 +101,7 @@ typedef enum { } qeiresolution_t; /** - * + * @brief Clusters of samples. */ typedef enum { QEI_REPORT_10 = 0x00UL, /**< 10 samples per report. */ @@ -117,9 +114,8 @@ typedef enum { QEI_REPORT_280 = 0x07UL, /**< 280 samples per report. */ } qeireport_t; - /** - * @brief Handling of counter overflow/underflow + * @brief Handling of counter overflow/underflow. */ typedef enum { QEI_OVERFLOW_WRAP = 0, /**< Counter value will wrap around. */ @@ -167,11 +163,8 @@ typedef struct { /** * @brief Handling of counter overflow/underflow * - * @details When overflow callback is called, the counter value - * is not updated, the decision on how to update is left - * to the callback. - * - * Three implementation are provided + * @details When overflow accours, the counter value is updated + * according to: * - QEI_OVERFLOW_DISCARD: * discard the update value, counter doesn't change * - QEI_OVERFLOW_MINMAX @@ -183,17 +176,19 @@ typedef struct { /** * @brief Min count value. * - * @note If min == max, the QEI_COUNT_MIN is used as default + * @note If min == max, then QEI_COUNT_MIN is used. */ qeicnt_t min; /** * @brief Max count value. * - * @note If min == max, the QEI_COUNT_MAX is used as default + * @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; /** @@ -201,6 +196,7 @@ typedef struct { * * @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.*/ @@ -251,6 +247,7 @@ typedef struct { * @brief Notify of internal accumulator overflowed * * @note MCU has discarded some of the samples. + * @note Called from ISR context. */ qeicallback_t overflowed_cb; } QEIConfig; @@ -275,9 +272,6 @@ struct QEIDriver { QEI_DRIVER_EXT_FIELDS #endif /* End of the mandatory fields.*/ - /** - */ - qeidelta_t delta; /** */ qeicnt_t count; -- cgit v1.2.3 From 7b8e263f8cd26a8c0413eed3560d44a615f812d5 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Tue, 28 Jun 2016 22:35:28 +0200 Subject: info --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index 40c751c..e4e89b6 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -18,6 +18,10 @@ * @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 * @{ */ -- cgit v1.2.3 From dde47ff1ab6d8155adfbaca1b912577f051509b4 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 29 Jun 2016 12:14:15 +0200 Subject: renamed QDEC1 to QDEC0, misc... --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 22 ++++++++++-------- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 38 +++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 18 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c index 7d78f1d..f74f5f7 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -39,13 +39,18 @@ static void serve_interrupt(QEIDriver *qeip) { NRF_QDEC_Type *qdec = qeip->qdec; + /* Accumulator overflowed + */ if (qdec->EVENTS_ACCOF) { qdec->EVENTS_ACCOF = 0; + qeip->overflowed++; if (qeip->config->overflowed_cb) qeip->config->overflowed_cb(qeip); } - + + /* Report ready + */ if (qdec->EVENTS_REPORTRDY) { qdec->EVENTS_REPORTRDY = 0; @@ -130,7 +135,7 @@ static void serve_interrupt(QEIDriver *qeip) { /** * @brief QEID1 driver identifier. */ -#if NRF51_QEI_USE_QDEC1 || defined(__DOXYGEN__) +#if NRF51_QEI_USE_QDEC0 || defined(__DOXYGEN__) QEIDriver QEID1; #endif @@ -147,7 +152,7 @@ QEIDriver QEID1; /* Driver interrupt handlers. */ /*===========================================================================*/ -#if NRF51_QEI_USE_QDEC1 == TRUE +#if NRF51_QEI_USE_QDEC0 == TRUE /** * @brief Quadrature decoder vector (QDEC) * @@ -172,7 +177,7 @@ OSAL_IRQ_HANDLER(Vector88) { */ void qei_lld_init(void) { -#if NRF51_QEI_USE_QDEC1 +#if NRF51_QEI_USE_QDEC0 == TRUE /* Driver initialization.*/ qeiObjectInit(&QEID1); QEID1.qdec = NRF_QDEC; @@ -201,9 +206,9 @@ void qei_lld_start(QEIDriver *qeip) { // Set interrupt masks and enable interrupt qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk | QDEC_INTENSET_ACCOF_Msk; -#if NRF51_QEI_USE_QDEC1 +#if NRF51_QEI_USE_QDEC0 == TRUE if (&QEID1 == qeip) { - nvicEnableVector(QDEC_IRQn, NRF51_QEI_IRQ_PRIORITY); + nvicEnableVector(QDEC_IRQn, NRF51_QEI_QDEC0_IRQ_PRIORITY); } #endif @@ -212,8 +217,7 @@ void qei_lld_start(QEIDriver *qeip) { qdec->PSELB = PAL_PAD(cfg->phase_b); // Select (optional) pin for LED, and configure it - qdec->PSELLED = (cfg->led == PAL_NOLINE) ? (uint32_t)-1 - : PAL_PAD(cfg->led); + qdec->PSELLED = PAL_PAD(cfg->led); qdec->LEDPOL = ((cfg->led_polarity == QEI_LED_POLARITY_LOW) ? QDEC_LEDPOL_LEDPOL_ActiveLow : QDEC_LEDPOL_LEDPOL_ActiveHigh) @@ -257,7 +261,7 @@ void qei_lld_stop(QEIDriver *qeip) { if (qeip->state == QEI_READY) { qdec->TASKS_STOP = 1; qdec->ENABLE = 0; -#if NRF51_QEI_USE_QDEC1 +#if NRF51_QEI_USE_QDEC0 == TRUE if (&QEID1 == qeip) { nvicDisableVector(QDEC_IRQn); } diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index e4e89b6..f8f29b9 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -56,15 +56,15 @@ * @details If set to @p TRUE the support for QEID1 is included. * @note The default is @p FALSE. */ -#if !defined(NRF51_QEI_USE_QDEC1) || defined(__DOXYGEN__) -#define NRF51_QEI_USE_QDEC1 FALSE +#if !defined(NRF51_QEI_USE_QDEC0) || defined(__DOXYGEN__) +#define NRF51_QEI_USE_QDEC0 FALSE #endif /** * @brief QEID interrupt priority level setting. */ -#if !defined(NRF51_QEI_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define NRF51_QEI_IRQ_PRIORITY 2 +#if !defined(NRF51_QEI_QDEC0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NRF51_QEI_QDEC0_IRQ_PRIORITY 2 #endif /** @} */ @@ -72,11 +72,16 @@ /* Derived constants and error checks. */ /*===========================================================================*/ -#if NRF51_QEI_USE_QDEC1 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(NRF51_QEI_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to QDEC1" +#if NRF51_QEI_USE_QDEC0 && \ + !OSAL_IRQ_IS_VALID_PRIORITY(NRF51_QEI_QDEC0_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to QDEC0" #endif +#if NRF51_QEI_USE_QDEC0 == FALSE +#error "Requesting QEI driver, but no QDEC peripheric attached" +#endif + + /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/ @@ -277,6 +282,7 @@ struct QEIDriver { #endif /* End of the mandatory fields.*/ /** + * @brief Counter */ qeicnt_t count; /** @@ -285,7 +291,7 @@ struct QEIDriver { */ uint32_t overflowed; /** - * @brief Pointer to the ADCx registers block. + * @brief Pointer to the QDECx registers block. */ NRF_QDEC_Type *qdec; }; @@ -305,11 +311,25 @@ struct QEIDriver { #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) \ + do { \ + (qeip)->count = value; \ + } while(0) + + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ -#if NRF51_QEI_USE_QDEC1 && !defined(__DOXYGEN__) +#if NRF51_QEI_USE_QDEC0 && !defined(__DOXYGEN__) extern QEIDriver QEID1; #endif -- cgit v1.2.3 From 5fee893778fad0d2b1a17e812aa0331f81a3ba7a Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 29 Jun 2016 12:26:22 +0200 Subject: conditionally include support for LED --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 10 +++++++++- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 14 +++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c index f74f5f7..ffbed95 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -199,9 +199,11 @@ void qei_lld_start(QEIDriver *qeip) { // Set Pins palSetLineMode(cfg->phase_a, PAL_MODE_INPUT); palSetLineMode(cfg->phase_b, PAL_MODE_INPUT); +#if NRF51_QEI_USE_LED == TRUE if (cfg->led != PAL_NOLINE) { palSetLineMode(cfg->led, PAL_MODE_INPUT); } +#endif // Set interrupt masks and enable interrupt qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk | @@ -217,13 +219,17 @@ void qei_lld_start(QEIDriver *qeip) { qdec->PSELB = PAL_PAD(cfg->phase_b); // Select (optional) pin for LED, and configure it +#if NRF51_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 @@ -272,9 +278,11 @@ void qei_lld_stop(QEIDriver *qeip) { // Return pins to reset state palSetLineMode(cfg->phase_a, PAL_MODE_RESET); palSetLineMode(cfg->phase_b, PAL_MODE_RESET); +#if NRF51_QEI_USE_LED == TRUE if (cfg->led != PAL_NOLINE) { palSetLineMode(cfg->led, PAL_MODE_RESET); } +#endif } } diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index f8f29b9..e1485e3 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -51,6 +51,16 @@ * @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(NRF51_QEI_USE_LED) || defined(__DOXYGEN__) +#define NRF51_QEI_USE_LED FALSE +#endif + /** * @brief QEID1 driver enable switch. * @details If set to @p TRUE the support for QEID1 is included. @@ -217,8 +227,9 @@ typedef struct { * @brief Line for reading Phase B */ ioline_t phase_b; +#if (NRF51_QEI_USE_LED == TRUE) || defined(__DOXYGEN__) /** - * @brief Line to use to control LED + * @brief Line used to control LED * * @note If LED is not controlled by MCU, you need to use the * PAL_NOLINE value. @@ -239,6 +250,7 @@ typedef struct { * @brief LED polarity to used (when LED is controlled by MCU) */ uint8_t led_polarity; +#endif /** * @brief Activate debouncing filter * -- cgit v1.2.3 From b20bf874d044c67bf72e6a054718e75531dc434a Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 29 Jun 2016 20:14:40 +0200 Subject: created more _lld_ fonctions. --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 216 +++++++++++++++++++----------- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 16 ++- 2 files changed, 150 insertions(+), 82 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c index ffbed95..66694dc 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -31,6 +31,130 @@ /* Driver local definitions. */ /*===========================================================================*/ +static inline +bool qei_adjust_count(qeicnt_t *count, qeidelta_t *delta, + qeicnt_t min, qeicnt_t max, qeioverflow_t mode) { + // See: https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow + + // Get values + const qeicnt_t _count = *count; + const qeidelta_t _delta = *delta; + + // Overflow operation + if ((_delta > 0) && (_count > (max - _delta))) { + switch(mode) { + case QEI_OVERFLOW_WRAP: + *delta = 0; + *count = (min + (_count - (max - _delta))) - 1; + break; + case QEI_OVERFLOW_DISCARD: + *delta = _delta; + *count = _count; + break; + case QEI_OVERFLOW_MINMAX: + *delta = _count - (max - _delta); + *count = max; + break; + } + return true; + + // Underflow operation + } else if ((_delta < 0) && (_count < (min - _delta))) { + switch(mode) { + case QEI_OVERFLOW_WRAP: + *delta = 0; + *count = (max + (_count - (min - _delta))) + 1; + break; + case QEI_OVERFLOW_DISCARD: + *delta = _delta; + *count = _count; + break; + case QEI_OVERFLOW_MINMAX: + *delta = _count - (min - _delta); + *count = min; + break; + } + return true; + + // Normal operation + } else { + *delta = 0; + *count = _count + _delta; + return false; + } +} + +qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta) { + // Get boundaries + qeicnt_t min = QEI_COUNT_MIN; + qeicnt_t max = QEI_COUNT_MAX; + if (qeip->config->min != qeip->config->max) { + min = qeip->config->min; + max = qeip->config->max; + } + + // Snapshot counter for later comparison + qeicnt_t count = qeip->count; + + // Adjust counter value + bool overflowed = qei_adjust_count(&qeip->count, &delta, + min, max, qeip->config->overflow); + + // Notify for value change + if ((qeip->count != count) && qeip->config->notify_cb) + qeip->config->notify_cb(qeip); + + // Notify for overflow (passing the remaining delta) + if (overflowed && qeip->config->overflow_cb) + qeip->config->overflow_cb(qeip, delta); + + // Remaining delta + return delta; +} + + +/** + * @brief Adjust the counter by delta. + * + * @param[in] qeip pointer to the @p QEIDriver object + * @param[in] delta the adjustement value + * @return The remaining delta (can occur during overflow) + * + * @api + */ +qeidelta_t qeiAdjust(QEIDriver *qeip, qeidelta_t delta) { + osalDbgCheck(qeip != NULL); + osalDbgAssert((qeip->state == QEI_ACTIVE), "invalid state"); + + osalSysLock(); + delta = qei_lld_adjust_count(qeip, delta); + osalSysUnlock(); + + return delta; +} + +/** + * @brief Set counter value + * + * @param[in] qeip pointer to the @p QEIDriver object + * @param[in] value the counter value + * + * @api + */ +void qeiSetCount(QEIDriver *qeip, qeicnt_t value) { + osalDbgCheck(qeip != NULL); + osalDbgAssert((qeip->state == QEI_READY) || (qeip->state == QEI_ACTIVE), + "invalid state"); + + osalSysLock(); + qei_lld_set_count(qeip, value); + osalSysUnlock(); +} + + + + + /** * @brief Common IRQ handler. * @@ -42,88 +166,28 @@ static void serve_interrupt(QEIDriver *qeip) { /* Accumulator overflowed */ if (qdec->EVENTS_ACCOF) { - qdec->EVENTS_ACCOF = 0; + qdec->EVENTS_ACCOF = 0; - qeip->overflowed++; - if (qeip->config->overflowed_cb) - qeip->config->overflowed_cb(qeip); + qeip->overflowed++; + if (qeip->config->overflowed_cb) + qeip->config->overflowed_cb(qeip); } /* 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 - - // Get boundaries - qeicnt_t min = QEI_COUNT_MIN; - qeicnt_t max = QEI_COUNT_MAX; - if (qeip->config->min != qeip->config->max) { - min = qeip->config->min; - max = qeip->config->max; - } - - // Compute new value - qeidelta_t delta = 0; - qeicnt_t count = qeip->count + acc; - bool overflowed = false; - - // See: https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow - - // Overflow - if ((acc > 0) && (qeip->count > (max - acc))) { - overflowed = true; - switch(qeip->config->overflow) { - case QEI_OVERFLOW_WRAP: - delta = 0; - count = (min + (qeip->count - (max - acc))) - 1; - break; - case QEI_OVERFLOW_DISCARD: - delta = acc; - count = qeip->count; - break; - case QEI_OVERFLOW_MINMAX: - delta = qeip->count - (max - acc); - count = max; - break; - } - - // Underflow - } else if ((acc < 0) && (qeip->count < (min - acc))) { - overflowed = true; - switch(qeip->config->overflow) { - case QEI_OVERFLOW_WRAP: - delta = 0; - count = (max + (qeip->count - (min - acc))) + 1; - break; - case QEI_OVERFLOW_DISCARD: - delta = acc; - count = qeip->count; - break; - case QEI_OVERFLOW_MINMAX: - delta = qeip->count - (min - acc); - count = min; - break; - } - } - - // Set value and notify - if (qeip->count != count) { - qeip->count = count; - if (qeip->config->notify_cb) - qeip->config->notify_cb(qeip); - } - - // Notify for overflow (passing the remaining delta) - if (overflowed && qeip->config->overflow_cb) - qeip->config->overflow_cb(qeip, delta); + 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 + qei_lld_adjust_count(qeip, acc); } } diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index e1485e3..813d169 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -31,7 +31,6 @@ #if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) - /*===========================================================================*/ /* Driver constants. */ /*===========================================================================*/ @@ -71,7 +70,7 @@ #endif /** - * @brief QEID interrupt priority level setting. + * @brief QEID interrupt priority level setting for QDEC0. */ #if !defined(NRF51_QEI_QDEC0_IRQ_PRIORITY) || defined(__DOXYGEN__) #define NRF51_QEI_QDEC0_IRQ_PRIORITY 2 @@ -296,12 +295,12 @@ struct QEIDriver { /** * @brief Counter */ - qeicnt_t count; + qeicnt_t count; /** * @brief Number of time the MCU discarded updates due to * accumulator overflow */ - uint32_t overflowed; + uint32_t overflowed; /** * @brief Pointer to the QDECx registers block. */ @@ -332,8 +331,10 @@ struct QEIDriver { * @notapi */ #define qei_lld_set_count(qeip, value) \ - do { \ - (qeip)->count = value; \ + if ((qeip)->count != ((qeicnt_t)value)) { \ + (qeip)->count = value; \ + if ((qeip)->config->notify_cb) \ + (qeip)->config->notify_cb(qeip); \ } while(0) @@ -357,6 +358,9 @@ extern "C" { } #endif +void qeiSetCount(QEIDriver *qeip, qeicnt_t value); +qeidelta_t qeiAdjust(QEIDriver *qeip, qeidelta_t delta); + #endif /* HAL_USE_QEI */ #endif /* HAL_QEI_LLD_H */ -- cgit v1.2.3 From a8b2364267be59dd2bc9d02bc6923a629bcecd72 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 29 Jun 2016 21:11:38 +0200 Subject: cleanup --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 116 ++++++++++++++++-------------- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 5 ++ 2 files changed, 68 insertions(+), 53 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c index 66694dc..9b1b6bb 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -28,7 +28,7 @@ /*===========================================================================*/ -/* Driver local definitions. */ +/* To be moved in hal_qei */ /*===========================================================================*/ static inline @@ -84,35 +84,6 @@ bool qei_adjust_count(qeicnt_t *count, qeidelta_t *delta, } } -qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta) { - // Get boundaries - qeicnt_t min = QEI_COUNT_MIN; - qeicnt_t max = QEI_COUNT_MAX; - if (qeip->config->min != qeip->config->max) { - min = qeip->config->min; - max = qeip->config->max; - } - - // Snapshot counter for later comparison - qeicnt_t count = qeip->count; - - // Adjust counter value - bool overflowed = qei_adjust_count(&qeip->count, &delta, - min, max, qeip->config->overflow); - - // Notify for value change - if ((qeip->count != count) && qeip->config->notify_cb) - qeip->config->notify_cb(qeip); - - // Notify for overflow (passing the remaining delta) - if (overflowed && qeip->config->overflow_cb) - qeip->config->overflow_cb(qeip, delta); - - // Remaining delta - return delta; -} - - /** * @brief Adjust the counter by delta. * @@ -152,9 +123,30 @@ void qeiSetCount(QEIDriver *qeip, qeicnt_t value) { } +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief QEID1 driver identifier. + */ +#if NRF51_QEI_USE_QDEC0 || defined(__DOXYGEN__) +QEIDriver QEID1; +#endif +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + /** * @brief Common IRQ handler. * @@ -191,27 +183,6 @@ static void serve_interrupt(QEIDriver *qeip) { } } - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief QEID1 driver identifier. - */ -#if NRF51_QEI_USE_QDEC0 || defined(__DOXYGEN__) -QEIDriver QEID1; -#endif - - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - /*===========================================================================*/ /* Driver interrupt handlers. */ /*===========================================================================*/ @@ -265,7 +236,7 @@ void qei_lld_start(QEIDriver *qeip) { palSetLineMode(cfg->phase_b, PAL_MODE_INPUT); #if NRF51_QEI_USE_LED == TRUE if (cfg->led != PAL_NOLINE) { - palSetLineMode(cfg->led, PAL_MODE_INPUT); + palSetLineMode(cfg->led, PAL_MODE_INPUT); } #endif @@ -344,7 +315,7 @@ void qei_lld_stop(QEIDriver *qeip) { palSetLineMode(cfg->phase_b, PAL_MODE_RESET); #if NRF51_QEI_USE_LED == TRUE if (cfg->led != PAL_NOLINE) { - palSetLineMode(cfg->led, PAL_MODE_RESET); + palSetLineMode(cfg->led, PAL_MODE_RESET); } #endif } @@ -378,6 +349,45 @@ void qei_lld_disable(QEIDriver *qeip) { } +/** + * @brief Adjust counter + * + * @param[in] qeip pointer to the @p QEIDriver object + * @param[in] delta value to use for adjustement + * @return remaining adjustement that were not applied + * + * @notapi + */ +qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta) { + // Get boundaries + qeicnt_t min = QEI_COUNT_MIN; + qeicnt_t max = QEI_COUNT_MAX; + if (qeip->config->min != qeip->config->max) { + min = qeip->config->min; + max = qeip->config->max; + } + + // Snapshot counter for later comparison + qeicnt_t count = qeip->count; + + // Adjust counter value + bool overflowed = qei_adjust_count(&qeip->count, &delta, + min, max, qeip->config->overflow); + + // Notify for value change + if ((qeip->count != count) && qeip->config->notify_cb) + qeip->config->notify_cb(qeip); + + // Notify for overflow (passing the remaining delta) + if (overflowed && qeip->config->overflow_cb) + qeip->config->overflow_cb(qeip, delta); + + // Remaining delta + return delta; +} + + + #endif /* HAL_USE_QEI */ /** @} */ diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index 813d169..ed5d9ae 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -354,10 +354,15 @@ extern "C" { 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); -- cgit v1.2.3 From e1e600b5ada75fe1bd77e13cb799433898cb848a Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 29 Jun 2016 21:27:56 +0200 Subject: conditionnaly compile accumulator overflow notification --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 22 ++++++++++++++++++---- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 14 ++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c index 9b1b6bb..595df89 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -155,6 +155,7 @@ QEIDriver QEID1; static void serve_interrupt(QEIDriver *qeip) { NRF_QDEC_Type *qdec = qeip->qdec; +#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE /* Accumulator overflowed */ if (qdec->EVENTS_ACCOF) { @@ -164,7 +165,8 @@ static void serve_interrupt(QEIDriver *qeip) { if (qeip->config->overflowed_cb) qeip->config->overflowed_cb(qeip); } - +#endif + /* Report ready */ if (qdec->EVENTS_REPORTRDY) { @@ -241,8 +243,13 @@ void qei_lld_start(QEIDriver *qeip) { #endif // Set interrupt masks and enable interrupt +#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk | QDEC_INTENSET_ACCOF_Msk; +#else + qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk; +#endif + #if NRF51_QEI_USE_QDEC0 == TRUE if (&QEID1 == qeip) { nvicEnableVector(QDEC_IRQn, NRF51_QEI_QDEC0_IRQ_PRIORITY); @@ -307,9 +314,14 @@ void qei_lld_stop(QEIDriver *qeip) { nvicDisableVector(QDEC_IRQn); } #endif - qdec->INTENCLR = QDEC_INTENSET_REPORTRDY_Msk | - QDEC_INTENSET_ACCOF_Msk; +#if NRF51_QEI_USE_ACC_OVERFLOW_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); @@ -329,8 +341,10 @@ void qei_lld_stop(QEIDriver *qeip) { * @notapi */ void qei_lld_enable(QEIDriver *qeip) { +#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE qeip->overflowed = 0; - +#endif + qeip->qdec->EVENTS_SAMPLERDY = 0; qeip->qdec->EVENTS_REPORTRDY = 0; qeip->qdec->EVENTS_ACCOF = 0; diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index ed5d9ae..aa3d1e8 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -60,6 +60,16 @@ #define NRF51_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(NRF51_QEI_USE_ACC_OVERFLOW_CB) || defined(__DOXYGEN__) +#define NRF51_QEI_USE_ACC_OVERFLOW_CB FALSE +#endif + /** * @brief QEID1 driver enable switch. * @details If set to @p TRUE the support for QEID1 is included. @@ -263,6 +273,7 @@ typedef struct { * @details Default to QEI_REPORT_10 */ qeireport_t report; +#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE /** * @brief Notify of internal accumulator overflowed * @@ -270,6 +281,7 @@ typedef struct { * @note Called from ISR context. */ qeicallback_t overflowed_cb; +#endif } QEIConfig; /** @@ -296,11 +308,13 @@ struct QEIDriver { * @brief Counter */ qeicnt_t count; +#if NRF51_QEI_USE_ACC_OVERFLOW_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. */ -- cgit v1.2.3 From 01874bedf49fc4fc1baf74871b653b5740912af5 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 29 Jun 2016 21:33:29 +0200 Subject: changed counter type to int32_t --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index aa3d1e8..aba7b59 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -38,8 +38,8 @@ #define QEI_LED_POLARITY_LOW 0 #define QEI_LED_POLARITY_HIGH 1 -#define QEI_COUNT_MIN 0 -#define QEI_COUNT_MAX 65535 +#define QEI_COUNT_MIN (-2147483648) +#define QEI_COUNT_MAX (2147483647) /*===========================================================================*/ @@ -67,7 +67,7 @@ * @note The default is @p FALSE. */ #if !defined(NRF51_QEI_USE_ACC_OVERFLOW_CB) || defined(__DOXYGEN__) -#define NRF51_QEI_USE_ACC_OVERFLOW_CB FALSE +#define NRF51_QEI_USE_ACC_OVERFLOW_CB FALSE #endif /** @@ -164,7 +164,7 @@ typedef enum { /** * @brief QEI counter type. */ -typedef uint16_t qeicnt_t; +typedef int32_t qeicnt_t; /** * @brief QEI delta type. -- cgit v1.2.3 From af18f7d43fe8f07016e985fed9e5dcd021da3303 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Wed, 29 Jun 2016 21:59:39 +0200 Subject: conditionally add support for overflow variant --- os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 15 ++++++--- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 53 +++++++++++++++++-------------- 2 files changed, 39 insertions(+), 29 deletions(-) (limited to 'os') diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c index 595df89..069c362 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -47,14 +47,18 @@ bool qei_adjust_count(qeicnt_t *count, qeidelta_t *delta, *delta = 0; *count = (min + (_count - (max - _delta))) - 1; break; +#if HAL_QEI_SUPPORT_OVERFLOW_DISCARD == TRUE case QEI_OVERFLOW_DISCARD: *delta = _delta; *count = _count; break; +#endif +#if HAL_QEI_SUPPORT_OVERFLOW_MINMAX == TRUE case QEI_OVERFLOW_MINMAX: *delta = _count - (max - _delta); *count = max; break; +#endif } return true; @@ -65,14 +69,18 @@ bool qei_adjust_count(qeicnt_t *count, qeidelta_t *delta, *delta = 0; *count = (max + (_count - (min - _delta))) + 1; break; +#if HAL_QEI_SUPPORT_OVERFLOW_DISCARD == TRUE case QEI_OVERFLOW_DISCARD: *delta = _delta; *count = _count; break; +#endif +#if HAL_QEI_SUPPORT_OVERFLOW_MINMAX == TRUE case QEI_OVERFLOW_MINMAX: *delta = _count - (min - _delta); *count = min; break; +#endif } return true; @@ -249,7 +257,6 @@ void qei_lld_start(QEIDriver *qeip) { #else qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk; #endif - #if NRF51_QEI_USE_QDEC0 == TRUE if (&QEID1 == qeip) { nvicEnableVector(QDEC_IRQn, NRF51_QEI_QDEC0_IRQ_PRIORITY); @@ -309,12 +316,13 @@ void qei_lld_stop(QEIDriver *qeip) { if (qeip->state == QEI_READY) { qdec->TASKS_STOP = 1; qdec->ENABLE = 0; + + // Unset interrupt masks and disable interrupt #if NRF51_QEI_USE_QDEC0 == TRUE if (&QEID1 == qeip) { nvicDisableVector(QDEC_IRQn); } #endif - #if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE qdec->INTENCLR = QDEC_INTENCLR_REPORTRDY_Msk | QDEC_INTENCLR_ACCOF_Msk; @@ -362,7 +370,6 @@ void qei_lld_disable(QEIDriver *qeip) { qeip->qdec->TASKS_STOP = 1; } - /** * @brief Adjust counter * @@ -399,8 +406,6 @@ qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta) { // Remaining delta return delta; } - - #endif /* HAL_USE_QEI */ diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index aba7b59..4de946e 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -41,6 +41,9 @@ #define QEI_COUNT_MIN (-2147483648) #define QEI_COUNT_MAX (2147483647) +#define HAL_QEI_SUPPORT_OVERFLOW_MINMAX TRUE +#define HAM_QEI_SUPPORT_OVERFLOW_DISCARD TRUE + /*===========================================================================*/ /* Driver pre-compile time settings. */ @@ -105,8 +108,6 @@ /* Driver data structures and types. */ /*===========================================================================*/ - - /** * @brief QEI count mode. */ @@ -118,41 +119,45 @@ typedef enum { * @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. */ + 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. */ + 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; + +// XXX: to be moved in hal_qei /** * @brief Handling of counter overflow/underflow. */ typedef enum { - QEI_OVERFLOW_WRAP = 0, /**< Counter value will wrap around. */ - QEI_OVERFLOW_DISCARD = 1, /**< Counter doesn't change. */ - QEI_OVERFLOW_MINMAX = 2, /**< Counter will be updated to min or max. */ + QEI_OVERFLOW_WRAP = 0, /**< Counter value will wrap around. */ +#if HAL_QEI_SUPPORT_OVERFLOW_DISCARD == TRUE + QEI_OVERFLOW_DISCARD = 1, /**< Counter doesn't change. */ +#endif +#if HAL_QEI_SUPPORT_OVERFLOW_MINMAX == TRUE + QEI_OVERFLOW_MINMAX = 2, /**< Counter will be updated to min or max. */ +#endif } qeioverflow_t; - - /** * @brief QEI direction inversion. */ @@ -191,7 +196,7 @@ typedef struct { /** * @brief Handling of counter overflow/underflow * - * @details When overflow accours, the counter value is updated + * @details When overflow occurs, the counter value is updated * according to: * - QEI_OVERFLOW_DISCARD: * discard the update value, counter doesn't change -- cgit v1.2.3 From 9c88423d66e9b4eafecc658058f25f79e08ff120 Mon Sep 17 00:00:00 2001 From: Stephane D'Alu Date: Thu, 7 Jul 2016 20:41:09 +0200 Subject: move functions to hal_qei.*, fixed comments --- os/hal/include/hal_qei.h | 30 ++++++ os/hal/ports/NRF51/NRF51822/hal_qei_lld.c | 154 +++++------------------------- os/hal/ports/NRF51/NRF51822/hal_qei_lld.h | 48 +++++----- os/hal/src/hal_qei.c | 123 ++++++++++++++++++++++++ 4 files changed, 201 insertions(+), 154 deletions(-) (limited to 'os') diff --git a/os/hal/include/hal_qei.h b/os/hal/include/hal_qei.h index 92f03fc..1032c84 100644 --- a/os/hal/include/hal_qei.h +++ b/os/hal/include/hal_qei.h @@ -65,8 +65,36 @@ typedef struct QEIDriver QEIDriver; */ typedef void (*qeicallback_t)(QEIDriver *qeip); +/** + * @brief Driver possible handling of counter overflow/underflow. + * + * @details When counter is going to overflow, the new value is + * computed according to this mode in such a way that + * the counter will either wrap around, stay unchange + * or reach min/max + * + * @note All driver implementation should support the + * QEI_OVERFLOW_WRAP mode. + * + * @note Mode QEI_OVERFLOW_DISCARD and QEI_OVERFLOW_MINMAX are included + * if QEI_USE_OVERFLOW_DISCARD and QEI_USE_OVERFLOW_MINMAX are + * set to TRUE in halconf_community.h and are not necessary supported + * by all drivers + */ +typedef enum { + QEI_OVERFLOW_WRAP = 0, /**< Counter value will wrap around. */ +#if QEI_USE_OVERFLOW_DISCARD == TRUE + QEI_OVERFLOW_DISCARD = 1, /**< Counter doesn't change. */ +#endif +#if QEI_USE_OVERFLOW_MINMAX == TRUE + QEI_OVERFLOW_MINMAX = 2, /**< Counter will be updated upto min or max.*/ +#endif +} qeioverflow_t; + + #include "hal_qei_lld.h" + /*===========================================================================*/ /* Driver macros. */ /*===========================================================================*/ @@ -119,6 +147,8 @@ extern "C" { qeicnt_t qeiGetCount(QEIDriver *qeip); qeidelta_t qeiUpdate(QEIDriver *qeip); qeidelta_t qeiUpdateI(QEIDriver *qeip); + bool qei_adjust_count(qeicnt_t *count, qeidelta_t *delta, + qeicnt_t min, qeicnt_t max, qeioverflow_t mode); #ifdef __cplusplus } #endif diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c index 069c362..fbaf3aa 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.c @@ -16,7 +16,7 @@ /** * @file NRF51/hal_qei_lld.c - * @brief NRF51 QEI subsystem low level driver header. + * @brief NRF51 QEI subsystem low level driver. * * @addtogroup QEI * @{ @@ -27,110 +27,6 @@ #if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__) -/*===========================================================================*/ -/* To be moved in hal_qei */ -/*===========================================================================*/ - -static inline -bool qei_adjust_count(qeicnt_t *count, qeidelta_t *delta, - qeicnt_t min, qeicnt_t max, qeioverflow_t mode) { - // See: https://www.securecoding.cert.org/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow - - // Get values - const qeicnt_t _count = *count; - const qeidelta_t _delta = *delta; - - // Overflow operation - if ((_delta > 0) && (_count > (max - _delta))) { - switch(mode) { - case QEI_OVERFLOW_WRAP: - *delta = 0; - *count = (min + (_count - (max - _delta))) - 1; - break; -#if HAL_QEI_SUPPORT_OVERFLOW_DISCARD == TRUE - case QEI_OVERFLOW_DISCARD: - *delta = _delta; - *count = _count; - break; -#endif -#if HAL_QEI_SUPPORT_OVERFLOW_MINMAX == TRUE - case QEI_OVERFLOW_MINMAX: - *delta = _count - (max - _delta); - *count = max; - break; -#endif - } - return true; - - // Underflow operation - } else if ((_delta < 0) && (_count < (min - _delta))) { - switch(mode) { - case QEI_OVERFLOW_WRAP: - *delta = 0; - *count = (max + (_count - (min - _delta))) + 1; - break; -#if HAL_QEI_SUPPORT_OVERFLOW_DISCARD == TRUE - case QEI_OVERFLOW_DISCARD: - *delta = _delta; - *count = _count; - break; -#endif -#if HAL_QEI_SUPPORT_OVERFLOW_MINMAX == TRUE - case QEI_OVERFLOW_MINMAX: - *delta = _count - (min - _delta); - *count = min; - break; -#endif - } - return true; - - // Normal operation - } else { - *delta = 0; - *count = _count + _delta; - return false; - } -} - -/** - * @brief Adjust the counter by delta. - * - * @param[in] qeip pointer to the @p QEIDriver object - * @param[in] delta the adjustement value - * @return The remaining delta (can occur during overflow) - * - * @api - */ -qeidelta_t qeiAdjust(QEIDriver *qeip, qeidelta_t delta) { - osalDbgCheck(qeip != NULL); - osalDbgAssert((qeip->state == QEI_ACTIVE), "invalid state"); - - osalSysLock(); - delta = qei_lld_adjust_count(qeip, delta); - osalSysUnlock(); - - return delta; -} - -/** - * @brief Set counter value - * - * @param[in] qeip pointer to the @p QEIDriver object - * @param[in] value the counter value - * - * @api - */ -void qeiSetCount(QEIDriver *qeip, qeicnt_t value) { - osalDbgCheck(qeip != NULL); - osalDbgAssert((qeip->state == QEI_READY) || (qeip->state == QEI_ACTIVE), - "invalid state"); - - osalSysLock(); - qei_lld_set_count(qeip, value); - osalSysUnlock(); -} - - /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ @@ -163,7 +59,7 @@ QEIDriver QEID1; static void serve_interrupt(QEIDriver *qeip) { NRF_QDEC_Type *qdec = qeip->qdec; -#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE +#if NRF51_QEI_USE_ACC_OVERFLOWED_CB == TRUE /* Accumulator overflowed */ if (qdec->EVENTS_ACCOF) { @@ -180,15 +76,15 @@ static void serve_interrupt(QEIDriver *qeip) { if (qdec->EVENTS_REPORTRDY) { qdec->EVENTS_REPORTRDY = 0; - // Read (and clear counters due to shortcut) + /* 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 + /* Inverse direction if requested */ if (qeip->config->dirinv) acc = -acc; // acc is [-1024..+1023], its okay on int16_t - // Adjust counter + /* Adjust counter */ qei_lld_adjust_count(qeip, acc); } } @@ -241,7 +137,7 @@ void qei_lld_start(QEIDriver *qeip) { const QEIConfig *cfg = qeip->config; if (qeip->state == QEI_STOP) { - // Set Pins + /* Set Pins */ palSetLineMode(cfg->phase_a, PAL_MODE_INPUT); palSetLineMode(cfg->phase_b, PAL_MODE_INPUT); #if NRF51_QEI_USE_LED == TRUE @@ -250,8 +146,8 @@ void qei_lld_start(QEIDriver *qeip) { } #endif - // Set interrupt masks and enable interrupt -#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE + /* Set interrupt masks and enable interrupt */ +#if NRF51_QEI_USE_ACC_OVERFLOWED_CB == TRUE qdec->INTENSET = QDEC_INTENSET_REPORTRDY_Msk | QDEC_INTENSET_ACCOF_Msk; #else @@ -263,11 +159,11 @@ void qei_lld_start(QEIDriver *qeip) { } #endif - // Select pin for Phase A and Phase B + /* 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 + /* Select (optional) pin for LED, and configure it */ #if NRF51_QEI_USE_LED == TRUE qdec->PSELLED = PAL_PAD(cfg->led); qdec->LEDPOL = ((cfg->led_polarity == QEI_LED_POLARITY_LOW) @@ -279,22 +175,22 @@ void qei_lld_start(QEIDriver *qeip) { qdec->PSELLED = (uint32_t)-1; #endif - // Set sampling resolution and debouncing + /* 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 + /* Define minimum sampling before reporting + and create shortcut to clear accumulation */ qdec->REPORTPER = cfg->report; qdec->SHORTS = QDEC_SHORTS_REPORTRDY_READCLRACC_Msk; - // Enable peripheric + /* Enable peripheric */ qdec->ENABLE = 1; } - // Initially state is stopped, events cleared + /* Initially state is stopped, events cleared */ qdec->TASKS_STOP = 1; qdec->EVENTS_SAMPLERDY = 0; qdec->EVENTS_REPORTRDY = 0; @@ -317,20 +213,20 @@ void qei_lld_stop(QEIDriver *qeip) { qdec->TASKS_STOP = 1; qdec->ENABLE = 0; - // Unset interrupt masks and disable interrupt + /* Unset interrupt masks and disable interrupt */ #if NRF51_QEI_USE_QDEC0 == TRUE if (&QEID1 == qeip) { nvicDisableVector(QDEC_IRQn); } #endif -#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE +#if NRF51_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 + /* Return pins to reset state */ palSetLineMode(cfg->phase_a, PAL_MODE_RESET); palSetLineMode(cfg->phase_b, PAL_MODE_RESET); #if NRF51_QEI_USE_LED == TRUE @@ -349,7 +245,7 @@ void qei_lld_stop(QEIDriver *qeip) { * @notapi */ void qei_lld_enable(QEIDriver *qeip) { -#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE +#if NRF51_QEI_USE_ACC_OVERFLOWED_CB == TRUE qeip->overflowed = 0; #endif @@ -380,7 +276,7 @@ void qei_lld_disable(QEIDriver *qeip) { * @notapi */ qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta) { - // Get boundaries + /* Get boundaries */ qeicnt_t min = QEI_COUNT_MIN; qeicnt_t max = QEI_COUNT_MAX; if (qeip->config->min != qeip->config->max) { @@ -388,22 +284,22 @@ qeidelta_t qei_lld_adjust_count(QEIDriver *qeip, qeidelta_t delta) { max = qeip->config->max; } - // Snapshot counter for later comparison + /* Snapshot counter for later comparison */ qeicnt_t count = qeip->count; - // Adjust counter value + /* Adjust counter value */ bool overflowed = qei_adjust_count(&qeip->count, &delta, min, max, qeip->config->overflow); - // Notify for value change + /* Notify for value change */ if ((qeip->count != count) && qeip->config->notify_cb) qeip->config->notify_cb(qeip); - // Notify for overflow (passing the remaining delta) + /* Notify for overflow (passing the remaining delta) */ if (overflowed && qeip->config->overflow_cb) qeip->config->overflow_cb(qeip, delta); - // Remaining delta + /* Remaining delta */ return delta; } diff --git a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h index 4de946e..5037591 100644 --- a/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h +++ b/os/hal/ports/NRF51/NRF51822/hal_qei_lld.h @@ -35,14 +35,26 @@ /* 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) -#define QEI_COUNT_MAX (2147483647) -#define HAL_QEI_SUPPORT_OVERFLOW_MINMAX TRUE -#define HAM_QEI_SUPPORT_OVERFLOW_DISCARD TRUE +/** + * @brief Maximum usable value for defining counter overflow + */ +#define QEI_COUNT_MAX ( 2147483647) + /*===========================================================================*/ @@ -69,8 +81,8 @@ * is included. * @note The default is @p FALSE. */ -#if !defined(NRF51_QEI_USE_ACC_OVERFLOW_CB) || defined(__DOXYGEN__) -#define NRF51_QEI_USE_ACC_OVERFLOW_CB FALSE +#if !defined(NRF51_QEI_USE_ACC_OVERFLOWED_CB) || defined(__DOXYGEN__) +#define NRF51_QEI_USE_ACC_OVERFLOWED_CB FALSE #endif /** @@ -143,21 +155,6 @@ typedef enum { QEI_REPORT_280 = 0x07UL, /**< 280 samples per report. */ } qeireport_t; - -// XXX: to be moved in hal_qei -/** - * @brief Handling of counter overflow/underflow. - */ -typedef enum { - QEI_OVERFLOW_WRAP = 0, /**< Counter value will wrap around. */ -#if HAL_QEI_SUPPORT_OVERFLOW_DISCARD == TRUE - QEI_OVERFLOW_DISCARD = 1, /**< Counter doesn't change. */ -#endif -#if HAL_QEI_SUPPORT_OVERFLOW_MINMAX == TRUE - QEI_OVERFLOW_MINMAX = 2, /**< Counter will be updated to min or max. */ -#endif -} qeioverflow_t; - /** * @brief QEI direction inversion. */ @@ -252,7 +249,8 @@ typedef struct { /** * @brief Period in µs the LED is switched on prior to sampling. * - * @details LED warming is between 0 and 511 (including boundaries) + * @details LED warming is expressed in micro-seconds and value + * is [0..511] * * @note 31µs is the recommanded default. * @@ -273,16 +271,16 @@ typedef struct { */ bool debouncing; /** - * @brief Number of sample per report + * @brief Number of samples per report * * @details Default to QEI_REPORT_10 */ qeireport_t report; -#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE +#if NRF51_QEI_USE_ACC_OVERFLOWED_CB == TRUE /** * @brief Notify of internal accumulator overflowed + * (ie: MCU discarding samples) * - * @note MCU has discarded some of the samples. * @note Called from ISR context. */ qeicallback_t overflowed_cb; @@ -313,7 +311,7 @@ struct QEIDriver { * @brief Counter */ qeicnt_t count; -#if NRF51_QEI_USE_ACC_OVERFLOW_CB == TRUE +#if NRF51_QEI_USE_ACC_OVERFLOWED_CB == TRUE /** * @brief Number of time the MCU discarded updates due to * accumulator overflow diff --git a/os/hal/src/hal_qei.c b/os/hal/src/hal_qei.c index a2b7303..abecdf8 100644 --- a/os/hal/src/hal_qei.c +++ b/os/hal/src/hal_qei.c @@ -46,6 +46,91 @@ /* Driver exported functions. */ /*===========================================================================*/ +/** + * @brief Helper for correclty handling overflow/underflow + * + * @details Underflow/overflow will be handled according to mode: + * QEI_OVERFLOW_WRAP: counter value will wrap around. + * QEI_OVERFLOW_DISCARD: counter will not change + * QEI_OVERFLOW_MINMAX: counter will be updated upto min or max. + * + * @note This function is for use by low level driver. + * + * @param[in,out] count counter value + * @param[in,out] delta adjustment value + * @param[in] min minimum allowed value for counter + * @param[in] max maximum allowed value for counter + * @param[in] mode how to handle overflow + * + * @return true if counter underflow/overflow occured or + * was due to occur + * + */ +bool qei_adjust_count(qeicnt_t *count, qeidelta_t *delta, + qeicnt_t min, qeicnt_t max, qeioverflow_t mode) { + /* For information on signed integer overflow see: + * https://www.securecoding.cert.org/confluence/x/RgE + */ + + /* Get values */ + const qeicnt_t _count = *count; + const qeidelta_t _delta = *delta; + + /* Overflow operation + */ + if ((_delta > 0) && (_count > (max - _delta))) { + switch(mode) { + case QEI_OVERFLOW_WRAP: + *delta = 0; + *count = (min + (_count - (max - _delta))) - 1; + break; +#if QEI_USE_OVERFLOW_DISCARD == TRUE + case QEI_OVERFLOW_DISCARD: + *delta = _delta; + *count = _count; + break; +#endif +#if QEI_USE_OVERFLOW_MINMAX == TRUE + case QEI_OVERFLOW_MINMAX: + *delta = _count - (max - _delta); + *count = max; + break; +#endif + } + return true; + + /* Underflow operation + */ + } else if ((_delta < 0) && (_count < (min - _delta))) { + switch(mode) { + case QEI_OVERFLOW_WRAP: + *delta = 0; + *count = (max + (_count - (min - _delta))) + 1; + break; +#if QEI_USE_OVERFLOW_DISCARD == TRUE + case QEI_OVERFLOW_DISCARD: + *delta = _delta; + *count = _count; + break; +#endif +#if QEI_USE_OVERFLOW_MINMAX == TRUE + case QEI_OVERFLOW_MINMAX: + *delta = _count - (min - _delta); + *count = min; + break; +#endif + } + return true; + + /* Normal operation + */ + } else { + *delta = 0; + *count = _count + _delta; + return false; + } +} + /** * @brief QEI Driver initialization. * @note This function is implicitly invoked by @p halInit(), there is @@ -167,6 +252,44 @@ qeicnt_t qeiGetCount(QEIDriver *qeip) { return cnt; } +/** + * @brief Set counter value. + * + * @param[in] qeip pointer to the @p QEIDriver object. + * @param[in] value the new counter value. + * + * @api + */ +void qeiSetCount(QEIDriver *qeip, qeicnt_t value) { + osalDbgCheck(qeip != NULL); + osalDbgAssert((qeip->state == QEI_READY) || (qeip->state == QEI_ACTIVE), + "invalid state"); + + osalSysLock(); + qei_lld_set_count(qeip, value); + osalSysUnlock(); +} + +/** + * @brief Adjust the counter by delta. + * + * @param[in] qeip pointer to the @p QEIDriver object. + * @param[in] delta the adjustement value. + * @return the remaining delta (can occur during overflow). + * + * @api + */ +qeidelta_t qeiAdjust(QEIDriver *qeip, qeidelta_t delta) { + osalDbgCheck(qeip != NULL); + osalDbgAssert((qeip->state == QEI_ACTIVE), "invalid state"); + + osalSysLock(); + delta = qei_lld_adjust_count(qeip, delta); + osalSysUnlock(); + + return delta; +} + /** * @brief Returns the counter delta from last reading. * -- cgit v1.2.3