incremental (quadrature) encoder interface and LLD

Use this forum for requesting small changes in ChibiOS. Large changes should be discussed in the development forum. This forum is NOT for support.
Thargon
Posts: 86
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 6 times
Been thanked: 12 times

incremental (quadrature) encoder interface and LLD

Postby Thargon » Thu Oct 18, 2018 8:15 am

Hi,

at the end of this post you can find a patch which introduces an incremental (quadrature) encoder interface (QEI) for HAL as well as a LLD implementation for STM32 TIMv1.
Please note that the newly introduced files contain our custom header with according copyright and licence information, which must be kept in place, if you want to use the patch for your project! Exception: For integration of this functionality into the ChibiOS/HAL project, the maintainer may replace our header, copyright and licence.

Patch for ChibiOS 18.2.x:

Code: Select all

diff --git a/os/hal/hal.mk b/os/hal/hal.mk
index f177a3f..64d96d9 100644
--- a/os/hal/hal.mk
+++ b/os/hal/hal.mk
@@ -41,6 +41,9 @@ endif
 ifneq ($(findstring HAL_USE_ICU TRUE,$(HALCONF)),)
 HALSRC += $(CHIBIOS)/os/hal/src/hal_icu.c
 endif
+ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),)
+HALSRC += $(CHIBIOS)/os/hal/src/hal_qei.c
+endif
 ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),)
 HALSRC += $(CHIBIOS)/os/hal/src/hal_mac.c
 endif
@@ -94,6 +97,7 @@ HALSRC = $(CHIBIOS)/os/hal/src/hal.c \
          $(CHIBIOS)/os/hal/src/hal_i2c.c \
          $(CHIBIOS)/os/hal/src/hal_i2s.c \
          $(CHIBIOS)/os/hal/src/hal_icu.c \
+         $(CHIBIOS)/os/hal/src/hal_qei.c \
          $(CHIBIOS)/os/hal/src/hal_mac.c \
          $(CHIBIOS)/os/hal/src/hal_mmc_spi.c \
          $(CHIBIOS)/os/hal/src/hal_pal.c \
diff --git a/os/hal/include/hal.h b/os/hal/include/hal.h
index 79f7c42..8cf221f 100644
--- a/os/hal/include/hal.h
+++ b/os/hal/include/hal.h
@@ -78,6 +78,10 @@
 #define HAL_USE_PWM                         FALSE
 #endif
 
+#if !defined(HAL_USE_QEI)
+#define HAL_USE_QEI                         FALSE
+#endif
+
 #if !defined(HAL_USE_QSPI)
 #define HAL_USE_QSPI                        FALSE
 #endif
@@ -138,6 +142,7 @@
 #include "hal_icu.h"
 #include "hal_mac.h"
 #include "hal_pwm.h"
+#include "hal_qei.h"
 #include "hal_qspi.h"
 #include "hal_rtc.h"
 #include "hal_serial.h"
diff --git a/os/hal/include/hal_qei.h b/os/hal/include/hal_qei.h
new file mode 100644
index 0000000..8769729
--- /dev/null
+++ b/os/hal/include/hal_qei.h
@@ -0,0 +1,148 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    hal_qei.h
+ * @brief   QEI Driver macros and structures.
+ *
+ * @addtogroup QEI
+ * @{
+ */
+
+#ifndef HAL_QEI_H
+#define HAL_QEI_H
+
+#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/**
+ * @brief   Driver state machine possible states.
+ */
+typedef enum {
+  QEI_UNINIT = 0,                   /**< Not initialized.                   */
+  QEI_STOP = 1,                     /**< Stopped.                           */
+  QEI_READY = 2,                    /**< Ready.                             */
+  QEI_ACTIVE = 4,                   /**< Active.                            */
+} qeistate_t;
+
+/**
+ * @brief   Type of a structure representing an QEI driver.
+ */
+typedef struct QEIDriver QEIDriver;
+
+#include "hal_qei_lld.h"
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/**
+ * @name    Macro Functions
+ * @{
+ */
+/**
+ * @brief   Enables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @iclass
+ */
+#define qeiEnableI(qeip) qei_lld_enable(qeip)
+
+/**
+ * @brief   Disables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @iclass
+ */
+#define qeiDisableI(qeip) qei_lld_disable(qeip)
+
+/**
+ * @brief   Returns the direction of the last transition.
+ * @details The direction is defined as boolean and is
+ *          calculated at each transition on any input.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The request direction.
+ * @retval FALSE        Position counted up.
+ * @retval TRUE         Position counted down.
+ * @iclass
+ */
+#define qeiGetDirectionI(qeip) qei_lld_get_direction(qeip)
+
+/**
+ * @brief   Returns the position of the encoder.
+ * @details The position is defined as number of pulses since last reset.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The number of pulses.
+ *
+ * @iclass
+ */
+#define qeiGetPositionI(qeip) qei_lld_get_position(qeip)
+
+/**
+ * @brief   Returns the range of the encoder.
+ * @details The range is defined as number of maximum pulse count.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The number of pulses.
+ *
+ * @iclass
+ */
+#define qeiGetRangeI(qeip) qei_lld_get_range(qeip)
+/** @} */
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void qeiInit(void);
+  void qeiObjectInit(QEIDriver *qeip);
+  void qeiStart(QEIDriver *qeip, const QEIConfig *config);
+  void qeiStop(QEIDriver *qeip);
+  void qeiEnable(QEIDriver *qeip);
+  void qeiDisable(QEIDriver *qeip);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_QEI */
+
+#endif /* HAL_QEI_H */
+
+/** @} */
diff --git a/os/hal/ports/STM32/LLD/TIMv1/driver.mk b/os/hal/ports/STM32/LLD/TIMv1/driver.mk
index 032d75a..13e3571 100644
--- a/os/hal/ports/STM32/LLD/TIMv1/driver.mk
+++ b/os/hal/ports/STM32/LLD/TIMv1/driver.mk
@@ -10,10 +10,14 @@ endif
 ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),)
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c
 endif
