aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/adc.h
diff options
context:
space:
mode:
authorPerry Hung <iperry@gmail.com>2011-02-27 03:07:31 -0500
committerPerry Hung <iperry@gmail.com>2011-02-27 04:58:43 -0500
commitdef4173e683c3538388aabceeb08e5336c2bdadf (patch)
tree54e2571fb12b31d6730eb1a1b33d09fc53e003a8 /libmaple/adc.h
parentc8ca7a2eb7528462677c80497854b940931eab16 (diff)
downloadlibrambutan-def4173e683c3538388aabceeb08e5336c2bdadf.tar.gz
librambutan-def4173e683c3538388aabceeb08e5336c2bdadf.zip
libmaple: Refactor ADC routines
ADC routines rewritten, support for ADC2, 3, added. Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
Diffstat (limited to 'libmaple/adc.h')
-rw-r--r--libmaple/adc.h193
1 files changed, 137 insertions, 56 deletions
diff --git a/libmaple/adc.h b/libmaple/adc.h
index 976986f..4997d14 100644
--- a/libmaple/adc.h
+++ b/libmaple/adc.h
@@ -25,87 +25,168 @@
/**
* @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 */
+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;
+#if NR_ADCS >= 3
+extern const adc_dev *ADC3;
+#endif
-/* TODO: We'll only use ADC1 for now. See page 41 of the manual for
- ADC2 and ADC3's real addresses. */
+/*
+ * ADC peripheral base 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) */
+#define ADC2_BASE 0x40012800
+#define ADC3_BASE 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(adc_reg_map *regs, 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(adc_reg_map *regs, 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(adc_reg_map *regs, uint8 channel) {
+ /* 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 regs adc register map
+ * @param enable if 1, conversion on external events is enabled, 0 to disable
+ */
+static inline void adc_set_exttrig(adc_reg_map *regs, uint8 enable) {
+ __write(BITBAND_PERI(&(regs->CR2), 20), enable);
+}
+
+/**
+ * @brief Enable an adc peripheral
+ * @param regs register map of peripheral to enable
+ */
+static inline void adc_enable(adc_reg_map *regs) {
+ __write(BITBAND_PERI(&(regs->CR2), 0), 1);
+}
+
+/**
+ * @brief Disable an adc peripheral
+ * @param regs register map of peripheral to disable
+ */
+static inline void adc_disable(adc_reg_map *regs) {
+ __write(BITBAND_PERI(&(regs->CR2), 0), 0);
+}
+
+/**
+ * @brief Disable all ADCs
+ */
+static inline void adc_disable_all(void) {
+ adc_disable(ADC1->regs);
}
#ifdef __cplusplus