diff --git a/arch/arm/src/stm32/stm32_qencoder.c b/arch/arm/src/stm32/stm32_qencoder.c index 7d87debe33..69b0f9b2e0 100644 --- a/arch/arm/src/stm32/stm32_qencoder.c +++ b/arch/arm/src/stm32/stm32_qencoder.c @@ -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; } diff --git a/arch/arm/src/stm32l4/stm32l4_qencoder.c b/arch/arm/src/stm32l4/stm32l4_qencoder.c index 7c9426de29..19436b2e18 100644 --- a/arch/arm/src/stm32l4/stm32l4_qencoder.c +++ b/arch/arm/src/stm32l4/stm32l4_qencoder.c @@ -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; } diff --git a/configs/nucleo-f4x1re/include/board.h b/configs/nucleo-f4x1re/include/board.h index 8580b8045a..888e79c9a5 100644 --- a/configs/nucleo-f4x1re/include/board.h +++ b/configs/nucleo-f4x1re/include/board.h @@ -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 ************************************************************************************/ diff --git a/configs/nucleo-f4x1re/src/Makefile b/configs/nucleo-f4x1re/src/Makefile index c5d250f03d..7778dd7f00 100644 --- a/configs/nucleo-f4x1re/src/Makefile +++ b/configs/nucleo-f4x1re/src/Makefile @@ -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 diff --git a/configs/nucleo-f4x1re/src/stm32_qencoder.c b/configs/nucleo-f4x1re/src/stm32_qencoder.c new file mode 100644 index 0000000000..6d72932844 --- /dev/null +++ b/configs/nucleo-f4x1re/src/stm32_qencoder.c @@ -0,0 +1,158 @@ +/************************************************************************************ + * configs/stm32f4discovery/src/stm32_qencoder.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include + +#include +#include + +#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 */ diff --git a/configs/nucleo-l476rg/include/board.h b/configs/nucleo-l476rg/include/board.h index f9ca1ada74..a7a983221d 100644 --- a/configs/nucleo-l476rg/include/board.h +++ b/configs/nucleo-l476rg/include/board.h @@ -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 ************************************************************************************/ diff --git a/configs/nucleo-l476rg/src/Makefile b/configs/nucleo-l476rg/src/Makefile index 46faa0d565..771a34ffd6 100644 --- a/configs/nucleo-l476rg/src/Makefile +++ b/configs/nucleo-l476rg/src/Makefile @@ -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 diff --git a/configs/nucleo-l476rg/src/stm32_qencoder.c b/configs/nucleo-l476rg/src/stm32_qencoder.c new file mode 100644 index 0000000000..308b674477 --- /dev/null +++ b/configs/nucleo-l476rg/src/stm32_qencoder.c @@ -0,0 +1,161 @@ +/************************************************************************************ + * configs/nucleo-l476rg/src/stm32_qencoder.c + * + * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Copyright (C) 2016 Sebastien Lorquet. All rights reserved. + * Author: Sebastien Lorquet + * + * 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 + +#include +#include + +#include +#include + +#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 */