arch/arm/src/stm32h7: add support for oneshot timer
The code is ported from arch/arm/src/stm32
This commit is contained in:
parent
1ef0fe36c4
commit
d96565a765
@ -1625,6 +1625,24 @@ config STM32H7_DMACAPABLE
|
|||||||
|
|
||||||
menu "Timer Configuration"
|
menu "Timer Configuration"
|
||||||
|
|
||||||
|
config STM32H7_ONESHOT
|
||||||
|
bool "TIM one-shot wrapper"
|
||||||
|
default n
|
||||||
|
---help---
|
||||||
|
Enable a wrapper around the low level timer/counter functions to
|
||||||
|
support one-shot timer.
|
||||||
|
|
||||||
|
config STM32H7_ONESHOT_MAXTIMERS
|
||||||
|
int "Maximum number of oneshot timers"
|
||||||
|
default 1
|
||||||
|
range 1 8
|
||||||
|
depends on STM32H7_ONESHOT
|
||||||
|
---help---
|
||||||
|
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 STM32H7_PWM_LL_OPS
|
config STM32H7_PWM_LL_OPS
|
||||||
bool "PWM low-level operations"
|
bool "PWM low-level operations"
|
||||||
default n
|
default n
|
||||||
|
@ -117,6 +117,10 @@ ifneq ($(CONFIG_SCHED_TICKLESS),y)
|
|||||||
CHIP_CSRCS += stm32_timerisr.c
|
CHIP_CSRCS += stm32_timerisr.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_STM32H7_ONESHOT),y)
|
||||||
|
CHIP_CSRCS += stm32_oneshot.c stm32_oneshot_lowerhalf.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_BUILD_PROTECTED),y)
|
ifeq ($(CONFIG_BUILD_PROTECTED),y)
|
||||||
CHIP_CSRCS += stm32_userspace.c stm32_mpuinit.c
|
CHIP_CSRCS += stm32_userspace.c stm32_mpuinit.c
|
||||||
endif
|
endif
|
||||||
|
402
arch/arm/src/stm32h7/stm32_oneshot.c
Normal file
402
arch/arm/src/stm32h7/stm32_oneshot.c
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/arm/src/stm32h7/stm32_oneshot.c
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
#include <nuttx/clock.h>
|
||||||
|
|
||||||
|
#include "stm32_oneshot.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_STM32H7_ONESHOT
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int stm32_oneshot_handler(int irg_num, void * context, void *arg);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static struct stm32_oneshot_s *g_oneshot[CONFIG_STM32H7_ONESHOT_MAXTIMERS];
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_handler
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* 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:
|
||||||
|
* oneshot - The state associated with the expired timer
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Always returns OK
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int stm32_oneshot_handler(int irg_num, void * context, void *arg)
|
||||||
|
{
|
||||||
|
struct stm32_oneshot_s * oneshot = (struct stm32_oneshot_s *) arg;
|
||||||
|
oneshot_handler_t oneshot_handler;
|
||||||
|
void *oneshot_arg;
|
||||||
|
|
||||||
|
tmrinfo("Expired (Interrupt)...\n");
|
||||||
|
DEBUGASSERT(oneshot != NULL && oneshot->handler);
|
||||||
|
|
||||||
|
/* The clock was stopped, but not disabled when the RC match occurred.
|
||||||
|
* Disable the TC now and disable any further interrupts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
STM32_TIM_SETISR(oneshot->tch, NULL, NULL, 0);
|
||||||
|
STM32_TIM_DISABLEINT(oneshot->tch, GTIM_DIER_UIE);
|
||||||
|
STM32_TIM_SETMODE(oneshot->tch, STM32_TIM_MODE_DISABLED);
|
||||||
|
STM32_TIM_ACKINT(oneshot->tch, GTIM_SR_UIF);
|
||||||
|
|
||||||
|
/* The timer is no longer running */
|
||||||
|
|
||||||
|
oneshot->running = false;
|
||||||
|
|
||||||
|
/* Forward the event, clearing out any vestiges */
|
||||||
|
|
||||||
|
oneshot_handler = (oneshot_handler_t)oneshot->handler;
|
||||||
|
oneshot->handler = NULL;
|
||||||
|
oneshot_arg = (void *)oneshot->arg;
|
||||||
|
oneshot->arg = NULL;
|
||||||
|
|
||||||
|
oneshot_handler(oneshot_arg);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_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_STM32H7_ONESHOT_MAXTIMERS.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static inline int stm32_allocate_handler(struct stm32_oneshot_s *oneshot)
|
||||||
|
{
|
||||||
|
#if CONFIG_STM32H7_ONESHOT_MAXTIMERS > 1
|
||||||
|
int ret = -EBUSY;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Search for an unused handler */
|
||||||
|
|
||||||
|
sched_lock();
|
||||||
|
for (i = 0; i < CONFIG_STM32H7_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 -EBUSY;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_initialize
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Initialize the oneshot timer wrapper
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* oneshot Caller allocated instance of the oneshot state structure
|
||||||
|
* chan Timer counter channel to be used.
|
||||||
|
* resolution The required resolution of the timer in units of
|
||||||
|
* microseconds. NOTE that the range is restricted to the
|
||||||
|
* range of uint16_t (excluding zero).
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int stm32_oneshot_initialize(struct stm32_oneshot_s *oneshot, int chan,
|
||||||
|
uint16_t resolution)
|
||||||
|
{
|
||||||
|
uint32_t frequency;
|
||||||
|
|
||||||
|
tmrinfo("chan=%d resolution=%d usec, USEC_PER_SEC:%d\n", chan, resolution, USEC_PER_SEC);
|
||||||
|
DEBUGASSERT(oneshot && resolution > 0);
|
||||||
|
|
||||||
|
/* Get the TC frequency the corresponds to the requested resolution */
|
||||||
|
|
||||||
|
frequency = USEC_PER_SEC / (uint32_t)resolution;
|
||||||
|
tmrinfo("frequency: %d\n", frequency);
|
||||||
|
oneshot->frequency = frequency;
|
||||||
|
|
||||||
|
oneshot->tch = stm32_tim_init(chan);
|
||||||
|
if (!oneshot->tch)
|
||||||
|
{
|
||||||
|
tmrerr("ERROR: Failed to allocate TIM%d\n", chan);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
STM32_TIM_SETCLOCK(oneshot->tch, frequency);
|
||||||
|
|
||||||
|
/* Initialize the remaining fields in the state structure. */
|
||||||
|
|
||||||
|
oneshot->chan = chan;
|
||||||
|
oneshot->running = false;
|
||||||
|
oneshot->handler = NULL;
|
||||||
|
oneshot->arg = NULL;
|
||||||
|
|
||||||
|
/* Assign a callback handler to the oneshot */
|
||||||
|
|
||||||
|
return stm32_allocate_handler(oneshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_max_delay
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Determine the maximum delay of the one-shot timer (in microseconds)
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int stm32_oneshot_max_delay(struct stm32_oneshot_s *oneshot, uint64_t *usec)
|
||||||
|
{
|
||||||
|
DEBUGASSERT(oneshot != NULL && usec != NULL);
|
||||||
|
|
||||||
|
tmrinfo("frequency: %d, USEC_PER_SEC: %d\n", oneshot->frequency, USEC_PER_SEC);
|
||||||
|
*usec = (uint64_t)(UINT32_MAX / oneshot->frequency) *
|
||||||
|
(uint64_t)USEC_PER_SEC;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_start
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Start the oneshot timer
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* oneshot Caller allocated instance of the oneshot state structure. This
|
||||||
|
* structure must have been previously initialized via a call to
|
||||||
|
* stm32_oneshot_initialize();
|
||||||
|
* handler The function to call when when the oneshot timer expires.
|
||||||
|
* arg An opaque argument that will accompany the callback.
|
||||||
|
* ts Provides the duration of the one shot timer.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int stm32_oneshot_start(struct stm32_oneshot_s *oneshot,
|
||||||
|
oneshot_handler_t handler, void *arg,
|
||||||
|
const struct timespec *ts)
|
||||||
|
{
|
||||||
|
uint64_t usec;
|
||||||
|
uint64_t period;
|
||||||
|
irqstate_t flags;
|
||||||
|
|
||||||
|
tmrinfo("handler=%p arg=%p, ts=(%lu, %lu)\n",
|
||||||
|
handler, arg, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
|
||||||
|
DEBUGASSERT(oneshot && handler && ts);
|
||||||
|
DEBUGASSERT(oneshot->tch);
|
||||||
|
|
||||||
|
/* Was the oneshot already running? */
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
if (oneshot->running)
|
||||||
|
{
|
||||||
|
/* Yes.. then cancel it */
|
||||||
|
|
||||||
|
tmrinfo("Already running... cancelling\n");
|
||||||
|
stm32_oneshot_cancel(oneshot, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the new handler and its argument */
|
||||||
|
|
||||||
|
oneshot->handler = handler;
|
||||||
|
oneshot->arg = arg;
|
||||||
|
|
||||||
|
/* Express the delay in microseconds */
|
||||||
|
|
||||||
|
usec = (uint64_t)ts->tv_sec * USEC_PER_SEC +
|
||||||
|
(uint64_t)(ts->tv_nsec / NSEC_PER_USEC);
|
||||||
|
|
||||||
|
/* Get the timer counter frequency and determine the number of counts need
|
||||||
|
* to achieve the requested delay.
|
||||||
|
*
|
||||||
|
* frequency = ticks / second
|
||||||
|
* ticks = seconds * frequency
|
||||||
|
* = (usecs * frequency) / USEC_PER_SEC;
|
||||||
|
*/
|
||||||
|
|
||||||
|
period = (usec * (uint64_t)oneshot->frequency) / USEC_PER_SEC;
|
||||||
|
|
||||||
|
tmrinfo("usec=%llu period=%08llx\n", usec, period);
|
||||||
|
DEBUGASSERT(period <= UINT32_MAX);
|
||||||
|
|
||||||
|
/* Set up to receive the callback when the interrupt occurs */
|
||||||
|
|
||||||
|
STM32_TIM_SETISR(oneshot->tch, stm32_oneshot_handler, oneshot, 0);
|
||||||
|
|
||||||
|
/* Set timer period */
|
||||||
|
|
||||||
|
oneshot->period = (uint32_t)period;
|
||||||
|
STM32_TIM_SETPERIOD(oneshot->tch, (uint32_t)period);
|
||||||
|
|
||||||
|
/* Start the counter */
|
||||||
|
|
||||||
|
STM32_TIM_SETMODE(oneshot->tch, STM32_TIM_MODE_PULSE);
|
||||||
|
|
||||||
|
STM32_TIM_ACKINT(oneshot->tch, GTIM_SR_UIF);
|
||||||
|
STM32_TIM_ENABLEINT(oneshot->tch, GTIM_DIER_UIE);
|
||||||
|
|
||||||
|
/* Enable interrupts. We should get the callback when the interrupt
|
||||||
|
* occurs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
oneshot->running = true;
|
||||||
|
leave_critical_section(flags);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_cancel
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Cancel the oneshot timer and return the time remaining on the timer.
|
||||||
|
*
|
||||||
|
* NOTE: This function may execute at a high rate with no timer running (as
|
||||||
|
* when pre-emption is enabled and disabled).
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* oneshot Caller allocated instance of the oneshot state structure. This
|
||||||
|
* structure must have been previously initialized via a call to
|
||||||
|
* stm32_oneshot_initialize();
|
||||||
|
* ts The location in which to return the time remaining on the
|
||||||
|
* oneshot timer. A time of zero is returned if the timer is
|
||||||
|
* not running. ts may be zero in which case the time remaining
|
||||||
|
* is not returned.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success. A call to up_timer_cancel() when
|
||||||
|
* the timer is not active should also return success; a negated errno
|
||||||
|
* value is returned on any failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int stm32_oneshot_cancel(struct stm32_oneshot_s *oneshot,
|
||||||
|
struct timespec *ts)
|
||||||
|
{
|
||||||
|
irqstate_t flags;
|
||||||
|
|
||||||
|
/* Was the timer running? */
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
if (!oneshot->running)
|
||||||
|
{
|
||||||
|
/* No.. Just return zero timer remaining and successful cancellation.
|
||||||
|
* This function may execute at a high rate with no timer running
|
||||||
|
* (as when pre-emption is enabled and disabled).
|
||||||
|
*/
|
||||||
|
|
||||||
|
ts->tv_sec = 0;
|
||||||
|
ts->tv_nsec = 0;
|
||||||
|
leave_critical_section(flags);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmrinfo("Cancelling...\n");
|
||||||
|
|
||||||
|
/* Now we can disable the interrupt and stop the timer. */
|
||||||
|
|
||||||
|
STM32_TIM_DISABLEINT(oneshot->tch, GTIM_DIER_UIE);
|
||||||
|
STM32_TIM_SETISR(oneshot->tch, NULL, NULL, 0);
|
||||||
|
STM32_TIM_SETMODE(oneshot->tch, STM32_TIM_MODE_DISABLED);
|
||||||
|
|
||||||
|
oneshot->running = false;
|
||||||
|
oneshot->handler = NULL;
|
||||||
|
oneshot->arg = NULL;
|
||||||
|
leave_critical_section(flags);
|
||||||
|
|
||||||
|
/* Did the caller provide us with a location to return the time
|
||||||
|
* remaining?
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ts)
|
||||||
|
{
|
||||||
|
/* Not implemented */
|
||||||
|
|
||||||
|
ts->tv_sec = 0;
|
||||||
|
ts->tv_nsec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_STM32H7_ONESHOT */
|
195
arch/arm/src/stm32h7/stm32_oneshot.h
Normal file
195
arch/arm/src/stm32h7/stm32_oneshot.h
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/arm/src/stm32h7/stm32_oneshot.h
|
||||||
|
*
|
||||||
|
* 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_STM32_ONESHOT_H
|
||||||
|
#define __ARCH_ARM_SRC_STM32_ONESHOT_H
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
|
||||||
|
#include "stm32_tim.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_STM32H7_ONESHOT
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#if !defined(CONFIG_STM32H7_ONESHOT_MAXTIMERS) || \
|
||||||
|
CONFIG_STM32H7_ONESHOT_MAXTIMERS < 1
|
||||||
|
# undef CONFIG_STM32H7_ONESHOT_MAXTIMERS
|
||||||
|
# define CONFIG_STM32H7_ONESHOT_MAXTIMERS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_STM32H7_ONESHOT_MAXTIMERS > 8
|
||||||
|
# warning Additional logic required to handle more than 8 timers
|
||||||
|
# undef CONFIG_STM32H7_ONESHOT_MAXTIMERS
|
||||||
|
# define CONFIG_STM32H7_ONESHOT_MAXTIMERS 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* This describes the callback function that will be invoked when the oneshot
|
||||||
|
* timer expires. The oneshot fires, the client will receive:
|
||||||
|
*
|
||||||
|
* arg - The opaque argument provided when the interrupt was registered
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef void (*oneshot_handler_t)(void *arg);
|
||||||
|
|
||||||
|
/* The oneshot client must allocate an instance of this structure and called
|
||||||
|
* stm32_oneshot_initialize() before using the oneshot facilities. The client
|
||||||
|
* should not access the contents of this structure directly since the
|
||||||
|
* contents are subject to change.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct stm32_oneshot_s
|
||||||
|
{
|
||||||
|
uint8_t chan; /* The timer/counter in use */
|
||||||
|
#if CONFIG_STM32H7_ONESHOT_MAXTIMERS > 1
|
||||||
|
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
|
||||||
|
* stm32_tim_init() */
|
||||||
|
volatile oneshot_handler_t handler; /* Oneshot expiration callback */
|
||||||
|
volatile void *arg; /* The argument that will accompany
|
||||||
|
* the callback */
|
||||||
|
uint32_t frequency;
|
||||||
|
uint32_t period;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#undef EXTERN
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#define EXTERN extern "C"
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#else
|
||||||
|
#define EXTERN extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_initialize
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Initialize the oneshot timer wrapper
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* oneshot Caller allocated instance of the oneshot state structure
|
||||||
|
* chan Timer counter channel to be used.
|
||||||
|
* resolution The required resolution of the timer in units of
|
||||||
|
* microseconds. NOTE that the range is restricted to the
|
||||||
|
* range of uint16_t (excluding zero).
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int stm32_oneshot_initialize(struct stm32_oneshot_s *oneshot, int chan,
|
||||||
|
uint16_t resolution);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_max_delay
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Determine the maximum delay of the one-shot timer (in microseconds)
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int stm32_oneshot_max_delay(struct stm32_oneshot_s *oneshot, uint64_t *usec);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_start
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Start the oneshot timer
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* oneshot Caller allocated instance of the oneshot state structure. This
|
||||||
|
* structure must have been previously initialized via a call to
|
||||||
|
* stm32_oneshot_initialize();
|
||||||
|
* handler The function to call when when the oneshot timer expires.
|
||||||
|
* arg An opaque argument that will accompany the callback.
|
||||||
|
* ts Provides the duration of the one shot timer.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int stm32_oneshot_start(struct stm32_oneshot_s *oneshot,
|
||||||
|
oneshot_handler_t handler, void *arg,
|
||||||
|
const struct timespec *ts);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_cancel
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Cancel the oneshot timer and return the time remaining on the timer.
|
||||||
|
*
|
||||||
|
* NOTE: This function may execute at a high rate with no timer running (as
|
||||||
|
* when pre-emption is enabled and disabled).
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* oneshot Caller allocated instance of the oneshot state structure. This
|
||||||
|
* structure must have been previously initialized via a call to
|
||||||
|
* stm32_oneshot_initialize();
|
||||||
|
* ts The location in which to return the time remaining on the
|
||||||
|
* oneshot timer. A time of zero is returned if the timer is
|
||||||
|
* not running.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success. A call to up_timer_cancel() when
|
||||||
|
* the timer is not active should also return success; a negated errno
|
||||||
|
* value is returned on any failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int stm32_oneshot_cancel(struct stm32_oneshot_s *oneshot,
|
||||||
|
struct timespec *ts);
|
||||||
|
|
||||||
|
#undef EXTERN
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CONFIG_STM32H7_ONESHOT */
|
||||||
|
#endif /* __ARCH_ARM_SRC_STM32_ONESHOT_H */
|
330
arch/arm/src/stm32h7/stm32_oneshot_lowerhalf.c
Normal file
330
arch/arm/src/stm32h7/stm32_oneshot_lowerhalf.c
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/arm/src/stm32h7/stm32_oneshot_lowerhalf.c
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
#include <nuttx/kmalloc.h>
|
||||||
|
#include <nuttx/timers/oneshot.h>
|
||||||
|
|
||||||
|
#include "stm32_oneshot.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* This structure describes the state of the oneshot timer lower-half driver */
|
||||||
|
|
||||||
|
struct stm32_oneshot_lowerhalf_s
|
||||||
|
{
|
||||||
|
/* This is the part of the lower half driver that is visible to the upper-
|
||||||
|
* half client of the driver. This must be the first thing in this
|
||||||
|
* structure so that pointers to struct oneshot_lowerhalf_s are cast
|
||||||
|
* compatible to struct stm32_oneshot_lowerhalf_s and vice versa.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct oneshot_lowerhalf_s lh; /* Common lower-half driver fields */
|
||||||
|
|
||||||
|
/* Private lower half data follows */
|
||||||
|
|
||||||
|
struct stm32_oneshot_s oneshot; /* STM32-specific oneshot state */
|
||||||
|
oneshot_callback_t callback; /* Internal handler that receives callback */
|
||||||
|
FAR void *arg; /* Argument that is passed to the handler */
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void stm32_oneshot_handler(void *arg);
|
||||||
|
|
||||||
|
static int stm32_max_delay(FAR struct oneshot_lowerhalf_s *lower,
|
||||||
|
FAR struct timespec *ts);
|
||||||
|
static int stm32_start(FAR struct oneshot_lowerhalf_s *lower,
|
||||||
|
oneshot_callback_t callback, FAR void *arg,
|
||||||
|
FAR const struct timespec *ts);
|
||||||
|
static int stm32_cancel(FAR struct oneshot_lowerhalf_s *lower,
|
||||||
|
FAR struct timespec *ts);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Lower half operations */
|
||||||
|
|
||||||
|
static const struct oneshot_operations_s g_oneshot_ops =
|
||||||
|
{
|
||||||
|
.max_delay = stm32_max_delay,
|
||||||
|
.start = stm32_start,
|
||||||
|
.cancel = stm32_cancel,
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_oneshot_handler
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Timer expiration handler
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* arg - Should be the same argument provided when stm32_oneshot_start()
|
||||||
|
* was called.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void stm32_oneshot_handler(void *arg)
|
||||||
|
{
|
||||||
|
FAR struct stm32_oneshot_lowerhalf_s *priv =
|
||||||
|
(FAR struct stm32_oneshot_lowerhalf_s *)arg;
|
||||||
|
oneshot_callback_t callback;
|
||||||
|
FAR void *cbarg;
|
||||||
|
|
||||||
|
DEBUGASSERT(priv != NULL);
|
||||||
|
|
||||||
|
/* Perhaps the callback was nullified in a race condition with
|
||||||
|
* stm32_cancel?
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (priv->callback)
|
||||||
|
{
|
||||||
|
/* Sample and nullify BEFORE executing callback (in case the callback
|
||||||
|
* restarts the oneshot).
|
||||||
|
*/
|
||||||
|
|
||||||
|
callback = priv->callback;
|
||||||
|
cbarg = priv->arg;
|
||||||
|
priv->callback = NULL;
|
||||||
|
priv->arg = NULL;
|
||||||
|
|
||||||
|
/* Then perform the callback */
|
||||||
|
|
||||||
|
callback(&priv->lh, cbarg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_max_delay
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Determine the maximum delay of the one-shot timer (in microseconds)
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* lower An instance of the lower-half oneshot state structure. This
|
||||||
|
* structure must have been previously initialized via a call to
|
||||||
|
* oneshot_initialize();
|
||||||
|
* ts The location in which to return the maximum delay.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int stm32_max_delay(FAR struct oneshot_lowerhalf_s *lower,
|
||||||
|
FAR struct timespec *ts)
|
||||||
|
{
|
||||||
|
FAR struct stm32_oneshot_lowerhalf_s *priv =
|
||||||
|
(FAR struct stm32_oneshot_lowerhalf_s *)lower;
|
||||||
|
uint64_t usecs;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DEBUGASSERT(priv != NULL && ts != NULL);
|
||||||
|
ret = stm32_oneshot_max_delay(&priv->oneshot, &usecs);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
uint64_t sec = usecs / 1000000;
|
||||||
|
usecs -= 1000000 * sec;
|
||||||
|
|
||||||
|
ts->tv_sec = (time_t)sec;
|
||||||
|
ts->tv_nsec = (long)(usecs * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_start
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Start the oneshot timer
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* lower An instance of the lower-half oneshot state structure. This
|
||||||
|
* structure must have been previously initialized via a call to
|
||||||
|
* oneshot_initialize();
|
||||||
|
* handler The function to call when when the oneshot timer expires.
|
||||||
|
* arg An opaque argument that will accompany the callback.
|
||||||
|
* ts Provides the duration of the one shot timer.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success; a negated errno value is returned
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int stm32_start(FAR struct oneshot_lowerhalf_s *lower,
|
||||||
|
oneshot_callback_t callback, FAR void *arg,
|
||||||
|
FAR const struct timespec *ts)
|
||||||
|
{
|
||||||
|
FAR struct stm32_oneshot_lowerhalf_s *priv =
|
||||||
|
(FAR struct stm32_oneshot_lowerhalf_s *)lower;
|
||||||
|
irqstate_t flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DEBUGASSERT(priv != NULL && callback != NULL && ts != NULL);
|
||||||
|
|
||||||
|
/* Save the callback information and start the timer */
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
priv->callback = callback;
|
||||||
|
priv->arg = arg;
|
||||||
|
ret = stm32_oneshot_start(&priv->oneshot,
|
||||||
|
stm32_oneshot_handler, priv, ts);
|
||||||
|
leave_critical_section(flags);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
tmrerr("ERROR: stm32_oneshot_start failed: %d\n", flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_cancel
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Cancel the oneshot timer and return the time remaining on the timer.
|
||||||
|
*
|
||||||
|
* NOTE: This function may execute at a high rate with no timer running (as
|
||||||
|
* when pre-emption is enabled and disabled).
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* lower Caller allocated instance of the oneshot state structure. This
|
||||||
|
* structure must have been previously initialized via a call to
|
||||||
|
* oneshot_initialize();
|
||||||
|
* ts The location in which to return the time remaining on the
|
||||||
|
* oneshot timer. A time of zero is returned if the timer is
|
||||||
|
* not running.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero (OK) is returned on success. A call to up_timer_cancel() when
|
||||||
|
* the timer is not active should also return success; a negated errno
|
||||||
|
* value is returned on any failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int stm32_cancel(FAR struct oneshot_lowerhalf_s *lower,
|
||||||
|
FAR struct timespec *ts)
|
||||||
|
{
|
||||||
|
FAR struct stm32_oneshot_lowerhalf_s *priv =
|
||||||
|
(FAR struct stm32_oneshot_lowerhalf_s *)lower;
|
||||||
|
irqstate_t flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DEBUGASSERT(priv != NULL);
|
||||||
|
|
||||||
|
/* Cancel the timer */
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
ret = stm32_oneshot_cancel(&priv->oneshot, ts);
|
||||||
|
priv->callback = NULL;
|
||||||
|
priv->arg = NULL;
|
||||||
|
leave_critical_section(flags);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
tmrerr("ERROR: stm32_oneshot_cancel failed: %d\n", flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: oneshot_initialize
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Initialize the oneshot timer and return a oneshot lower half driver
|
||||||
|
* instance.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* chan Timer counter channel to be used.
|
||||||
|
* resolution The required resolution of the timer in units of
|
||||||
|
* microseconds. NOTE that the range is restricted to the
|
||||||
|
* range of uint16_t (excluding zero).
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* On success, a non-NULL instance of the oneshot lower-half driver is
|
||||||
|
* returned. NULL is return on any failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
FAR struct oneshot_lowerhalf_s *oneshot_initialize(int chan,
|
||||||
|
uint16_t resolution)
|
||||||
|
{
|
||||||
|
FAR struct stm32_oneshot_lowerhalf_s *priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Allocate an instance of the lower half driver */
|
||||||
|
|
||||||
|
priv = (FAR struct stm32_oneshot_lowerhalf_s *)
|
||||||
|
kmm_zalloc(sizeof(struct stm32_oneshot_lowerhalf_s));
|
||||||
|
|
||||||
|
if (priv == NULL)
|
||||||
|
{
|
||||||
|
tmrerr("ERROR: Failed to initialized state structure\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the lower-half driver structure */
|
||||||
|
|
||||||
|
priv->lh.ops = &g_oneshot_ops;
|
||||||
|
|
||||||
|
/* Initialize the contained STM32 oneshot timer */
|
||||||
|
|
||||||
|
ret = stm32_oneshot_initialize(&priv->oneshot, chan, resolution);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
tmrerr("ERROR: stm32_oneshot_initialize failed: %d\n", ret);
|
||||||
|
kmm_free(priv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &priv->lh;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user