diff options
Diffstat (limited to 'libmaple/adc.h')
-rw-r--r-- | libmaple/adc.h | 203 |
1 files changed, 145 insertions, 58 deletions
diff --git a/libmaple/adc.h b/libmaple/adc.h index 976986f..ac386fb 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -25,87 +25,174 @@ /** * @file adc.h * - * @brief Analog-to-Digital Conversion (ADC) routines. + * @brief Analog-to-Digital Conversion (ADC) header. */ #ifndef _ADC_H_ #define _ADC_H_ #include "util.h" +#include "rcc.h" + #ifdef __cplusplus extern "C"{ #endif -/* Notes: - * The maximum input impedance on each channel MUST be below .4kohms, - * or face the wrath of incorrect readings... - * This can be changed at the expense of sample time... see datasheet - * - * Need to up the sample time if otherwise... see datasheet */ - -/* TODO: We'll only use ADC1 for now. See page 41 of the manual for - ADC2 and ADC3's real addresses. */ -#define ADC1_BASE 0x40012400 -#define ADC2_BASE 0x40012400 -#define ADC3_BASE 0x40012400 - -#define ADC_SR *(volatile uint32*)(ADC1_BASE + 0) -#define ADC_CR1 *(volatile uint32*)(ADC1_BASE + 0x4) -#define ADC_CR2 *(volatile uint32*)(ADC1_BASE + 0x8) -#define ADC_SMPR1 *(volatile uint32*)(ADC1_BASE + 0xC) -#define ADC_SMPR2 *(volatile uint32*)(ADC1_BASE + 0x10) -#define ADC_SQR1 *(volatile uint32*)(ADC1_BASE + 0x2C) -#define ADC_SQR3 *(volatile uint32*)(ADC1_BASE + 0x34) -#define ADC_DR *(volatile uint32*)(ADC1_BASE + 0x4C) - -#define CR2_EXTSEL_SWSTART (0xE << 16) -#define CR2_RSTCAL (BIT(3)) -#define CR2_EXTTRIG (BIT(20)) - -/* Bit banded bits */ -#define CR2_ADON_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 0)) -#define CR2_CAL_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 2)) -#define CR2_RSTCAL_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 3)) -#define CR2_SWSTART_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 22)) -#define SR_EOC_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0, 1)) -/* (NR_ANALOG_PINS is board specific) */ +typedef struct adc_reg_map { + __io uint32 SR; ///< Status register + __io uint32 CR1; ///< Control register 1 + __io uint32 CR2; ///< Control register 2 + __io uint32 SMPR1; ///< Sample time register 1 + __io uint32 SMPR2; ///< Sample time register 2 + __io uint32 JOFR1; ///< Injected channel data offset register 1 + __io uint32 JOFR2; ///< Injected channel data offset register 2 + __io uint32 JOFR3; ///< Injected channel data offset register 3 + __io uint32 JOFR4; ///< Injected channel data offset register 4 + __io uint32 HTR; ///< Watchdog high threshold register + __io uint32 LTR; ///< Watchdog low threshold register + __io uint32 SQR1; ///< Regular sequence register 1 + __io uint32 SQR2; ///< Regular sequence register 2 + __io uint32 SQR3; ///< Regular sequence register 3 + __io uint32 JSQR; ///< Injected sequence register + __io uint32 JDR1; ///< Injected data register 1 + __io uint32 JDR2; ///< Injected data register 2 + __io uint32 JDR3; ///< Injected data register 3 + __io uint32 JDR4; ///< Injected data register 4 + __io uint32 DR; ///< Regular data register +} adc_reg_map; + +typedef struct adc_dev { + adc_reg_map *regs; + rcc_clk_id clk_id; +} adc_dev; + +extern const adc_dev *ADC1; +extern const adc_dev *ADC2; +#ifdef STM32_HIGH_DENSITY +extern const adc_dev *ADC3; +#endif + +/* + * ADC peripheral base addresses + */ +#define ADC1_BASE ((adc_reg_map*)0x40012400) +#define ADC2_BASE ((adc_reg_map*)0x40012800) +#define ADC3_BASE ((adc_reg_map*)0x40013C00) + +/* + * Register bit definitions + */ + +/* Status register */ +#define ADC_SR_AWD BIT(0) +#define ADC_SR_EOC BIT(1) +#define ADC_SR_JEOC BIT(2) +#define ADC_SR_JSTRT BIT(3) +#define ADC_SR_STRT BIT(4) + +/* Control register 1 */ +#define ADC_CR1_AWDCH (0x1F) +#define ADC_CR1_EOCIE BIT(5) +#define ADC_CR1_AWDIE BIT(6) +#define ADC_CR1_JEOCIE BIT(7) +#define ADC_CR1_SCAN BIT(8) +#define ADC_CR1_AWDSGL BIT(9) +#define ADC_CR1_JAUTO BIT(10) +#define ADC_CR1_DISCEN BIT(11) +#define ADC_CR1_JDISCEN BIT(12) +#define ADC_CR1_DISCNUM (0xE000) +#define ADC_CR1_JAWDEN BIT(22) +#define ADC_CR1_AWDEN BIT(23) + +/* Control register 2 */ +#define ADC_CR2_ADON BIT(0) +#define ADC_CR2_CONT BIT(1) +#define ADC_CR2_CAL BIT(2) +#define ADC_CR2_RSTCAL BIT(3) +#define ADC_CR2_DMA BIT(8) +#define ADC_CR2_ALIGN BIT(11) +#define ADC_CR2_JEXTSEL (0x7000) +#define ADC_CR2_JEXTTRIG BIT(15) +#define ADC_CR2_EXTSEL (0xE0000) +#define ADC_CR2_EXTTRIG BIT(20) +#define ADC_CR2_JSWSTART BIT(21) +#define ADC_CR2_SWSTART BIT(22) +#define ADC_CR2_TSEREFE BIT(23) + +void adc_init(const adc_dev *dev, uint32 flags); +void adc_set_extsel(const adc_dev *dev, uint8 trigger); /** ADC per-sample conversion times, in ADC clock cycles */ typedef enum { - ADC_SMPR_1_5, - ADC_SMPR_7_5, - ADC_SMPR_13_5, - ADC_SMPR_28_5, - ADC_SMPR_41_5, - ADC_SMPR_55_5, - ADC_SMPR_71_5, - ADC_SMPR_239_5 + ADC_SMPR_1_5, ///< 1.5 ADC cycles + ADC_SMPR_7_5, ///< 7.5 ADC cycles + ADC_SMPR_13_5, ///< 13.5 ADC cycles + ADC_SMPR_28_5, ///< 28.5 ADC cycles + ADC_SMPR_41_5, ///< 41.5 ADC cycles + ADC_SMPR_55_5, ///< 55.5 ADC cycles + ADC_SMPR_71_5, ///< 71.5 ADC cycles + ADC_SMPR_239_5 ///< 239.5 ADC cycles } adc_smp_rate; -/** Initialize ADC1 to do one-shot conversions at the given sample - rate. */ -void adc_init(adc_smp_rate smp_rate); - -void adc_set_sample_rate(adc_smp_rate smp_rate); - -void adc_disable(void); +void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); /** - * Perform a single conversion on ADC[0-15]. - * PRECONDITIONS: - * adc initialized */ -static inline int adc_read(int channel) { - /* Set channel */ - ADC_SQR3 = channel; + * @brief Perform a single synchronous software triggered conversion on a + * channel + * @param regs ADC register map + * @param channel channel to convert + * @return conversion result + */ +static inline uint32 adc_read(const adc_dev *dev, uint8 channel) { + adc_reg_map *regs = dev->regs; + + /* Set target channel */ + regs->SQR3 = channel; /* Start the conversion */ - CR2_SWSTART_BIT = 1; + regs->CR2 |= ADC_CR2_SWSTART; /* Wait for it to finish */ - while(SR_EOC_BIT == 0) + while((regs->SR & ADC_SR_EOC) == 0) ; - return ADC_DR; + return regs->DR; +} + +/** + * @brief Set external trigger conversion mode event for regular channels + * @param dev adc device + * @param enable if 1, conversion on external events is enabled, 0 to disable + */ +static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { + __write(BITBAND_PERI(&(dev->regs->CR2), 20), enable); +} + +/** + * @brief Enable an adc peripheral + * @param regs register map of peripheral to enable + */ +static inline void adc_enable(const adc_dev *dev) { + __write(BITBAND_PERI(&(dev->regs->CR2), 0), 1); +} + +/** + * @brief Disable an adc peripheral + * @param regs register map of peripheral to disable + */ +static inline void adc_disable(const adc_dev *dev) { + __write(BITBAND_PERI(&(dev->regs->CR2), 0), 0); +} + +/** + * @brief Disable all ADCs + */ +static inline void adc_disable_all(void) { + adc_disable(ADC1); + adc_disable(ADC2); +#ifdef STM32_HIGH_DENSITY + adc_disable(ADC3); +#endif } #ifdef __cplusplus |