This is an automated email from the ASF dual-hosted git repository. jerpelea pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 224b710da74487abaed818b0637356bcb7ced7ea Author: raiden00pl <[email protected]> AuthorDate: Wed May 20 10:16:31 2026 +0200 !arch/stm32l4: separate pulse count from PWM driver BREAKING CHANGE: separate pulse count from PWM driver Pulse count handling was removed from PWM driver and moved to a separate driver. For details about this change, look at previous commit. Signed-off-by: raiden00pl <[email protected]> --- arch/arm/src/stm32l4/CMakeLists.txt | 4 + arch/arm/src/stm32l4/Kconfig | 74 +- arch/arm/src/stm32l4/Make.defs | 4 + arch/arm/src/stm32l4/stm32l4_pulsecount.c | 1657 +++++++++++++++++++++++++++++ arch/arm/src/stm32l4/stm32l4_pulsecount.h | 39 + arch/arm/src/stm32l4/stm32l4_pwm.c | 436 +------- 6 files changed, 1778 insertions(+), 436 deletions(-) diff --git a/arch/arm/src/stm32l4/CMakeLists.txt b/arch/arm/src/stm32l4/CMakeLists.txt index ae4098bd0a2..040c98142bc 100644 --- a/arch/arm/src/stm32l4/CMakeLists.txt +++ b/arch/arm/src/stm32l4/CMakeLists.txt @@ -164,6 +164,10 @@ if(CONFIG_STM32L4_PWM) list(APPEND SRCS stm32l4_pwm.c) endif() +if(CONFIG_PULSECOUNT) + list(APPEND SRCS stm32l4_pulsecount.c) +endif() + if(CONFIG_SENSORS_QENCODER) list(APPEND SRCS stm32l4_qencoder.c) endif() diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index 0731829dd6c..b6d2bb1fb80 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -1219,7 +1219,6 @@ config STM32L4_SPI config STM32L4_PWM bool default n - select ARCH_HAVE_PWM_PULSECOUNT config STM32L4_USART bool @@ -3713,6 +3712,79 @@ config STM32L4_PWM_MULTICHAN Specifies that the PWM driver supports multiple output channels per timer. +config STM32L4_PULSECOUNT + bool + default n + select ARCH_HAVE_PULSECOUNT + select PULSECOUNT + +config STM32L4_TIM1_PULSECOUNT + bool "TIM1 pulse count" + default n + depends on STM32L4_TIM1 + select STM32L4_PULSECOUNT + ---help--- + Reserve timer 1 for pulse count output. + +if STM32L4_TIM1_PULSECOUNT + +config STM32L4_TIM1_PULSECOUNT_TDTS + int "TIM1 pulse count clock division" + default 0 + range 0 2 + +config STM32L4_TIM1_PULSECOUNT_CHANNEL + int "TIM1 pulse count channel" + default 1 + range 1 4 + ---help--- + Specifies the timer channel {1,..,4}. + +config STM32L4_TIM1_PULSECOUNT_POL + int "TIM1 pulse count output polarity" + default 0 + range 0 1 + +config STM32L4_TIM1_PULSECOUNT_IDLE + int "TIM1 pulse count idle state" + default 0 + range 0 1 + +endif # STM32L4_TIM1_PULSECOUNT + +config STM32L4_TIM8_PULSECOUNT + bool "TIM8 pulse count" + default n + depends on STM32L4_TIM8 + select STM32L4_PULSECOUNT + ---help--- + Reserve timer 8 for pulse count output. + +if STM32L4_TIM8_PULSECOUNT + +config STM32L4_TIM8_PULSECOUNT_TDTS + int "TIM8 pulse count clock division" + default 0 + range 0 2 + +config STM32L4_TIM8_PULSECOUNT_CHANNEL + int "TIM8 pulse count channel" + default 1 + range 1 4 + ---help--- + Specifies the timer channel {1,..,4}. + +config STM32L4_TIM8_PULSECOUNT_POL + int "TIM8 pulse count output polarity" + default 0 + range 0 1 + +config STM32L4_TIM8_PULSECOUNT_IDLE + int "TIM8 pulse count idle state" + default 0 + range 0 1 + +endif # STM32L4_TIM8_PULSECOUNT config STM32L4_TIM1_ADC bool "TIM1 ADC" default n diff --git a/arch/arm/src/stm32l4/Make.defs b/arch/arm/src/stm32l4/Make.defs index b2a675e6d93..3d981681ff0 100644 --- a/arch/arm/src/stm32l4/Make.defs +++ b/arch/arm/src/stm32l4/Make.defs @@ -157,6 +157,10 @@ ifeq ($(CONFIG_STM32L4_PWM),y) CHIP_CSRCS += stm32l4_pwm.c endif +ifeq ($(CONFIG_STM32L4_PULSECOUNT),y) +CHIP_CSRCS += stm32l4_pulsecount.c +endif + ifeq ($(CONFIG_SENSORS_QENCODER),y) CHIP_CSRCS += stm32l4_qencoder.c endif diff --git a/arch/arm/src/stm32l4/stm32l4_pulsecount.c b/arch/arm/src/stm32l4/stm32l4_pulsecount.c new file mode 100644 index 00000000000..08807a2334e --- /dev/null +++ b/arch/arm/src/stm32l4/stm32l4_pulsecount.c @@ -0,0 +1,1657 @@ +/**************************************************************************** + * arch/arm/src/stm32l4/stm32l4_pulsecount.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 <inttypes.h> +#include <stdint.h> +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <nuttx/debug.h> + +#include <nuttx/arch.h> +#include <arch/board/board.h> + +#include "arm_internal.h" +#include "chip.h" +#include "stm32l4_pulsecount.h" +#include "stm32l4.h" +#include "stm32l4_tim.h" + +/* This module then only compiles if there is at least one enabled timer + * intended for use with the pulsecount upper half driver. + */ + +#if defined(CONFIG_STM32L4_TIM1_PULSECOUNT) || defined(CONFIG_STM32L4_TIM8_PULSECOUNT) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Timer Definitions ********************************************************/ + +/* Pulsecount is supported by advanced timers only. */ + +#define TIMTYPE_ADVANCED 5 +#define TIMTYPE_TIM1 TIMTYPE_ADVANCED +#define TIMTYPE_TIM8 TIMTYPE_ADVANCED + +#define PULSECOUNT_POL_NEG 1 +#define PULSECOUNT_IDLE_ACTIVE 1 + +/* Debug ********************************************************************/ + +#ifdef CONFIG_DEBUG_TIMER_INFO +# define pulsecount_dumpgpio(p,m) stm32l4_dumpgpio(p,m) +#else +# define pulsecount_dumpgpio(p,m) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Pulsecount output configuration */ + +struct stm32l4_out_s +{ + uint8_t in_use:1; + uint8_t pol:1; + uint8_t idle:1; + uint8_t _res:5; + uint32_t pincfg; +}; + +/* Pulsecount channel configuration */ + +struct stm32l4_chan_s +{ + uint8_t channel; + struct stm32l4_out_s out1; +}; + +/* This structure represents the state of one pulsecount timer */ + +struct stm32l4_tim_s +{ + struct stm32l4_chan_s channel; + uint8_t timid:5; + uint8_t timtype:3; + uint8_t t_dts:3; + uint8_t _res:5; + uint8_t irq; + uint8_t prev; + uint8_t curr; + uint32_t count; + uint32_t frequency; + uint32_t base; + uint32_t pclk; + void *handle; +}; + +struct stm32l4_pulsecount_s +{ + const struct pulsecount_ops_s *ops; + struct stm32l4_tim_s *timer; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register access */ + +static uint16_t pulsecount_getreg(struct stm32l4_tim_s *priv, int offset); +static void pulsecount_putreg(struct stm32l4_tim_s *priv, int offset, + uint16_t value); +static void pulsecount_modifyreg(struct stm32l4_tim_s *priv, uint32_t offset, + uint32_t clearbits, uint32_t setbits); + +#ifdef CONFIG_DEBUG_TIMER_INFO +static void pulsecount_dumpregs(struct pulsecount_lowerhalf_s *dev, + const char *msg); +#else +# define pulsecount_dumpregs(priv,msg) +#endif + +/* Timer management */ + +static int pulsecount_ccr_update(struct pulsecount_lowerhalf_s *dev, + uint8_t index, uint32_t ccr); +static int pulsecount_duty_update(struct pulsecount_lowerhalf_s *dev, + uint8_t channel, ub16_t duty); +static int pulsecount_frequency_update(struct pulsecount_lowerhalf_s *dev, + uint32_t frequency); +static int pulsecount_timer_configure(struct stm32l4_tim_s *priv); +static int pulsecount_channel_configure(struct pulsecount_lowerhalf_s *dev, + uint8_t channel); +static int pulsecount_output_configure(struct stm32l4_tim_s *priv, + struct stm32l4_chan_s *chan); +static int pulsecount_outputs_enable(struct pulsecount_lowerhalf_s *dev, + uint16_t outputs, bool state); +static void pulsecount_moe_enable(struct pulsecount_lowerhalf_s *dev, + bool enable); +static int pulsecount_configure(struct pulsecount_lowerhalf_s *dev); +static int pulsecount_timer(struct pulsecount_lowerhalf_s *dev, + const struct pulsecount_info_s *info); +static int pulsecount_interrupt(struct pulsecount_lowerhalf_s *dev); +# ifdef CONFIG_STM32L4_TIM1_PULSECOUNT +static int pulsecount_tim1interrupt(int irq, void *context, void *arg); +# endif +# ifdef CONFIG_STM32L4_TIM8_PULSECOUNT +static int pulsecount_tim8interrupt(int irq, void *context, void *arg); +# endif +static uint8_t pulsecount_count(uint32_t count); + +/* Pulsecount driver methods */ + +static int pulsecount_ll_setup(struct pulsecount_lowerhalf_s *dev); +static int pulsecount_ll_shutdown(struct pulsecount_lowerhalf_s *dev); + +static int pulsecount_ll_stop(struct pulsecount_lowerhalf_s *dev); +static int pulsecount_ll_ioctl(struct pulsecount_lowerhalf_s *dev, + int cmd, unsigned long arg); + +static int pulsecount_setup(struct pulsecount_lowerhalf_s *dev); +static int pulsecount_shutdown(struct pulsecount_lowerhalf_s *dev); +static int pulsecount_start(struct pulsecount_lowerhalf_s *dev, + const struct pulsecount_info_s *info, + void *handle); +static int pulsecount_stop(struct pulsecount_lowerhalf_s *dev); +static int pulsecount_ioctl(struct pulsecount_lowerhalf_s *dev, + int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_STM32L4_TIM1_PULSECOUNT + +static struct stm32l4_tim_s g_pulsecount1dev = +{ + .channel = + { + .channel = CONFIG_STM32L4_TIM1_PULSECOUNT_CHANNEL, +#if CONFIG_STM32L4_TIM1_PULSECOUNT_CHANNEL == 1 + .out1 = + { + .in_use = 1, + .pol = CONFIG_STM32L4_TIM1_PULSECOUNT_POL, + .idle = CONFIG_STM32L4_TIM1_PULSECOUNT_IDLE, + .pincfg = GPIO_TIM1_CH1OUT, + }, +#elif CONFIG_STM32L4_TIM1_PULSECOUNT_CHANNEL == 2 + .out1 = + { + .in_use = 1, + .pol = CONFIG_STM32L4_TIM1_PULSECOUNT_POL, + .idle = CONFIG_STM32L4_TIM1_PULSECOUNT_IDLE, + .pincfg = GPIO_TIM1_CH2OUT, + }, +#elif CONFIG_STM32L4_TIM1_PULSECOUNT_CHANNEL == 3 + .out1 = + { + .in_use = 1, + .pol = CONFIG_STM32L4_TIM1_PULSECOUNT_POL, + .idle = CONFIG_STM32L4_TIM1_PULSECOUNT_IDLE, + .pincfg = GPIO_TIM1_CH3OUT, + }, +#elif CONFIG_STM32L4_TIM1_PULSECOUNT_CHANNEL == 4 + .out1 = + { + .in_use = 1, + .pol = CONFIG_STM32L4_TIM1_PULSECOUNT_POL, + .idle = CONFIG_STM32L4_TIM1_PULSECOUNT_IDLE, + .pincfg = GPIO_TIM1_CH4OUT, + }, +#endif + }, + .timid = 1, + .timtype = TIMTYPE_TIM1, + .t_dts = CONFIG_STM32L4_TIM1_PULSECOUNT_TDTS, + .irq = STM32L4_IRQ_TIM1UP, + .base = STM32L4_TIM1_BASE, + .pclk = STM32L4_APB2_TIM1_CLKIN, +}; + +#endif /* CONFIG_STM32L4_TIM1_PULSECOUNT */ + +#ifdef CONFIG_STM32L4_TIM8_PULSECOUNT + +static struct stm32l4_tim_s g_pulsecount8dev = +{ + .channel = + { + .channel = CONFIG_STM32L4_TIM8_PULSECOUNT_CHANNEL, +#if CONFIG_STM32L4_TIM8_PULSECOUNT_CHANNEL == 1 + .out1 = + { + .in_use = 1, + .pol = CONFIG_STM32L4_TIM8_PULSECOUNT_POL, + .idle = CONFIG_STM32L4_TIM8_PULSECOUNT_IDLE, + .pincfg = GPIO_TIM8_CH1OUT, + }, +#elif CONFIG_STM32L4_TIM8_PULSECOUNT_CHANNEL == 2 + .out1 = + { + .in_use = 1, + .pol = CONFIG_STM32L4_TIM8_PULSECOUNT_POL, + .idle = CONFIG_STM32L4_TIM8_PULSECOUNT_IDLE, + .pincfg = GPIO_TIM8_CH2OUT, + }, +#elif CONFIG_STM32L4_TIM8_PULSECOUNT_CHANNEL == 3 + .out1 = + { + .in_use = 1, + .pol = CONFIG_STM32L4_TIM8_PULSECOUNT_POL, + .idle = CONFIG_STM32L4_TIM8_PULSECOUNT_IDLE, + .pincfg = GPIO_TIM8_CH3OUT, + }, +#elif CONFIG_STM32L4_TIM8_PULSECOUNT_CHANNEL == 4 + .out1 = + { + .in_use = 1, + .pol = CONFIG_STM32L4_TIM8_PULSECOUNT_POL, + .idle = CONFIG_STM32L4_TIM8_PULSECOUNT_IDLE, + .pincfg = GPIO_TIM8_CH4OUT, + }, +#endif + }, + .timid = 8, + .timtype = TIMTYPE_TIM8, + .t_dts = CONFIG_STM32L4_TIM8_PULSECOUNT_TDTS, + .irq = STM32L4_IRQ_TIM8UP, + .base = STM32L4_TIM8_BASE, + .pclk = STM32L4_APB2_TIM8_CLKIN, +}; + +#endif /* CONFIG_STM32L4_TIM8_PULSECOUNT */ + +static const struct pulsecount_ops_s g_pulsecountops = +{ + .setup = pulsecount_setup, + .shutdown = pulsecount_shutdown, + .start = pulsecount_start, + .stop = pulsecount_stop, + .ioctl = pulsecount_ioctl, +}; + +#ifdef CONFIG_STM32L4_TIM1_PULSECOUNT +static struct stm32l4_pulsecount_s g_pulsecount1lower = +{ + .ops = &g_pulsecountops, + .timer = &g_pulsecount1dev, +}; +#endif + +#ifdef CONFIG_STM32L4_TIM8_PULSECOUNT +static struct stm32l4_pulsecount_s g_pulsecount8lower = +{ + .ops = &g_pulsecountops, + .timer = &g_pulsecount8dev, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pulsecount_getreg + * + * Description: + * Read the value of an pulsecount timer register. + * + * Input Parameters: + * priv - A reference to the pulsecount block status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +static uint16_t pulsecount_getreg(struct stm32l4_tim_s *priv, int offset) +{ + return getreg16(priv->base + offset); +} + +/**************************************************************************** + * Name: pulsecount_putreg + * + * Description: + * Read the value of an pulsecount timer register. + * + * Input Parameters: + * priv - A reference to the pulsecount block status + * offset - The offset to the register to read + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void pulsecount_putreg(struct stm32l4_tim_s *priv, int offset, + uint16_t value) +{ + putreg16(value, priv->base + offset); +} + +/**************************************************************************** + * Name: pulsecount_modifyreg + * + * Description: + * Modify timer register (32-bit or 16-bit) + * + * Input Parameters: + * priv - A reference to the pulsecount block status + * offset - The offset to the register to read + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void pulsecount_modifyreg(struct stm32l4_tim_s *priv, uint32_t offset, + uint32_t clearbits, uint32_t setbits) +{ + modifyreg16(priv->base + offset, (uint16_t)clearbits, + (uint16_t)setbits); +} + +/**************************************************************************** + * Name: pulsecount_dumpregs + * + * Description: + * Dump all timer registers. + * + * Input Parameters: + * priv - A reference to the pulsecount block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_TIMER_INFO +static void pulsecount_dumpregs(struct pulsecount_lowerhalf_s *dev, + const char *msg) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + + _info("%s:\n", msg); + _info(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n", + pulsecount_getreg(priv, STM32L4_GTIM_CR1_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_CR2_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_SMCR_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_DIER_OFFSET)); + _info(" SR: %04x EGR: %04x CCMR1: %04x CCMR2: %04x\n", + pulsecount_getreg(priv, STM32L4_GTIM_SR_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_EGR_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_CCMR1_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_CCMR2_OFFSET)); + _info(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n", + pulsecount_getreg(priv, STM32L4_GTIM_CCER_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_CNT_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_PSC_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_ARR_OFFSET)); + _info(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n", + pulsecount_getreg(priv, STM32L4_GTIM_CCR1_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_CCR2_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_CCR3_OFFSET), + pulsecount_getreg(priv, STM32L4_GTIM_CCR4_OFFSET)); + _info(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n", + pulsecount_getreg(priv, STM32L4_ATIM_RCR_OFFSET), + pulsecount_getreg(priv, STM32L4_ATIM_BDTR_OFFSET), + pulsecount_getreg(priv, STM32L4_ATIM_DCR_OFFSET), + pulsecount_getreg(priv, STM32L4_ATIM_DMAR_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: pulsecount_ccr_update + ****************************************************************************/ + +static int pulsecount_ccr_update(struct pulsecount_lowerhalf_s *dev, + uint8_t index, uint32_t ccr) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint32_t offset = 0; + + /* CCR channel indices are one-based to match timer channel numbers. */ + + switch (index) + { + case 1: + { + offset = STM32L4_GTIM_CCR1_OFFSET; + break; + } + + case 2: + { + offset = STM32L4_GTIM_CCR2_OFFSET; + break; + } + + case 3: + { + offset = STM32L4_GTIM_CCR3_OFFSET; + break; + } + + case 4: + { + offset = STM32L4_GTIM_CCR4_OFFSET; + break; + } + + default: + { + _err("ERROR: No such CCR: %u\n", index); + return -EINVAL; + } + } + + /* Update CCR register */ + + pulsecount_putreg(priv, offset, ccr); + + return OK; +} + +/**************************************************************************** + * Name: pulsecount_duty_update + * + * Description: + * Try to change only channel duty + * + * Input Parameters: + * dev - A reference to the lower half driver state structure + * channel - Channel to by updated + * duty - New duty + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pulsecount_duty_update(struct pulsecount_lowerhalf_s *dev, + uint8_t channel, ub16_t duty) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint32_t reload = 0; + uint32_t ccr = 0; + + /* We don't want compilation warnings if no DEBUGASSERT */ + + UNUSED(priv); + + DEBUGASSERT(priv != NULL); + + _info("TIM%u channel: %u duty: %08" PRIx32 "\n", + priv->timid, channel, duty); + + /* Get the reload values */ + + reload = pulsecount_getreg(priv, STM32L4_GTIM_ARR_OFFSET); + + /* Duty cycle: + * + * duty cycle = ccr / reload (fractional value) + */ + + ccr = b16toi(duty * reload + b16HALF); + + _info("ccr: %" PRIu32 "\n", ccr); + + /* Write corresponding CCR register */ + + return pulsecount_ccr_update(dev, channel, ccr); +} + +/**************************************************************************** + * Name: pulsecount_frequency_update + * + * Description: + * Update a pulsecount timer frequency + * + ****************************************************************************/ + +static int pulsecount_frequency_update(struct pulsecount_lowerhalf_s *dev, + uint32_t frequency) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint32_t reload = 0; + uint32_t timclk = 0; + uint32_t prescaler = 0; + + /* Calculate optimal values for the timer prescaler and for the timer + * reload register. If 'frequency' is the desired frequency, then + * + * reload = timclk / frequency + * timclk = pclk / presc + * + * Or, + * + * reload = pclk / presc / frequency + * + * There are many solutions to this, but the best solution will be the one + * that has the largest reload value and the smallest prescaler value. + * That is the solution that should give us the most accuracy in the timer + * control. Subject to: + * + * 0 <= presc <= 65536 + * 1 <= reload <= 65535 + * + * So presc = pclk / 65535 / frequency would be optimal. + * + * Example: + * + * pclk = 42 MHz + * frequency = 100 Hz + * + * prescaler = 42,000,000 / 65,535 / 100 + * = 6.4 (or 7 -- taking the ceiling always) + * timclk = 42,000,000 / 7 + * = 6,000,000 + * reload = 6,000,000 / 100 + * = 60,000 + */ + + prescaler = (priv->pclk / frequency + 65534) / 65535; + if (prescaler < 1) + { + prescaler = 1; + } + else if (prescaler > 65536) + { + prescaler = 65536; + } + + timclk = priv->pclk / prescaler; + + reload = timclk / frequency; + if (reload < 2) + { + reload = 1; + } + else if (reload > 65535) + { + reload = 65535; + } + else + { + reload--; + } + + _info("TIM%u PCLK: %" PRIu32 " frequency: %" PRIu32 " TIMCLK: %" PRIu32 + " prescaler: %" PRIu32 " reload: %" PRIu32 "\n", + priv->timid, priv->pclk, frequency, timclk, prescaler, reload); + + /* Set the reload and prescaler values */ + + pulsecount_putreg(priv, STM32L4_GTIM_ARR_OFFSET, reload); + pulsecount_putreg(priv, STM32L4_GTIM_PSC_OFFSET, + (uint16_t)(prescaler - 1)); + + return OK; +} + +/**************************************************************************** + * Name: pulsecount_timer_configure + * + * Description: + * Initial configuration for pulsecount timer + * + ****************************************************************************/ + +static int pulsecount_timer_configure(struct stm32l4_tim_s *priv) +{ + uint16_t cr1 = 0; + + /* Set up the advanced timer CR1 register. */ + + cr1 = pulsecount_getreg(priv, STM32L4_GTIM_CR1_OFFSET); + + /* Pulsecount always uses edge-aligned up-counting mode. */ + + cr1 &= ~(GTIM_CR1_DIR | GTIM_CR1_CMS_MASK); + cr1 |= GTIM_CR1_EDGE; + cr1 &= ~GTIM_CR1_CKD_MASK; + cr1 |= priv->t_dts << GTIM_CR1_CKD_SHIFT; + + /* Enable ARR preload to preserve the previous pulsecount behavior. */ + + cr1 |= GTIM_CR1_ARPE; + + /* Write CR1 */ + + pulsecount_putreg(priv, STM32L4_GTIM_CR1_OFFSET, cr1); + + return OK; +} + +/**************************************************************************** + * Name: pulsecount_channel_configure + * + * Description: + * Configure pulsecount output compare for a channel + * + ****************************************************************************/ + +static int pulsecount_channel_configure(struct pulsecount_lowerhalf_s *dev, + uint8_t channel) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint32_t chanmode = 0; + uint32_t ocmode = 0; + uint32_t ccmr = 0; + uint32_t offset = 0; + int ret = OK; + + /* Configure output compare mode */ + + chanmode = GTIM_CCMR_MODE_PWM1; + + /* output compare configuration */ + + switch (channel) + { + /* Get CCMR offset */ + + case 1: + case 2: + { + offset = STM32L4_GTIM_CCMR1_OFFSET; + break; + } + + case 3: + case 4: + { + offset = STM32L4_GTIM_CCMR2_OFFSET; + break; + } + + default: + { + _err("ERROR: No such channel: %u\n", channel); + ret = -EINVAL; + goto errout; + } + } + + /* Get current registers */ + + ccmr = pulsecount_getreg(priv, offset); + + /* output compare configuration. + * NOTE: The CCMRx registers are identical if the channels are outputs. + */ + + switch (channel) + { + /* Configure channel 1/3 */ + + case 1: + case 3: + { + ccmr &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | + ATIM_CCMR1_OC1PE | ATIM_CCMR1_OC1M); + ocmode |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT); + ocmode |= (chanmode << ATIM_CCMR1_OC1M_SHIFT); + ocmode |= ATIM_CCMR1_OC1PE; + break; + } + + /* Configure channel 2/4 */ + + case 2: + case 4: + { + ccmr &= ~(ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | + ATIM_CCMR1_OC2PE | ATIM_CCMR1_OC2M); + ocmode |= (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT); + ocmode |= (chanmode << ATIM_CCMR1_OC2M_SHIFT); + ocmode |= ATIM_CCMR1_OC2PE; + break; + } + } + + /* Set the selected output compare configuration */ + + ccmr |= ocmode; + + /* Write CCMRx registers */ + + pulsecount_putreg(priv, offset, ccmr); + +errout: + return ret; +} + +/**************************************************************************** + * Name: pulsecount_output_configure + * + * Description: + * Configure pulsecount output for given channel + * + ****************************************************************************/ + +static int pulsecount_output_configure(struct stm32l4_tim_s *priv, + uint8_t channel) +{ + uint32_t cr2 = 0; + uint32_t ccer = 0; + + /* Get current registers state */ + + cr2 = pulsecount_getreg(priv, STM32L4_GTIM_CR2_OFFSET); + ccer = pulsecount_getreg(priv, STM32L4_GTIM_CCER_OFFSET); + + /* | OISx | IDLE | advanced timers | CR2 register + * | CCxP | POL | all pulsecount timers | CCER register + */ + + /* Configure output polarity (all pulsecount timers) */ + + if (priv->channel.out1.pol == PULSECOUNT_POL_NEG) + { + ccer |= (GTIM_CCER_CC1P << ((channel - 1) * 4)); + } + else + { + ccer &= ~(GTIM_CCER_CC1P << ((channel - 1) * 4)); + } + + if (priv->timtype == TIMTYPE_ADVANCED) + { + /* Configure output IDLE State */ + + if (priv->channel.out1.idle == PULSECOUNT_IDLE_ACTIVE) + { + cr2 |= (ATIM_CR2_OIS1 << ((channel - 1) * 2)); + } + else + { + cr2 &= ~(ATIM_CR2_OIS1 << ((channel - 1) * 2)); + } + } + + /* Write registers */ + + pulsecount_modifyreg(priv, STM32L4_GTIM_CR2_OFFSET, 0, cr2); + pulsecount_modifyreg(priv, STM32L4_GTIM_CCER_OFFSET, 0, ccer); + + return OK; +} + +/**************************************************************************** + * Name: pulsecount_outputs_enable + * + * Description: + * Enable/disable given timer pulsecount outputs. + * + * NOTE: This is bulk operation - we can enable/disable many outputs + * at one time + * + * Input Parameters: + * dev - A reference to the lower half driver state structure + * outputs - outputs to set (look at enum stm32l4_pulsecount_chan_e) + * state - Enable/disable operation + * + ****************************************************************************/ + +static int pulsecount_outputs_enable(struct pulsecount_lowerhalf_s *dev, + uint16_t outputs, bool state) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint32_t ccer = 0; + uint32_t regval = 0; + + /* Get current register state */ + + ccer = pulsecount_getreg(priv, STM32L4_GTIM_CCER_OFFSET); + + /* Get outputs configuration */ + + regval |= ((outputs & (1 << 0)) ? GTIM_CCER_CC1E : 0); + regval |= ((outputs & (1 << 2)) ? GTIM_CCER_CC2E : 0); + regval |= ((outputs & (1 << 4)) ? GTIM_CCER_CC3E : 0); + regval |= ((outputs & (1 << 6)) ? GTIM_CCER_CC4E : 0); + + /* NOTE: CC4N does not exist, but some docs show configuration bits for it + */ + + if (state == true) + { + /* Enable outputs - set bits */ + + ccer |= regval; + } + else + { + /* Disable outputs - reset bits */ + + ccer &= ~regval; + } + + /* Write register */ + + pulsecount_putreg(priv, STM32L4_GTIM_CCER_OFFSET, ccer); + + return OK; +} + +/**************************************************************************** + * Name: pulsecount_moe_enable + ****************************************************************************/ + +static void pulsecount_moe_enable(struct pulsecount_lowerhalf_s *dev, + bool enable) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + + if (enable) + { + pulsecount_modifyreg(priv, STM32L4_ATIM_BDTR_OFFSET, 0, ATIM_BDTR_MOE); + } + else + { + pulsecount_modifyreg(priv, STM32L4_ATIM_BDTR_OFFSET, ATIM_BDTR_MOE, 0); + } +} + +/**************************************************************************** + * Name: pulsecount_outputs_from_channels + * + * Description: + * Get enabled outputs configuration from the pulsecount timer state + * + ****************************************************************************/ + +static uint16_t +pulsecount_outputs_from_channels(struct stm32l4_tim_s *priv, + uint8_t selected) +{ + uint16_t outputs = 0; + uint8_t channel; + + channel = priv->channel.channel; + + if (channel != 0 && (selected == 0 || channel == selected) && + priv->channel.out1.in_use == 1) + { + outputs = (1 << ((channel - 1) * 2)); + } + + return outputs; +} + +/**************************************************************************** + * Name: pulsecount_configure + * + * Description: + * Configure pulsecount timer for pulse output + * + ****************************************************************************/ + +static int pulsecount_configure(struct pulsecount_lowerhalf_s *dev) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint16_t outputs = 0; + int ret = OK; + + /* NOTE: leave timer counter disabled and all outputs disabled! */ + + /* Disable the timer until we get it configured */ + + pulsecount_modifyreg(priv, STM32L4_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0); + + /* Get configured outputs */ + + outputs = pulsecount_outputs_from_channels(priv, 0); + + /* Disable configured outputs before the timer is reconfigured. */ + + ret = pulsecount_outputs_enable(dev, outputs, false); + if (ret < 0) + { + goto errout; + } + + /* Initial timer configuration */ + + ret = pulsecount_timer_configure(priv); + if (ret < 0) + { + goto errout; + } + + /* Disable software break (enable outputs) */ + + pulsecount_moe_enable(dev, true); + + /* Configure timer channel */ + + if (priv->channel.channel != 0) + { + pulsecount_channel_configure(dev, priv->channel.channel); + pulsecount_output_configure(priv, priv->channel.channel); + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: pulsecount_timer + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input Parameters: + * dev - A reference to the lower half pulsecount driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * This split keeps pulsecount as the existing single-channel mode. + * + ****************************************************************************/ + +static int pulsecount_timer(struct pulsecount_lowerhalf_s *dev, + const struct pulsecount_info_s *info) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + ub16_t duty = 0; + uint8_t channel = 0; + uint16_t outputs = 0; + int ret = OK; + + /* If we got here then the timer instance supports pulsecount output. */ + + DEBUGASSERT(priv != NULL && info != NULL); + + _info("TIM%u channel: %u high: %" PRIu32 " ns low: %" PRIu32 + " ns count: %" PRIu32 "\n", + priv->timid, priv->channel.channel, info->high_ns, + info->low_ns, info->count); + + DEBUGASSERT(pulsecount_frequency(info) > 0); + + /* Channel specific setup */ + + duty = pulsecount_duty(info); + channel = priv->channel.channel; + + /* Disable all interrupts and DMA requests, clear all pending status */ + + pulsecount_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0); + pulsecount_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0); + + /* Set timer frequency */ + + ret = pulsecount_frequency_update(dev, pulsecount_frequency(info)); + if (ret < 0) + { + goto errout; + } + + /* Update duty cycle */ + + ret = pulsecount_duty_update(dev, channel, duty); + if (ret < 0) + { + goto errout; + } + + /* If a non-zero repetition count has been selected, then set the + * repetition counter to the count-1 (pulsecount_start() has already + * assured us that the count value is within range). + */ + + if (info->count > 0) + { + /* Save the remaining count and the number of counts that will have + * elapsed on the first interrupt. + */ + + /* If the first interrupt occurs at the end end of the first + * repetition count, then the count will be the same as the RCR + * value. + */ + + priv->prev = pulsecount_count(info->count); + pulsecount_putreg(priv, STM32L4_GTIM_RCR_OFFSET, + (uint16_t)priv->prev - 1); + + /* Generate an update event to reload the prescaler. This should + * preload the RCR into active repetition counter. + */ + + pulsecount_putreg(priv, STM32L4_GTIM_EGR_OFFSET, GTIM_EGR_UG); + + /* Now set the value of the RCR that will be loaded on the next + * update event. + */ + + priv->count = info->count; + priv->curr = pulsecount_count(info->count - priv->prev); + pulsecount_putreg(priv, STM32L4_GTIM_RCR_OFFSET, + (uint16_t)priv->curr - 1); + } + + /* Otherwise, just clear the repetition counter */ + + else + { + /* Set the repetition counter to zero */ + + pulsecount_putreg(priv, STM32L4_GTIM_RCR_OFFSET, 0); + + /* Generate an update event to reload the prescaler */ + + pulsecount_putreg(priv, STM32L4_GTIM_EGR_OFFSET, GTIM_EGR_UG); + } + + /* Get configured outputs */ + + outputs = pulsecount_outputs_from_channels(priv, channel); + + /* Enable output */ + + ret = pulsecount_outputs_enable(dev, outputs, true); + if (ret < 0) + { + goto errout; + } + + /* Setup update interrupt. If info->count is > 0, then we can + * be assured that pulsecount_start() has already verified: (1) that + * this is an advanced timer, and that (2) the repetition count is within + * range. + */ + + if (info->count > 0) + { + /* Clear all pending interrupts and enable the update interrupt. */ + + pulsecount_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0); + pulsecount_putreg(priv, STM32L4_GTIM_DIER_OFFSET, GTIM_DIER_UIE); + + /* Enable the timer */ + + pulsecount_modifyreg(priv, STM32L4_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN); + + /* And enable timer interrupts at the NVIC */ + + up_enable_irq(priv->irq); + } + + pulsecount_dumpregs(dev, "After starting"); + +errout: + return ret; +} + +/**************************************************************************** + * Name: pulsecount_interrupt + * + * Description: + * Handle timer interrupts. + * + * Input Parameters: + * dev - A reference to the lower half pulsecount driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pulsecount_interrupt(struct pulsecount_lowerhalf_s *dev) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint16_t regval; + + /* Verify that this is an update interrupt. Nothing else is expected. */ + + regval = pulsecount_getreg(priv, STM32L4_ATIM_SR_OFFSET); + DEBUGASSERT((regval & ATIM_SR_UIF) != 0); + + /* Clear the UIF interrupt bit */ + + pulsecount_putreg(priv, STM32L4_ATIM_SR_OFFSET, regval & ~ATIM_SR_UIF); + + /* Calculate the new count by subtracting the number of pulses + * since the last interrupt. + */ + + if (priv->count <= priv->prev) + { + /* We are finished. Turn off the mast output to stop the output as + * quickly as possible. + */ + + regval = pulsecount_getreg(priv, STM32L4_ATIM_BDTR_OFFSET); + regval &= ~ATIM_BDTR_MOE; + pulsecount_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, regval); + + /* Disable first interrupts, stop and reset the timer */ + + pulsecount_ll_stop(dev); + + /* Then perform the callback into the upper half driver */ + + pulsecount_expired(priv->handle); + + priv->handle = NULL; + priv->count = 0; + priv->prev = 0; + priv->curr = 0; + } + else + { + /* Decrement the count of pulses remaining using the number of + * pulses generated since the last interrupt. + */ + + priv->count -= priv->prev; + + /* Set up the next RCR. Set 'prev' to the value of the RCR that + * was loaded when the update occurred (just before this interrupt) + * and set 'curr' to the current value of the RCR register (which + * will bet loaded on the next update event). + */ + + priv->prev = priv->curr; + priv->curr = pulsecount_count(priv->count - priv->prev); + pulsecount_putreg(priv, STM32L4_ATIM_RCR_OFFSET, + (uint16_t)priv->curr - 1); + } + + /* Now all of the time critical stuff is done so we can do some debug + * output + */ + + _info("Update interrupt SR: %04" PRIx16 " prev: %u curr: %u" + " count: %" PRIu32 "\n", + regval, (unsigned int)priv->prev, (unsigned int)priv->curr, + priv->count); + + return OK; +} + +/**************************************************************************** + * Name: pulsecount_tim1/8interrupt + * + * Description: + * Handle timer 1 and 8 interrupts. + * + * Input Parameters: + * Standard NuttX interrupt inputs + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +#ifdef CONFIG_STM32L4_TIM1_PULSECOUNT +static int pulsecount_tim1interrupt(int irq, void *context, void *arg) +{ + return pulsecount_interrupt((struct pulsecount_lowerhalf_s *) + &g_pulsecount1dev); +} +#endif /* CONFIG_STM32L4_TIM1_PULSECOUNT */ + +#ifdef CONFIG_STM32L4_TIM8_PULSECOUNT +static int pulsecount_tim8interrupt(int irq, void *context, void *arg) +{ + return pulsecount_interrupt((struct pulsecount_lowerhalf_s *) + &g_pulsecount8dev); +} +#endif /* CONFIG_STM32L4_TIM8_PULSECOUNT */ + +/**************************************************************************** + * Name: pulsecount_count + * + * Description: + * Pick an optimal pulse count to program the RCR. + * + * Input Parameters: + * count - The total count remaining + * + * Returned Value: + * The recommended pulse count + * + ****************************************************************************/ + +static uint8_t pulsecount_count(uint32_t count) +{ + /* The the remaining pulse count is less than or equal to the maximum, the + * just return the count. + */ + + if (count <= ATIM_RCR_REP_MAX) + { + return (uint8_t)count; + } + + /* Otherwise, we have to be careful. We do not want a small number of + * counts at the end because we might have trouble responding fast enough. + * If the remaining count is less than 150% of the maximum, then return + * half of the maximum. In this case the final sequence will be between 64 + * and 128. + */ + + else if (count < (3 * ATIM_RCR_REP_MAX / 2)) + { + return (uint8_t)((ATIM_RCR_REP_MAX + 1) >> 1); + } + + /* Otherwise, return the maximum. The final count will be 64 or more */ + + else + { + return (uint8_t)ATIM_RCR_REP_MAX; + } +} + +/**************************************************************************** + * Name: pulsecount_setapbclock + * + * Description: + * Enable or disable APB clock for the timer peripheral + * + * Input Parameters: + * dev - A reference to the lower half pulsecount driver state structure + * on - Enable clock if 'on' is 'true' and disable if 'false' + * + ****************************************************************************/ + +static int pulsecount_setapbclock(struct stm32l4_tim_s *priv, + bool on) +{ + uint32_t en_bit; + uint32_t regaddr; + int ret = OK; + + /* Determine which timer to configure */ + + switch (priv->timid) + { +#ifdef CONFIG_STM32L4_TIM1_PULSECOUNT + case 1: + { + regaddr = STM32L4_RCC_APB2ENR; + en_bit = RCC_APB2ENR_TIM1EN; + break; + } +#endif + +#ifdef CONFIG_STM32L4_TIM8_PULSECOUNT + case 8: + { + regaddr = STM32L4_RCC_APB2ENR; + en_bit = RCC_APB2ENR_TIM8EN; + break; + } +#endif + + default: + { + _err("ERROR: No such timer configured %d\n", priv->timid); + ret = -EINVAL; + goto errout; + } + } + + /* Enable/disable APB 1/2 clock for timer */ + + if (on) + { + modifyreg32(regaddr, 0, en_bit); + } + else + { + modifyreg32(regaddr, en_bit, 0); + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: pulsecount_ll_setup + * + * Description: + * This method is called when the driver is opened. The lower half driver + * should configure and initialize the device so that it is ready for use. + * It should not, however, output pulses until the start method is called. + * + * Input Parameters: + * dev - A reference to the lower half pulsecount driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * APB1 or 2 clocking for the GPIOs has already been configured by the RCC + * logic at power up. + * + ****************************************************************************/ + +static int pulsecount_ll_setup(struct pulsecount_lowerhalf_s *dev) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint32_t pincfg; + + _info("TIM%u\n", priv->timid); + + /* Enable APB1/2 clocking for timer. */ + + pulsecount_setapbclock(priv, true); + + pulsecount_dumpregs(dev, "Initially"); + + /* Configure the pulsecount output pins, but do not start the timer yet */ + + if (priv->channel.out1.in_use == 1) + { + pincfg = priv->channel.out1.pincfg; + _info("pincfg: %08" PRIx32 "\n", pincfg); + + stm32l4_configgpio(pincfg); + pulsecount_dumpgpio(pincfg, "pulsecount setup"); + } + + return OK; +} + +/**************************************************************************** + * Name: pulsecount_ll_shutdown + * + * Description: + * This method is called when the driver is closed. The lower half driver + * stop pulsed output, free any resources, disable the timer hardware, and + * put the system into the lowest possible power usage state + * + * Input Parameters: + * dev - A reference to the lower half pulsecount driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pulsecount_ll_shutdown(struct pulsecount_lowerhalf_s *dev) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint32_t pincfg = 0; + int ret = OK; + + _info("TIM%u\n", priv->timid); + + /* Make sure that the output has been stopped */ + + pulsecount_ll_stop(dev); + + /* Disable APB1/2 clocking for timer. */ + + ret = pulsecount_setapbclock(priv, false); + if (ret < 0) + { + goto errout; + } + + /* Then put the GPIO pins back to the default state */ + + pincfg = priv->channel.out1.pincfg; + if (pincfg != 0) + { + _info("pincfg: %08" PRIx32 "\n", pincfg); + + pincfg &= (GPIO_PORT_MASK | GPIO_PIN_MASK); + pincfg |= GPIO_INPUT | GPIO_FLOAT; + + stm32l4_configgpio(pincfg); + } + +errout: + return ret; +} + +/**************************************************************************** + * Name: pulsecount_ll_stop + * + * Description: + * Stop the pulsed output and reset the timer resources + * + * Input Parameters: + * dev - A reference to the lower half pulsecount driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * This function is called to stop the pulsed output at anytime. This + * method is also called from the timer interrupt handler when a repetition + * count expires... automatically stopping the timer. + * + ****************************************************************************/ + +static int pulsecount_ll_stop(struct pulsecount_lowerhalf_s *dev) +{ + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + uint32_t resetbit = 0; + uint32_t regaddr; + uint32_t regval; + irqstate_t flags; + + _info("TIM%u\n", priv->timid); + + /* Determine which timer to reset */ + + switch (priv->timid) + { +#ifdef CONFIG_STM32L4_TIM1_PULSECOUNT + case 1: + regaddr = STM32L4_RCC_APB2RSTR; + resetbit = RCC_APB2RSTR_TIM1RST; + break; +#endif +#ifdef CONFIG_STM32L4_TIM8_PULSECOUNT + case 8: + regaddr = STM32L4_RCC_APB2RSTR; + resetbit = RCC_APB2RSTR_TIM8RST; + break; +#endif + default: + return -EINVAL; + } + + /* Disable interrupts momentary to stop any ongoing timer processing and + * to prevent any concurrent access to the reset register. + */ + + flags = enter_critical_section(); + + /* Disable further interrupts and stop the timer */ + + pulsecount_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0); + pulsecount_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0); + + /* Reset the timer - stopping the output and putting the timer back + * into a state where pulsecount_start() can be called. + */ + + regval = getreg32(regaddr); + regval |= resetbit; + putreg32(regval, regaddr); + + regval &= ~resetbit; + putreg32(regval, regaddr); + leave_critical_section(flags); + + _info("regaddr: %08" PRIx32 " resetbit: %08" PRIx32 "\n", + regaddr, resetbit); + pulsecount_dumpregs(dev, "After stop"); + return OK; +} + +/**************************************************************************** + * Name: pulsecount_ll_ioctl + * + * Description: + * Lower-half logic may support platform-specific ioctl commands + * + * Input Parameters: + * dev - A reference to the lower half pulsecount driver state structure + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pulsecount_ll_ioctl(struct pulsecount_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ +#ifdef CONFIG_DEBUG_TIMER_INFO + struct stm32l4_tim_s *priv = (struct stm32l4_tim_s *)dev; + + /* There are no platform-specific ioctl commands */ + + _info("TIM%u\n", priv->timid); +#endif + return -ENOTTY; +} + +static int pulsecount_setup(struct pulsecount_lowerhalf_s *dev) +{ + struct stm32l4_pulsecount_s *pulse = (struct stm32l4_pulsecount_s *)dev; + int ret; + + ret = pulsecount_ll_setup((struct pulsecount_lowerhalf_s *)pulse->timer); + if (ret < 0) + { + return ret; + } + + return pulsecount_configure((struct pulsecount_lowerhalf_s *)pulse->timer); +} + +static int pulsecount_shutdown(struct pulsecount_lowerhalf_s *dev) +{ + struct stm32l4_pulsecount_s *pulse = (struct stm32l4_pulsecount_s *)dev; + return pulsecount_ll_shutdown((struct pulsecount_lowerhalf_s *) + pulse->timer); +} + +static int pulsecount_start(struct pulsecount_lowerhalf_s *dev, + const struct pulsecount_info_s *info, + void *handle) +{ + struct stm32l4_pulsecount_s *pulse = (struct stm32l4_pulsecount_s *)dev; + struct stm32l4_tim_s *priv = pulse->timer; + + if (info->count > 0) + { + if (priv->timtype != TIMTYPE_ADVANCED) + { + _err("ERROR: TIM%u cannot support pulse count: %" PRIu32 "\n", + priv->timid, info->count); + return -EPERM; + } + } + + priv->handle = handle; + return pulsecount_timer((struct pulsecount_lowerhalf_s *)priv, info); +} + +static int pulsecount_stop(struct pulsecount_lowerhalf_s *dev) +{ + struct stm32l4_pulsecount_s *pulse = (struct stm32l4_pulsecount_s *)dev; + return pulsecount_ll_stop((struct pulsecount_lowerhalf_s *)pulse->timer); +} + +static int pulsecount_ioctl(struct pulsecount_lowerhalf_s *dev, + int cmd, unsigned long arg) +{ + struct stm32l4_pulsecount_s *pulse = (struct stm32l4_pulsecount_s *)dev; + return pulsecount_ll_ioctl((struct pulsecount_lowerhalf_s *)pulse->timer, + cmd, arg); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +struct pulsecount_lowerhalf_s *stm32l4_pulsecountinitialize(int timer) +{ + struct stm32l4_pulsecount_s *lower = NULL; + + _info("TIM%u\n", timer); + + switch (timer) + { +#ifdef CONFIG_STM32L4_TIM1_PULSECOUNT + case 1: + { + lower = &g_pulsecount1lower; + irq_attach(lower->timer->irq, pulsecount_tim1interrupt, NULL); + up_disable_irq(lower->timer->irq); + break; + } +#endif + +#ifdef CONFIG_STM32L4_TIM8_PULSECOUNT + case 8: + { + lower = &g_pulsecount8lower; + irq_attach(lower->timer->irq, pulsecount_tim8interrupt, NULL); + up_disable_irq(lower->timer->irq); + break; + } +#endif + + default: + { + _err("ERROR: TIM%d does not support pulse count\n", timer); + return NULL; + } + } + + return (struct pulsecount_lowerhalf_s *)lower; +} + +#endif /* CONFIG_STM32L4_TIM1_PULSECOUNT || CONFIG_STM32L4_TIM8_PULSECOUNT */ diff --git a/arch/arm/src/stm32l4/stm32l4_pulsecount.h b/arch/arm/src/stm32l4/stm32l4_pulsecount.h new file mode 100644 index 00000000000..8d1a95c595b --- /dev/null +++ b/arch/arm/src/stm32l4/stm32l4_pulsecount.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * arch/arm/src/stm32l4/stm32l4_pulsecount.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_STM32L4_STM32L4_PULSECOUNT_H +#define __ARCH_ARM_SRC_STM32L4_STM32L4_PULSECOUNT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/timers/pulsecount.h> + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct pulsecount_lowerhalf_s *stm32l4_pulsecountinitialize(int timer); + +#endif /* __ARCH_ARM_SRC_STM32L4_STM32L4_PULSECOUNT_H */ diff --git a/arch/arm/src/stm32l4/stm32l4_pwm.c b/arch/arm/src/stm32l4/stm32l4_pwm.c index 37a4ec2b6a5..46d0aff8193 100644 --- a/arch/arm/src/stm32l4/stm32l4_pwm.c +++ b/arch/arm/src/stm32l4/stm32l4_pwm.c @@ -107,17 +107,6 @@ # undef HAVE_LPTIM #endif -/* Pulsecount support */ - -#ifdef CONFIG_PWM_PULSECOUNT -# ifndef HAVE_ADVTIM -# error "PWM_PULSECOUNT requires HAVE_ADVTIM" -# endif -# if defined(CONFIG_STM32L4_TIM1_PWM) || defined(CONFIG_STM32L4_TIM8_PWM) -# define HAVE_PWM_INTERRUPT -# endif -#endif - /* Synchronisation support */ #ifdef CONFIG_STM32L4_PWM_TRGO @@ -196,20 +185,10 @@ struct stm32l4_pwmtimer_s * 4 LSB = TRGO, 4 MSB = TRGO2 */ #endif -#ifdef CONFIG_PWM_PULSECOUNT - uint8_t irq; /* Timer update IRQ */ - uint8_t prev; /* The previous value of the RCR (pre-loaded) */ - uint8_t curr; /* The current value of the RCR (pre-loaded) */ - uint32_t count; /* Remaining pulse count */ -#else uint32_t frequency; /* Current frequency setting */ -#endif uint32_t base; /* The base address of the timer */ uint32_t pclk; /* Frequency of the peripheral clock * that drives the timer module. */ -#ifdef CONFIG_PWM_PULSECOUNT - void *handle; /* Handle used for upper-half callback */ -#endif }; /**************************************************************************** @@ -233,17 +212,12 @@ static void pwm_dumpregs(struct pwm_lowerhalf_s *dev, /* Timer management */ -#ifdef CONFIG_PWM_PULSECOUNT -static int pwm_pulsecount_timer(struct pwm_lowerhalf_s *dev, - const struct pwm_info_s *info); -#else static int pwm_timer(struct pwm_lowerhalf_s *dev, const struct pwm_info_s *info); # ifdef HAVE_LPTIM static int pwm_lptimer(struct pwm_lowerhalf_s *dev, const struct pwm_info_s *info); # endif -#endif static int pwm_configure(struct pwm_lowerhalf_s *dev); @@ -270,30 +244,13 @@ static int pwm_deadtime_update(struct pwm_lowerhalf_s *dev, uint8_t dt); static uint32_t pwm_ccr_get(struct pwm_lowerhalf_s *dev, uint8_t index); #endif -#ifdef HAVE_PWM_INTERRUPT -static int pwm_interrupt(struct pwm_lowerhalf_s *dev); -# ifdef CONFIG_STM32L4_TIM1_PWM -static int pwm_tim1interrupt(int irq, void *context, void *arg); -# endif -# ifdef CONFIG_STM32L4_TIM8_PWM -static int pwm_tim8interrupt(int irq, void *context, void *arg); -# endif -static uint8_t pwm_pulsecount(uint32_t count); -#endif - /* PWM driver methods */ static int pwm_setup(struct pwm_lowerhalf_s *dev); static int pwm_shutdown(struct pwm_lowerhalf_s *dev); -#ifdef CONFIG_PWM_PULSECOUNT -static int pwm_start(struct pwm_lowerhalf_s *dev, - const struct pwm_info_s *info, - void *handle); -#else static int pwm_start(struct pwm_lowerhalf_s *dev, const struct pwm_info_s *info); -#endif static int pwm_stop(struct pwm_lowerhalf_s *dev); static int pwm_ioctl(struct pwm_lowerhalf_s *dev, @@ -496,9 +453,6 @@ static struct stm32l4_pwmtimer_s g_pwm1dev = #endif #if defined(HAVE_TRGO) && defined(STM32L4_TIM1_TRGO) .trgo = STM32L4_TIM1_TRGO, -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM1UP, #endif .base = STM32L4_TIM1_BASE, .pclk = STM32L4_APB2_TIM1_CLKIN, @@ -595,9 +549,6 @@ static struct stm32l4_pwmtimer_s g_pwm2dev = #endif #if defined(HAVE_TRGO) && defined(STM32L4_TIM2_TRGO) .trgo = STM32L4_TIM2_TRGO, -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM2, #endif .base = STM32L4_TIM2_BASE, .pclk = STM32L4_APB1_TIM2_CLKIN, @@ -695,9 +646,6 @@ static struct stm32l4_pwmtimer_s g_pwm3dev = #endif #if defined(HAVE_TRGO) && defined(STM32L4_TIM3_TRGO) .trgo = STM32L4_TIM3_TRGO, -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM3, #endif .base = STM32L4_TIM3_BASE, .pclk = STM32L4_APB1_TIM3_CLKIN, @@ -794,9 +742,6 @@ static struct stm32l4_pwmtimer_s g_pwm4dev = #endif #if defined(HAVE_TRGO) && defined(STM32L4_TIM4_TRGO) .trgo = STM32L4_TIM4_TRGO, -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM4, #endif .base = STM32L4_TIM4_BASE, .pclk = STM32L4_APB1_TIM4_CLKIN, @@ -891,9 +836,6 @@ static struct stm32l4_pwmtimer_s g_pwm5dev = #endif #if defined(HAVE_TRGO) && defined(STM32L4_TIM5_TRGO) .trgo = STM32L4_TIM5_TRGO -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM5, #endif .base = STM32L4_TIM5_BASE, .pclk = STM32L4_APB1_TIM5_CLKIN, @@ -1057,9 +999,6 @@ static struct stm32l4_pwmtimer_s g_pwm8dev = #endif #if defined(HAVE_TRGO) && defined(STM32L4_TIM8_TRGO) .trgo = STM32L4_TIM8_TRGO, -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM8UP, #endif .base = STM32L4_TIM8_BASE, .pclk = STM32L4_APB2_TIM8_CLKIN, @@ -1142,9 +1081,6 @@ static struct stm32l4_pwmtimer_s g_pwm15dev = #endif #if defined(HAVE_TRGO) && defined(STM32L4_TIM15_TRGO) .trgo = STM32L4_TIM15_TRGO, -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM15, #endif .base = STM32L4_TIM15_BASE, .pclk = STM32L4_APB2_TIM15_CLKIN, @@ -1211,9 +1147,6 @@ static struct stm32l4_pwmtimer_s g_pwm16dev = #endif #if defined(HAVE_TRGO) .trgo = 0, /* TRGO not supported for TIM16 */ -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM16, #endif .base = STM32L4_TIM16_BASE, .pclk = STM32L4_APB2_TIM16_CLKIN, @@ -1280,9 +1213,6 @@ static struct stm32l4_pwmtimer_s g_pwm17dev = #endif #if defined(HAVE_TRGO) .trgo = 0, /* TRGO not supported for TIM17 */ -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_TIM17, #endif .base = STM32L4_TIM17_BASE, .pclk = STM32L4_APB2_TIM17_CLKIN, @@ -1331,9 +1261,6 @@ static struct stm32l4_pwmtimer_s g_pwmlp1dev = #endif #if defined(HAVE_TRGO) .trgo = 0, /* TRGO not supported for LPTIM1 */ -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_LPTIM1, #endif .base = STM32L4_LPTIM1_BASE, #if defined(CONFIG_STM32L4_LPTIM1_CLK_APB1) @@ -1390,9 +1317,6 @@ static struct stm32l4_pwmtimer_s g_pwmlp2dev = #endif #if defined(HAVE_TRGO) .trgo = 0, /* TRGO not supported for LPTIM2 */ -#endif -#ifdef CONFIG_PWM_PULSECOUNT - .irq = STM32L4_IRQ_LPTIM2, #endif .base = STM32L4_LPTIM2_BASE, #if defined(CONFIG_STM32L4_LPTIM2_CLK_APB1) @@ -2786,7 +2710,7 @@ static int pwm_break_dt_configure(struct stm32l4_pwmtimer_s *priv) * Name: pwm_configure * * Description: - * Configure PWM timer in normal mode (no PULSECOUNT) + * Configure PWM timer in standard mode * ****************************************************************************/ @@ -2905,160 +2829,6 @@ errout: return ret; } -#ifdef CONFIG_PWM_PULSECOUNT - -/**************************************************************************** - * Name: pwm_pulsecount_timer - * - * Description: - * (Re-)initialize the timer resources and start the pulsed output - * - * Input Parameters: - * dev - A reference to the lower half PWM driver state structure - * info - A reference to the characteristics of the pulsed output - * - * Returned Value: - * Zero on success; a negated errno value on failure - * - * TODO: PWM_PULSECOUNT should be configurable for each timer instance - * TODO: PULSECOUNT doesn't work with MULTICHAN at this moment - * - ****************************************************************************/ - -static int pwm_pulsecount_timer(struct pwm_lowerhalf_s *dev, - const struct pwm_info_s *info) -{ - struct stm32l4_pwmtimer_s *priv = (struct stm32l4_pwmtimer_s *)dev; - ub16_t duty = 0; - uint8_t channel = 0; - uint16_t outputs = 0; - int ret = OK; - - /* If we got here it means that timer instance support pulsecount mode! */ - - DEBUGASSERT(priv != NULL && info != NULL); - - pwminfo("TIM%u channel: %u frequency: %u duty: %08x count: %u\n", - priv->timid, priv->channels[0].channel, info->frequency, - info->channels[0].duty, info->channels[0].count); - - DEBUGASSERT(info->frequency > 0); - - /* Channel specific setup */ - - duty = info->channels[0].duty; - channel = priv->channels[0].channel; - - /* Disable all interrupts and DMA requests, clear all pending status */ - - pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, 0); - pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0); - - /* Set timer frequency */ - - ret = pwm_frequency_update(dev, info->frequency); - if (ret < 0) - { - goto errout; - } - - /* Update duty cycle */ - - ret = pwm_duty_update(dev, channel, duty); - if (ret < 0) - { - goto errout; - } - - /* If a non-zero repetition count has been selected, then set the - * repetition counter to the count-1 (pwm_pulsecount_start() has already - * assured us that the count value is within range). - */ - - if (info->channels[0].count > 0) - { - /* Save the remaining count and the number of counts that will have - * elapsed on the first interrupt. - */ - - /* If the first interrupt occurs at the end end of the first - * repetition count, then the count will be the same as the RCR - * value. - */ - - priv->prev = pwm_pulsecount(info->channels[0].count); - pwm_putreg(priv, STM32L4_GTIM_RCR_OFFSET, (uint16_t)priv->prev - 1); - - /* Generate an update event to reload the prescaler. This should - * preload the RCR into active repetition counter. - */ - - pwm_soft_update(dev); - - /* Now set the value of the RCR that will be loaded on the next - * update event. - */ - - priv->count = info->channels[0].count; - priv->curr = pwm_pulsecount(info->channels[0].count - priv->prev); - pwm_putreg(priv, STM32L4_GTIM_RCR_OFFSET, (uint16_t)priv->curr - 1); - } - - /* Otherwise, just clear the repetition counter */ - - else - { - /* Set the repetition counter to zero */ - - pwm_putreg(priv, STM32L4_GTIM_RCR_OFFSET, 0); - - /* Generate an update event to reload the prescaler */ - - pwm_soft_update(dev); - } - - /* Get configured outputs */ - - outputs = pwm_outputs_from_channels(priv); - - /* Enable output */ - - ret = pwm_outputs_enable(dev, outputs, true); - if (ret < 0) - { - goto errout; - } - - /* Setup update interrupt. If info->channels[0].count is > 0, then we can - * be assured that pwm_pulsecount_start() has already verified: (1) that - * this is an advanced timer, and that (2) the repetition count is within - * range. - */ - - if (info->channels[0].count > 0) - { - /* Clear all pending interrupts and enable the update interrupt. */ - - pwm_putreg(priv, STM32L4_GTIM_SR_OFFSET, 0); - pwm_putreg(priv, STM32L4_GTIM_DIER_OFFSET, GTIM_DIER_UIE); - - /* Enable the timer */ - - pwm_timer_enable(dev, true); - - /* And enable timer interrupts at the NVIC */ - - up_enable_irq(priv->irq); - } - - pwm_dumpregs(dev, "After starting"); - -errout: - return ret; -} - -#else /* !CONFIG_PWM_PULSECOUNT */ - /**************************************************************************** * Name: pwm_duty_channels_update * @@ -3288,168 +3058,6 @@ errout: } #endif /* HAVE_LPTIM */ -#endif /* CONFIG_PWM_PULSECOUNT */ - -#ifdef HAVE_PWM_INTERRUPT - -/**************************************************************************** - * Name: pwm_interrupt - * - * Description: - * Handle timer interrupts. - * - * Input Parameters: - * dev - A reference to the lower half PWM driver state structure - * - * Returned Value: - * Zero on success; a negated errno value on failure - * - ****************************************************************************/ - -static int pwm_interrupt(struct pwm_lowerhalf_s *dev) -{ - struct stm32l4_pwmtimer_s *priv = (struct stm32l4_pwmtimer_s *)dev; - uint16_t regval; - - /* Verify that this is an update interrupt. Nothing else is expected. */ - - regval = pwm_getreg(priv, STM32L4_ATIM_SR_OFFSET); - DEBUGASSERT((regval & ATIM_SR_UIF) != 0); - - /* Clear the UIF interrupt bit */ - - pwm_putreg(priv, STM32L4_ATIM_SR_OFFSET, regval & ~ATIM_SR_UIF); - - /* Calculate the new count by subtracting the number of pulses - * since the last interrupt. - */ - - if (priv->count <= priv->prev) - { - /* We are finished. Turn off the mast output to stop the output as - * quickly as possible. - */ - - regval = pwm_getreg(priv, STM32L4_ATIM_BDTR_OFFSET); - regval &= ~ATIM_BDTR_MOE; - pwm_putreg(priv, STM32L4_ATIM_BDTR_OFFSET, regval); - - /* Disable first interrupts, stop and reset the timer */ - - pwm_stop(dev); - - /* Then perform the callback into the upper half driver */ - - pwm_expired(priv->handle); - - priv->handle = NULL; - priv->count = 0; - priv->prev = 0; - priv->curr = 0; - } - else - { - /* Decrement the count of pulses remaining using the number of - * pulses generated since the last interrupt. - */ - - priv->count -= priv->prev; - - /* Set up the next RCR. Set 'prev' to the value of the RCR that - * was loaded when the update occurred (just before this interrupt) - * and set 'curr' to the current value of the RCR register (which - * will bet loaded on the next update event). - */ - - priv->prev = priv->curr; - priv->curr = pwm_pulsecount(priv->count - priv->prev); - pwm_putreg(priv, STM32L4_ATIM_RCR_OFFSET, (uint16_t)priv->curr - 1); - } - - /* Now all of the time critical stuff is done so we can do some debug - * output - */ - - pwminfo("Update interrupt SR: %04x prev: %u curr: %u count: %u\n", - regval, priv->prev, priv->curr, priv->count); - - return OK; -} - -/**************************************************************************** - * Name: pwm_tim1/8interrupt - * - * Description: - * Handle timer 1 and 8 interrupts. - * - * Input Parameters: - * Standard NuttX interrupt inputs - * - * Returned Value: - * Zero on success; a negated errno value on failure - * - ****************************************************************************/ - -#ifdef CONFIG_STM32L4_TIM1_PWM -static int pwm_tim1interrupt(int irq, void *context, void *arg) -{ - return pwm_interrupt((struct pwm_lowerhalf_s *)&g_pwm1dev); -} -#endif /* CONFIG_STM32L4_TIM1_PWM */ - -#ifdef CONFIG_STM32L4_TIM8_PWM -static int pwm_tim8interrupt(int irq, void *context, void *arg) -{ - return pwm_interrupt((struct pwm_lowerhalf_s *)&g_pwm8dev); -} -#endif /* CONFIG_STM32L4_TIM8_PWM */ - -/**************************************************************************** - * Name: pwm_pulsecount - * - * Description: - * Pick an optimal pulse count to program the RCR. - * - * Input Parameters: - * count - The total count remaining - * - * Returned Value: - * The recommended pulse count - * - ****************************************************************************/ - -static uint8_t pwm_pulsecount(uint32_t count) -{ - /* The the remaining pulse count is less than or equal to the maximum, the - * just return the count. - */ - - if (count <= ATIM_RCR_REP_MAX) - { - return (uint8_t)count; - } - - /* Otherwise, we have to be careful. We do not want a small number of - * counts at the end because we might have trouble responding fast enough. - * If the remaining count is less than 150% of the maximum, then return - * half of the maximum. In this case the final sequence will be between 64 - * and 128. - */ - - else if (count < (3 * ATIM_RCR_REP_MAX / 2)) - { - return (uint8_t)((ATIM_RCR_REP_MAX + 1) >> 1); - } - - /* Otherwise, return the maximum. The final count will be 64 or more */ - - else - { - return (uint8_t)ATIM_RCR_REP_MAX; - } -} -#endif /* HAVE_PWM_INTERRUPT */ - /**************************************************************************** * Name: pwm_setapbclock * @@ -3837,37 +3445,6 @@ errout: * ****************************************************************************/ -#ifdef CONFIG_PWM_PULSECOUNT -static int pwm_start(struct pwm_lowerhalf_s *dev, - const struct pwm_info_s *info, - void *handle) -{ - struct stm32l4_pwmtimer_s *priv = (struct stm32l4_pwmtimer_s *)dev; - - /* Check if a pulsecount has been selected */ - - if (info->channels[0].count > 0) - { - /* Only the advanced timers (TIM1,8 can support the pulse counting) */ - - if (priv->timtype != TIMTYPE_ADVANCED) - { - pwmerr("ERROR: TIM%u cannot support pulse count: %u\n", - priv->timid, info->channels[0].count); - return -EPERM; - } - } - - /* Save the handle */ - - priv->handle = handle; - - /* Start the time */ - - return pwm_pulsecount_timer(dev, info); -} -#else /* !CONFIG_PWM_PULSECOUNT */ - static int pwm_start(struct pwm_lowerhalf_s *dev, const struct pwm_info_s *info) { @@ -3921,7 +3498,6 @@ static int pwm_start(struct pwm_lowerhalf_s *dev, return ret; } -#endif /* CONFIG_PWM_PULSECOUNT */ /**************************************************************************** * Name: pwm_stop @@ -4044,11 +3620,9 @@ static int pwm_stop(struct pwm_lowerhalf_s *dev) flags = enter_critical_section(); -#ifndef CONFIG_PWM_PULSECOUNT /* Stopped so frequency is zero */ priv->frequency = 0; -#endif /* Disable further interrupts and stop the timer */ @@ -4137,10 +3711,6 @@ struct pwm_lowerhalf_s *stm32l4_pwminitialize(int timer) /* Attach but disable the TIM1 update interrupt */ -#ifdef CONFIG_PWM_PULSECOUNT - irq_attach(lower->irq, pwm_tim1interrupt, NULL); - up_disable_irq(lower->irq); -#endif break; #endif @@ -4174,10 +3744,6 @@ struct pwm_lowerhalf_s *stm32l4_pwminitialize(int timer) /* Attach but disable the TIM8 update interrupt */ -#ifdef CONFIG_PWM_PULSECOUNT - irq_attach(lower->irq, pwm_tim8interrupt, NULL); - up_disable_irq(lower->irq); -#endif break; #endif
