diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 8e9c2d4e49..189b5a6399 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -2666,6 +2666,7 @@ config STM32_ONESHOT_MAXTIMERS int "Maximum number of oneshot timers" default 1 range 1 8 + depends on STM32_ONESHOT ---help--- Determines the maximum number of oneshot timers that can be supported. This setting pre-allocates some minimal support for each diff --git a/arch/arm/src/stm32/stm32_oneshot.c b/arch/arm/src/stm32/stm32_oneshot.c index 20607f3b01..007f833baa 100644 --- a/arch/arm/src/stm32/stm32_oneshot.c +++ b/arch/arm/src/stm32/stm32_oneshot.c @@ -105,7 +105,7 @@ static const xcpt_t g_callbacks[CONFIG_STM32_ONESHOT_MAXTIMERS] = stm32_oneshot5_handler, #endif #if CONFIG_STM32_ONESHOT_MAXTIMERS > 5 - stm32_oneshot5_handler, + stm32_oneshot6_handler, #endif #if CONFIG_STM32_ONESHOT_MAXTIMERS > 6 stm32_oneshot7_handler, @@ -223,7 +223,7 @@ static int stm32_oneshot5_handler(int irq, void *context) #endif #if CONFIG_STM32_ONESHOT_MAXTIMERS > 5 -static int stm32_oneshot5_handler(int irq, void *context) +static int stm32_oneshot6_handler(int irq, void *context) { DEBUGASSERT(g_oneshot[6] != NULL); return stm32_oneshot_handler(g_oneshot[5]); diff --git a/arch/arm/src/stm32/stm32_oneshot.h b/arch/arm/src/stm32/stm32_oneshot.h index 2762006edf..d32c924a79 100644 --- a/arch/arm/src/stm32/stm32_oneshot.h +++ b/arch/arm/src/stm32/stm32_oneshot.h @@ -89,7 +89,7 @@ struct stm32_oneshot_s { uint8_t chan; /* The timer/counter in use */ #if CONFIG_STM32_ONESHOT_MAXTIMERS > 1 - uint8_t cbndx; /* Timer callback handler index*/ + uint8_t cbndx; /* Timer callback handler index */ #endif volatile bool running; /* True: the timer is running */ FAR struct stm32_tim_dev_s *tch; /* Pointer returned by diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig index 9f8d6cbda1..a518c5cede 100644 --- a/arch/arm/src/stm32l4/Kconfig +++ b/arch/arm/src/stm32l4/Kconfig @@ -659,6 +659,24 @@ config STM32L4_FREERUN bool default y +config STM32L4_TICKLESS_ONESHOT + int "Tickless one-shot timer channel" + default 2 + range 1 8 + depends on STM32L4_ONESHOT + ---help--- + If the Tickless OS feature is enabled, then one clock must be + assigned to provide the one-shot timer needed by the OS. + +config STM32L4_TICKLESS_FREERUN + int "Tickless free-running timer channel" + default 5 + range 1 8 + depends on STM32L4_FREERUN + ---help--- + If the Tickless OS feature is enabled, then one clock must be + assigned to provide the free-running timer needed by the OS. + endif # SCHED_TICKLESS if !SCHED_TICKLESS @@ -679,23 +697,16 @@ config STM32L4_FREERUN endif # !SCHED_TICKLESS -config STM32L4_TICKLESS_ONESHOT - int "Tickless one-shot timer channel" - default 2 +config STM32L4_ONESHOT_MAXTIMERS + int "Maximum number of oneshot timers" + default 1 range 1 8 depends on STM32L4_ONESHOT ---help--- - If the Tickless OS feature is enabled, then one clock must be - assigned to provide the one-shot timer needed by the OS. - -config STM32L4_TICKLESS_FREERUN - int "Tickless free-running timer channel" - default 5 - range 1 8 - depends on STM32L4_FREERUN - ---help--- - If the Tickless OS feature is enabled, then one clock must be - assigned to provide the free-running timer needed by the OS. + Determines the maximum number of oneshot timers that can be + supported. This setting pre-allocates some minimal support for each + of the timers and places an upper limit on the number of oneshot + timers that you can use. config STM32L4_TIM1_PWM bool "TIM1 PWM" diff --git a/arch/arm/src/stm32l4/stm32l4_oneshot.c b/arch/arm/src/stm32l4/stm32l4_oneshot.c index 073ca62d42..3c65866cd5 100644 --- a/arch/arm/src/stm32l4/stm32l4_oneshot.c +++ b/arch/arm/src/stm32l4/stm32l4_oneshot.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32l4/stm32l4_oneshot.c * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * dev@ziggurat29.com * @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -55,10 +56,66 @@ #ifdef CONFIG_STM32L4_ONESHOT /**************************************************************************** - * Private Date + * Private Function Prototypes ****************************************************************************/ -static struct stm32l4_oneshot_s *g_oneshot; +static int stm32l4_oneshot_handler(struct stm32l4_oneshot_s *oneshot); +static int stm32l4_oneshot1_handler(int irq, void *context); +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 1 +static int stm32l4_oneshot2_handler(int irq, void *context); +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 2 +static int stm32l4_oneshot3_handler(int irq, void *context); +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 3 +static int stm32l4_oneshot4_handler(int irq, void *context); +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 4 +static int stm32l4_oneshot5_handler(int irq, void *context); +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 5 +static int stm32l4_oneshot6_handler(int irq, void *context); +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 6 +static int stm32l4_oneshot7_handler(int irq, void *context); +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 7 +static int stm32l4_oneshot8_handler(int irq, void *context); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct stm32l4_oneshot_s *g_oneshot[CONFIG_STM32L4_ONESHOT_MAXTIMERS]; + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 1 +static const xcpt_t g_callbacks[CONFIG_STM32L4_ONESHOT_MAXTIMERS] = +{ + stm32l4_oneshot1_handler, +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 1 + stm32l4_oneshot2_handler, +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 2 + stm32l4_oneshot3_handler, +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 3 + stm32l4_oneshot4_handler, +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 4 + stm32l4_oneshot5_handler, +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 5 + stm32l4_oneshot6_handler, +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 6 + stm32l4_oneshot7_handler, +#endif +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 7 + stm32l4_oneshot8_handler, +#endif +}; +#endif /**************************************************************************** * Private Functions @@ -68,24 +125,20 @@ static struct stm32l4_oneshot_s *g_oneshot; * Name: stm32l4_oneshot_handler * * Description: - * Timer interrupt callback. When the oneshot timer interrupt expires, - * this function will be called. It will forward the call to the next - * level up. + * Common timer interrupt callback. When any oneshot timer interrupt + * expires, this function will be called. It will forward the call to + * the next level up. * * Input Parameters: - * tch - The handle that represents the timer state - * arg - An opaque argument provided when the interrupt was registered - * sr - The value of the timer interrupt status register at the time - * that the interrupt occurred. + * oneshot - The state associated with the expired timer * * Returned Value: - * None + * Always returns OK * ****************************************************************************/ -static int stm32l4_oneshot_handler(int irq, FAR void *context) +static int stm32l4_oneshot_handler(struct stm32l4_oneshot_s *oneshot) { - FAR struct stm32l4_oneshot_s *oneshot = g_oneshot; oneshot_handler_t oneshot_handler; FAR void *oneshot_arg; @@ -116,6 +169,137 @@ static int stm32l4_oneshot_handler(int irq, FAR void *context) return OK; } +/**************************************************************************** + * Name: stm32l4_oneshot[N]_handler + * + * Description: + * Timer interrupt callbacks. When a oneshot timer interrupt expires, + * one of these functions will be called. These functions will forward + * the call to the nextlevel up. + * + * Input Parameters: + * Standard interrupt handler arguments. + * + * Returned Value: + * Always returns OK + * + ****************************************************************************/ + +static int stm32l4_oneshot1_handler(int irq, void *context) +{ + DEBUGASSERT(g_oneshot[0] != NULL); + return stm32l4_oneshot_handler(g_oneshot[0]); +} + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 1 +static int stm32l4_oneshot2_handler(int irq, void *context) +{ + DEBUGASSERT(g_oneshot[1] != NULL); + return stm32l4_oneshot_handler(g_oneshot[1]); +} +#endif + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 2 +static int stm32l4_oneshot3_handler(int irq, void *context) +{ + DEBUGASSERT(g_oneshot[2] != NULL); + return stm32l4_oneshot_handler(g_oneshot[2]); +} +#endif + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 3 +static int stm32l4_oneshot4_handler(int irq, void *context) +{ + DEBUGASSERT(g_oneshot[3] != NULL); + return stm32l4_oneshot_handler(g_oneshot[3]); +} +#endif + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 4 +static int stm32l4_oneshot5_handler(int irq, void *context) +{ + DEBUGASSERT(g_oneshot[4] != NULL); + return stm32l4_oneshot_handler(g_oneshot[4]); +} +#endif + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 5 +static int stm32l4_oneshot6_handler(int irq, void *context) +{ + DEBUGASSERT(g_oneshot[6] != NULL); + return stm32l4_oneshot_handler(g_oneshot[5]); +} +#endif + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 6 +static int stm32l4_oneshot7_handler(int irq, void *context) +{ + DEBUGASSERT(g_oneshot[7] != NULL); + return stm32l4_oneshot_handler(g_oneshot[6]); +} +#endif + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 7 +static int stm32l4_oneshot8_handler(int irq, void *context) +{ + DEBUGASSERT(g_oneshot[0] != NULL); + return stm32l4_oneshot_handler(g_oneshot[7]); +} +#endif + +/**************************************************************************** + * Name: stm32l4_allocate_handler + * + * Description: + * Allocate a timer callback handler for the oneshot instance. + * + * Input Parameters: + * oneshot - The state instance the new oneshot timer + * + * Returned Value: + * Returns zero (OK) on success. This can only fail if the number of + * timers exceeds CONFIG_STM32L4_ONESHOT_MAXTIMERS. + * + ****************************************************************************/ + +static inline int stm32l4_allocate_handler(struct stm32l4_oneshot_s *oneshot) +{ +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 1 + int ret = -ENOMEM; + int i; + + /* Search for an unused handler */ + + sched_lock(); + for (i = 0; i < CONFIG_STM32L4_ONESHOT_MAXTIMERS; i++) + { + /* Is this handler available? */ + + if (g_oneshot[i] == NULL) + { + /* Yes... assign it to this oneshot */ + + g_oneshot[i] = oneshot; + oneshot->cbndx = i; + ret = OK; + break; + } + } + + sched_unlock(); + return ret; + +#else + if (g_oneshot[0] == NULL) + { + g_oneshot[0] = oneshot; + return OK; + } + + return -ENOMEM; +#endif +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -139,8 +323,8 @@ static int stm32l4_oneshot_handler(int irq, FAR void *context) * ****************************************************************************/ -int stm32l4_oneshot_initialize(FAR struct stm32l4_oneshot_s *oneshot, int chan, - uint16_t resolution) +int stm32l4_oneshot_initialize(FAR struct stm32l4_oneshot_s *oneshot, + int chan, uint16_t resolution) { uint32_t frequency; @@ -161,17 +345,16 @@ int stm32l4_oneshot_initialize(FAR struct stm32l4_oneshot_s *oneshot, int chan, STM32L4_TIM_SETCLOCK(oneshot->tch, frequency); - /* Initialize the remaining fields in the state structure and return - * success. - */ + /* Initialize the remaining fields in the state structure. */ oneshot->chan = chan; oneshot->running = false; oneshot->handler = NULL; oneshot->arg = NULL; - g_oneshot = oneshot; - return OK; + /* Assign a callback handler to the oneshot */ + + return stm32l4_allocate_handler(oneshot); } /**************************************************************************** @@ -261,7 +444,11 @@ int stm32l4_oneshot_start(FAR struct stm32l4_oneshot_s *oneshot, /* Set up to receive the callback when the interrupt occurs */ - STM32L4_TIM_SETISR(oneshot->tch, stm32l4_oneshot_handler, 0); +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 1 + STM32L4_TIM_SETISR(oneshot->tch, g_callbacks[oneshot->cbndx], 0); +#else + STM32L4_TIM_SETISR(oneshot->tch, stm32l4_oneshot1_handler, 0); +#endif /* Set timer period */ diff --git a/arch/arm/src/stm32l4/stm32l4_oneshot.h b/arch/arm/src/stm32l4/stm32l4_oneshot.h index 86800f6b35..410f0930d7 100644 --- a/arch/arm/src/stm32l4/stm32l4_oneshot.h +++ b/arch/arm/src/stm32l4/stm32l4_oneshot.h @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32l4/stm32l4_oneshot.h * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * dev@ziggurat29.com * @@ -46,10 +46,28 @@ #include #include +#include + #include "stm32l4_tim.h" #ifdef CONFIG_STM32L4_ONESHOT +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(CONFIG_STM32L4_ONESHOT_MAXTIMERS) || \ + CONFIG_STM32L4_ONESHOT_MAXTIMERS < 1 +# undef CONFIG_STM32L4_ONESHOT_MAXTIMERS +# define CONFIG_STM32L4_ONESHOT_MAXTIMERS 1 +#endif + +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 8 +# warning Additional logic required to handle more than 8 timers +# undef CONFIG_STM32L4_ONESHOT_MAXTIMERS +# define CONFIG_STM32L4_ONESHOT_MAXTIMERS 8 +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -71,6 +89,9 @@ typedef void (*oneshot_handler_t)(void *arg); struct stm32l4_oneshot_s { uint8_t chan; /* The timer/counter in use */ +#if CONFIG_STM32L4_ONESHOT_MAXTIMERS > 1 + uint8_t cbndx; /* Timer callback handler index */ +#endif volatile bool running; /* True: the timer is running */ FAR struct stm32l4_tim_dev_s *tch; /* Pointer returned by * stm32l4_tim_init() */