From 14205580387ff7d21e5be8efea91e7a92f6fe48e Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 14 Dec 2011 00:34:12 +0000 Subject: Progress on STM32 ADC driver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4173 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/arch/arm/src/stm32/stm32_adc.c | 360 +++++++++++++++++++++++++++++++---- 1 file changed, 322 insertions(+), 38 deletions(-) (limited to 'nuttx/arch/arm/src/stm32/stm32_adc.c') 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 + * Author: Gregory Nutt + * Diego Sanchez * * 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); } /**************************************************************************** @@ -334,6 +443,178 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) return -ENOTTY; } +/**************************************************************************** + * 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) { -- cgit v1.2.3