diff --git a/arch/arm/src/stm32/chip/stm32f10xxx_rcc.h b/arch/arm/src/stm32/chip/stm32f10xxx_rcc.h index fac59b1043..110816f1f2 100644 --- a/arch/arm/src/stm32/chip/stm32f10xxx_rcc.h +++ b/arch/arm/src/stm32/chip/stm32f10xxx_rcc.h @@ -190,7 +190,7 @@ #define RCC_APB2RSTR_SPI1RST (1 << 12) /* Bit 12: SPI 1 reset */ #define RCC_APB2RSTR_TIM8RST (1 << 13) /* Bit 13: TIM8 Timer reset */ #define RCC_APB2RSTR_USART1RST (1 << 14) /* Bit 14: USART1 reset */ -#define RCC_APB2RTST_ADC2RST (1 << 15) /* Bit 15: ADC3 interface reset */ +#define RCC_APB2RSTR_ADC3RST (1 << 15) /* Bit 15: ADC3 interface reset */ /* APB1 Peripheral reset register */ diff --git a/arch/arm/src/stm32/stm32_adc.c b/arch/arm/src/stm32/stm32_adc.c index 8356f53d50..fdafd48e6e 100644 --- a/arch/arm/src/stm32/stm32_adc.c +++ b/arch/arm/src/stm32/stm32_adc.c @@ -95,18 +95,25 @@ # define ADC_CR1_ALLINTS (ADC_CR1_AWDIE | ADC_CR1_EOCIE | ADC_CR1_JEOCIE | ADC_CR1_OVRIE) #endif +/* The maximum number of samples */ + +#define ADC_MAX_SAMPLES 16 + /**************************************************************************** * Private Types ****************************************************************************/ - + /* This structure describes the state of one ADC block */ struct stm32_dev_s { - int irq; /* Interrupt generated by this ADC block */ + uint8_t irq; /* Interrupt generated by this ADC block */ + uint8_t nchannels; /* Number of channels */ + uint8_t intf; /* ADC interface number */ xcpt_t isr; /* Interrupt handler for this ADC block */ uint32_t base; /* Base address of registers unique to this ADC block */ + uint8_t chanlist[ADC_MAX_SAMPLES]; int32_t buf[8]; uint8_t count[8]; }; @@ -118,19 +125,20 @@ struct stm32_dev_s /* 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); +static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value); +static void adc_rccreset(int regaddr, bool reset); /* ADC Interrupt Handler */ -static void adc_interrupt(FAR struct stm32_dev_s *priv); +static int 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) +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) +#if defined(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) +static int adc123_interrupt(int irq, void *context); #endif /* ADC Driver Methods */ @@ -140,6 +148,7 @@ 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 void adc_enable(FAR struct adc_dev_s *dev, bool enable); /**************************************************************************** * Private Data @@ -168,6 +177,7 @@ static struct stm32_dev_s g_adcpriv1 = .irq = STM32_IRQ_ADC, .isr = adc123_interrupt, #endif + .intf = 1; .base = STM32_ADC1_BASE, }; @@ -190,6 +200,7 @@ static struct stm32_dev_s g_adcpriv2 = .irq = STM32_IRQ_ADC, .isr = adc123_interrupt, #endif + .intf = 2; .base = STM32_ADC2_BASE, }; @@ -212,6 +223,7 @@ static struct stm32_dev_s g_adcpriv3 = .irq = STM32_IRQ_ADC, .isr = adc123_interrupt, #endif + .intf = 3; .base = STM32_ADC3_BASE, }; @@ -264,6 +276,108 @@ static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value) putreg32(value, priv->base + offset); } +/**************************************************************************** + * Name: adc_rccreset + * + * Description: + * Deinitializes the ADCx peripheral registers to their default + * reset values. It could set all the ADCs configured. + * + * Input Parameters: + * regaddr - The register to read + * reset - Condition, set or reset + * + * Returned Value: + * + ****************************************************************************/ + +static void adc_rccreset(struct stm32_dev_s *priv, bool reset) +{ + uint32_t regval; + uint32_t adcbit; + + /* Pick the appropriate bit in the APB2 reset register */ + +#ifdef CONFIG_STM32_STM32F10XX + /* For the STM32 F1, there is an individual bit to reset each ADC. */ + + switch (priv->intf) + { +#ifdef CONFIG_STM32_ADC1 + case 1: + adcbit = RCC_APB2RSTR_ADC1RST; + break; +#endif +#ifdef CONFIG_STM32_ADC2 + case 2: + adcbit = RCC_APB2RSTR_ADC2RST; + break; +#endif +#ifdef CONFIG_STM32_ADC3 + case 3: + adcbit = RCC_APB2RSTR_ADC3RST; + break; +#endif + default: + return; + } + +#else + /* For the STM32 F4, there is one common reset for all ADC block. + * THIS will probably cause some problems! + */ + + adcbit = RCC_APB2RSTR_ADCRST; +#endif + + /* Set or clear the selected bit in the APB2 reset register */ + + regval = getreg32(STM32_RCC_APB2RSTR); + if (reset) + { + /* Enable ADC reset state */ + + regval |= adcbit; + } + else + { + /* Release ADC from reset state */ + + regval &= ~adcbit; + } + putreg32(regval, STM32_RCC_APB2RSTR); +} + +/******************************************************************************* + * Name: adc_enable + * + * Description : Enables or disables the specified ADC peripheral. + * + * Input Parameters: + * + * enable - true: enable ADC convertion + * false: disable ADC convertion + * + * Returned Value: + * + *******************************************************************************/ +static void adc_enable(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; + + regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); + if (enable) + { + regval |= ADC_CR2_ADON; + } + else + { + regval &= ~ADC_CR2_ADON; + } + adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval); +} + /**************************************************************************** * Name: adc_reset * @@ -279,15 +393,64 @@ static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value) static void adc_reset(FAR struct adc_dev_s *dev) { + adbg("Initializing the ADC to the reset values \n"); + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; irqstate_t flags; uint32_t regval; - + uint32_t L = priv->nchannels; + uint32_t ch; + int offset = 0; + flags = irqsave(); + /* Enable ADC reset state */ + + adc_rccreset(priv, true); + + /* Release ADC from reset state */ + + adc_rccreset(priv, false); + /* Initialize the ADC data structures */ - /* ADC1 CR Configuration */ + /* Initialize the watchdog high threshold register */ + + adc_putreg(priv, STM32_ADC_HTR_OFFSET, 0x00000fff); + + /* Initialize the watchdog low threshold register */ + + adc_putreg(priv, STM32_ADC_LTR_OFFSET, 0x00000000); + +#ifdef CONFIG_STM32_STM32F40XX + /* Initialize ADC Prescaler*/ + + regval = getreg32(STM32_ADC_CCR_OFFSET); + + /* PCLK2 divided by 2 */ + + regval &= ~ADC_CCR_ADCPRE_MASK; + putreg32(regval,STM32_ADC_CCR_OFFSET); +#endif + + /* Initialize the same sample time for each ADC 1.5 cycles + * + * During sample cycles channel selection bits must remain unchanged. + * + * 000: 1.5 cycles + * 001: 7.5 cycles + * 010: 13.5 cycles + * 011: 28.5 cycles + * 100: 41.5 cycles + * 101: 55.5 cycles + * 110: 71.5 cycles + * 111: 239.5 cycles + */ + + adc_putreg(priv,STM32_ADC_SMPR1_OFFSET,0x00000000); + adc_putreg(priv,STM32_ADC_SMPR2_OFFSET,0x00000000); + + /* ADC CR1 Configuration */ regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); regval &= ~ADC_CR1_DUALMOD_MASK; @@ -305,6 +468,12 @@ static void adc_reset(FAR struct adc_dev_s *dev) adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); /* ADC1 CR2 Configuration */ + + /* Set the ADON bit to wake up the ADC from power down mode */ + + regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); + regval |= ADC_CR2_ADON; + /* Clear CONT, ALIGN and EXTTRIG bits */ regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); @@ -328,13 +497,183 @@ static void adc_reset(FAR struct adc_dev_s *dev) regval &= ~ADC_CR2_CONT; adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval); - /* ADC1 SQR1 Configuration */ + /* ADC1 SQR Configuration */ + L = L << 20; 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); + regval &= ~ADC_SQR1_L_MASK; /* Clear L Mask */ + regval |= L; /* SetL, # of convertions */ + adc_putreg(priv, STM32_ADC_SQR1_OFFSET, regval); - irqrestore(flags); + /* Configuration of the channels convertions */ + +#warning "I can improve the ugly code below with a logic using offsets" +#warning "Or.. better yet, a loop" + regval = adc_getreg(priv, STM32_ADC_SQR3_OFFSET); + if (priv->nchannels >= 1) + { + ch = priv->chanlist[0]; + ch <<= offset; + regval &= ~ADC_SQR3_SQ1_MASK; /* clear SQ1 */ + regval |= ch; /* Set SQ1 */ + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 2) + { + ch = priv->chanlist[1]; + ch <<= offset; + regval &= ~ADC_SQR3_SQ2_MASK; /* clear SQ2 */ + regval |= ch; /* Set SQ2 */ + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 3) + { + ch = priv->chanlist[2]; + ch <<= offset; + regval &= ~ADC_SQR3_SQ3_MASK; /* clear SQ3 */ + regval |= ch; /* SetSQ3 */ + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 4) + { + ch = priv->chanlist[3]; + ch <<= offset; + regval &= ~ADC_SQR3_SQ4_MASK; /* clear SQ4 */ + regval |= ch; /* SetSQ4 */ + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 5) + { + ch = priv->chanlist[4]; + ch <<= offset; + regval &= ~ADC_SQR3_SQ5_MASK; /* clear SQ5 */ + regval |= ch; /* SetSQ5 */ + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 6) + { + ch = priv->chanlist[5]; + ch <<= offset; + regval &= ~ADC_SQR3_SQ6_MASK; /* clear SQ6 */ + regval |= ch; /* SetSQ6 */ + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); + offset = 0; + } + + if (priv->nchannels >= 7) + { + ch = priv->chanlist[6]; + ch <<= offset; + regval &= ~ADC_SQR2_SQ7_MASK; /* clear SQ7 */ + regval |= ch; /* SetSQ7 */ + adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 8) + { + ch = priv->chanlist[7]; + ch <<= offset; + regval &= ~ADC_SQR2_SQ8_MASK; /* clear SQ8 */ + regval |= ch; /* SetSQ8 */ + adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 9) + { + ch = priv->chanlist[8]; + ch <<= offset; + regval &= ~ADC_SQR2_SQ9_MASK; /* clear SQ9 */ + regval |= ch; /* SetSQ9 */ + adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 10) + { + ch = priv->chanlist[9]; + ch <<= offset; + regval &= ~ADC_SQR2_SQ10_MASK; /* clear SQ10 */ + regval |= ch; /* SetSQ10 */ + adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 11) + { + ch = priv->chanlist[10]; + ch <<= offset; + regval &= ~ADC_SQR2_SQ11_MASK; /* clear SQ11 */ + regval |= ch; /* SetSQ11 */ + adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 12) + { + ch = priv->chanlist[11]; + ch <<= offset; + regval &= ~ADC_SQR2_SQ12_MASK; /* clear SQ12 */ + regval |= ch; /* SetSQ12 */ + adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); + offset = 0; + } + + if (priv->nchannels >= 13) + { + ch = priv->chanlist[12]; + ch <<= offset; + regval &= ~ADC_SQR1_SQ13_MASK; /* clear SQ13 */ + regval |= ch; /* SetSQ13 */ + adc_putreg(priv, STM32_ADC_SQR1_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 14) + { + ch = priv->chanlist[13]; + ch <<= offset; + regval &= ~ADC_SQR1_SQ14_MASK; /* clear SQ14 */ + regval |= ch; /* SetSQ14 */ + adc_putreg(priv, STM32_ADC_SQR1_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 15) + { + ch = priv->chanlist[14]; + ch <<= offset; + regval &= ~ADC_SQR1_SQ15_MASK; /* clear SQ15 */ + regval |= ch; /* SetSQ15 */ + adc_putreg(priv, STM32_ADC_SQR1_OFFSET, regval); + offset += 5; + } + + if (priv->nchannels >= 16) + { + ch = priv->chanlist[15]; + ch <<= offset; + regval &= ~ADC_SQR1_SQ16_MASK; /* clear SQ16 */ + regval |= ch; /* SetSQ16 */ + adc_putreg(priv, STM32_ADC_SQR1_OFFSET, regval); + } + + if (priv->nchannels >= 17) + { + adbg("ERROR: Number of channels exceeded\n"); + } + irqrestore(flags); } /**************************************************************************** @@ -356,7 +695,6 @@ 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 */ @@ -373,6 +711,7 @@ static int adc_setup(FAR struct adc_dev_s *dev) up_enable_irq(priv->irq); } + return ret; } @@ -418,7 +757,7 @@ 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); + regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); if (enable) { /* Enable the end-of-conversion ADC interrupt */ @@ -463,24 +802,38 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) * ****************************************************************************/ -static void adc_interrupt(FAR struct stm32_dev_s *priv) +static int adc_interrupt(FAR struct stm32_dev_s *priv) { - uint32_t regval; - unsigned char ch; /* channel */ - int32_t value; + uint32_t adcsr; + int32_t value; + uint8_t ch; + int i; - regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); - regval &= ADC_CR1_AWDCH_MASK; - ch = regval; + /* Identifies the interruption AWD or EOC */ + + adcsr = adc_getreg(priv, STM32_ADC_SR_OFFSET); + if ((adcsr & ADC_SR_AWD) != 0) + { + adbg(" Analog Watchdog, Value converted out of range!\n"); + } + + /* EOC: End of conversion */ - /* Handle the ADC interrupt */ + if ((adcsr & ADC_SR_EOC) != 0) + { + value = adc_getreg(priv, STM32_ADC_DR_OFFSET); + value &= ADC_DR_DATA_MASK; +#error "i is not assigned a value" + ch = priv->chanlist[i]; /* Channel converted */ + + /* Handle the ADC interrupt */ -# warning "still missing logic, value computation" - adc_receive(priv, ch, value); - priv->buf[ch] = 0; - priv->count[ch] = 0; + adc_receive(priv, ch, value); + priv->buf[ch] = 0; + priv->count[ch] = 0; + } - return OK; + return OK; } /**************************************************************************** @@ -498,13 +851,13 @@ 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) { - uint32_regval; + uint32_t regval; uint32_t pending; /* Check for pending ADC1 interrupts */ #ifdef CONFIG_STM32_ADC1 - regval = getreg32(priv, STM32_ADC1_SR); + regval = getreg32(STM32_ADC1_SR); pending = regval & ADC_SR_ALLINTS; if (pending != 0) { @@ -517,7 +870,7 @@ static int adc12_interrupt(int irq, void *context) /* Check for pending ADC2 interrupts */ #ifdef CONFIG_STM32_ADC2 - regval = getreg32(priv, STM32_ADC2_SR); + regval = getreg32(STM32_ADC2_SR); pending = regval & ADC_SR_ALLINTS; if (pending != 0) { @@ -542,7 +895,7 @@ static int adc12_interrupt(int irq, void *context) * ****************************************************************************/ -#ifdef CONFIG_STM32_STM32F10XX && defined (CONFIG_STM32_ADC3) +#if defined (CONFIG_STM32_STM32F10XX) && defined (CONFIG_STM32_ADC3) static int adc3_interrupt(int irq, void *context) { uint32_t regval; @@ -550,7 +903,7 @@ static int adc3_interrupt(int irq, void *context) /* Check for pending ADC3 interrupts */ - regval = getreg32(priv, STM32_ADC3_SR); + regval = getreg32(STM32_ADC3_SR); pending = regval & ADC_SR_ALLINTS; if (pending != 0) { @@ -584,7 +937,7 @@ static int adc123_interrupt(int irq, void *context) /* Check for pending ADC1 interrupts */ #ifdef CONFIG_STM32_ADC1 - regval = getreg32(priv, STM32_ADC1_SR); + regval = getreg32(STM32_ADC1_SR); pending = regval & ADC_SR_ALLINTS; if (pending != 0) { @@ -597,7 +950,7 @@ static int adc123_interrupt(int irq, void *context) /* Check for pending ADC2 interrupts */ #ifdef CONFIG_STM32_ADC2 - regval = getreg32(priv, STM32_ADC2_SR); + regval = getreg32(STM32_ADC2_SR); pending = regval & ADC_SR_ALLINTS; if (pending != 0) { @@ -610,7 +963,7 @@ static int adc123_interrupt(int irq, void *context) /* Check for pending ADC3 interrupts */ #ifdef CONFIG_STM32_ADC3 - regval = getreg32(priv, STM32_ADC3_SR); + regval = getreg32(STM32_ADC3_SR); pending = regval & ADC_SR_ALLINTS; if (pending != 0) { @@ -628,45 +981,74 @@ static int adc123_interrupt(int irq, void *context) ****************************************************************************/ /**************************************************************************** - * Name: up_adcinitialize + * Name: stm32_adcinitialize * * Description: - * Initialize the adc + * Initialize the ADC. The logic is, save nchannels : # of channels + * (conversions) in ADC_SQR1_L + * Then, take the chanlist array and store it in the SQR Regs, + * chanlist[0] -> ADC_SQR3_SQ1 + * chanlist[1] -> ADC_SQR3_SQ2 + * chanlist[2] -> ADC_SQR3_SQ3 + * chanlist[3] -> ADC_SQR3_SQ4 + * chanlist[4] -> ADC_SQR3_SQ5 + * chanlist[5] -> ADC_SQR3_SQ6 + * ... + * chanlist[15]-> ADC_SQR1_SQ16 + * + * up to + * chanlist[nchannels] + * + * Input Parameters: + * intf - Could be {1,2,3} for ADC1, ADC2, or ADC3 + * chanlist - The list of channels + * nchannels - Number of channels * * Returned Value: * Valid can device structure reference on succcess; a NULL on failure * ****************************************************************************/ -struct adc_dev_s *up_adcinitialize(int intf) +struct adc_dev_s *stm32_adcinitialize(int intf, uint8_t *chanlist, int nchannels) { -# warning "Question: How do you plan to handle the ADC channels? Can we do" -# " 16 or 18 individual channels? or one group?" - + FAR struct adc_dev_s *dev; + FAR struct stm32_dev_s *priv; + #ifdef CONFIG_STM32_ADC1 if (intf == 1) { - return &g_adcdev1; + adbg("ADC1 Selected \n"); + dev = &g_adcdev1; } else #endif #ifdef CONFIG_STM32_ADC2 if (intf == 2) { - return &g_adcdev2; + adbg("ADC2 Selected \n"); + dev = &g_adcdev2; } else #endif #ifdef CONFIG_STM32_ADC3 if (intf == 3) { - return &g_adcdev3; + adbg("ADC3 Selected \n"); + dev = &g_adcdev3; } else #endif { + adbg("No ADC interface defined\n"); return NULL; } + + /* Configure the selected ADC */ + + priv = dev->ad_priv; + priv->nchannels = nchannels; + memcpy(priv->chanlist, chanlist, nchannels); + return dev; } #endif /* CONFIG_STM32_ADC || CONFIG_STM32_ADC2 || CONFIG_STM32_ADC3 */