diff --git a/arch/arm/src/samv7/chip/sam_emac.h b/arch/arm/src/samv7/chip/sam_emac.h index b97961ecb6..e0a0cbb9a7 100644 --- a/arch/arm/src/samv7/chip/sam_emac.h +++ b/arch/arm/src/samv7/chip/sam_emac.h @@ -1,5 +1,5 @@ /************************************************************************************ - * arch/arm/src/sama5/chip/sam_emac.h + * arch/arm/src/samv7/chip/sam_emac.h * This is the form of the EMAC interface used the the SAMV7. * This is referred as GMAC in the documentation even though it does not support * Gibabit Ethernet. diff --git a/arch/arm/src/samv7/sam_emac.c b/arch/arm/src/samv7/sam_emac.c index 72b42c2205..d617e0c405 100644 --- a/arch/arm/src/samv7/sam_emac.c +++ b/arch/arm/src/samv7/sam_emac.c @@ -2138,7 +2138,7 @@ static void sam_txerr_interrupt(FAR struct sam_emac_s *priv, int qid) NETDEV_TXERRORS(&priv->dev); /* Clear TXEN bit into the Network Configuration Register. This is a - * workaround to recover from TX lockups that occur on sama5d3 gmac + * workaround to recover from TX lockups that occurred on the sama5d3 gmac * (r1p24f2) when using scatter-gather. This issue has never been * seen on sama5d4 gmac (r1p31). */ diff --git a/arch/arm/src/samv7/sam_freerun.c b/arch/arm/src/samv7/sam_freerun.c new file mode 100644 index 0000000000..c31472f894 --- /dev/null +++ b/arch/arm/src/samv7/sam_freerun.c @@ -0,0 +1,322 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_freerun.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: + * + * SAMV71 Series Data Sheet + * NuttX SAMA5 free-running timer driver + * Atmel NoOS sample code for the SAMA5D3. + * + * The Atmel sample code has a BSD compatible license that requires this + * copyright notice: + * + * Copyright (c) 2011, Atmel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names NuttX nor Atmel nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "sam_freerun.h" + +#ifdef CONFIG_SAMV7_ONESHOT + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + + /**************************************************************************** + * Name: sam_freerun_handler + * + * Description: + * Timer interrupt callback. When the freerun timer counter overflows, + * this interrupt will occur. We will just increment an overflow count. + * + * Input Parameters: + * tch - The handle that represents the timer state + * arg - An opaque argument provided when the interrupt was registered + * sr - The value of the timer interrupt status register at the time + * that the interrupt occurred. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void sam_freerun_handler(TC_HANDLE tch, void *arg, uint32_t sr) +{ + struct sam_freerun_s *freerun = (struct sam_freerun_s *)arg; + DEBUGASSERT(freerun && freerun->overflow < UINT32_MAX); + freerun->overflow++; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_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. See the TC_CHAN* + * definitions in arch/arm/src/samv7/sam_tc.h. + * 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 sam_freerun_initialize(struct sam_freerun_s *freerun, int chan, + uint16_t resolution) +{ + uint32_t frequency; + uint32_t divisor; + uint32_t cmr; + int ret; + + tcvdbg("chan=%d resolution=%d usec\n", chan, resolution); + DEBUGASSERT(freerun && resolution > 0); + + /* Get the TC frequency the corresponds to the requested resolution */ + + frequency = USEC_PER_SEC / (uint32_t)resolution; + + /* The pre-calculate values to use when we start the timer */ + + ret = sam_tc_divisor(frequency, &divisor, &cmr); + if (ret < 0) + { + tcdbg("ERROR: sam_tc_divisor failed: %d\n", ret); + return ret; + } + + tcvdbg("frequency=%lu, divisor=%u, cmr=%08lx\n", + (unsigned long)frequency, (unsigned long)divisor, + (unsigned long)cmr); + + /* Allocate the timer/counter and select its mode of operation + * + * CMR_TCCLKS - Returned by sam_tc_divisor + * TC_CMR_CLKI=0 - Not inverted + * TC_CMR_BURST_NONE - Not gated by an external signal + * TC_CMR_CPCSTOP=0 - Don't stop the clock on an RC compare event + * TC_CMR_CPCDIS=0 - Don't disable the clock on an RC compare event + * TC_CMR_EEVTEDG_NONE - No external events (and, hence, no edges + * TC_CMR_EEVT_TIOB - ???? REVISIT + * TC_CMR_ENET=0 - External event trigger disabled + * TC_CMR_WAVSEL_UP - TC_CV is incremented from 0 to 0xffffffff + * TC_CMR_WAVE - Waveform mode + * TC_CMR_ACPA_NONE - RA compare has no effect on TIOA + * TC_CMR_ACPC_NONE - RC compare has no effect on TIOA + * TC_CMR_AEEVT_NONE - No external event effect on TIOA + * TC_CMR_ASWTRG_NONE - No software trigger effect on TIOA + * TC_CMR_BCPB_NONE - RB compare has no effect on TIOB + * TC_CMR_BCPC_NONE - RC compare has no effect on TIOB + * TC_CMR_BEEVT_NONE - No external event effect on TIOB + * TC_CMR_BSWTRG_NONE - No software trigger effect on TIOB + */ + + cmr |= (TC_CMR_BURST_NONE | TC_CMR_EEVTEDG_NONE | TC_CMR_EEVT_TIOB | + TC_CMR_WAVSEL_UP | TC_CMR_WAVE | TC_CMR_ACPA_NONE | + TC_CMR_ACPC_NONE | TC_CMR_AEEVT_NONE | TC_CMR_ASWTRG_NONE | + TC_CMR_BCPB_NONE | TC_CMR_BCPC_NONE | TC_CMR_BEEVT_NONE | + TC_CMR_BSWTRG_NONE); + + freerun->tch = sam_tc_allocate(chan, cmr); + if (!freerun->tch) + { + tcdbg("ERROR: Failed to allocate timer channel %d\n", chan); + return -EBUSY; + } + + /* Initialize the remaining fields in the state structure and return + * success. + */ + + freerun->chan = chan; + freerun->running = false; + freerun->overflow = 0; + + /* Set up to receive the callback when the counter overflow occurs */ + + (void)sam_tc_attach(freerun->tch, sam_freerun_handler, freerun, + TC_INT_COVFS); + + /* Start the counter */ + + sam_tc_start(freerun->tch); + return OK; +} + +/**************************************************************************** + * Name: sam_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 + * sam_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 sam_freerun_counter(struct sam_freerun_s *freerun, struct timespec *ts) +{ + uint64_t usec; + uint32_t counter; + uint32_t verify; + uint32_t sr; + uint32_t overflow; + uint32_t sec; + irqstate_t flags; + + DEBUGASSERT(freerun && freerun->tch && ts); + + /* Temporarily disable the overflow counter. NOTE that we have to be careful + * here because sam_tc_getpending() will reset the pending interrupt status. + * If we do not handle the overflow here then, it will be lost. + */ + + flags = irqsave(); + overflow = freerun->overflow; + counter = sam_tc_getcounter(freerun->tch); + sr = sam_tc_getpending(freerun->tch); + verify = sam_tc_getcounter(freerun->tch); + + /* If an interrupt was pending before we re-enabled interrupts, + * then the overflow needs to be incremented. + */ + + if ((sr & TC_INT_COVFS) != 0) + { + /* 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; + } + + irqrestore(flags); + + tcvdbg("counter=%lu (%lu) overflow=%lu, sr=%08lx\n", + (unsigned long)counter, (unsigned long)verify, + (unsigned long)overflow, (unsigned long)sr); + + /* Convert the whole thing to units of microseconds. + * + * frequency = ticks / second + * seconds = ticks * frequency + * usecs = (ticks * USEC_PER_SEC) / frequency; + */ + + usec = ((((uint64_t)overflow << 16) + (uint64_t)counter) * USEC_PER_SEC) / + sam_tc_divfreq(freerun->tch); + + /* 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; + + tcvdbg("usec=%llu ts=(%lu, %lu)\n", + usec, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec); + + return OK; +} + +/**************************************************************************** + * Name: sam_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 + * sam_freerun_initialize(); + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int sam_freerun_uninitialize(struct sam_freerun_s *freerun) +{ + DEBUGASSERT(freerun && freerun->tch); + + /* Now we can disable the timer interrupt and disable the timer. */ + + sam_tc_attach(freerun->tch, NULL, NULL, 0); + sam_tc_stop(freerun->tch); + + /* Free the timer */ + + sam_tc_free(freerun->tch); + freerun->tch = NULL; + return OK; +} + +#endif /* CONFIG_SAMV7_ONESHOT */ diff --git a/arch/arm/src/samv7/sam_freerun.h b/arch/arm/src/samv7/sam_freerun.h new file mode 100644 index 0000000000..52075b2ecc --- /dev/null +++ b/arch/arm/src/samv7/sam_freerun.h @@ -0,0 +1,160 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_freerun.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMV7_SAM_FREERUN_H +#define __ARCH_ARM_SRC_SAMV7_SAM_FREERUN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sam_tc.h" + +#ifdef CONFIG_SAMV7_FREERUN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The freerun client must allocate an instance of this structure and called + * sam_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 sam_freerun_s +{ + uint8_t chan; /* The timer/counter in use */ + bool running; /* True: the timer is running */ + uint32_t overflow; /* Timer counter overflow */ + TC_HANDLE tch; /* Handle returned by sam_tc_initialize() */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_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. See the TC_CHAN* + * definitions in arch/arm/src/samv7/sam_tc.h. + * 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 sam_freerun_initialize(struct sam_freerun_s *freerun, int chan, + uint16_t resolution); + +/**************************************************************************** + * Name: sam_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 + * sam_freerun_initialize(); + * ts The location in which to return the time remaining on the + * oneshot timer. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int sam_freerun_counter(struct sam_freerun_s *freerun, struct timespec *ts); + +/**************************************************************************** + * Name: sam_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 + * sam_freerun_initialize(); + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int sam_freerun_uninitialize(struct sam_freerun_s *freerun); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_SAMV7_FREERUN */ +#endif /* __ARCH_ARM_SRC_SAMV7_SAM_FREERUN_H */ diff --git a/arch/arm/src/samv7/sam_oneshot.c b/arch/arm/src/samv7/sam_oneshot.c new file mode 100644 index 0000000000..9c165bd687 --- /dev/null +++ b/arch/arm/src/samv7/sam_oneshot.c @@ -0,0 +1,479 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_oneshot.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: + * + * SAMV71 Series Data Sheet + * NuttX SAMA5 one-shot timer driver + * Atmel NoOS sample code. + * + * The Atmel sample code has a BSD compatible license that requires this + * copyright notice: + * + * Copyright (c) 2011, Atmel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the names NuttX nor Atmel nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "sam_oneshot.h" + +#ifdef CONFIG_SAMV7_ONESHOT + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_oneshot_handler + * + * Description: + * Timer interrupt callback. When the oneshot timer interrupt expires, + * this function will be called. It will forward the call to the next + * level up. + * + * Input Parameters: + * tch - The handle that represents the timer state + * arg - An opaque argument provided when the interrupt was registered + * sr - The value of the timer interrupt status register at the time + * that the interrupt occurred. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void sam_oneshot_handler(TC_HANDLE tch, void *arg, uint32_t sr) +{ + struct sam_oneshot_s *oneshot = (struct sam_oneshot_s *)arg; + oneshot_handler_t oneshot_handler; + void *oneshot_arg; + + tcllvdbg("Expired...\n"); + DEBUGASSERT(oneshot && oneshot->handler); + + /* The clock was stopped, but not disabled when the RC match occurred. + * Disable the TC now and disable any further interrupts. + */ + + sam_tc_attach(oneshot->tch, NULL, NULL, 0); + sam_tc_stop(oneshot->tch); + + /* The timer is no longer running */ + + oneshot->running = false; + + /* Forward the event, clearing out any vestiges */ + + oneshot_handler = (oneshot_handler_t)oneshot->handler; + oneshot->handler = NULL; + oneshot_arg = (void *)oneshot->arg; + oneshot->arg = NULL; + + oneshot_handler(oneshot_arg); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_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. See the TC_CHAN* + * definitions in arch/arm/src/samv7/sam_tc.h. + * 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 sam_oneshot_initialize(struct sam_oneshot_s *oneshot, int chan, + uint16_t resolution) +{ + uint32_t frequency; + uint32_t divisor; + uint32_t cmr; + int ret; + + tcvdbg("chan=%d resolution=%d usec\n", chan, resolution); + DEBUGASSERT(oneshot && resolution > 0); + + /* Get the TC frequency the corresponds to the requested resolution */ + + frequency = USEC_PER_SEC / (uint32_t)resolution; + + /* The pre-calculate values to use when we start the timer */ + + ret = sam_tc_divisor(frequency, &divisor, &cmr); + if (ret < 0) + { + tcdbg("ERROR: sam_tc_divisor failed: %d\n", ret); + return ret; + } + + tcvdbg("frequency=%lu, divisor=%lu, cmr=%08lx\n", + (unsigned long)frequency, (unsigned long)divisor, + (unsigned long)cmr); + + /* Allocate the timer/counter and select its mode of operation + * + * CMR_TCCLKS - Returned by sam_tc_divisor + * TC_CMR_CLKI=0 - Not inverted + * TC_CMR_BURST_NONE - Not gated by an external signal + * TC_CMR_CPCSTOP=1 - Stop the clock on an RC compare event + * TC_CMR_CPCDIS=0 - Don't disable the clock on an RC compare event + * TC_CMR_EEVTEDG_NONE - No external events (and, hence, no edges + * TC_CMR_EEVT_TIOB - ???? REVISIT + * TC_CMR_ENET=0 - External event trigger disabled + * TC_CMR_WAVSEL_UPRC - TC_CV is incremented from 0 to the value of RC, + * then automatically reset on a RC Compare + * TC_CMR_WAVE - Waveform mode + * TC_CMR_ACPA_NONE - RA compare has no effect on TIOA + * TC_CMR_ACPC_NONE - RC compare has no effect on TIOA + * TC_CMR_AEEVT_NONE - No external event effect on TIOA + * TC_CMR_ASWTRG_NONE - No software trigger effect on TIOA + * TC_CMR_BCPB_NONE - RB compare has no effect on TIOB + * TC_CMR_BCPC_NONE - RC compare has no effect on TIOB + * TC_CMR_BEEVT_NONE - No external event effect on TIOB + * TC_CMR_BSWTRG_NONE - No software trigger effect on TIOB + */ + + cmr |= (TC_CMR_BURST_NONE | TC_CMR_CPCSTOP | TC_CMR_EEVTEDG_NONE | + TC_CMR_EEVT_TIOB | TC_CMR_WAVSEL_UPRC | TC_CMR_WAVE | + TC_CMR_ACPA_NONE | TC_CMR_ACPC_NONE | TC_CMR_AEEVT_NONE | + TC_CMR_ASWTRG_NONE | TC_CMR_BCPB_NONE | TC_CMR_BCPC_NONE | + TC_CMR_BEEVT_NONE | TC_CMR_BSWTRG_NONE); + + oneshot->tch = sam_tc_allocate(chan, cmr); + if (!oneshot->tch) + { + tcdbg("ERROR: Failed to allocate timer channel %d\n", chan); + return -EBUSY; + } + + /* Initialize the remaining fields in the state structure and return + * success. + */ + + oneshot->chan = chan; + oneshot->running = false; + oneshot->handler = NULL; + oneshot->arg = NULL; + return OK; +} + +/**************************************************************************** + * Name: sam_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 + * sam_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 sam_oneshot_start(struct sam_oneshot_s *oneshot, oneshot_handler_t handler, + void *arg, const struct timespec *ts) +{ + uint64_t usec; + uint64_t regval; + irqstate_t flags; + + tcvdbg("handler=%p arg=%p, ts=(%lu, %lu)\n", + handler, arg, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec); + DEBUGASSERT(oneshot && handler && ts); + + /* Was the oneshot already running? */ + + flags = irqsave(); + if (oneshot->running) + { + /* Yes.. then cancel it */ + + tcvdbg("Already running... cancelling\n"); + (void)sam_oneshot_cancel(oneshot, NULL); + } + + /* Save the new handler and its argument */ + + oneshot->handler = handler; + oneshot->arg = arg; + + /* Express the delay in microseconds */ + + usec = (uint64_t)ts->tv_sec * USEC_PER_SEC + (uint64_t)(ts->tv_nsec / NSEC_PER_USEC); + + /* Get the timer counter frequency and determine the number of counts need to achieve the requested delay. + * + * frequency = ticks / second + * ticks = seconds * frequency + * = (usecs * frequency) / USEC_PER_SEC; + */ + + regval = (usec * (uint64_t)sam_tc_divfreq(oneshot->tch)) / USEC_PER_SEC; + + tcvdbg("usec=%llu regval=%08llx\n", usec, regval); + DEBUGASSERT(regval <= UINT16_MAX); + + /* Set up to receive the callback when the interrupt occurs */ + + (void)sam_tc_attach(oneshot->tch, sam_oneshot_handler, oneshot, + TC_INT_CPCS); + + /* Set RC so that an event will be triggered when TC_CV register counts + * up to RC. + */ + + sam_tc_setregister(oneshot->tch, TC_REGC, (uint32_t)regval); + + /* Start the counter */ + + sam_tc_start(oneshot->tch); + + /* Enable interrupts. We should get the callback when the interrupt + * occurs. + */ + + oneshot->running = true; + irqrestore(flags); + return OK; +} + +/**************************************************************************** + * Name: sam_oneshot_cancel + * + * Description: + * Cancel the oneshot timer and return the time remaining on the timer. + * + * NOTE: This function may execute at a high rate with no timer running (as + * when pre-emption is enabled and disabled). + * + * Input Parameters: + * oneshot Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * sam_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 sam_oneshot_cancel(struct sam_oneshot_s *oneshot, struct timespec *ts) +{ + irqstate_t flags; + uint64_t usec; + uint64_t sec; + uint64_t nsec; + uint32_t count; + uint32_t rc; + + /* Was the timer running? */ + + flags = irqsave(); + if (!oneshot->running) + { + /* No.. Just return zero timer remaining and successful cancellation. + * This function may execute at a high rate with no timer running + * (as when pre-emption is enabled and disabled). + */ + + ts->tv_sec = 0; + ts->tv_nsec = 0; + irqrestore(flags); + return OK; + } + + /* Yes.. Get the timer counter and rc registers and stop the counter. If + * the counter expires while we are doing this, the counter clock will be + * stopped, but the clock will not be disabled. + * + * The expected behavior is that the the counter register will freezes at + * a value equal to the RC register when the timer expires. The counter + * should have values between 0 and RC in all other cased. + * + * REVISIT: This does not appear to be the case. + */ + + tcvdbg("Cancelling...\n"); + + count = sam_tc_getcounter(oneshot->tch); + rc = sam_tc_getregister(oneshot->tch, TC_REGC); + + /* Now we can disable the interrupt and stop the timer. */ + + sam_tc_attach(oneshot->tch, NULL, NULL, 0); + sam_tc_stop(oneshot->tch); + + oneshot->running = false; + oneshot->handler = NULL; + oneshot->arg = NULL; + irqrestore(flags); + + /* Did the caller provide us with a location to return the time + * remaining? + */ + + if (ts) + { + /* Yes.. then calculate and return the time remaining on the + * oneshot timer. + */ + + tcvdbg("rc=%lu count=%lu usec=%lu\n", + (unsigned long)rc, (unsigned long)count, (unsigned long)usec); + + /* REVISIT: I am not certain why the timer counter value sometimes + * exceeds RC. Might be a bug, or perhaps the counter does not stop + * in all cases. + */ + + if (count >= rc) + { + /* No time remaining (?) */ + + ts->tv_sec = 0; + ts->tv_nsec = 0; + } + else + { + /* The total time remaining is the difference. Convert the that + * to units of microseconds. + * + * frequency = ticks / second + * seconds = ticks * frequency + * usecs = (ticks * USEC_PER_SEC) / frequency; + */ + + usec = (((uint64_t)(rc - count)) * USEC_PER_SEC) / + sam_tc_divfreq(oneshot->tch); + + /* Return the time remaining in the correct form */ + + sec = usec / USEC_PER_SEC; + nsec = ((usec) - (sec * USEC_PER_SEC)) * NSEC_PER_USEC; + + ts->tv_sec = (time_t)sec; + ts->tv_nsec = (unsigned long)nsec; + } + + tcvdbg("remaining (%lu, %lu)\n", + (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec); + } + + return OK; +} + +/**************************************************************************** + * Name: sam_oneshot_max_delay + * + * Description: + * Return the maximum delay supported by the one shot timer (in + * microseconds). + * + * Input Parameters: + * oneshot Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * sam_oneshot_initialize(); + * usec 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. + * + ****************************************************************************/ + +#if 0 /* Not used */ +int sam_oneshot_max_delay(struct sam_oneshot_s *oneshot, uint64_t *usec) +{ + DEBUGASSERT(oneshot && usec); + *usec = (0xffffull * USEC_PER_SEC) / (uint64_t)sam_tc_divfreq(oneshot->tch); + return OK; +} +#endif + +#endif /* CONFIG_SAMV7_ONESHOT */ diff --git a/arch/arm/src/samv7/sam_oneshot.h b/arch/arm/src/samv7/sam_oneshot.h new file mode 100644 index 0000000000..09b341cdf2 --- /dev/null +++ b/arch/arm/src/samv7/sam_oneshot.h @@ -0,0 +1,203 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_oneshot.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMV7_SAM_ONESHOT_H +#define __ARCH_ARM_SRC_SAMV7_SAM_ONESHOT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sam_tc.h" + +#ifdef CONFIG_SAMV7_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 called + * sam_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 sam_oneshot_s +{ + uint8_t chan; /* The timer/counter in use */ + volatile bool running; /* True: the timer is running */ + TC_HANDLE tch; /* Handle returned by + * sam_tc_initialize() */ + volatile oneshot_handler_t handler; /* Oneshot expiration callback */ + volatile void *arg; /* The argument that will accompany + * the callback */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_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. See the TC_CHAN* + * definitions in arch/arm/src/samv7/sam_tc.h. + * 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 sam_oneshot_initialize(struct sam_oneshot_s *oneshot, int chan, + uint16_t resolution); + +/**************************************************************************** + * Name: sam_oneshot_max_delay + * + * Description: + * Return the maximum delay supported by the one shot timer (in + * microseconds). + * + * Input Parameters: + * oneshot Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * sam_oneshot_initialize(); + * usec 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. + * + ****************************************************************************/ + +#if 0 /* Not used */ +int sam_oneshot_max_delay(struct sam_oneshot_s *oneshot, uint64_t *usec); +#endif + +/**************************************************************************** + * Name: sam_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 + * sam_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 sam_oneshot_start(struct sam_oneshot_s *oneshot, oneshot_handler_t handler, + void *arg, const struct timespec *ts); + +/**************************************************************************** + * Name: sam_oneshot_cancel + * + * Description: + * Cancel the oneshot timer and return the time remaining on the timer. + * + * NOTE: This function may execute at a high rate with no timer running (as + * when pre-emption is enabled and disabled). + * + * Input Parameters: + * oneshot Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * sam_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 sam_oneshot_cancel(struct sam_oneshot_s *oneshot, struct timespec *ts); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_SAMV7_ONESHOT */ +#endif /* __ARCH_ARM_SRC_SAMV7_SAM_ONESHOT_H */ diff --git a/arch/arm/src/samv7/sam_tc.c b/arch/arm/src/samv7/sam_tc.c index 2ccacb0872..bd87786147 100644 --- a/arch/arm/src/samv7/sam_tc.c +++ b/arch/arm/src/samv7/sam_tc.c @@ -8,7 +8,7 @@ * * SAMV71 Series Data Sheet * NuttX SAMA5 timer/counter driver - * Atmel NoOS sample code for the SAMA5. + * Atmel NoOS sample code for the SAMA5D3. * * The Atmel sample code has a BSD compatible license that requires this * copyright notice: diff --git a/arch/arm/src/samv7/sam_tickless.c b/arch/arm/src/samv7/sam_tickless.c new file mode 100644 index 0000000000..c8f584ca55 --- /dev/null +++ b/arch/arm/src/samv7/sam_tickless.c @@ -0,0 +1,391 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_tickless.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +/**************************************************************************** + * Tickless OS Support. + * + * When CONFIG_SCHED_TICKLESS is enabled, all support for timer interrupts + * is suppressed and the platform specific code is expected to provide the + * following custom functions. + * + * void up_timer_initialize(void): Initializes the timer facilities. Called + * early in the initialization sequence (by up_intialize()). + * int up_timer_gettime(FAR struct timespec *ts): Returns the current + * time from the platform specific time source. + * int up_timer_cancel(void): Cancels the interval timer. + * int up_timer_start(FAR const struct timespec *ts): Start (or re-starts) + * the interval timer. + * + * The RTOS will provide the following interfaces for use by the platform- + * specific interval timer implementation: + * + * void sched_timer_expiration(void): Called by the platform-specific + * logic when the interval timer expires. + * + ****************************************************************************/ +/**************************************************************************** + * SAMV7 Timer Usage + * + * This current implementation uses two timers: A one-shot timer to provide + * the timed events and a free running timer to provide the current time. + * Since timers are a limited resource, that could be an issue on some + * systems. + * + * We could do the job with a single timer if we were to keep the single + * timer in a free-running at all times. The SAMV7 timer/counters have + * 16-bit counters with the capability to generate a compare interrupt when + * the timer matches a compare value but also to continue counting without + * stopping (giving another, different interrupt when the timer rolls over + * from 0xffff to zero). So we could potentially just set the compare at + * the number of ticks you want PLUS the current value of timer. Then you + * could have both with a single timer: An interval timer and a free- + * running counter with the same timer! + * + * Patches are welcome! + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "sam_oneshot.h" +#include "sam_freerun.h" + +#ifdef CONFIG_SCHED_TICKLESS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_SAMV7_HAVE_TC +# error Timer/counters must be selected for the Tickless OS option +#endif + +#ifndef CONFIG_SAMV7_ONESHOT +# error CONFIG_SAMV7_ONESHOT must be selected for the Tickless OS option +#endif + +#ifndef CONFIG_SAMV7_FREERUN +# error CONFIG_SAMV7_FREERUN must be selected for the Tickless OS option +#endif + +#ifndef CONFIG_SAMV7_TICKLESS_FREERUN +# error CONFIG_SAMV7_TICKLESS_FREERUN must be selected for the Tickless OS option +#endif + +#ifndef CONFIG_SAMV7_TICKLESS_ONESHOT +# error CONFIG_SAMV7_TICKLESS_ONESHOT must be selected for the Tickless OS option +#endif + +#if CONFIG_SAMV7_TICKLESS_ONESHOT == 0 && !defined(CONFIG_SAMV7_TC0) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 0 && CONFIG_SAMV7_TC0 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 1 && !defined(CONFIG_SAMV7_TC0) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 1 && CONFIG_SAMV7_TC0 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 2 && !defined(CONFIG_SAMV7_TC0) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 2 && CONFIG_SAMV7_TC0 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 3 && !defined(CONFIG_SAMV7_TC1) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 3 && CONFIG_SAMV7_TC1 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 4 && !defined(CONFIG_SAMV7_TC1) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 4 && CONFIG_SAMV7_TC1 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 5 && !defined(CONFIG_SAMV7_TC1) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 5 && CONFIG_SAMV7_TC1 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 6 && !defined(CONFIG_SAMV7_TC2) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 6 && CONFIG_SAMV7_TC2 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 7 && !defined(CONFIG_SAMV7_TC2) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 7 && CONFIG_SAMV7_TC2 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 8 && !defined(CONFIG_SAMV7_TC2) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 8 && CONFIG_SAMV7_TC2 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 9 && !defined(CONFIG_SAMV7_TC3) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 9 && CONFIG_SAMV7_TC3 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 10 && !defined(CONFIG_SAMV7_TC3) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 10 && CONFIG_SAMV7_TC3 not selected +#elif CONFIG_SAMV7_TICKLESS_ONESHOT == 11 && !defined(CONFIG_SAMV7_TC3) +# error CONFIG_SAMV7_TICKLESS_ONESHOT == 11 && CONFIG_SAMV7_TC3 not selected +#endif + +#if CONFIG_SAMV7_TICKLESS_ONESHOT < 0 || CONFIG_SAMV7_TICKLESS_ONESHOT > 11 +# error CONFIG_SAMV7_TICKLESS_ONESHOT is not valid +#endif + +#if CONFIG_SAMV7_TICKLESS_FREERUN == 0 && !defined(CONFIG_SAMV7_TC0) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 0 && CONFIG_SAMV7_TC0 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 1 && !defined(CONFIG_SAMV7_TC0) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 1 && CONFIG_SAMV7_TC0 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 2 && !defined(CONFIG_SAMV7_TC0) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 2 && CONFIG_SAMV7_TC0 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 3 && !defined(CONFIG_SAMV7_TC1) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 3 && CONFIG_SAMV7_TC1 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 4 && !defined(CONFIG_SAMV7_TC1) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 4 && CONFIG_SAMV7_TC1 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 5 && !defined(CONFIG_SAMV7_TC1) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 5 && CONFIG_SAMV7_TC1 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 6 && !defined(CONFIG_SAMV7_TC2) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 6 && CONFIG_SAMV7_TC2 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 7 && !defined(CONFIG_SAMV7_TC2) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 7 && CONFIG_SAMV7_TC2 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 8 && !defined(CONFIG_SAMV7_TC2) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 8 && CONFIG_SAMV7_TC2 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 9 && !defined(CONFIG_SAMV7_TC3) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 9 && CONFIG_SAMV7_TC3 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 10 && !defined(CONFIG_SAMV7_TC3) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 10 && CONFIG_SAMV7_TC3 not selected +#elif CONFIG_SAMV7_TICKLESS_FREERUN == 11 && !defined(CONFIG_SAMV7_TC3) +# error CONFIG_SAMV7_TICKLESS_FREERUN == 11 && CONFIG_SAMV7_TC3 not selected +#endif + +#if CONFIG_SAMV7_TICKLESS_FREERUN < 0 || CONFIG_SAMV7_TICKLESS_FREERUN > 11 +# error CONFIG_SAMV7_TICKLESS_FREERUN is not valid +#endif + +#if CONFIG_SAMV7_TICKLESS_FREERUN == CONFIG_SAMV7_TICKLESS_ONESHOT +# error CONFIG_SAMV7_TICKLESS_FREERUN is the same as CONFIG_SAMV7_TICKLESS_ONESHOT +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sam_tickless_s +{ + struct sam_oneshot_s oneshot; + struct sam_freerun_s freerun; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct sam_tickless_s g_tickless; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_oneshot_handler + * + * Description: + * Called when the one shot timer expires + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in the initialization sequence before any special + * concurrency protections are required. + * + ****************************************************************************/ + +static void sam_oneshot_handler(void *arg) +{ + tcllvdbg("Expired...\n"); + sched_timer_expiration(); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_timer_initialize + * + * Description: + * Initializes all platform-specific timer facilities. This function is + * called early in the initialization sequence by up_intialize(). + * On return, the current up-time should be available from + * up_timer_gettime() and the interval timer is ready for use (but not + * actively timing. + * + * Provided by platform-specific code and called from the architecture- + * specific logic. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in the initialization sequence before any special + * concurrency protections are required. + * + ****************************************************************************/ + +void up_timer_initialize(void) +{ + int ret; + + /* Initialize the one-shot timer */ + + ret = sam_oneshot_initialize(&g_tickless.oneshot, + CONFIG_SAMV7_TICKLESS_ONESHOT, + CONFIG_USEC_PER_TICK); + if (ret < 0) + { + tclldbg("ERROR: sam_oneshot_initialize failed\n"); + PANIC(); + } + + /* Initialize the free-running timer */ + + ret = sam_freerun_initialize(&g_tickless.freerun, + CONFIG_SAMV7_TICKLESS_FREERUN, + CONFIG_USEC_PER_TICK); + if (ret < 0) + { + tclldbg("ERROR: sam_freerun_initialize failed\n"); + PANIC(); + } +} + +/**************************************************************************** + * Name: up_timer_gettime + * + * Description: + * Return the elapsed time since power-up (or, more correctly, since + * up_timer_initialize() was called). This function is functionally + * equivalent to: + * + * int clock_gettime(clockid_t clockid, FAR struct timespec *ts); + * + * when clockid is CLOCK_MONOTONIC. + * + * This function provides the basis for reporting the current time and + * also is used to eliminate error build-up from small errors in interval + * time calculations. + * + * Provided by platform-specific code and called from the RTOS base code. + * + * Input Parameters: + * ts - Provides the location in which to return the up-time. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + * Assumptions: + * Called from the the normal tasking context. The implementation must + * provide whatever mutual exclusion is necessary for correct operation. + * This can include disabling interrupts in order to assure atomic register + * operations. + * + ****************************************************************************/ + +int up_timer_gettime(FAR struct timespec *ts) +{ + return sam_freerun_counter(&g_tickless.freerun, ts); +} + +/**************************************************************************** + * Name: up_timer_cancel + * + * Description: + * Cancel the interval timer and return the time remaining on the timer. + * These two steps need to be as nearly atomic as possible. + * sched_timer_expiration() will not be called unless the timer is + * restarted with up_timer_start(). + * + * If, as a race condition, the timer has already expired when this + * function is called, then that pending interrupt must be cleared so + * that up_timer_start() and the remaining time of zero should be + * returned. + * + * NOTE: This function may execute at a high rate with no timer running (as + * when pre-emption is enabled and disabled). + * + * Provided by platform-specific code and called from the RTOS base code. + * + * Input Parameters: + * ts - Location to return the remaining time. Zero should be returned + * if the timer is not active. 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. + * + * Assumptions: + * May be called from interrupt level handling or from the normal tasking + * level. Interrupts may need to be disabled internally to assure + * non-reentrancy. + * + ****************************************************************************/ + +int up_timer_cancel(FAR struct timespec *ts) +{ + return sam_oneshot_cancel(&g_tickless.oneshot, ts); +} + +/**************************************************************************** + * Name: up_timer_start + * + * Description: + * Start the interval timer. sched_timer_expiration() will be + * called at the completion of the timeout (unless up_timer_cancel + * is called to stop the timing. + * + * Provided by platform-specific code and called from the RTOS base code. + * + * Input Parameters: + * ts - Provides the time interval until sched_timer_expiration() is + * called. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + * Assumptions: + * May be called from interrupt level handling or from the normal tasking + * level. Interrupts may need to be disabled internally to assure + * non-reentrancy. + * + ****************************************************************************/ + +int up_timer_start(FAR const struct timespec *ts) +{ + return sam_oneshot_start(&g_tickless.oneshot, sam_oneshot_handler, NULL, ts); +} +#endif /* CONFIG_SCHED_TICKLESS */