diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig index b1c9ec3ee50..bb9660c4019 100644 --- a/arch/risc-v/src/esp32c3/Kconfig +++ b/arch/risc-v/src/esp32c3/Kconfig @@ -341,6 +341,19 @@ config ESP32C3_RT_TIMER_TASK_STACK_SIZE endmenu # Real-Time Timer +if ESP32C3_TIMER +menu "Timer/counter Configuration" + +config ESP32C3_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 +endif # ESP32C3_TIMER + menu "Wi-Fi configuration" depends on ESP32C3_WIRELESS diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs index 25320983515..76c01ae9491 100644 --- a/arch/risc-v/src/esp32c3/Make.defs +++ b/arch/risc-v/src/esp32c3/Make.defs @@ -85,6 +85,13 @@ CHIP_CSRCS += esp32c3_tim_lowerhalf.c endif endif +ifeq ($(CONFIG_ESP32C3_ONESHOT),y) +CHIP_CSRCS += esp32c3_oneshot.c +ifeq ($(CONFIG_ONESHOT),y) +CHIP_CSRCS += esp32c3_oneshot_lowerhalf.c +endif +endif + ifeq ($(CONFIG_ESP32C3_RT_TIMER),y) CHIP_CSRCS += esp32c3_rt_timer.c endif diff --git a/arch/risc-v/src/esp32c3/esp32c3_oneshot.c b/arch/risc-v/src/esp32c3/esp32c3_oneshot.c new file mode 100644 index 00000000000..adcf7956a89 --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_oneshot.c @@ -0,0 +1,456 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_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 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "hardware/esp32c3_soc.h" + +#include "esp32c3_tim.h" +#include "esp32c3_clockconfig.h" +#include "esp32c3_oneshot.h" + +#ifdef CONFIG_ESP32C3_ONESHOT + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MAX_TIMER_COUNTER() ((uint64_t)1 << 53) /* 2^53 */ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int esp32c3_oneshot_handler(int irq, void * context, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_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 + * 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 esp32c3_oneshot_handler(int irq, void * context, void *arg) +{ + int ret = OK; + struct esp32c3_oneshot_s *oneshot = (struct esp32c3_oneshot_s *)arg; + + DEBUGASSERT(oneshot != NULL && oneshot->handler != NULL); + + tmrinfo("Oneshot handler triggered\n"); + + /* Stop timer + * Note: It's not necessary to disable the alarm because + * it automatically disables each time it expires. + */ + + ESP32C3_TIM_STOP(oneshot->tim); + + /* Disable interrupts */ + + ESP32C3_TIM_DISABLEINT(oneshot->tim); + + /* Detach handler */ + + ret = ESP32C3_TIM_SETISR(oneshot->tim, NULL, NULL); + + /* Call the callback */ + + oneshot->handler((void *)oneshot->arg); + + /* Restore state */ + + oneshot->running = false; + oneshot->handler = NULL; + oneshot->arg = NULL; + + /* Clear the Interrupt */ + + ESP32C3_TIM_ACKINT(oneshot->tim); + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_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 esp32c3_oneshot_initialize(struct esp32c3_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 = esp32c3_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. + */ + + ESP32C3_TIM_STOP(oneshot->tim); + + /* Calculate the suitable prescaler according to the current apb + * frequency to generate a period equals to resolution. + */ + + pre = (esp32c3_clk_apb_freq() * resolution) / USEC_PER_SEC; + + /* Configure TIMER prescaler */ + + ESP32C3_TIM_SETPRE(oneshot->tim, pre); + } + + return ret; +} + +/**************************************************************************** + * Name: esp32c3_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 + * esp32c3_oneshot_initialize(); + * usec The maximum delay in us. + * + * Returned Value: + * Zero (OK). + * + ****************************************************************************/ + +int esp32c3_oneshot_max_delay(struct esp32c3_oneshot_s *oneshot, + uint64_t *usec) +{ + DEBUGASSERT(oneshot != NULL && 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: esp32c3_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 + * esp32c3_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 esp32c3_oneshot_start(struct esp32c3_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("One shot timer already in use. Cancelling it ...\n"); + + /* If the oneshot timer was already started, cancel it and then + * restart. + */ + + esp32c3_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 */ + + ESP32C3_TIM_STOP(oneshot->tim); + + /* Configure TIMER mode */ + + ESP32C3_TIM_SETMODE(oneshot->tim, ESP32C3_TIM_MODE_UP); + + /* Clear TIMER counter value */ + + ESP32C3_TIM_CLEAR(oneshot->tim); + + /* Disable autoreload */ + + ESP32C3_TIM_SETARLD(oneshot->tim, false); + + /* Set the timeout */ + + ESP32C3_TIM_SETALRVL(oneshot->tim, timeout_us / oneshot->resolution); + + /* Enable TIMER alarm */ + + ESP32C3_TIM_SETALRM(oneshot->tim, true); + + /* Clear Interrupt Bits Status */ + + ESP32C3_TIM_ACKINT(oneshot->tim); + + /* Set the interrupt */ + + /* Register the handler that calls the callback */ + + ret = ESP32C3_TIM_SETISR(oneshot->tim, esp32c3_oneshot_handler, oneshot); + if (ret == OK) + { + ESP32C3_TIM_ENABLEINT(oneshot->tim); + + /* Finally, start the TIMER */ + + ESP32C3_TIM_START(oneshot->tim); + + oneshot->running = true; + } + + return ret; +} + +/**************************************************************************** + * Name: esp32c3_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 + * esp32c3_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 esp32c3_oneshot_cancel(struct esp32c3_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); + + if (oneshot->running == false) + { + tmrinfo("Trying to cancel a non started oneshot timer.\n"); + ts->tv_sec = 0; + ts->tv_nsec = 0; + } + else + { + /* Stop timer */ + + ESP32C3_TIM_STOP(oneshot->tim); + + /* Disable int */ + + ESP32C3_TIM_DISABLEINT(oneshot->tim); + + /* Detach handler */ + + ret = ESP32C3_TIM_SETISR(oneshot->tim, NULL, NULL); + + if (ts != NULL) + { + /* Get the current counter value */ + + ESP32C3_TIM_GETCTR(oneshot->tim, &counter_value); + + /* Get the current configured timeout */ + + ESP32C3_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: esp32c3_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 + * esp32c3_oneshot_initialize(); + * usec The maximum delay in us. + * + * Returned Value: + * Zero (OK). + * + ****************************************************************************/ + +int esp32c3_oneshot_current(struct esp32c3_oneshot_s *oneshot, + uint64_t *usec) +{ + /* Get the current counter value */ + + ESP32C3_TIM_GETCTR(oneshot->tim, usec); + + *usec = *usec * (uint64_t)oneshot->resolution; + + return OK; +} + +#endif /* CONFIG_ESP32C3_ONESHOT */ diff --git a/arch/risc-v/src/esp32c3/esp32c3_oneshot.h b/arch/risc-v/src/esp32c3/esp32c3_oneshot.h new file mode 100644 index 00000000000..169d5a95f56 --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_oneshot.h @@ -0,0 +1,204 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_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_RISCV_SRC_ESP32C3_ONESHOT_H +#define __ARCH_RISCV_SRC_ESP32C3_ONESHOT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "esp32c3_tim.h" + +#ifdef CONFIG_ESP32C3_ONESHOT + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * 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 + * esp32c3_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 esp32c3_oneshot_s +{ + uint8_t chan; /* The timer/counter in use */ + volatile bool running; /* True: the timer is running */ + FAR struct esp32c3_tim_dev_s *tim; /* Pointer returned by + * esp32c3_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: esp32c3_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 esp32c3_oneshot_initialize(struct esp32c3_oneshot_s *oneshot, int chan, + uint16_t resolution); + +/**************************************************************************** + * Name: esp32c3_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. + * chan 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 esp32c3_oneshot_max_delay(struct esp32c3_oneshot_s *oneshot, + uint64_t *usec); + +/**************************************************************************** + * Name: esp32c3_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 + * esp32c3_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 esp32c3_oneshot_start(struct esp32c3_oneshot_s *oneshot, + oneshot_handler_t handler, void *arg, + const struct timespec *ts); + +/**************************************************************************** + * Name: esp32c3_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 + * esp32c3_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 esp32c3_oneshot_cancel(struct esp32c3_oneshot_s *oneshot, + struct timespec *ts); + +/**************************************************************************** + * Name: esp32c3_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 + * esp32c3_oneshot_initialize(); + * usec The maximum delay in us. + * + * Returned Value: + * Zero (OK). + * + ****************************************************************************/ + +int esp32c3_oneshot_current(struct esp32c3_oneshot_s *oneshot, + uint64_t *usec); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_ESP32C3_ONESHOT */ +#endif /* __ARCH_RISCV_SRC_ESP32C3_ONESHOT_H */ diff --git a/arch/risc-v/src/esp32c3/esp32c3_oneshot_lowerhalf.c b/arch/risc-v/src/esp32c3/esp32c3_oneshot_lowerhalf.c new file mode 100644 index 00000000000..d2c98fe7643 --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_oneshot_lowerhalf.c @@ -0,0 +1,369 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "esp32c3_oneshot.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct esp32c3_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 esp32c3_oneshot_lowerhalf_s and vice versa. + */ + + struct oneshot_lowerhalf_s lh; /* Lower half instance */ + struct esp32c3_oneshot_s oneshot; /* ESP32C3-specific oneshot state */ + oneshot_callback_t callback; /* Upper half Interrupt callback */ + FAR void *arg; /* Argument passed to handler */ + uint16_t resolution; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void esp32c3_oneshot_lh_handler(void *arg); + +/* "Lower half" driver methods **********************************************/ + +static int oneshot_lh_max_delay(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts); +static int oneshot_lh_start(FAR struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, + FAR void *arg, + FAR const struct timespec *ts); +static int oneshot_lh_cancel(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts); +static int oneshot_lh_current(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* "Lower half" driver methods */ + +static const struct oneshot_operations_s g_esp32c3_timer_ops = +{ + .max_delay = oneshot_lh_max_delay, + .start = oneshot_lh_start, + .cancel = oneshot_lh_cancel, + .current = oneshot_lh_current +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_oneshot_lh_handler + * + * Description: + * Timer expiration handler. + * + * Input Parameters: + * arg - Should be the same argument provided when esp32c3_oneshot_start() + * was called. + * + ****************************************************************************/ + +static void esp32c3_oneshot_lh_handler(void *arg) +{ + FAR struct esp32c3_oneshot_lowerhalf_s *priv = + (FAR struct esp32c3_oneshot_lowerhalf_s *)arg; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv->callback != NULL); + + tmrinfo("Oneshot LH handler triggered\n"); + + /* Call the callback */ + + priv->callback(&priv->lh, priv->arg); + + /* Restore state */ + + priv->callback = NULL; + priv->arg = NULL; +} + +/**************************************************************************** + * Name: oneshot_lh_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 oneshot_lh_max_delay(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts) +{ + DEBUGASSERT(ts != NULL); + + /* The real maximum delay surpass the limit that timespec can + * reprent. Even using the better case: a resolution of + * 1 us. + * Therefore, here, fulfill the timespec with the + * maximum value it can 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(FAR struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, + FAR void *arg, + FAR const struct timespec *ts) +{ + FAR struct esp32c3_oneshot_lowerhalf_s *priv = + (FAR struct esp32c3_oneshot_lowerhalf_s *)lower; + int ret; + irqstate_t flags; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(callback != NULL); + DEBUGASSERT(arg != NULL); + DEBUGASSERT(ts != NULL); + + /* Save the callback information and start the timer */ + + flags = enter_critical_section(); + priv->callback = callback; + priv->arg = arg; + ret = esp32c3_oneshot_start(&priv->oneshot, + esp32c3_oneshot_lh_handler, + priv, + ts); + leave_critical_section(flags); + + if (ret < 0) + { + tmrerr("ERROR: esp32c3_oneshot_start failed: %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(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts) +{ + FAR struct esp32c3_oneshot_lowerhalf_s *priv = + (FAR struct esp32c3_oneshot_lowerhalf_s *)lower; + irqstate_t flags; + int ret; + + DEBUGASSERT(priv != NULL); + + /* Cancel the timer */ + + flags = enter_critical_section(); + ret = esp32c3_oneshot_cancel(&priv->oneshot, ts); + priv->callback = NULL; + priv->arg = NULL; + leave_critical_section(flags); + + if (ret < 0) + { + tmrerr("ERROR: esp32c3_oneshot_cancel failed: %d\n", flags); + } + + 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(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts) +{ + FAR struct esp32c3_oneshot_lowerhalf_s *priv = + (FAR struct esp32c3_oneshot_lowerhalf_s *)lower; + uint64_t current_us; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(ts != NULL); + + esp32c3_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. + * + ****************************************************************************/ + +FAR struct oneshot_lowerhalf_s *oneshot_initialize(int chan, + uint16_t resolution) +{ + FAR struct esp32c3_oneshot_lowerhalf_s *priv; + int ret; + + /* Allocate an instance of the lower half driver */ + + priv = (FAR struct esp32c3_oneshot_lowerhalf_s *)kmm_zalloc( + sizeof(struct esp32c3_oneshot_lowerhalf_s)); + + if (priv == NULL) + { + tmrerr("ERROR: Failed to initialize oneshot state structure\n"); + return NULL; + } + + priv->lh.ops = &g_esp32c3_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 esp32c3_oneshot_s structure */ + + ret = esp32c3_oneshot_initialize(&priv->oneshot, chan, resolution); + if (ret < 0) + { + tmrerr("ERROR: esp32c3_oneshot_initialize failed: %d\n", ret); + kmm_free(priv); + return NULL; + } + + return &priv->lh; +} diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/configs/oneshot/defconfig b/boards/risc-v/esp32c3/esp32c3-devkit/configs/oneshot/defconfig new file mode 100644 index 00000000000..f8a0d84d421 --- /dev/null +++ b/boards/risc-v/esp32c3/esp32c3-devkit/configs/oneshot/defconfig @@ -0,0 +1,52 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +# CONFIG_NSH_CMDPARMS is not set +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="esp32c3-devkit" +CONFIG_ARCH_BOARD_ESP32C3_DEVKIT=y +CONFIG_ARCH_CHIP="esp32c3" +CONFIG_ARCH_CHIP_ESP32C3=y +CONFIG_ARCH_CHIP_ESP32C3WROOM02=y +CONFIG_ARCH_INTERRUPTSTACK=1536 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=15000 +CONFIG_BUILTIN=y +CONFIG_DEV_ZERO=y +CONFIG_ESP32C3_ONESHOT=y +CONFIG_ESP32C3_TIMER0=y +CONFIG_ESP32C3_TIMER1=y +CONFIG_EXAMPLES_ONESHOT=y +CONFIG_EXAMPLES_ONESHOT_DELAY=2000000 +CONFIG_EXAMPLES_TIMER=y +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_MAX_TASKS=8 +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NSH_STRERROR=y +CONFIG_ONESHOT=y +CONFIG_PREALLOC_TIMERS=0 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=29 +CONFIG_START_MONTH=11 +CONFIG_START_YEAR=2019 +CONFIG_SYSTEM_NSH=y +CONFIG_TIMER=y +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_USER_ENTRYPOINT="nsh_main" diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile b/boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile index b216b51acec..82081ad5389 100644 --- a/boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile +++ b/boards/risc-v/esp32c3/esp32c3-devkit/src/Makefile @@ -54,8 +54,8 @@ ifeq ($(CONFIG_WATCHDOG),y) CSRCS += esp32c3_wdt.c endif -ifeq ($(CONFIG_TIMER),y) -CSRCS += esp32c3_timer.c +ifeq ($(CONFIG_ONESHOT),y) +CSRCS += esp32c3_oneshot.c endif SCRIPTIN = $(SCRIPTDIR)$(DELIM)esp32c3.template.ld diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3-devkit.h b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3-devkit.h index 08c3ba34e58..81c94f70671 100644 --- a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3-devkit.h +++ b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3-devkit.h @@ -31,6 +31,16 @@ * Pre-processor Definitions ****************************************************************************/ +/* TIMERS */ + +#define TIMER0 0 +#define TIMER1 1 + +/* ONESHOT */ + +#define ONESHOT_TIMER 1 +#define ONESHOT_RESOLUTION_US 1 + /**************************************************************************** * Public Types ****************************************************************************/ @@ -101,10 +111,14 @@ int board_i2c_init(void); #endif /**************************************************************************** - * Name: board_tim_init + * Name: board_oneshot_init * * Description: - * Configure the timer driver. + * Configure the oneshot timer driver. + * + * Input Parameters: + * timer - Timer instance to be used as oneshot timer. + * resolution - Oneshot timer resolution. * * Returned Value: * Zero (OK) is returned on success; A negated errno value is returned @@ -112,8 +126,8 @@ int board_i2c_init(void); * ****************************************************************************/ -#ifdef CONFIG_TIMER -int board_tim_init(void); +#ifdef CONFIG_ONESHOT +int board_oneshot_init(int timer, uint16_t resolution); #endif /**************************************************************************** diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_bringup.c b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_bringup.c index 95f324849b6..1e8a94443d5 100644 --- a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_bringup.c +++ b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_bringup.c @@ -42,6 +42,10 @@ #include "esp32c3_partition.h" #include "esp32c3-devkit.h" +#ifdef CONFIG_TIMER +# include "esp32c3_tim_lowerhalf.h" +#endif + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -193,18 +197,46 @@ int esp32c3_bringup(void) } #endif -#ifdef CONFIG_TIMER - /* Configure timer timer */ +/* First, register the timer drivers and let timer 1 for oneshot + * if it is enabled. + */ - ret = board_tim_init(); +#ifdef CONFIG_TIMER + +#if defined(CONFIG_ESP32C3_TIMER0) && !defined(CONFIG_ESP32C3_RT_TIMER) + ret = esp32c3_timer_initialize("/dev/timer0", TIMER0); if (ret < 0) { syslog(LOG_ERR, - "ERROR: Failed to initialize timer drivers: %d\n", + "ERROR: Failed to initialize timer driver: %d\n", ret); } #endif +#if defined(CONFIG_ESP32C3_TIMER1) && !defined(CONFIG_ONESHOT) + ret = esp32c3_timer_initialize("/dev/timer1", TIMER1); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to initialize timer driver: %d\n", + ret); + } +#endif + +#endif /* CONFIG_TIMER */ + + /* Now register one oneshot driver */ + +#if defined(CONFIG_ONESHOT) && defined(CONFIG_ESP32C3_TIMER1) + + ret = board_oneshot_init(ONESHOT_TIMER, ONESHOT_RESOLUTION_US); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: board_oneshot_init() failed: %d\n", ret); + } + +#endif /* CONFIG_ONESHOT */ + #ifdef CONFIG_ESP32C3_WIRELESS #ifdef CONFIG_ESP32C3_WIFI_SAVE_PARAM diff --git a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_timer.c b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_oneshot.c similarity index 69% rename from boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_timer.c rename to boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_oneshot.c index dc37c220ffd..60a40c57375 100644 --- a/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_timer.c +++ b/boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_oneshot.c @@ -1,5 +1,5 @@ /**************************************************************************** - * boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_timer.c + * boards/risc-v/esp32c3/esp32c3-devkit/src/esp32c3_oneshot.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -24,12 +24,11 @@ #include -#include #include - -#include "esp32c3_tim_lowerhalf.h" -#include "esp32c3_tim.h" - +#include +#include +#include +#include #include "esp32c3-devkit.h" /**************************************************************************** @@ -41,10 +40,10 @@ ****************************************************************************/ /**************************************************************************** - * Name: board_tim_init + * Name: board_oneshot_init * * Description: - * Configure the timer driver. + * Configure the oneshot timer driver. * * Returned Value: * Zero (OK) is returned on success; A negated errno value is returned @@ -52,32 +51,33 @@ * ****************************************************************************/ -int board_tim_init(void) +int board_oneshot_init(int timer, uint16_t resolution) { int ret = OK; + FAR struct oneshot_lowerhalf_s *os_lower = NULL; -#if defined(CONFIG_ESP32C3_TIMER0) && !defined(CONFIG_ESP32C3_RT_TIMER) - ret = esp32c3_timer_initialize("/dev/timer0", ESP32C3_TIMER0); - if (ret < 0) + os_lower = oneshot_initialize(timer, resolution); + if (os_lower != NULL) { - syslog(LOG_ERR, - "ERROR: Failed to initialize timer driver: %d\n", - ret); - return ret; - } -#endif /* CONFIG_ESP32C3_TIMER0 */ +#if defined(CONFIG_CPULOAD_ONESHOT) + /* Configure the oneshot timer to support CPU load measurement */ -#ifdef CONFIG_ESP32C3_TIMER1 - ret = esp32c3_timer_initialize("/dev/timer1", ESP32C3_TIMER1); - if (ret < 0) - { - syslog(LOG_ERR, - "ERROR: Failed to initialize timer driver: %d\n", - ret); - return ret; + nxsched_oneshot_extclk(os_lower); + +#else + ret = oneshot_register("/dev/oneshot", os_lower); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: Failed to register oneshot at /dev/oneshot: %d\n", ret); + } +#endif /* CONFIG_CPULOAD_ONESHOT */ + } + else + { + syslog(LOG_ERR, "ERROR: oneshot_initialize failed\n"); + ret = -EBUSY; } -#endif /* CONFIG_ESP32C3_TIMER1 */ return ret; } -