/* * Copyright (C) 2017 Gilles DOFFE * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @defgroup drivers_periph_qdec Quadrature Decoder (QDEC) * @ingroup drivers_periph * @brief Low-level QDEC peripheral driver * * This file was inspired by pwm.h written by : * Hauke Petersen * * QDEC interface enables access to CPU peripherals acquiring quadrature * signals. On most platforms, this interface will be implemented based * on hardware timers. * * A quadrature encoder outputs two wave forms that are 90 degrees * out of phase. * * @verbatim * * Clockwise (C) : Counter-clockwise (CC) : * ___________________ ___________________ * | Phase | A | B | | Phase | A | B | * |-------------------| |-------------------| * | 1 | 0 | 0 | | 1 | 0 | 0 | * |-------------------| |-------------------| * | 2 | 0 | 1 | | 2 | 1 | 0 | * |-------------------| |-------------------| * | 3 | 1 | 1 | | 3 | 1 | 1 | * |-------------------| |-------------------| * | 4 | 1 | 0 | | 4 | 0 | 1 | * ------------------- ------------------- * __ __ __ __ * __| |__| |_ _| |__| |__ * __ __ __ __ * _| |__| |__ __| |__| |_ * * These signals are decoded to produce a count up or a count down. * On rising or falling edge of one signal, other signal state is checked to * determine direction. * * 1. Rising edge on A and signal B is up => (C) => increment counter * 2. Rising edge on A and signal B is down => (CC) => decrement counter * 3. Falling edge on A and signal B is up => (C) => decrement counter * 4. Falling edge on A and signal B is down => (CC) => increment counter * 5. Rising edge on B and signal A is up => (C) => decrement counter * 6. Rising edge on B and signal A is down => (CC) => increment counter * 7. Falling edge on B and signal A is up => (C) => increment counter * 8. Falling edge on B and signal A is down => (CC) => decrement counter * @endverbatim * * According to these cases, three modes are available : * - X1 mode : signal A, rising edges (cases 1 and 2) * - X2 mode : signal A, rising and falling edges (cases 1, 2, 3 and 4) * - X4 mode : signals A and B, rising and falling edges (all cases) * * The mapping/configuration of QDEC devices (timers) and the used pins has to be * done in the board configuration (the board's `periph_conf.h). * * When using the QDEC interface, first thing you have to do is initialize the * QDEC device with the targeted mode. Once the device is initialized, * it will start counting quadrature signals on all configured pins * immediately. * * @{ * @file * @brief Low-level QDEC peripheral driver interface definitions * * @author Gilles DOFFE */ #ifndef PERIPH_QDEC_H #define PERIPH_QDEC_H #include #include #include "periph_cpu.h" #include "periph_conf.h" #ifdef __cplusplus extern "C" { #endif /** * @brief Default QDEC access macro */ #ifndef QDEC_DEV #define QDEC_DEV(x) (x) #endif /** * @brief Default QDEC undefined value */ #ifndef QDEC_UNDEF #define QDEC_UNDEF (UINT_FAST8_MAX) #endif /** * @brief Default QDEC type definition */ #ifndef HAVE_QDEC_T typedef uint_fast8_t qdec_t; #endif /** * @brief Default QDEC mode definition */ #ifndef HAVE_QDEC_MODE_T typedef enum { QDEC_X1, /* X1 mode */ QDEC_X2, /* X2 mode */ QDEC_X4, /* X4 mode */ } qdec_mode_t; #endif /** * @brief Signature of event callback functions triggered from interrupts * * @param[in] arg optional context for the callback */ typedef void (*qdec_cb_t)(void *arg); /** * @brief Default interrupt context entry holding callback and argument */ #ifndef HAVE_TIMER_ISR_CTX_T typedef struct { qdec_cb_t cb; /**< callback executed from qdec interrupt */ void *arg; /**< optional argument given to that callback */ } qdec_isr_ctx_t; #endif /** * @brief Initialize a QDEC device * * The QDEC module is based on virtual QDEC devices. * The QDEC devices can be configured to run in three modes : * - X1 * - X2 * - X4 * See description above for more details about modes. * * On QDEC counter overflow, an interrupt is triggered. * The interruption calls the callback defined. * * @param[in] dev QDEC device to initialize * @param[in] mode QDEC mode : X1, X2 or X4 * @param[in] cb Callback on QDEC timer overflow * @param[in] arg Callback arguments * * @return error code on error * @return 0 on success */ int32_t qdec_init(qdec_t dev, qdec_mode_t mode, qdec_cb_t cb, void *arg); /** * @brief Read the current value of the given qdec device * * @param[in] dev the qdec to read the current value from * * @return the qdecs current value */ int32_t qdec_read(qdec_t dev); /** * @brief Read the current value of the given qdec device and reset it * * @param[in] dev the qdec to read the current value from * * @return the qdecs current value */ int32_t qdec_read_and_reset(qdec_t dev); /** * @brief Start the given qdec timer * * This function is only needed if the qdec timer was stopped manually before. * * @param[in] qdec the qdec device to start */ void qdec_start(qdec_t qdec); /** * @brief Stop the given qdec timer * * This will effect all of the timer's channels. * * @param[in] qdec the qdec device to stop */ void qdec_stop(qdec_t qdec); #ifdef __cplusplus } #endif #endif /* PERIPH_QDEC_H */ /** @} */