This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push: new 2771df62507 arch/arm/stm32h7: Port timer capture driver from stm32 2771df62507 is described below commit 2771df625078ce309c2643ac5f1fcc0c5e2f4a7a Author: Côme VINCENT <44554692+com...@users.noreply.github.com> AuthorDate: Wed Aug 6 17:44:01 2025 -0400 arch/arm/stm32h7: Port timer capture driver from stm32 This commit introduces a timer capture driver for the STM32H7 series ported from the STM32 F series. The main changes include: - A new generic timer capture driver for STM32H7. - A lower-half driver to integrate with the NuttX capture subsystem. - Kconfig options to enable and configure capture for various timers. - Pin definitions for TIM1-4 capture inputs on the nucleo-h743zi. - An update to `cap_register_multiple` to handle multiple device registration. - An update to `stm32_bringup` to register the capture drivers. The current implementation is based on a driver originally for PWM input, and as such, it calculates duty cycle and frequency. It is also limited to a single capture channel per timer. The original implementation's `stm32_cap_init` in `arch/arm/src/stm32h7/stm32_capture.c` has been modified to accept a channel number instead of using a hardcoded 0 through `STM32_CAP_CHANNEL_COUNTER`. This serves as a foundation for future development of more comprehensive input capture capabilities on STM32H7 platforms. Tested by polling and reading `/dev/cap0-4` with `ioctl(fds[i], CAPIOC_FREQUENCE, freq)` while sending a square wave signal to appropriate pins and checking frequency. Also tested by bypassing upper half driver and setting up capture on TIM4 channels 1-4 as explained in #16762. Signed-off-by: Côme VINCENT <44554692+com...@users.noreply.github.com> --- arch/arm/src/stm32h7/CMakeLists.txt | 5 + arch/arm/src/stm32h7/Kconfig | 423 ++++- arch/arm/src/stm32h7/stm32_capture.c | 1625 ++++++++++++++++++++ arch/arm/src/stm32h7/stm32_capture.h | 240 +++ arch/arm/src/stm32h7/stm32_capture_lowerhalf.c | 590 +++++++ boards/arm/stm32h7/nucleo-h743zi/include/board.h | 76 +- .../arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c | 112 ++ drivers/timers/capture.c | 34 +- 8 files changed, 3030 insertions(+), 75 deletions(-) diff --git a/arch/arm/src/stm32h7/CMakeLists.txt b/arch/arm/src/stm32h7/CMakeLists.txt index d5dfd8b2f12..eb96cf2ef97 100644 --- a/arch/arm/src/stm32h7/CMakeLists.txt +++ b/arch/arm/src/stm32h7/CMakeLists.txt @@ -32,6 +32,7 @@ list( stm32_start.c stm32_rcc.c stm32_lowputc.c + stm32_capture.c stm32_serial.c stm32_uid.c) @@ -142,6 +143,10 @@ if(CONFIG_TIMER) list(APPEND SRCS stm32_tim_lowerhalf.c) endif() +if(CONFIG_CAPTURE) + list(APPEND SRCS stm32_capture_lowerhalf.c) +endif() + if(CONFIG_USBDEV) list(APPEND SRCS stm32_otgdev.c) endif() diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig index c8e839b58a6..12bf79aa1c0 100644 --- a/arch/arm/src/stm32h7/Kconfig +++ b/arch/arm/src/stm32h7/Kconfig @@ -4584,125 +4584,450 @@ config STM32H7_ADC3_TIMTRIG ---help--- Values 0:CC1 1:CC2 2:CC3 3:CC4 4:TRGO +config STM32H7_CAP + bool + default n + config STM32H7_TIM1_CAP bool "TIM1 Capture" default n depends on STM32H7_TIM1 + select STM32H7_CAP ---help--- - Reserve timer 1 for use by Capture + Reserve timer 1 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM1_CAP + +config STM32H7_TIM1_CHANNEL + int "TIM1 Capture Input Channel" + default 1 + range 1 6 + ---help--- + Specifies the timer input channel {1..6} for TIM1. + +config STM32H7_TIM1_CLOCK + int "TIM1 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM1_CAP + +config STM32H7_TIM8_CAP + bool "TIM8 Capture" + default n + depends on STM32H7_TIM8 + select STM32H7_CAP + ---help--- + Reserve timer 8 for use by the capture driver. + +if STM32H7_TIM8_CAP + +config STM32H7_TIM8_CHANNEL + int "TIM8 Capture Input Channel" + default 1 + range 1 6 + ---help--- + Specifies the timer input channel {1..6} for TIM8. + +config STM32H7_TIM8_CLOCK + int "TIM8 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM8_CAP + +# +# General-Purpose Timers (4 Channels) +# config STM32H7_TIM2_CAP bool "TIM2 Capture" default n depends on STM32H7_TIM2 + select STM32H7_CAP ---help--- - Reserve timer 2 for use by Capture + Reserve timer 2 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM2_CAP + +config STM32H7_TIM2_CHANNEL + int "TIM2 Capture Input Channel" + default 1 + range 1 4 + ---help--- + Specifies the timer input channel {1..4} for TIM2. + +config STM32H7_TIM2_CLOCK + int "TIM2 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM2_CAP config STM32H7_TIM3_CAP bool "TIM3 Capture" default n depends on STM32H7_TIM3 + select STM32H7_CAP ---help--- - Reserve timer 3 for use by Capture + Reserve timer 3 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM3_CAP + +config STM32H7_TIM3_CHANNEL + int "TIM3 Capture Input Channel" + default 1 + range 1 4 + ---help--- + Specifies the timer input channel {1..4} for TIM3. + +config STM32H7_TIM3_CLOCK + int "TIM3 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM3_CAP config STM32H7_TIM4_CAP bool "TIM4 Capture" default n depends on STM32H7_TIM4 + select STM32H7_CAP ---help--- - Reserve timer 4 for use by Capture + Reserve timer 4 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM4_CAP + +config STM32H7_TIM4_CHANNEL + int "TIM4 Capture Input Channel" + default 1 + range 1 4 + ---help--- + Specifies the timer input channel {1..4} for TIM4. + +config STM32H7_TIM4_CLOCK + int "TIM4 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM4_CAP config STM32H7_TIM5_CAP bool "TIM5 Capture" default n depends on STM32H7_TIM5 + select STM32H7_CAP ---help--- - Reserve timer 5 for use by Capture + Reserve timer 5 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM5_CAP -config STM32H7_TIM8_CAP - bool "TIM8 Capture" - default n - depends on STM32H7_TIM8 +config STM32H7_TIM5_CHANNEL + int "TIM5 Capture Input Channel" + default 1 + range 1 4 ---help--- - Reserve timer 8 for use by Capture + Specifies the timer input channel {1..4} for TIM5. - Timer devices may be used for different purposes. One special purpose is - to capture input. +config STM32H7_TIM5_CLOCK + int "TIM5 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM5_CAP + +# +# General-Purpose Timers (2 Channels) +# config STM32H7_TIM12_CAP bool "TIM12 Capture" default n depends on STM32H7_TIM12 + select STM32H7_CAP ---help--- - Reserve timer 12 for use by Capture + Reserve timer 12 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM12_CAP + +config STM32H7_TIM12_CHANNEL + int "TIM12 Capture Input Channel" + default 1 + range 1 2 + ---help--- + Specifies the timer input channel {1..2} for TIM12. + +config STM32H7_TIM12_CLOCK + int "TIM12 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM12_CAP + +config STM32H7_TIM15_CAP + bool "TIM15 Capture" + default n + depends on STM32H7_TIM15 + select STM32H7_CAP + ---help--- + Reserve timer 15 for use by the capture driver. + +if STM32H7_TIM15_CAP + +config STM32H7_TIM15_CHANNEL + int "TIM15 Capture Input Channel" + default 1 + range 1 2 + ---help--- + Specifies the timer input channel {1..2} for TIM15. + +config STM32H7_TIM15_CLOCK + int "TIM15 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM15_CAP + +# +# General-Purpose Timers (1 Channel) +# config STM32H7_TIM13_CAP bool "TIM13 Capture" default n depends on STM32H7_TIM13 + select STM32H7_CAP ---help--- - Reserve timer 13 for use by Capture + Reserve timer 13 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM13_CAP + +config STM32H7_TIM13_CHANNEL + int "TIM13 Capture Input Channel" + default 1 + range 1 1 + ---help--- + Specifies the timer input channel {1} for TIM13. + +config STM32H7_TIM13_CLOCK + int "TIM13 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM13_CAP config STM32H7_TIM14_CAP bool "TIM14 Capture" default n depends on STM32H7_TIM14 + select STM32H7_CAP ---help--- - Reserve timer 14 for use by Capture + Reserve timer 14 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM14_CAP -config STM32H7_TIM15_CAP - bool "TIM15 Capture" - default n - depends on STM32H7_TIM15 +config STM32H7_TIM14_CHANNEL + int "TIM14 Capture Input Channel" + default 1 + range 1 1 ---help--- - Reserve timer 15 for use by Capture + Specifies the timer input channel {1} for TIM14. - Timer devices may be used for different purposes. One special purpose is - to capture input. +config STM32H7_TIM14_CLOCK + int "TIM14 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM14_CAP config STM32H7_TIM16_CAP bool "TIM16 Capture" default n depends on STM32H7_TIM16 + select STM32H7_CAP ---help--- - Reserve timer 16 for use by Capture + Reserve timer 16 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM16_CAP + +config STM32H7_TIM16_CHANNEL + int "TIM16 Capture Input Channel" + default 1 + range 1 1 + ---help--- + Specifies the timer input channel {1} for TIM16. + +config STM32H7_TIM16_CLOCK + int "TIM16 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM16_CAP config STM32H7_TIM17_CAP - bool "TIM14 Capture" + bool "TIM17 Capture" default n depends on STM32H7_TIM17 + select STM32H7_CAP ---help--- - Reserve timer 17 for use by Capture + Reserve timer 17 for use by the capture driver. - Timer devices may be used for different purposes. One special purpose is - to capture input. +if STM32H7_TIM17_CAP + +config STM32H7_TIM17_CHANNEL + int "TIM17 Capture Input Channel" + default 1 + range 1 1 + ---help--- + Specifies the timer input channel {1} for TIM17. + +config STM32H7_TIM17_CLOCK + int "TIM17 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_TIM17_CAP + +# +# Low-Power Timers +# + +config STM32H7_LPTIM1_CAP + bool "LPTIM1 Capture" + default n + depends on STM32H7_LPTIM1 + select STM32H7_CAP + ---help--- + Reserve low-power timer 1 for use by the capture driver. + +if STM32H7_LPTIM1_CAP + +config STM32H7LPTIM1_CHANNEL + int "LPTIM1 Capture Input Channel" + default 1 + range 1 2 + ---help--- + Specifies the timer input channel {1,2} for LPTIM1. + +config STM32H7LPTIM1_CLOCK + int "LPTIM1 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_LPTIM1_CAP + +config STM32H7_LPTIM2_CAP + bool "LPTIM2 Capture" + default n + depends on STM32H7_LPTIM2 + select STM32H7_CAP + ---help--- + Reserve low-power timer 2 for use by the capture driver. + +if STM32H7_LPTIM2_CAP + +config STM32H7LPTIM2_CHANNEL + int "LPTIM2 Capture Input Channel" + default 1 + range 1 2 + ---help--- + Specifies the timer input channel {1,2} for LPTIM2. + +config STM32H7LPTIM2_CLOCK + int "LPTIM2 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_LPTIM2_CAP + +config STM32H7_LPTIM3_CAP + bool "LPTIM3 Capture" + default n + depends on STM32H7_LPTIM3 + select STM32H7_CAP + ---help--- + Reserve low-power timer 3 for use by the capture driver. + +if STM32H7_LPTIM3_CAP + +config STM32H7LPTIM3_CHANNEL + int "LPTIM3 Capture Input Channel" + default 1 + range 1 2 + ---help--- + Specifies the timer input channel {1,2} for LPTIM3. + +config STM32H7LPTIM3_CLOCK + int "LPTIM3 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_LPTIM3_CAP + +config STM32H7_LPTIM4_CAP + bool "LPTIM4 Capture" + default n + depends on STM32H7_LPTIM4 + select STM32H7_CAP + ---help--- + Reserve low-power timer 4 for use by the capture driver. + +if STM32H7_LPTIM4_CAP + +config STM32H7LPTIM4_CHANNEL + int "LPTIM4 Capture Input Channel" + default 1 + range 1 2 + ---help--- + Specifies the timer input channel {1,2} for LPTIM4. + +config STM32H7LPTIM4_CLOCK + int "LPTIM4 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_LPTIM4_CAP + +config STM32H7_LPTIM5_CAP + bool "LPTIM5 Capture" + default n + depends on STM32H7_LPTIM5 + select STM32H7_CAP + ---help--- + Reserve low-power timer 5 for use by the capture driver. + +if STM32H7_LPTIM5_CAP + +config STM32H7LPTIM5_CHANNEL + int "LPTIM5 Capture Input Channel" + default 1 + range 1 2 + ---help--- + Specifies the timer input channel {1,2} for LPTIM5. + +config STM32H7LPTIM5_CLOCK + int "LPTIM5 capture frequency (Hz)" + default 100000 + ---help--- + This clock frequency determines the timer's counting rate. + +endif # STM32H7_LPTIM5_CAP menu "STM32 TIMx Outputs Configuration" @@ -6036,12 +6361,12 @@ menu "FDCAN1 Configuration" config FDCAN1_BITRATE int "CAN bitrate" depends on !NET_CAN_CANFD - default 1000000 + default 100000 config FDCAN1_ARBI_BITRATE int "CAN FD Arbitration phase bitrate" depends on NET_CAN_CANFD - default 1000000 + default 100000 config FDCAN1_DATA_BITRATE int "CAN FD Data phase bitrate" @@ -6056,12 +6381,12 @@ menu "FDCAN2 Configuration" config FDCAN2_BITRATE int "CAN bitrate" depends on !NET_CAN_CANFD - default 1000000 + default 100000 config FDCAN2_ARBI_BITRATE int "CAN FD Arbitration phase bitrate" depends on NET_CAN_CANFD - default 1000000 + default 100000 config FDCAN2_DATA_BITRATE int "CAN FD Data phase bitrate" diff --git a/arch/arm/src/stm32h7/stm32_capture.c b/arch/arm/src/stm32h7/stm32_capture.c new file mode 100644 index 00000000000..3b740c38160 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_capture.c @@ -0,0 +1,1625 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_capture.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/arch.h> +#include <nuttx/irq.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <arch/board/board.h> + +#include "chip.h" +#include "arm_internal.h" +#include "stm32.h" +#include "stm32_gpio.h" +#include "stm32_capture.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Sanity checks ************************************************************/ + +#if !defined(CONFIG_STM32H7_STM32H7X3XX) +# warning "This driver is for STM32H7X3XX devices" +#endif + +/* Timer Channel Configuration **********************************************/ + +/* This module only compiles if there are enabled timers that are not + * intended for some other purpose. + */ + +#if defined(CONFIG_STM32H7_TIM1_CAP) || defined(CONFIG_STM32H7_TIM2_CAP) || \ + defined(CONFIG_STM32H7_TIM3_CAP) || defined(CONFIG_STM32H7_TIM4_CAP) || \ + defined(CONFIG_STM32H7_TIM5_CAP) || defined(CONFIG_STM32H7_TIM8_CAP) || \ + defined(CONFIG_STM32H7_TIM12_CAP) || defined(CONFIG_STM32H7_TIM13_CAP) || \ + defined(CONFIG_STM32H7_TIM14_CAP) || defined(CONFIG_STM32H7_TIM15_CAP) || \ + defined(CONFIG_STM32H7_TIM16_CAP) || defined(CONFIG_STM32H7_TIM17_CAP) || \ + defined(CONFIG_STM32H7_LPTIM1_CAP) || defined(CONFIG_STM32H7_LPTIM2_CAP) || \ + defined(CONFIG_STM32H7_LPTIM3_CAP) || defined(CONFIG_STM32H7_LPTIM4_CAP) || \ + defined(CONFIG_STM32H7_LPTIM5_CAP) + +/* Check if any channel is enabled. + * This is done to simplify the logic below. + */ + +#if defined(GPIO_TIM1_CH1IN) || defined(GPIO_TIM2_CH1IN) || defined(GPIO_TIM3_CH1IN) || \ + defined(GPIO_TIM4_CH1IN) || defined(GPIO_TIM5_CH1IN) || defined(GPIO_TIM8_CH1IN) || \ + defined(GPIO_TIM12_CH1IN) || defined(GPIO_TIM13_CH1IN) || defined(GPIO_TIM14_CH1IN) || \ + defined(GPIO_TIM15_CH1IN) || defined(GPIO_TIM16_CH1IN) || defined(GPIO_TIM17_CH1IN) || \ + defined(GPIO_LPTIM1_CH1IN) || defined(GPIO_LPTIM2_CH1IN) || defined(GPIO_LPTIM3_CH1IN) || \ + defined(GPIO_LPTIM4_CH1IN) || defined(GPIO_LPTIM5_CH1IN) +# define HAVE_CH1IN 1 +#endif + +#if defined(GPIO_TIM1_CH2IN) || defined(GPIO_TIM2_CH2IN) || defined(GPIO_TIM3_CH2IN) || \ + defined(GPIO_TIM4_CH2IN) || defined(GPIO_TIM5_CH2IN) || defined(GPIO_TIM8_CH2IN) || \ + defined(GPIO_TIM12_CH2IN) || defined(GPIO_TIM15_CH2IN) || \ + defined(GPIO_LPTIM1_CH2IN) || defined(GPIO_LPTIM2_CH2IN) || defined(GPIO_LPTIM3_CH2IN) || \ + defined(GPIO_LPTIM4_CH2IN) || defined(GPIO_LPTIM5_CH2IN) +# define HAVE_CH2IN 1 +#endif + +#if defined(GPIO_TIM1_CH3IN) || defined(GPIO_TIM2_CH3IN) || defined(GPIO_TIM3_CH3IN) || \ + defined(GPIO_TIM4_CH3IN) || defined(GPIO_TIM5_CH3IN) || defined(GPIO_TIM8_CH3IN) +# define HAVE_CH3IN 1 +#endif + +#if defined(GPIO_TIM1_CH4IN) || defined(GPIO_TIM2_CH4IN) || defined(GPIO_TIM3_CH4IN) || \ + defined(GPIO_TIM4_CH4IN) || defined(GPIO_TIM5_CH4IN) || defined(GPIO_TIM8_CH4IN) +# define HAVE_CH4IN 1 +#endif + +#if defined(GPIO_TIM1_CH5IN) || defined(GPIO_TIM8_CH5IN) +# define HAVE_CH5IN 1 +#endif + +#if defined(GPIO_TIM1_CH6IN) || defined(GPIO_TIM8_CH6IN) +# define HAVE_CH6IN 1 +#endif + +/* Check if we have any advanced timers */ + +#if defined(CONFIG_STM32H7_TIM1_CAP) || defined(CONFIG_STM32H7_TIM8_CAP) +# define USE_ADVANCED_TIM 1 +#endif + +/* Check if we have any general purpose timers */ + +#if defined(CONFIG_STM32H7_TIM2_CAP) || defined(CONFIG_STM32H7_TIM3_CAP) || \ + defined(CONFIG_STM32H7_TIM4_CAP) || defined(CONFIG_STM32H7_TIM5_CAP) || \ + defined(CONFIG_STM32H7_TIM12_CAP) || defined(CONFIG_STM32H7_TIM13_CAP) || \ + defined(CONFIG_STM32H7_TIM14_CAP) || defined(CONFIG_STM32H7_TIM15_CAP) || \ + defined(CONFIG_STM32H7_TIM16_CAP) || defined(CONFIG_STM32H7_TIM17_CAP) +# define USE_GENERAL_TIM 1 +#endif + +/* Check if we have any low-power timers */ + +#if defined(CONFIG_STM32H7_LPTIM1_CAP) || defined(CONFIG_STM32H7_LPTIM2_CAP) || \ + defined(CONFIG_STM32H7_LPTIM3_CAP) || defined(CONFIG_STM32H7_LPTIM4_CAP) || \ + defined(CONFIG_STM32H7_LPTIM5_CAP) +# define USE_LOWPOWER_TIM 1 +#endif + +/* Check for external clock signal */ + +#if defined(GPIO_TIM1_ETR_IN) || defined(GPIO_TIM2_ETR_IN) || defined(GPIO_TIM3_ETR_IN) || \ + defined(GPIO_TIM4_ETR_IN) || defined(GPIO_TIM5_ETR_IN) || defined(GPIO_TIM8_ETR_IN) +# define USE_EXT_CLOCK 1 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* TIM Device Structure */ + +struct stm32_cap_priv_s +{ + const struct stm32_cap_ops_s *ops; + const uint32_t base; /* TIMn base address */ +#ifdef USE_EXT_CLOCK + const uint32_t gpio_clk; /* TIMn base address */ +#endif + const int irq; /* irq vector */ +#ifdef USE_ADVANCED_TIM + const int irq_of; /* irq timer overflow is deferent in advanced timer */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Get a 16-bit register value by offset */ + +static inline +uint16_t stm32_getreg16(const struct stm32_cap_priv_s *priv, + uint8_t offset) +{ + return getreg16(priv->base + offset); +} + +/* Put a 16-bit register value by offset */ + +static inline void stm32_putreg16(const struct stm32_cap_priv_s *priv, + uint8_t offset, uint16_t value) +{ + putreg16(value, priv->base + offset); +} + +/* Modify a 16-bit register value by offset */ + +static inline void stm32_modifyreg16(const struct stm32_cap_priv_s *priv, + uint8_t offset, uint16_t clearbits, + uint16_t setbits) +{ + modifyreg16(priv->base + offset, clearbits, setbits); +} + +/* Get a 32-bit register value by offset. This applies only for the STM32 F4 + * 32-bit registers (CNT, ARR, CRR1-4) in the 32-bit timers TIM2 and TIM5. + */ + +static inline +uint32_t stm32_getreg32(const struct stm32_cap_priv_s *priv, + uint8_t offset) +{ + return getreg32(priv->base + offset); +} + +/* Put a 32-bit register value by offset. This applies only for the STM32 F4 + * 32-bit registers (CNT, ARR, CRR1-4) in the 32-bit timers TIM2 and TIM5. + */ + +static inline void stm32_putreg32(const struct stm32_cap_priv_s *priv, + uint8_t offset, uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * gpio Functions + ****************************************************************************/ + +static inline +uint32_t stm32_cap_gpio(const struct stm32_cap_priv_s *priv, + int channel) +{ + switch (priv->base) + { +#ifdef CONFIG_STM32H7_TIM1_CAP + case STM32_TIM1_BASE: + switch (channel) + { +#ifdef GPIO_TIM1_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM1_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM1_CH1IN + case 1: + return GPIO_TIM1_CH1IN; +#endif +#ifdef GPIO_TIM1_CH2IN + case 2: + return GPIO_TIM1_CH2IN; +#endif +#ifdef GPIO_TIM1_CH3IN + case 3: + return GPIO_TIM1_CH3IN; +#endif +#ifdef GPIO_TIM1_CH4IN + case 4: + return GPIO_TIM1_CH4IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM2_CAP + case STM32_TIM2_BASE: + switch (channel) + { +#ifdef GPIO_TIM2_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM2_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM2_CH1IN + case 1: + return GPIO_TIM2_CH1IN; +#endif +#ifdef GPIO_TIM2_CH2IN + case 2: + return GPIO_TIM2_CH2IN; +#endif +#ifdef GPIO_TIM2_CH3IN + case 3: + return GPIO_TIM2_CH3IN; +#endif +#ifdef GPIO_TIM2_CH4IN + case 4: + return GPIO_TIM2_CH4IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM3_CAP + case STM32_TIM3_BASE: + switch (channel) + { +#ifdef GPIO_TIM3_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM3_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM3_CH1IN + case 1: + return GPIO_TIM3_CH1IN; +#endif +#ifdef GPIO_TIM3_CH2IN + case 2: + return GPIO_TIM3_CH2IN; +#endif +#ifdef GPIO_TIM3_CH3IN + case 3: + return GPIO_TIM3_CH3IN; +#endif +#ifdef GPIO_TIM3_CH4IN + case 4: + return GPIO_TIM3_CH4IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM4_CAP + case STM32_TIM4_BASE: + switch (channel) + { +#ifdef GPIO_TIM4_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM4_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM4_CH1IN + case 1: + return GPIO_TIM4_CH1IN; +#endif +#ifdef GPIO_TIM4_CH2IN + case 2: + return GPIO_TIM4_CH2IN; +#endif +#ifdef GPIO_TIM4_CH3IN + case 3: + return GPIO_TIM4_CH3IN; +#endif +#ifdef GPIO_TIM4_CH4IN + case 4: + return GPIO_TIM4_CH4IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM5_CAP + case STM32_TIM5_BASE: + switch (channel) + { +#ifdef GPIO_TIM5_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM5_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM5_CH1IN + case 1: + return GPIO_TIM5_CH1IN; +#endif +#ifdef GPIO_TIM5_CH2IN + case 2: + return GPIO_TIM5_CH2IN; +#endif +#ifdef GPIO_TIM5_CH3IN + case 3: + return GPIO_TIM5_CH3IN; +#endif +#ifdef GPIO_TIM5_CH4IN + case 4: + return GPIO_TIM5_CH4IN; +#endif + } + break; +#endif + + /* TIM6 and TIM7 cannot be used in capture */ + +#ifdef CONFIG_STM32H7_TIM8_CAP + case STM32_TIM8_BASE: + switch (channel) + { +#ifdef GPIO_TIM8_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM8_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM8_CH1IN + case 1: + return GPIO_TIM8_CH1IN; +#endif +#ifdef GPIO_TIM8_CH2IN + case 2: + return GPIO_TIM8_CH2IN; +#endif +#ifdef GPIO_TIM8_CH3IN + case 3: + return GPIO_TIM8_CH3IN; +#endif +#ifdef GPIO_TIM8_CH4IN + case 4: + return GPIO_TIM8_CH4IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM9_CAP + case STM32_TIM9_BASE: + switch (channel) + { +#ifdef GPIO_TIM9_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM9_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM9_CH1IN + case 1: + return GPIO_TIM9_CH1IN; +#endif +#ifdef GPIO_TIM9_CH2IN + case 2: + return GPIO_TIM9_CH2IN; +#endif +#ifdef GPIO_TIM9_CH3IN + case 3: + return GPIO_TIM9_CH3IN; +#endif +#ifdef GPIO_TIM9_CH4IN + case 4: + return GPIO_TIM9_CH4IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM10_CAP + case STM32_TIM10_BASE: + switch (channel) + { +#ifdef GPIO_TIM10_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM10_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM10_CH1IN + case 1: + return GPIO_TIM10_CH1IN; +#endif +#ifdef GPIO_TIM10_CH2IN + case 2: + return GPIO_TIM10_CH2IN; +#endif +#ifdef GPIO_TIM10_CH4IN + case 3: + return GPIO_TIM10_CH4IN; +#endif +#ifdef GPIO_TIM10_CH5IN + case 4: + return GPIO_TIM10_CH5IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM11_CAP + case STM32_TIM11_BASE: + switch (channel) + { +#ifdef GPIO_TIM11_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM11_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM11_CH1IN + case 1: + return GPIO_TIM11_CH1IN; +#endif +#ifdef GPIO_TIM11_CH2IN + case 2: + return GPIO_TIM11_CH2IN; +#endif +#ifdef GPIO_TIM11_CH4IN + case 3: + return GPIO_TIM11_CH4IN; +#endif +#ifdef GPIO_TIM11_CH5IN + case 4: + return GPIO_TIM11_CH5IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM12_CAP + case STM32_TIM12_BASE: + switch (channel) + { +#ifdef GPIO_TIM12_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM12_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM12_CH1IN + case 1: + return GPIO_TIM12_CH1IN; +#endif +#ifdef GPIO_TIM12_CH2IN + case 2: + return GPIO_TIM12_CH2IN; +#endif +#ifdef GPIO_TIM12_CH4IN + case 3: + return GPIO_TIM12_CH4IN; +#endif +#ifdef GPIO_TIM12_CH5IN + case 4: + return GPIO_TIM12_CH5IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM13_CAP + case STM32_TIM13_BASE: + switch (channel) + { +#ifdef GPIO_TIM13_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM13_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM13_CH1IN + case 1: + return GPIO_TIM13_CH1IN; +#endif +#ifdef GPIO_TIM13_CH2IN + case 2: + return GPIO_TIM13_CH2IN; +#endif +#ifdef GPIO_TIM13_CH4IN + case 3: + return GPIO_TIM13_CH4IN; +#endif +#ifdef GPIO_TIM13_CH5IN + case 4: + return GPIO_TIM13_CH5IN; +#endif + } + break; +#endif + +#ifdef CONFIG_STM32H7_TIM14_CAP + case STM32_TIM14_BASE: + switch (channel) + { +#ifdef GPIO_TIM14_EXT_CLK_IN + case STM32_CAP_CHANNEL_COUNTER: + return GPIO_TIM14_EXT_CLK_IN; +#endif +#ifdef GPIO_TIM14_CH1IN + case 1: + return GPIO_TIM14_CH1IN; +#endif +#ifdef GPIO_TIM14_CH2IN + case 2: + return GPIO_TIM14_CH2IN; +#endif +#ifdef GPIO_TIM14_CH4IN + case 3: + return GPIO_TIM14_CH4IN; +#endif +#ifdef GPIO_TIM14_CH5IN + case 4: + return GPIO_TIM14_CH5IN; +#endif + } + break; +#endif + } + + return 0; +} + +static inline int stm32_cap_set_rcc(const struct stm32_cap_priv_s *priv, + bool on) +{ + uint32_t offset = 0; + uint32_t mask = 0; + + switch (priv->base) + { + /* APB2 Timers */ + +#ifdef CONFIG_STM32H7_TIM1_CAP + case STM32_TIM1_BASE: + offset = STM32_RCC_APB2ENR; + mask = RCC_APB2ENR_TIM1EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM8_CAP + case STM32_TIM8_BASE: + offset = STM32_RCC_APB2ENR; + mask = RCC_APB2ENR_TIM8EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM15_CAP + case STM32_TIM15_BASE: + offset = STM32_RCC_APB2ENR; + mask = RCC_APB2ENR_TIM15EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM16_CAP + case STM32_TIM16_BASE: + offset = STM32_RCC_APB2ENR; + mask = RCC_APB2ENR_TIM16EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM17_CAP + case STM32_TIM17_BASE: + offset = STM32_RCC_APB2ENR; + mask = RCC_APB2ENR_TIM17EN; + break; +#endif + + /* APB1L Timers */ + +#ifdef CONFIG_STM32H7_TIM2_CAP + case STM32_TIM2_BASE: + offset = STM32_RCC_APB1LENR; + mask = RCC_APB1LENR_TIM2EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM3_CAP + case STM32_TIM3_BASE: + offset = STM32_RCC_APB1LENR; + mask = RCC_APB1LENR_TIM3EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM4_CAP + case STM32_TIM4_BASE: + offset = STM32_RCC_APB1LENR; + mask = RCC_APB1LENR_TIM4EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM5_CAP + case STM32_TIM5_BASE: + offset = STM32_RCC_APB1LENR; + mask = RCC_APB1LENR_TIM5EN; + break; +#endif + /* TIM6 and TIM7 cannot be used in capture */ +#ifdef CONFIG_STM32H7_TIM12_CAP + case STM32_TIM12_BASE: + offset = STM32_RCC_APB1LENR; + mask = RCC_APB1LENR_TIM12EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM13_CAP + case STM32_TIM13_BASE: + offset = STM32_RCC_APB1LENR; + mask = RCC_APB1LENR_TIM13EN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM14_CAP + case STM32_TIM14_BASE: + offset = STM32_RCC_APB1LENR; + mask = RCC_APB1LENR_TIM14EN; + break; +#endif +#ifdef CONFIG_STM32H7_LPTIM1_CAP + case STM32_LPTIM1_BASE: + offset = STM32_RCC_APB1LENR; + mask = RCC_APB1LENR_LPTIM1EN; + break; +#endif + + /* APB4 Timers */ + +#ifdef CONFIG_STM32H7_LPTIM2_CAP + case STM32_LPTIM2_BASE: + offset = STM32_RCC_APB4ENR; + mask = RCC_APB4ENR_LPTIM2EN; + break; +#endif +#ifdef CONFIG_STM32H7_LPTIM3_CAP + case STM32_LPTIM3_BASE: + offset = STM32_RCC_APB4ENR; + mask = RCC_APB4ENR_LPTIM3EN; + break; +#endif +#ifdef CONFIG_STM32H7_LPTIM4_CAP + case STM32_LPTIM4_BASE: + offset = STM32_RCC_APB4ENR; + mask = RCC_APB4ENR_LPTIM4EN; + break; +#endif +#ifdef CONFIG_STM32H7_LPTIM5_CAP + case STM32_LPTIM5_BASE: + offset = STM32_RCC_APB4ENR; + mask = RCC_APB4ENR_LPTIM5EN; + break; +#endif + + default: + return -EINVAL; + } + + if (on) + { + modifyreg32(offset, 0, mask); + } + else + { + modifyreg32(offset, mask, 0); + } + + return OK; +} + +/**************************************************************************** + * Basic Functions + ****************************************************************************/ + +static int stm32_cap_setclock(struct stm32_cap_dev_s *dev, + uint32_t freq, uint32_t max) +{ + const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; + uint32_t freqin; + int prescaler; + + /* Disable Timer? */ + + if (freq == 0) + { + /* Disable Timer */ + + stm32_modifyreg16(priv, STM32_BTIM_CR1_OFFSET, ATIM_CR1_CEN, 0); + return 0; + } + + /* Get the input clock frequency for this timer. These vary with + * different timer clock sources, MCU-specific timer configuration, and + * board-specific clock configuration. The correct input clock frequency + * must be defined in the board.h header file. + */ + + switch (priv->base) + { +#ifdef CONFIG_STM32H7_TIM1 + case STM32_TIM1_BASE: + freqin = STM32_APB2_TIM1_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM2 + case STM32_TIM2_BASE: + freqin = STM32_APB1_TIM2_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM3 + case STM32_TIM3_BASE: + freqin = STM32_APB1_TIM3_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM4 + case STM32_TIM4_BASE: + freqin = STM32_APB1_TIM4_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM5 + case STM32_TIM5_BASE: + freqin = STM32_APB1_TIM5_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM8 + case STM32_TIM8_BASE: + freqin = STM32_APB2_TIM8_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM9 + case STM32_TIM9_BASE: + freqin = STM32_APB2_TIM9_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM10 + case STM32_TIM10_BASE: + freqin = STM32_APB2_TIM10_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM11 + case STM32_TIM11_BASE: + freqin = STM32_APB2_TIM11_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM12 + case STM32_TIM12_BASE: + freqin = STM32_APB1_TIM12_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM13 + case STM32_TIM13_BASE: + freqin = STM32_APB1_TIM13_CLKIN; + break; +#endif +#ifdef CONFIG_STM32H7_TIM14 + case STM32_TIM14_BASE: + freqin = STM32_APB1_TIM14_CLKIN; + break; +#endif + + default: + return -EINVAL; + } + + /* Select a pre-scaler value for this timer using the input clock + * frequency. + */ + + prescaler = freqin / freq; + + /* We need to decrement value for '1', but only, if we are allowed to + * not to cause underflow. Check for overflow. + */ + + if (prescaler > 0) + { + prescaler--; + } + + if (prescaler > 0xffff) + { + prescaler = 0xffff; + } + + /* Set Maximum */ + + stm32_putreg32(priv, STM32_BTIM_ARR_OFFSET, max); + + /* Set prescaler */ + + stm32_putreg16(priv, STM32_BTIM_PSC_OFFSET, prescaler); + + /* Reset counter timer */ + + stm32_modifyreg16(priv, STM32_BTIM_EGR_OFFSET, 0, BTIM_EGR_UG); + + /* Enable timer */ + + stm32_modifyreg16(priv, STM32_BTIM_CR1_OFFSET, 0, BTIM_CR1_CEN); + +#ifdef USE_ADVANCED_TIM + /* Advanced registers require Main Output Enable */ + + if (priv->base == STM32_TIM1_BASE || priv->base == STM32_TIM8_BASE) + { + stm32_modifyreg16(priv, STM32_ATIM_BDTR_OFFSET, 0, ATIM_BDTR_MOE); + } +#endif + + return prescaler; +} + +/**************************************************************************** + * Name: stm32_cap_setsmc + * + * Description: + * set slave mode control register + * + * Input Parameters: + * dev - A pointer of the stm32 capture device structure. + * cfg - Slave mode control register configure of timer. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32_cap_setsmc(struct stm32_cap_dev_s *dev, + stm32_cap_smc_cfg_t cfg) +{ + const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; + uint16_t regval = 0; + uint16_t mask = 0; + + switch (cfg & STM32_CAP_SMS_MASK) + { + case STM32_CAP_SMS_INT: + regval |= GTIM_SMCR_DISAB; + break; + + case STM32_CAP_SMS_ENC1: + regval |= GTIM_SMCR_ENCMD1; + break; + + case STM32_CAP_SMS_ENC2: + regval |= GTIM_SMCR_ENCMD2; + break; + + case STM32_CAP_SMS_ENC3: + regval |= GTIM_SMCR_ENCMD3; + break; + + case STM32_CAP_SMS_RST: + regval |= GTIM_SMCR_RESET; + break; + + case STM32_CAP_SMS_GAT: + regval |= GTIM_SMCR_GATED; + break; + + case STM32_CAP_SMS_TRG: + regval |= GTIM_SMCR_TRIGGER; + break; + + case STM32_CAP_SMS_EXT: + regval |= GTIM_SMCR_EXTCLK1; + break; + + default: + break; + } + + switch (cfg & STM32_CAP_TS_MASK) + { + case STM32_CAP_TS_ITR0: + regval |= GTIM_SMCR_ITR0; + break; + + case STM32_CAP_TS_ITR1: + regval |= GTIM_SMCR_ITR1; + break; + + case STM32_CAP_TS_ITR2: + regval |= GTIM_SMCR_ITR2; + break; + + case STM32_CAP_TS_ITR3: + regval |= GTIM_SMCR_ITR3; + break; + + case STM32_CAP_TS_TI1FED: + regval |= GTIM_SMCR_TI1FED; + break; + + case STM32_CAP_TS_TI1FP1: + regval |= GTIM_SMCR_TI1FP1; + break; + + case STM32_CAP_TS_TI2FP2: + regval |= GTIM_SMCR_TI2FP2; + break; + + case STM32_CAP_TS_ETRF: + regval |= GTIM_SMCR_ETRF; + break; + + default: + break; + } + + if (cfg & STM32_CAP_MSM_MASK) + { + regval |= STM32_CAP_MSM_MASK; + } + + mask = (STM32_CAP_SMS_MASK | STM32_CAP_TS_MASK | STM32_CAP_MSM_MASK); + stm32_modifyreg16(priv, STM32_GTIM_SMCR_OFFSET, mask, regval); + + return OK; +} + +static int stm32_cap_setisr(struct stm32_cap_dev_s *dev, xcpt_t handler, + void *arg) +{ + const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; + int irq; +#ifdef USE_ADVANCED_TIM + int irq_of; +#endif + + DEBUGASSERT(dev != NULL); + + irq = priv->irq; +#ifdef USE_ADVANCED_TIM + irq_of = priv->irq_of; +#endif + + /* Disable interrupt when callback is removed */ + + if (!handler) + { + up_disable_irq(irq); + irq_detach(irq); + +#ifdef USE_ADVANCED_TIM + if (priv->irq_of) + { + up_disable_irq(irq_of); + irq_detach(irq_of); + } +#endif + + return OK; + } + + /* Otherwise set callback and enable interrupt */ + + irq_attach(irq, handler, arg); + up_enable_irq(irq); + +#ifdef USE_ADVANCED_TIM + if (priv->irq_of) + { + irq_attach(priv->irq_of, handler, arg); + up_enable_irq(priv->irq_of); + } +#endif + + return OK; +} + +static void stm32_cap_enableint(struct stm32_cap_dev_s *dev, + stm32_cap_flags_t src, bool on) +{ + const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; + uint16_t mask = 0; + + DEBUGASSERT(dev != NULL); + + if (src & STM32_CAP_FLAG_IRQ_COUNTER) + { + mask |= ATIM_DIER_UIE; + } + + if (src & STM32_CAP_FLAG_IRQ_CH_1) + { + mask |= ATIM_DIER_CC1IE; + } + + if (src & STM32_CAP_FLAG_IRQ_CH_2) + { + mask |= ATIM_DIER_CC2IE; + } + + if (src & STM32_CAP_FLAG_IRQ_CH_3) + { + mask |= ATIM_DIER_CC3IE; + } + + if (src & STM32_CAP_FLAG_IRQ_CH_4) + { + mask |= ATIM_DIER_CC4IE; + } + + /* Not IRQ on channel overflow */ + + if (on) + { + stm32_modifyreg16(priv, STM32_BTIM_DIER_OFFSET, 0, mask); + } + else + { + stm32_modifyreg16(priv, STM32_BTIM_DIER_OFFSET, mask, 0); + } +} + +static void stm32_cap_ackflags(struct stm32_cap_dev_s *dev, int flags) +{ + const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; + uint16_t mask = 0; + + if (flags & STM32_CAP_FLAG_IRQ_COUNTER) + { + mask |= ATIM_SR_UIF; + } + + if (flags & STM32_CAP_FLAG_IRQ_CH_1) + { + mask |= ATIM_SR_CC1IF; + } + + if (flags & STM32_CAP_FLAG_IRQ_CH_2) + { + mask |= ATIM_SR_CC2IF; + } + + if (flags & STM32_CAP_FLAG_IRQ_CH_3) + { + mask |= ATIM_SR_CC3IF; + } + + if (flags & STM32_CAP_FLAG_IRQ_CH_4) + { + mask |= ATIM_SR_CC4IF; + } + + if (flags & STM32_CAP_FLAG_OF_CH_1) + { + mask |= ATIM_SR_CC1OF; + } + + if (flags & STM32_CAP_FLAG_OF_CH_2) + { + mask |= ATIM_SR_CC2OF; + } + + if (flags & STM32_CAP_FLAG_OF_CH_3) + { + mask |= ATIM_SR_CC3OF; + } + + if (flags & STM32_CAP_FLAG_OF_CH_4) + { + mask |= ATIM_SR_CC4OF; + } + + stm32_putreg16(priv, STM32_BTIM_SR_OFFSET, ~mask); +} + +static stm32_cap_flags_t stm32_cap_getflags(struct stm32_cap_dev_s *dev) +{ + const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; + uint16_t regval = 0; + stm32_cap_flags_t flags = 0; + + regval = stm32_getreg16(priv, STM32_BTIM_SR_OFFSET); + + if (regval & ATIM_SR_UIF) + { + flags |= STM32_CAP_FLAG_IRQ_COUNTER; + } + + if (regval & ATIM_SR_CC1IF) + { + flags |= STM32_CAP_FLAG_IRQ_CH_1; + } + + if (regval & ATIM_SR_CC2IF) + { + flags |= STM32_CAP_FLAG_IRQ_CH_2; + } + + if (regval & ATIM_SR_CC3IF) + { + flags |= STM32_CAP_FLAG_IRQ_CH_3; + } + + if (regval & ATIM_SR_CC4IF) + { + flags |= STM32_CAP_FLAG_IRQ_CH_4; + } + + if (regval & ATIM_SR_CC1OF) + { + flags |= STM32_CAP_FLAG_OF_CH_1; + } + + if (regval & ATIM_SR_CC2OF) + { + flags |= STM32_CAP_FLAG_OF_CH_2; + } + + if (regval & ATIM_SR_CC3OF) + { + flags |= STM32_CAP_FLAG_OF_CH_3; + } + + if (regval & ATIM_SR_CC4OF) + { + flags |= STM32_CAP_FLAG_OF_CH_4; + } + + return flags; +} + +/**************************************************************************** + * General Functions + ****************************************************************************/ + +static int stm32_cap_setchannel(struct stm32_cap_dev_s *dev, + uint8_t channel, + stm32_cap_ch_cfg_t cfg) +{ + const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; + uint32_t gpio = 0; + uint16_t mask; + uint16_t regval; + uint16_t ccer_en_bit; + + DEBUGASSERT(dev != NULL); + + gpio = stm32_cap_gpio(priv, channel); + + if (gpio == 0) + { + return ERROR; + } + + if ((cfg & STM32_CAP_MAPPED_MASK) == 0) + { + return ERROR; /* MAPPED not selected */ + } + + /* Change to zero base index */ + + channel--; + + /* Set ccer : + * + * GTIM_CCER_CCxE Is written latter to allow writing CCxS bits. + * + */ + + switch (cfg & STM32_CAP_EDGE_MASK) + { + case STM32_CAP_EDGE_DISABLED: + regval = 0; + ccer_en_bit = 0; + break; + + case STM32_CAP_EDGE_RISING: + ccer_en_bit = GTIM_CCER_CC1E; + regval = 0; + break; + + case STM32_CAP_EDGE_FALLING: + ccer_en_bit = GTIM_CCER_CC1E; + regval = GTIM_CCER_CC1P; + break; + + case STM32_CAP_EDGE_BOTH: + ccer_en_bit = GTIM_CCER_CC1E; + regval = GTIM_CCER_CC1P | GTIM_CCER_CC1NP; + break; + + default: + return ERROR; + } + + /* Shift all CCER bits to corresponding channel */ + + mask = (GTIM_CCER_CC1E | GTIM_CCER_CC1P | GTIM_CCER_CC1NP); + mask <<= GTIM_CCER_CCXBASE(channel); + regval <<= GTIM_CCER_CCXBASE(channel); + ccer_en_bit <<= GTIM_CCER_CCXBASE(channel); + + stm32_modifyreg16(priv, STM32_GTIM_CCER_OFFSET, mask, regval); + + /* Set ccmr */ + + regval = cfg; + mask = (GTIM_CCMR1_IC1F_MASK | + GTIM_CCMR1_IC1PSC_MASK | + GTIM_CCMR1_CC1S_MASK); + regval &= mask; + + if (channel & 1) + { + regval <<= 8; + mask <<= 8; + } + + if (channel < 2) + { + stm32_modifyreg16(priv, STM32_GTIM_CCMR1_OFFSET, mask, regval); + } + else + { + stm32_modifyreg16(priv, STM32_GTIM_CCMR2_OFFSET, mask, regval); + } + + /* Set GPIO */ + + if ((cfg & STM32_CAP_EDGE_MASK) == STM32_CAP_EDGE_DISABLED) + { + stm32_unconfiggpio(gpio); + } + else + { + stm32_configgpio(gpio); + } + + /* Enable this channel timer */ + + stm32_modifyreg16(priv, STM32_GTIM_CCER_OFFSET, 0, ccer_en_bit); + return OK; +} + +static uint32_t stm32_cap_getcapture(struct stm32_cap_dev_s *dev, + uint8_t channel) +{ + const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; + uint32_t offset; + + DEBUGASSERT(dev != NULL); + + switch (channel) + { + case STM32_CAP_CHANNEL_COUNTER: + offset = STM32_GTIM_CNT_OFFSET; + break; +#ifdef HAVE_CH1IN + case 1: + offset = STM32_GTIM_CCR1_OFFSET; + break; +#endif +#ifdef HAVE_CH2IN + case 2: + offset = STM32_GTIM_CCR2_OFFSET; + break; +#endif +#ifdef HAVE_CH3IN + case 3: + offset = STM32_GTIM_CCR3_OFFSET; + break; +#endif +#ifdef HAVE_CH4IN + case 4: + offset = STM32_GTIM_CCR4_OFFSET; + break; +#endif + default: + return ERROR; + } + + if (priv->base == STM32_TIM2_BASE || priv->base == STM32_TIM5_BASE) + { + return stm32_getreg32(priv, offset); + } + + return stm32_getreg16(priv, offset); +} + +/**************************************************************************** + * Advanced Functions + ****************************************************************************/ + +/* TODO: Advanced functions for the STM32_ATIM */ + +/**************************************************************************** + * Device Structures, Instantiation + ****************************************************************************/ + +struct stm32_cap_ops_s stm32_cap_ops = +{ + .setsmc = &stm32_cap_setsmc, + .setclock = &stm32_cap_setclock, + .setchannel = &stm32_cap_setchannel, + .getcapture = &stm32_cap_getcapture, + .setisr = &stm32_cap_setisr, + .enableint = &stm32_cap_enableint, + .ackflags = &stm32_cap_ackflags, + .getflags = &stm32_cap_getflags +}; + +#ifdef CONFIG_STM32H7_TIM1_CAP +const struct stm32_cap_priv_s stm32_tim1_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM1_BASE, + .irq = STM32_IRQ_TIM1CC, +#ifdef USE_ADVANCED_TIM + .irq_of = STM32_IRQ_TIM1UP, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM2_CAP +const struct stm32_cap_priv_s stm32_tim2_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM2_BASE, + .irq = STM32_IRQ_TIM2, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM3_CAP +const struct stm32_cap_priv_s stm32_tim3_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM3_BASE, + .irq = STM32_IRQ_TIM3, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM4_CAP +const struct stm32_cap_priv_s stm32_tim4_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM4_BASE, + .irq = STM32_IRQ_TIM4, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM5_CAP +const struct stm32_cap_priv_s stm32_tim5_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM5_BASE, + .irq = STM32_IRQ_TIM5, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +/* TIM6 and TIM7 cannot be used in capture */ + +#ifdef CONFIG_STM32H7_TIM8_CAP +const struct stm32_cap_priv_s stm32_tim8_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM8_BASE, + .irq = STM32_IRQ_TIM8CC, +#ifdef USE_ADVANCED_TIM + .irq_of = STM32_IRQ_TIM8UP, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM9_CAP +const struct stm32_cap_priv_s stm32_tim9_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM9_BASE, + .irq = STM32_IRQ_TIM9, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM10_CAP +const struct stm32_cap_priv_s stm32_tim10_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM10_BASE, + .irq = STM32_IRQ_TIM10, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM11_CAP +const struct stm32_cap_priv_s stm32_tim11_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM11_BASE, + .irq = STM32_IRQ_TIM11, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM12_CAP +const struct stm32_cap_priv_s stm32_tim12_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM12_BASE, + .irq = STM32_IRQ_TIM12, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM13_CAP +const struct stm32_cap_priv_s stm32_tim13_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM13_BASE, + .irq = STM32_IRQ_TIM13, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM14_CAP +const struct stm32_cap_priv_s stm32_tim14_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM14_BASE, + .irq = STM32_IRQ_TIM14, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM15_CAP +static const struct stm32_cap_priv_s stm32_tim15_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM15_BASE, + .irq = STM32_IRQ_TIM15, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM16_CAP +static const struct stm32_cap_priv_s stm32_tim16_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM16_BASE, + .irq = STM32_IRQ_TIM16, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +#ifdef CONFIG_STM32H7_TIM17_CAP +static const struct stm32_cap_priv_s stm32_tim17_priv = +{ + .ops = &stm32_cap_ops, + .base = STM32_TIM17_BASE, + .irq = STM32_IRQ_TIM17, +#ifdef USE_ADVANCED_TIM + .irq_of = 0, +#endif +}; +#endif + +static inline const struct stm32_cap_priv_s * stm32_cap_get_priv(int timer) +{ + switch (timer) + { +#ifdef CONFIG_STM32H7_TIM1_CAP + case 1: + return &stm32_tim1_priv; +#endif +#ifdef CONFIG_STM32H7_TIM2_CAP + case 2: + return &stm32_tim2_priv; +#endif +#ifdef CONFIG_STM32H7_TIM3_CAP + case 3: + return &stm32_tim3_priv; +#endif +#ifdef CONFIG_STM32H7_TIM4_CAP + case 4: + return &stm32_tim4_priv; +#endif +#ifdef CONFIG_STM32H7_TIM5_CAP + case 5: + return &stm32_tim5_priv; +#endif + + /* TIM6 and TIM7 cannot be used in capture */ + +#ifdef CONFIG_STM32H7_TIM8_CAP + case 8: + return &stm32_tim8_priv; +#endif +#ifdef CONFIG_STM32H7_TIM9_CAP + case 9: + return &stm32_tim9_priv; +#endif +#ifdef CONFIG_STM32H7_TIM10_CAP + case 10: + return &stm32_tim10_priv; +#endif +#ifdef CONFIG_STM32H7_TIM11_CAP + case 11: + return &stm32_tim11_priv; +#endif +#ifdef CONFIG_STM32H7_TIM12_CAP + case 12: + return &stm32_tim12_priv; +#endif +#ifdef CONFIG_STM32H7_TIM13_CAP + case 13: + return &stm32_tim13_priv; +#endif +#ifdef CONFIG_STM32H7_TIM14_CAP + case 14: + return &stm32_tim14_priv; +#endif + } + + return NULL; +} + +/**************************************************************************** + * Public Function - Initialization + ****************************************************************************/ + +struct stm32_cap_dev_s *stm32_cap_init(int timer, uint8_t channel) +{ + const struct stm32_cap_priv_s *priv = stm32_cap_get_priv(timer); + uint32_t gpio; + + if (priv) + { + stm32_cap_set_rcc(priv, true); + + gpio = stm32_cap_gpio(priv, channel); + if (gpio) + { + stm32_configgpio(gpio); + } + + /* Disable timer while is not configured */ + + stm32_modifyreg16(priv, STM32_BTIM_CR1_OFFSET, ATIM_CR1_CEN, 0); + } + + return (struct stm32_cap_dev_s *)priv; +} + +int stm32_cap_deinit(struct stm32_cap_dev_s * dev, uint8_t channel) +{ + const struct stm32_cap_priv_s *priv = (struct stm32_cap_priv_s *)dev; + uint32_t gpio; + + DEBUGASSERT(dev != NULL); + + /* Disable timer while is not configured */ + + stm32_modifyreg16(priv, STM32_BTIM_CR1_OFFSET, ATIM_CR1_CEN, 0); + + gpio = stm32_cap_gpio(priv, channel); + if (gpio) + { + stm32_unconfiggpio(gpio); + } + + stm32_cap_set_rcc(priv, false); + return OK; +} + +#endif /* defined(CONFIG_STM32H7_TIM1 || ... || TIM14) */ diff --git a/arch/arm/src/stm32h7/stm32_capture.h b/arch/arm/src/stm32h7/stm32_capture.h new file mode 100644 index 00000000000..954cd911a25 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_capture.h @@ -0,0 +1,240 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_capture.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_STM32H7_STM32_CAPTURE_H +#define __ARCH_ARM_SRC_STM32H7_STM32_CAPTURE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include "chip.h" +#include <arch/board/board.h> +#include "hardware/stm32_tim.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Helpers ******************************************************************/ + +#define STM32_CAP_SETSMC(d,cfg) ((d)->ops->setsmc(d,cfg)) +#define STM32_CAP_SETCLOCK(d,clk,max) ((d)->ops->setclock(d,clk,max)) +#define STM32_CAP_SETCHANNEL(d,ch,cfg) ((d)->ops->setchannel(d,ch,cfg)) +#define STM32_CAP_GETCAPTURE(d,ch) ((d)->ops->getcapture(d,ch)) +#define STM32_CAP_SETISR(d,hnd,arg) ((d)->ops->setisr(d,hnd,arg)) +#define STM32_CAP_ENABLEINT(d,s,on) ((d)->ops->enableint(d,s,on)) +#define STM32_CAP_ACKFLAGS(d,f) ((d)->ops->ackflags(d,f)) +#define STM32_CAP_GETFLAGS(d) ((d)->ops->getflags(d)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* Capture Device Structure */ + +struct stm32_cap_dev_s +{ + struct stm32_cap_ops_s *ops; +}; + +/* Capture input EDGE sources */ + +typedef enum +{ + /* Mapped */ + + STM32_CAP_MAPPED_MASK = (GTIM_CCMR1_CC1S_MASK), + STM32_CAP_MAPPED_TI1 = (GTIM_CCMR_CCS_CCIN1), + STM32_CAP_MAPPED_TI2 = (GTIM_CCMR_CCS_CCIN2), + +/* TODO STM32_CAP_MAPPED_TRC = (GTIM_CCMR_CCS_CCINTRC), */ + + /* Event prescaler */ + + STM32_CAP_INPSC_MASK = (GTIM_CCMR1_IC1PSC_MASK), + STM32_CAP_INPSC_NO = (0 << GTIM_CCMR1_IC1PSC_SHIFT), + STM32_CAP_INPSC_2EVENTS = (1 << GTIM_CCMR1_IC1PSC_SHIFT), + STM32_CAP_INPSC_4EVENTS = (2 << GTIM_CCMR1_IC1PSC_SHIFT), + STM32_CAP_INPSC_8EVENTS = (3 << GTIM_CCMR1_IC1PSC_SHIFT), + + /* Event prescaler */ + + STM32_CAP_FILTER_MASK = (GTIM_CCMR1_IC1F_MASK), + STM32_CAP_FILTER_NO = (0 << GTIM_CCMR1_IC1F_SHIFT), + + /* Internal clock with N time to confirm event */ + + STM32_CAP_FILTER_INT_N2 = (1 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_INT_N4 = (2 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_INT_N8 = (3 << GTIM_CCMR1_IC1F_SHIFT), + + /* DTS clock div by D with N time to confirm event */ + + STM32_CAP_FILTER_DTS_D2_N6 = (4 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D2_N8 = (5 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D4_N6 = (6 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D4_N8 = (7 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D8_N6 = (8 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D8_N8 = (9 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D16_N5 = (10 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D16_N6 = (11 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D16_N8 = (12 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D32_N5 = (13 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D32_N6 = (14 << GTIM_CCMR1_IC1F_SHIFT), + STM32_CAP_FILTER_DTS_D32_N8 = (15 << GTIM_CCMR1_IC1F_SHIFT), + + /* EDGE */ + + STM32_CAP_EDGE_MASK = (3 << 8), + STM32_CAP_EDGE_DISABLED = (0 << 8), + STM32_CAP_EDGE_RISING = (1 << 8), + STM32_CAP_EDGE_FALLING = (2 << 8), + STM32_CAP_EDGE_BOTH = (3 << 8), +} stm32_cap_ch_cfg_t; + +/* Slave mode control configure */ + +typedef enum +{ + /* Slave mode selection */ + + STM32_CAP_SMS_MASK = (7 << GTIM_SMCR_SMS_SHIFT), + STM32_CAP_SMS_INT = (0 << GTIM_SMCR_SMS_SHIFT), + STM32_CAP_SMS_ENC1 = (1 << GTIM_SMCR_SMS_SHIFT), + STM32_CAP_SMS_ENC2 = (2 << GTIM_SMCR_SMS_SHIFT), + STM32_CAP_SMS_ENC3 = (3 << GTIM_SMCR_SMS_SHIFT), + STM32_CAP_SMS_RST = (4 << GTIM_SMCR_SMS_SHIFT), + STM32_CAP_SMS_GAT = (5 << GTIM_SMCR_SMS_SHIFT), + STM32_CAP_SMS_TRG = (6 << GTIM_SMCR_SMS_SHIFT), + STM32_CAP_SMS_EXT = (7 << GTIM_SMCR_SMS_SHIFT), + + /* Trigger selection */ + + STM32_CAP_TS_MASK = (7 << GTIM_SMCR_TS_SHIFT), + STM32_CAP_TS_ITR0 = (0 << GTIM_SMCR_TS_SHIFT), + STM32_CAP_TS_ITR1 = (1 << GTIM_SMCR_TS_SHIFT), + STM32_CAP_TS_ITR2 = (2 << GTIM_SMCR_TS_SHIFT), + STM32_CAP_TS_ITR3 = (3 << GTIM_SMCR_TS_SHIFT), + STM32_CAP_TS_TI1FED = (4 << GTIM_SMCR_TS_SHIFT), + STM32_CAP_TS_TI1FP1 = (5 << GTIM_SMCR_TS_SHIFT), + STM32_CAP_TS_TI2FP2 = (6 << GTIM_SMCR_TS_SHIFT), + STM32_CAP_TS_ETRF = (7 << GTIM_SMCR_TS_SHIFT), + + /* Master/Slave mode setting */ + + STM32_CAP_MSM_MASK = (1 << 7) +} stm32_cap_smc_cfg_t; + +/* Capture flags */ + +typedef enum +{ + /* One of the following */ + + STM32_CAP_FLAG_IRQ_COUNTER = (GTIM_SR_UIF), + + STM32_CAP_FLAG_IRQ_CH_1 = (GTIM_SR_CC1IF), + STM32_CAP_FLAG_IRQ_CH_2 = (GTIM_SR_CC2IF), + STM32_CAP_FLAG_IRQ_CH_3 = (GTIM_SR_CC3IF), + STM32_CAP_FLAG_IRQ_CH_4 = (GTIM_SR_CC4IF), + + STM32_CAP_FLAG_OF_CH_1 = (GTIM_SR_CC1OF), + STM32_CAP_FLAG_OF_CH_2 = (GTIM_SR_CC2OF), + STM32_CAP_FLAG_OF_CH_3 = (GTIM_SR_CC3OF), + STM32_CAP_FLAG_OF_CH_4 = (GTIM_SR_CC4OF) +} stm32_cap_flags_t; + +#define STM32_CAP_FLAG_IRQ_CH(ch) (GTIM_SR_CC1IF<<((ch)-1)) +#define STM32_CAP_FLAG_OF_CH(ch) (GTIM_SR_CC1OF<<((ch)-1)) +#define STM32_CAP_CHANNEL_COUNTER 0 + +/* Capture Operations */ + +struct stm32_cap_ops_s +{ + int (*setsmc)(struct stm32_cap_dev_s *dev, stm32_cap_smc_cfg_t cfg); + int (*setclock)(struct stm32_cap_dev_s *dev, uint32_t freq, + uint32_t max); + int (*setchannel)(struct stm32_cap_dev_s *dev, uint8_t channel, + stm32_cap_ch_cfg_t cfg); + uint32_t (*getcapture)(struct stm32_cap_dev_s *dev, uint8_t channel); + int (*setisr)(struct stm32_cap_dev_s *dev, xcpt_t handler, void *arg); + void (*enableint)(struct stm32_cap_dev_s *dev, stm32_cap_flags_t src, + bool on); + void (*ackflags)(struct stm32_cap_dev_s *dev, int flags); + stm32_cap_flags_t (*getflags)(struct stm32_cap_dev_s *dev); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Power-up timer and get its structure */ + +struct stm32_cap_dev_s *stm32_cap_init(int timer, uint8_t channel); + +/* Power-down timer, mark it as unused */ + +int stm32_cap_deinit(struct stm32_cap_dev_s *dev, uint8_t channel); + +/**************************************************************************** + * Name: stm32_cap_initialize + * + * Description: + * Initialize one timer for use with the upper_level capture driver. + * + * Input Parameters: + * timer - A number identifying the timer use. The number of valid timer + * IDs varies with the STM32 MCU and MCU family but is somewhere in + * the range of {1,..,5 8,...,14}. + * + * Returned Value: + * On success, a pointer to the STM32 lower half capture driver returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_CAPTURE +struct cap_lowerhalf_s *stm32_cap_initialize(int timer, uint8_t channel); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_STM32H7_STM32_CAPTURE_H */ diff --git a/arch/arm/src/stm32h7/stm32_capture_lowerhalf.c b/arch/arm/src/stm32h7/stm32_capture_lowerhalf.c new file mode 100644 index 00000000000..84bbeef1331 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_capture_lowerhalf.c @@ -0,0 +1,590 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_capture_lowerhalf.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <nuttx/irq.h> +#include <nuttx/timers/capture.h> + +#include <arch/board/board.h> + +#include "stm32_capture.h" + +#if defined(CONFIG_STM32H7_CAP) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* 32-Bit Timers ************************************************************/ + +#define STM32H7_TIM2_RES 32 +#define STM32H7_TIM5_RES 32 + +/* 16-Bit Timers ************************************************************/ + +/* Advanced-Control Timers */ +#define STM32H7_TIM1_RES 16 +#define STM32H7_TIM8_RES 16 + +/* General-Purpose Timers */ +#define STM32H7_TIM3_RES 16 +#define STM32H7_TIM4_RES 16 +#define STM32H7_TIM12_RES 16 +#define STM32H7_TIM13_RES 16 +#define STM32H7_TIM14_RES 16 +#define STM32H7_TIM15_RES 16 +#define STM32H7_TIM16_RES 16 +#define STM32H7_TIM17_RES 16 + +/* Basic Timers */ +#define STM32H7_TIM6_RES 16 +#define STM32H7_TIM7_RES 16 + +/* Low-Power Timers */ +#define STM32H7_LPTIM1_RES 16 +#define STM32H7_LPTIM2_RES 16 +#define STM32H7_LPTIM3_RES 16 +#define STM32H7_LPTIM4_RES 16 +#define STM32H7_LPTIM5_RES 16 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * cap_lowerhalf_s structure. + */ + +struct stm32_lowerhalf_s +{ + const struct cap_ops_s *ops; /* Lower half operations */ + struct stm32_cap_dev_s *cap; /* stm32 capture driver */ + bool started; /* True: Timer has been started */ + const uint8_t resolution; /* Number of bits in the timer */ + uint8_t channel; /* pwm input channel */ + uint32_t clock; /* Timer clock frequency */ + uint8_t duty; /* Result pwm frequency */ + uint32_t freq; /* Result pwm frequency */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int stm32_cap_handler(int irq, void * context, void * arg); + +/* "Lower half" driver methods **********************************************/ + +static int stm32_start(struct cap_lowerhalf_s *lower); +static int stm32_stop(struct cap_lowerhalf_s *lower); +static int stm32_getduty(struct cap_lowerhalf_s *lower, uint8_t *duty); +static int stm32_getfreq(struct cap_lowerhalf_s *lower, uint32_t *freq); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct cap_ops_s g_cap_ops = +{ + .start = stm32_start, + .stop = stm32_stop, + .getduty = stm32_getduty, + .getfreq = stm32_getfreq, +}; + +#ifdef CONFIG_STM32H7_TIM1_CAP +static struct stm32_lowerhalf_s g_cap1_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM1_RES, + .channel = CONFIG_STM32H7_TIM1_CHANNEL, + .clock = CONFIG_STM32H7_TIM1_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM2_CAP +static struct stm32_lowerhalf_s g_cap2_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM2_RES, + .channel = CONFIG_STM32H7_TIM2_CHANNEL, + .clock = CONFIG_STM32H7_TIM2_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM3_CAP +static struct stm32_lowerhalf_s g_cap3_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM3_RES, + .channel = CONFIG_STM32H7_TIM3_CHANNEL, + .clock = CONFIG_STM32H7_TIM3_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM4_CAP +static struct stm32_lowerhalf_s g_cap4_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM4_RES, + .channel = CONFIG_STM32H7_TIM4_CHANNEL, + .clock = CONFIG_STM32H7_TIM4_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM5_CAP +static struct stm32_lowerhalf_s g_cap5_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM5_RES, + .channel = CONFIG_STM32H7_TIM5_CHANNEL, + .clock = CONFIG_STM32H7_TIM5_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM8_CAP +static struct stm32_lowerhalf_s g_cap8_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM8_RES, + .channel = CONFIG_STM32H7_TIM8_CHANNEL, + .clock = CONFIG_STM32H7_TIM8_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM12_CAP +static struct stm32_lowerhalf_s g_cap12_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM12_RES, + .channel = CONFIG_STM32H7_TIM12_CHANNEL, + .clock = CONFIG_STM32H7_TIM12_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM13_CAP +static struct stm32_lowerhalf_s g_cap13_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM13_RES, + .channel = CONFIG_STM32H7_TIM13_CHANNEL, + .clock = CONFIG_STM32H7_TIM13_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM14_CAP +static struct stm32_lowerhalf_s g_cap14_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM14_RES, + .channel = CONFIG_STM32H7_TIM14_CHANNEL, + .clock = CONFIG_STM32H7_TIM14_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM15_CAP +static struct stm32_lowerhalf_s g_cap15_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM15_RES, + .channel = CONFIG_STM32H7_TIM15_CHANNEL, + .clock = CONFIG_STM32H7_TIM15_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM16_CAP +static struct stm32_lowerhalf_s g_cap16_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM16_RES, + .channel = CONFIG_STM32H7_TIM16_CHANNEL, + .clock = CONFIG_STM32H7_TIM16_CLOCK, +}; +#endif + +#ifdef CONFIG_STM32H7_TIM17_CAP +static struct stm32_lowerhalf_s g_cap17_lowerhalf = +{ + .ops = &g_cap_ops, + .resolution = STM32H7_TIM17_RES, + .channel = CONFIG_STM32H7_TIM17_CHANNEL, + .clock = CONFIG_STM32H7_TIM17_CLOCK, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_cap_handler + * + * Description: + * timer interrupt handler + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +static int stm32_cap_handler(int irq, void * context, void * arg) +{ + struct stm32_lowerhalf_s *lower = (struct stm32_lowerhalf_s *) arg; + uint8_t ch = 0x3 & lower->channel; + int period = 0; + int flags = 0; + + flags = (int)STM32_CAP_GETFLAGS(lower->cap) ; + + STM32_CAP_ACKFLAGS(lower->cap, flags); + + period = STM32_CAP_GETCAPTURE(lower->cap, ch); + + if (period != 0) + { + lower->duty = (100 * STM32_CAP_GETCAPTURE(lower->cap, 0x3 & (~ch))) / + period; + } + else + { + lower->duty = 0; + } + + lower->freq = lower->clock / period; + + return OK; +} + +/**************************************************************************** + * Name: stm32_start + * + * Description: + * Start the timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32_start(struct cap_lowerhalf_s *lower) +{ + struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; + int flags = 0; + uint32_t maxtimeout = (1 << priv->resolution) - 1; + + if (priv->started) + { + /* Return EBUSY to indicate that the timer was already running */ + + return -EBUSY; + } + + switch (priv->channel) + { + case 1: + STM32_CAP_SETSMC(priv->cap, STM32_CAP_SMS_RST | + STM32_CAP_TS_TI1FP1 | + STM32_CAP_MSM_MASK); + + STM32_CAP_SETCLOCK(priv->cap, priv->clock, maxtimeout); + + STM32_CAP_SETCHANNEL(priv->cap, 1, + STM32_CAP_EDGE_RISING | + STM32_CAP_MAPPED_TI1); + STM32_CAP_SETCHANNEL(priv->cap, 2, + STM32_CAP_EDGE_FALLING | + STM32_CAP_MAPPED_TI2); + + flags = (int)STM32_CAP_GETFLAGS(priv->cap); + STM32_CAP_ACKFLAGS(priv->cap, flags); + + STM32_CAP_SETISR(priv->cap, stm32_cap_handler, priv); + STM32_CAP_ENABLEINT(priv->cap, STM32_CAP_FLAG_IRQ_CH_1, true); + + priv->started = true; + break; + + case 2: + STM32_CAP_SETSMC(priv->cap, STM32_CAP_SMS_RST | + STM32_CAP_TS_TI2FP2 | + STM32_CAP_MSM_MASK); + + STM32_CAP_SETCLOCK(priv->cap, priv->clock, maxtimeout); + + STM32_CAP_SETCHANNEL(priv->cap, 2, + STM32_CAP_EDGE_RISING | + STM32_CAP_MAPPED_TI1); + STM32_CAP_SETCHANNEL(priv->cap, 1, + STM32_CAP_EDGE_FALLING | + STM32_CAP_MAPPED_TI2); + + flags = (int)STM32_CAP_GETFLAGS(priv->cap); + STM32_CAP_ACKFLAGS(priv->cap, flags); + + STM32_CAP_SETISR(priv->cap, stm32_cap_handler, priv); + STM32_CAP_ENABLEINT(priv->cap, STM32_CAP_FLAG_IRQ_CH_2, true); + + priv->started = true; + break; + + default: + return ERROR; + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_stop + * + * Description: + * Stop the capture + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32_stop(struct cap_lowerhalf_s *lower) +{ + struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; + + if (priv->started) + { + STM32_CAP_SETCHANNEL(priv->cap, STM32_CAP_FLAG_IRQ_COUNTER, + STM32_CAP_EDGE_DISABLED); + switch (priv->channel) + { + case 1: + STM32_CAP_ENABLEINT(priv->cap, STM32_CAP_FLAG_IRQ_CH_1, false); + break; + + case 2: + STM32_CAP_ENABLEINT(priv->cap, STM32_CAP_FLAG_IRQ_CH_2, false); + break; + + default: + return ERROR; + } + + STM32_CAP_SETISR(priv->cap, NULL, NULL); + priv->started = false; + return OK; + } + + /* Return ENODEV to indicate that the timer was not running */ + + return -ENODEV; +} + +/**************************************************************************** + * Name: stm32_getduty + * + * Description: + * get result duty + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * duty - DutyCycle * 100. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32_getduty(struct cap_lowerhalf_s *lower, uint8_t *duty) +{ + struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; + + irqstate_t flags = enter_critical_section(); + + *duty = priv->duty; + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: stm32_getfreq + * + * Description: + * get result freq + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the + * "lower-half" driver state structure. + * freq - Frequency in Hz. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32_getfreq(struct cap_lowerhalf_s *lower, uint32_t *freq) +{ + struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; + + irqstate_t flags = enter_critical_section(); + + *freq = priv->freq; + + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_cap_initialize + * + * Description: + * Initialize one timer for use with the upper_level capture driver. + * + * Input Parameters: + * timer - A number identifying the timer use. The number of valid timer + * IDs varies with the STM32 MCU and MCU family but is somewhere in + * the range of {1,..,5 8,...,14}. + * + * Returned Value: + * On success, a pointer to the STM32 lower half capture driver returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +struct cap_lowerhalf_s *stm32_cap_initialize(int timer) +{ + struct stm32_lowerhalf_s *lower = NULL; + + switch (timer) + { +#ifdef CONFIG_STM32H7_TIM1_CAP + case 1: + lower = &g_cap1_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM2_CAP + case 2: + lower = &g_cap2_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM3_CAP + case 3: + lower = &g_cap3_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM4_CAP + case 4: + lower = &g_cap4_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM5_CAP + case 5: + lower = &g_cap5_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM8_CAP + case 8: + lower = &g_cap8_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM12_CAP + case 12: + lower = &g_cap12_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM13_CAP + case 13: + lower = &g_cap13_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM14_CAP + case 14: + lower = &g_cap14_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM15_CAP + case 15: + lower = &g_cap15_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM16_CAP + case 16: + lower = &g_cap16_lowerhalf; + break; +#endif +#ifdef CONFIG_STM32H7_TIM17_CAP + case 17: + lower = &g_cap17_lowerhalf; + break; +#endif + /* TODO: LPTIMy_CAP */ + + default: + { + lower = NULL; + goto errout; + } + } + + /* Initialize the elements of lower half state structure */ + + lower->started = false; + lower->cap = stm32_cap_init(timer, lower->channel); + + if (lower->cap == NULL) + { + lower = NULL; + } + +errout: + return (struct cap_lowerhalf_s *)lower; +} + +#endif /* CONFIG_STM32H7_CAP */ diff --git a/boards/arm/stm32h7/nucleo-h743zi/include/board.h b/boards/arm/stm32h7/nucleo-h743zi/include/board.h index cd0b7155d29..c6927c46443 100644 --- a/boards/arm/stm32h7/nucleo-h743zi/include/board.h +++ b/boards/arm/stm32h7/nucleo-h743zi/include/board.h @@ -408,15 +408,73 @@ #define GPIO_SPI3_SCK (GPIO_SPI3_SCK_1 | GPIO_SPEED_50MHz) /* PB3 */ #define GPIO_SPI3_NSS (GPIO_SPI3_NSS_2 | GPIO_SPEED_50MHz) /* PA4 */ -/* TIM1 */ - -#define GPIO_TIM1_CH1OUT (GPIO_TIM1_CH1OUT_2 | GPIO_SPEED_50MHz) /* PE9 - D6 */ -#define GPIO_TIM1_CH1NOUT (GPIO_TIM1_CH1NOUT_3 | GPIO_SPEED_50MHz) /* PE8 - D42 */ -#define GPIO_TIM1_CH2OUT (GPIO_TIM1_CH2OUT_2 | GPIO_SPEED_50MHz) /* PE11 - D5 */ -#define GPIO_TIM1_CH2NOUT (GPIO_TIM1_CH2NOUT_3 | GPIO_SPEED_50MHz) /* PE10 - D40 */ -#define GPIO_TIM1_CH3OUT (GPIO_TIM1_CH3OUT_2 | GPIO_SPEED_50MHz) /* PE13 - D3 */ -#define GPIO_TIM1_CH3NOUT (GPIO_TIM1_CH3NOUT_3 | GPIO_SPEED_50MHz) /* PE12 - D39 */ -#define GPIO_TIM1_CH4OUT (GPIO_TIM1_CH4OUT_2 | GPIO_SPEED_50MHz) /* PE14 - D38 */ +/* TIM1 - Advanced Timer 16-bit (4 channels) */ +#define GPIO_TIM1_CH1IN (GPIO_TIM1_CH1IN_2) /* PE9 */ +#define GPIO_TIM1_CH2IN (GPIO_TIM1_CH2IN_2) /* PE11 */ +#define GPIO_TIM1_CH3IN (GPIO_TIM1_CH3IN_2) /* PE13 */ +#define GPIO_TIM1_CH4IN (GPIO_TIM1_CH4IN_2) /* PE14 */ + +#define GPIO_TIM1_CH1OUT (GPIO_TIM1_CH1OUT_2) /* PE9 - D6 */ +#define GPIO_TIM1_CH1NOUT (GPIO_TIM1_CH1NOUT_3) /* PE8 - D42 */ +#define GPIO_TIM1_CH2OUT (GPIO_TIM1_CH2OUT_2) /* PE11 - D5 */ +#define GPIO_TIM1_CH2NOUT (GPIO_TIM1_CH2NOUT_3) /* PE10 - D40 */ +#define GPIO_TIM1_CH3OUT (GPIO_TIM1_CH3OUT_2) /* PE13 - D3 */ +#define GPIO_TIM1_CH3NOUT (GPIO_TIM1_CH3NOUT_3) /* PE12 - D39 */ +#define GPIO_TIM1_CH4OUT (GPIO_TIM1_CH4OUT_2) /* PE14 - D38 */ + +/* TIM2 - General Purpose 32-bit Timer (4 channels) */ +#define GPIO_TIM2_CH1IN (GPIO_TIM2_CH1IN_2) /* PA15 */ +#define GPIO_TIM2_CH2IN (GPIO_TIM2_CH2IN_1) /* PB3 */ +#define GPIO_TIM2_CH3IN (GPIO_TIM2_CH3IN_1) /* PB10 */ +#define GPIO_TIM2_CH4IN (GPIO_TIM2_CH4IN_1) /* PB11 */ + +/* TIM3 - General Purpose 16-bit Timer (4 channels) */ +#define GPIO_TIM3_CH1IN (GPIO_TIM3_CH1IN_1) /* PA6 */ +#define GPIO_TIM3_CH2IN (GPIO_TIM3_CH2IN_1) /* PA7 */ +#define GPIO_TIM3_CH3IN (GPIO_TIM3_CH3IN_1) /* PB0 */ +#define GPIO_TIM3_CH4IN (GPIO_TIM3_CH4IN_1) /* PB1 */ + +/* TIM4 - General Purpose 16-bit Timer (4 channels) */ +#define GPIO_TIM4_CH1IN (GPIO_TIM4_CH1IN_2) /* PD12 */ +#define GPIO_TIM4_CH2IN (GPIO_TIM4_CH2IN_2) /* PD13 */ +#define GPIO_TIM4_CH3IN (GPIO_TIM4_CH3IN_2) /* PD14 */ +#define GPIO_TIM4_CH4IN (GPIO_TIM4_CH4IN_2) /* PD15 */ + +/* TIM5 - General Purpose 32-bit Timer (4 channels) */ +#define GPIO_TIM5_CH1IN (GPIO_TIM5_CH1IN_2) +#define GPIO_TIM5_CH2IN (GPIO_TIM5_CH2IN_2) +#define GPIO_TIM5_CH3IN (GPIO_TIM5_CH3IN_2) +#define GPIO_TIM5_CH4IN (GPIO_TIM5_CH4IN_2) + +/* TIM6 - Basic 16-bit Timer (0 channels) */ + +/* TIM7 - Basic 16-bit Timer (0 channels) */ + +/* TIM8 - Advanced 16-bit Timer (4 channels) */ +#define GPIO_TIM8_CH1IN (GPIO_TIM8_CH1IN_1) +#define GPIO_TIM8_CH2IN (GPIO_TIM8_CH2IN_1) +#define GPIO_TIM8_CH3IN (GPIO_TIM8_CH3IN_1) +#define GPIO_TIM8_CH4IN (GPIO_TIM8_CH4IN_1) + +/* TIM12 - General purpose 16-bit Timer (2 channels) */ +#define GPIO_TIM12_CH1IN (GPIO_TIM12_CH1IN_1) +#define GPIO_TIM12_CH2IN (GPIO_TIM12_CH2IN_1) + +/* TIM13 - General purpose 16-bit Timer (1 channels) */ +#define GPIO_TIM13_CH1IN (GPIO_TIM13_CH1IN_1) + +/* TIM14 - General purpose 16-bit Timer (1 channels) */ +#define GPIO_TIM14_CH1IN (GPIO_TIM14_CH1IN_1) + +/* TIM15 - General purpose 16-bit Timer (2 channels) */ +#define GPIO_TIM15_CH1IN (GPIO_TIM15_CH1IN_1) +#define GPIO_TIM15_CH2IN (GPIO_TIM15_CH2IN_1) + +/* TIM16 - General purpose 16-bit Timer (1 channels) */ +#define GPIO_TIM16_CH1IN (GPIO_TIM16_CH1IN_1) + +/* TIM17 - General purpose 16-bit Timer (1 channels) */ +#define GPIO_TIM17_CH1IN (GPIO_TIM17_CH1IN_1) /* OTGFS */ diff --git a/boards/arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c b/boards/arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c index 22988c4eb56..4b7b95e16f9 100644 --- a/boards/arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c +++ b/boards/arm/stm32h7/nucleo-h743zi/src/stm32_bringup.c @@ -57,6 +57,11 @@ # include "stm32_romfs.h" #endif +#ifdef CONFIG_CAPTURE +# include <nuttx/timers/capture.h> +# include "stm32_capture.h" +#endif + #ifdef CONFIG_STM32H7_IWDG # include "stm32_wdg.h" #endif @@ -71,6 +76,103 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: stm32_capture_setup + * + * Description: + * Initialize and register capture drivers. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_CAPTURE +static int stm32_capture_setup(void) +{ + int ret; + struct cap_lowerhalf_s *lower[] = + { +#if defined(CONFIG_STM32H7_TIM1_CAP) + stm32_cap_initialize(1), +#endif +#if defined(CONFIG_STM32H7_TIM2_CAP) + stm32_cap_initialize(2), +#endif +#if defined(CONFIG_STM32H7_TIM3_CAP) + stm32_cap_initialize(3), +#endif +#if defined(CONFIG_STM32H7_TIM4_CAP) + stm32_cap_initialize(4), +#endif +#if defined(CONFIG_STM32H7_TIM5_CAP) + stm32_cap_initialize(5), +#endif +#if defined(CONFIG_STM32H7_TIM8_CAP) + stm32_cap_initialize(8), +#endif +#if defined(CONFIG_STM32H7_TIM12_CAP) + stm32_cap_initialize(12), +#endif +#if defined(CONFIG_STM32H7_TIM13_CAP) + stm32_cap_initialize(13), +#endif +#if defined(CONFIG_STM32H7_TIM14_CAP) + stm32_cap_initialize(14), +#endif +#if defined(CONFIG_STM32H7_TIM15_CAP) + stm32_cap_initialize(15), +#endif +#if defined(CONFIG_STM32H7_TIM16_CAP) + stm32_cap_initialize(16), +#endif +#if defined(CONFIG_STM32H7_TIM17_CAP) + stm32_cap_initialize(17), +#endif + /* TODO: LPTIMy_CAP */ + }; + + size_t count = sizeof(lower) / sizeof(lower[0]); + + /* Nothing to do if no timers enabled */ + + if (count == 0) + { + return OK; + } + + /* This will register “/dev/cap0” ... “/dev/cap<count-1>” */ + + ret = cap_register_multiple("/dev/cap", lower, count); + if (ret == EINVAL) + { + syslog(LOG_ERR, + "ERROR: cap_register_multiple path is invalid\n"); + } + else if (ret == EEXIST) + { + syslog(LOG_ERR, "ERROR: cap_register_multiple an inode " + "already exists at this path\n"); + } + else if (ret == ENOMEM) + { + syslog(LOG_ERR, "ERROR: cap_register_multiple not enough " + "memory to register capture drivers\n"); + } + else if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: cap_register_multiple failed: %d\n", + ret); + } + + return ret; +} +#endif + /**************************************************************************** * Name: stm32_i2c_register * @@ -358,6 +460,16 @@ int stm32_bringup(void) } #endif +#ifdef CONFIG_CAPTURE + /* Initialize the capture driver */ + + ret = stm32_capture_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_capture_setup() failed: %d\\n", ret); + } +#endif + #ifdef CONFIG_MTD #ifdef HAVE_PROGMEM_CHARDEV ret = stm32_progmem_init(); diff --git a/drivers/timers/capture.c b/drivers/timers/capture.c index 54e4df38758..7fae3d31fcd 100644 --- a/drivers/timers/capture.c +++ b/drivers/timers/capture.c @@ -469,30 +469,30 @@ int cap_register(FAR const char *devpath, FAR struct cap_lowerhalf_s *lower) } int cap_register_multiple(FAR const char *devpath, - FAR struct cap_lowerhalf_s **lower, int n) + FAR struct cap_lowerhalf_s **lower, + int n) { - FAR struct cap_upperhalf_s *upper; - - /* Allocate the upper-half data structure */ + char fullpath[16]; + int ret; - upper = (FAR struct cap_upperhalf_s *) - kmm_zalloc(sizeof(struct cap_upperhalf_s)); - if (!upper) + if (n < 1) { - return -ENOMEM; + return -EINVAL; } - /* Initialize the PWM Capture device structure - * (it was already zeroed by kmm_zalloc()) - */ - - nxmutex_init(&upper->lock); - upper->lower = lower; - upper->nchan = n; + for (int i = 0; i < n; i++) + { + snprintf(fullpath, sizeof(fullpath), "%s%d", devpath, i); + ret = cap_register(fullpath, lower[i]); + if (ret < 0) + { + /* TODO: unwind */ - /* Register the PWM Capture device */ + return ret; + } + } - return register_driver(devpath, &g_capops, 0666, upper); + return OK; } #endif /* CONFIG_CAPTURE */