diff options
Diffstat (limited to 'nuttx/arch/arm/src/stm32/stm32_adc.c')
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_adc.c | 1546 |
1 files changed, 0 insertions, 1546 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_adc.c b/nuttx/arch/arm/src/stm32/stm32_adc.c deleted file mode 100644 index b5033b057..000000000 --- a/nuttx/arch/arm/src/stm32/stm32_adc.c +++ /dev/null @@ -1,1546 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32/stm32_adc.c - * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * Diego Sanchez <dsanchez@nx-engineering.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <stdio.h> -#include <sys/types.h> -#include <stdint.h> -#include <stdbool.h> -#include <unistd.h> -#include <string.h> -#include <semaphore.h> -#include <errno.h> -#include <assert.h> -#include <debug.h> -#include <unistd.h> - -#include <arch/board/board.h> -#include <nuttx/arch.h> -#include <nuttx/analog/adc.h> - -#include "up_internal.h" -#include "up_arch.h" - -#include "chip.h" -#include "stm32_internal.h" -#include "stm32_adc.h" - -#ifdef CONFIG_ADC -#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) || defined(CONFIG_STM32_ADC3) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* 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 - -/* The maximum number of channels that can be sampled. If dma support is - * not enabled, then only a single channel can be sampled. Otherwise, - * data overruns would occur. - */ - -#ifdef CONFIG_ADC_DMA -# define ADC_MAX_SAMPLES 16 -#else -# define ADC_MAX_SAMPLES 1 -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure describes the state of one ADC block */ - -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 */ -#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 */ -#endif - uint8_t chanlist[ADC_MAX_SAMPLES]; -}; - -/**************************************************************************** - * 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); -#ifdef ADC_HAVE_TIMER -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)) -static int adc12_interrupt(int irq, void *context); -#endif -#if defined(CONFIG_STM32_STM32F10XX) && defined (CONFIG_STM32_ADC3) -static int adc3_interrupt(int irq, void *context); -#endif -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) -static int adc123_interrupt(int irq, void *context); -#endif - -/* ADC Driver Methods */ - -static void adc_reset(FAR struct adc_dev_s *dev); -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 stm32_dev_s *priv, bool enable); - -#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) -static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* ADC interface operations */ - -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, -}; - -/* ADC1 state */ - -#ifdef CONFIG_STM32_ADC1 -static struct stm32_dev_s g_adcpriv1 = -{ -#ifdef CONFIG_STM32_STM32F10XX - .irq = STM32_IRQ_ADC12, - .isr = adc12_interrupt, -#else - .irq = STM32_IRQ_ADC, - .isr = adc123_interrupt, -#endif - .intf = 1, - .base = STM32_ADC1_BASE, -#ifdef ADC1_HAVE_TIMER - .trigger = CONFIG_STM32_ADC1_TIMTRIG, - .tbase = ADC1_TIMER_BASE, - .extsel = ADC1_EXTSEL_VALUE, - .pclck = ADC1_TIMER_PCLK_FREQUENCY, - .freq = CONFIG_STM32_ADC1_SAMPLE_FREQUENCY, -#endif -}; - -static struct adc_dev_s g_adcdev1 = -{ - .ad_ops = &g_adcops, - .ad_priv= &g_adcpriv1, -}; -#endif - -/* ADC2 state */ - -#ifdef CONFIG_STM32_ADC2 -static struct stm32_dev_s g_adcpriv2 = -{ -#ifdef CONFIG_STM32_STM32F10XX - .irq = STM32_IRQ_ADC12, - .isr = adc12_interrupt, -#else - .irq = STM32_IRQ_ADC, - .isr = adc123_interrupt, -#endif - .intf = 2, - .base = STM32_ADC2_BASE, -#ifdef ADC2_HAVE_TIMER - .trigger = CONFIG_STM32_ADC2_TIMTRIG, - .tbase = ADC2_TIMER_BASE, - .extsel = ADC2_EXTSEL_VALUE, - .pclck = ADC2_TIMER_PCLK_FREQUENCY, - .freq = CONFIG_STM32_ADC2_SAMPLE_FREQUENCY, -#endif -}; - -static struct adc_dev_s g_adcdev2 = -{ - .ad_ops = &g_adcops, - .ad_priv= &g_adcpriv2, -}; -#endif - -/* ADC3 state */ - -#ifdef CONFIG_STM32_ADC3 -static struct stm32_dev_s g_adcpriv3 = -{ -#ifdef CONFIG_STM32_STM32F10XX - .irq = STM32_IRQ_ADC3, - .isr = adc3_interrupt, -#else - .irq = STM32_IRQ_ADC, - .isr = adc123_interrupt, -#endif - .intf = 3, - .base = STM32_ADC3_BASE, -#ifdef ADC3_HAVE_TIMER - .trigger = CONFIG_STM32_ADC3_TIMTRIG, - .tbase = ADC3_TIMER_BASE, - .extsel = ADC3_EXTSEL_VALUE, - .pclck = ADC3_TIMER_PCLK_FREQUENCY, - .freq = CONFIG_STM32_ADC3_SAMPLE_FREQUENCY, -#endif -}; - -static struct adc_dev_s g_adcdev3 = -{ - .ad_ops = &g_adcops, - .ad_priv= &g_adcpriv3, -}; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * 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: - * - ****************************************************************************/ - -static uint32_t adc_getreg(struct stm32_dev_s *priv, int offset) -{ - return getreg32(priv->base + offset); -} - -/**************************************************************************** - * 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: - * - ****************************************************************************/ - -static void adc_putreg(struct stm32_dev_s *priv, int offset, uint32_t value) -{ - putreg32(value, priv->base + offset); -} - -/**************************************************************************** - * Name: tim_getreg - * - * Description: - * Read the value of an ADC timer register. - * - * Input Parameters: - * priv - A reference to the ADC block status - * offset - The offset to the register to read - * - * Returned Value: - * The current contents of the specified register - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static uint16_t tim_getreg(struct stm32_dev_s *priv, int offset) -{ - return getreg16(priv->tbase + offset); -} -#endif - -/**************************************************************************** - * Name: tim_putreg - * - * Description: - * Read the value of an ADC timer register. - * - * Input Parameters: - * priv - A reference to the ADC block status - * offset - The offset to the register to read - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static void tim_putreg(struct stm32_dev_s *priv, int offset, uint16_t value) -{ - putreg16(value, priv->tbase + offset); -} -#endif - -/**************************************************************************** - * Name: adc_tim_dumpregs - * - * Description: - * Dump all timer registers. - * - * Input parameters: - * priv - A reference to the ADC block status - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static void adc_tim_dumpregs(struct stm32_dev_s *priv, FAR const char *msg) -{ -#if defined(CONFIG_DEBUG_ANALOG) && defined(CONFIG_DEBUG_VERBOSE) - avdbg("%s:\n", msg); - avdbg(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n", - tim_getreg(priv, STM32_GTIM_CR1_OFFSET), - tim_getreg(priv, STM32_GTIM_CR2_OFFSET), - tim_getreg(priv, STM32_GTIM_SMCR_OFFSET), - tim_getreg(priv, STM32_GTIM_DIER_OFFSET)); - avdbg(" SR: %04x EGR: 0000 CCMR1: %04x CCMR2: %04x\n", - tim_getreg(priv, STM32_GTIM_SR_OFFSET), - tim_getreg(priv, STM32_GTIM_CCMR1_OFFSET), - tim_getreg(priv, STM32_GTIM_CCMR2_OFFSET)); - avdbg(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n", - tim_getreg(priv, STM32_GTIM_CCER_OFFSET), - tim_getreg(priv, STM32_GTIM_CNT_OFFSET), - tim_getreg(priv, STM32_GTIM_PSC_OFFSET), - tim_getreg(priv, STM32_GTIM_ARR_OFFSET)); - avdbg(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n", - tim_getreg(priv, STM32_GTIM_CCR1_OFFSET), - 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)); - } -#endif -} -#endif - -/**************************************************************************** - * Name: adc_timstart - * - * Description: - * Start (or stop) the timer counter - * - * Input Parameters: - * priv - A reference to the ADC block status - * enable - True: Start conversion - * - * Returned Value: - * - ****************************************************************************/ - - #ifdef ADC_HAVE_TIMER -static void adc_timstart(struct stm32_dev_s *priv, bool enable) -{ - uint16_t regval; - - avdbg("enable: %d\n", enable); - regval = tim_getreg(priv, STM32_GTIM_CR1_OFFSET); - - if (enable) - { - /* Start the counter */ - - regval |= ATIM_CR1_CEN; - } - - else - { - /* Disable the counter */ - - regval &= ~ATIM_CR1_CEN; - } - tim_putreg(priv, STM32_GTIM_CR1_OFFSET, regval); -} -#endif - -/**************************************************************************** - * Name: adc_timinit - * - * Description: - * Initialize the timer that drivers the ADC sampling for this channel using - * the pre-calculated timer divider definitions. - * - * Input Parameters: - * priv - A reference to the ADC block status - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static int adc_timinit(FAR struct stm32_dev_s *priv) -{ - uint32_t prescaler; - uint32_t reload; - uint32_t regval; - uint32_t timclk; - - uint16_t cr1; - uint16_t cr2; - uint16_t ccmr1; - uint16_t ccmr2; - uint16_t ocmode1; - uint16_t ocmode2; - uint16_t ccenable; - uint16_t ccer; - uint16_t egr; - - avdbg("Initializing timers extsel = %d\n", priv->extsel); - - /* If the timer base address is zero, then this ADC was not configured to - * use a timer. - */ - - regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); - -#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 - */ - - regval &= ~ADC_CR2_EXTTRIG; - adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval); - return OK; - } - else - { - regval |= ADC_CR2_EXTTRIG; - } -#endif - - /* 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 - * 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. - */ - - regval &= ~ADC_CR2_EXTSEL_MASK; - regval |= priv->extsel; - adc_putreg(priv, STM32_ADC_CR2_OFFSET, regval); - - /* 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 - * - * reload = timclk / freq - * reload = (pclck / prescaler) / freq - * - * There are many solutions to do this, but the best solution will be the - * one that has the largest reload value and the smallest prescaler value. - * That is the solution that should give us the most accuracy in the timer - * control. Subject to: - * - * 0 <= prescaler <= 65536 - * 1 <= reload <= 65535 - * - * So ( prescaler = pclck / 65535 / freq ) would be optimal. - */ - - prescaler = (priv->pclck / priv->freq + 65534) / 65535; - - /* We need to decrement the prescaler value by one, but only, the value does - * not underflow. - */ - - if (prescaler < 1) - { - adbg("WARNING: Prescaler underflowed.\n"); - prescaler = 1; - } - - /* Check for overflow */ - - else if (prescaler > 65536) - { - adbg("WARNING: Prescaler overflowed.\n"); - prescaler = 65536; - } - - timclk = priv->pclck / prescaler; - - reload = timclk / priv->freq; - if (reload < 1) - { - adbg("WARNING: Reload value underflowed.\n"); - reload = 1; - } - else if (reload > 65535) - { - adbg("WARNING: Reload value overflowed.\n"); - reload = 65535; - } - - /* Set up the timer CR1 register */ - - cr1 = tim_getreg(priv, STM32_GTIM_CR1_OFFSET); - - /* Disable the timer until we get it configured */ - - adc_timstart(priv, false); - - /* Select the Counter Mode == count up: - * - * ATIM_CR1_EDGE: The counter counts up or down depending on the - * direction bit(DIR). - * ATIM_CR1_DIR: 0: count up, 1: count down - */ - - cr1 &= ~(ATIM_CR1_DIR | ATIM_CR1_CMS_MASK); - cr1 |= ATIM_CR1_EDGE; - - /* Set the clock division to zero for all */ - - cr1 &= ~GTIM_CR1_CKD_MASK; - tim_putreg(priv, STM32_GTIM_CR1_OFFSET, cr1); - - /* Set the reload and prescaler values */ - - 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 */ - - 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 */ - } - - /* TIMx event generation: Bit 0 UG: Update generation */ - - tim_putreg(priv, STM32_GTIM_EGR_OFFSET, ATIM_EGR_UG); - - /* Handle channel specific setup */ - - ocmode1 = 0; - ocmode2 = 0; - - switch (priv->trigger) - { - case 0: /* TimerX CC1 event */ - { - ccenable = ATIM_CCER_CC1E; - ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT) | - (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC1M_SHIFT) | - ATIM_CCMR1_OC1PE; - - /* Set the event CC1 */ - - egr = ATIM_EGR_CC1G; - - /* Set the duty cycle by writing to the CCR register for this channel */ - - tim_putreg(priv, STM32_GTIM_CCR1_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - case 1: /* TimerX CC2 event */ - { - ccenable = ATIM_CCER_CC2E; - ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT) | - (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC2M_SHIFT) | - ATIM_CCMR1_OC2PE; - - /* Set the event CC2 */ - - egr = ATIM_EGR_CC2G; - - /* Set the duty cycle by writing to the CCR register for this channel */ - - tim_putreg(priv, STM32_GTIM_CCR2_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - case 2: /* TimerX CC3 event */ - { - ccenable = ATIM_CCER_CC3E; - ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC3S_SHIFT) | - (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC3M_SHIFT) | - ATIM_CCMR2_OC3PE; - - /* Set the event CC3 */ - - egr = ATIM_EGR_CC3G; - - /* Set the duty cycle by writing to the CCR register for this channel */ - - tim_putreg(priv, STM32_GTIM_CCR3_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - case 3: /* TimerX CC4 event */ - { - ccenable = ATIM_CCER_CC4E; - ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC4S_SHIFT) | - (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC4M_SHIFT) | - ATIM_CCMR2_OC4PE; - - /* Set the event CC4 */ - - egr = ATIM_EGR_CC4G; - - /* Set the duty cycle by writing to the CCR register for this channel */ - - tim_putreg(priv, STM32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - case 4: /* TimerX TRGO event */ - { - /* TODO: TRGO support not yet implemented */ - /* Set the event TRGO */ - - ccenable = 0; - egr = GTIM_EGR_TG; - - /* Set the duty cycle by writing to the CCR register for this channel */ - - tim_putreg(priv, STM32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - default: - adbg("No such trigger: %d\n", priv->trigger); - return -EINVAL; - } - - /* Disable the Channel by resetting the CCxE Bit in the CCER register */ - - ccer = tim_getreg(priv, STM32_GTIM_CCER_OFFSET); - ccer &= ~ccenable; - tim_putreg(priv, STM32_GTIM_CCER_OFFSET, ccer); - - /* Fetch the CR2, CCMR1, and CCMR2 register (already have cr1 and ccer) */ - - cr2 = tim_getreg(priv, STM32_GTIM_CR2_OFFSET); - ccmr1 = tim_getreg(priv, STM32_GTIM_CCMR1_OFFSET); - ccmr2 = tim_getreg(priv, STM32_GTIM_CCMR2_OFFSET); - - /* Reset the Output Compare Mode Bits and set the select output compare mode */ - - ccmr1 &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | ATIM_CCMR1_OC1PE | - ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | ATIM_CCMR1_OC2PE); - ccmr2 &= ~(ATIM_CCMR2_CC3S_MASK | ATIM_CCMR2_OC3M_MASK | ATIM_CCMR2_OC3PE | - ATIM_CCMR2_CC4S_MASK | ATIM_CCMR2_OC4M_MASK | ATIM_CCMR2_OC4PE); - ccmr1 |= ocmode1; - ccmr2 |= ocmode2; - - /* Reset the output polarity level of all channels (selects high polarity)*/ - - ccer &= ~(ATIM_CCER_CC1P | ATIM_CCER_CC2P | ATIM_CCER_CC3P | ATIM_CCER_CC4P); - - /* Enable the output state of the selected channel (only) */ - - 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) - { - /* Reset output N polarity level, output N state, output compre 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 | GTIM_CCER_CC4NP); - } -#endif - - /* Save the modified register values */ - - tim_putreg(priv, STM32_GTIM_CR2_OFFSET, cr2); - tim_putreg(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1); - tim_putreg(priv, STM32_GTIM_CCMR2_OFFSET, ccmr2); - tim_putreg(priv, STM32_GTIM_CCER_OFFSET, ccer); - tim_putreg(priv, STM32_GTIM_EGR_OFFSET, egr); - - /* Set the ARR Preload Bit */ - - cr1 = tim_getreg(priv, STM32_GTIM_CR1_OFFSET); - cr1 |= GTIM_CR1_ARPE; - tim_putreg(priv, STM32_GTIM_CR1_OFFSET, cr1); - - /* Enable the timer counter - * All but the CEN bit with the default config in CR1 - */ - - adc_timstart(priv, true); - - adc_tim_dumpregs(priv, "After starting Timers"); - - return OK; -} -#endif - -/**************************************************************************** - * Name: adc_startconv - * - * Description: - * Start (or stop) the ADC conversion process in DMA mode - * - * Input Parameters: - * priv - A reference to the ADC block status - * enable - True: Start conversion - * - * Returned Value: - * - ****************************************************************************/ - -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) -static void adc_startconv(struct stm32_dev_s *priv, bool enable) -{ - uint32_t regval; - - avdbg("enable: %d\n", enable); - - regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); - if (enable) - { - /* Start conversion of regular channles */ - - regval |= ADC_CR2_SWSTART; - } - else - { - /* Disable the conversion of regular channels */ - - regval &= ~ADC_CR2_SWSTART; - } - adc_putreg(priv, STM32_ADC_CR2_OFFSET,regval); -} -#endif - -/**************************************************************************** - * 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) -{ - irqstate_t flags; - 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 - - /* Disable interrupts. This is necessary because the APB2RTSR register - * is used by several different drivers. - */ - - flags = irqsave(); - - /* 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); - irqrestore(flags); -} - -/******************************************************************************* - * Name: adc_enable - * - * Description : Enables or disables the specified ADC peripheral. - * Also, starts a conversion when the ADC is not - * triggered by timers - * - * Input Parameters: - * - * enable - true: enable ADC conversion - * false: disable ADC conversion - * - * Returned Value: - * - *******************************************************************************/ - -static void adc_enable(FAR struct stm32_dev_s *priv, bool enable) -{ - uint32_t regval; - - avdbg("enable: %d\n", enable); - - 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 - * - * Description: - * Reset the ADC device. Called early to initialize the hardware. This - * is called, before adc_setup() and on error conditions. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -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); - flags = irqsave(); - - /* Enable ADC reset state */ - - adc_rccreset(priv, true); - - /* Release ADC from reset state */ - - adc_rccreset(priv, false); - - /* Initialize the ADC data structures */ - - /* 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); - - /* Initialize the same sample time for each ADC 55.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, 0x00b6db6d); - adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, 0x00b6db6d); - - /* ADC CR1 Configuration */ - - regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); - - /* Set mode configuration (Independent mode) */ - -#ifdef CONFIG_STM32_STM32F10XX - regval |= ADC_CR1_IND; -#endif - - /* Initialize the Analog watchdog enable */ - - regval |= ADC_CR1_AWDEN; - regval |= (priv->chanlist[0] << ADC_CR1_AWDCH_SHIFT); - - /* Enable interrupt flags */ - - regval |= ADC_CR1_ALLINTS; - -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) - - /* Enable or disable Overrun interrupt */ - - regval &= ~ADC_CR1_OVRIE; - - /* Set the resolution of the conversion */ - - regval |= ACD_CR1_RES_12BIT; -#endif - - adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); - - /* ADC CR2 Configuration */ - - regval = adc_getreg(priv, STM32_ADC_CR2_OFFSET); - - /* Clear CONT, continuous mode disable */ - - regval &= ~ADC_CR2_CONT; - - /* Set ALIGN (Right = 0) */ - - regval &= ~ADC_CR2_ALIGN; - -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) - /* External trigger enable for regular channels */ - - regval |= ACD_CR2_EXTEN_RISING; -#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; - } - - /* 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); - putreg32(regval, STM32_ADC_CCR); -#endif - - /* Set the number of conversions */ - - DEBUGASSERT(priv->nchannels <= ADC_MAX_SAMPLES); - - regval |= (((uint32_t)priv->nchannels-1) << ADC_SQR1_L_SHIFT); - adc_putreg(priv, STM32_ADC_SQR1_OFFSET, regval); - - /* Set the channel index of the first conversion */ - - priv->current = 0; - - /* Set ADON to wake up the ADC from Power Down state. */ - - adc_enable(priv, true); - -#ifdef ADC_HAVE_TIMER - ret = adc_timinit(priv); - if (ret!=OK) - { - 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 - adc_startconv(priv, true); -#endif /* CONFIG_STM32_STM32F10XX */ -#endif /* ADC_HAVE_TIMER */ - - irqrestore(flags); - - avdbg("SR: 0x%08x CR1: 0x%08x CR2: 0x%08x\n", - adc_getreg(priv, STM32_ADC_SR_OFFSET), - adc_getreg(priv, STM32_ADC_CR1_OFFSET), - adc_getreg(priv, STM32_ADC_CR2_OFFSET)); - avdbg("SQR1: 0x%08x SQR2: 0x%08x SQR3: 0x%08x\n", - 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) - avdbg("CCR: 0x%08x\n", - getreg32(STM32_ADC_CCR)); -#endif -} - -/**************************************************************************** - * Name: adc_setup - * - * Description: - * Configure the ADC. This method is called the first time that the ADC - * device is opened. This will occur when the port is first opened. - * This setup includes configuring and attaching ADC interrupts. Interrupts - * are all disabled upon return. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -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; - - /* Attach the ADC interrupt */ - - ret = irq_attach(priv->irq, priv->isr); - if (ret == OK) - { - /* Make sure that the ADC device is in the powered up, reset state */ - - adc_reset(dev); - - /* Enable the ADC interrupt */ - - avdbg("Enable the ADC interrupt: irq=%d\n", priv->irq); - up_enable_irq(priv->irq); - } - - return ret; -} - -/**************************************************************************** - * Name: adc_shutdown - * - * Description: - * Disable the ADC. This method is called when the ADC device is closed. - * This method reverses the operation the setup method. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -static void adc_shutdown(FAR struct adc_dev_s *dev) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - - /* Disable ADC interrupts and detach the ADC interrupt handler */ - - up_disable_irq(priv->irq); - irq_detach(priv->irq); - - /* Disable and reset the ADC module */ - - adc_rccreset(priv, true); -} - -/**************************************************************************** - * Name: adc_rxint - * - * Description: - * Call to enable or disable RX interrupts. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -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; - - avdbg("intf: %d enable: %d\n", priv->intf, enable); - - regval = adc_getreg(priv, STM32_ADC_CR1_OFFSET); - if (enable) - { - /* Enable the end-of-conversion ADC and analog watchdog interrupts */ - - regval |= ADC_CR1_ALLINTS; - } - else - { - /* Disable all ADC interrupts */ - - regval &= ~ADC_CR1_ALLINTS; - } - adc_putreg(priv, STM32_ADC_CR1_OFFSET, regval); -} - -/**************************************************************************** - * Name: adc_ioctl - * - * Description: - * All ioctl calls will be routed through this method. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -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 int adc_interrupt(FAR struct adc_dev_s *dev) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - uint32_t adcsr; - int32_t value; - - /* Identifies the interruption AWD, OVR or EOC */ - - adcsr = adc_getreg(priv, STM32_ADC_SR_OFFSET); - if ((adcsr & ADC_SR_AWD) != 0) - { - alldbg("WARNING: Analog Watchdog, Value converted out of range!\n"); - } - -#if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) - if ((adcsr & ADC_SR_OVR) != 0) - { - alldbg("WARNING: Overrun has ocurred!\n"); - } -#endif - - /* EOC: End of conversion */ - - if ((adcsr & ADC_SR_EOC) != 0) - { - /* Read the converted value and clear EOC bit - * (It is cleared by reading the ADC_DR) - */ - - 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: - * - * 1) The first is the ADC device instance for this ADC block. - * 2) The second is the channel number for the data, and - * 3) The third is the converted data for the channel. - */ - - adc_receive(dev, priv->chanlist[priv->current], value); - - /* Set the channel number of the next channel that will complete conversion */ - - priv->current++; - - if (priv->current >= priv->nchannels) - { - /* Restart the conversion sequence from the beginning */ - - priv->current = 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_t regval; - uint32_t pending; - - /* Check for pending ADC1 interrupts */ - -#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 - - /* Check for pending ADC2 interrupts */ - -#ifdef CONFIG_STM32_ADC2 - regval = getreg32(STM32_ADC2_SR); - pending = regval & ADC_SR_ALLINTS; - if (pending != 0) - { - adc_interrupt(&g_adcdev2); - 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: - * - ****************************************************************************/ - -#if defined (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(STM32_ADC3_SR); - pending = regval & ADC_SR_ALLINTS; - if (pending != 0) - { - adc_interrupt(&g_adcdev3); - 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: - * - ****************************************************************************/ - -#if defined(CONFIG_STM32_STM32F20XX) || defined(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(STM32_ADC1_SR); - pending = regval & ADC_SR_ALLINTS; - if (pending != 0) - { - adc_interrupt(&g_adcdev1); - regval &= ~pending; - putreg32(regval, STM32_ADC1_SR); - } -#endif - - /* Check for pending ADC2 interrupts */ - -#ifdef CONFIG_STM32_ADC2 - regval = getreg32(STM32_ADC2_SR); - pending = regval & ADC_SR_ALLINTS; - if (pending != 0) - { - adc_interrupt(&g_adcdev2); - regval &= ~pending; - putreg32(regval, STM32_ADC2_SR); - } -#endif - - /* Check for pending ADC3 interrupts */ - -#ifdef CONFIG_STM32_ADC3 - regval = getreg32(STM32_ADC3_SR); - pending = regval & ADC_SR_ALLINTS; - if (pending != 0) - { - adc_interrupt(&g_adcdev3); - regval &= ~pending; - putreg32(regval, STM32_ADC3_SR); - } -#endif - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_adcinitialize - * - * Description: - * 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[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 ADC device structure reference on succcess; a NULL on failure - * - ****************************************************************************/ - -struct adc_dev_s *stm32_adcinitialize(int intf, const uint8_t *chanlist, int nchannels) -{ - FAR struct adc_dev_s *dev; - FAR struct stm32_dev_s *priv; - - avdbg("intf: %d nchannels: %d\n", intf, nchannels); - -#ifdef CONFIG_STM32_ADC1 - if (intf == 1) - { - avdbg("ADC1 Selected\n"); - dev = &g_adcdev1; - } - else -#endif -#ifdef CONFIG_STM32_ADC2 - if (intf == 2) - { - avdbg("ADC2 Selected\n"); - dev = &g_adcdev2; - } - else -#endif -#ifdef CONFIG_STM32_ADC3 - if (intf == 3) - { - avdbg("ADC3 Selected\n"); - dev = &g_adcdev3; - } - else -#endif - { - adbg("No ADC interface defined\n"); - return NULL; - } - - /* Configure the selected ADC */ - - priv = dev->ad_priv; - - DEBUGASSERT(nchannels <= ADC_MAX_SAMPLES); - priv->nchannels = nchannels; - - memcpy(priv->chanlist, chanlist, nchannels); - return dev; -} - -#endif /* CONFIG_STM32_ADC || CONFIG_STM32_ADC2 || CONFIG_STM32_ADC3 */ -#endif /* CONFIG_ADC */ - |