SAMA5: Hook in timer/counter logic so that it can driver periodic ADC sampling
This commit is contained in:
parent
21c59c0aa7
commit
aab5b6b2d9
@ -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).
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
@ -1067,6 +1081,85 @@ static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg)
|
||||
* Initialization/Configuration
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
@ -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
|
||||
|
@ -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 ********************************************************************/
|
||||
|
@ -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;
|
||||
|
||||
@ -588,6 +822,53 @@ void sam_tc_stop(TCHANDLE handle)
|
||||
sam_chan_putreg(chan, SAM_TC_CCR_OFFSET, TC_CCR_CLKDIS);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
@ -595,17 +876,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
|
||||
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user