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