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 */


Reply via email to