diff --git a/arch/arm/src/stm32/stm32_adc.c b/arch/arm/src/stm32/stm32_adc.c index ab876966d95..c84c0d1527f 100644 --- a/arch/arm/src/stm32/stm32_adc.c +++ b/arch/arm/src/stm32/stm32_adc.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32/stm32_adc.c * - * Copyright (C) 2011, 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2013, 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * Diego Sanchez * @@ -69,12 +69,21 @@ /* Some ADC peripheral must be enabled */ -#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) || defined(CONFIG_STM32_ADC3) +#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) || \ + defined(CONFIG_STM32_ADC3) -/* This implementation is for the STM32 F1, F2, and F4 only */ +/* This implementation is for the STM32 F1, F2, F4 and STM32L15XX only */ #if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F20XX) || \ - defined(CONFIG_STM32_STM32F40XX) + defined(CONFIG_STM32_STM32F40XX) || defined(CONFIG_STM32_STM32L15XX) + +/* At the moment there is no proper implementation for timers external + * trigger in STM32L15XX May be added latter + */ + +#if defined(ADC_HAVE_TIMER) && defined(CONFIG_STM32_STM32L15XX) +# warning "There is no proper implementation for TIMER TRIGGERS at the moment" +#endif /**************************************************************************** * Pre-processor Definitions @@ -82,15 +91,17 @@ /* ADC interrupts ***********************************************************/ #ifdef CONFIG_STM32_STM32F10XX -# define ADC_SR_ALLINTS (ADC_SR_AWD | ADC_SR_EOC | ADC_SR_JEOC) +# 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) +# 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) +# define ADC_CR1_ALLINTS (ADC_CR1_AWDIE | ADC_CR1_EOCIE | ADC_CR1_JEOCIE | \ + ADC_CR1_OVRIE) #endif /* The maximum number of channels that can be sampled. If dma support is @@ -104,6 +115,19 @@ # define ADC_MAX_SAMPLES 1 #endif +#if defined(CONFIG_STM32_STM32L15XX) +# define ADC_CHANNELS_NUMBER 32 +# define ADC_DEFAULT_SAMPLE 0x7 +#endif + +/* This can be refined or defined in Kconfig */ + +#ifndef CONFIG_ADC_TOTAL_CHANNELS +# define ADC_MAX_CHANNELS ADC_MAX_SAMPLES +#else +# define ADC_MAX_CHANNELS CONFIG_ADC_TOTAL_CHANNELS +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -112,22 +136,37 @@ struct stm32_dev_s { - uint8_t irq; /* Interrupt generated by this ADC block */ - uint8_t nchannels; /* Number of channels */ - uint8_t intf; /* ADC interface number */ - uint8_t current; /* Current ADC channel being converted */ -#ifdef ADC_HAVE_TIMER - uint8_t trigger; /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3, 3=CC4, 4=TRGO */ + uint8_t irq; /* Interrupt generated by this + * ADC block */ + uint8_t nchannels; /* Number of channels */ + uint8_t cchannels; /* Number of configured channels */ + uint8_t intf; /* ADC interface number */ + uint8_t current; /* Current ADC channel being + * converted */ +#if defined(CONFIG_STM32_STM32L15XX) + uint8_t sample_rate[ADC_CHANNELS_NUMBER]; /* Sample time selection. These + * bits must be written only + * when ADON=0 */ #endif - xcpt_t isr; /* Interrupt handler for this ADC block */ - uint32_t base; /* Base address of registers unique to this ADC block */ #ifdef ADC_HAVE_TIMER - uint32_t tbase; /* Base address of timer used by this ADC block */ - uint32_t extsel; /* EXTSEL value used by this ADC block */ - uint32_t pclck; /* The PCLK frequency that drives this timer */ - uint32_t freq; /* The desired frequency of conversions */ + uint8_t trigger; /* Timer trigger channel: 0=CC1, + * 1=CC2, 2=CC3, 3=CC4, 4=TRGO */ #endif - uint8_t chanlist[ADC_MAX_SAMPLES]; + xcpt_t isr; /* Interrupt handler for this + * ADC block */ + uint32_t base; /* Base address of registers + * unique to this ADC block */ +#ifdef ADC_HAVE_TIMER + uint32_t tbase; /* Base address of timer used by + * this ADC block */ + uint32_t extsel; /* EXTSEL value used by this ADC + * block */ + uint32_t pclck; /* The PCLK frequency that + * drives this timer */ + uint32_t freq; /* The desired frequency of + * conversions */ +#endif + uint8_t chanlist[ADC_MAX_CHANNELS]; }; /**************************************************************************** @@ -143,12 +182,14 @@ static uint16_t tim_getreg(struct stm32_dev_s *priv, int offset); static void tim_putreg(struct stm32_dev_s *priv, int offset, uint16_t value); static void adc_tim_dumpregs(struct stm32_dev_s *priv, FAR const char *msg); #endif + static void adc_rccreset(struct stm32_dev_s *priv, bool reset); /* ADC Interrupt Handler */ static int adc_interrupt(FAR struct adc_dev_s *dev); -#if defined(CONFIG_STM32_STM32F10XX) && (defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2)) +#if defined(CONFIG_STM32_STM32F10XX) && (defined(CONFIG_STM32_ADC1) || \ + defined(CONFIG_STM32_ADC2)) static int adc12_interrupt(int irq, void *context); #endif #if defined(CONFIG_STM32_STM32F10XX) && defined (CONFIG_STM32_ADC3) @@ -157,6 +198,9 @@ static int adc3_interrupt(int irq, void *context); #if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) static int adc123_interrupt(int irq, void *context); #endif +#ifdef CONFIG_STM32_STM32L15XX +static int adc_stm32l_interrupt(int irq, void *context); +#endif /* ADC Driver Methods */ @@ -166,13 +210,33 @@ 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 stm32_dev_s *priv, bool enable); +static int adc_set_ch(FAR struct adc_dev_s *dev, uint8_t ch); +static int adc_set_ch_idx(FAR struct adc_dev_s *dev, uint8_t idx); +#ifdef CONFIG_STM32_STM32L15XX + static void adc_power_down_idle(FAR struct stm32_dev_s *priv, + bool pdi_high); + static void adc_power_down_delay(FAR struct stm32_dev_s *priv, + bool pdd_high); + static void adc_dels_after_conversion(FAR struct stm32_dev_s *priv, + uint32_t delay); + static void adc_select_ch_bank(FAR struct stm32_dev_s *priv, + bool chb_selected); + static int adc_ioc_change_ints(FAR struct adc_dev_s *dev, int cmd, + bool arg); +#endif +#if defined(CONFIG_STM32_STM32L15XX) && ((STM32_CFGR_PLLSRC != 0) || \ + (STM32_SYSCLK_SW != RCC_CFGR_SW_HSI)) + static void adc_enable_hsi(bool enable); + static void adc_reset_hsi_disable(FAR struct adc_dev_s *dev); +#endif #ifdef ADC_HAVE_TIMER static void adc_timstart(FAR struct stm32_dev_s *priv, bool enable); static int adc_timinit(FAR struct stm32_dev_s *priv); #endif -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) +#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) || \ + defined(CONFIG_STM32_STM32L15XX) static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable); #endif @@ -184,11 +248,16 @@ static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable); static const struct adc_ops_s g_adcops = { - .ao_reset = adc_reset, - .ao_setup = adc_setup, - .ao_shutdown = adc_shutdown, - .ao_rxint = adc_rxint, - .ao_ioctl = adc_ioctl, +#if defined(CONFIG_STM32_STM32L15XX) && ((STM32_CFGR_PLLSRC != 0) || \ + (STM32_SYSCLK_SW != RCC_CFGR_SW_HSI)) + .ao_reset = adc_reset_hsi_disable, +#else + .ao_reset = adc_reset, +#endif + .ao_setup = adc_setup, + .ao_shutdown = adc_shutdown, + .ao_rxint = adc_rxint, + .ao_ioctl = adc_ioctl, }; /* ADC1 state */ @@ -199,12 +268,20 @@ static struct stm32_dev_s g_adcpriv1 = #ifdef CONFIG_STM32_STM32F10XX .irq = STM32_IRQ_ADC12, .isr = adc12_interrupt, +#elif defined(CONFIG_STM32_STM32L15XX) + .irq = STM32_IRQ_ADC1, + .isr = adc_stm32l_interrupt, #else .irq = STM32_IRQ_ADC, .isr = adc123_interrupt, #endif .intf = 1, +#ifndef CONFIG_STM32_STM32L15XX .base = STM32_ADC1_BASE, +#else + .base = STM32_ADC_BASE, +#endif + #ifdef ADC1_HAVE_TIMER .trigger = CONFIG_STM32_ADC1_TIMTRIG, .tbase = ADC1_TIMER_BASE, @@ -405,21 +482,22 @@ static void adc_tim_dumpregs(struct stm32_dev_s *priv, FAR const char *msg) tim_getreg(priv, STM32_GTIM_CCR2_OFFSET), tim_getreg(priv, STM32_GTIM_CCR3_OFFSET), tim_getreg(priv, STM32_GTIM_CCR4_OFFSET)); - - if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE) - { - avdbg(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n", - tim_getreg(priv, STM32_ATIM_RCR_OFFSET), - tim_getreg(priv, STM32_ATIM_BDTR_OFFSET), - tim_getreg(priv, STM32_ATIM_DCR_OFFSET), - tim_getreg(priv, STM32_ATIM_DMAR_OFFSET)); - } - else - { - avdbg(" DCR: %04x DMAR: %04x\n", - tim_getreg(priv, STM32_GTIM_DCR_OFFSET), - tim_getreg(priv, STM32_GTIM_DMAR_OFFSET)); - } +# ifndef CONFIG_STM32_STM32L15XX + if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE) + { + avdbg(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n", + tim_getreg(priv, STM32_ATIM_RCR_OFFSET), + tim_getreg(priv, STM32_ATIM_BDTR_OFFSET), + tim_getreg(priv, STM32_ATIM_DCR_OFFSET), + tim_getreg(priv, STM32_ATIM_DMAR_OFFSET)); + } + else + { + avdbg(" DCR: %04x DMAR: %04x\n", + tim_getreg(priv, STM32_GTIM_DCR_OFFSET), + tim_getreg(priv, STM32_GTIM_DMAR_OFFSET)); + } +# endif #endif } #endif @@ -459,6 +537,7 @@ static void adc_timstart(struct stm32_dev_s *priv, bool enable) regval &= ~ATIM_CR1_CEN; } + tim_putreg(priv, STM32_GTIM_CR1_OFFSET, regval); } #endif @@ -496,7 +575,7 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) uint16_t ccer; uint16_t egr; - avdbg("Initializing timers extsel = %d\n", priv->extsel); + avdbg("Initializing timers extsel = 0x%08X\n", priv->extsel); /* If the timer base address is zero, then this ADC was not configured to * use a timer. @@ -507,8 +586,9 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) #ifdef CONFIG_STM32_STM32F10XX if (!priv->tbase) { - /* Configure the ADC to use the selected timer and timer channel as the trigger - * EXTTRIG: External Trigger Conversion mode for regular channels DISABLE + /* Configure the ADC to use the selected timer and timer channel as + * the trigger EXTTRIG: External Trigger Conversion mode for regular + * channels DISABLE */ regval &= ~ADC_CR2_EXTTRIG; @@ -524,10 +604,11 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) /* EXTSEL selection: These bits select the external event used to trigger * the start of conversion of a regular group. NOTE: * - * - The position with with of the EXTSEL field varies from one STM32 MCU + * - The position with of the EXTSEL field varies from one STM32 MCU * to another. * - The width of the EXTSEL field varies from one STM3 MCU to another. - * - The value in priv->extsel is already shifted into the correct bit position. + * - The value in priv->extsel is already shifted into the correct bit + * position. */ regval &= ~ADC_CR2_EXTSEL_MASK; @@ -536,8 +617,8 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) /* Configure the timer channel to drive the ADC */ - /* Caculate optimal values for the timer prescaler and for the timer reload - * register. If freq is the desired frequency, then + /* Caculate optimal values for the timer prescaler and for the timer + * reload register. If freq is the desired frequency, then * * reload = timclk / freq * reload = (pclck / prescaler) / freq @@ -555,8 +636,8 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) prescaler = (priv->pclck / priv->freq + 65534) / 65535; - /* We need to decrement the prescaler value by one, but only, the value does - * not underflow. + /* We need to decrement the prescaler value by one, but only, the value + * does not underflow. */ if (prescaler < 1) @@ -615,13 +696,15 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) tim_putreg(priv, STM32_GTIM_PSC_OFFSET, prescaler-1); tim_putreg(priv, STM32_GTIM_ARR_OFFSET, reload); - /* Clear the advanced timers repitition counter in TIM1 */ + /* Clear the advanced timers repetition counter in TIM1 */ +#ifndef CONFIG_STM32_STM32L15XX if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE) { tim_putreg(priv, STM32_ATIM_RCR_OFFSET, 0); tim_putreg(priv, STM32_ATIM_BDTR_OFFSET, ATIM_BDTR_MOE); /* Check me */ } +#endif /* TIMx event generation: Bit 0 UG: Update generation */ @@ -751,28 +834,47 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) ccer &= ~(ATIM_CCER_CC1E | ATIM_CCER_CC2E | ATIM_CCER_CC3E | ATIM_CCER_CC4E); ccer |= ccenable; - if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE) +#ifndef CONFIG_STM32_STM32L15XX + + if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE) + { + /* Reset output N polarity level, output N state, output compare state, + * output compare N idle state. + */ + +# if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) + ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | ATIM_CCER_CC2NE | ATIM_CCER_CC2NP | + ATIM_CCER_CC3NE | ATIM_CCER_CC3NP | ATIM_CCER_CC4NP); +# else + ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | ATIM_CCER_CC2NE | ATIM_CCER_CC2NP | + ATIM_CCER_CC3NE | ATIM_CCER_CC3NP); +# endif + + /* Reset the output compare and output compare N IDLE State */ + + cr2 &= ~(ATIM_CR2_OIS1 | ATIM_CR2_OIS1N | ATIM_CR2_OIS2 | ATIM_CR2_OIS2N | + ATIM_CR2_OIS3 | ATIM_CR2_OIS3N | ATIM_CR2_OIS4); + } +# if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) + else + { + ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP); + } + #endif + +#else + + /* For the STM32L15XX family only these timers can be used: 2-4, 6, 7, 9, 10 + * Reset the output compare and output compare N IDLE State + */ + + if (priv->tbase >= STM32_TIM2_BASE && priv->tbase <= STM32_TIM4_BASE) { - /* Reset output N polarity level, output N state, output compre state, + /* Reset output N polarity level, output N state, output compare state, * output compare N idle state. */ -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | ATIM_CCER_CC2NE | ATIM_CCER_CC2NP | ATIM_CCER_CC3NE | ATIM_CCER_CC3NP | ATIM_CCER_CC4NP); -#else - ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | ATIM_CCER_CC2NE | ATIM_CCER_CC2NP | - ATIM_CCER_CC3NE | ATIM_CCER_CC3NP); -#endif - - /* Reset the output compare and output compare N IDLE State */ - - cr2 &= ~(ATIM_CR2_OIS1 | ATIM_CR2_OIS1N | ATIM_CR2_OIS2 | ATIM_CR2_OIS2N | - ATIM_CR2_OIS3 | ATIM_CR2_OIS3N | ATIM_CR2_OIS4); - } -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) - else - { - ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP); } #endif @@ -816,7 +918,8 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) * ****************************************************************************/ -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) +#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) || \ + defined(CONFIG_STM32_STM32L15XX) static void adc_startconv(struct stm32_dev_s *priv, bool enable) { uint32_t regval; @@ -824,14 +927,31 @@ static void adc_startconv(struct stm32_dev_s *priv, bool enable) avdbg("enable: %d\n", enable); regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); + if (enable) { - /* Start conversion of regular channles */ +#if CONFIG_ADC_CONTINUOUS + + /* Set continuous mode */ + + regval |= ADC_CR2_CONT; + +#endif + + /* Start conversion of regular channels */ regval |= ADC_CR2_SWSTART; } else { +#if CONFIG_ADC_CONTINUOUS + + /* Disable the continuous conversion */ + + regval &= ~ADC_CR2_CONT; + +#endif + /* Disable the conversion of regular channels */ regval &= ~ADC_CR2_SWSTART; @@ -887,6 +1007,9 @@ static void adc_rccreset(struct stm32_dev_s *priv, bool reset) return; } +#elif defined(CONFIG_STM32_STM32L15XX) + adcbit = RCC_APB2RSTR_ADC1RST; + #else /* For the STM32 F4, there is one common reset for all ADC block. * THIS will probably cause some problems! @@ -916,10 +1039,162 @@ static void adc_rccreset(struct stm32_dev_s *priv, bool reset) regval &= ~adcbit; } + putreg32(regval, STM32_RCC_APB2RSTR); irqrestore(flags); } +/******************************************************************************* + * Name: adc_power_down_idle + * + * Description : Enables or disables power down during the idle phase. + * + * Input Parameters: + * + * priv - pointer to the adc device structure + * pdi_high - true: The ADC is powered down when waiting for a start event + * false: The ADC is powered up when waiting for a start event + * + * Returned Value: + * None. + * + *******************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_power_down_idle(FAR struct stm32_dev_s *priv, bool pdi_high) +{ + uint32_t regval = 0; + + avdbg("PDI: %d\n", (pdi_high ? 1 : 0)); + + regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); + + if (!(STM32_ADC1_CR2 & ADC_CR2_ADON)) + { + if (pdi_high) + { + regval |= ADC_CR1_PDI; + } + else + { + regval &= ~ADC_CR1_PDI; + } + + adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); + } +} +#endif + +/******************************************************************************* + * Name: adc_power_down_delay + * + * Description : Enables or disables power down during the delay phase. + * + * Input Parameters: + * + * priv - pointer to the adc device structure + * pdd_high - true: The ADC is powered down when waiting for a start event + * false: The ADC is powered up when waiting for a start event + * + * Returned Value: + * None. + * + *******************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_power_down_delay(FAR struct stm32_dev_s *priv, bool pdd_high) +{ + uint32_t regval = 0; + + avdbg("PDD: %d\n", (pdd_high ? 1 : 0)); + + regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); + + if (!(STM32_ADC1_CR2 & ADC_CR2_ADON)) + { + if (pdd_high) + { + regval |= ADC_CR1_PDD; + } + else + { + regval &= ~ADC_CR1_PDD; + } + + adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); + } +} +#endif + +/******************************************************************************* + * Name: adc_dels_after_conversion + * + * Description : Defines the length of the delay which is applied + * after a conversion or a sequence of conversions. + * + * Input Parameters: + * + * priv - pointer to the adc device structure + * delay - delay selection (see definition in chip/chip/stm32_adc.h + * starting from line 284) + * + * Returned Value: + * + *******************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_dels_after_conversion(FAR struct stm32_dev_s *priv, + uint32_t delay) +{ + uint32_t regval; + + avdbg("Delay selected: 0x%08X\n", delay); + + regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); + regval &= ~ADC_CR2_DELS_MASK; + regval |= delay; + adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval); +} +#endif + +/******************************************************************************* + * Name: adc_select_ch_bank + * + * Description : Selects the bank of channels to be converted + * (! Must be modified only when no conversion is on going !) + * + * Input Parameters: + * + * priv - pointer to the adc device structure + * enable - true: bank of channels B selected + * false: bank of channels A selected + * + * Returned Value: + * + *******************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_select_ch_bank(FAR struct stm32_dev_s *priv, bool chb_selected) +{ + uint32_t regval; + + avdbg("Bank of channels selected: %c\n", (chb_selected ? 'B' : 'A')); + + regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); + + if (chb_selected) + { + regval |= ADC_CR2_CFG; + } + else + { + regval &= ~ADC_CR2_CFG; + } + + adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval); +} +#endif + /******************************************************************************* * Name: adc_enable * @@ -940,20 +1215,92 @@ static void adc_enable(FAR struct stm32_dev_s *priv, bool enable) { uint32_t regval; - avdbg("enable: %d\n", enable); + avdbg("enable: %d\n", (enable ? 1 : 0)); - regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); - if (enable) + regval = adc_getreg(priv, STM32_ADC_SR_OFFSET); + + if (!(regval & ADC_SR_ADONS) && enable) { + regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); regval |= ADC_CR2_ADON; } - else + else if ((regval & ADC_SR_ADONS) && !enable) { + regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); regval &= ~ADC_CR2_ADON; } + adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval); } +/**************************************************************************** + * Name: adc_write_sample_time_registers + * + * Description: + * Writes previously defined values into ADC_SMPR0, ADC_SMPR1, ADC_SMPR2 + * and ADC_SMPR3 registers + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_write_sample_time_registers(FAR struct adc_dev_s *dev) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + uint32_t value = 0; + uint8_t i, shift; + + /* Sampling time individually for each channel + * 000: 4 cycles + * 001: 9 cycles + * 010: 16 cycles + * 011: 24 cycles + * 100: 48 cycles + * 101: 96 cycles + * 110: 192 cycles + * 111: 384 cycles - selected for all channels + */ + + for (i = 0, shift = 0; i < 32; i++) + { + value |= priv->sample_rate[i] << (shift * 3); + switch (i) + { + case 9: + adc_putreg(priv, STM32_ADC_SMPR3_OFFSET, value); + shift = 0; + value = 0; + break; + + case 19: + adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, value); + shift = 0; + value = 0; + break; + + case 29: + adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, value); + shift = 0; + value = 0; + break; + + case 31: + adc_putreg(priv, STM32_ADC_SMPR0_OFFSET, value); + shift = 0; + value = 0; + break; + + default: + shift++; + break; + } + } +} +#endif + /**************************************************************************** * Name: adc_reset * @@ -972,15 +1319,22 @@ static void adc_reset(FAR struct adc_dev_s *dev) FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; irqstate_t flags; uint32_t regval; - int offset; - int i; #ifdef ADC_HAVE_TIMER int ret; #endif - avdbg("intf: ADC%d\n", priv->intf); + allvdbg("intf: ADC%d\n", priv->intf); flags = irqsave(); + /* In STM32L15XX family HSI used as an independent clock-source for the ADC */ + +#if defined(CONFIG_STM32_STM32L15XX) && ((STM32_CFGR_PLLSRC != 0) || \ + (STM32_SYSCLK_SW != RCC_CFGR_SW_HSI)) + + adc_enable_hsi(true); + +#endif + /* Enable ADC reset state */ adc_rccreset(priv, true); @@ -1002,6 +1356,7 @@ static void adc_reset(FAR struct adc_dev_s *dev) /* Initialize the same sample time for each ADC 55.5 cycles * * During sample cycles channel selection bits must remain unchanged. + * For F-family only * * 000: 1.5 cycles * 001: 7.5 cycles @@ -1013,8 +1368,12 @@ static void adc_reset(FAR struct adc_dev_s *dev) * 111: 239.5 cycles */ +#ifndef CONFIG_STM32_STM32L15XX adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, 0x00b6db6d); adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, 0x00b6db6d); +#else + adc_write_sample_time_registers(dev); +#endif /* ADC CR1 Configuration */ @@ -1035,7 +1394,8 @@ static void adc_reset(FAR struct adc_dev_s *dev) regval |= ADC_CR1_ALLINTS; -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) +#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) || \ + defined(CONFIG_STM32_STM32L15XX) /* Enable or disable Overrun interrupt */ @@ -1048,6 +1408,25 @@ static void adc_reset(FAR struct adc_dev_s *dev) adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); +#ifdef CONFIG_STM32_STM32L15XX + + /* Disables power down during the delay phase */ + + adc_power_down_idle(priv, false); + adc_power_down_delay(priv, false); +#endif + +#ifdef CONFIG_STM32_STM32L15XX + + /* Select the bank of channels A */ + + adc_select_ch_bank(priv, false); + + /* Delay until the converted data has been read */ + + adc_dels_after_conversion(priv, ADC_CR2_DELS_TILLRD); +#endif + /* ADC CR2 Configuration */ regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); @@ -1060,43 +1439,39 @@ static void adc_reset(FAR struct adc_dev_s *dev) regval &= ~ADC_CR2_ALIGN; -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) +#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) || \ + defined(CONFIG_STM32_STM32L15XX) /* External trigger enable for regular channels */ - regval |= ADC_CR2_EXTEN_RISING; + regval |= ADC_CR2_EXTEN_NONE; #endif adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval); /* Configuration of the channel conversions */ - regval = adc_getreg(priv, STM32_ADC_SQR3_OFFSET) & ADC_SQR3_RESERVED; - for (i = 0, offset = 0; i < priv->nchannels && i < 6; i++, offset += 5) - { - regval |= (uint32_t)priv->chanlist[i] << offset; - } - adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); - - regval = adc_getreg(priv, STM32_ADC_SQR2_OFFSET) & ADC_SQR2_RESERVED; - for (i = 6, offset = 0; i < priv->nchannels && i < 12; i++, offset += 5) - { - regval |= (uint32_t)priv->chanlist[i] << offset; - } - adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); - - regval = adc_getreg(priv, STM32_ADC_SQR1_OFFSET) & ADC_SQR1_RESERVED; - for (i = 12, offset = 0; i < priv->nchannels && i < 16; i++, offset += 5) - { - regval |= (uint32_t)priv->chanlist[i] << offset; - } +#if ADC_MAX_SAMPLES == 1 + /* Select on first indexed channel for backward compatibility. */ + adc_set_ch_idx(dev,0); +#else + adc_set_ch(dev,0); +#endif /* ADC CCR configuration */ #if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) regval = getreg32(STM32_ADC_CCR); - regval &= ~(ADC_CCR_MULTI_MASK | ADC_CCR_DELAY_MASK | ADC_CCR_DDS | ADC_CCR_DMA_MASK | - ADC_CCR_ADCPRE_MASK | ADC_CCR_VBATE | ADC_CCR_TSVREFE); - regval |= (ADC_CCR_MULTI_NONE | ADC_CCR_DMA_DISABLED | ADC_CCR_ADCPRE_DIV2); + regval &= ~(ADC_CCR_MULTI_MASK | ADC_CCR_DELAY_MASK | ADC_CCR_DDS | + ADC_CCR_DMA_MASK | ADC_CCR_ADCPRE_MASK | ADC_CCR_VBATE | + ADC_CCR_TSVREFE); + regval |= (ADC_CCR_MULTI_NONE | ADC_CCR_DMA_DISABLED | + ADC_CCR_ADCPRE_DIV2); + putreg32(regval, STM32_ADC_CCR); + +#elif defined(CONFIG_STM32_STM32L15XX) + regval = getreg32(STM32_ADC_CCR); + regval &= ~(ADC_CCR_ADCPRE_MASK | ADC_CCR_TSVREFE); + regval |= ADC_CCR_ADCPRE_DIV2; putreg32(regval, STM32_ADC_CCR); #endif @@ -1122,13 +1497,15 @@ static void adc_reset(FAR struct adc_dev_s *dev) adbg("Error initializing the timers\n"); } #else + #ifdef CONFIG_STM32_STM32F10XX /* Set ADON (Again) to start the conversion. Only if Timers are not * configured as triggers */ adc_enable(priv, true); -#else + +#elif !defined(CONFIG_ADC_NO_STARTUP_CONV) adc_startconv(priv, true); #endif /* CONFIG_STM32_STM32F10XX */ #endif /* ADC_HAVE_TIMER */ @@ -1143,12 +1520,43 @@ static void adc_reset(FAR struct adc_dev_s *dev) adc_getreg(priv, STM32_ADC_SQR1_OFFSET), adc_getreg(priv, STM32_ADC_SQR2_OFFSET), adc_getreg(priv, STM32_ADC_SQR3_OFFSET)); -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) +#ifdef CONFIG_STM32_STM32L15XX + avdbg("SQR4: 0x%08x SQR5: 0x%08x\n", + adc_getreg(priv, STM32_ADC_SQR4_OFFSET), + adc_getreg(priv, STM32_ADC_SQR5_OFFSET)); +#endif + +#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) || \ + defined(CONFIG_STM32_STM32L15XX) avdbg("CCR: 0x%08x\n", getreg32(STM32_ADC_CCR)); #endif } +/**************************************************************************** + * Name: adc_reset_hsi_disable + * + * Description: + * Reset the ADC device with HSI and ADC shut down. Called early to + * initialize the hardware. This is called, before adc_setup() and on + * error conditions. In STM32L15XX case sometimes HSI must be shut + * down after the first initialization + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(CONFIG_STM32_STM32L15XX) && ((STM32_CFGR_PLLSRC != 0) || \ + (STM32_SYSCLK_SW != RCC_CFGR_SW_HSI)) +static void adc_reset_hsi_disable(FAR struct adc_dev_s *dev) +{ + adc_reset(dev); + adc_shutdown(dev); +} +#endif + /**************************************************************************** * Name: adc_setup * @@ -1204,6 +1612,14 @@ static void adc_shutdown(FAR struct adc_dev_s *dev) { FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; +#if CONFIG_STM32_STM32L15XX + adc_enable(priv, false); +# if defined(CONFIG_STM32_STM32L15XX) && ((STM32_CFGR_PLLSRC != 0) || \ + (STM32_SYSCLK_SW != RCC_CFGR_SW_HSI)) + adc_enable_hsi(false); +# endif +#endif + /* Disable ADC interrupts and detach the ADC interrupt handler */ up_disable_irq(priv->irq); @@ -1234,21 +1650,542 @@ static void adc_rxint(FAR struct adc_dev_s *dev, bool enable) avdbg("intf: %d enable: %d\n", priv->intf, enable); regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); + +#ifndef CONFIG_STM32_HAVE_ONLY_EOCIE if (enable) { /* Enable the end-of-conversion ADC and analog watchdog interrupts */ regval |= ADC_CR1_ALLINTS; } +#else + if (enable) + { + + /* Clear all interrupts */ + + regval &= ~ADC_CR1_ALLINTS; + + /* Enable the end-of-conversion ADC interrupt */ + + regval |= ADC_CR1_EOCIE; + } +#endif else { /* Disable all ADC interrupts */ regval &= ~ADC_CR1_ALLINTS; } + adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); } +/**************************************************************************** + * Name: adc_enable_tvref_register + * + * Description: + * Enable/disable the temperature sensor and the VREFINT channel. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * enable - true: Temperature sensor and V REFINT channel enabled (ch 16 and 17) + * false: Temperature sensor and V REFINT channel disabled (ch 16 and 17) + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_ioc_enable_tvref_register(FAR struct adc_dev_s *dev, bool enable) +{ + uint32_t regval; + + regval = getreg32(STM32_ADC_CCR); + + if (enable) + { + regval |= ADC_CCR_TSVREFE; + } + else + { + regval &= ~ADC_CCR_TSVREFE; + } + + putreg32(regval, STM32_ADC_CCR); + allvdbg("STM32_ADC_CCR value: 0x%08X\n", getreg32(STM32_ADC_CCR)); +} +#endif + +/**************************************************************************** + * Name: adc_ioc_change_sleep_between_opers + * + * Description: + * Changes PDI and PDD bits to save battery. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * cmd - command + * arg - arguments passed with command + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static int adc_ioc_change_sleep_between_opers(FAR struct adc_dev_s *dev, + int cmd, bool arg) +{ + int ret = OK; + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + + adc_enable(priv, false); + + switch (cmd) + { + case IO_ENABLE_DISABLE_PDI: + adc_power_down_idle(priv, arg); + break; + + case IO_ENABLE_DISABLE_PDD: + adc_power_down_delay(priv, arg); + break; + + case IO_ENABLE_DISABLE_PDD_PDI: + adc_power_down_idle(priv, arg); + adc_power_down_delay(priv, arg); + break; + + default: + avdbg("unknown cmd: %d\n", cmd); + break; + } + + adc_enable(priv, true); + + return ret; +} +#endif + +/**************************************************************************** + * Name: adc_ioc_enable_awd_int + * + * Description: + * Turns ON/OFF ADC analog watch-dog interrupt. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * arg - true: Turn ON interrupt + * false: Turn OFF interrupt + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_ioc_enable_awd_int(FAR struct stm32_dev_s *priv, bool enable) +{ + uint32_t regval = 0; + + regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); + if (enable) + { + regval |= ADC_CR1_AWDIE; + } + else + { + regval &= ~ADC_CR1_AWDIE; + } + + adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); +} +#endif + +/**************************************************************************** + * Name: adc_ioc_enable_eoc_int + * + * Description: + * Turns ON/OFF ADC EOC interrupt. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * arg - true: Turn ON interrupt + * false: Turn OFF interrupt + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_ioc_enable_eoc_int(FAR struct stm32_dev_s *priv, bool enable) +{ + uint32_t regval = 0; + + regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); + if (enable) + { + regval |= ADC_CR1_EOCIE; + } + else + { + regval &= ~ADC_CR1_EOCIE; + } + + adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); +} +#endif + +/**************************************************************************** + * Name: adc_ioc_enable_jeoc_int + * + * Description: + * Turns ON/OFF ADC injected channels interrupt. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * arg - true: Turn ON interrupt + * false: Turn OFF interrupt + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_ioc_enable_jeoc_int(FAR struct stm32_dev_s *priv, bool enable) +{ + uint32_t regval = 0; + + regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); + if (enable) + { + regval |= ADC_CR1_JEOCIE; + } + else + { + regval &= ~ADC_CR1_JEOCIE; + } + + adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); +} +#endif + +/**************************************************************************** + * Name: adc_ioc_enable_ovr_int + * + * Description: + * Turns ON/OFF ADC overrun interrupt. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * arg - true: Turn ON interrupt + * false: Turn OFF interrupt + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static void adc_ioc_enable_ovr_int(FAR struct stm32_dev_s *priv, bool enable) +{ + uint32_t regval = 0; + + regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); + if (enable) + { + regval |= ADC_CR1_OVRIE; + } + else + { + regval &= ~ADC_CR1_OVRIE; + } + + adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); +} +#endif + +/**************************************************************************** + * Name: adc_ioc_change_ints + * + * Description: + * Turns ON/OFF ADC interrupts. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * cmd - command + * arg - arguments passed with command + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static int adc_ioc_change_ints(FAR struct adc_dev_s *dev, int cmd, bool arg) +{ + int ret = OK; + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + + switch (cmd) + { + case IO_ENABLE_DISABLE_AWDIE: + adc_ioc_enable_awd_int(priv, arg); + break; + + case IO_ENABLE_DISABLE_EOCIE: + adc_ioc_enable_eoc_int(priv, arg); + break; + + case IO_ENABLE_DISABLE_JEOCIE: + adc_ioc_enable_jeoc_int(priv, arg); + break; + + case IO_ENABLE_DISABLE_OVRIE: + adc_ioc_enable_ovr_int(priv, arg); + break; + + case IO_ENABLE_DISABLE_ALL_INTS: + adc_ioc_enable_awd_int(priv, arg); + adc_ioc_enable_eoc_int(priv, arg); + adc_ioc_enable_jeoc_int(priv, arg); + adc_ioc_enable_ovr_int(priv, arg); + break; + + default: + avdbg("unknown cmd: %d\n", cmd); + break; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: adc_ioc_wait_rcnr_zeroed + * + * Description: + * For the STM3215XX-family the ADC_SR_RCNR bit must be zeroed, + * before next conversion. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static int adc_ioc_wait_rcnr_zeroed(FAR struct stm32_dev_s *priv) +{ + int i = 0; + uint32_t regval = 0; + + for (i = 0; i < 30000; i++) + { + if (!((regval = adc_getreg(priv, STM32_ADC_SR_OFFSET)) & ADC_SR_RCNR)) + { + return OK; + } + } + + return -ENODATA; +} +#endif + +/**************************************************************************** + * Name: adc_enable_hsi + * + * Description: + * Enable/Disable HSI clock + * + * Input Parameters: + * enable - true : HSI clock for ADC enabled + * false : HSI clock for ADC disabled + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(CONFIG_STM32_STM32L15XX) && ((STM32_CFGR_PLLSRC != 0) || \ + (STM32_SYSCLK_SW != RCC_CFGR_SW_HSI)) +static void adc_enable_hsi(bool enable) +{ + uint32_t regval = 0; + + if (enable) + { + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_HSION; + putreg32(regval, STM32_RCC_CR); /* Enable the HSI */ + while ((getreg32(STM32_RCC_CR) & RCC_CR_HSIRDY) == 0); + } + else + { + regval = getreg32(STM32_RCC_CR); + regval &= ~RCC_CR_HSION; + putreg32(regval, STM32_RCC_CR); /* Disable the HSI */ + } +} +#endif + +/**************************************************************************** + * Name: adc_set_ch_idx + * + * Description: + * Set single channel for adc conversion. Channel selected from + * configured channel list by index. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * idx - channel index in configured channel list + * + * Returned Value: + * int - errno + * + ****************************************************************************/ + +static int adc_set_ch_idx(FAR struct adc_dev_s *dev, uint8_t idx) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + int32_t regval; + + if (idx < priv->cchannels) + { +#ifdef CONFIG_STM32_STM32L15XX + regval = adc_getreg(priv, STM32_ADC_SQR5_OFFSET) & ADC_SQR3_RESERVED; +#else + regval = adc_getreg(priv, STM32_ADC_SQR3_OFFSET) & ADC_SQR3_RESERVED; +#endif + regval |= (uint32_t)priv->chanlist[idx]; +#ifdef CONFIG_STM32_STM32L15XX + adc_putreg(priv, STM32_ADC_SQR5_OFFSET, regval); +#else + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); +#endif + return 0; + } + else + { + return -ENODEV; + } +} + +/**************************************************************************** + * Name: adc_set_channel + * + * Description: + * All ioctl calls will be routed through this method. + * + * Input Parameters: + * dev - pointer to device structure used by the driver + * ch - ADC channel number + 1. 0 reserved for all configured channels + * + * Returned Value: + * int - errno + * + ****************************************************************************/ + +static int adc_set_ch(FAR struct adc_dev_s *dev, uint8_t ch) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + uint32_t regval; + int i, ret = 0; + + if (ch == 0) + { + int offset; + +#ifdef CONFIG_STM32_STM32L15XX + priv->nchannels = priv->cchannels; + regval = adc_getreg(priv, STM32_ADC_SQR5_OFFSET) & ADC_SQR5_RESERVED; + for (i = 0, offset = 0; i < priv->nchannels && i < 6; i++, offset += 5) + { + regval |= (uint32_t)priv->chanlist[i] << offset; + } + + adc_putreg(priv, STM32_ADC_SQR5_OFFSET, regval); + + regval = adc_getreg(priv, STM32_ADC_SQR4_OFFSET) & ADC_SQR4_RESERVED; + for (i = 6, offset = 0; i < priv->nchannels && i < 12; i++, offset += 5) + { + regval |= (uint32_t)priv->chanlist[i] << offset; + } + + adc_putreg(priv, STM32_ADC_SQR4_OFFSET, regval); + + regval = adc_getreg(priv, STM32_ADC_SQR3_OFFSET) & ADC_SQR3_RESERVED; + for (i = 12, offset = 0; i < priv->nchannels && i < 18; i++, offset += 5) + { + regval |= (uint32_t)priv->chanlist[i] << offset; + } + + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); + + regval = adc_getreg(priv, STM32_ADC_SQR2_OFFSET) & ADC_SQR2_RESERVED; + for (i = 18, offset = 0; i < priv->nchannels && i < 24; i++, offset += 5) + { + regval |= (uint32_t)priv->chanlist[i] << offset; + } + + adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); + + regval = adc_getreg(priv, STM32_ADC_SQR1_OFFSET) & ADC_SQR1_RESERVED; + for (i = 24, offset = 0; i < priv->nchannels && i < 28; i++, offset += 5) + { + regval |= (uint32_t)priv->chanlist[i] << offset; + } + +#else + regval = adc_getreg(priv, STM32_ADC_SQR3_OFFSET) & ADC_SQR3_RESERVED; + for (i = 0, offset = 0; i < priv->nchannels && i < 6; i++, offset += 5) + { + regval |= (uint32_t)priv->chanlist[i] << offset; + } + + adc_putreg(priv, STM32_ADC_SQR3_OFFSET, regval); + + regval = adc_getreg(priv, STM32_ADC_SQR2_OFFSET) & ADC_SQR2_RESERVED; + for (i = 6, offset = 0; i < priv->nchannels && i < 12; i++, offset += 5) + { + regval |= (uint32_t)priv->chanlist[i] << offset; + } + + adc_putreg(priv, STM32_ADC_SQR2_OFFSET, regval); + + regval = adc_getreg(priv, STM32_ADC_SQR1_OFFSET) & ADC_SQR1_RESERVED; + for (i = 12, offset = 0; i < priv->nchannels && i < 16; i++, offset += 5) + { + regval |= (uint32_t)priv->chanlist[i] << offset; + } +#endif + } + else + { + ch = ch - 1; + for (i = 0; i < priv->cchannels; i++) + { + if ((uint32_t)priv->chanlist[i] == ch) + { + ret = adc_set_ch_idx(dev,i); + if (ret < 0) + { + break; + } + + regval = adc_getreg(priv, STM32_ADC_SQR1_OFFSET) & ADC_SQR1_RESERVED; + regval &= ~(ADC_SQR1_L_MASK); + adc_putreg(priv, STM32_ADC_SQR1_OFFSET, regval); + priv->current = i; + priv->nchannels = 1; + return ret; + } + } + + ret = -ENODEV; + } + + return ret; +} + /**************************************************************************** * Name: adc_ioctl * @@ -1256,6 +2193,9 @@ static void adc_rxint(FAR struct adc_dev_s *dev, bool enable) * All ioctl calls will be routed through this method. * * Input Parameters: + * dev - pointer to device structure used by the driver + * cmd - command + * arg - arguments passed with command * * Returned Value: * @@ -1263,7 +2203,83 @@ 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) { +#ifdef CONFIG_STM32_STM32L15XX + int ret = OK; + FAR struct stm32_dev_s * priv = (FAR struct stm32_dev_s *)dev->ad_priv; + + switch (cmd) + { + case IO_ENABLE_TEMPER_VOLT_CH: + adc_ioc_enable_tvref_register(dev, *(bool *)arg); + break; + + case IO_ENABLE_DISABLE_PDI: + case IO_ENABLE_DISABLE_PDD: + case IO_ENABLE_DISABLE_PDD_PDI: + adc_ioc_change_sleep_between_opers(dev, cmd, *(bool *)arg); + break; + + case IO_ENABLE_DISABLE_AWDIE: + case IO_ENABLE_DISABLE_EOCIE: + case IO_ENABLE_DISABLE_JEOCIE: + case IO_ENABLE_DISABLE_OVRIE: + case IO_ENABLE_DISABLE_ALL_INTS: + adc_ioc_change_ints(dev, cmd, *(bool*)arg); + break; + + case IO_START_CONV: + { + uint8_t ch = ((uint8_t)arg); + + ret = adc_ioc_wait_rcnr_zeroed(priv); + if (ret < 0) + { + set_errno(-ret); + return ret; + } + + ret = adc_set_ch(dev,ch); + if (ret < 0) + { + set_errno(-ret); + return ret; + } + + if (ch) + { + /* Clear fifo */ + + dev->ad_recv.af_head = 0; + dev->ad_recv.af_tail = 0; + } + + adc_startconv(priv, true); + break; + } + +#if defined(CONFIG_STM32_STM32L15XX) && ((STM32_CFGR_PLLSRC != 0) || \ + (STM32_SYSCLK_SW != RCC_CFGR_SW_HSI)) + case IO_STOP_ADC: + adc_enable(priv, false); + adc_enable_hsi(false); + break; + + case IO_START_ADC: + adc_enable_hsi(true); + adc_enable(priv, true); + break; +#endif + + default: + alldbg("unknown cmd: %d\n", cmd); + break; + } + + return OK; +#else + return -ENOTTY; +#endif } /**************************************************************************** @@ -1292,10 +2308,11 @@ static int adc_interrupt(FAR struct adc_dev_s *dev) alldbg("WARNING: Analog Watchdog, Value converted out of range!\n"); } -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) +#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) || \ + defined(CONFIG_STM32_STM32L15XX) if ((adcsr & ADC_SR_OVR) != 0) { - alldbg("WARNING: Overrun has ocurred!\n"); + alldbg("WARNING: Overrun has occurred!\n"); } #endif @@ -1310,7 +2327,8 @@ static int adc_interrupt(FAR struct adc_dev_s *dev) value = adc_getreg(priv, STM32_ADC_DR_OFFSET); value &= ADC_DR_DATA_MASK; - /* Give the ADC data to the ADC driver. adc_receive accepts 3 parameters: + /* Give the ADC data to the ADC driver. adc_receive accepts 3 + * parameters: * * 1) The first is the ADC device instance for this ADC block. * 2) The second is the channel number for the data, and @@ -1319,7 +2337,9 @@ static int adc_interrupt(FAR struct adc_dev_s *dev) adc_receive(dev, priv->chanlist[priv->current], value); - /* Set the channel number of the next channel that will complete conversion */ + /* Set the channel number of the next channel that will complete + * conversion. + */ priv->current++; @@ -1346,7 +2366,8 @@ static int adc_interrupt(FAR struct adc_dev_s *dev) * ****************************************************************************/ -#if defined(CONFIG_STM32_STM32F10XX) && (defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2)) +#if defined(CONFIG_STM32_STM32F10XX) && (defined(CONFIG_STM32_ADC1) || \ + defined(CONFIG_STM32_ADC2)) static int adc12_interrupt(int irq, void *context) { uint32_t regval; @@ -1414,6 +2435,45 @@ static int adc3_interrupt(int irq, void *context) } #endif +/**************************************************************************** + * Name: adc123_interrupt + * + * Description: + * ADC interrupt handler for the STM32 L15XX family. + * + * Input Parameters: + * irq - The IRQ number that generated the interrupt. + * context - Architecture specific register save information. + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +static int adc_stm32l_interrupt(int irq, void *context) +{ + uint32_t regval; + uint32_t pending; + + /* STM32L15XX-family has the only ADC. For the sake of the simplicity the ADC1 + * name is used everywhere + */ + +#ifdef CONFIG_STM32_ADC1 + regval = getreg32(STM32_ADC1_SR); + pending = regval & ADC_SR_ALLINTS; + if (pending != 0) + { + adc_interrupt(&g_adcdev1); + regval &= ~pending; + putreg32(regval, STM32_ADC1_SR); + } +#endif + + return OK; +} +#endif + /**************************************************************************** * Name: adc123_interrupt * @@ -1478,6 +2538,59 @@ static int adc123_interrupt(int irq, void *context) * Public Functions ****************************************************************************/ +/******************************************************************************* + * Name: adc_change_sample_time + * + * Description : Changes sample times for specified channels. This method + * doesn't make any register writing. So, it's only stores the information. + * Values provided by user will be written in registers only on the next adc + * peripheral start, as it was told to do in manual. However, before very first + * start, user can call this method and override default values either + * for every channels or for only some predefined by user channel(s) + * + * Input Parameters: + * + * priv - pointer to the adc device structure + * pdi_high - true: The ADC is powered down when waiting for a start event + * false: The ADC is powered up when waiting for a start event + * + * Returned Value: + * None. + * + *******************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +void stm32_adcchange_sample_time(FAR struct adc_dev_s *dev, + FAR struct adc_sample_time_s *time_samples) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + uint8_t ch_index; + uint8_t i; + + /* Check if user wants to assign the same value for all channels + * or just wants to change sample time values for certain channels */ + + if (time_samples->all_same) + { + memset(priv->sample_rate, time_samples->all_ch_sample_time, + ADC_CHANNELS_NUMBER); + } + else + { + for (i = 0; i < time_samples->channels_nbr; i++) + { + ch_index = time_samples->channel->channel; + if (ch_index >= ADC_CHANNELS_NUMBER) + { + break; + } + + priv->sample_rate[ch_index] = time_samples->channel->sample_time; + } + } +} +#endif + /**************************************************************************** * Name: stm32_adcinitialize * @@ -1504,17 +2617,18 @@ static int adc123_interrupt(int irq, void *context) * ****************************************************************************/ -struct adc_dev_s *stm32_adcinitialize(int intf, const uint8_t *chanlist, int nchannels) +struct adc_dev_s *stm32_adcinitialize(int intf, const uint8_t *chanlist, + int cchannels) { FAR struct adc_dev_s *dev; FAR struct stm32_dev_s *priv; - avdbg("intf: %d nchannels: %d\n", intf, nchannels); + allvdbg("intf: %d nchannels: %d\n", intf, cchannels); #ifdef CONFIG_STM32_ADC1 if (intf == 1) { - avdbg("ADC1 Selected\n"); + allvdbg("ADC1 Selected\n"); dev = &g_adcdev1; } else @@ -1544,10 +2658,19 @@ struct adc_dev_s *stm32_adcinitialize(int intf, const uint8_t *chanlist, int nch priv = dev->ad_priv; - DEBUGASSERT(nchannels <= ADC_MAX_SAMPLES); - priv->nchannels = nchannels; +#if defined(CONFIG_STM32_STM32L15XX) + + /* Assign default values for the sample time table */ + + memset(priv->sample_rate, ADC_DEFAULT_SAMPLE, ADC_CHANNELS_NUMBER); + +#endif + + DEBUGASSERT(cchannels <= ADC_MAX_CHANNELS); + priv->cchannels = cchannels; + + memcpy(priv->chanlist, chanlist, cchannels); - memcpy(priv->chanlist, chanlist, nchannels); return dev; } diff --git a/arch/arm/src/stm32/stm32_adc.h b/arch/arm/src/stm32/stm32_adc.h index f1e4d1dd5ef..e89d502c8cd 100644 --- a/arch/arm/src/stm32/stm32_adc.h +++ b/arch/arm/src/stm32/stm32_adc.h @@ -63,7 +63,7 @@ */ /* For the STM32 F1 line, timers 1-4 may be used. For STM32 F4 line, timers 1-5 and - * 8 may be used. + * 8 may be used. For the STM32L15XX line, timers 2-4, 6, 7, 9, 10 may be used */ #ifndef CONFIG_STM32_TIM1 @@ -104,6 +104,7 @@ # undef CONFIG_STM32_TIM8_ADC2 # undef CONFIG_STM32_TIM8_ADC3 # endif +# #else # undef CONFIG_STM32_TIM5_ADC # undef CONFIG_STM32_TIM5_ADC1 @@ -115,24 +116,60 @@ # undef CONFIG_STM32_TIM8_ADC3 #endif -/* Timers 6, 7, and 10-14 are not used with the ADC by any supported family */ +/* Timers 6, 7, 9, 10 used by STM32L15XX family devices. Though there is only ADC + * presented in specification and in device as well, the ADC1 is used here in code. + * See definition of the STM32_NADC + */ + +#if defined(CONFIG_STM32_STM32L15XX) +# ifndef CONFIG_STM32_TIM6 +# undef CONFIG_STM32_TIM6_ADC +# undef CONFIG_STM32_TIM6_ADC1 +# undef CONFIG_STM32_TIM6_ADC2 +# undef CONFIG_STM32_TIM6_ADC3 +# endif +# ifndef CONFIG_STM32_TIM7 +# undef CONFIG_STM32_TIM7_ADC +# undef CONFIG_STM32_TIM7_ADC1 +# undef CONFIG_STM32_TIM7_ADC2 +# undef CONFIG_STM32_TIM7_ADC3 +# endif +# ifndef CONFIG_STM32_TIM9 +# undef CONFIG_STM32_TIM9_ADC +# undef CONFIG_STM32_TIM9_ADC1 +# undef CONFIG_STM32_TIM9_ADC2 +# undef CONFIG_STM32_TIM9_ADC3 +# endif +# ifndef CONFIG_STM32_TIM10 +# undef CONFIG_STM32_TIM10_ADC +# undef CONFIG_STM32_TIM10_ADC1 +# undef CONFIG_STM32_TIM10_ADC2 +# undef CONFIG_STM32_TIM10_ADC3 +# endif +# +#else +# undef CONFIG_STM32_TIM6_ADC +# undef CONFIG_STM32_TIM6_ADC1 +# undef CONFIG_STM32_TIM6_ADC2 +# undef CONFIG_STM32_TIM6_ADC3 +# undef CONFIG_STM32_TIM7_ADC +# undef CONFIG_STM32_TIM7_ADC1 +# undef CONFIG_STM32_TIM7_ADC2 +# undef CONFIG_STM32_TIM7_ADC3 +# undef CONFIG_STM32_TIM9_ADC +# undef CONFIG_STM32_TIM9_ADC1 +# undef CONFIG_STM32_TIM9_ADC2 +# undef CONFIG_STM32_TIM9_ADC3 +# undef CONFIG_STM32_TIM10_ADC +# undef CONFIG_STM32_TIM10_ADC1 +# undef CONFIG_STM32_TIM10_ADC2 +# undef CONFIG_STM32_TIM10_ADC3 +# +#endif + +/* Timers 6, 7, and 10-14 are not used with the ADC by any supported family + */ -#undef CONFIG_STM32_TIM6_ADC -#undef CONFIG_STM32_TIM6_ADC1 -#undef CONFIG_STM32_TIM6_ADC2 -#undef CONFIG_STM32_TIM6_ADC3 -#undef CONFIG_STM32_TIM7_ADC -#undef CONFIG_STM32_TIM7_ADC1 -#undef CONFIG_STM32_TIM7_ADC2 -#undef CONFIG_STM32_TIM7_ADC3 -#undef CONFIG_STM32_TIM9_ADC -#undef CONFIG_STM32_TIM9_ADC1 -#undef CONFIG_STM32_TIM9_ADC2 -#undef CONFIG_STM32_TIM9_ADC3 -#undef CONFIG_STM32_TIM10_ADC -#undef CONFIG_STM32_TIM10_ADC1 -#undef CONFIG_STM32_TIM10_ADC2 -#undef CONFIG_STM32_TIM10_ADC3 #undef CONFIG_STM32_TIM11_ADC #undef CONFIG_STM32_TIM11_ADC1 #undef CONFIG_STM32_TIM11_ADC2 @@ -164,7 +201,8 @@ # undef CONFIG_STM32_ADC1 #endif -#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) || defined(CONFIG_STM32_ADC3) +#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) || \ + defined(CONFIG_STM32_ADC3) /* DMA support is not yet implemented for this driver */ @@ -172,8 +210,11 @@ # warning "DMA is not supported by the current driver" #endif -/* Timer configuration: If a timer trigger is specified, then get information - * about the timer. +/* Timer configuration: If a timer trigger is specified, then get + * information about the timer. + * + * STM32L15XX-family has only one ADC onboard, thus there is no definition + * for other 3 ADC's */ #if defined(CONFIG_STM32_TIM1_ADC1) @@ -196,10 +237,26 @@ # define ADC1_HAVE_TIMER 1 # define ADC1_TIMER_BASE STM32_TIM5_BASE # define ADC1_TIMER_PCLK_FREQUENCY STM32_APB1_TIM5_CLKIN +#elif defined(CONFIG_STM32_TIM6_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE STM32_TIM6_BASE +# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB1_TIM6_CLKIN +#elif defined(CONFIG_STM32_TIM7_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE STM32_TIM7_BASE +# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB1_TIM7_CLKIN #elif defined(CONFIG_STM32_TIM8_ADC1) # define ADC1_HAVE_TIMER 1 # define ADC1_TIMER_BASE STM32_TIM8_BASE # define ADC1_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN +#elif defined(CONFIG_STM32_TIM9_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE STM32_TIM9_BASE +# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB2_TIM9_CLKIN +#elif defined(CONFIG_STM32_TIM10_ADC1) +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE STM32_TIM10_BASE +# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB2_TIM10_CLKIN #else # undef ADC1_HAVE_TIMER #endif @@ -235,9 +292,9 @@ # define ADC2_TIMER_BASE STM32_TIM5_BASE # define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM5_CLKIN #elif defined(CONFIG_STM32_TIM8_ADC2) -# define ADC2_HAVE_TIMER 1 -# define ADC2_TIMER_BASE STM32_TIM8_BASE -# define ADC2_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE STM32_TIM8_BASE +# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN #else # undef ADC2_HAVE_TIMER #endif @@ -273,9 +330,9 @@ # define ADC3_TIMER_BASE STM32_TIM5_BASE # define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM5_CLKIN #elif defined(CONFIG_STM32_TIM8_ADC3) -# define ADC3_HAVE_TIMER 1 -# define ADC3_TIMER_BASE STM32_TIM8_BASE -# define ADC3_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN +# define ADC1_HAVE_TIMER 1 +# define ADC1_TIMER_BASE STM32_TIM8_BASE +# define ADC1_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN #else # undef ADC3_HAVE_TIMER #endif @@ -300,10 +357,14 @@ #endif /* NOTE: The following assumes that all possible combinations of timers and - * values are support EXTSEL. That is not so and it varies from one STM32 to another. - * But this (wrong) assumptions keeps the logic as simple as possible. If un - * unsupported combination is used, an error will show up later during compilation - * although it may be difficult to track it back to this simplification. + * values are support EXTSEL. That is not so and it varies from one STM32 + * to another. But this (wrong) assumptions keeps the logic as simple as + * possible. If unsupported combination is used, an error will show up + * later during compilation although it may be difficult to track it back + * to this simplification. + * + * STM32L15XX-family has only one ADC onboard, thus there is no definition + * for other 3 ADC's */ #if defined(CONFIG_STM32_TIM1_ADC1) @@ -376,6 +437,34 @@ # else # error "CONFIG_STM32_ADC1_TIMTRIG is out of range" # endif +#elif defined(CONFIG_STM32_TIM6_ADC1) +# if CONFIG_STM32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5CC1 +# elif CONFIG_STM32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5CC2 +# elif CONFIG_STM32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5CC3 +# elif CONFIG_STM32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5CC4 +# elif CONFIG_STM32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5TRGO +# else +# error "CONFIG_STM32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_STM32_TIM7_ADC1) +# if CONFIG_STM32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5CC1 +# elif CONFIG_STM32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5CC2 +# elif CONFIG_STM32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5CC3 +# elif CONFIG_STM32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5CC4 +# elif CONFIG_STM32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T5TRGO +# else +# error "CONFIG_STM32_ADC1_TIMTRIG is out of range" +# endif #elif defined(CONFIG_STM32_TIM8_ADC1) # if CONFIG_STM32_ADC1_TIMTRIG == 0 # define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC1 @@ -390,6 +479,34 @@ # else # error "CONFIG_STM32_ADC1_TIMTRIG is out of range" # endif +#elif defined(CONFIG_STM32_TIM9_ADC1) +# if CONFIG_STM32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC1 +# elif CONFIG_STM32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC2 +# elif CONFIG_STM32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC3 +# elif CONFIG_STM32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC4 +# elif CONFIG_STM32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8TRGO +# else +# error "CONFIG_STM32_ADC1_TIMTRIG is out of range" +# endif +#elif defined(CONFIG_STM32_TIM10_ADC1) +# if CONFIG_STM32_ADC1_TIMTRIG == 0 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC1 +# elif CONFIG_STM32_ADC1_TIMTRIG == 1 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC2 +# elif CONFIG_STM32_ADC1_TIMTRIG == 2 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC3 +# elif CONFIG_STM32_ADC1_TIMTRIG == 3 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8CC4 +# elif CONFIG_STM32_ADC1_TIMTRIG == 4 +# define ADC1_EXTSEL_VALUE ADC_CR2_EXTSEL_T8TRGO +# else +# error "CONFIG_STM32_ADC1_TIMTRIG is out of range" +# endif #endif #if defined(CONFIG_STM32_TIM1_ADC2) @@ -564,6 +681,61 @@ # endif #endif +/************************************************************************************ + * Public Types + ************************************************************************************/ + +#ifdef CONFIG_STM32_STM32L15XX +typedef enum ADC_IO_CMDS +{ + IO_ENABLE_TEMPER_VOLT_CH = 0, + IO_ENABLE_DISABLE_PDI, + IO_ENABLE_DISABLE_PDD, + IO_ENABLE_DISABLE_PDD_PDI, + IO_ENABLE_DISABLE_AWDIE, + IO_ENABLE_DISABLE_EOCIE, + IO_ENABLE_DISABLE_JEOCIE, + IO_ENABLE_DISABLE_OVRIE = 7, + IO_ENABLE_DISABLE_ALL_INTS, + IO_START_CONV, + IO_STOP_ADC, + IO_START_ADC, +} ADC_IO_CMDS; + +/* Channel and sample time pair */ + +typedef struct adc_channel_s +{ + uint8_t channel : 5; + + /* Sampling time individually for each channel + * 000: 4 cycles + * 001: 9 cycles + * 010: 16 cycles + * 011: 24 cycles + * 100: 48 cycles + * 101: 96 cycles + * 110: 192 cycles + * 111: 384 cycles - selected for all channels + */ + + uint8_t sample_time : 3; +} adc_channel_t; + +/* This structure will be used while setting channels to specified by the + * "channel-sample time" pairs' values + */ + +struct adc_sample_time_s { + adc_channel_t *channel; /* array of channels */ + uint8_t channels_nbr:5; /* number of channels in array */ + bool all_same:1; /* All 32 channels will get the + * same value of the sample time */ + uint8_t all_ch_sample_time:3; /* Sample time for all 32 channels */ +}; + +#endif + /************************************************************************************ * Public Function Prototypes ************************************************************************************/ @@ -594,9 +766,14 @@ extern "C" ****************************************************************************/ struct adc_dev_s; -struct adc_dev_s *stm32_adcinitialize(int intf, const uint8_t *chanlist, +struct adc_dev_s *stm32_adcinitialize(int intf, FAR const uint8_t *chanlist, int nchannels); +#ifdef CONFIG_STM32_STM32L15XX +void stm32_adcchange_sample_time(FAR struct adc_dev_s *dev, + FAR struct adc_sample_time_s *time_samples); +#endif + #undef EXTERN #ifdef __cplusplus } @@ -605,4 +782,3 @@ struct adc_dev_s *stm32_adcinitialize(int intf, const uint8_t *chanlist, #endif /* CONFIG_STM32_ADC || CONFIG_STM32_ADC2 || CONFIG_STM32_ADC3 */ #endif /* __ARCH_ARM_SRC_STM32_STM32_ADC_H */ -