summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/stm32/stm32_adc.c
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-12-14 00:34:12 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-12-14 00:34:12 +0000
commit14205580387ff7d21e5be8efea91e7a92f6fe48e (patch)
tree139d59eb1abc6cf849f401861505aeb69b075294 /nuttx/arch/arm/src/stm32/stm32_adc.c
parentc3c84de7ece1bc02227ee922499193fadb611499 (diff)
downloadpx4-nuttx-14205580387ff7d21e5be8efea91e7a92f6fe48e.tar.gz
px4-nuttx-14205580387ff7d21e5be8efea91e7a92f6fe48e.tar.bz2
px4-nuttx-14205580387ff7d21e5be8efea91e7a92f6fe48e.zip
Progress on STM32 ADC driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4173 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/arm/src/stm32/stm32_adc.c')
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_adc.c360
1 files changed, 322 insertions, 38 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_adc.c b/nuttx/arch/arm/src/stm32/stm32_adc.c
index 6c14e4784..bb8efa2e9 100644
--- a/nuttx/arch/arm/src/stm32/stm32_adc.c
+++ b/nuttx/arch/arm/src/stm32/stm32_adc.c
@@ -2,7 +2,8 @@
* arch/arm/src/stm32/stm32_adc.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
- * Author: Li Zhuoyi <gnutt@nuttx.org>
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ * Diego Sanchez <dsanchez@nx-engineering.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
-
+
/****************************************************************************
* Included Files
****************************************************************************/
@@ -80,22 +81,57 @@
#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) || defined(CONFIG_STM32_ADC3)
+/* ADC interrupts */
+
+#ifdef CONFIG_STM32_STM32F10XX
+# define ADC_SR_ALLINTS (ADC_SR_AWD | ADC_SR_EOC | ADC_SR_JEOC)
+#else
+# define ADC_SR_ALLINTS (ADC_SR_AWD | ADC_SR_EOC | ADC_SR_JEOC | ADC_SR_OVR)
+#endif
+
+#ifdef CONFIG_STM32_STM32F10XX
+# define ADC_CR1_ALLINTS (ADC_CR1_AWDIE | ADC_CR1_EOCIE | ADC_CR1_JEOCIE)
+#else
+# define ADC_CR1_ALLINTS (ADC_CR1_AWDIE | ADC_CR1_EOCIE | ADC_CR1_JEOCIE | ADC_CR1_OVRIE)
+#endif
+
/****************************************************************************
* Private Types
****************************************************************************/
+/* This structure describes the state of one ADC block */
+
struct stm32_dev_s
{
- int irq;
-# warning "Missing logic"
+ int irq; /* Interrupt generated by this ADC block */
+ xcpt_t isr; /* Interrupt handler for this ADC block */
+ uint32_t base; /* Base address of registers unique to this ADC block */
+
+ int32_t buf[8];
+ uint8_t count[8];
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
+
+/* ADC Register access */
+
+static uint32_t adc_getreg(struct stm32_dev_s *priv, int offset);
+static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value);
+
/* ADC Interrupt Handler */
-static int adc_interrupt(int irq, void *context);
+static void adc_interrupt(FAR struct stm32_dev_s *priv);
+#if defined(CONFIG_STM32_STM32F10XX) && (defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2))
+static int adc12_interrupt(int irq, void *context)
+#endif
+#ifdef CONFIG_STM32_STM32F10XX && defined (CONFIG_STM32_ADC3)
+static int adc3_interrupt(int irq, void *context)
+#endif
+#ifdef CONFIG_STM32_STM32F40XX
+static int adc123_interrupt(int irq, void *context)
+#endif
/* ADC Driver Methods */
@@ -104,7 +140,6 @@ static int adc_setup(FAR struct adc_dev_s *dev);
static void adc_shutdown(FAR struct adc_dev_s *dev);
static void adc_rxint(FAR struct adc_dev_s *dev, bool enable);
static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg);
-static int adc_interrupt(int irq, void *context);
/****************************************************************************
* Private Data
@@ -123,17 +158,19 @@ static const struct adc_ops_s g_adcops =
static struct stm32_dev_s g_adcpriv1 =
{
#ifdef CONFIG_STM32_STM32F10XX
- .irq = STM32_IRQ_ADC12;
+ .irq = STM32_IRQ_ADC12,
+ .isr = adc12_interrupt,
#else
- .irq = STM32_IRQ_ADC;
+ .irq = STM32_IRQ_ADC,
+ .isr = adc123_interrupt,
#endif
-# warning "Missing logic"
+ .base = STM32_ADC1_BASE,
};
static struct adc_dev_s g_adcdev1 =
{
.ad_ops = &g_adcops,
- .ad_priv= &g_adcpriv1
+ .ad_priv= &g_adcpriv1,
};
#endif
@@ -141,17 +178,19 @@ static struct adc_dev_s g_adcdev1 =
static struct stm32_dev_s g_adcpriv2 =
{
#ifdef CONFIG_STM32_STM32F10XX
- .irq = STM32_IRQ_ADC12;
+ .irq = STM32_IRQ_ADC12,
+ .isr = adc12_interrupt,
#else
- .irq = STM32_IRQ_ADC;
+ .irq = STM32_IRQ_ADC,
+ .isr = adc123_interrupt,
#endif
-# warning "Missing logic"
+ .base = STM32_ADC2_BASE,
};
static struct adc_dev_s g_adcdev2 =
{
- .ad_ops = &g_adcops
- .ad_priv= &g_adcpriv2
+ .ad_ops = &g_adcops,
+ .ad_priv= &g_adcpriv2,
};
#endif
@@ -160,17 +199,19 @@ static struct adc_dev_s g_adcdev2 =
static struct stm32_dev_s g_adcpriv3 =
{
#ifdef CONFIG_STM32_STM32F10XX
- .irq = STM32_IRQ_ADC3;
+ .irq = STM32_IRQ_ADC3,
+ .isr = adc3_interrupt,
#else
- .irq = STM32_IRQ_ADC;
+ .irq = STM32_IRQ_ADC,
+ .isr = adc123_interrupt,
#endif
-# warning "Missing logic"
+ .base = STM32_ADC3_BASE,
};
static struct adc_dev_s g_adcdev3 =
{
.ad_ops = &g_adcops,
- .ad_priv= &g_adcpriv3
+ .ad_priv= &g_adcpriv3,
};
#endif
@@ -180,28 +221,41 @@ static struct adc_dev_s g_adcdev3 =
****************************************************************************/
/****************************************************************************
- * Name: adc_interrupt
+ * Name: adc_getreg
*
* Description:
- * ADC interrupt handler.
+ * Read the value of an ADC register.
*
* Input Parameters:
+ * priv - A reference to the ADC block status
+ * offset - The offset to the register to read
*
* Returned Value:
*
****************************************************************************/
-static int adc_interrupt(int irq, void *context)
+static uint32_t adc_getreg(struct stm32_dev_s *priv, int offset)
{
- FAR struct stm32_dev_s *priv;
- uint32_t regval;
+ return getreg32(priv->base + offset);
+}
- /* Determine which ADC caused the interrupt */
-# warning "Missing logic"
+/****************************************************************************
+ * Name: adc_getreg
+ *
+ * Description:
+ * Read the value of an ADC register.
+ *
+ * Input Parameters:
+ * priv - A reference to the ADC block status
+ * offset - The offset to the register to read
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
- /* Handle the ADC interrupt */
-# warning "Missing logic"
- return OK;
+static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value)
+{
+ putreg32(value, priv->base + offst);
}
/****************************************************************************
@@ -225,7 +279,52 @@ static void adc_reset(FAR struct adc_dev_s *dev)
flags = irqsave();
-# warning "Missing logic"
+ /* Initialize the ADC data structures */
+
+ /* ADC1 CR Configuration */
+
+ regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET);
+ regval &= ~ADC_CR1_DUALMOD_MASK;
+ regval &= ~ADC_CR1_SCAN; /* Clear DUALMODE and SCAN bits */
+ adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval);
+
+ /* Initialize the ADC_Mode (ADC_Mode_Independent) */
+
+ regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET);
+ regval |= ADC_CR1_IND;
+
+ /* Initialize the ADC_CR1_SCAN member DISABLE */
+
+ regval &= ~ADC_CR1_SCAN;
+ adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval);
+
+ /* ADC1 CR2 Configuration */
+ /* Clear CONT, ALIGN and EXTTRIG bits */
+
+ regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET);
+ regval &= ~ADC_CR2_CONT;
+ regval &= ~ADC_CR2_ALIGN;
+ regval &= ~ADC_CR2_EXTSEL_MASK;
+ adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval);
+
+ /* Set CONT, ALIGN and EXTTRIG bits */
+ /* Initialize the ALIGN: Data alignment Right */
+
+ regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET);
+ regval &= ~ADC_CR2_ALIGN;
+
+ /* Initialize the External event select "Timer CC1 event" */
+ regval &= ~ADC_CR2_EXTSEL_MASK;
+
+ /* Initialize the ADC_ContinuousConvMode "Single conversion mode" */
+ regval &= ~ADC_CR2_CONT;
+ adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval);
+
+ /* ADC1 SQR1 Configuration */
+
+ regval = adc_getreg(priv, STM32_ADC_SQR1_OFFSET);
+ regval &= ~ADC_SQR1_L_MASK; /* L = 0000: 1 conversion */
+ adc_putreg(priv, STM32_ADC_SQR_OFFSET1, regval);
irqrestore(flags);
}
@@ -249,15 +348,19 @@ static int adc_setup(FAR struct adc_dev_s *dev)
{
FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv;
int ret;
-
+ uint32_t regval = 0;
+ int i;
/* Attach the ADC interrupt */
- ret = irq_attach(priv->irq, adc_interrupt);
+ ret = irq_attach(priv->irq, priv->isr);
if (ret == OK)
{
- /* Initialize the ADC data structures */
-#warning "Missing logic"
-
+ for (i = 0; i < 8; i++)
+ {
+ priv->buf[i]=0;
+ priv->count[i]=0;
+ }
+
/* Enable the ADC interrupt */
up_enable_irq(priv->irq);
@@ -288,7 +391,6 @@ static void adc_shutdown(FAR struct adc_dev_s *dev)
irq_detach(priv->irq);
/* Disable and reset the ADC module */
-#warning "Missing logic"
}
/****************************************************************************
@@ -306,15 +408,22 @@ static void adc_shutdown(FAR struct adc_dev_s *dev)
static void adc_rxint(FAR struct adc_dev_s *dev, bool enable)
{
FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv;
+ uint32_t regval;
+ uint32_t adc_getreg(priv, STM32_ADC_CR1_OFFSET);
if (enable)
{
-#warning "Missing logic"
+ /* Enable the end-of-conversion ADC interrupt */
+
+ regval |= ADC_CR1_EOCIE;
}
else
{
-#warning "Missing logic"
+ /* Enable all ADC interrupts */
+
+ regval &= ~ADC_CR1_ALLINTS;
}
+ adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval);
}
/****************************************************************************
@@ -335,6 +444,178 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
}
/****************************************************************************
+ * Name: adc_interrupt
+ *
+ * Description:
+ * Common ADC interrupt handler.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_interrupt(FAR struct stm32_dev_s *priv)
+{
+ uint32_t regval;
+ unsigned char ch; /* channel */
+ int32_t value;
+
+ regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET);
+ regval &= ADC_CR1_AWDCH_MASK;
+ ch = regval;
+
+ /* Handle the ADC interrupt */
+
+# warning "still missing logic, value computation"
+ adc_receive(priv, ch, value);
+ priv->buf[ch] = 0;
+ priv->count[ch] = 0;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: adc12_interrupt
+ *
+ * Description:
+ * ADC12 interrupt handler for the STM32 F1 family.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_STM32_STM32F10XX) && (defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2))
+static int adc12_interrupt(int irq, void *context)
+{
+ uint32_regval;
+ uint32_t pending;
+
+ /* Check for pending ADC1 interrupts */
+
+#ifdef CONFIG_STM32_ADC1
+ regval = getreg32(priv, STM32_ADC1_SR);
+ pending = regval & ADC_SR_ALLINTS;
+ if (pending != 0)
+ {
+ adc_interrupt(&g_adcpriv1);
+ regval &= ~pending;
+ putreg32(regval, STM32_ADC1_SR);
+ }
+#endif
+
+ /* Check for pending ADC2 interrupts */
+
+#ifdef CONFIG_STM32_ADC2
+ regval = getreg32(priv, STM32_ADC2_SR);
+ pending = regval & ADC_SR_ALLINTS;
+ if (pending != 0)
+ {
+ adc_interrupt(&g_adcpriv2);
+ regval &= ~pending;
+ putreg32(regval, STM32_ADC2_SR);
+ }
+#endif
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: adc3_interrupt
+ *
+ * Description:
+ * ADC1/2 interrupt handler for the STM32 F1 family.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_STM32F10XX && defined (CONFIG_STM32_ADC3)
+static int adc3_interrupt(int irq, void *context)
+{
+ uint32_t regval;
+ uint32_t pending;
+
+ /* Check for pending ADC3 interrupts */
+
+ regval = getreg32(priv, STM32_ADC3_SR);
+ pending = regval & ADC_SR_ALLINTS;
+ if (pending != 0)
+ {
+ adc_interrupt(&g_adcpriv3);
+ regval &= ~pending;
+ putreg32(regval, STM32_ADC3_SR);
+ }
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: adc123_interrupt
+ *
+ * Description:
+ * ADC1/2/3 interrupt handler for the STM32 F4 family.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_STM32F40XX
+static int adc123_interrupt(int irq, void *context)
+{
+ uint32_t regval;
+ uint32_t pending;
+
+ /* Check for pending ADC1 interrupts */
+
+#ifdef CONFIG_STM32_ADC1
+ regval = getreg32(priv, STM32_ADC1_SR);
+ pending = regval & ADC_SR_ALLINTS;
+ if (pending != 0)
+ {
+ adc_interrupt(&g_adcpriv1);
+ regval &= ~pending;
+ putreg32(regval, STM32_ADC1_SR);
+ }
+#endif
+
+ /* Check for pending ADC2 interrupts */
+
+#ifdef CONFIG_STM32_ADC2
+ regval = getreg32(priv, STM32_ADC2_SR);
+ pending = regval & ADC_SR_ALLINTS;
+ if (pending != 0)
+ {
+ adc_interrupt(&g_adcpriv2);
+ regval &= ~pending;
+ putreg32(regval, STM32_ADC2_SR);
+ }
+#endif
+
+ /* Check for pending ADC3 interrupts */
+
+#ifdef CONFIG_STM32_ADC3
+ regval = getreg32(priv, STM32_ADC3_SR);
+ pending = regval & ADC_SR_ALLINTS;
+ if (pending != 0)
+ {
+ adc_interrupt(&g_adcpriv2);
+ regval &= ~pending;
+ putreg32(regval, STM32_ADC3_SR);
+ }
+#endif
+ return OK;
+}
+#endif
+
+/****************************************************************************
* Public Functions
****************************************************************************/
@@ -351,6 +632,9 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
struct adc_dev_s *up_adcinitialize(int intf)
{
+# warning "Question: How do you plan to handle the ADC channels? Can we do"
+# " 16 or 18 individual channels? or one group?"
+
#ifdef CONFIG_STM32_ADC1
if (intf == 1)
{