diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig index aa400b48b9..1d854843ee 100644 --- a/arch/arm/src/sama5/Kconfig +++ b/arch/arm/src/sama5/Kconfig @@ -3552,6 +3552,34 @@ config SAMA5_ONESHOT Enable a wrapper around the low level timer/counter functions to support one-shot timer. +config SAMA5_FREERUN + bool "TC free-running wrapper" + default n if !SCHED_TICKLESS + default y if SCHED_TICKLESS + ---help--- + Enable a wrapper around the low level timer/counter functions to + support a free-running timer. + +if SCHED_TICKLESS + +config SAMA5_TICKLESS_ONESHOT + int "Tickless one-shot timer channel" + range 0 8 + default 0 + ---help--- + If the Tickless OS feature is enabled, the one clock must be + assigned to provided the one-shot timer needed by the OS. + +config SAMA5_TICKLESS_FREERUN + int "Tickless free-running timer channel" + range 0 8 + default 0 + ---help--- + If the Tickless OS feature is enabled, the one clock must be + assigned to provided the free-running timer needed by the OS. + +endif + config SAMA5_TC_DEBUG bool "TC debug" depends on DEBUG diff --git a/arch/arm/src/sama5/Make.defs b/arch/arm/src/sama5/Make.defs index 4bffa4e481..cd08660fe4 100644 --- a/arch/arm/src/sama5/Make.defs +++ b/arch/arm/src/sama5/Make.defs @@ -255,6 +255,9 @@ CHIP_CSRCS += sam_tc.c ifeq ($(CONFIG_SAMA5_ONESHOT),y) CHIP_CSRCS += sam_oneshot.c endif +ifeq ($(CONFIG_SAMA5_FREERUN),y) +CHIP_CSRCS += sam_freerun.c +endif endif ifeq ($(CONFIG_SAMA5_EBICS0_NAND),y) diff --git a/arch/arm/src/sama5/sam_freerun.c b/arch/arm/src/sama5/sam_freerun.c new file mode 100644 index 0000000000..514e227781 --- /dev/null +++ b/arch/arm/src/sama5/sam_freerun.c @@ -0,0 +1,333 @@ +/**************************************************************************** + * arch/arm/src/sama5/sam_freerun.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: + * + * SAMA5D3 Series Data Sheet + * 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_freerun.h" + +#ifdef CONFIG_SAMA5_ONESHOT + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_SAMA5_TC_DEBUG +# define tcdbg dbg +# define tcvdbg vdbg +#else +# define tcdbg(x...) +# define tcvdbg(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * 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: + * handle - 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 handle, void *arg, uint32_t sr) +{ + struct sam_freerun_s *freerun = (struct sam_freerun_s *)arg; + DEBUGASSERT(freerun && freerun->overflow < UINT16_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/sama5/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 = 1000000 / (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->handle = sam_tc_allocate(chan, cmr); + if (!freerun->handle) + { + 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->resolution = resolution; + + /* Set up to receive the callback when the counter overflow occurs */ + + (void)sam_tc_attach(freerun->handle, sam_freerun_handler, freerun, + TC_INT_COVFS); + + /* Start the counter */ + + sam_tc_start(freerun->handle); + + 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; + + /* Temporarily disable the overflow counter */ + + flags = irqsave(); + overflow = freerun->overflow; + counter = sam_tc_getcounter(freerun->handle); + sr = sam_tc_getpending(freerun->handle); + verify = sam_tc_getcounter(freerun->handle); + irqrestore(flags); + + tcvdbg("counter=%lu (%lu) overflow=%lu, sr=%08lx\n", + (unsigned long)counter, (unsigned long)verify, + (unsigned long)overflow, (unsigned long)sr); + + /* If an interrupt was pending before we re-enabled interrupts, + * then our value of 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; + + tcvdbg("counter=%lu overflow=%lu\n", + (unsigned long)counter, (unsigned long)overflow); + } + + /* Convert the whole thing to units of microseconds */ + + usec = (((uint64_t)overflow << 32) + (uint64_t)counter) * + freerun->resolution; + + /* And return the value of the timer */ + + sec = (uint32_t)(usec / 1000000); + ts->tv_sec = sec; + ts->tv_nsec = (usec - (sec * 1000000)) * 1000; + + tcvdbg("usec=%016llx 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) +{ + irqstate_t flags; + + /* Now we can disable the timer interrupt and disable the timer. */ + + sam_tc_attach(freerun->handle, NULL, NULL, 0); + sam_tc_stop(freerun->handle); + + /* Free the timer */ + + sam_tc_free(freerun->handle); + irqrestore(flags); + return OK; +} + +#endif /* CONFIG_SAMA5_ONESHOT */ diff --git a/arch/arm/src/sama5/sam_freerun.h b/arch/arm/src/sama5/sam_freerun.h new file mode 100644 index 0000000000..48ce56e9ae --- /dev/null +++ b/arch/arm/src/sama5/sam_freerun.h @@ -0,0 +1,161 @@ +/**************************************************************************** + * arch/arm/src/sama5/sam_freerun.h + * + * Copyright (C) 2014 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_SAMA5_SAM_FREERUN_H +#define __ARCH_ARM_SRC_SAMA5_SAM_FREERUN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sam_tc.h" + +#ifdef CONFIG_SAMA5_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 */ + uint16_t resolution; /* Timer resolution in microseconds */ + uint16_t overflow; /* Timer counter overflow */ + TC_HANDLE handle; /* 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/sama5/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_SAMA5_FREERUN */ +#endif /* __ARCH_ARM_SRC_SAMA5_SAM_FREERUN_H */