diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig index 8115c55fdcd..72e5090a542 100644 --- a/arch/risc-v/src/esp32c3/Kconfig +++ b/arch/risc-v/src/esp32c3/Kconfig @@ -403,6 +403,13 @@ config ESP32C3_ONESHOT Enable a wrapper around the low level timer/counter functions to support one-shot timer. +config ESP32C3_FREERUN + bool "TIM free-running wrapper" + default n + ---help--- + Enable a wrapper around the low level timer/counter functions to + support a free-running timer. + endmenu # Timer/counter Configuration endif # ESP32C3_TIMER diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs index 30d217ff687..7c333a7486a 100644 --- a/arch/risc-v/src/esp32c3/Make.defs +++ b/arch/risc-v/src/esp32c3/Make.defs @@ -100,6 +100,10 @@ ifeq ($(CONFIG_ESP32C3_RT_TIMER),y) CHIP_CSRCS += esp32c3_rt_timer.c endif +ifeq ($(CONFIG_ESP32C3_FREERUN),y) +CHIP_CSRCS += esp32c3_freerun.c +endif + ifeq ($(CONFIG_ESP32C3_DISABLE_STDC_ATOMIC),) CHIP_CSRCS += esp32c3_std_atomic.c endif diff --git a/arch/risc-v/src/esp32c3/esp32c3_freerun.c b/arch/risc-v/src/esp32c3/esp32c3_freerun.c new file mode 100644 index 00000000000..635a2497f7b --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_freerun.c @@ -0,0 +1,354 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_freerun.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_freerun.h" +#include "esp32c3_clockconfig.h" +#include "esp32c3_gpio.h" + +#ifdef CONFIG_ESP32C3_FREERUN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MAX_TIMERS 2 +#define MAX_US_RESOLUTION 819 +#define TIMER_WIDTH 54 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_freerun_handler + * + * Description: + * Timer interrupt callback. When the freerun timer counter overflows, + * this interrupt will occur. We will just increment an overflow counter. + * + * Input Parameters: + * irq - IRQ associated to that interrupt. + * arg - An opaque argument provided when the interrupt + * was registered. + * + * Returned Value: + * OK + * + ****************************************************************************/ + +#ifndef CONFIG_CLOCK_TIMEKEEPING +static int esp32c3_freerun_handler(int irq, void *context, void *arg) +{ + struct esp32c3_freerun_s *freerun = (struct esp32c3_freerun_s *) arg; + + DEBUGASSERT(freerun != NULL); + + freerun->overflow++; + ESP32C3_TIM_SETALRM(freerun->tch, true); /* Re-enables the alarm */ + ESP32C3_TIM_ACKINT(freerun->tch); /* Clear the Interrupt */ + return OK; +} +#endif /* CONFIG_CLOCK_TIMEKEEPING */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_freerun_initialize + * + * Description: + * Initialize the freerun timer wrapper. + * + * Input Parameters: + * freerun - Caller allocated instance of the freerun + * 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_freerun_initialize(struct esp32c3_freerun_s *freerun, int chan, + uint16_t resolution) +{ + uint16_t pre; + int ret = OK; + + tmrinfo("chan=%d resolution=%d usecs\n", chan, resolution); + + DEBUGASSERT(freerun != NULL); + DEBUGASSERT(chan >= 0); + DEBUGASSERT(chan < MAX_TIMERS); + DEBUGASSERT(resolution > 0); + + /* We can't have a resolution bigger than this. + * The ESP32-C3 prescaler doesn't support. + * max resolution = (max prescaler * USEC_PER_SEC) / esp32c3_clk_apb_freq() + */ + + DEBUGASSERT(resolution <= MAX_US_RESOLUTION); + + freerun->tch = esp32c3_tim_init(chan); + if (freerun->tch == NULL) + { + tmrerr("ERROR: Failed to allocate TIM %d\n", chan); + ret = -EBUSY; + } + else + { + /* Initialize the remaining fields in the state structure. */ + + freerun->chan = chan; + freerun->resolution = resolution; + freerun->max_timeout = (UINT64_C(1) << (TIMER_WIDTH - 1)); + + /* Ensure timer is disabled. + * Change the prescaler divider with the timer enabled can lead to + * unpredictable results. + */ + + ESP32C3_TIM_STOP(freerun->tch); + + /* Configure clock source */ + + ESP32C3_TIM_CLK_SRC(freerun->tch, ESP32C3_TIM_APB_CLK); + + /* Calculate the suitable prescaler for a period + * for the requested resolution. + */ + + pre = esp32c3_clk_apb_freq() * resolution / USEC_PER_SEC; + + tmrinfo("pre=% "PRIu16 " clk=%d \n", pre, esp32c3_clk_apb_freq()); + + /* Configure TIMER prescaler */ + + ESP32C3_TIM_SETPRE(freerun->tch, pre); + + /* Configure TIMER mode */ + + ESP32C3_TIM_SETMODE(freerun->tch, ESP32C3_TIM_MODE_UP); + + /* Clear TIMER counter value */ + + ESP32C3_TIM_CLEAR(freerun->tch); + + /* Set the maximum timeout */ + + ESP32C3_TIM_SETALRVL(freerun->tch, freerun->max_timeout); + +#ifndef CONFIG_CLOCK_TIMEKEEPING + + /* Set the interrupt */ + + freerun->overflow = 0; + + /* Enable autoreload */ + + ESP32C3_TIM_SETARLD(freerun->tch, true); + + /* Enable TIMER alarm */ + + ESP32C3_TIM_SETALRM(freerun->tch, true); + + /* Clear Interrupt Bits Status */ + + ESP32C3_TIM_ACKINT(freerun->tch); + + /* Register the handler */ + + { + irqstate_t flags = enter_critical_section(); + ret = ESP32C3_TIM_SETISR(freerun->tch, esp32c3_freerun_handler, + freerun); + leave_critical_section(flags); + } + + if (ret == OK) + { + ESP32C3_TIM_ENABLEINT(freerun->tch); + } + +#endif + /* Finally, start the TIMER */ + + ESP32C3_TIM_START(freerun->tch); + } + + return ret; +} + +/**************************************************************************** + * Name: esp32c3_freerun_counter + * + * Description: + * Read the counter register of the free-running timer. + * + * Input Parameters: + * freerun - Caller allocated instance of the freerun state + * structure. This structure must have been previously + * initialized via a call to + * esp32c3_freerun_initialize(); + * ts - The location in which to return the time from the + * free-running timer. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +#ifndef CONFIG_CLOCK_TIMEKEEPING + +int esp32c3_freerun_counter(struct esp32c3_freerun_s *freerun, + struct timespec *ts) +{ + uint64_t usec; + uint64_t counter; + uint64_t verify; + uint32_t overflow; + uint32_t sec; + int pending; + irqstate_t flags; + + DEBUGASSERT(freerun != NULL); + DEBUGASSERT(ts != NULL); + DEBUGASSERT(freerun->tch != NULL); + + /* Temporarily disable the overflow counter. */ + + flags = enter_critical_section(); + + overflow = freerun->overflow; + ESP32C3_TIM_GETCTR(freerun->tch, &counter); + pending = ESP32C3_TIM_CHECKINT(freerun->tch); + ESP32C3_TIM_GETCTR(freerun->tch, &verify); + + /* If an interrupt was pending before we re-enabled interrupts, + * then the overflow needs to be incremented. + */ + + if (pending) + { + ESP32C3_TIM_ACKINT(freerun->tch); + + /* Increment the overflow count and use the value of the + * guaranteed to be AFTER the overflow occurred. + */ + + overflow++; + counter = verify; + + /* Update freerun overflow counter. */ + + freerun->overflow = overflow; + } + + leave_critical_section(flags); + + tmrinfo("counter=%" PRIu64 " (%" PRIu64 ") overflow=%" PRIu32 + ", pending=%i\n", + counter, verify, overflow, pending); + + usec = (uint64_t)(((overflow * freerun->max_timeout) + counter) + * freerun->resolution); + + /* And return the value of the timer */ + + sec = (uint32_t)(usec / USEC_PER_SEC); + ts->tv_sec = sec; + ts->tv_nsec = (usec - (sec * USEC_PER_SEC)) * NSEC_PER_USEC; + + tmrinfo(" usec=%" PRIu64 " ts=(%lu, %lu)\n", + usec, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec); + + return OK; +} + +#endif /* CONFIG_CLOCK_TIMEKEEPING */ + +/**************************************************************************** + * Name: esp32c3_freerun_uninitialize + * + * Description: + * Stop the free-running timer and release all resources that it uses. + * + * Input Parameters: + * freerun - Caller allocated instance of the freerun state + * structure. This structure must have been previously + * initialized via a call to + * esp32c3_freerun_initialize(); + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int esp32c3_freerun_uninitialize(struct esp32c3_freerun_s *freerun) +{ + int ret; + DEBUGASSERT(freerun != NULL); + DEBUGASSERT(freerun->tch != NULL); + + /* Stop timer */ + + ESP32C3_TIM_STOP(freerun->tch); + + /* Disable timer interrupt */ + + ESP32C3_TIM_DISABLEINT(freerun->tch); + + /* Detach handler */ + + ret = ESP32C3_TIM_SETISR(freerun->tch, NULL, NULL); + + /* Free the timer */ + + esp32c3_tim_deinit(freerun->tch); + freerun->tch = NULL; + + return ret; +} + +#endif /* CONFIG_ESP32C3_FREERUN */ diff --git a/arch/risc-v/src/esp32c3/esp32c3_freerun.h b/arch/risc-v/src/esp32c3/esp32c3_freerun.h new file mode 100644 index 00000000000..d80da590489 --- /dev/null +++ b/arch/risc-v/src/esp32c3/esp32c3_freerun.h @@ -0,0 +1,145 @@ +/**************************************************************************** + * arch/risc-v/src/esp32c3/esp32c3_freerun.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_FREERUN_H +#define __ARCH_RISCV_SRC_ESP32C3_FREERUN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "esp32c3_tim.h" + +#ifdef CONFIG_ESP32C3_FREERUN + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The freerun client must allocate an instance of this structure and called + * esp32c3_freerun_initialize() before using the freerun facilities. The + * client should not access the contents of this structure directly since + * the contents are subject to change. + */ + +struct esp32c3_freerun_s +{ + uint8_t chan; /* The timer/counter in use */ + uint32_t overflow; /* Timer counter overflow */ + uint16_t resolution; /* Timer resolution */ + uint64_t max_timeout; /* Maximum timeout to overflow */ + FAR struct esp32c3_tim_dev_s *tch; /* Handle returned by esp32c3_tim_init() */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: esp32c3_freerun_initialize + * + * Description: + * Initialize the freerun timer wrapper. + * + * Input Parameters: + * freerun - Caller allocated instance of the freerun + * 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_freerun_initialize(struct esp32c3_freerun_s *freerun, int chan, + uint16_t resolution); + +/**************************************************************************** + * Name: esp32c3_freerun_counter + * + * Description: + * Read the counter register of the free-running timer. + * + * Input Parameters: + * freerun - Caller allocated instance of the freerun state + * structure. This structure must have been previously + * initialized via a call to + * esp32c3_freerun_initialize(); + * ts - The location in which to return the time from the + * free-running timer. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int esp32c3_freerun_counter(struct esp32c3_freerun_s *freerun, + struct timespec *ts); + +/**************************************************************************** + * Name: esp32c3_freerun_uninitialize + * + * Description: + * Stop the free-running timer and release all resources that it uses. + * + * Input Parameters: + * freerun - Caller allocated instance of the freerun state + * structure. This structure must have been previously + * initialized via a call to + * esp32c3_freerun_initialize(); + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int esp32c3_freerun_uninitialize(struct esp32c3_freerun_s *freerun); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_ESP32C3_FREERUN */ +#endif /* __ARCH_RISCV_SRC_ESP32C3_FREERUN_H */ diff --git a/arch/risc-v/src/esp32c3/esp32c3_tim.c b/arch/risc-v/src/esp32c3/esp32c3_tim.c index 5acb8983e6c..db5830087c7 100644 --- a/arch/risc-v/src/esp32c3/esp32c3_tim.c +++ b/arch/risc-v/src/esp32c3/esp32c3_tim.c @@ -34,6 +34,7 @@ #include "esp32c3_tim.h" #include "esp32c3_irq.h" +#include "esp32c3_gpio.h" /**************************************************************************** * Private Types @@ -82,6 +83,7 @@ static int esp32c3_tim_setisr(FAR struct esp32c3_tim_dev_s *dev, static void esp32c3_tim_enableint(FAR struct esp32c3_tim_dev_s *dev); static void esp32c3_tim_disableint(FAR struct esp32c3_tim_dev_s *dev); static void esp32c3_tim_ackint(FAR struct esp32c3_tim_dev_s *dev); +static int esp32c3_tim_checkint(FAR struct esp32c3_tim_dev_s *dev); /**************************************************************************** * Private Data @@ -107,7 +109,8 @@ struct esp32c3_tim_ops_s esp32c3_tim_ops = .setisr = esp32c3_tim_setisr, .enableint = esp32c3_tim_enableint, .disableint = esp32c3_tim_disableint, - .ackint = esp32c3_tim_ackint + .ackint = esp32c3_tim_ackint, + .checkint = esp32c3_tim_checkint }; #ifdef CONFIG_ESP32C3_TIMER0 @@ -654,6 +657,31 @@ static void esp32c3_tim_ackint(FAR struct esp32c3_tim_dev_s *dev) modifyreg32(TIMG_INT_CLR_TIMERS_REG(priv->id), 0, TIMG_T0_INT_CLR_M); } +/**************************************************************************** + * Name: esp32c3_tim_checkint + * + * Description: + * Check the interrupt status bit. + * + * Parameters: + * dev - Pointer to the timer driver struct. + * + * Returned Values: + * Return 1 in case of an interrupt is triggered, otherwise 0. + * + ****************************************************************************/ + +static int esp32c3_tim_checkint(FAR struct esp32c3_tim_dev_s *dev) +{ + struct esp32c3_tim_priv_s *priv = (struct esp32c3_tim_priv_s *)dev; + uint32_t reg_value; + + DEBUGASSERT(dev != NULL); + + reg_value = getreg32(TIMG_INT_ST_TIMERS_REG(priv->id)); + return ((reg_value & TIMG_T0_INT_ST_V) >> TIMG_T0_INT_ST_S); +} + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/arch/risc-v/src/esp32c3/esp32c3_tim.h b/arch/risc-v/src/esp32c3/esp32c3_tim.h index e3a00989cff..12ad92ad6ea 100644 --- a/arch/risc-v/src/esp32c3/esp32c3_tim.h +++ b/arch/risc-v/src/esp32c3/esp32c3_tim.h @@ -53,6 +53,7 @@ #define ESP32C3_TIM_ENABLEINT(d) ((d)->ops->enableint(d)) #define ESP32C3_TIM_DISABLEINT(d) ((d)->ops->disableint(d)) #define ESP32C3_TIM_ACKINT(d) ((d)->ops->ackint(d)) +#define ESP32C3_TIM_CHECKINT(d) ((d)->ops->checkint(d)) /**************************************************************************** * Public Types @@ -126,6 +127,7 @@ struct esp32c3_tim_ops_s CODE void (*enableint)(FAR struct esp32c3_tim_dev_s *dev); CODE void (*disableint)(FAR struct esp32c3_tim_dev_s *dev); CODE void (*ackint)(FAR struct esp32c3_tim_dev_s *dev); + CODE int (*checkint)(FAR struct esp32c3_tim_dev_s *dev); }; /**************************************************************************** diff --git a/arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h b/arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h index b9846d816b9..d4d080c54f8 100644 --- a/arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h +++ b/arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h @@ -72,7 +72,7 @@ /* Maximum value in the high 22 bits from timer counters */ #define LOW_32_MASK 0xffffffff -#define LOW_22_MASK 0x3fffff +#define LOW_22_MASK 0x003fffff #define SHIFT_32 32 #define TIMG_T0CONFIG_REG(i) (REG_TIMG_BASE(i) + 0x0000)