move functions to hal_qei.*, fixed comments

This commit is contained in:
Stephane D'Alu 2016-07-07 20:41:09 +02:00
parent af18f7d43f
commit 9c88423d66
4 changed files with 201 additions and 154 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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.
*