diff options
Diffstat (limited to 'nuttx/arch/arm/src/sama5/sam_adc.c')
-rw-r--r-- | nuttx/arch/arm/src/sama5/sam_adc.c | 345 |
1 files changed, 265 insertions, 80 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_adc.c b/nuttx/arch/arm/src/sama5/sam_adc.c index 4249a44ab..d8b58010d 100644 --- a/nuttx/arch/arm/src/sama5/sam_adc.c +++ b/nuttx/arch/arm/src/sama5/sam_adc.c @@ -1,7 +1,6 @@ /************************************************************************************ * arch/arm/src/sama5/sam_adc.c * - * * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * @@ -65,6 +64,64 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Get the set of channel interrupts to enable */ + +#define SAMA5_CHAN0_ENABLE 0 +#define SAMA5_CHAN1_ENABLE 0 +#define SAMA5_CHAN2_ENABLE 0 +#define SAMA5_CHAN3_ENABLE 0 +#define SAMA5_CHAN4_ENABLE 0 +#define SAMA5_CHAN5_ENABLE 0 +#define SAMA5_CHAN6_ENABLE 0 +#define SAMA5_CHAN7_ENABLE 0 +#define SAMA5_CHAN8_ENABLE 0 +#define SAMA5_CHAN9_ENABLE 0 +#define SAMA5_CHAN10_ENABLE 0 +#define SAMA5_CHAN11_ENABLE 0 + +#if defined(CONFIG_SAMA5_ADC_CHAN0) +# undef SAMA5_CHAN0_ENABLE +# define SAMA5_CHAN0_ENABLE ADC_INT_EOC0 +#elif defined(CONFIG_SAMA5_ADC_CHAN1) +# undef SAMA5_CHAN1_ENABLE +# define SAMA5_CHAN1_ENABLE ADC_INT_EOC1 +#elif defined(CONFIG_SAMA5_ADC_CHAN2) +# undef SAMA5_CHAN2_ENABLE +# define SAMA5_CHAN2_ENABLE ADC_INT_EOC2 +#elif defined(CONFIG_SAMA5_ADC_CHAN3) +# undef SAMA5_CHAN3_ENABLE +# define SAMA5_CHAN3_ENABLE ADC_INT_EOC3 +#elif defined(CONFIG_SAMA5_ADC_CHAN4) +# undef SAMA5_CHAN4_ENABLE +# define SAMA5_CHAN4_ENABLE ADC_INT_EOC4 +#elif defined(CONFIG_SAMA5_ADC_CHAN5) +# undef SAMA5_CHAN5_ENABLE +# define SAMA5_CHAN5_ENABLE ADC_INT_EOC5 +#elif defined(CONFIG_SAMA5_ADC_CHAN6) +# undef SAMA5_CHAN6_ENABLE +# define SAMA5_CHAN6_ENABLE ADC_INT_EOC6 +#elif defined(CONFIG_SAMA5_ADC_CHAN7) +# undef SAMA5_CHAN7_ENABLE +# define SAMA5_CHAN7_ENABLE ADC_INT_EOC7 +#elif defined(CONFIG_SAMA5_ADC_CHAN8) +# undef SAMA5_CHAN8_ENABLE +# define SAMA5_CHAN8_ENABLE ADC_INT_EOC8 +#elif defined(CONFIG_SAMA5_ADC_CHAN9) +# undef SAMA5_CHAN9_ENABLE +# define SAMA5_CHAN9_ENABLE ADC_INT_EOC9 +#elif defined(CONFIG_SAMA5_ADC_CHAN10) +# undef SAMA5_CHAN10_ENABLE +# define SAMA5_CHAN10_ENABLE ADC_INT_EOC10 +#elif defined(CONFIG_SAMA5_ADC_CHAN11) +# undef SAMA5_CHAN11_ENABLE +# define SAMA5_CHAN11_ENABLE ADC_INT_EOC11 +#endif + +#define SAMA5_CHAN_ENABLE \ + (SAMA5_CHAN0_ENABLE || SAMA5_CHAN1_ENABLE || SAMA5_CHAN2_ENABLE || \ + SAMA5_CHAN3_ENABLE || SAMA5_CHAN4_ENABLE || SAMA5_CHAN5_ENABLE || \ + SAMA5_CHAN6_ENABLE || SAMA5_CHAN7_ENABLE || SAMA5_CHAN8_ENABLE || \ + SAMA5_CHAN9_ENABLE || SAMA5_CHAN10_ENABLE || SAMA5_CHAN11_ENABLE) /**************************************************************************** * Private Types @@ -74,13 +131,17 @@ struct sam_adc_s { +#ifdef SAMA5_ADC_HAVE_CHANNELS + struct adc_dev_s dev; /* The external via of the ADC device */ +#endif + /* Debug stuff */ #ifdef CONFIG_SAMA5_ADC_REGDEBUG - bool wrlast; /* Last was a write */ - uintptr_t addrlast; /* Last address */ - uint32_t vallast; /* Last value */ - int ntimes; /* Number of times */ + bool wrlast; /* Last was a write */ + uintptr_t addrlast; /* Last address */ + uint32_t vallast; /* Last value */ + int ntimes; /* Number of times */ #endif }; @@ -90,31 +151,32 @@ struct sam_adc_s /* Register operations ******************************************************/ #if defined(CONFIG_SAMA5_ADC_REGDEBUG) && defined(CONFIG_DEBUG) -static bool sam_adc_checkreg(struct sam_gmac_s *priv, bool wr, - uint32_t regval, uintptr_t address); -static uint32_t sam_adc_getreg(struct sam_gmac_s *priv, uintptr_t addr); -static void sam_adc_putreg(struct sam_gmac_s *priv, uintptr_t addr, uint32_t val); -#else -# define sam_adc_getreg(priv,addr) getreg32(addr) -# define sam_adc_putreg(priv,addr,val) putreg32(val,addr) +static bool sam_adc_checkreg(struct sam_adc_s *priv, bool wr, + uint32_t regval, uintptr_t address); #endif /* ADC interrupt handling */ +#ifdef SAMA5_ADC_HAVE_CHANNELS +static void sam_adc_endconversion(struct sam_adc_s *priv, uint32_t pending); +#endif static int sam_adc_interrupt(int irq, void *context); /* ADC methods */ -static void sam_adc_reset(FAR struct adc_dev_s *dev); -static int sam_adc_setup(FAR struct adc_dev_s *dev); -static void sam_adc_shutdown(FAR struct adc_dev_s *dev); -static void sam_adc_rxint(FAR struct adc_dev_s *dev, bool enable); -static int sam_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg); +#ifdef SAMA5_ADC_HAVE_CHANNELS +static void sam_adc_reset(struct adc_dev_s *dev); +static int sam_adc_setup(struct adc_dev_s *dev); +static void sam_adc_shutdown(struct adc_dev_s *dev); +static void sam_adc_rxint(struct adc_dev_s *dev, bool enable); +static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg); +#endif /**************************************************************************** * Private Data ****************************************************************************/ +#ifdef SAMA5_ADC_HAVE_CHANNELS /* ADC lower half device operations */ static const struct adc_ops_s g_adcops = @@ -125,20 +187,21 @@ static const struct adc_ops_s g_adcops = .ao_rxint = sam_adc_rxint, .ao_ioctl = sam_adc_ioctl, }; +#endif /* ADC internal state */ -static struct sam_adc_s g_adcpriv = -{ -}; +static struct sam_adc_s g_adcpriv; +#ifdef SAMA5_ADC_HAVE_CHANNELS /* ADC device instance */ static struct adc_dev_s g_adcdev = { .ad_ops = &g_adcops, - .ad_priv = &g_adcpriv, + .ad_priv = &g_adcpriv.dev, }; +#endif /**************************************************************************** * Private Functions @@ -161,7 +224,7 @@ static struct adc_dev_s g_adcdev = ****************************************************************************/ #ifdef CONFIG_SAMA5_ADC_REGDEBUG -static bool sam_adc_checkreg(struct sam_gmac_s *priv, bool wr, +static bool sam_adc_checkreg(struct sam_adc_s *priv, bool wr, uint32_t regval, uintptr_t address) { if (wr == priv->wrlast && /* Same kind of access? */ @@ -198,48 +261,7 @@ static bool sam_adc_checkreg(struct sam_gmac_s *priv, bool wr, } #endif -/**************************************************************************** - * Name: sam_adc_getreg - * - * Description: - * Read any 32-bit register using an absolute address. - * - ****************************************************************************/ - -#ifdef CONFIG_SAMA5_ADC_REGDEBUG -static uint32_t sam_adc_getreg(struct sam_gmac_s *priv, uintptr_t address) -{ - uint32_t regval = getreg32(address); - - if (sam_adc_checkreg(priv, false, regval, address)) - { - lldbg("%08x->%08x\n", address, regval); - } - - return regval; -} -#endif - -/**************************************************************************** - * Name: sam_adc_putreg - * - * Description: - * Write to any 32-bit register using an absolute address. - * - ****************************************************************************/ - -#ifdef CONFIG_SAMA5_ADC_REGDEBUG -static void sam_adc_putreg(struct sam_gmac_s *priv, uintptr_t address, - uint32_t regval) -{ - if (sam_adc_checkreg(priv, true, regval, address)) - { - lldbg("%08x<-%08x\n", address, regval); - } - - putreg32(regval, address); -} -#endif +#ifdef SAMA5_ADC_HAVE_CHANNELS /**************************************************************************** * Name: sam_adc_reset @@ -250,15 +272,20 @@ static void sam_adc_putreg(struct sam_gmac_s *priv, uintptr_t address, * ****************************************************************************/ -static void sam_adc_reset(FAR struct adc_dev_s *dev) +static void sam_adc_reset(struct adc_dev_s *dev) { - FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)dev->ad_priv; + struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv; irqstate_t flags; uint32_t regval; + /* Reset the ADC controller */ + flags = irqsave(); -#warning Missing logic + sam_adc_putreg(priv, SAM_ADC_CR, ADC_CR_SWRST); + + /* Reset Mode Register */ + sam_adc_putreg(priv, SAM_ADC_MR, 0); irqrestore(flags); } @@ -273,9 +300,9 @@ static void sam_adc_reset(FAR struct adc_dev_s *dev) * ****************************************************************************/ -static int sam_adc_setup(FAR struct adc_dev_s *dev) +static int sam_adc_setup(struct adc_dev_s *dev) { - FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)dev->ad_priv; + struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv; int ret; /* Attach the ADC interrupt */ @@ -302,15 +329,15 @@ static int sam_adc_setup(FAR struct adc_dev_s *dev) * ****************************************************************************/ -static void sam_adc_shutdown(FAR struct adc_dev_s *dev) +static void sam_adc_shutdown(struct adc_dev_s *dev) { - FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)dev->ad_priv; + struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv; /* Disable ADC interrupts, both at the level of the ADC device and at the * level of the NVIC. */ -#warning Missing logic + sam_adc_putreg32(priv, SAM_ADC_IDR, ADC_TSD_INTS); up_disable_irq(SAM_IRQ_ADC); /* Then detach the ADC interrupt handler. */ @@ -326,18 +353,23 @@ static void sam_adc_shutdown(FAR struct adc_dev_s *dev) * ****************************************************************************/ -static void sam_adc_rxint(FAR struct adc_dev_s *dev, bool enable) +static void sam_adc_rxint(struct adc_dev_s *dev, bool enable) { - FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)dev->ad_priv; + struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv; /* Are we enabling or disabling? */ + if (enable) { -#warning Missing logic + /* Enable channel interrupts */ + + sam_adc_putreg32(priv, SAM_ADC_IER, SAMA5_CHAN_ENABLE); } else { -#warning Missing logic + /* Disable channel interrupts */ + + sam_adc_putreg32(priv, SAM_ADC_IDR, ADC_INT_EOCALL); } } @@ -349,7 +381,7 @@ static void sam_adc_rxint(FAR struct adc_dev_s *dev, bool enable) * ****************************************************************************/ -static int sam_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) +static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg) { /* No ioctl commands supported */ @@ -357,6 +389,37 @@ static int sam_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) } /**************************************************************************** + * Name: sam_adc_endconversion + * + * Description: + * End of conversion interrupt handler + * + ****************************************************************************/ + +static void sam_adc_endconversion(struct sam_adc_s *priv, uint32_t pending) +{ + uint32_t regval; + int chan; + + /* Check for the end of conversion event on each channel */ + + for (chan = 0; chan < SAM_ADC_NCHANNELS && pending != 0; chan++) + { + uint32_t bit = ADC_INT_EOC(chan); + if ((pending & bit) != 0) + { + /* Read the ADC sample and pass it to the upper half */ + + regval = sam_adc_getreg(priv, SAM_ADC_CDR(chan)); + ret = adc_receive(&priv->dev, chan, regval & ADC_CDR_DATA_MASK); + pending &= ~bit; + } + } +} + +#endif /* SAMA5_ADC_HAVE_CHANNELS */ + +/**************************************************************************** * Name: sam_adc_interrupt * * Description: @@ -366,11 +429,46 @@ static int sam_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) static int sam_adc_interrupt(int irq, void *context) { - FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)g_adcdev.ad_priv; + struct sam_adc_s *priv = (struct sam_adc_s *)g_adcdev.ad_priv; uint32_t regval; + struct sam_adc_s *priv = &g_adcpriv; + uint32_t isr; + uint32_t imr; + uint32_t pending; + + /* Get the set of unmasked, pending ADC interrupts */ + + isr = sam_adc_getreg(priv, SAM_ADC_ISR); + imr = sam_adc_getreg(priv, SAM_ADC_IMR); + pending = isr & imr; -#warning Missing logic + /* Handle pending touchscreen interrupts */ + +#ifdef CONFIG_SAMA5_TOUCHSCREEN + if ((pending & ADC_TSD_INTS) != 0) + { + /* Let the touchscreen handle its interrupts */ + + sam_tsd_interrupt(pending); + pending &= ~ADC_TSD_INTS; + } +#endif +#ifdef SAMA5_ADC_HAVE_CHANNELS + /* Check for end-of-conversion interrupts */ + + if ((pending & ADC_INT_EOCALL) != 0) + { + /* Let the touchscreen handle its interrupts */ + + sam_adc_endconversion(pending); + pending &= ~ADC_INT_EOCALL; + } +#endif + + /* Make sure that all interrupts were handled */ + + DEBUGASSERT(pending == 0); return OK; } @@ -389,12 +487,54 @@ static int sam_adc_interrupt(int irq, void *context) * ****************************************************************************/ -FAR struct adc_dev_s *sam_adc_initialize(void) +struct adc_dev_s *sam_adc_initialize(void) { /* Enable the ADC peripheral clock*/ sam_adc_enableclk(); + /* Configure ADC pins */ + +#ifdef CONFIG_SAMA5_ADC_CHAN0 + sam_configpio(PIO_ADC_AD0); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN1 + sam_configpio(PIO_ADC_AD1); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN2 + sam_configpio(PIO_ADC_AD2); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN3 + sam_configpio(PIO_ADC_AD3); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN4 + sam_configpio(PIO_ADC_AD4); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN5 + sam_configpio(PIO_ADC_AD5); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN6 + sam_configpio(PIO_ADC_AD6); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN7 + sam_configpio(PIO_ADC_AD7); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN8 + sam_configpio(PIO_ADC_AD8); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN9 + sam_configpio(PIO_ADC_AD9); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN10 + sam_configpio(PIO_ADC_AD10); +#endif +#ifdef CONFIG_SAMA5_ADC_CHAN11 + sam_configpio(PIO_ADC_AD11); +#endif +#if 0 + sam_configpio(PIO_ADC_TRG); +#endif + /* Reset the ADC controller */ sam_adc_putreg(priv, SAM_ADC_CR, ADC_CR_SWRST); @@ -408,4 +548,49 @@ FAR struct adc_dev_s *sam_adc_initialize(void) return &g_adcdev; } +/**************************************************************************** + * Name: sam_adc_getreg + * + * Description: + * Read any 32-bit register using an absolute address. + * + ****************************************************************************/ + +#ifdef CONFIG_SAMA5_ADC_REGDEBUG +static uint32_t sam_adc_getreg(ADC_HANDLE handle, uintptr_t address) +{ + struct sam_adc_s *priv = (struct sam_adc_s *)handle; + uint32_t regval = getreg32(address); + + if (sam_adc_checkreg(priv, false, regval, address)) + { + lldbg("%08x->%08x\n", address, regval); + } + + return regval; +} +#endif + +/**************************************************************************** + * Name: sam_adc_putreg + * + * Description: + * Write to any 32-bit register using an absolute address. + * + ****************************************************************************/ + +#ifdef CONFIG_SAMA5_ADC_REGDEBUG +void sam_adc_putreg(ADC_HANDLE handle, uintptr_t address, uint32_t regval) +{ + struct sam_adc_s *priv = (struct sam_adc_s *)handle; + + if (sam_adc_checkreg(priv, true, regval, address)) + { + lldbg("%08x<-%08x\n", address, regval); + } + + putreg32(regval, address); +} +#endif + #endif /* CONFIG_SAMA5_ADC */ |