+ifneq ($(findstring HAL_USE_QEI TRUE,$(HALCONF)),)
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
+endif
 else
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_gpt_lld.c
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_icu_lld.c
 PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_pwm_lld.c
+PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
 endif
 
 PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1
diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
new file mode 100644
index 0000000..cd1ab9b
--- /dev/null
+++ b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.c
@@ -0,0 +1,304 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    STM32/hal_qei_lld.c
+ * @brief   STM32 QEI subsystem low level driver.
+ *
+ * @addtogroup QEI
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   QEID1 driver identifier.
+ * @note    The driver QEID1 allocates the complex timer TIM1 when enabled.
+ */
+#if STM32_QEI_USE_TIM1 || defined(__DOXYGEN__)
+QEIDriver QEID1;
+#endif
+
+/**
+ * @brief   QEID2 driver identifier.
+ * @note    The driver QEID1 allocates the timer TIM2 when enabled.
+ */
+#if STM32_QEI_USE_TIM2 || defined(__DOXYGEN__)
+QEIDriver QEID2;
+#endif
+
+/**
+ * @brief   QEID3 driver identifier.
+ * @note    The driver QEID1 allocates the timer TIM3 when enabled.
+ */
+#if STM32_QEI_USE_TIM3 || defined(__DOXYGEN__)
+QEIDriver QEID3;
+#endif
+
+/**
+ * @brief   QEID4 driver identifier.
+ * @note    The driver QEID4 allocates the timer TIM4 when enabled.
+ */
+#if STM32_QEI_USE_TIM4 || defined(__DOXYGEN__)
+QEIDriver QEID4;
+#endif
+
+/**
+ * @brief   QEID5 driver identifier.
+ * @note    The driver QEID5 allocates the timer TIM5 when enabled.
+ */
+#if STM32_QEI_USE_TIM5 || defined(__DOXYGEN__)
+QEIDriver QEID5;
+#endif
+
+/**
+ * @brief   QEID8 driver identifier.
+ * @note    The driver QEID8 allocates the timer TIM8 when enabled.
+ */
+#if STM32_QEI_USE_TIM8 || defined(__DOXYGEN__)
+QEIDriver QEID8;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Low level QEI driver initialization.
+ *
+ * @notapi
+ */
+void qei_lld_init(void) {
+
+#if STM32_QEI_USE_TIM1
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID1);
+  QEID1.tim = STM32_TIM1;
+#endif
+
+#if STM32_QEI_USE_TIM2
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID2);
+  QEID2.tim = STM32_TIM2;
+#endif
+
+#if STM32_QEI_USE_TIM3
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID3);
+  QEID3.tim = STM32_TIM3;
+#endif
+
+#if STM32_QEI_USE_TIM4
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID4);
+  QEID4.tim = STM32_TIM4;
+#endif
+
+#if STM32_QEI_USE_TIM5
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID5);
+  QEID5.tim = STM32_TIM5;
+#endif
+
+#if STM32_QEI_USE_TIM8
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID8);
+  QEID8.tim = STM32_TIM8;
+#endif
+}
+
+/**
+ * @brief   Configures and activates the QEI peripheral.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @notapi
+ */
+void qei_lld_start(QEIDriver *qeip) {
+  uint32_t arr, ccer;
+
+  if (qeip->state == QEI_STOP) {
+    /* Clock activation and timer reset.*/
+#if STM32_QEI_USE_TIM1
+    if (&QEID1 == qeip) {
+      rccEnableTIM1();
+      rccResetTIM1();
+    }
+#endif
+#if STM32_QEI_USE_TIM2
+    if (&QEID2 == qeip) {
+      rccEnableTIM2();
+      rccResetTIM2();
+    }
+#endif
+#if STM32_QEI_USE_TIM3
+    if (&QEID3 == qeip) {
+      rccEnableTIM3();
+      rccResetTIM3();
+    }
+#endif
+#if STM32_QEI_USE_TIM4
+    if (&QEID4 == qeip) {
+      rccEnableTIM4();
+      rccResetTIM4();
+    }
+#endif
+
+#if STM32_QEI_USE_TIM5
+    if (&QEID5 == qeip) {
+      rccEnableTIM5();
+      rccResetTIM5();
+    }
+#endif
+#if STM32_QEI_USE_TIM8
+    if (&QEID8 == qeip) {
+      rccEnableTIM8();
+      rccResetTIM8();
+    }
+#endif
+  }
+  else {
+    /* Driver re-configuration scenario, it must be stopped first.*/
+    qeip->tim->CR1    = 0;                  /* Timer disabled.              */
+    qeip->tim->DIER   = 0;                  /* All IRQs disabled.           */
+    qeip->tim->SR     = 0;                  /* Clear eventual pending IRQs. */
+    qeip->tim->CCR[0] = 0;                  /* Comparator 1 disabled.       */
+    qeip->tim->CCR[1] = 0;                  /* Comparator 2 disabled.       */
+    qeip->tim->CNT    = 0;                  /* Counter reset to zero.       */
+  }
+
+  /* Timer configuration.*/
+  qeip->tim->PSC  = 0;
+  arr = qeip->config->range - 1;
+  osalDbgAssert((arr <= 0xFFFF), "invalid range");
+  qeip->tim->ARR  = arr & 0xFFFF;
+
+  /* CCMR1_CC1S = 01 - CH1 Input on TI1.
+     CCMR1_CC2S = 01 - CH2 Input on TI2.*/
+  qeip->tim->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
+
+  ccer = 0;
+  if (qeip->config->channels[0].mode == QEI_INPUT_INVERTED)
+    ccer |= TIM_CCER_CC1P;
+  if (qeip->config->channels[1].mode == QEI_INPUT_INVERTED)
+    ccer |= TIM_CCER_CC2P;
+  qeip->tim->CCER = ccer;
+
+  if (qeip->config->mode == QEI_COUNT_CH1)
+    qeip->tim->SMCR  = TIM_SMCR_SMS_1;
+  else if (qeip->config->mode == QEI_COUNT_CH2)
+    qeip->tim->SMCR  = TIM_SMCR_SMS_0;
+  else
+    qeip->tim->SMCR  = TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;
+}
+
+/**
+ * @brief   Deactivates the QEI peripheral.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @notapi
+ */
+void qei_lld_stop(QEIDriver *qeip) {
+
+  if (qeip->state == QEI_READY) {
+    /* Clock deactivation.*/
+    qeip->tim->CR1  = 0;                    /* Timer disabled.              */
+
+#if STM32_QEI_USE_TIM1
+    if (&QEID1 == qeip) {
+      rccDisableTIM1();
+    }
+#endif
+#if STM32_QEI_USE_TIM2
+    if (&QEID2 == qeip) {
+      rccDisableTIM2();
+    }
+#endif
+#if STM32_QEI_USE_TIM3
+    if (&QEID3 == qeip) {
+      rccDisableTIM3();
+    }
+#endif
+#if STM32_QEI_USE_TIM4
+    if (&QEID4 == qeip) {
+      rccDisableTIM4();
+    }
+#endif
+#if STM32_QEI_USE_TIM5
+    if (&QEID5 == qeip) {
+      rccDisableTIM5();
+    }
+#endif
+  }
+#if STM32_QEI_USE_TIM8
+    if (&QEID8 == qeip) {
+      rccDisableTIM8();
+    }
+#endif
+}
+
+/**
+ * @brief   Enables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @notapi
+ */
+void qei_lld_enable(QEIDriver *qeip) {
+
+  qeip->tim->CR1  = TIM_CR1_CEN;
+}
+
+/**
+ * @brief   Disables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @notapi
+ */
+void qei_lld_disable(QEIDriver *qeip) {
+
+  qeip->tim->CR1  = 0;
+}
+
+#endif /* HAL_USE_QEI */
+
+/** @} */
diff --git a/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h
new file mode 100644
index 0000000..ec1cd42
--- /dev/null
+++ b/os/hal/ports/STM32/LLD/TIMv1/hal_qei_lld.h
@@ -0,0 +1,302 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    STM32/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__)
+
+#include "stm32_tim.h"
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/**
+ * @brief   Number of input channels per QEI driver.
+ */
+#define QEI_CHANNELS                            2
+
+/*===========================================================================*/
+/* 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 TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM1) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM1                  FALSE
+#endif
+
+/**
+ * @brief   QEID2 driver enable switch.
+ * @details If set to @p TRUE the support for QEID2 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM2) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM2                  FALSE
+#endif
+
+/**
+ * @brief   QEID3 driver enable switch.
+ * @details If set to @p TRUE the support for QEID3 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM3) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM3                  FALSE
+#endif
+
+/**
+ * @brief   QEID4 driver enable switch.
+ * @details If set to @p TRUE the support for QEID4 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM4) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM4                  FALSE
+#endif
+
+/**
+ * @brief   QEID5 driver enable switch.
+ * @details If set to @p TRUE the support for QEID5 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM5) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM5                  FALSE
+#endif
+
+/**
+ * @brief   QEID8 driver enable switch.
+ * @details If set to @p TRUE the support for QEID8 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM8) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM8                  FALSE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+#if STM32_QEI_USE_TIM1 && !STM32_HAS_TIM1
+#error "TIM1 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM2 && !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM3 && !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM4 && !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM5 && !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM8 && !STM32_HAS_TIM8
+#error "TIM8 not present in the selected device"
+#endif
+
+#if !STM32_QEI_USE_TIM1 && !STM32_QEI_USE_TIM2 &&                           \
+    !STM32_QEI_USE_TIM3 && !STM32_QEI_USE_TIM4 &&                           \
+    !STM32_QEI_USE_TIM5 && !STM32_QEI_USE_TIM8
+#error "QEI driver activated but no TIM peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/**
+ * @brief QEI driver mode.
+ */
+typedef enum {
+  QEI_COUNT_BOTH = 0,
+  QEI_COUNT_CH1 = 1,
+  QEI_COUNT_CH2 = 2,
+} qeimode_t;
+
+/**
+ * @brief QEI input mode.
+ */
+typedef enum {
+  QEI_INPUT_NONINVERTED = 0, /**< Input channel noninverted.*/
+  QEI_INPUT_INVERTED = 1, /**< Input channel inverted.*/
+} qeiinputmode_t;
+
+/**
+ * @brief   QEI count type.
+ */
+typedef uint32_t qeicnt_t;
+
+/**
+ * @brief   Driver channel configuration structure.
+ */
+typedef struct {
+  /**
+   * @brief Channel input logic.
+   */
+  qeiinputmode_t                 mode;
+  /* End of the mandatory fields.*/
+} QEIChannelConfig;
+
+/**
+ * @brief   Driver configuration structure.
+ */
+typedef struct {
+  /**
+   * @brief   Driver mode.
+   */
+  qeimode_t                 mode;
+  /**
+   * @brief   Channels configurations.
+   */
+  QEIChannelConfig          channels[QEI_CHANNELS];
+  /**
+   * @brief   Range in pulses.
+   */
+  qeicnt_t                  range;
+  /* End of the mandatory fields.*/
+} QEIConfig;
+
+/**
+ * @brief   Structure representing an QEI driver.
+ */
+struct QEIDriver {
+  /**
+   * @brief Driver state.
+   */
+  qeistate_t                state;
+  /**
+   * @brief Current configuration data.
+   */
+  const QEIConfig           *config;
+#if defined(QEI_DRIVER_EXT_FIELDS)
+  QEI_DRIVER_EXT_FIELDS
+#endif
+  /* End of the mandatory fields.*/
+  /**
+   * @brief Pointer to the TIMx registers block.
+   */
+  stm32_tim_t               *tim;
+};
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/**
+ * @brief   Returns the direction of the last transition.
+ * @details The direction is defined as boolean and is
+ *          calculated at each transition on any input.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The request direction.
+ * @retval FALSE        Position counted up.
+ * @retval TRUE         Position counted down.
+ *
+ * @iclass
+ */
+#define qei_lld_get_direction(qeip) !!((qeip)->tim->CR1 & TIM_CR1_DIR)
+
+/**
+ * @brief   Returns the position of the encoder.
+ * @details The position is defined as number of pulses since last reset.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The number of pulses.
+ *
+ * @iclass
+ */
+#define qei_lld_get_position(qeip) ((qeip)->tim->CNT)
+
+/**
+ * @brief   Returns the range of the encoder.
+ * @details The range is defined as number of maximum pulse count.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The number of pulses.
+ *
+ * @iclass
+ */
+#define qei_lld_get_range(qeip) ((qeip)->tim->ARR + 1)
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if STM32_QEI_USE_TIM1 && !defined(__DOXYGEN__)
+extern QEIDriver QEID1;
+#endif
+
+#if STM32_QEI_USE_TIM2 && !defined(__DOXYGEN__)
+extern QEIDriver QEID2;
+#endif
+
+#if STM32_QEI_USE_TIM3 && !defined(__DOXYGEN__)
+extern QEIDriver QEID3;
+#endif
+
+#if STM32_QEI_USE_TIM4 && !defined(__DOXYGEN__)
+extern QEIDriver QEID4;
+#endif
+
+#if STM32_QEI_USE_TIM5 && !defined(__DOXYGEN__)
+extern QEIDriver QEID5;
+#endif
+
+#if STM32_QEI_USE_TIM8 && !defined(__DOXYGEN__)
+extern QEIDriver QEID8;
+#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/src/hal_qei.c b/os/hal/src/hal_qei.c
new file mode 100644
index 0000000..00334bb
--- /dev/null
+++ b/os/hal/src/hal_qei.c
@@ -0,0 +1,152 @@
+/*
+AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file    hal_qei.c
+ * @brief   QEI Driver code.
+ *
+ * @addtogroup QEI
+ * @{
+ */
+
+#include "hal.h"
+
+#if (HAL_USE_QEI == TRUE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   QEI Driver initialization.
+ * @note    This function is implicitly invoked by @p halInit(), there is
+ *          no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void qeiInit(void) {
+
+  qei_lld_init();
+}
+
+/**
+ * @brief   Initializes the standard part of a @p QEIDriver structure.
+ *
+ * @param[out] qeip     pointer to the @p QEIDriver object
+ *
+ * @init
+ */
+void qeiObjectInit(QEIDriver *qeip) {
+
+  qeip->state  = QEI_STOP;
+  qeip->config = NULL;
+}
+
+/**
+ * @brief   Configures and activates the QEI peripheral.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @param[in] config    pointer to the @p QEIConfig object
+ *
+ * @api
+ */
+void qeiStart(QEIDriver *qeip, const QEIConfig *config) {
+
+  osalDbgCheck((qeip != NULL) && (config != NULL));
+
+  osalSysLock();
+  osalDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY), "invalid state");
+  qeip->config = config;
+  qei_lld_start(qeip);
+  qeip->state = QEI_READY;
+  osalSysUnlock();
+}
+
+/**
+ * @brief   Deactivates the QEI peripheral.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @api
+ */
+void qeiStop(QEIDriver *qeip) {
+
+  osalDbgCheck(qeip != NULL);
+
+  osalSysLock();
+  osalDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY), "invalid state");
+  qei_lld_stop(qeip);
+  qeip->state = QEI_STOP;
+  osalSysUnlock();
+}
+
+/**
+ * @brief   Enables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @api
+ */
+void qeiEnable(QEIDriver *qeip) {
+
+  osalDbgCheck(qeip != NULL);
+
+  osalSysLock();
+  osalDbgAssert(qeip->state == QEI_READY, "invalid state");
+  qei_lld_enable(qeip);
+  qeip->state = QEI_ACTIVE;
+  osalSysUnlock();
+}
+
+/**
+ * @brief   Disables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @api
+ */
+void qeiDisable(QEIDriver *qeip) {
+
+  osalDbgCheck(qeip != NULL);
+
+  osalSysLock();
+  osalDbgAssert((qeip->state == QEI_READY) || (qeip->state == QEI_ACTIVE), "invalid state");
+  qei_lld_disable(qeip);
+  qeip->state = QEI_READY;
+  osalSysUnlock();
+}
+
+#endif /* HAL_USE_QEI */
+
+/** @} */

User avatar
Giovanni
Site Admin
Posts: 11472
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 450 times
Been thanked: 375 times
Contact:

Re: incremental (quadrature) encoder interface and LLD

Postby Giovanni » Sun Jan 06, 2019 5:11 pm

bump


Return to “Small Change Requests”

Who is online

Users browsing this forum: No registered users and 0 guests