Add support for qencoders on various nucleo boards

This commit is contained in:
Sebastien Lorquet 2016-10-03 16:07:20 +02:00
parent 06c70129ed
commit 9dcecd4b15
8 changed files with 370 additions and 25 deletions

View File

@ -1029,6 +1029,8 @@ static int stm32_setup(FAR struct qe_lowerhalf_s *lower)
cr1 |= GTIM_CR1_CEN;
stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1);
stm32_dumpregs(priv, "After setup");
return OK;
}

View File

@ -579,26 +579,27 @@ static void stm32l4_dumpregs(FAR struct stm32l4_lowerhalf_s *priv,
FAR const char *msg)
{
sninfo("%s:\n", msg);
sninfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n",
sninfo(" CR1: %04x CR2: %04x SMCR: %08x DIER: %04x\n",
stm32l4_getreg16(priv, STM32L4_GTIM_CR1_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_CR2_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_SMCR_OFFSET),
stm32l4_getreg32(priv, STM32L4_GTIM_SMCR_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_DIER_OFFSET));
sninfo(" SR: %04x EGR: %04x CCMR1: %04x CCMR2: %04x\n",
sninfo(" SR: %04x EGR: %04x CCMR1: %08x CCMR2: %08x\n",
stm32l4_getreg16(priv, STM32L4_GTIM_SR_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_EGR_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_CCMR1_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_CCMR2_OFFSET));
sninfo(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n",
stm32l4_getreg32(priv, STM32L4_GTIM_CCMR1_OFFSET),
stm32l4_getreg32(priv, STM32L4_GTIM_CCMR2_OFFSET));
sninfo(" CCER: %04x CNT: %08x PSC: %04x ARR: %08x\n",
stm32l4_getreg16(priv, STM32L4_GTIM_CCER_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_CNT_OFFSET),
stm32l4_getreg32(priv, STM32L4_GTIM_CNT_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_PSC_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_ARR_OFFSET));
sninfo(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n",
stm32l4_getreg16(priv, STM32L4_GTIM_CCR1_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_CCR2_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_CCR3_OFFSET),
stm32l4_getreg16(priv, STM32L4_GTIM_CCR4_OFFSET));
stm32l4_getreg32(priv, STM32L4_GTIM_ARR_OFFSET));
sninfo(" CCR1: %08x CCR2: %08x\n",
stm32l4_getreg32(priv, STM32L4_GTIM_CCR1_OFFSET),
stm32l4_getreg32(priv, STM32L4_GTIM_CCR2_OFFSET));
sninfo(" CCR3: %08x CCR4: %08x\n",
stm32l4_getreg32(priv, STM32L4_GTIM_CCR3_OFFSET),
stm32l4_getreg32(priv, STM32L4_GTIM_CCR4_OFFSET));
#if defined(CONFIG_STM32L4_TIM1_QE) || defined(CONFIG_STM32L4_TIM8_QE)
if (priv->config->timid == 1 || priv->config->timid == 8)
{
@ -764,8 +765,8 @@ static int stm32l4_setup(FAR struct qe_lowerhalf_s *lower)
{
FAR struct stm32l4_lowerhalf_s *priv = (FAR struct stm32l4_lowerhalf_s *)lower;
uint16_t dier;
uint16_t smcr;
uint16_t ccmr1;
uint32_t smcr;
uint32_t ccmr1;
uint16_t ccer;
uint16_t cr1;
#ifdef HAVE_16BIT_TIMERS
@ -833,10 +834,10 @@ static int stm32l4_setup(FAR struct qe_lowerhalf_s *lower)
/* Set the encoder Mode 3 */
smcr = stm32l4_getreg16(priv, STM32L4_GTIM_SMCR_OFFSET);
smcr = stm32l4_getreg32(priv, STM32L4_GTIM_SMCR_OFFSET);
smcr &= ~GTIM_SMCR_SMS_MASK;
smcr |= GTIM_SMCR_ENCMD3;
stm32l4_putreg16(priv, STM32L4_GTIM_SMCR_OFFSET, smcr);
stm32l4_putreg32(priv, STM32L4_GTIM_SMCR_OFFSET, smcr);
/* TI1 Channel Configuration */
/* Disable the Channel 1: Reset the CC1E Bit */
@ -845,7 +846,7 @@ static int stm32l4_setup(FAR struct qe_lowerhalf_s *lower)
ccer &= ~GTIM_CCER_CC1E;
stm32l4_putreg16(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
ccmr1 = stm32l4_getreg16(priv, STM32L4_GTIM_CCMR1_OFFSET);
ccmr1 = stm32l4_getreg32(priv, STM32L4_GTIM_CCMR1_OFFSET);
ccer = stm32l4_getreg16(priv, STM32L4_GTIM_CCER_OFFSET);
/* Select the Input IC1=TI1 and set the filter fSAMPLING=fDTS/4, N=6 */
@ -861,17 +862,17 @@ static int stm32l4_setup(FAR struct qe_lowerhalf_s *lower)
/* Write to TIM CCMR1 and CCER registers */
stm32l4_putreg16(priv, STM32L4_GTIM_CCMR1_OFFSET, ccmr1);
stm32l4_putreg32(priv, STM32L4_GTIM_CCMR1_OFFSET, ccmr1);
stm32l4_putreg16(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
/* Set the Input Capture Prescaler value: Capture performed each time an
* edge is detected on the capture input.
*/
ccmr1 = stm32l4_getreg16(priv, STM32L4_GTIM_CCMR1_OFFSET);
ccmr1 = stm32l4_getreg32(priv, STM32L4_GTIM_CCMR1_OFFSET);
ccmr1 &= ~GTIM_CCMR1_IC1PSC_MASK;
ccmr1 |= (GTIM_CCMR_ICPSC_NOPSC << GTIM_CCMR1_IC1PSC_SHIFT);
stm32l4_putreg16(priv, STM32L4_GTIM_CCMR1_OFFSET, ccmr1);
stm32l4_putreg32(priv, STM32L4_GTIM_CCMR1_OFFSET, ccmr1);
/* TI2 Channel Configuration */
/* Disable the Channel 2: Reset the CC2E Bit */
@ -880,7 +881,7 @@ static int stm32l4_setup(FAR struct qe_lowerhalf_s *lower)
ccer &= ~GTIM_CCER_CC2E;
stm32l4_putreg16(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
ccmr1 = stm32l4_getreg16(priv, STM32L4_GTIM_CCMR1_OFFSET);
ccmr1 = stm32l4_getreg32(priv, STM32L4_GTIM_CCMR1_OFFSET);
ccer = stm32l4_getreg16(priv, STM32L4_GTIM_CCER_OFFSET);
/* Select the Input IC2=TI2 and set the filter fSAMPLING=fDTS/4, N=6 */
@ -896,17 +897,17 @@ static int stm32l4_setup(FAR struct qe_lowerhalf_s *lower)
/* Write to TIM CCMR1 and CCER registers */
stm32l4_putreg16(priv, STM32L4_GTIM_CCMR1_OFFSET, ccmr1);
stm32l4_putreg32(priv, STM32L4_GTIM_CCMR1_OFFSET, ccmr1);
stm32l4_putreg16(priv, STM32L4_GTIM_CCER_OFFSET, ccer);
/* Set the Input Capture Prescaler value: Capture performed each time an
* edge is detected on the capture input.
*/
ccmr1 = stm32l4_getreg16(priv, STM32L4_GTIM_CCMR1_OFFSET);
ccmr1 = stm32l4_getreg32(priv, STM32L4_GTIM_CCMR1_OFFSET);
ccmr1 &= ~GTIM_CCMR1_IC2PSC_MASK;
ccmr1 |= (GTIM_CCMR_ICPSC_NOPSC << GTIM_CCMR1_IC2PSC_SHIFT);
stm32l4_putreg16(priv, STM32L4_GTIM_CCMR1_OFFSET, ccmr1);
stm32l4_putreg32(priv, STM32L4_GTIM_CCMR1_OFFSET, ccmr1);
/* Disable the update interrupt */
@ -973,6 +974,8 @@ static int stm32l4_setup(FAR struct qe_lowerhalf_s *lower)
cr1 |= GTIM_CR1_CEN;
stm32l4_putreg16(priv, STM32L4_GTIM_CR1_OFFSET, cr1);
stm32l4_dumpregs(priv, "After setup");
return OK;
}

View File

@ -216,6 +216,9 @@
#define BUTTON_USER_BIT (1 << BUTTON_USER)
#define GPIO_TIM2_CH1IN (GPIO_TIM2_CH1IN_1 | GPIO_PULLUP)
#define GPIO_TIM2_CH2IN (GPIO_TIM2_CH2IN_1 | GPIO_PULLUP)
/************************************************************************************
* Public Data
************************************************************************************/

View File

@ -62,6 +62,10 @@ CSRCS += stm32_ajoystick.c
endif
endif
ifeq ($(CONFIG_QENCODER),y)
CSRCS += stm32_qencoder.c
endif
ifeq ($(CONFIG_NSH_LIBRARY),y)
CSRCS += stm32_appinit.c
endif

View File

@ -0,0 +1,158 @@
/************************************************************************************
* configs/stm32f4discovery/src/stm32_qencoder.c
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
/************************************************************************************
* Included Files
************************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/sensors/qencoder.h>
#include <arch/board/board.h>
#include "chip.h"
#include "up_arch.h"
#include "stm32_qencoder.h"
#include "nucleo-f4x1re.h"
/************************************************************************************
* Pre-processor Definitions
************************************************************************************/
/* Configuration *******************************************************************/
/* Check if we have a timer configured for quadrature encoder -- assume YES. */
#define HAVE_QENCODER 1
/* If TIMn is not enabled (via CONFIG_STM32_TIMn), then the configuration cannot
* specify TIMn as a quadrature encoder (via CONFIG_STM32_TIMn_QE).
*/
#ifndef CONFIG_STM32_TIM1
# undef CONFIG_STM32_TIM1_QE
#endif
#ifndef CONFIG_STM32_TIM2
# undef CONFIG_STM32_TIM2_QE
#endif
#ifndef CONFIG_STM32_TIM3
# undef CONFIG_STM32_TIM3_QE
#endif
#ifndef CONFIG_STM32_TIM4
# undef CONFIG_STM32_TIM4_QE
#endif
#ifndef CONFIG_STM32_TIM5
# undef CONFIG_STM32_TIM5_QE
#endif
#ifndef CONFIG_STM32_TIM8
# undef CONFIG_STM32_TIM8_QE
#endif
/* If the upper-half quadrature encoder driver is not enabled, then we cannot
* support the quadrature encoder.
*/
#ifndef CONFIG_QENCODER
# undef HAVE_QENCODER
#endif
/* Which Timer should we use, TIMID={1,2,3,4,5,8}. If multiple timers are
* configured as quadrature encoders, this logic will arbitrarily select
* the lowest numbered timer.
*
* At least one TIMn, n={1,2,3,4,5,8}, must be both enabled and configured
* as a quadrature encoder in order to support the lower half quadrature
* encoder driver. The above check assures that if CONFIG_STM32_TIMn_QE
* is defined, then the correspdonding TIMn is also enabled.
*/
#if defined CONFIG_STM32_TIM1_QE
# define TIMID 1
#elif defined CONFIG_STM32_TIM2_QE
# define TIMID 2
#elif defined CONFIG_STM32_TIM3_QE
# define TIMID 3
#elif defined CONFIG_STM32_TIM4_QE
# define TIMID 4
#elif defined CONFIG_STM32_TIM5_QE
# define TIMID 5
#elif defined CONFIG_STM32_TIM8_QE
# define TIMID 8
#else
# undef HAVE_QENCODER
#endif
#ifdef HAVE_QENCODER
/************************************************************************************
* Public Functions
************************************************************************************/
/************************************************************************************
* Name: qe_devinit
*
* Description:
* All STM32 architectures must provide the following interface to work with
* examples/qencoder.
*
************************************************************************************/
int qe_devinit(void)
{
static bool initialized = false;
int ret;
/* Check if we are already initialized */
if (!initialized)
{
/* Initialize a quadrature encoder interface. */
sninfo("Initializing the quadrature encoder using TIM%d\n", TIMID);
ret = stm32_qeinitialize("/dev/qe0", TIMID);
if (ret < 0)
{
snerr("ERROR: stm32_qeinitialize failed: %d\n", ret);
return ret;
}
initialized = true;
}
return OK;
}
#endif /* HAVE_QENCODER */

View File

@ -202,6 +202,16 @@
#define BUTTON_USER_BIT (1 << BUTTON_USER)
/* Quadrature encoder
* Default is to use timer 5 (32-bit) and encoder on PA0/PA1
*/
#define GPIO_TIM5_CH1IN GPIO_TIM5_CH1IN_1
#define GPIO_TIM5_CH2IN GPIO_TIM5_CH2IN_1
#define GPIO_TIM2_CH1IN GPIO_TIM2_CH1IN_1
#define GPIO_TIM2_CH2IN GPIO_TIM2_CH2IN_1
/************************************************************************************
* Public Data
************************************************************************************/

View File

@ -62,6 +62,10 @@ CSRCS += stm32_ajoystick.c
endif
endif
ifeq ($(CONFIG_QENCODER),y)
CSRCS += stm32_qencoder.c
endif
ifeq ($(CONFIG_LIB_BOARDCTL),y)
CSRCS += stm32_appinit.c
endif

View File

@ -0,0 +1,161 @@
/************************************************************************************
* configs/nucleo-l476rg/src/stm32_qencoder.c
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Copyright (C) 2016 Sebastien Lorquet. All rights reserved.
* Author: Sebastien Lorquet <sebastien@lorquet.fr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
/************************************************************************************
* Included Files
************************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/sensors/qencoder.h>
#include <arch/board/board.h>
#include "chip.h"
#include "up_arch.h"
#include "stm32l4_qencoder.h"
#include "nucleo-l476rg.h"
/************************************************************************************
* Pre-processor Definitions
************************************************************************************/
/* Configuration *******************************************************************/
/* Check if we have a timer configured for quadrature encoder -- assume YES. */
#define HAVE_QENCODER 1
/* If TIMn is not enabled (via CONFIG_STM32L4_TIMn), then the configuration cannot
* specify TIMn as a quadrature encoder (via CONFIG_STM32L4_TIMn_QE).
*/
#ifndef CONFIG_STM32L4_TIM1
# undef CONFIG_STM32L4_TIM1_QE
#endif
#ifndef CONFIG_STM32L4_TIM2
# undef CONFIG_STM32L4_TIM2_QE
#endif
#ifndef CONFIG_STM32L4_TIM3
# undef CONFIG_STM32L4_TIM3_QE
#endif
#ifndef CONFIG_STM32L4_TIM4
# undef CONFIG_STM32L4_TIM4_QE
#endif
#ifndef CONFIG_STM32L4_TIM5
# undef CONFIG_STM32L4_TIM5_QE
#endif
#ifndef CONFIG_STM32L4_TIM8
# undef CONFIG_STM32L4_TIM8_QE
#endif
/* If the upper-half quadrature encoder driver is not enabled, then we cannot
* support the quadrature encoder.
*/
#ifndef CONFIG_QENCODER
# undef HAVE_QENCODER
#endif
/* Which Timer should we use, TIMID={1,2,3,4,5,8}. If multiple timers are
* configured as quadrature encoders, this logic will arbitrarily select
* the lowest numbered timer.
*
* At least one TIMn, n={1,2,3,4,5,8}, must be both enabled and configured
* as a quadrature encoder in order to support the lower half quadrature
* encoder driver. The above check assures that if CONFIG_STM32L4_TIMn_QE
* is defined, then the correspdonding TIMn is also enabled.
*/
#if defined CONFIG_STM32L4_TIM1_QE
# define TIMID 1
#elif defined CONFIG_STM32L4_TIM2_QE
# define TIMID 2
#elif defined CONFIG_STM32L4_TIM3_QE
# define TIMID 3
#elif defined CONFIG_STM32L4_TIM4_QE
# define TIMID 4
#elif defined CONFIG_STM32L4_TIM5_QE
# define TIMID 5
#elif defined CONFIG_STM32L4_TIM8_QE
# define TIMID 8
#else
# undef HAVE_QENCODER
#endif
#ifdef HAVE_QENCODER
/************************************************************************************
* Public Functions
************************************************************************************/
/************************************************************************************
* Name: qe_devinit
*
* Description:
* All STM32L4 architectures must provide the following interface to work with
* examples/qencoder.
*
************************************************************************************/
int qe_devinit(void)
{
static bool initialized = false;
int ret;
/* Check if we are already initialized */
if (!initialized)
{
/* Initialize a quadrature encoder interface. */
sninfo("Initializing the quadrature encoder using TIM%d\n", TIMID);
ret = stm32l4_qeinitialize("/dev/qe0", TIMID);
if (ret < 0)
{
snerr("ERROR: stm32_qeinitialize failed: %d\n", ret);
return ret;
}
initialized = true;
}
return OK;
}
#endif /* HAVE_QENCODER */