diff --git a/arch/arm/src/stm32/Make.defs b/arch/arm/src/stm32/Make.defs index dcdab4c1efc..8563141bb95 100644 --- a/arch/arm/src/stm32/Make.defs +++ b/arch/arm/src/stm32/Make.defs @@ -111,6 +111,10 @@ CHIP_CSRCS += stm32_lsi.c stm32_gpio.c stm32_exti_gpio.c stm32_flash.c stm32_irq CHIP_CSRCS += stm32_dma.c stm32_lowputc.c stm32_serial.c stm32_spi.c CHIP_CSRCS += stm32_sdio.c stm32_tim.c stm32_waste.c stm32_ccm.c +ifeq ($(CONFIG_TIMER),y) +CHIP_CSRCS += stm32_tim_lowerhalf.c +endif + ifneq ($(CONFIG_SCHED_TICKLESS),y) CHIP_CSRCS += stm32_timerisr.c endif diff --git a/arch/arm/src/stm32/stm32_tim.h b/arch/arm/src/stm32/stm32_tim.h index fadf58e6b74..768e709c666 100644 --- a/arch/arm/src/stm32/stm32_tim.h +++ b/arch/arm/src/stm32/stm32_tim.h @@ -185,6 +185,26 @@ FAR struct stm32_tim_dev_s *stm32_tim_init(int timer); int stm32_tim_deinit(FAR struct stm32_tim_dev_s * dev); +/**************************************************************************** + * Name: stm32_timer_initialize + * + * Description: + * Bind the configuration timer to a timer lower half instance and + * register the timer drivers at 'devpath' + * + * Input Parameters: + * devpath - The full path to the timer device. This should be of the form /dev/timer0 + * timer - the timer number. + * + * Returned Values: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ +#ifdef CONFIG_TIMER +int stm32_timer_initialize(FAR const char *devpath, int timer); +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/arm/src/stm32/stm32_tim_lowerhalf.c b/arch/arm/src/stm32/stm32_tim_lowerhalf.c new file mode 100644 index 00000000000..8c7c97d0ec2 --- /dev/null +++ b/arch/arm/src/stm32/stm32_tim_lowerhalf.c @@ -0,0 +1,733 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_tim_lowerhalf.c + * + * Copyright (C) 2015 Wail Khemir. All rights reserved. + * Authors: Wail Khemir + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include "stm32_tim.h" + +#if defined(CONFIG_TIMER) && \ + ( defined(CONFIG_STM32_TIM1) || defined(CONFIG_STM32_TIM2) || defined(CONFIG_STM32_TIM3) || \ + defined(CONFIG_STM32_TIM4) || defined(CONFIG_STM32_TIM5) || defined(CONFIG_STM32_TIM6) || \ + defined(CONFIG_STM32_TIM7) || defined(CONFIG_STM32_TIM8) ) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* This structure provides the private representation of the "lower-half" + * driver state structure. This structure must be cast-compatible with the + * timer_lowerhalf_s structure. + */ +struct stm32_lowerhalf_s +{ + const struct timer_ops_s *ops; /* Lower half operations */ + struct stm32_tim_dev_s *tim; /* stm32 timer driver */ + tccb_t handlerUsr; /* Current user interrupt handler */ + xcpt_t handlerTim; /* Current timer interrupt handler */ + bool started; /* True: Timer has been started */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helper functions *********************************************************/ +static struct stm32_lowerhalf_s* stm32_get_lowerhalf(int timer); +static xcpt_t stm32_get_interrupt(int timer); + + +/* Interrupt handling *******************************************************/ +#ifdef CONFIG_STM32_TIM1 +static int stm32_tim1_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM2 +static int stm32_tim2_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM3 +static int stm32_tim3_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM4 +static int stm32_tim4_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM5 +static int stm32_tim5_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM6 +static int stm32_tim6_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM7 +static int stm32_tim7_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM8 +static int stm32_tim8_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM9 +static int stm32_tim9_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM10 +static int stm32_tim10_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM11 +static int stm32_tim11_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM12 +static int stm32_tim12_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM13 +static int stm32_tim13_interrupt(int irq, FAR void *context); +#endif +#ifdef CONFIG_STM32_TIM14 +static int stm32_tim14_interrupt(int irq, FAR void *context); +#endif + +static int stm32_timer_handler(struct stm32_lowerhalf_s* attr); + +/* "Lower half" driver methods **********************************************/ +static int stm32_start(struct timer_lowerhalf_s *lower); +static int stm32_stop(struct timer_lowerhalf_s *lower); +static int stm32_settimeout(struct timer_lowerhalf_s *lower, uint32_t timeout); +static tccb_t stm32_sethandler(struct timer_lowerhalf_s *lower, tccb_t handler); + + + +/**************************************************************************** + * Private Data + ****************************************************************************/ +/* "Lower half" driver methods */ +static const struct timer_ops_s g_timer_ops = +{ + .start = stm32_start, + .stop = stm32_stop, + .getstatus = 0, + .settimeout = stm32_settimeout, + .sethandler = stm32_sethandler, + .ioctl = 0, +}; + +#ifdef CONFIG_STM32_TIM1 +static struct stm32_lowerhalf_s g_tim1_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM2 +static struct stm32_lowerhalf_s g_tim2_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM3 +static struct stm32_lowerhalf_s g_tim3_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM4 +static struct stm32_lowerhalf_s g_tim4_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM5 +static struct stm32_lowerhalf_s g_tim5_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM6 +static struct stm32_lowerhalf_s g_tim6_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM7 +static struct stm32_lowerhalf_s g_tim7_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM8 +static struct stm32_lowerhalf_s g_tim8_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM9 +static struct stm32_lowerhalf_s g_tim9_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM10 +static struct stm32_lowerhalf_s g_tim10_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM11 +static struct stm32_lowerhalf_s g_tim11_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM12 +static struct stm32_lowerhalf_s g_tim12_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM13 +static struct stm32_lowerhalf_s g_tim13_lowerHalf; +#endif +#ifdef CONFIG_STM32_TIM14 +static struct stm32_lowerhalf_s g_tim14_lowerHalf; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_get_lowerhalf + * + * Description: + * Get the lower half timer structure of the corresponding timer + * + * Input Parameters: + * timer - the timer's number + * + * Returned Values: + * A pointer to the lower half structure on success, NULL on failure + * + ****************************************************************************/ +static struct stm32_lowerhalf_s* stm32_get_lowerhalf(int timer) +{ + struct stm32_lowerhalf_s* lower; + + switch(timer) + { +#ifdef CONFIG_STM32_TIM1 + case 1: + lower = &g_tim1_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM2 + case 2: + lower = &g_tim2_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM3 + case 3: + lower = &g_tim3_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM4 + case 4: + lower = &g_tim4_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM5 + case 5: + lower = &g_tim5_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM6 + case 6: + lower = &g_tim6_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM7 + case 7: + lower = &g_tim7_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM8 + case 8: + lower = &g_tim8_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM9 + case 9: + lower = &g_tim9_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM10 + case 10: + lower = &g_tim10_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM11 + case 11: + lower = &g_tim11_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM12 + case 12: + lower = &g_tim12_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM13 + case 13: + lower = &g_tim13_lowerHalf; + break; +#endif +#ifdef CONFIG_STM32_TIM14 + case 14: + lower = &g_tim14_lowerHalf; + break; +#endif + default: + lower = 0; + } + + return lower; +} + +/**************************************************************************** + * Name: stm32_get_interrupt + * + * Description: + * Get a pointer to the interrupt handler of the corresponding timer + * + * Input Parameters: + * timer - the timer's number + * + * Returned Values: + * A pointer to the interrupt handler on success, NULL on failure + * + ****************************************************************************/ +static xcpt_t stm32_get_interrupt(int timer) +{ + xcpt_t intr; + + switch(timer) + { +#ifdef CONFIG_STM32_TIM1 + case 1: + intr = stm32_tim1_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM2 + case 2: + intr = stm32_tim2_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM3 + case 3: + intr = stm32_tim3_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM4 + case 4: + intr = stm32_tim4_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM5 + case 5: + intr = stm32_tim5_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM6 + case 6: + intr = stm32_tim6_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM7 + case 7: + intr = stm32_tim7_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM8 + case 8: + intr = stm32_tim8_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM9 + case 9: + intr = stm32_tim9_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM10 + case 10: + intr = stm32_tim10_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM11 + case 11: + intr = stm32_tim11_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM12 + case 12: + intr = stm32_tim12_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM13 + case 13: + intr = stm32_tim13_interrupt; + break; +#endif +#ifdef CONFIG_STM32_TIM14 + case 14: + intr = stm32_tim14_interrupt; + break; +#endif + default: + intr = 0; + } + + return intr; +} + +/**************************************************************************** + * Name: stm32_timN_interrupt, N=1..14 + * + * Description: + * Individual interrupt handlers for each timer + * + ****************************************************************************/ +#ifdef CONFIG_STM32_TIM1 +static int stm32_tim1_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim1_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM2 +static int stm32_tim2_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim2_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM3 +static int stm32_tim3_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim3_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM4 +static int stm32_tim4_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim4_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM5 +static int stm32_tim5_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim5_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM6 +static int stm32_tim6_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim6_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM7 +static int stm32_tim7_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim7_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM8 +static int stm32_tim8_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim8_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM9 +static int stm32_tim9_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim9_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM10 +static int stm32_tim10_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim10_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM11 +static int stm32_tim11_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim11_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM12 +static int stm32_tim12_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim12_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM13 +static int stm32_tim13_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim13_lowerHalf); +} +#endif + +#ifdef CONFIG_STM32_TIM14 +static int stm32_tim14_interrupt(int irq, FAR void *context) +{ + return stm32_timer_handler(&g_tim14_lowerHalf); +} +#endif + +/**************************************************************************** + * Name: stm32_timer_handler + * + * Description: + * timer interrupt handler + * + * Input Parameters: + * + * + * Returned Values: + * + * + ****************************************************************************/ +static int stm32_timer_handler(struct stm32_lowerhalf_s* lower) +{ + STM32_TIM_ACKINT(lower->tim, 0); + + uint32_t next_interval_us = 0; + int ret = (*lower->handlerUsr)(&next_interval_us); + + if(ret == OK) + { + if(next_interval_us > 0) + STM32_TIM_SETPERIOD(lower->tim, next_interval_us); + } + else + { + stm32_stop(lower); + } + + return 0; +} + +/**************************************************************************** + * Name: stm32_start + * + * Description: + * Start the timer, resetting the time to the current timeout, + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32_start(struct timer_lowerhalf_s *lower) +{ + struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; + + if (!priv->started) + { + STM32_TIM_SETCLOCK(priv->tim, 1000000); // 1000000 Hz = 1 microsecond + STM32_TIM_SETMODE(priv->tim, STM32_TIM_MODE_UP); + + if(priv->handlerUsr) + { + STM32_TIM_SETISR(priv->tim, priv->handlerTim, 0); + STM32_TIM_ENABLEINT(priv->tim, 0); + } + + priv->started = true; + return OK; + } + + /* Return EBUSY to indicate that the timer was already running */ + return -EBUSY; +} + +/**************************************************************************** + * Name: stm32_stop + * + * Description: + * Stop the timer + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32_stop(struct timer_lowerhalf_s *lower) +{ + struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; + + if (priv->started) + { + STM32_TIM_SETMODE(priv->tim, STM32_TIM_MODE_DISABLED); + STM32_TIM_DISABLEINT(priv->tim, 0); + STM32_TIM_SETISR(priv->tim, 0, 0); + priv->started = false; + return OK; + } + + /* Return ENODEV to indicate that the timer was not running */ + return -ENODEV; +} + +/**************************************************************************** + * Name: stm32_settimeout + * + * Description: + * Set a new timeout value (and reset the timer) + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * timeout - The new timeout value in microseconds. + * + * Returned Values: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +static int stm32_settimeout(struct timer_lowerhalf_s *lower, uint32_t timeout) +{ + struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; + + if (priv->started) + { + return -EPERM; + } + + STM32_TIM_SETPERIOD(priv->tim, timeout); + return OK; +} + +/**************************************************************************** + * Name: stm32_sethandler + * + * Description: + * Call this user provided timeout handler. + * + * Input Parameters: + * lower - A pointer the publicly visible representation of the "lower-half" + * driver state structure. + * newhandler - The new timer expiration function pointer. If this + * function pointer is NULL, then the reset-on-expiration + * behavior is restored, + * + * Returned Values: + * The previous timer expiration function pointer or NULL is there was + * no previous function pointer. + * + ****************************************************************************/ +static tccb_t stm32_sethandler(struct timer_lowerhalf_s *lower, tccb_t newhandler) +{ + struct stm32_lowerhalf_s *priv = (struct stm32_lowerhalf_s *)lower; + + irqstate_t flags = irqsave(); + + /* Get the old handler return value */ + tccb_t oldhandler = priv->handlerUsr; + + /* Save the new handler */ + priv->handlerUsr = newhandler; + + if(newhandler) + { + STM32_TIM_SETISR(priv->tim, priv->handlerTim, 0); + STM32_TIM_ENABLEINT(priv->tim, 0); + } + else + { + STM32_TIM_DISABLEINT(priv->tim, 0); + STM32_TIM_SETISR(priv->tim, 0, 0); + } + + irqrestore(flags); + + return oldhandler; +} + + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_timer_initialize + * + * Description: + * Bind the configuration timer to a timer lower half instance and + * register the timer drivers at 'devpath' + * + * Input Parameters: + * devpath - The full path to the timer device. This should be of the + * form /dev/timer0 + * timer - the timer's number. + * + * Returned Values: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int stm32_timer_initialize(FAR const char *devpath, int timer) +{ + struct stm32_lowerhalf_s *lower = stm32_get_lowerhalf(timer); + memset(lower, 0, sizeof(struct stm32_lowerhalf_s)); + + /* Initialize the non-zero elements of lower half state structure */ + lower->ops = &g_timer_ops; + lower->handlerTim = stm32_get_interrupt(timer); + lower->tim = stm32_tim_init(timer); + if(!lower->tim) + { + return -EINVAL; + } + + /* Register the timer driver as /dev/timerX. The returned value from + * timer_register is a handle that could be used with timer_unregister(). + * REVISIT: The returned handle is discard here. + */ + void *drvr = timer_register(devpath, (struct timer_lowerhalf_s *)lower); + if (!drvr) + { + /* The actual cause of the failure may have been a failure to allocate + * perhaps a failure to register the timer driver (such as if the + * 'depath' were not unique). We know here but we return EEXIST to + * indicate the failure (implying the non-unique devpath). + */ + return -EEXIST; + } + + return OK; +} + +#endif /* CONFIG_TIMER */