| /**************************************************************************** |
| * arch/arm/src/stm32f7/stm32_capture.c |
| * |
| * 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_gpio.h" |
| #include "stm32_capture.h" |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| /* Configuration ************************************************************/ |
| |
| #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_TIM9_CH1IN) || defined(GPIO_TIM10_CH1IN) || \ |
| defined(GPIO_TIM11_CH1IN) || defined(GPIO_TIM12_CH1IN) || \ |
| defined(GPIO_TIM13_CH1IN) || defined(GPIO_TIM14_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_TIM9_CH2IN) || defined(GPIO_TIM12_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(CONFIG_STM32_TIM1_CAP) || defined(CONFIG_STM32_TIM8_CAP) |
| #define USE_ADVENCED_TIM 1 |
| #endif |
| |
| #if defined(GPIO_TIM1_EXT_CLK_IN) || defined(GPIO_TIM2_EXT_CLK_IN) || \ |
| defined(GPIO_TIM3_EXT_CLK_IN) || defined(GPIO_TIM4_EXT_CLK_IN) || \ |
| defined(GPIO_TIM5_EXT_CLK_IN) || defined(GPIO_TIM8_EXT_CLK_IN) || \ |
| defined(GPIO_TIM9_EXT_CLK_IN) || defined(GPIO_TIM12_EXT_CLK_IN) |
| # define USE_EXT_CLOCK 1 |
| #endif |
| |
| /* This module then only compiles if there are enabled timers that are not |
| * intended for some other purpose. |
| */ |
| |
| #if defined(CONFIG_STM32F7_TIM1_CAP) || \ |
| defined(CONFIG_STM32F7_TIM2_CAP) || \ |
| defined(CONFIG_STM32F7_TIM3_CAP) || \ |
| defined(CONFIG_STM32F7_TIM4_CAP) || \ |
| defined(CONFIG_STM32F7_TIM5_CAP) || \ |
| defined(CONFIG_STM32F7_TIM8_CAP) || \ |
| defined(CONFIG_STM32F7_TIM9_CAP) || \ |
| defined(CONFIG_STM32F7_TIM10_CAP) || \ |
| defined(CONFIG_STM32F7_TIM11_CAP) || \ |
| defined(CONFIG_STM32F7_TIM12_CAP) || \ |
| defined(CONFIG_STM32F7_TIM13_CAP) || \ |
| defined(CONFIG_STM32F7_TIM14_CAP) |
| |
| /**************************************************************************** |
| * 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_ADVENCED_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 F7 |
| * 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 F7 |
| * 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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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_STM32F7_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) |
| { |
| #ifdef CONFIG_STM32F7_TIM1_CAP |
| case STM32_TIM1_BASE: |
| offset = STM32_RCC_APB2ENR; |
| mask = RCC_APB2ENR_TIM1EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM2_CAP |
| case STM32_TIM2_BASE: |
| offset = STM32_RCC_APB1ENR; |
| mask = RCC_APB1ENR_TIM2EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM3_CAP |
| case STM32_TIM3_BASE: |
| offset = STM32_RCC_APB1ENR; |
| mask = RCC_APB1ENR_TIM3EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM4_CAP |
| case STM32_TIM4_BASE: |
| offset = STM32_RCC_APB1ENR; |
| mask = RCC_APB1ENR_TIM4EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM5_CAP |
| case STM32_TIM5_BASE: |
| offset = STM32_RCC_APB1ENR; |
| mask = RCC_APB1ENR_TIM5EN; |
| break; |
| #endif |
| |
| /* TIM6 and TIM7 cannot be used in capture */ |
| |
| #ifdef CONFIG_STM32F7_TIM8_CAP |
| case STM32_TIM8_BASE: |
| offset = STM32_RCC_APB2ENR; |
| mask = RCC_APB2ENR_TIM8EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM9_CAP |
| case STM32_TIM9_BASE: |
| offset = STM32_RCC_APB2ENR; |
| mask = RCC_APB2ENR_TIM9EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM10_CAP |
| case STM32_TIM10_BASE: |
| offset = STM32_RCC_APB2ENR; |
| mask = RCC_APB2ENR_TIM10EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM11_CAP |
| case STM32_TIM11_BASE: |
| offset = STM32_RCC_APB2ENR; |
| mask = RCC_APB2ENR_TIM11EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM12_CAP |
| case STM32_TIM12_BASE: |
| offset = STM32_RCC_APB1ENR; |
| mask = RCC_APB1ENR_TIM12EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM13_CAP |
| case STM32_TIM13_BASE: |
| offset = STM32_RCC_APB1ENR; |
| mask = RCC_APB1ENR_TIM13EN; |
| break; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM14_CAP |
| case STM32_TIM14_BASE: |
| offset = STM32_RCC_APB1ENR; |
| mask = RCC_APB1ENR_TIM14EN; |
| break; |
| #endif |
| } |
| |
| if (mask == 0) |
| { |
| return ERROR; |
| } |
| |
| 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, |
| stm32_cap_clk_t clk, uint32_t prescaler, |
| uint32_t max) |
| { |
| const struct stm32_cap_priv_s *priv = (const struct stm32_cap_priv_s *)dev; |
| uint16_t regval = 0; |
| |
| if (prescaler == 0) |
| { |
| /* Disable Timer */ |
| |
| stm32_modifyreg16(priv, STM32_BTIM_CR1_OFFSET, ATIM_CR1_CEN, 0); |
| return 0; |
| } |
| |
| /* 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; |
| } |
| |
| switch (clk) |
| { |
| case STM32_CAP_CLK_INT: |
| regval = GTIM_SMCR_DISAB; |
| break; |
| |
| case STM32_CAP_CLK_EXT: |
| regval = GTIM_SMCR_EXTCLK1; |
| break; |
| |
| /* TODO: Add other case */ |
| |
| default: |
| return ERROR; |
| } |
| |
| stm32_modifyreg16(priv, STM32_BTIM_EGR_OFFSET, GTIM_SMCR_SMS_MASK, regval); |
| |
| /* 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_ADVENCED_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; |
| } |
| |
| 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_ADVENCED_TIM |
| int irq_of; |
| #endif |
| |
| DEBUGASSERT(dev != NULL); |
| |
| irq = priv->irq; |
| #ifdef USE_ADVENCED_TIM |
| irq_of = priv->irq_of; |
| #endif |
| |
| /* Disable interrupt when callback is removed */ |
| |
| if (!handler) |
| { |
| up_disable_irq(irq); |
| irq_detach(irq); |
| |
| #ifdef USE_ADVENCED_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_ADVENCED_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 = |
| { |
| .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_STM32F7_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_ADVENCED_TIM |
| .irq_of = STM32_IRQ_TIM1UP, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| /* TIM6 and TIM7 cannot be used in capture */ |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = STM32_IRQ_TIM8UP, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| #ifdef CONFIG_STM32F7_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_ADVENCED_TIM |
| .irq_of = 0, |
| #endif |
| }; |
| #endif |
| |
| static inline const struct stm32_cap_priv_s * stm32_cap_get_priv(int timer) |
| { |
| switch (timer) |
| { |
| #ifdef CONFIG_STM32F7_TIM1_CAP |
| case 1: |
| return &stm32_tim1_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM2_CAP |
| case 2: |
| return &stm32_tim2_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM3_CAP |
| case 3: |
| return &stm32_tim3_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM4_CAP |
| case 4: |
| return &stm32_tim4_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM5_CAP |
| case 5: |
| return &stm32_tim5_priv; |
| #endif |
| |
| /* TIM6 and TIM7 cannot be used in capture */ |
| |
| #ifdef CONFIG_STM32F7_TIM8_CAP |
| case 8: |
| return &stm32_tim8_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM9_CAP |
| case 9: |
| return &stm32_tim9_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM10_CAP |
| case 10: |
| return &stm32_tim10_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM11_CAP |
| case 11: |
| return &stm32_tim11_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM12_CAP |
| case 12: |
| return &stm32_tim12_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM13_CAP |
| case 13: |
| return &stm32_tim13_priv; |
| #endif |
| #ifdef CONFIG_STM32F7_TIM14_CAP |
| case 14: |
| return &stm32_tim14_priv; |
| #endif |
| } |
| |
| return NULL; |
| } |
| |
| /**************************************************************************** |
| * Public Function - Initialization |
| ****************************************************************************/ |
| |
| struct stm32_cap_dev_s *stm32_cap_init(int timer) |
| { |
| 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, STM32_CAP_CHANNEL_COUNTER); |
| 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) |
| { |
| 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, STM32_CAP_CHANNEL_COUNTER); |
| if (gpio) |
| { |
| stm32_unconfiggpio(gpio); |
| } |
| |
| stm32_cap_set_rcc(priv, false); |
| return OK; |
| } |
| |
| #endif /* defined(CONFIG_STM32F7_TIM1 || ... || TIM14) */ |