xtensa/esp32s3: Add support for Oneshot timer
Signed-off-by: Gustavo Henrique Nihei <gustavo.nihei@espressif.com>
This commit is contained in:
parent
de95a8550f
commit
add99fead3
@ -388,7 +388,7 @@ config ESP32S3_RWDT
|
||||
|
||||
endmenu # ESP32-S3 Peripheral Selection
|
||||
|
||||
menu "UART configuration"
|
||||
menu "UART Configuration"
|
||||
depends on ESP32S3_UART
|
||||
|
||||
if ESP32S3_UART0
|
||||
@ -469,7 +469,19 @@ config ESP32S3_UART2_CTSPIN
|
||||
|
||||
endif # ESP32S3_UART2
|
||||
|
||||
endmenu # UART configuration
|
||||
endmenu # UART Configuration
|
||||
|
||||
menu "Timer/Counter Configuration"
|
||||
depends on ESP32S3_TIMER
|
||||
|
||||
config ESP32S3_ONESHOT
|
||||
bool "One-shot wrapper"
|
||||
default n
|
||||
---help---
|
||||
Enable a wrapper around the low level timer/counter functions to
|
||||
support one-shot timer.
|
||||
|
||||
endmenu # Timer/Counter Configuration
|
||||
|
||||
menu "Application Image Configuration"
|
||||
|
||||
|
@ -83,3 +83,10 @@ endif
|
||||
ifeq ($(CONFIG_WATCHDOG),y)
|
||||
CHIP_CSRCS += esp32s3_wdt_lowerhalf.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ESP32S3_ONESHOT),y)
|
||||
CHIP_CSRCS += esp32s3_oneshot.c
|
||||
ifeq ($(CONFIG_ONESHOT),y)
|
||||
CHIP_CSRCS += esp32s3_oneshot_lowerhalf.c
|
||||
endif
|
||||
endif
|
||||
|
467
arch/xtensa/src/esp32s3/esp32s3_oneshot.c
Normal file
467
arch/xtensa/src/esp32s3/esp32s3_oneshot.c
Normal file
@ -0,0 +1,467 @@
|
||||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32s3/esp32s3_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 <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
|
||||
#include "esp32s3_clockconfig.h"
|
||||
#include "esp32s3_oneshot.h"
|
||||
#include "esp32s3_tim.h"
|
||||
#include "hardware/esp32s3_soc.h"
|
||||
|
||||
#ifdef CONFIG_ESP32S3_ONESHOT
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define MAX_TIMER_COUNTER (UINT64_C(1) << 53)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int oneshot_handler(int irq, void *context, void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: oneshot_handler
|
||||
*
|
||||
* Description:
|
||||
* Oneshot interrupt handler. When any oneshot timer interrupt
|
||||
* expires, this function will be triggered. It will forward the call to
|
||||
* the next level up.
|
||||
*
|
||||
* Input Parameters:
|
||||
* irq - IRQ associated to that interrupt
|
||||
* context - Interrupt register state save info
|
||||
* arg - A pointer to the argument provided when the interrupt was
|
||||
* registered.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int oneshot_handler(int irq, void *context, void *arg)
|
||||
{
|
||||
int ret = OK;
|
||||
struct esp32s3_oneshot_s *oneshot = (struct esp32s3_oneshot_s *)arg;
|
||||
oneshot_handler_t handler;
|
||||
void *handler_arg;
|
||||
|
||||
DEBUGASSERT(oneshot != NULL);
|
||||
DEBUGASSERT(oneshot->handler != NULL);
|
||||
|
||||
tmrinfo("Oneshot handler triggered\n");
|
||||
|
||||
/* Disable interrupts */
|
||||
|
||||
ESP32S3_TIM_DISABLEINT(oneshot->tim);
|
||||
|
||||
/* Detach handler */
|
||||
|
||||
ret = ESP32S3_TIM_SETISR(oneshot->tim, NULL, NULL);
|
||||
|
||||
/* Clear the Interrupt */
|
||||
|
||||
ESP32S3_TIM_ACKINT(oneshot->tim);
|
||||
|
||||
/* The timer is no longer running */
|
||||
|
||||
oneshot->running = false;
|
||||
|
||||
/* Forward the event, clearing out any vestiges */
|
||||
|
||||
handler = (oneshot_handler_t)oneshot->handler;
|
||||
oneshot->handler = NULL;
|
||||
handler_arg = (void *)oneshot->arg;
|
||||
oneshot->arg = NULL;
|
||||
|
||||
/* Call the callback */
|
||||
|
||||
handler(handler_arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_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 esp32s3_oneshot_initialize(struct esp32s3_oneshot_s *oneshot,
|
||||
int chan, uint16_t resolution)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
tmrinfo("chan=%d resolution=%d usecs\n", chan, resolution);
|
||||
|
||||
DEBUGASSERT(oneshot != NULL);
|
||||
DEBUGASSERT(resolution > 0);
|
||||
|
||||
oneshot->chan = chan;
|
||||
|
||||
oneshot->tim = esp32s3_tim_init(chan);
|
||||
if (oneshot->tim == NULL)
|
||||
{
|
||||
tmrerr("ERROR: Failed to allocate TIM %d\n", chan);
|
||||
ret = -EBUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t pre;
|
||||
|
||||
/* Initialize the remaining fields in the state structure. */
|
||||
|
||||
oneshot->running = false;
|
||||
oneshot->handler = NULL;
|
||||
oneshot->arg = NULL;
|
||||
oneshot->resolution = resolution;
|
||||
|
||||
/* Ensure timer is disabled.
|
||||
* Change the prescaler divider with the timer enabled can lead to
|
||||
* unpredictable results.
|
||||
*/
|
||||
|
||||
ESP32S3_TIM_STOP(oneshot->tim);
|
||||
|
||||
ESP32S3_TIM_CLK_SRC(oneshot->tim, ESP32S3_TIM_APB_CLK);
|
||||
|
||||
/* Calculate the suitable prescaler according to the current APB
|
||||
* frequency to generate a period equals to resolution.
|
||||
*/
|
||||
|
||||
pre = (esp_clk_apb_freq() * resolution) / USEC_PER_SEC;
|
||||
|
||||
/* Configure TIMER prescaler */
|
||||
|
||||
ESP32S3_TIM_SETPRE(oneshot->tim, pre);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_oneshot_max_delay
|
||||
*
|
||||
* Description:
|
||||
* Return the maximum delay supported by the timer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot Caller allocated instance of the oneshot state structure. This
|
||||
* structure must have been previously initialized via a call to
|
||||
* esp32s3_oneshot_initialize();
|
||||
*
|
||||
* Output Parameters:
|
||||
* usec The location in which to return the maximum delay in us.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s3_oneshot_max_delay(struct esp32s3_oneshot_s *oneshot,
|
||||
uint64_t *usec)
|
||||
{
|
||||
DEBUGASSERT(oneshot != NULL);
|
||||
DEBUGASSERT(usec != NULL);
|
||||
|
||||
/* In theory, Maximum delay (us) = resolution (us) * MAX_TIMER_COUNTER
|
||||
* But if the resolution is bigger than 1 us, the value will not fit
|
||||
* in a uint64_t. So, this function assumes the max delay using a
|
||||
* resolution of 1 us.
|
||||
*/
|
||||
|
||||
*usec = MAX_TIMER_COUNTER;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_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
|
||||
* esp32s3_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 esp32s3_oneshot_start(struct esp32s3_oneshot_s *oneshot,
|
||||
oneshot_handler_t handler, void *arg,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
uint64_t timeout_us;
|
||||
int ret = OK;
|
||||
|
||||
tmrinfo("handler=%p arg=%p, ts=(%lu, %lu)\n",
|
||||
handler, arg, (unsigned long)ts->tv_sec,
|
||||
(unsigned long)ts->tv_nsec);
|
||||
|
||||
DEBUGASSERT(oneshot != NULL);
|
||||
DEBUGASSERT(handler != NULL);
|
||||
DEBUGASSERT(ts != NULL);
|
||||
|
||||
if (oneshot->running)
|
||||
{
|
||||
tmrinfo("Oneshot timer already in use. Cancelling it...\n");
|
||||
|
||||
/* If the oneshot timer was already started, cancel it and then
|
||||
* restart.
|
||||
*/
|
||||
|
||||
esp32s3_oneshot_cancel(oneshot, NULL);
|
||||
}
|
||||
|
||||
/* Save the new callback and its argument */
|
||||
|
||||
oneshot->handler = handler;
|
||||
oneshot->arg = arg;
|
||||
|
||||
/* Retrieve the duration from timespec in microsecond */
|
||||
|
||||
timeout_us = (uint64_t)ts->tv_sec * USEC_PER_SEC +
|
||||
(uint64_t)(ts->tv_nsec / NSEC_PER_USEC);
|
||||
|
||||
/* Verify if it is a multiple of the configured resolution.
|
||||
* In case it isn't, warn the user.
|
||||
*/
|
||||
|
||||
if ((timeout_us % oneshot->resolution) != 0)
|
||||
{
|
||||
tmrwarn("Warning: The interval is not multiple of the resolution.\n"
|
||||
"Adjust the resolution in your bringup file.\n");
|
||||
}
|
||||
|
||||
/* Set the timer */
|
||||
|
||||
/* Ensure timer is stopped */
|
||||
|
||||
ESP32S3_TIM_STOP(oneshot->tim);
|
||||
|
||||
/* Configure TIMER mode */
|
||||
|
||||
ESP32S3_TIM_SETMODE(oneshot->tim, ESP32S3_TIM_MODE_UP);
|
||||
|
||||
/* Clear TIMER counter value */
|
||||
|
||||
ESP32S3_TIM_CLEAR(oneshot->tim);
|
||||
|
||||
/* Disable autoreload */
|
||||
|
||||
ESP32S3_TIM_SETARLD(oneshot->tim, false);
|
||||
|
||||
/* Set the timeout */
|
||||
|
||||
ESP32S3_TIM_SETALRVL(oneshot->tim, timeout_us / oneshot->resolution);
|
||||
|
||||
/* Enable TIMER alarm */
|
||||
|
||||
ESP32S3_TIM_SETALRM(oneshot->tim, true);
|
||||
|
||||
/* Clear Interrupt Bits Status */
|
||||
|
||||
ESP32S3_TIM_ACKINT(oneshot->tim);
|
||||
|
||||
/* Set the interrupt */
|
||||
|
||||
/* Register the handler that calls the callback */
|
||||
|
||||
ret = ESP32S3_TIM_SETISR(oneshot->tim, oneshot_handler, oneshot);
|
||||
if (ret == OK)
|
||||
{
|
||||
ESP32S3_TIM_ENABLEINT(oneshot->tim);
|
||||
|
||||
/* Finally, start the TIMER */
|
||||
|
||||
ESP32S3_TIM_START(oneshot->tim);
|
||||
|
||||
oneshot->running = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_oneshot_cancel
|
||||
*
|
||||
* Description:
|
||||
* Cancel the oneshot timer and return the time remaining on the timer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot Caller allocated instance of the oneshot state structure. This
|
||||
* structure must have been previously initialized via a call to
|
||||
* esp32s3_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 esp32s3_oneshot_cancel(struct esp32s3_oneshot_s *oneshot,
|
||||
struct timespec *ts)
|
||||
{
|
||||
int ret = OK;
|
||||
uint64_t current_us;
|
||||
uint64_t remaining_us;
|
||||
uint64_t timeout_us;
|
||||
uint64_t counter_value;
|
||||
uint64_t alarm_value;
|
||||
|
||||
DEBUGASSERT(oneshot != NULL);
|
||||
|
||||
if (!oneshot->running)
|
||||
{
|
||||
tmrinfo("Trying to cancel a non started oneshot timer.\n");
|
||||
ts->tv_sec = 0;
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop timer */
|
||||
|
||||
ESP32S3_TIM_STOP(oneshot->tim);
|
||||
|
||||
/* Disable int */
|
||||
|
||||
ESP32S3_TIM_DISABLEINT(oneshot->tim);
|
||||
|
||||
/* Detach handler */
|
||||
|
||||
ret = ESP32S3_TIM_SETISR(oneshot->tim, NULL, NULL);
|
||||
|
||||
if (ts != NULL)
|
||||
{
|
||||
/* Get the current counter value */
|
||||
|
||||
ESP32S3_TIM_GETCTR(oneshot->tim, &counter_value);
|
||||
|
||||
/* Get the current configured timeout */
|
||||
|
||||
ESP32S3_TIM_GETALRVL(oneshot->tim, &alarm_value);
|
||||
|
||||
current_us = counter_value * oneshot->resolution;
|
||||
timeout_us = alarm_value * oneshot->resolution;
|
||||
|
||||
/* Remaining time (us) = timeout (us) - current (us) */
|
||||
|
||||
remaining_us = timeout_us - current_us;
|
||||
ts->tv_sec = remaining_us / USEC_PER_SEC;
|
||||
remaining_us = remaining_us - ts->tv_sec * USEC_PER_SEC;
|
||||
ts->tv_nsec = remaining_us * NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
oneshot->running = false;
|
||||
oneshot->handler = NULL;
|
||||
oneshot->arg = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_oneshot_current
|
||||
*
|
||||
* Description:
|
||||
* Get the current time.
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot Caller allocated instance of the oneshot state structure. This
|
||||
* structure must have been previously initialized via a call to
|
||||
* esp32s3_oneshot_initialize();
|
||||
*
|
||||
* Output Parameters:
|
||||
* usec The location in which to return the current time in us.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s3_oneshot_current(struct esp32s3_oneshot_s *oneshot,
|
||||
uint64_t *usec)
|
||||
{
|
||||
/* Get the current counter value */
|
||||
|
||||
ESP32S3_TIM_GETCTR(oneshot->tim, usec);
|
||||
|
||||
*usec = *usec * (uint64_t)oneshot->resolution;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ESP32S3_ONESHOT */
|
212
arch/xtensa/src/esp32s3/esp32s3_oneshot.h
Normal file
212
arch/xtensa/src/esp32s3/esp32s3_oneshot.h
Normal file
@ -0,0 +1,212 @@
|
||||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32s3/esp32s3_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_XTENSA_SRC_ESP32S3_ONESHOT_H
|
||||
#define __ARCH_XTENSA_SRC_ESP32S3_ONESHOT_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "esp32s3_tim.h"
|
||||
|
||||
#ifdef CONFIG_ESP32S3_ONESHOT
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* ONESHOT */
|
||||
|
||||
#define ONESHOT_RESOLUTION_US 1
|
||||
|
||||
/****************************************************************************
|
||||
* 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 call
|
||||
* esp32s3_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 esp32s3_oneshot_s
|
||||
{
|
||||
uint8_t chan; /* The timer/counter in use */
|
||||
volatile bool running; /* True: the timer is running */
|
||||
struct esp32s3_tim_dev_s *tim; /* Pointer returned by
|
||||
* esp32s3_tim_init() */
|
||||
volatile oneshot_handler_t handler; /* Oneshot expiration callback */
|
||||
volatile void *arg; /* The argument that will accompany
|
||||
* the callback */
|
||||
uint32_t resolution; /* us */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_oneshot_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the oneshot timer wrapper.
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot 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 esp32s3_oneshot_initialize(struct esp32s3_oneshot_s *oneshot,
|
||||
int chan, uint16_t resolution);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_oneshot_max_delay
|
||||
*
|
||||
* Description:
|
||||
* Determine the maximum delay of the one-shot timer (in microseconds).
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot Allocated instance of the oneshot state structure.
|
||||
*
|
||||
* Output Parameters:
|
||||
* usec The location in which to return the maximum delay in us.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned
|
||||
* on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s3_oneshot_max_delay(struct esp32s3_oneshot_s *oneshot,
|
||||
uint64_t *usec);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_oneshot_start
|
||||
*
|
||||
* Description:
|
||||
* Start the oneshot timer
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot Allocated instance of the oneshot state structure. This
|
||||
* structure must have been previously initialized via a call to
|
||||
* esp32s3_oneshot_initialize();
|
||||
* handler The function to call 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 esp32s3_oneshot_start(struct esp32s3_oneshot_s *oneshot,
|
||||
oneshot_handler_t handler, void *arg,
|
||||
const struct timespec *ts);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_oneshot_cancel
|
||||
*
|
||||
* Description:
|
||||
* Cancel the oneshot timer and return the time remaining on the timer.
|
||||
*
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot Allocated instance of the oneshot state structure. This
|
||||
* structure must have been previously initialized via a call to
|
||||
* esp32s3_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 esp32s3_oneshot_cancel(struct esp32s3_oneshot_s *oneshot,
|
||||
struct timespec *ts);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32s3_oneshot_current
|
||||
*
|
||||
* Description:
|
||||
* Get the current time.
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot Caller allocated instance of the oneshot state structure. This
|
||||
* structure must have been previously initialized via a call to
|
||||
* esp32s3_oneshot_initialize();
|
||||
*
|
||||
* Output Parameters:
|
||||
* usec The location in which to return the current time in us.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int esp32s3_oneshot_current(struct esp32s3_oneshot_s *oneshot,
|
||||
uint64_t *usec);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_ESP32S3_ONESHOT */
|
||||
#endif /* __ARCH_XTENSA_SRC_ESP32S3_ONESHOT_H */
|
370
arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c
Normal file
370
arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c
Normal file
@ -0,0 +1,370 @@
|
||||
/****************************************************************************
|
||||
* arch/xtensa/src/esp32s3/esp32s3_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 <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
|
||||
#include "esp32s3_oneshot.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct esp32s3_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
|
||||
* struct so that pointers to struct oneshot_lowerhalf_s are cast
|
||||
* compatible to struct esp32s3_oneshot_lowerhalf_s and vice versa.
|
||||
*/
|
||||
|
||||
struct oneshot_lowerhalf_s lh; /* Lower-half instance */
|
||||
struct esp32s3_oneshot_s oneshot; /* ESP32-S3-specific oneshot state */
|
||||
oneshot_callback_t callback; /* Upper-half Interrupt callback */
|
||||
void *arg; /* Argument passed to handler */
|
||||
uint16_t resolution;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void oneshot_lh_handler(void *arg);
|
||||
|
||||
/* "Lower-half" driver methods **********************************************/
|
||||
|
||||
static int oneshot_lh_max_delay(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
static int oneshot_lh_start(struct oneshot_lowerhalf_s *lower,
|
||||
oneshot_callback_t callback,
|
||||
void *arg,
|
||||
const struct timespec *ts);
|
||||
static int oneshot_lh_cancel(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
static int oneshot_lh_current(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* "Lower-half" driver methods */
|
||||
|
||||
static const struct oneshot_operations_s g_esp32s3_timer_ops =
|
||||
{
|
||||
.max_delay = oneshot_lh_max_delay,
|
||||
.start = oneshot_lh_start,
|
||||
.cancel = oneshot_lh_cancel,
|
||||
.current = oneshot_lh_current
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: oneshot_lh_handler
|
||||
*
|
||||
* Description:
|
||||
* Timer expiration handler.
|
||||
*
|
||||
* Input Parameters:
|
||||
* arg - Should be the same argument provided when esp32s3_oneshot_start()
|
||||
* was called.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void oneshot_lh_handler(void *arg)
|
||||
{
|
||||
struct esp32s3_oneshot_lowerhalf_s *priv =
|
||||
(struct esp32s3_oneshot_lowerhalf_s *)arg;
|
||||
oneshot_callback_t callback;
|
||||
FAR void *cb_arg;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
DEBUGASSERT(priv->callback != NULL);
|
||||
|
||||
tmrinfo("Oneshot LH handler triggered\n");
|
||||
|
||||
/* Sample and nullify BEFORE executing callback (in case the callback
|
||||
* restarts the oneshot).
|
||||
*/
|
||||
|
||||
callback = priv->callback;
|
||||
cb_arg = priv->arg;
|
||||
priv->callback = NULL;
|
||||
priv->arg = NULL;
|
||||
|
||||
/* Then perform the callback */
|
||||
|
||||
callback(&priv->lh, cb_arg);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: oneshot_lh_max_delay
|
||||
*
|
||||
* Description:
|
||||
* Determine the maximum delay of the oneshot 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 oneshot_lh_max_delay(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
{
|
||||
DEBUGASSERT(ts != NULL);
|
||||
|
||||
/* The real maximum delay surpass the limit that timespec can represent.
|
||||
* Even using the better case: a resolution of 1 us.
|
||||
* Therefore, here, set the timespec with the maximum value it represent.
|
||||
*/
|
||||
|
||||
ts->tv_sec = UINT32_MAX;
|
||||
ts->tv_nsec = NSEC_PER_SEC - 1;
|
||||
|
||||
tmrinfo("max sec=%" PRIu32 "\n", ts->tv_sec);
|
||||
tmrinfo("max nsec=%ld\n", ts->tv_nsec);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: oneshot_lh_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().
|
||||
* callback The function to call when when the oneshot timer expires.
|
||||
* Inside the handler scope.
|
||||
* arg A pointer to the 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 oneshot_lh_start(struct oneshot_lowerhalf_s *lower,
|
||||
oneshot_callback_t callback,
|
||||
void *arg,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct esp32s3_oneshot_lowerhalf_s *priv =
|
||||
(struct esp32s3_oneshot_lowerhalf_s *)lower;
|
||||
int ret;
|
||||
irqstate_t flags;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
DEBUGASSERT(callback != NULL);
|
||||
DEBUGASSERT(ts != NULL);
|
||||
|
||||
/* Save the callback information and start the timer */
|
||||
|
||||
flags = enter_critical_section();
|
||||
priv->callback = callback;
|
||||
priv->arg = arg;
|
||||
ret = esp32s3_oneshot_start(&priv->oneshot, oneshot_lh_handler,
|
||||
priv, ts);
|
||||
leave_critical_section(flags);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
tmrerr("Failed to start oneshot timer: %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: oneshot_lh_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 oneshot_lh_cancel(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
{
|
||||
struct esp32s3_oneshot_lowerhalf_s *priv =
|
||||
(struct esp32s3_oneshot_lowerhalf_s *)lower;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
|
||||
/* Cancel the timer */
|
||||
|
||||
flags = enter_critical_section();
|
||||
ret = esp32s3_oneshot_cancel(&priv->oneshot, ts);
|
||||
priv->callback = NULL;
|
||||
priv->arg = NULL;
|
||||
leave_critical_section(flags);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
tmrerr("Failed to cancel oneshot timer: %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: oneshot_lh_current
|
||||
*
|
||||
* Description:
|
||||
* Get the current time.
|
||||
*
|
||||
* 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 current time. A time of zero
|
||||
* is returned for the initialization moment.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success, a negated errno value is returned on
|
||||
* any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int oneshot_lh_current(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
{
|
||||
struct esp32s3_oneshot_lowerhalf_s *priv =
|
||||
(struct esp32s3_oneshot_lowerhalf_s *)lower;
|
||||
uint64_t current_us;
|
||||
|
||||
DEBUGASSERT(priv != NULL);
|
||||
DEBUGASSERT(ts != NULL);
|
||||
|
||||
esp32s3_oneshot_current(&priv->oneshot, ¤t_us);
|
||||
ts->tv_sec = current_us / USEC_PER_SEC;
|
||||
current_us = current_us - ts->tv_sec * USEC_PER_SEC;
|
||||
ts->tv_nsec = current_us * NSEC_PER_USEC;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct oneshot_lowerhalf_s *oneshot_initialize(int chan, uint16_t resolution)
|
||||
{
|
||||
struct esp32s3_oneshot_lowerhalf_s *priv;
|
||||
int ret;
|
||||
|
||||
/* Allocate an instance of the lower-half driver */
|
||||
|
||||
priv = (struct esp32s3_oneshot_lowerhalf_s *)kmm_zalloc(
|
||||
sizeof(struct esp32s3_oneshot_lowerhalf_s));
|
||||
|
||||
if (priv == NULL)
|
||||
{
|
||||
tmrerr("Failed to allocate oneshot state structure\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
priv->lh.ops = &g_esp32s3_timer_ops; /* Pointer to the LH operations */
|
||||
priv->callback = NULL; /* No callback yet */
|
||||
priv->arg = NULL; /* No arg yet */
|
||||
priv->resolution = resolution; /* Configured resolution */
|
||||
|
||||
/* Initialize esp32s3_oneshot_s structure */
|
||||
|
||||
ret = esp32s3_oneshot_initialize(&priv->oneshot, chan, resolution);
|
||||
if (ret < 0)
|
||||
{
|
||||
tmrerr("Failed to initialize oneshot timer driver: %d\n", ret);
|
||||
kmm_free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &priv->lh;
|
||||
}
|
Loading…
Reference in New Issue
Block a user