From 056eebd9dac50f88050ec43d5c40c28dd0f80c5a Mon Sep 17 00:00:00 2001 From: Eduard Niesner Date: Thu, 27 Jun 2019 07:00:50 -0600 Subject: [PATCH] arch/arm/src/stm32h7: Ported the QEncoder from F7 to H7. --- arch/arm/src/stm32h7/Kconfig | 177 ++++ arch/arm/src/stm32h7/Make.defs | 4 + arch/arm/src/stm32h7/stm32_qencoder.c | 1177 +++++++++++++++++++++++++ arch/arm/src/stm32h7/stm32_qencoder.h | 143 +++ configs/makerlisp/README.txt | 2 +- libs/libc/misc/lib_debug.c | 2 +- 6 files changed, 1503 insertions(+), 2 deletions(-) create mode 100644 arch/arm/src/stm32h7/stm32_qencoder.c create mode 100644 arch/arm/src/stm32h7/stm32_qencoder.h diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig index b200160418..02570a7c56 100644 --- a/arch/arm/src/stm32h7/Kconfig +++ b/arch/arm/src/stm32h7/Kconfig @@ -4229,4 +4229,181 @@ config STM32H7_ETHMAC_REGDEBUG endmenu # Ethernet MAC configuration +menu "QEncoder Driver" + depends on SENSORS_QENCODER + depends on STM32H7_TIM1 || STM32H7_TIM2 || STM32H7_TIM3 || STM32H7_TIM4 || STM32H7_TIM5 || STM32H7_TIM8 + +config STM32H7_TIM1_QE + bool "TIM1" + default n + depends on STM32H7_TIM1 + ---help--- + Reserve TIM1 for use by QEncoder. + +if STM32H7_TIM1_QE + +config STM32H7_TIM1_QEPSC + int "TIM1 pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config STM32H7_TIM2_QE + bool "TIM2" + default n + depends on STM32H7_TIM2 + ---help--- + Reserve TIM2 for use by QEncoder. + +if STM32H7_TIM2_QE + +config STM32H7_TIM2_QEPSC + int "TIM2 pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config STM32H7_TIM3_QE + bool "TIM3" + default n + depends on STM32H7_TIM3 + ---help--- + Reserve TIM3 for use by QEncoder. + +if STM32H7_TIM3_QE + +config STM32H7_TIM3_QEPSC + int "TIM3 pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config STM32H7_TIM4_QE + bool "TIM4" + default n + depends on STM32H7_TIM4 + ---help--- + Reserve TIM4 for use by QEncoder. + +if STM32H7_TIM4_QE + +config STM32H7_TIM4_QEPSC + int "TIM4 pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config STM32H7_TIM5_QE + bool "TIM5" + default n + depends on STM32H7_TIM5 + ---help--- + Reserve TIM5 for use by QEncoder. + +if STM32H7_TIM5_QE + +config STM32H7_TIM5_QEPSC + int "TIM5 pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config STM32H7_TIM8_QE + bool "TIM8" + default n + depends on STM32H7_TIM8 + ---help--- + Reserve TIM8 for use by QEncoder. + +if STM32H7_TIM8_QE + +config STM32H7_TIM8_QEPSC + int "TIM8 pulse prescaler" + default 1 + ---help--- + This prescaler divides the number of recorded encoder pulses, + limiting the count rate at the expense of resolution. + +endif + +config STM32H7_QENCODER_FILTER + bool "Enable filtering on STM32 QEncoder input" + default y + +choice + depends on STM32H7_QENCODER_FILTER + prompt "Input channel sampling frequency" + default STM32H7_QENCODER_SAMPLE_FDTS_4 + +config STM32H7_QENCODER_SAMPLE_FDTS + bool "fDTS" + +config STM32H7_QENCODER_SAMPLE_CKINT + bool "fCK_INT" + +config STM32H7_QENCODER_SAMPLE_FDTS_2 + bool "fDTS/2" + +config STM32H7_QENCODER_SAMPLE_FDTS_4 + bool "fDTS/4" + +config STM32H7_QENCODER_SAMPLE_FDTS_8 + bool "fDTS/8" + +config STM32H7_QENCODER_SAMPLE_FDTS_16 + bool "fDTS/16" + +config STM32H7_QENCODER_SAMPLE_FDTS_32 + bool "fDTS/32" + +endchoice + +choice + depends on STM32H7_QENCODER_FILTER + prompt "Input channel event count" + default STM32H7_QENCODER_SAMPLE_EVENT_6 + +config STM32H7_QENCODER_SAMPLE_EVENT_1 + depends on STM32H7_QENCODER_SAMPLE_FDTS + bool "1" + +config STM32H7_QENCODER_SAMPLE_EVENT_2 + depends on STM32H7_QENCODER_SAMPLE_CKINT + bool "2" + +config STM32H7_QENCODER_SAMPLE_EVENT_4 + depends on STM32H7_QENCODER_SAMPLE_CKINT + bool "4" + +config STM32H7_QENCODER_SAMPLE_EVENT_5 + depends on STM32H7_QENCODER_SAMPLE_FDTS_16 || STM32H7_QENCODER_SAMPLE_FDTS_32 + bool "5" + +config STM32H7_QENCODER_SAMPLE_EVENT_6 + depends on !STM32H7_QENCODER_SAMPLE_FDTS && !STM32H7_QENCODER_SAMPLE_CKINT + bool "6" + +config STM32H7_QENCODER_SAMPLE_EVENT_8 + depends on !STM32H7_QENCODER_SAMPLE_FDTS + bool "8" + +endchoice + +endmenu + endif # ARCH_CHIP_STM32H7 diff --git a/arch/arm/src/stm32h7/Make.defs b/arch/arm/src/stm32h7/Make.defs index dd12df7245..efaaac71e5 100644 --- a/arch/arm/src/stm32h7/Make.defs +++ b/arch/arm/src/stm32h7/Make.defs @@ -141,3 +141,7 @@ endif ifeq ($(CONFIG_STM32H7_ETHMAC),y) CHIP_CSRCS += stm32_ethernet.c endif + +ifeq ($(CONFIG_SENSORS_QENCODER),y) +CHIP_CSRCS += stm32_qencoder.c +endif diff --git a/arch/arm/src/stm32h7/stm32_qencoder.c b/arch/arm/src/stm32h7/stm32_qencoder.c new file mode 100644 index 0000000000..41d56c244a --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_qencoder.c @@ -0,0 +1,1177 @@ +/************************************************************************************ + * arch/arm/src/stm32h7/stm32_qencoder.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Authors: 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 +#include +#include + +#include + +#include "chip.h" +#include "up_internal.h" +#include "up_arch.h" + +#include "stm32_gpio.h" +#include "stm32_tim.h" +#include "stm32_qencoder.h" +#include "stm32_rcc.h" + +#ifdef CONFIG_SENSORS_QENCODER + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +/* Timers ***************************************************************************/ + +#undef HAVE_32BIT_TIMERS +#undef HAVE_16BIT_TIMERS + +/* On the H7 series, TIM2 and TIM5 are 32-bit. All of the rest are 16-bit */ + +/* If TIM2 or TIM5 are enabled, then we have 32-bit timers */ + +#if defined(CONFIG_STM32H7_TIM2_QE) || defined(CONFIG_STM32H7_TIM5_QE) +# define HAVE_32BIT_TIMERS 1 +#endif + +/* If TIM1,3,4, or 8 are enabled, then we have 16-bit timers */ + +#if defined(CONFIG_STM32H7_TIM1_QE) || defined(CONFIG_STM32H7_TIM3_QE) || \ + defined(CONFIG_STM32H7_TIM4_QE) || defined(CONFIG_STM32H7_TIM8_QE) +# define HAVE_16BIT_TIMERS 1 +#endif + +/* The width in bits of each timer */ + +#define TIM1_BITWIDTH 16 +#define TIM2_BITWIDTH 32 +#define TIM3_BITWIDTH 16 +#define TIM4_BITWIDTH 16 +#define TIM5_BITWIDTH 32 +#define TIM8_BITWIDTH 16 + +/* Do we need to support mixed 16- and 32-bit timers */ + +#undef HAVE_MIXEDWIDTH_TIMERS +#if defined(HAVE_16BIT_TIMERS) && defined(HAVE_32BIT_TIMERS) +# define HAVE_MIXEDWIDTH_TIMERS 1 +#endif + +/* Input filter *********************************************************************/ + +#ifdef CONFIG_STM32H7_QENCODER_FILTER +# if defined(CONFIG_STM32H7_QENCODER_SAMPLE_FDTS) +# if defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_1) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_NOFILT +# endif +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_CKINT) +# if defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_2) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FCKINT2 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_4) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FCKINT4 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_8) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FCKINT8 +# endif +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_FDTS_2) +# if defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_6) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd26 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_8) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd28 +# endif +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_FDTS_4) +# if defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_6) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd46 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_8) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd48 +# endif +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_FDTS_8) +# if defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_6) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd86 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_8) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd88 +# endif +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_FDTS_16) +# if defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_5) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd165 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_6) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd166 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_8) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd168 +# endif +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_FDTS_32) +# if defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_5) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd325 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_6) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd326 +# elif defined(CONFIG_STM32H7_QENCODER_SAMPLE_EVENT_8) +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_FDTSd328 +# endif +# endif + +# ifndef STM32_QENCODER_ICF +# warning "Invalid encoder filter combination, filter disabled" +# endif +#endif + +#ifndef STM32_QENCODER_ICF +# define STM32_QENCODER_ICF GTIM_CCMR_ICF_NOFILT +#endif + +#define STM32_GPIO_INPUT_FLOAT (GPIO_INPUT | GPIO_FLOAT) + +/* Debug ****************************************************************************/ + +/* Non-standard debug that may be enabled just for testing the quadrature encoder */ + +#ifndef CONFIG_DEBUG_FEATURES +# undef CONFIG_DEBUG_SENSORS +#endif + +#ifdef CONFIG_DEBUG_SENSORS +# ifdef CONFIG_DEBUG_INFO +# define qe_dumpgpio(p,m) stm32_dumpgpio(p,m) +# else +# define qe_dumpgpio(p,m) +# endif +#else +# define qe_dumpgpio(p,m) +#endif + +/************************************************************************************ + * Private Types + ************************************************************************************/ + +/* Constant configuration structure that is retained in FLASH */ + +struct stm32_qeconfig_s +{ + uint8_t timid; /* Timer ID {1,2,3,4,5,8} */ + uint8_t irq; /* Timer update IRQ */ +#ifdef HAVE_MIXEDWIDTH_TIMERS + uint8_t width; /* Timer width (16- or 32-bits) */ +#endif +#ifdef CONFIG_STM32_STM32F10XX + uint16_t ti1cfg; /* TI1 input pin configuration (16-bit encoding) */ + uint16_t ti2cfg; /* TI2 input pin configuration (16-bit encoding) */ +#else + uint32_t ti1cfg; /* TI1 input pin configuration (20-bit encoding) */ + uint32_t ti2cfg; /* TI2 input pin configuration (20-bit encoding) */ +#endif + uintptr_t regaddr; /* RCC clock enable register address */ + uint32_t enable; /* RCC clock enable bit */ + uint32_t base; /* Register base address */ + uint32_t psc; /* Timer input clock prescaler */ +}; + +/* Overall, RAM-based state structure */ + +struct stm32_lowerhalf_s +{ + /* The first field of this state structure must be a pointer to the lower- + * half callback structure: + */ + + FAR const struct qe_ops_s *ops; /* Lower half callback structure */ + + /* STM32 driver-specific fields: */ + + FAR const struct stm32_qeconfig_s *config; /* static onfiguration */ + + bool inuse; /* True: The lower-half driver is in-use */ + +#ifdef HAVE_16BIT_TIMERS + volatile int32_t position; /* The current position offset */ +#endif +}; + +/************************************************************************************ + * Private Function Prototypes + ************************************************************************************/ + +/* Helper functions */ + +static uint16_t stm32_getreg16(FAR struct stm32_lowerhalf_s *priv, int offset); +static void stm32_putreg16(FAR struct stm32_lowerhalf_s *priv, int offset, + uint16_t value); +static uint32_t stm32_getreg32(FAR struct stm32_lowerhalf_s *priv, int offset); +static void stm32_putreg32(FAR struct stm32_lowerhalf_s *priv, int offset, + uint32_t value); + +#if defined(CONFIG_DEBUG_SENSORS) && defined(CONFIG_DEBUG_INFO) +static void stm32_dumpregs(FAR struct stm32_lowerhalf_s *priv, + FAR const char *msg); +#else +# define stm32_dumpregs(priv,msg) +#endif + +static FAR struct stm32_lowerhalf_s *stm32_tim2lower(int tim); + +/* Interrupt handling */ + +#ifdef HAVE_16BIT_TIMERS +static int stm32_interrupt(int irq, FAR void *context, FAR void *arg); +#endif + +/* Lower-half Quadrature Encoder Driver Methods */ + +static int stm32_setup(FAR struct qe_lowerhalf_s *lower); +static int stm32_shutdown(FAR struct qe_lowerhalf_s *lower); +static int stm32_position(FAR struct qe_lowerhalf_s *lower, FAR int32_t *pos); +static int stm32_reset(FAR struct qe_lowerhalf_s *lower); +static int stm32_ioctl(FAR struct qe_lowerhalf_s *lower, int cmd, + unsigned long arg); + +/************************************************************************************ + * Private Data + ************************************************************************************/ + +/* The lower half callback structure */ + +static const struct qe_ops_s g_qecallbacks = +{ + .setup = stm32_setup, + .shutdown = stm32_shutdown, + .position = stm32_position, + .reset = stm32_reset, + .ioctl = stm32_ioctl, +}; + +/* Per-timer state structures */ + +#ifdef CONFIG_STM32H7_TIM1_QE +static const struct stm32_qeconfig_s g_tim1config = +{ + .timid = 1, + .irq = STM32_IRQ_TIM1UP, +#ifdef HAVE_MIXEDWIDTH_TIMERS + .width = TIM1_BITWIDTH, +#endif + .regaddr = STM32_RCC_APB2ENR, + .enable = RCC_APB2ENR_TIM1EN, + .base = STM32_TIM1_BASE, + .psc = CONFIG_STM32H7_TIM1_QEPSC, + .ti1cfg = GPIO_TIM1_CH1IN, + .ti2cfg = GPIO_TIM1_CH2IN, +}; + +static struct stm32_lowerhalf_s g_tim1lower = +{ + .ops = &g_qecallbacks, + .config = &g_tim1config, + .inuse = false, +}; + +#endif + +#ifdef CONFIG_STM32H7_TIM2_QE +static const struct stm32_qeconfig_s g_tim2config = +{ + .timid = 2, + .irq = STM32_IRQ_TIM2, +#ifdef HAVE_MIXEDWIDTH_TIMERS + .width = TIM2_BITWIDTH, +#endif + .regaddr = STM32_RCC_APB1LENR, + .enable = RCC_APB1LENR_TIM2EN, + .base = STM32_TIM2_BASE, + .psc = CONFIG_STM32H7_TIM2_QEPSC, + .ti1cfg = GPIO_TIM2_CH1IN, + .ti2cfg = GPIO_TIM2_CH2IN, +}; + +static struct stm32_lowerhalf_s g_tim2lower = +{ + .ops = &g_qecallbacks, + .config = &g_tim2config, + .inuse = false, +}; + +#endif + +#ifdef CONFIG_STM32H7_TIM3_QE +static const struct stm32_qeconfig_s g_tim3config = +{ + .timid = 3, + .irq = STM32_IRQ_TIM3, +#ifdef HAVE_MIXEDWIDTH_TIMERS + .width = TIM3_BITWIDTH, +#endif + .regaddr = STM32_RCC_APB1LENR, + .enable = RCC_APB1LENR_TIM3EN, + .base = STM32_TIM3_BASE, + .psc = CONFIG_STM32H7_TIM3_QEPSC, + .ti1cfg = GPIO_TIM3_CH1IN, + .ti2cfg = GPIO_TIM3_CH2IN, +}; + +static struct stm32_lowerhalf_s g_tim3lower = +{ + .ops = &g_qecallbacks, + .config = &g_tim3config, + .inuse = false, +}; + +#endif + +#ifdef CONFIG_STM32H7_TIM4_QE +static const struct stm32_qeconfig_s g_tim4config = +{ + .timid = 4, + .irq = STM32_IRQ_TIM4, +#ifdef HAVE_MIXEDWIDTH_TIMERS + .width = TIM4_BITWIDTH, +#endif + .regaddr = STM32_RCC_APB1LENR, + .enable = RCC_APB1LENR_TIM4EN, + .base = STM32_TIM4_BASE, + .psc = CONFIG_STM32H7_TIM4_QEPSC, + .ti1cfg = GPIO_TIM4_CH1IN, + .ti2cfg = GPIO_TIM4_CH2IN, +}; + +static struct stm32_lowerhalf_s g_tim4lower = +{ + .ops = &g_qecallbacks, + .config = &g_tim4config, + .inuse = false, +}; + +#endif + +#ifdef CONFIG_STM32H7_TIM5_QE +static const struct stm32_qeconfig_s g_tim5config = +{ + .timid = 5, + .irq = STM32_IRQ_TIM5, +#ifdef HAVE_MIXEDWIDTH_TIMERS + .width = TIM5_BITWIDTH, +#endif + .regaddr = STM32_RCC_APB1LENR, + .enable = RCC_APB1LENR_TIM5EN, + .base = STM32_TIM5_BASE, + .psc = CONFIG_STM32H7_TIM5_QEPSC, + .ti1cfg = GPIO_TIM5_CH1IN, + .ti2cfg = GPIO_TIM5_CH2IN, +}; + +static struct stm32_lowerhalf_s g_tim5lower = +{ + .ops = &g_qecallbacks, + .config = &g_tim5config, + .inuse = false, +}; + +#endif + +#ifdef CONFIG_STM32H7_TIM8_QE +static const struct stm32_qeconfig_s g_tim8config = +{ + .timid = 8, + .irq = STM32_IRQ_TIM8UP, +#ifdef HAVE_MIXEDWIDTH_TIMERS + .width = TIM8_BITWIDTH, +#endif + .regaddr = STM32_RCC_APB2ENR, + .enable = RCC_APB2ENR_TIM8EN, + .base = STM32_TIM8_BASE, + .psc = CONFIG_STM32H7_TIM8_QEPSC, + .ti1cfg = GPIO_TIM8_CH1IN, + .ti2cfg = GPIO_TIM8_CH2IN, +}; + +static struct stm32_lowerhalf_s g_tim8lower = +{ + .ops = &g_qecallbacks, + .config = &g_tim8config, + .inuse = false, +}; + +#endif + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: stm32_getreg16 + * + * Description: + * Read the value of a 16-bit timer register. + * + * Input Parameters: + * priv - A reference to the lower half status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ************************************************************************************/ + +static uint16_t stm32_getreg16(struct stm32_lowerhalf_s *priv, int offset) +{ + return getreg16(priv->config->base + offset); +} + +/************************************************************************************ + * Name: stm32_putreg16 + * + * Description: + * Write a value to a 16-bit timer register. + * + * Input Parameters: + * priv - A reference to the lower half status + * offset - The offset to the register to read + * + * Returned Value: + * None + * + ************************************************************************************/ + +static void stm32_putreg16(FAR struct stm32_lowerhalf_s *priv, int offset, + uint16_t value) +{ + putreg16(value, priv->config->base + offset); +} + +/************************************************************************************ + * Name: stm32_getreg32 + * + * Description: + * Read the value of a 32-bit timer register. This applies for the STM32 H7 + * 32-bit registers (CNT, ARR, CRR1-4) in the 32-bit timers TIM2-5 (but works OK + * with the 16-bit TIM1,8 as well). + * + * Input Parameters: + * priv - A reference to the lower half status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ************************************************************************************/ + +static uint32_t stm32_getreg32(FAR struct stm32_lowerhalf_s *priv, int offset) +{ + return getreg32(priv->config->base + offset); +} + +/************************************************************************************ + * Name: stm32_putreg32 + * + * Description: + * Write a value to a 32-bit timer register. This applies for the STM32 H7 + * 32-bit registers (CNT, ARR, CRR1-4) in the 32-bit timers TIM2-5 (but works OK + * with the 16-bit TIM1,8 as well). + * + * Input Parameters: + * priv - A reference to the lower half status + * offset - The offset to the register to read + * + * Returned Value: + * None + * + ************************************************************************************/ + +static void stm32_putreg32(FAR struct stm32_lowerhalf_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32_dumpregs + * + * Description: + * Dump all timer registers. + * + * Input Parameters: + * priv - A reference to the QENCODER block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_SENSORS) && defined(CONFIG_DEBUG_INFO) +static void stm32_dumpregs(FAR struct stm32_lowerhalf_s *priv, + FAR const char *msg) +{ + sninfo("%s:\n", msg); + sninfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n", + stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET), + stm32_getreg16(priv, STM32_GTIM_CR2_OFFSET), + stm32_getreg16(priv, STM32_GTIM_SMCR_OFFSET), + stm32_getreg16(priv, STM32_GTIM_DIER_OFFSET)); + sninfo(" SR: %04x EGR: %04x CCMR1: %04x CCMR2: %04x\n", + stm32_getreg16(priv, STM32_GTIM_SR_OFFSET), + stm32_getreg16(priv, STM32_GTIM_EGR_OFFSET), + stm32_getreg16(priv, STM32_GTIM_CCMR1_OFFSET), + stm32_getreg16(priv, STM32_GTIM_CCMR2_OFFSET)); + sninfo(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n", + stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET), + stm32_getreg16(priv, STM32_GTIM_CNT_OFFSET), + stm32_getreg16(priv, STM32_GTIM_PSC_OFFSET), + stm32_getreg16(priv, STM32_GTIM_ARR_OFFSET)); + sninfo(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n", + stm32_getreg16(priv, STM32_GTIM_CCR1_OFFSET), + stm32_getreg16(priv, STM32_GTIM_CCR2_OFFSET), + stm32_getreg16(priv, STM32_GTIM_CCR3_OFFSET), + stm32_getreg16(priv, STM32_GTIM_CCR4_OFFSET)); +#if defined(CONFIG_STM32H7_TIM1_QE) || defined(CONFIG_STM32H7_TIM8_QE) + if (priv->config->timid == 1 || priv->config->timid == 8) + { + sninfo(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n", + stm32_getreg16(priv, STM32_ATIM_RCR_OFFSET), + stm32_getreg16(priv, STM32_ATIM_BDTR_OFFSET), + stm32_getreg16(priv, STM32_ATIM_DCR_OFFSET), + stm32_getreg16(priv, STM32_ATIM_DMAR_OFFSET)); + } + else +#endif + { + sninfo(" DCR: %04x DMAR: %04x\n", + stm32_getreg16(priv, STM32_GTIM_DCR_OFFSET), + stm32_getreg16(priv, STM32_GTIM_DMAR_OFFSET)); + } +} +#endif + +/************************************************************************************ + * Name: stm32_tim2lower + * + * Description: + * Map a timer number to a device structure + * + ************************************************************************************/ + +static FAR struct stm32_lowerhalf_s *stm32_tim2lower(int tim) +{ + switch (tim) + { +#ifdef CONFIG_STM32H7_TIM1_QE + case 1: + return &g_tim1lower; +#endif +#ifdef CONFIG_STM32H7_TIM2_QE + case 2: + return &g_tim2lower; +#endif +#ifdef CONFIG_STM32H7_TIM3_QE + case 3: + return &g_tim3lower; +#endif +#ifdef CONFIG_STM32H7_TIM4_QE + case 4: + return &g_tim4lower; +#endif +#ifdef CONFIG_STM32H7_TIM5_QE + case 5: + return &g_tim5lower; +#endif +#ifdef CONFIG_STM32H7_TIM8_QE + case 8: + return &g_tim8lower; +#endif + default: + return NULL; + } +} + +/************************************************************************************ + * Name: stm32_interrupt + * + * Description: + * Common timer interrupt handling. NOTE: Only 16-bit timers require timer + * interrupts. + * + ************************************************************************************/ + +#ifdef HAVE_16BIT_TIMERS +static int stm32_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct stm32_lowerhalf_s *priv = (FAR struct stm32_lowerhalf_s *)arg; + uint16_t regval; + + DEBUGASSERT(priv != NULL); + + /* Verify that this is an update interrupt. Nothing else is expected. */ + + regval = stm32_getreg16(priv, STM32_GTIM_SR_OFFSET); + DEBUGASSERT((regval & ATIM_SR_UIF) != 0); + + /* Clear the UIF interrupt bit */ + + stm32_putreg16(priv, STM32_GTIM_SR_OFFSET, regval & ~GTIM_SR_UIF); + + /* Check the direction bit in the CR1 register and add or subtract the + * maximum value + 1, as appropriate. + */ + + regval = stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET); + if ((regval & ATIM_CR1_DIR) != 0) + { + priv->position -= (int32_t)0x00010000; + } + else + { + priv->position += (int32_t)0x00010000; + } + + return OK; +} +#endif + +/************************************************************************************ + * Name: stm32_setup + * + * Description: + * This method is called when the driver is opened. The lower half driver + * should configure and initialize the device so that it is ready for use. + * The initial position value should be zero. * + * + ************************************************************************************/ + +static int stm32_setup(FAR struct qe_lowerhalf_s *lower) +{ + FAR struct stm32_lowerhalf_s *priv = (FAR struct stm32_lowerhalf_s *)lower; + uint16_t dier; + uint32_t smcr; + uint32_t ccmr1; + uint16_t ccer; + uint16_t cr1; +#ifdef HAVE_16BIT_TIMERS + uint16_t regval; + int ret; +#endif + + /* Enable clocking to the timer */ + + modifyreg32(priv->config->regaddr, 0, priv->config->enable); + + /* Timer base configuration */ + + cr1 = stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET); + + /* Clear the direction bit (0=count up) and select the Counter Mode (0=Edge aligned) + * (Timers 2-5 and 1-8 only) + */ + + cr1 &= ~(GTIM_CR1_DIR | GTIM_CR1_CMS_MASK); + stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1); + + /* Set the Autoreload value */ + +#if defined(HAVE_MIXEDWIDTH_TIMERS) + if (priv->config->width == 32) + { + stm32_putreg32(priv, STM32_GTIM_ARR_OFFSET, 0xffffffff); + } + else + { + stm32_putreg16(priv, STM32_GTIM_ARR_OFFSET, 0xffff); + } +#elif defined(HAVE_32BIT_TIMERS) + stm32_putreg32(priv, STM32_GTIM_ARR_OFFSET, 0xffffffff); +#else + stm32_putreg16(priv, STM32_GTIM_ARR_OFFSET, 0xffff); +#endif + + /* Set the timer prescaler value. + * + * If we are doing precise shaft positioning, each qe pulse is important. + * So the STM32 has direct config control on the pulse count prescaler. + * This input clock just limits the incoming pulse rate, which should be + * lower than the peripheral clock due to resynchronization, but it is the + * responsibility of the system designer to decide the correct prescaler + * value, because it has a direct influence on the encoder resolution. + */ + + stm32_putreg16(priv, STM32_GTIM_PSC_OFFSET, (uint16_t)priv->config->psc); + +#if defined(CONFIG_STM32H7_TIM1_QE) || defined(CONFIG_STM32H7_TIM8_QE) + if (priv->config->timid == 1 || priv->config->timid == 8) + { + /* Clear the Repetition Counter value */ + + stm32_putreg16(priv, STM32_ATIM_RCR_OFFSET, 0); + } +#endif + + /* Generate an update event to reload the Prescaler + * and the repetition counter (only for TIM1 and TIM8) value immediately + */ + + stm32_putreg16(priv, STM32_GTIM_EGR_OFFSET, GTIM_EGR_UG); + + /* GPIO pin configuration */ + + stm32_configgpio(priv->config->ti1cfg); + stm32_configgpio(priv->config->ti2cfg); + + /* Set the encoder Mode 3 */ + + smcr = stm32_getreg32(priv, STM32_GTIM_SMCR_OFFSET); + smcr &= ~GTIM_SMCR_SMS_MASK; + smcr |= GTIM_SMCR_ENCMD3; + stm32_putreg32(priv, STM32_GTIM_SMCR_OFFSET, smcr); + + /* TI1 Channel Configuration */ + /* Disable the Channel 1: Reset the CC1E Bit */ + + ccer = stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET); + ccer &= ~GTIM_CCER_CC1E; + stm32_putreg16(priv, STM32_GTIM_CCER_OFFSET, ccer); + + ccmr1 = stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET); + ccer = stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET); + + /* Select the Input IC1=TI1 and set the filter fSAMPLING=fDTS/4, N=6 */ + + ccmr1 &= ~(GTIM_CCMR1_CC1S_MASK | GTIM_CCMR1_IC1F_MASK); + ccmr1 |= GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR1_CC1S_SHIFT; + ccmr1 |= STM32_QENCODER_ICF << GTIM_CCMR1_IC1F_SHIFT; + + /* Select the Polarity=rising and set the CC1E Bit */ + + ccer &= ~(GTIM_CCER_CC1P | GTIM_CCER_CC1NP); + ccer |= GTIM_CCER_CC1E; + + /* Write to TIM CCMR1 and CCER registers */ + + stm32_putreg32(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1); + stm32_putreg16(priv, STM32_GTIM_CCER_OFFSET, ccer); + + /* Set the Input Capture Prescaler value: Capture performed each time an + * edge is detected on the capture input. + */ + + ccmr1 = stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET); + ccmr1 &= ~GTIM_CCMR1_IC1PSC_MASK; + ccmr1 |= (GTIM_CCMR_ICPSC_NOPSC << GTIM_CCMR1_IC1PSC_SHIFT); + stm32_putreg32(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1); + + /* TI2 Channel Configuration */ + /* Disable the Channel 2: Reset the CC2E Bit */ + + ccer = stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET); + ccer &= ~GTIM_CCER_CC2E; + stm32_putreg16(priv, STM32_GTIM_CCER_OFFSET, ccer); + + ccmr1 = stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET); + ccer = stm32_getreg16(priv, STM32_GTIM_CCER_OFFSET); + + /* Select the Input IC2=TI2 and set the filter fSAMPLING=fDTS/4, N=6 */ + + ccmr1 &= ~(GTIM_CCMR1_CC2S_MASK | GTIM_CCMR1_IC2F_MASK); + ccmr1 |= GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR1_CC2S_SHIFT; + ccmr1 |= STM32_QENCODER_ICF << GTIM_CCMR1_IC2F_SHIFT; + + /* Select the Polarity=rising and set the CC2E Bit */ + + ccer &= ~(GTIM_CCER_CC2P | GTIM_CCER_CC2NP); + ccer |= GTIM_CCER_CC2E; + + /* Write to TIM CCMR1 and CCER registers */ + + stm32_putreg32(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1); + stm32_putreg16(priv, STM32_GTIM_CCER_OFFSET, ccer); + + /* Set the Input Capture Prescaler value: Capture performed each time an + * edge is detected on the capture input. + */ + + ccmr1 = stm32_getreg32(priv, STM32_GTIM_CCMR1_OFFSET); + ccmr1 &= ~GTIM_CCMR1_IC2PSC_MASK; + ccmr1 |= (GTIM_CCMR_ICPSC_NOPSC << GTIM_CCMR1_IC2PSC_SHIFT); + stm32_putreg32(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1); + + /* Disable the update interrupt */ + + dier = stm32_getreg16(priv, STM32_GTIM_DIER_OFFSET); + dier &= ~GTIM_DIER_UIE; + stm32_putreg16(priv, STM32_GTIM_DIER_OFFSET, dier); + + /* There is no need for interrupts with 32-bit timers */ + +#ifdef HAVE_16BIT_TIMERS +#ifdef HAVE_MIXEDWIDTH_TIMERS + if (priv->config->width != 32) +#endif + { + /* Attach the interrupt handler */ + + ret = irq_attach(priv->config->irq, stm32_interrupt, priv); + if (ret < 0) + { + stm32_shutdown(lower); + return ret; + } + + /* Enable the update/global interrupt at the NVIC */ + + up_enable_irq(priv->config->irq); + } +#endif + + /* Reset the Update Disable Bit */ + + cr1 = stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET); + cr1 &= ~GTIM_CR1_UDIS; + stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1); + + /* Reset the URS Bit */ + + cr1 &= ~GTIM_CR1_URS; + stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1); + + /* There is no need for interrupts with 32-bit timers */ + +#ifdef HAVE_16BIT_TIMERS +#ifdef HAVE_MIXEDWIDTH_TIMERS + if (priv->config->width != 32) +#endif + { + /* Clear any pending update interrupts */ + + regval = stm32_getreg16(priv, STM32_GTIM_SR_OFFSET); + stm32_putreg16(priv, STM32_GTIM_SR_OFFSET, regval & ~GTIM_SR_UIF); + + /* Then enable the update interrupt */ + + dier = stm32_getreg16(priv, STM32_GTIM_DIER_OFFSET); + dier |= GTIM_DIER_UIE; + stm32_putreg16(priv, STM32_GTIM_DIER_OFFSET, dier); + } +#endif + + /* Enable the TIM Counter */ + + cr1 = stm32_getreg16(priv, STM32_GTIM_CR1_OFFSET); + cr1 |= GTIM_CR1_CEN; + stm32_putreg16(priv, STM32_GTIM_CR1_OFFSET, cr1); + + stm32_dumpregs(priv, "After setup"); + + return OK; +} + +/************************************************************************************ + * Name: stm32_shutdown + * + * Description: + * This method is called when the driver is closed. The lower half driver + * should stop data collection, free any resources, disable timer hardware, and + * put the system into the lowest possible power usage state * + * + ************************************************************************************/ + +static int stm32_shutdown(FAR struct qe_lowerhalf_s *lower) +{ + FAR struct stm32_lowerhalf_s *priv = (FAR struct stm32_lowerhalf_s *)lower; + irqstate_t flags; + uint32_t regaddr; + uint32_t regval; + uint32_t resetbit; + uint32_t pincfg; + + /* Disable the update/global interrupt at the NVIC */ + + flags = enter_critical_section(); + up_disable_irq(priv->config->irq); + + /* Detach the interrupt handler */ + + (void)irq_detach(priv->config->irq); + + /* Disable interrupts momentary to stop any ongoing timer processing and + * to prevent any concurrent access to the reset register. + */ + + /* Disable further interrupts and stop the timer */ + + stm32_putreg16(priv, STM32_GTIM_DIER_OFFSET, 0); + stm32_putreg16(priv, STM32_GTIM_SR_OFFSET, 0); + + /* Determine which timer to reset */ + + switch (priv->config->timid) + { +#ifdef CONFIG_STM32H7_TIM1_QE + case 1: + regaddr = STM32_RCC_APB2RSTR; + resetbit = RCC_APB2RSTR_TIM1RST; + break; +#endif +#ifdef CONFIG_STM32H7_TIM2_QE + case 2: + regaddr = STM32_RCC_APB1LRSTR; + resetbit = RCC_APB1LRSTR_TIM2RST; + break; +#endif +#ifdef CONFIG_STM32H7_TIM3_QE + case 3: + regaddr = STM32_RCC_APB1LRSTR; + resetbit = RCC_APB1LRSTR_TIM3RST; + break; +#endif +#ifdef CONFIG_STM32H7_TIM4_QE + case 4: + regaddr = STM32_RCC_APB1LRSTR; + resetbit = RCC_APB1LRSTR_TIM4RST; + break; +#endif +#ifdef CONFIG_STM32H7_TIM5_QE + case 5: + regaddr = STM32_RCC_APB1LRSTR; + resetbit = RCC_APB1LRSTR_TIM5RST; + break; +#endif +#ifdef CONFIG_STM32H7_TIM8_QE + case 8: + regaddr = STM32_RCC_APB2RSTR; + resetbit = RCC_APB2RSTR_TIM8RST; + break; +#endif + default: + return -EINVAL; + } + + /* Reset the timer - stopping the output and putting the timer back + * into a state where stm32_start() can be called. + */ + + regval = getreg32(regaddr); + regval |= resetbit; + putreg32(regval, regaddr); + + regval &= ~resetbit; + putreg32(regval, regaddr); + leave_critical_section(flags); + + sninfo("regaddr: %08x resetbit: %08x\n", regaddr, resetbit); + stm32_dumpregs(priv, "After stop"); + + /* Disable clocking to the timer */ + + modifyreg32(priv->config->regaddr, priv->config->enable, 0); + + /* Put the TI1 GPIO pin back to its default state */ + + pincfg = priv->config->ti1cfg & (GPIO_PORT_MASK | GPIO_PIN_MASK); + pincfg |= STM32_GPIO_INPUT_FLOAT; + + stm32_configgpio(pincfg); + + /* Put the TI2 GPIO pin back to its default state */ + + pincfg = priv->config->ti2cfg & (GPIO_PORT_MASK | GPIO_PIN_MASK); + pincfg |= STM32_GPIO_INPUT_FLOAT; + + stm32_configgpio(pincfg); + return OK; +} + +/************************************************************************************ + * Name: stm32_position + * + * Description: + * Return the current position measurement. + * + ************************************************************************************/ + +static int stm32_position(FAR struct qe_lowerhalf_s *lower, FAR int32_t *pos) +{ + FAR struct stm32_lowerhalf_s *priv = (FAR struct stm32_lowerhalf_s *)lower; +#ifdef HAVE_16BIT_TIMERS + int32_t position; + int32_t verify; + uint32_t count; + + DEBUGASSERT(lower && priv->inuse); + + /* Loop until we are certain that no interrupt occurred between samples */ + + do + { + /* Don't let another task pre-empt us until we get the measurement. The timer + * interrupt may still be processed + */ + + sched_lock(); + position = priv->position; + count = stm32_getreg32(priv, STM32_GTIM_CNT_OFFSET); + verify = priv->position; + sched_unlock(); + } + while (position != verify); + + /* Return the position measurement */ + + *pos = position + (int32_t)count; +#else + /* Return the counter value */ + + *pos = (int32_t)stm32_getreg32(priv, STM32_GTIM_CNT_OFFSET); +#endif + return OK; +} + +/************************************************************************************ + * Name: stm32_reset + * + * Description: + * Reset the position measurement to zero. + * + ************************************************************************************/ + +static int stm32_reset(FAR struct qe_lowerhalf_s *lower) +{ + FAR struct stm32_lowerhalf_s *priv = (FAR struct stm32_lowerhalf_s *)lower; +#ifdef HAVE_16BIT_TIMERS + irqstate_t flags; + + sninfo("Resetting position to zero\n"); + DEBUGASSERT(lower && priv->inuse); + + /* Reset the timer and the counter. Interrupts are disabled to make this atomic + * (if possible) + */ + + flags = enter_critical_section(); + stm32_putreg32(priv, STM32_GTIM_CNT_OFFSET, 0); + priv->position = 0; + leave_critical_section(flags); +#else + sninfo("Resetting position to zero\n"); + DEBUGASSERT(lower && priv->inuse); + + /* Reset the counter to zero */ + + stm32_putreg32(priv, STM32_GTIM_CNT_OFFSET, 0); +#endif + return OK; +} + +/************************************************************************************ + * Name: stm32_ioctl + * + * Description: + * Lower-half logic may support platform-specific ioctl commands + * + ************************************************************************************/ + +static int stm32_ioctl(FAR struct qe_lowerhalf_s *lower, int cmd, unsigned long arg) +{ + /* No ioctl commands supported */ + + /* TODO add an IOCTL to control the encoder pulse count prescaler */ + + return -ENOTTY; +} + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: stm32_qeinitialize + * + * Description: + * Initialize a quadrature encoder interface. This function must be called from + * board-specific logic. + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/qe0" + * tim - The timer number to used. 'tim' must be an element of {1,2,3,4,5,8} + * + * Returned Value: + * Zero on success; A negated errno value is returned on failure. + * + ************************************************************************************/ + +int stm32_qeinitialize(FAR const char *devpath, int tim) +{ + FAR struct stm32_lowerhalf_s *priv; + int ret; + + /* Find the pre-allocated timer state structure corresponding to this timer */ + + priv = stm32_tim2lower(tim); + if (!priv) + { + snerr("ERROR: TIM%d support not configured\n", tim); + return -ENXIO; + } + + /* Make sure that it is available */ + + if (priv->inuse) + { + snerr("ERROR: TIM%d is in-use\n", tim); + return -EBUSY; + } + + /* Register the upper-half driver */ + + ret = qe_register(devpath, (FAR struct qe_lowerhalf_s *)priv); + if (ret < 0) + { + snerr("ERROR: qe_register failed: %d\n", ret); + return ret; + } + + /* Make sure that the timer is in the shutdown state */ + + stm32_shutdown((FAR struct qe_lowerhalf_s *)priv); + + /* The driver is now in-use */ + + priv->inuse = true; + return OK; +} + +#endif /* CONFIG_SENSORS_QENCODER */ diff --git a/arch/arm/src/stm32h7/stm32_qencoder.h b/arch/arm/src/stm32h7/stm32_qencoder.h new file mode 100644 index 0000000000..05871d05f3 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_qencoder.h @@ -0,0 +1,143 @@ +/************************************************************************************ + * arch/arm/src/stm32h7/stm32_qencoder.h + * + * Copyright (C) 2018 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. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H7_STM32_QENCODER_H +#define __ARCH_ARM_SRC_STM32H7_STM32_QENCODER_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include + +#include "chip.h" + +#ifdef CONFIG_SENSORS_QENCODER + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/* Timer devices may be used for different purposes. One special purpose is as + * a quadrature encoder input device. If CONFIG_STM32H7_TIMn is defined then the + * CONFIG_STM32H7_TIMn_QE must also be defined to indicate that timer "n" is intended + * to be used for as a quadrature encoder. + */ + +#ifndef CONFIG_STM32H7_TIM1 +# undef CONFIG_STM32H7_TIM1_QE +#endif +#ifndef CONFIG_STM32H7_TIM2 +# undef CONFIG_STM32H7_TIM2_QE +#endif +#ifndef CONFIG_STM32H7_TIM3 +# undef CONFIG_STM32H7_TIM3_QE +#endif +#ifndef CONFIG_STM32H7_TIM4 +# undef CONFIG_STM32H7_TIM4_QE +#endif +#ifndef CONFIG_STM32H7_TIM5 +# undef CONFIG_STM32H7_TIM5_QE +#endif +#ifndef CONFIG_STM32H7_TIM8 +# undef CONFIG_STM32H7_TIM8_QE +#endif + +/* Only timers 2-5, and 1 & 8 can be used as a quadrature encoder (at least for the + * STM32 H7) + */ + +#undef CONFIG_STM32H7_TIM6_QE +#undef CONFIG_STM32H7_TIM7_QE +#undef CONFIG_STM32H7_TIM9_QE +#undef CONFIG_STM32H7_TIM10_QE +#undef CONFIG_STM32H7_TIM11_QE +#undef CONFIG_STM32H7_TIM12_QE +#undef CONFIG_STM32H7_TIM13_QE +#undef CONFIG_STM32H7_TIM14_QE + +/* Clock out frequency. This value is used to calculation the timer CLKIN in + * prescaler value. + */ + +#ifndef CONFIG_STM32H7_TIM1_QECLKOUT +# define CONFIG_STM32H7_TIM1_QECLKOUT 28000000 +#endif + +#ifndef CONFIG_STM32H7_TIM2_QECLKOUT +# define CONFIG_STM32H7_TIM2_QECLKOUT 28000000 +#endif + +#ifndef CONFIG_STM32H7_TIM3_QECLKOUT +# define CONFIG_STM32H7_TIM3_QECLKOUT 28000000 +#endif + +#ifndef CONFIG_STM32H7_TIM4_QECLKOUT +# define CONFIG_STM32H7_TIM4_QECLKOUT 28000000 +#endif + +#ifndef CONFIG_STM32H7_TIM5_QECLKOUT +# define CONFIG_STM32H7_TIM5_QECLKOUT 28000000 +#endif + +#ifndef CONFIG_STM32H7_TIM8_QECLKOUT +# define CONFIG_STM32H7_TIM8_QECLKOUT 28000000 +#endif + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +/************************************************************************************ + * Name: stm32_qeinitialize + * + * Description: + * Initialize a quadrature encoder interface. This function must be called from + * board-specific logic.. + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/qe0" + * tim - The timer number to used. 'tim' must be an element of {1,2,3,4,5,8} + * + * Returned Value: + * Zero on success; A negated errno value is returned on failure. + * + ************************************************************************************/ + +int stm32_qeinitialize(FAR const char *devpath, int tim); + +#endif /* CONFIG_SENSORS_QENCODER */ +#endif /* __ARCH_ARM_SRC_STM32H7_STM32_QENCODER_H */ + diff --git a/configs/makerlisp/README.txt b/configs/makerlisp/README.txt index 7831dbf146..ccf18a8a93 100644 --- a/configs/makerlisp/README.txt +++ b/configs/makerlisp/README.txt @@ -395,7 +395,7 @@ Configuration Subdirectories 2019-06-18: The RTC now appears to be fully functional. 2019-06-26: Renamed nsh configuration to nsh_flash. Added nsh_ram - configuration. + configuration. Not yet verified. sdboot diff --git a/libs/libc/misc/lib_debug.c b/libs/libc/misc/lib_debug.c index f9aeb29a21..6e6a2076c3 100644 --- a/libs/libc/misc/lib_debug.c +++ b/libs/libc/misc/lib_debug.c @@ -52,7 +52,7 @@ ****************************************************************************/ /**************************************************************************** - * Name: alert, err, warn, and info + * Name: _alert, _err, _warn, and _info * * Description: * If the cross-compiler's pre-processor does not support variable