diff options
| author | Marti Bolivar <mbolivar@leaflabs.com> | 2011-05-09 16:43:27 -0400 | 
|---|---|---|
| committer | Marti Bolivar <mbolivar@leaflabs.com> | 2011-05-09 16:49:08 -0400 | 
| commit | 19ea6ba4ea3f1ecb9830cf4d3e1366513f4f96e3 (patch) | |
| tree | a43f7e0fb3650ca54f245b750a078a0e8c356504 /libmaple/adc.c | |
| parent | 868fb1c273e562a1140abfa948022c9d4f55bccf (diff) | |
| parent | 1e2e177f6dae62e040c674b617744c73be187062 (diff) | |
| download | librambutan-19ea6ba4ea3f1ecb9830cf4d3e1366513f4f96e3.tar.gz librambutan-19ea6ba4ea3f1ecb9830cf4d3e1366513f4f96e3.zip | |
Merge branch 'refactor'
This merges the libmaple refactor work into master.  The contents of
libmaple proper (/libmaple/) are almost completely incompatible with
previous APIs in master.  See /docs/source/libmaple/overview.rst for
more information on the new design.
Wirish incompatibilities are limited to the HardwareTimer class;
however, there are several new deprecations, most likely to be removed
in 0.1.0.
Diffstat (limited to 'libmaple/adc.c')
| -rw-r--r-- | libmaple/adc.c | 171 | 
1 files changed, 108 insertions, 63 deletions
| diff --git a/libmaple/adc.c b/libmaple/adc.c index 3e6818c..73dce0a 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -23,85 +23,92 @@   *****************************************************************************/  /** - * @brief Analog to digital converter routines - */ - -#include "libmaple.h" -#include "rcc.h" -#include "adc.h" - -/* The ADC input clock is generated from PCLK2/APB2 divided by a prescaler - * and it must not exceed 14MHz. + * @file adc.c   * - * ADC1 and ADC2 are clocked by APB2 - * - * 1) Power on by setting ADON in ADC_CR2 - * Conversion starts when ADON is set for a second time after some - * time t > t_stab. - * - * Up to 16 selected conversion must be selected in ADC_SQRx - * - * Single conversion mode: - * Set the ADON bit in the ADC_CR2 register - * Once the conversion is complete: - *  Converted data is stored in ADC_DR - *  EOC flag is set - *  Interrupt is generated if EOCIE is set - * - * Calibration: - * Calibration is started by setting the CAL bit in the ADC_CR2 register. - * Once calibration is over, the CAL bit is reset by hardware and normal - * conversion can be performed. Calibrate at power-on. - * - * ALIGN in ADC_CR2 selects the alignment of data + * @brief Analog to digital converter routines   *   * IMPORTANT: maximum external impedance must be below 0.4kOhms for 1.5   * sample conversion time.   * - * At 55.5 cycles/sample, the external input impedance < 50kOhms*/ - -void set_adc_smprx(adc_smp_rate smp_rate); + * At 55.5 cycles/sample, the external input impedance < 50kOhms. + * + * See STM32 manual RM0008 for how to calculate this. + */ -void adc_init(adc_smp_rate smp_rate) { -    rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); -    rcc_clk_enable(RCC_ADC1); -    rcc_reset_dev(RCC_ADC1); +#include "libmaple.h" +#include "rcc.h" +#include "adc.h" -    ADC_CR1  = 0; -    /* Software triggers conversions */ -    ADC_CR2  = CR2_EXTSEL_SWSTART | CR2_EXTTRIG; -    ADC_SQR1 = 0; +adc_dev adc1 = { +    .regs   = ADC1_BASE, +    .clk_id = RCC_ADC1 +}; +const adc_dev *ADC1 = &adc1; -    /* Set the sample conversion time.  See note above for impedance -       requirements. */ -    adc_set_sample_rate(smp_rate); +adc_dev adc2 = { +    .regs   = ADC2_BASE, +    .clk_id = RCC_ADC2 +}; +const adc_dev *ADC2 = &adc2; -    /* Enable the ADC */ -    CR2_ADON_BIT = 1; +#ifdef STM32_HIGH_DENSITY +adc_dev adc3 = { +    .regs   = ADC3_BASE, +    .clk_id = RCC_ADC3 +}; +const adc_dev *ADC3 = &adc3; +#endif -    /* Reset the calibration registers and then perform a reset */ -    CR2_RSTCAL_BIT = 1; -    while(CR2_RSTCAL_BIT) -        ; - -    CR2_CAL_BIT = 1; -    while(CR2_CAL_BIT) -        ; +/** + * @brief Initialize an ADC peripheral. + * + * Initializes the RCC clock line for the given peripheral, using ADC + * prescaler RCC_ADCPRE_PCLK_DIV_6.  Resets ADC device registers. + * + * @param dev ADC peripheral to initialize + */ +void adc_init(const adc_dev *dev) { +    rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); +    rcc_clk_enable(dev->clk_id); +    rcc_reset_dev(dev->clk_id);  } +/** + * @brief Set external event select for regular group + * @param dev ADC device + * @param event Event used to trigger the start of conversion. + * @see adc_extsel_event + */ +void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) { +    uint32 cr2 = dev->regs->CR2; +    cr2 &= ~ADC_CR2_EXTSEL; +    cr2 |= event; +    dev->regs->CR2 = cr2; +} -void adc_disable(void) { -    CR2_ADON_BIT = 0; +/** + * @brief Call a function on all ADC devices. + * @param fn Function to call on each ADC device. + */ +void adc_foreach(void (*fn)(const adc_dev*)) { +    fn(ADC1); +    fn(ADC2); +#ifdef STM32_HIGH_DENSITY +    fn(ADC3); +#endif  } -/* Turn the given sample rate into values for ADC_SMPRx.  (Don't - * precompute in order to avoid wasting space). - * - * Don't call this during conversion! +/** + * @brief Turn the given sample rate into values for ADC_SMPRx. Don't + * call this during conversion. + * @param dev adc device + * @param smp_rate sample rate to set + * @see adc_smp_rate   */ -void adc_set_sample_rate(adc_smp_rate smp_rate) { +void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) {      uint32 adc_smpr1_val = 0, adc_smpr2_val = 0;      int i; +      for (i = 0; i < 10; i++) {          if (i < 8) {              /* ADC_SMPR1 determines sample time for channels [10,17] */ @@ -110,6 +117,44 @@ void adc_set_sample_rate(adc_smp_rate smp_rate) {          /* ADC_SMPR2 determines sample time for channels [0,9] */          adc_smpr2_val |= smp_rate << (i * 3);      } -    ADC_SMPR1 = adc_smpr1_val; -    ADC_SMPR2 = adc_smpr2_val; + +    dev->regs->SMPR1 = adc_smpr1_val; +    dev->regs->SMPR2 = adc_smpr2_val; +} + +/** + * @brief Calibrate an ADC peripheral + * @param dev adc device + */ +void adc_calibrate(const adc_dev *dev) { +    __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); +    __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); + +    *rstcal_bit = 1; +    while (*rstcal_bit) +        ; + +    *cal_bit = 1; +    while (*cal_bit) +        ; +} + +/** + * @brief Perform a single synchronous software triggered conversion on a + * channel. + * @param dev ADC device to use for reading. + * @param channel channel to convert + * @return conversion result + */ +uint16 adc_read(const adc_dev *dev, uint8 channel) { +    adc_reg_map *regs = dev->regs; + +    adc_set_reg_seqlen(dev, 1); + +    regs->SQR3 = channel; +    regs->CR2 |= ADC_CR2_SWSTART; +    while(!(regs->SR & ADC_SR_EOC)) +        ; + +    return (uint16)(regs->DR & ADC_DR_DATA);  } | 
