summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-10-24 12:35:42 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-10-24 12:35:42 -0600
commite545be9cad1166568e88e9a569b23dd26a78ea86 (patch)
tree6a5f290b630cb84208cdd1588f0f27995041f77b
parentbd5634083301f3fc7070ec26fef3340aeeba8d28 (diff)
downloadpx4-nuttx-e545be9cad1166568e88e9a569b23dd26a78ea86.tar.gz
px4-nuttx-e545be9cad1166568e88e9a569b23dd26a78ea86.tar.bz2
px4-nuttx-e545be9cad1166568e88e9a569b23dd26a78ea86.zip
SAMA5: Hook in timer/counter logic so that it can driver periodic ADC sampling
-rw-r--r--nuttx/ChangeLog4
-rw-r--r--nuttx/arch/arm/src/sama5/Kconfig97
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_tc.h4
-rw-r--r--nuttx/arch/arm/src/sama5/sam_adc.c105
-rw-r--r--nuttx/arch/arm/src/sama5/sam_can.c2
-rw-r--r--nuttx/arch/arm/src/sama5/sam_tc.c402
-rw-r--r--nuttx/arch/arm/src/sama5/sam_tc.h66
7 files changed, 603 insertions, 77 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 13a8a3def..dfe62d637 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -5871,4 +5871,6 @@
(2013-10-24).
* configs/olimex-stm32-p207 and other files: Support for the Olimex
STM32 P207 board added by Martin Lederhilger (2017-10-24).
-
+ * arch/arm/src/sama5/sam_adc.c, sam_tc.c and sam_tc.h: Hook in the
+ timer/counter logic so that it can driver periodic ADC sampling
+ (2013-10-24).
diff --git a/nuttx/arch/arm/src/sama5/Kconfig b/nuttx/arch/arm/src/sama5/Kconfig
index 8da6191b2..d1b947cf7 100644
--- a/nuttx/arch/arm/src/sama5/Kconfig
+++ b/nuttx/arch/arm/src/sama5/Kconfig
@@ -2070,6 +2070,7 @@ config SAMA5_ADC_ADTRG
config SAMA5_ADC_TIOATRIG
bool "TC0 ouput A trigger"
+ depends on SAMA5_TC0
---help---
A-to-D Conversion is initiated the A output from one of
Timer/Counter 0 channels.
@@ -2100,12 +2101,20 @@ endchoice # ADTRG edge
if SAMA5_ADC_TIOATRIG
+config SAMA5_ADC_TIOAFREQ
+ int "ADC sampling frequency"
+ default 1
+ ---help---
+ This setting provides the rate at which the timer will driver ADC
+ sampling.
+
choice
prompt "TC0 channel"
default SAMA5_ADC_TIOA0TRIG
config SAMA5_ADC_TIOA0TRIG
bool "TC0 Channel 0 Output A"
+ select SAMA5_TC0_TIOA0
---help---
A-to-D conversion is triggered by the TC0 channel 0 output A signal.
This output must be enabled independently in the Timer/Counter
@@ -2113,6 +2122,7 @@ config SAMA5_ADC_TIOA0TRIG
config SAMA5_ADC_TIOA1TRIG
bool "TC0 Channel 1 Output A"
+ select SAMA5_TC0_TIOA1
---help---
A-to-D conversion is triggered by the TC0 channel 1 output A signal.
This output must be enabled independently in the Timer/Counter
@@ -2120,6 +2130,7 @@ config SAMA5_ADC_TIOA1TRIG
config SAMA5_ADC_TIOA2TRIG
bool "TC0 Channel 2 Output A"
+ select SAMA5_TC0_TIOA2
---help---
A-to-D conversion is triggered by the TC0 channel 2 output A signal.
This output must be enabled independently in the Timer/Counter
@@ -2161,6 +2172,92 @@ config SAMA5_ADC_REGDEBUG
endmenu # ADC Configuration
+if SAMA5_TC0 || SAMA5_TC1
+menu "Timer/counter Configuration"
+
+if SAMA5_TC0
+
+config SAMA5_TC0_CLK0
+ bool "Enable TC0 channel 0 clock input pin"
+ default n
+
+config SAMA5_TC0_TIOA0
+ bool "Enable TC0 channel 0 ouput A"
+ default n
+
+config SAMA5_TC0_TIOB0
+ bool "Enable TC0 channel 0 ouput B"
+ default n
+
+config SAMA5_TC0_CLK1
+ bool "Enable TC0 channel 1 clock input pin"
+ default n
+
+config SAMA5_TC0_TIOA1
+ bool "Enable TC0 channel 1 ouput A"
+ default n
+
+config SAMA5_TC0_TIOB1
+ bool "Enable TC0 channel 1 ouput B"
+ default n
+
+config SAMA5_TC0_CLK2
+ bool "Enable TC0 channel 2 clock input pin"
+ default n
+
+config SAMA5_TC0_TIOA2
+ bool "Enable TC0 channel 2 ouput A"
+ default n
+
+config SAMA5_TC0_TIOB2
+ bool "Enable TC0 channel 2 ouput B"
+ default n
+
+endif # SAMA5_TC0
+
+if SAMA5_TC1
+
+config SAMA5_TC1_CLK3
+ bool "Enable TC1 channel 3 clock input pin"
+ default n
+
+config SAMA5_TC1_TIOA3
+ bool "Enable TC1 channel 3 ouput A"
+ default n
+
+config SAMA5_TC1_TIOB3
+ bool "Enable TC1 channel 3 ouput B"
+ default n
+
+config SAMA5_TC1_CLK4
+ bool "Enable TC1 channel 4 clock input pin"
+ default n
+
+config SAMA5_TC1_TIOA4
+ bool "Enable TC1 channel 4 ouput A"
+ default n
+
+config SAMA5_TC1_TIOB4
+ bool "Enable TC1 channel 4 ouput B"
+ default n
+
+config SAMA5_TC1_CLK5
+ bool "Enable TC1 channel 5 clock input pin"
+ default n
+
+config SAMA5_TC1_TIOA5
+ bool "Enable TC1 channel 5 ouput A"
+ default n
+
+config SAMA5_TC1_TIOB5
+ bool "Enable TC1 channel 5 ouput B"
+ default n
+
+endif # SAMA5_TC1
+
+endmenu # Timer/counter Configuration
+endif # SAMA5_TC0 || SAMA5_TC1
+
menu "Touchscreen configuration"
config SAMA5_TSD
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_tc.h b/nuttx/arch/arm/src/sama5/chip/sam_tc.h
index bf8fc1817..fcbb194c7 100644
--- a/nuttx/arch/arm/src/sama5/chip/sam_tc.h
+++ b/nuttx/arch/arm/src/sama5/chip/sam_tc.h
@@ -46,6 +46,10 @@
/************************************************************************************
* Pre-processor Definitions
************************************************************************************/
+
+#define SAM_TC_NCHANNELS 3 /* Number of channels per TC peripheral */
+#define SAM_TC_MAXPERCLK 66000000 /* Maximum peripheral input clock frequency */
+
/* TC Register Offsets **************************************************************/
#define SAM_TC_CHAN_OFFSET(n) ((n) << 6) /* Channel n offset */
diff --git a/nuttx/arch/arm/src/sama5/sam_adc.c b/nuttx/arch/arm/src/sama5/sam_adc.c
index c9d47daea..2201f71b5 100644
--- a/nuttx/arch/arm/src/sama5/sam_adc.c
+++ b/nuttx/arch/arm/src/sama5/sam_adc.c
@@ -71,6 +71,7 @@
#include "chip/sam_pmc.h"
#include "sam_periphclks.h"
#include "sam_dmac.h"
+#include "sam_tc.h"
#include "sam_tsd.h"
#include "sam_adc.h"
@@ -379,6 +380,9 @@ struct sam_adc_s
#ifdef CONFIG_SAMA5_ADC_DMA
DMA_HANDLE dma; /* Handle for DMA channel */
#endif
+#ifdef CONFIG_SAMA5_ADC_TIOATRIG
+ TC_HANDLE tc; /* Handle for the timer channel */
+#endif
/* DMA sample data buffer */
@@ -435,6 +439,10 @@ static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg);
/* Initialization/Configuration */
+#ifdef CONFIG_SAMA5_ADC_TIOATRIG
+static void sam_adc_settimer(struct sam_adc_s *priv, uint32_t frequency,
+ int channel, boot tioa);
+#endif
static void sam_adc_trigger(struct sam_adc_s *priv);
static void sam_adc_autocalibrate(struct sam_adc_s *priv);
static void sam_adc_offset(struct sam_adc_s *priv);
@@ -878,6 +886,12 @@ static void sam_adc_reset(struct adc_dev_s *dev)
dma_stop(priv->dma);
+ /* Stop an release any timer */
+
+#ifdef CONFIG_SAMA5_ADC_TIOATRIG
+ sam_adc_freetimer(priv);
+#endif
+
/* Disable all EOC interrupts */
sam_adc_putreg(priv, SAM_ADC_IDR, ADC_INT_EOCALL);
@@ -1068,6 +1082,85 @@ static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg)
****************************************************************************/
/****************************************************************************
+ * Name: sam_adc_settimer
+ *
+ * Description:
+ * Configure a timer to trigger the sampling periodically
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_ADC_TIOATRIG
+static void sam_adc_settimer(struct sam_adc_s *priv, uint32_t frequency,
+ int channel)
+{
+ uint32_t div;
+ uint32_t tcclks;
+
+ /* Configure TC for a 1Hz frequency and trigger on RC compare. */
+
+ ret = sam_tc_divisor(frequency, &div, &tcclks);
+ if (ret < 0)
+ {
+ adbg("ERROR: sam_tc_divisor failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Set the timer/counter waveform mode the the clock input slected by
+ * sam_tc_divisor()
+ */
+
+ mode = ((tcclks << TC_CMR_TCCLKS_SHIFT) | /* Use selected TCCLKS value */
+ TC_CMR_WAVSEL_UPRC | /* UP mode w/ trigger on RC Compare */
+ TC_CMR_WAVE | /* Wave mode */
+ TC_CMR_ACPA_CLEAR | /* RA Compare Effect on TIOA: Clear */
+ TC_CMR_ACPC_SET); /* RC effect on TIOA: Set
+
+ /* Now allocate and configure the channel */
+
+ priv->tc = sam_tc_allocate(channel, mode);
+ if (!priv->tc)
+ {
+ adbg("ERROR: Failed to allocate channel %d mode %08x\n", channel, mode);
+ return -EINVAL;
+ }
+
+ /* Set up TC_RA and TC_RC */
+
+ sam_tc_setregister(priv->tc, TC_REGA, div / 2);
+ sam_tc_setregister(priv->tc, TC_REGC, div);
+
+ /* And start the timer */
+
+ sam_tc_start(priv->tc);
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_adc_settimer
+ *
+ * Description:
+ * Configure a timer to trigger the sampling periodically
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_ADC_TIOATRIG
+static void sam_adc_settimer(struct sam_adc_s *priv, uint32_t frequency,
+ int channel)
+{
+ /* Is a timer allocated? */
+
+ if (priv->tc)
+ {
+ /* Yes.. stop it and free it */
+
+ sam_tc_stop(priv->tc);
+ sam_tc_free(priv->tc);
+ priv->tc = NULL;
+ }
+}
+#endif
+
+/****************************************************************************
* Name: sam_adc_trigger
*
* Description:
@@ -1119,6 +1212,18 @@ static void sam_adc_trigger(struct sam_adc_s *priv)
sam_adc_putreg(priv, SAM_ADC_TRGR, regval);
#elif defined(CONFIG_SAMA5_ADC_TIOATRIG)
+ /* Start the timer */
+
+#if defined(CONFIG_SAMA5_ADC_TIOA0TRIG)
+ sam_adc_settimer(priv, CONFIG_SAMA5_ADC_TIOAFREQ, TC_CHAN0);
+#elif defined(CONFIG_SAMA5_ADC_TIOA1TRIG)
+ sam_adc_settimer(priv, CONFIG_SAMA5_ADC_TIOAFREQ, TC_CHAN1);
+#elif defined(CONFIG_SAMA5_ADC_TIOA2TRIG)
+ sam_adc_settimer(priv, CONFIG_SAMA5_ADC_TIOAFREQ, TC_CHAN2);
+#else
+# error Timer/counter for trigger not defined
+#endif
+
/* Configure to trigger using Timer/counter 0, channel 1, 2, or 3.
* NOTE: This trigger option depends on having properly configuer
* timer/counter 0 to provide this output. That is done independently
diff --git a/nuttx/arch/arm/src/sama5/sam_can.c b/nuttx/arch/arm/src/sama5/sam_can.c
index 7ce3a15bb..5bd302fb0 100644
--- a/nuttx/arch/arm/src/sama5/sam_can.c
+++ b/nuttx/arch/arm/src/sama5/sam_can.c
@@ -116,7 +116,7 @@
# define CAN_FREQUENCY (BOARD_MCK_FREQUENCY >> 3)
# define CAN_PCR_DIV PMC_PCR_DIV8
#else
-# error Cannot realize ADC input frequency
+# error Cannot realize CAN input frequency
#endif
/* Debug ********************************************************************/
diff --git a/nuttx/arch/arm/src/sama5/sam_tc.c b/nuttx/arch/arm/src/sama5/sam_tc.c
index 4007cdcfd..7e2e93d72 100644
--- a/nuttx/arch/arm/src/sama5/sam_tc.c
+++ b/nuttx/arch/arm/src/sama5/sam_tc.c
@@ -57,15 +57,63 @@
#include <assert.h>
#include <errno.h>
+#include <arch/board/board.h>
+
#include "up_arch.h"
#include "sam_periphclks.h"
+#include "chip/sam_pmc.h"
+#include "sam_pio.h"
#include "sam_tc.h"
#if defined(CONFIG_SAMA5_TC0) || defined(CONFIG_SAMA5_TC1)
/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Clocking */
+
+#if BOARD_MCK_FREQUENCY <= SAM_TC_MAXPERCLK
+# define TC_FREQUENCY BOARD_MCK_FREQUENCY
+# define TC_PCR_DIV PMC_PCR_DIV1
+#elif (BOARD_MCK_FREQUENCY >> 1) <= SAM_TC_MAXPERCLK
+# define TC_FREQUENCY (BOARD_MCK_FREQUENCY >> 1)
+# define TC_PCR_DIV PMC_PCR_DIV2
+#elif (BOARD_MCK_FREQUENCY >> 2) <= SAM_TC_MAXPERCLK
+# define TC_FREQUENCY (BOARD_MCK_FREQUENCY >> 2)
+# define TC_PCR_DIV PMC_PCR_DIV4
+#elif (BOARD_MCK_FREQUENCY >> 3) <= SAM_TC_MAXPERCLK
+# define TC_FREQUENCY (BOARD_MCK_FREQUENCY >> 3)
+# define TC_PCR_DIV PMC_PCR_DIV8
+#else
+# error Cannot realize TC input frequency
+#endif
+
+/****************************************************************************
* Private Types
****************************************************************************/
+/* This structure describes the static configuration of a TC channel */
+
+struct sam_chconfig_s
+{
+ uintptr_t base; /* Channel register base address */
+ pio_pinset_t clkset; /* CLK input PIO configuration */
+ pio_pinset_t tioaset; /* Output A PIO configuration */
+ pio_pinset_t tiobset; /* Output B PIO configuration */
+};
+
+/* This structure describes the static configuration of a TC */
+
+struct sam_tcconfig_s
+{
+ uintptr_t base; /* TC register base address */
+ uint8_t pid; /* Peripheral ID */
+ uint8_t chfirst; /* First channel number */
+
+ /* Channels */
+
+ struct sam_chconfig_s channel[3];
+};
/* This structure describes one timer counter channel */
@@ -134,14 +182,187 @@ static inline struct sam_chan_s *sam_tc_initialize(int channel);
/****************************************************************************
* Private Data
****************************************************************************/
+/* Static timer configuration */
+
+#ifdef CONFIG_SAMA5_TC0
+static const struct sam_tcconfig_s g_tc012config =
+{
+ .base = SAM_TC012_VBASE,
+ .pid = SAM_PID_TC0,
+ .chfirst = 0,
+ .channel =
+ {
+ {
+ SAM_TC012_CHAN_BASE(0),
+#ifdef CONFIG_SAMA5_TC0_CLK0
+ .clkset = PIO_TC0_CLK,
+#else
+ .clkset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC0_TIOA0
+ .tioaset = PIO_TC0_IOA,
+#else
+ .tioaset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC0_TIOB0
+ .tiobset = PIO_TC0_IOB,
+#else
+ .tiobset = 0,
+#endif
+ },
+ {
+ SAM_TC012_CHAN_BASE(1),
+#ifdef CONFIG_SAMA5_TC0_CLK1
+ .clkset = PIO_TC1_CLK,
+#else
+ .clkset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC0_TIOA1
+ .tioaset = PIO_TC1_IOA,
+#else
+ .tioaset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC0_TIOB1
+ .tiobset = PIO_TC1_IOB,
+#else
+ .tiobset = 0,
+#endif
+ },
+ {
+ SAM_TC012_CHAN_BASE(2),
+#ifdef CONFIG_SAMA5_TC0_CLK2
+ .clkset = PIO_TC2_CLK,
+#else
+ .clkset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC0_TIOA2
+ .tioaset = PIO_TC2_IOA,
+#else
+ .tioaset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC0_TIOB2
+ .tiobset = PIO_TC2_IOB,
+#else
+ .tiobset = 0,
+#endif
+ },
+ },
+};
+#endif
+
+#ifdef CONFIG_SAMA5_TC1
+static const struct sam_tcconfig_s g_tc345config =
+{
+ .base = SAM_TC345_VBASE,
+ .pid = SAM_PID_TC1,
+ .chfirst = 3,
+ .channel =
+ {
+ {
+ SAM_TC345_CHAN_BASE(3),
+#ifdef CONFIG_SAMA5_TC1_CLK3
+ .clkset = PIO_TC3_CLK,
+#else
+ .clkset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC1_TIOA3
+ .tioaset = PIO_TC3_IOA,
+#else
+ .tioaset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC1_TIOB3
+ .tiobset = PIO_TC3_IOB,
+#else
+ .tiobset = 0,
+#endif
+ },
+ {
+ SAM_TC345_CHAN_BASE(4),
+#ifdef CONFIG_SAMA5_TC1_CLK4
+ .clkset = PIO_TC4_CLK,
+#else
+ .clkset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC1_TIOA4
+ .tioaset = PIO_TC4_IOA,
+#else
+ .tioaset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC1_TIOB4
+ .tiobset = PIO_TC4_IOB,
+#else
+ .tiobset = 0,
+#endif
+ },
+ {
+ SAM_TC345_CHAN_BASE(5),
+#ifdef CONFIG_SAMA5_TC1_CLK5
+ .clkset = PIO_TC5_CLK,
+#else
+ .clkset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC1_TIOA5
+ .tioaset = PIO_TC5_IOA,
+#else
+ .tioaset = 0,
+#endif
+#ifdef CONFIG_SAMA5_TC1_TIOB5
+ .tiobset = PIO_TC5_IOB,
+#else
+ .tiobset = 0,
+#endif
+ },
+ },
+};
+#endif
+
+/* Timer/counter state */
#ifdef CONFIG_SAMA5_TC0
static struct sam_tc_s g_tc012;
#endif
+
#ifdef CONFIG_SAMA5_TC1
static struct sam_tc_s g_tc345;
#endif
+/* TC frequency data. This table provides the frequency for each selection of TCCLK */
+
+#define TC_NDIVIDERS 5
+
+/* This is the list of divider values */
+
+static const uint16_t g_divider[TC_NDIVIDERS] =
+{
+ 2, /* TIMER_CLOCK1 -> div2 */
+ 8, /* TIMER_CLOCK2 -> div8 */
+ 32, /* TIMER_CLOCK3 -> div32 */
+ 128, /* TIMER_CLOCK4 -> div128 */
+ TC_FREQUENCY / 32768 /* TIMER_CLOCK5 -> slow clock (not really a divider) */
+};
+
+/* This is the list of divided down frequencies */
+
+static const uint32_t g_divfreq[TC_NDIVIDERS] =
+{
+ TC_FREQUENCY / 2, /* TIMER_CLOCK1 -> div2 */
+ TC_FREQUENCY / 8, /* TIMER_CLOCK2 -> div8 */
+ TC_FREQUENCY / 32, /* TIMER_CLOCK3 -> div32 */
+ TC_FREQUENCY / 128, /* TIMER_CLOCK4 -> div128 */
+ 32768 /* TIMER_CLOCK5 -> slow clock */
+};
+
+/* TC register lookup used by sam_tc_setregister */
+
+#define TC_NREGISTERS 3
+
+static const uint8_t g_regoffset[TC_NREGISTERS] =
+{
+ SAM_TC_RA_OFFSET, /* Register A */
+ SAM_TC_RB_OFFSET, /* Register B */
+ SAM_TC_RC_OFFSET /* Register C */
+};
+
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -352,14 +573,13 @@ static inline void sam_chan_putreg(struct sam_chan_s *chan, unsigned int offset,
static inline struct sam_chan_s *sam_tc_initialize(int channel)
{
- static struct sam_tc_s *tc;
- static struct sam_chan_s *chan;
+ FAR struct sam_tc_s *tc;
+ FAR const struct sam_tcconfig_s *tcconfig;
+ FAR struct sam_chan_s *chan;
+ FAR const struct sam_chconfig_s *chconfig;
irqstate_t flags;
- uintptr_t tcbase;
- uintptr_t chbase;
- int chfirst;
- int chndx;
- int pid;
+ uint32_t regval;
+ uint8_t ch;
int i;
/* Select the timer/counter and get the index associated with the
@@ -369,34 +589,16 @@ static inline struct sam_chan_s *sam_tc_initialize(int channel)
#ifdef CONFIG_SAMA5_TC0
if (channel >= 0 && channel < 3)
{
- tc = &g_tc012;
- chndx = channel;
-
- /* These are only needed in the case where we need to initialize the
- * timer/counter.
- */
-
- chfirst = 0;
- tcbase = SAM_TC012_VBASE;
- chbase = SAM_TC012_CHAN_BASE(channel);
- pid = SAM_PID_TC0;
+ tc = &g_tc012;
+ tcconfig = &g_tc012config;
}
else
#endif
#ifdef CONFIG_SAMA5_TC1
if (channel >= 3 && channel < 5)
{
- tc = &g_tc345;
- chndx = channel - 3;
-
- /* These are only needed in the case where we need to initialize the
- * timer/counter.
- */
-
- chfirst = 3;
- tcbase = SAM_TC345_VBASE;
- chbase = SAM_TC345_CHAN_BASE(channel)
- pid = SAM_PID_TC0;
+ tc = &g_tc345;
+ tcconfig = &g_tc345config;
}
else
#endif
@@ -417,21 +619,53 @@ static inline struct sam_chan_s *sam_tc_initialize(int channel)
memset(tc, 0, sizeof(struct sam_tc_s));
sem_init(&tc->exclsem, 0, 1);
- tc->base = tcbase;
- tc->pid = pid;
+ tc->base = tcconfig->base;
+ tc->pid = tcconfig->pid;
/* Initialize the channels */
- for (i = 0; i < 3; i++)
+ for (i = 0, ch = tcconfig->chfirst; i < SAM_TC_NCHANNELS; i++)
{
+ /* Initialize the channel data structure */
+
chan = &tc->channel[i];
- chan->base = chbase;
- chan->chan = chfirst++;
+ chconfig = &tcconfig->channel[i];
+
+ chan->base = chconfig->base;
+ chan->chan = ch++;
+
+ /* Configure channel input/output pins */
+
+ if (chconfig->clkset)
+ {
+ /* Configure clock input pin */
+
+ sam_configpio(chconfig->clkset);
+ }
+
+ if (chconfig->tioaset)
+ {
+ /* Configure output A pin */
+
+ sam_configpio(chconfig->tioaset);
+ }
+
+ if (chconfig->tiobset)
+ {
+ /* Configure output B pin */
+
+ sam_configpio(chconfig->tiobset);
+ }
}
+ /* Set the maximum TC peripheral clock frequency */
+
+ regval = PMC_PCR_PID(tcconfig->pid) | PMC_PCR_CMD | TC_PCR_DIV | PMC_PCR_EN;
+ putreg32(regval, SAM_PMC_PCR);
+
/* Enable clocking to the timer counter */
- sam_enableperiph0(pid);
+ sam_enableperiph0(tcconfig->pid);
/* Now the channel is initialized */
@@ -445,7 +679,7 @@ static inline struct sam_chan_s *sam_tc_initialize(int channel)
/* Get the requested channel structure */
- chan = &tc->channel[chndx];
+ chan = &tc->channel[channel - tcconfig->chfirst];
/* Is it available? */
@@ -484,7 +718,7 @@ static inline struct sam_chan_s *sam_tc_initialize(int channel)
*
****************************************************************************/
-TCHANDLE sam_tc_allocate(int channel, int mode)
+TC_HANDLE sam_tc_allocate(int channel, int mode)
{
struct sam_chan_s *chan;
@@ -514,7 +748,7 @@ TCHANDLE sam_tc_allocate(int channel, int mode)
/* Return an opaque reference to the channel */
- return (TCHANDLE)chan;
+ return (TC_HANDLE)chan;
}
/****************************************************************************
@@ -531,7 +765,7 @@ TCHANDLE sam_tc_allocate(int channel, int mode)
*
****************************************************************************/
-void sam_tc_free(TCHANDLE handle)
+void sam_tc_free(TC_HANDLE handle)
{
struct sam_chan_s *chan = (struct sam_chan_s *)handle;
DEBUGASSERT(chan && chan->inuse);
@@ -559,7 +793,7 @@ void sam_tc_free(TCHANDLE handle)
*
****************************************************************************/
-void sam_tc_start(TCHANDLE handle)
+void sam_tc_start(TC_HANDLE handle)
{
struct sam_chan_s *chan = (struct sam_chan_s *)handle;
@@ -580,7 +814,7 @@ void sam_tc_start(TCHANDLE handle)
*
****************************************************************************/
-void sam_tc_stop(TCHANDLE handle)
+void sam_tc_stop(TC_HANDLE handle)
{
struct sam_chan_s *chan = (struct sam_chan_s *)handle;
@@ -589,23 +823,70 @@ void sam_tc_stop(TCHANDLE handle)
}
/****************************************************************************
+ * Name: sam_tc_setregister
+ *
+ * Description:
+ * Set TC_RA, TC_RB, or TC_RB using the provided divisor. The actual
+ * setting in the regsiter will be the TC input frequency divided by
+ * the provided divider (which should derive from the divider returned
+ * by sam_tc_divider).
+ *
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void sam_tc_setregister(TC_HANDLE handle, int reg, unsigned int div)
+{
+ struct sam_chan_s *chan = (struct sam_chan_s *)handle;
+ DEBUGASSERT(reg < TC_NREGISTERS);
+
+ sam_chan_putreg(chan, g_regoffset[reg], TC_FREQUENCY / div);
+}
+
+/****************************************************************************
+ * Name: sam_tc_frequency
+ *
+ * Description:
+ * Return the timer input frequency, that is, the MCK frequency divided
+ * down so that the timer/counter is driven within its maximum frequency.
+ * This value needed for
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The timer input frequency.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_frequency(void)
+{
+ return TC_FREQUENCY;
+}
+
+/****************************************************************************
* Name: sam_tc_divisor
*
* Description:
* Finds the best MCK divisor given the timer frequency and MCK. The
* result is guaranteed to satisfy the following equation:
*
- * (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
+ * (Ftc / (div * 65536)) <= freq <= (Ftc / dev)
*
- * with DIV being the highest possible value.
+ * where:
+ * freq - the desitred frequency
+ * Ftc - The timer/counter input frequency
+ * div - With DIV being the highest possible value.
*
* Input Parameters:
- *
* frequency Desired timer frequency.
- * mck Master clock frequency.
* div Divisor value.
* tcclks TCCLKS field value for divisor.
- * boardmck Board clock frequency.
*
* Returned Value:
* Zero (OK) if a proper divisor has been found, otherwise a negated errno
@@ -613,46 +894,41 @@ void sam_tc_stop(TCHANDLE handle)
*
****************************************************************************/
-uint32_t sam_tc_divisor(uint32_t frequency, uint32_t mck, uint32_t *div,
- uint32_t *tcclks, uint32_t boardmck)
+int sam_tc_divisor(uint32_t frequency, uint32_t *div, uint32_t *tcclks)
{
- const uint32_t adivisors[5] = { 2, 8, 32, 128, boardmck / 32768 };
int ndx = 0;
/* Satisfy lower bound */
- while (frequency < ((mck / adivisors[ndx]) / 65536))
+ while (frequency < (g_divfreq[ndx] >> 16))
{
- ndx++;
-
- /* If no divisor can be found, return -ERANGE */
-
- if (ndx == (sizeof(adivisors)/sizeof(adivisors[0])))
+ if (++ndx > TC_NDIVIDERS)
{
+ /* If no divisor can be found, return -ERANGE */
+
return -ERANGE;
}
}
- /* Try to maximize DIV while satisfying upper bound */
+ /* Try to maximize DIV while still satisfying upper bound */
- while (ndx < 4)
+ for (; ndx < (TC_NDIVIDERS-1); ndx++)
{
-
- if (frequency > (mck / adivisors[ndx + 1]))
+ if (frequency > g_divfreq[ndx + 1])
{
break;
}
-
- ndx++;
}
- /* Store results */
+ /* Return the divider value */
if (div)
{
- *div = adivisors[ndx];
+ *div = g_divider[ndx];
}
+ /* REturn the TCCLKS selection */
+
if (tcclks)
{
*tcclks = ndx;
diff --git a/nuttx/arch/arm/src/sama5/sam_tc.h b/nuttx/arch/arm/src/sama5/sam_tc.h
index d73f3e0d1..97e7b0c34 100644
--- a/nuttx/arch/arm/src/sama5/sam_tc.h
+++ b/nuttx/arch/arm/src/sama5/sam_tc.h
@@ -62,11 +62,17 @@
#define TC_CHAN4 4
#define TC_CHAN5 5
+/* Register identifier used with sam_tc_setregister */
+
+#define TC_REGA 0
+#define TC_REGB 1
+#define TC_REGC 2
+
/****************************************************************************
* Public Types
****************************************************************************/
-typedef void *TCHANDLE;
+typedef void *TC_HANDLE;
/****************************************************************************
* Public Data
@@ -104,7 +110,7 @@ extern "C"
*
****************************************************************************/
-TCHANDLE sam_tc_allocate(int channel, int mode);
+TC_HANDLE sam_tc_allocate(int channel, int mode);
/****************************************************************************
* Name: sam_tc_free
@@ -120,7 +126,7 @@ TCHANDLE sam_tc_allocate(int channel, int mode);
*
****************************************************************************/
-void sam_tc_free(TCHANDLE handle);
+void sam_tc_free(TC_HANDLE handle);
/****************************************************************************
* Name: sam_tc_start
@@ -136,7 +142,7 @@ void sam_tc_free(TCHANDLE handle);
*
****************************************************************************/
-void sam_tc_start(TCHANDLE handle);
+void sam_tc_start(TC_HANDLE handle);
/****************************************************************************
* Name: sam_tc_stop
@@ -151,7 +157,44 @@ void sam_tc_start(TCHANDLE handle);
*
****************************************************************************/
-void sam_tc_stop(TCHANDLE handle);
+void sam_tc_stop(TC_HANDLE handle);
+
+/****************************************************************************
+ * Name: sam_tc_setregister
+ *
+ * Description:
+ * Set TC_RA, TC_RB, or TC_RB using the provided divisor. The actual
+ * setting in the regsiter will be the TC input frequency divided by
+ * the provided divider (which should derive from the divider returned
+ * by sam_tc_divider).
+ *
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void sam_tc_setregister(TC_HANDLE handle, int reg, unsigned int div);
+
+/****************************************************************************
+ * Name: sam_tc_frequency
+ *
+ * Description:
+ * Return the timer input frequency, that is, the MCK frequency divided
+ * down so that the timer/counter is driven within its maximum frequency.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The timer input frequency.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_frequency(void);
/****************************************************************************
* Name: sam_tc_divisor
@@ -160,17 +203,17 @@ void sam_tc_stop(TCHANDLE handle);
* Finds the best MCK divisor given the timer frequency and MCK. The
* result is guaranteed to satisfy the following equation:
*
- * (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
+ * (Ftc / (div * 65536)) <= freq <= (Ftc / dev)
*
- * with DIV being the highest possible value.
+ * where:
+ * freq - the desitred frequency
+ * Ftc - The timer/counter input frequency
+ * div - With DIV being the highest possible value.
*
* Input Parameters:
- *
* frequency Desired timer frequency.
- * mck Master clock frequency.
* div Divisor value.
* tcclks TCCLKS field value for divisor.
- * boardmck Board clock frequency.
*
* Returned Value:
* Zero (OK) if a proper divisor has been found, otherwise a negated errno
@@ -178,8 +221,7 @@ void sam_tc_stop(TCHANDLE handle);
*
****************************************************************************/
-uint32_t sam_tc_divisor(uint32_t frequency, uint32_t mck, uint32_t *div,
- uint32_t *tcclks, uint32_t boardmck);
+int sam_tc_divisor(uint32_t frequency, uint32_t *div, uint32_t *tcclks);
#undef EXTERN
#ifdef __cplusplus