diff options
author | Marti Bolivar <mbolivar@leaflabs.com> | 2012-03-26 22:17:47 -0400 |
---|---|---|
committer | Marti Bolivar <mbolivar@leaflabs.com> | 2012-04-11 16:56:56 -0400 |
commit | 28825b6a2f66b0329229185eb9cbd9004fae4b1b (patch) | |
tree | e9714efb41196c4492b68ff878974d01981708cd | |
parent | 7a400b065167beda0a1a9c642954e08581bc0c29 (diff) | |
download | librambutan-28825b6a2f66b0329229185eb9cbd9004fae4b1b.tar.gz librambutan-28825b6a2f66b0329229185eb9cbd9004fae4b1b.zip |
Resurrect ADC support.
Standard refactoring: add series headers for F1 and F2, along with
series adc.c files. There are some issues relating to adc_extsel_event
to hammer out later, but this will do for now.
We also add some new portability interfaces to libmaple/adc.h in order
for Wirish to use the same code to initialize the ADCs at init() time.
As usual, F1 is untested.
Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
-rw-r--r-- | libmaple/adc.c | 74 | ||||
-rw-r--r-- | libmaple/include/libmaple/adc.h | 175 | ||||
-rw-r--r-- | libmaple/rules.mk | 4 | ||||
-rw-r--r-- | libmaple/stm32f1/adc.c | 110 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/adc.h | 254 | ||||
-rw-r--r-- | libmaple/stm32f1/rules.mk | 3 | ||||
-rw-r--r-- | libmaple/stm32f2/adc.c | 84 | ||||
-rw-r--r-- | libmaple/stm32f2/include/series/adc.h | 331 | ||||
-rw-r--r-- | libmaple/stm32f2/rules.mk | 1 | ||||
-rw-r--r-- | wirish/boards.cpp | 15 | ||||
-rw-r--r-- | wirish/boards_private.h | 12 | ||||
-rw-r--r-- | wirish/stm32f1/boards_setup.cpp | 39 | ||||
-rw-r--r-- | wirish/stm32f2/boards_setup.cpp | 32 |
13 files changed, 920 insertions, 214 deletions
diff --git a/libmaple/adc.c b/libmaple/adc.c index 40369e9..acce923 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -25,44 +25,15 @@ *****************************************************************************/ /** - * @file adc.c - * + * @file libmaple/adc.c + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> * @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. - * - * See STM32 manual RM0008 for how to calculate this. */ +#include <libmaple/adc.h> #include <libmaple/libmaple.h> #include <libmaple/rcc.h> -#include <libmaple/adc.h> - -static adc_dev adc1 = { - .regs = ADC1_BASE, - .clk_id = RCC_ADC1 -}; -/** ADC1 device. */ -const adc_dev *ADC1 = &adc1; - -static adc_dev adc2 = { - .regs = ADC2_BASE, - .clk_id = RCC_ADC2 -}; -/** ADC2 device. */ -const adc_dev *ADC2 = &adc2; - -#ifdef STM32_HIGH_DENSITY -adc_dev adc3 = { - .regs = ADC3_BASE, - .clk_id = RCC_ADC3 -}; -/** ADC3 device. */ -const adc_dev *ADC3 = &adc3; -#endif /** * @brief Initialize an ADC peripheral. @@ -91,20 +62,10 @@ void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) { } /** - * @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 -} - -/** - * @brief Turn the given sample rate into values for ADC_SMPRx. Don't - * call this during conversion. + * @brief Set the sample rate for all channels on an ADC device. + * + * Don't call this during conversion. + * * @param dev adc device * @param smp_rate sample rate to set * @see adc_smp_rate @@ -127,25 +88,8 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { } /** - * @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. + * channel. * @param dev ADC device to use for reading. * @param channel channel to convert * @return conversion result diff --git a/libmaple/include/libmaple/adc.h b/libmaple/include/libmaple/adc.h index d531d00..be29676 100644 --- a/libmaple/include/libmaple/adc.h +++ b/libmaple/include/libmaple/adc.h @@ -1,6 +1,7 @@ /****************************************************************************** * The MIT License * + * Copyright (c) 2012 LeafLabs, LLC. * Copyright (c) 2010 Perry Hung. * * Permission is hereby granted, free of charge, to any person @@ -25,9 +26,10 @@ *****************************************************************************/ /** - * @file adc.h - * - * @brief Analog-to-Digital Conversion (ADC) header. + * @file libmaple/adc.h + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> + * @brief Analog-to-Digital Conversion (ADC) header. */ #ifndef _LIBMAPLE_ADC_H_ @@ -40,6 +42,12 @@ extern "C"{ #include <libmaple/libmaple.h> #include <libmaple/bitband.h> #include <libmaple/rcc.h> +/* We include the series header below, after defining the register map + * and device structs. */ + +/* + * Register map + */ /** ADC register map type. */ typedef struct adc_reg_map { @@ -71,24 +79,30 @@ typedef struct adc_dev { rcc_clk_id clk_id; /**< RCC clock information */ } adc_dev; -extern const adc_dev *ADC1; -extern const adc_dev *ADC2; -#ifdef STM32_HIGH_DENSITY -extern const adc_dev *ADC3; -#endif - -/* - * Register map base pointers +/* Pull in the series header (which may need the above struct + * definitions). + * + * IMPORTANT: The series header must define the following: + * + * - enum adc_extsel_event (and typedef to adc_extsel_event): One per + * external event used to trigger start of conversion of a regular + * group. If two different series support the same event as a + * trigger, they must use the same token for the enumerator for that + * event. (The value of the enumerator is of course allowed to be + * different). + * + * - enum adc_smp_rate (and typedef to adc_smp_rate): One per + * available sampling time. These must be in the form ADC_SMPR_X_Y + * for X.Y cycles (e.g. ADC_SMPR_1_5 means 1.5 cycles), or + * ADC_SMPR_X for X cycles (e.g. ADC_SMPR_3 means 3 cycles). + * + * - enum adc_prescaler (and typedef): One per available prescaler, + * suitable for adc_set_prescaler. Series which have the same + * prescaler dividers (e.g. STM32F1 and STM32F2 both divide PCLK2 by + * 2, 4, 6, or 8) must provide the same tokens as enumerators, for + * portability. */ - -/** ADC1 register map base pointer. */ -#define ADC1_BASE ((struct adc_reg_map*)0x40012400) -/** ADC2 register map base pointer. */ -#define ADC2_BASE ((struct adc_reg_map*)0x40012800) -#ifdef STM32_HIGH_DENSITY -/** ADC3 register map base pointer. */ -#define ADC3_BASE ((struct adc_reg_map*)0x40013C00) -#endif +#include <series/adc.h> /* * Register bit definitions @@ -136,31 +150,9 @@ extern const adc_dev *ADC3; /* 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_JEXTTRIG_BIT 15 -#define ADC_CR2_EXTTRIG_BIT 20 -#define ADC_CR2_JSWSTART_BIT 21 -#define ADC_CR2_SWSTART_BIT 22 -#define ADC_CR2_TSEREFE_BIT 23 - -#define ADC_CR2_ADON BIT(ADC_CR2_ADON_BIT) -#define ADC_CR2_CONT BIT(ADC_CR2_CONT_BIT) -#define ADC_CR2_CAL BIT(ADC_CR2_CAL_BIT) -#define ADC_CR2_RSTCAL BIT(ADC_CR2_RSTCAL_BIT) -#define ADC_CR2_DMA BIT(ADC_CR2_DMA_BIT) -#define ADC_CR2_ALIGN BIT(ADC_CR2_ALIGN_BIT) -#define ADC_CR2_JEXTSEL (0x7000) -#define ADC_CR2_JEXTTRIG BIT(ADC_CR2_JEXTTRIG_BIT) -#define ADC_CR2_EXTSEL (0xE0000) -#define ADC_CR2_EXTTRIG BIT(ADC_CR2_EXTTRIG_BIT) -#define ADC_CR2_JSWSTART BIT(ADC_CR2_JSWSTART_BIT) -#define ADC_CR2_SWSTART BIT(ADC_CR2_SWSTART_BIT) -#define ADC_CR2_TSEREFE BIT(ADC_CR2_TSEREFE_BIT) +/* Because this register varies significantly by series (e.g. some + * bits moved and others disappeared in the F1->F2 transition), its + * definitions are in the series headers. */ /* Sample time register 1 */ @@ -245,68 +237,47 @@ extern const adc_dev *ADC3; #define ADC_DR_ADC2DATA (0xFFFF << 16) #define ADC_DR_DATA 0xFFFF -void adc_init(const adc_dev *dev); +/* + * Routines + */ /** - * @brief External event selector for regular group conversion. - * @see adc_set_extsel + * @brief Set the ADC prescaler. + * + * This determines the ADC clock for all devices. */ -typedef enum adc_extsel_event { - ADC_ADC12_TIM1_CC1 = (0 << 17), /**< ADC1 and ADC2: Timer 1 CC1 event */ - ADC_ADC12_TIM1_CC2 = (1 << 17), /**< ADC1 and ADC2: Timer 1 CC2 event */ - ADC_ADC12_TIM1_CC3 = (2 << 17), /**< ADC1 and ADC2: Timer 1 CC3 event */ - ADC_ADC12_TIM2_CC2 = (3 << 17), /**< ADC1 and ADC2: Timer 2 CC2 event */ - ADC_ADC12_TIM3_TRGO = (4 << 17), /**< ADC1 and ADC2: Timer 3 TRGO event */ - ADC_ADC12_TIM4_CC4 = (5 << 17), /**< ADC1 and ADC2: Timer 4 CC4 event */ - ADC_ADC12_EXTI11 = (6 << 17), /**< ADC1 and ADC2: EXTI11 event */ -#ifdef STM32_HIGH_DENSITY - ADC_ADC12_TIM8_TRGO = (6 << 17), /**< ADC1 and ADC2: Timer 8 TRGO - event (high density only) */ -#endif - ADC_ADC12_SWSTART = (7 << 17), /**< ADC1 and ADC2: Software start */ -#ifdef STM32_HIGH_DENSITY - ADC_ADC3_TIM3_CC1 = (0 << 17), /**< ADC3: Timer 3 CC1 event - (high density only) */ - ADC_ADC3_TIM2_CC3 = (1 << 17), /**< ADC3: Timer 2 CC3 event - (high density only) */ - ADC_ADC3_TIM1_CC3 = (2 << 17), /**< ADC3: Timer 1 CC3 event - (high density only) */ - ADC_ADC3_TIM8_CC1 = (3 << 17), /**< ADC3: Timer 8 CC1 event - (high density only) */ - ADC_ADC3_TIM8_TRGO = (4 << 17), /**< ADC3: Timer 8 TRGO event - (high density only) */ - ADC_ADC3_TIM5_CC1 = (5 << 17), /**< ADC3: Timer 5 CC1 event - (high density only) */ - ADC_ADC3_TIM5_CC3 = (6 << 17), /**< ADC3: Timer 5 CC3 event - (high density only) */ - ADC_ADC3_SWSTART = (7 << 17), /**< ADC3: Software start (high - density only) */ -#endif - ADC_SWSTART = (7 << 17) /**< ADC1, ADC2, ADC3: Software start */ -} adc_extsel_event; +void adc_set_prescaler(adc_prescaler pre); +void adc_init(const adc_dev *dev); void adc_set_extsel(const adc_dev *dev, adc_extsel_event event); +void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); +uint16 adc_read(const adc_dev *dev, uint8 channel); + +/** + * @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*)); /** - * @brief ADC sample times, in ADC clock cycles - * - * These control the amount of time spent sampling the input voltage. + * @brief Configure a GPIO pin for ADC conversion. + * @param gdev GPIO device to configure. + * @param bit Bit on gdev to configure for ADC conversion. */ -typedef enum { - 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; +struct gpio_dev; +void adc_gpio_cfg(struct gpio_dev *gdev, uint8 bit); -void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); -void adc_calibrate(const adc_dev *dev); -uint16 adc_read(const adc_dev *dev, uint8 channel); +/** + * @brief Enable an ADC and configure it for single conversion mode. + * + * This function performs any initialization necessary to allow the + * ADC device to perform a single synchronous regular software + * triggered conversion, using adc_read(). + * + * @param dev Device to enable. + * @see adc_read() + */ +void adc_enable_single_swstart(const adc_dev* dev); /** * @brief Set the regular channel sequence length. @@ -325,16 +296,6 @@ static inline void adc_set_reg_seqlen(const adc_dev *dev, uint8 length) { } /** - * @brief Set external trigger conversion mode event for regular channels - * @param dev ADC device - * @param enable If 1, conversion on external events is enabled; if 0, - * disabled. - */ -static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { - *bb_perip(&dev->regs->CR2, ADC_CR2_EXTTRIG_BIT) = !!enable; -} - -/** * @brief Enable an adc peripheral * @param dev ADC device to enable */ diff --git a/libmaple/rules.mk b/libmaple/rules.mk index cc562ea..d118b16 100644 --- a/libmaple/rules.mk +++ b/libmaple/rules.mk @@ -11,7 +11,8 @@ LIBMAPLE_PRIVATE_INCLUDES := -I$(LIBMAPLE_PATH) CFLAGS_$(d) = $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror # Local rules and targets -cSRCS_$(d) := flash.c +cSRCS_$(d) := adc.c +cSRCS_$(d) += flash.c cSRCS_$(d) += gpio.c cSRCS_$(d) += iwdg.c cSRCS_$(d) += nvic.c @@ -23,7 +24,6 @@ cSRCS_$(d) += usart.c cSRCS_$(d) += usart_private.c cSRCS_$(d) += util.c # These still need to be ported to F2: -# cSRCS_$(d) += adc.c # cSRCS_$(d) += dac.c # cSRCS_$(d) += dma.c # cSRCS_$(d) += exti.c diff --git a/libmaple/stm32f1/adc.c b/libmaple/stm32f1/adc.c new file mode 100644 index 0000000..8242520 --- /dev/null +++ b/libmaple/stm32f1/adc.c @@ -0,0 +1,110 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/adc.c + * @brief STM32F1 ADC header. + */ + +#include <libmaple/adc.h> +#include <libmaple/gpio.h> + +/* + * Devices + */ + +static adc_dev adc1 = { + .regs = ADC1_BASE, + .clk_id = RCC_ADC1 +}; +/** ADC1 device. */ +const adc_dev *ADC1 = &adc1; + +static adc_dev adc2 = { + .regs = ADC2_BASE, + .clk_id = RCC_ADC2 +}; +/** ADC2 device. */ +const adc_dev *ADC2 = &adc2; + +#ifdef STM32_HIGH_DENSITY +adc_dev adc3 = { + .regs = ADC3_BASE, + .clk_id = RCC_ADC3 +}; +/** ADC3 device. */ +const adc_dev *ADC3 = &adc3; +#endif + +/* + * STM32F1 routines + */ + +/** + * @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) + ; +} + +/* + * Common routines + */ + +void adc_set_prescaler(adc_prescaler pre) { + rcc_set_prescaler(RCC_PRESCALER_ADC, (uint32)pre); +} + +void adc_foreach(void (*fn)(const adc_dev*)) { + fn(ADC1); + fn(ADC2); +#ifdef STM32_HIGH_DENSITY + fn(ADC3); +#endif +} + +void adc_gpio_cfg(gpio_dev *gdev, uint8 bit) { + gpio_set_mode(gdev, bit, GPIO_INPUT_ANALOG); +} + +void adc_enable_single_swstart(const adc_dev *dev) { + adc_init(dev); + adc_set_extsel(dev, ADC_SWSTART); + adc_set_exttrig(dev, 1); + adc_enable(dev); + adc_calibrate(dev); +} diff --git a/libmaple/stm32f1/include/series/adc.h b/libmaple/stm32f1/include/series/adc.h new file mode 100644 index 0000000..1798e55 --- /dev/null +++ b/libmaple/stm32f1/include/series/adc.h @@ -0,0 +1,254 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file stm32f1/include/series/adc.h + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> + * @brief STM32F1 ADC header. + */ + +#ifndef _LIBMAPLE_STM32F1_ADC_H_ +#define _LIBMAPLE_STM32F1_ADC_H_ + +#include <libmaple/rcc.h> /* For the prescalers */ + +/* + * Devices + */ + +extern const struct adc_dev *ADC1; +extern const struct adc_dev *ADC2; +#ifdef STM32_HIGH_DENSITY +extern const struct adc_dev *ADC3; +#endif + +/* + * Register map base pointers + */ + +/** ADC1 register map base pointer. */ +#define ADC1_BASE ((struct adc_reg_map*)0x40012400) +/** ADC2 register map base pointer. */ +#define ADC2_BASE ((struct adc_reg_map*)0x40012800) +#ifdef STM32_HIGH_DENSITY +/** ADC3 register map base pointer. */ +#define ADC3_BASE ((struct adc_reg_map*)0x40013C00) +#endif + +/* + * Register bit definitions + */ + +/* 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_JEXTTRIG_BIT 15 +#define ADC_CR2_EXTTRIG_BIT 20 +#define ADC_CR2_JSWSTART_BIT 21 +#define ADC_CR2_SWSTART_BIT 22 +#define ADC_CR2_TSEREFE_BIT 23 + +#define ADC_CR2_ADON (1U << ADC_CR2_ADON_BIT) +#define ADC_CR2_CONT (1U << ADC_CR2_CONT_BIT) +#define ADC_CR2_CAL (1U << ADC_CR2_CAL_BIT) +#define ADC_CR2_RSTCAL (1U << ADC_CR2_RSTCAL_BIT) +#define ADC_CR2_DMA (1U << ADC_CR2_DMA_BIT) +#define ADC_CR2_ALIGN (1U << ADC_CR2_ALIGN_BIT) +#define ADC_CR2_JEXTSEL 0x7000 +#define ADC_CR2_JEXTTRIG (1U << ADC_CR2_JEXTTRIG_BIT) +#define ADC_CR2_EXTSEL 0xE0000 +#define ADC_CR2_EXTTRIG (1U << ADC_CR2_EXTTRIG_BIT) +#define ADC_CR2_JSWSTART (1U << ADC_CR2_JSWSTART_BIT) +#define ADC_CR2_SWSTART (1U << ADC_CR2_SWSTART_BIT) +#define ADC_CR2_TSEREFE (1U << ADC_CR2_TSEREFE_BIT) + +/* + * Other types + */ + +/** + * @brief STM32F1 external event selectors for regular group + * conversion. + * + * Some external events are only available on ADCs 1 and 2, others + * only on ADC3, while others are available on all three ADCs. + * Additionally, some events are only available on high- and + * XL-density STM32F1 MCUs, as they use peripherals only available on + * those MCU densities. + * + * For ease of use, each event selector is given along with the ADCs + * it's available on, along with any other availability restrictions. + * + * @see adc_set_extsel() + */ +typedef enum adc_extsel_event { + /* TODO: Smarten this up a bit, as follows. + * + * The EXTSEL bits on F1 are a little brain-damaged in that the + * TIM8 TRGO event has different bits depending on whether you're + * using ADC1/2 or ADC3. We route around this by declaring two + * enumerators, ADC_EXT_EV_ADC12_TIM8_TRGO and + * ADC_EXT_EV_ADC3_TIM8_TRGO. + * + * The right thing to do is to provide a single + * ADC_EXT_EV_TIM8_TRGO enumerator and override adc_set_extsel on + * STM32F1 to handle this situation correctly. We can do that + * later, though, and change the per-ADC enumerator values to + * ADC_EXT_EV_TIM8_TRGO to preserve compatibility. */ + + /* ADC1 and ADC2 only: */ + ADC_EXT_EV_TIM1_CC1 = 0x00000, /**< ADC1, ADC2: Timer 1 CC1 event */ + ADC_EXT_EV_TIM1_CC2 = 0x20000, /**< ADC1, ADC2: Timer 1 CC2 event */ + ADC_EXT_EV_TIM2_CC2 = 0x60000, /**< ADC1, ADC2: Timer 2 CC2 event */ + ADC_EXT_EV_TIM3_TRGO = 0x80000, /**< ADC1, ADC2: Timer 3 TRGO event */ + ADC_EXT_EV_TIM4_CC4 = 0xA0000, /**< ADC1, ADC2: Timer 4 CC4 event */ + ADC_EXT_EV_EXTI11 = 0xC0000, /**< ADC1, ADC2: EXTI11 event */ + + /* Common: */ + ADC_EXT_EV_TIM1_CC3 = 0x40000, /**< ADC1, ADC2, ADC3: Timer 1 CC3 event */ + ADC_EXT_EV_SWSTART = 0xE0000, /**< ADC1, ADC2, ADC3: Software start */ + + /* HD only: */ + ADC_EXT_EV_TIM3_CC1 = 0x00000, /**< + * ADC3: Timer 3 CC1 event + * Availability: high- and XL-density. */ + ADC_EXT_EV_TIM2_CC3 = 0x20000, /**< + * ADC3: Timer 2 CC3 event + * Availability: high- and XL-density. */ + ADC_EXT_EV_TIM8_CC1 = 0x60000, /**< + * ADC3: Timer 8 CC1 event + * Availability: high- and XL-density. */ + ADC_EXT_EV_ADC3_TIM8_TRGO = 0x80000, /**< + * ADC3: Timer 8 TRGO event + * Availability: high- and XL-density. */ + ADC_EXT_EV_TIM5_CC1 = 0xA0000, /**< + * ADC3: Timer 5 CC1 event + * Availability: high- and XL-density. */ + ADC_EXT_EV_ADC12_TIM8_TRGO = 0xC0000, /**< + * ADC1, ADC2: Timer 8 TRGO event + * Availability: high- and XL-density. */ + ADC_EXT_EV_TIM5_CC3 = 0xC0000, /**< + * ADC3: Timer 5 CC3 event + * Availability: high- and XL-density. */ +} adc_extsel_event; + +/* We'll keep these old adc_extsel_event enumerators around for a + * while, for backwards compatibility: */ +/** Deprecated. Use ADC_EXT_EV_TIM1_CC1 instead. */ +#define ADC_ADC12_TIM1_CC1 ADC_EXT_EV_TIM1_CC1 +/** Deprecated. Use ADC_EXT_EV_TIM1_CC2 instead. */ +#define ADC_ADC12_TIM1_CC2 ADC_EXT_EV_TIM1_CC2 +/** Deprecated. Use ADC_EXT_EV_TIM1_CC3 instead. */ +#define ADC_ADC12_TIM1_CC3 ADC_EXT_EV_TIM1_CC3 +/** Deprecated. Use ADC_EXT_EV_TIM2_CC2 instead. */ +#define ADC_ADC12_TIM2_CC2 ADC_EXT_EV_TIM2_CC2 +/** Deprecated. Use ADC_EXT_EV_TIM3_TRGO instead. */ +#define ADC_ADC12_TIM3_TRGO ADC_EXT_EV_TIM3_TRGO +/** Deprecated. Use ADC_EXT_EV_TIM4_CC4 instead. */ +#define ADC_ADC12_TIM4_CC4 ADC_EXT_EV_TIM4_CC4 +/** Deprecated. Use ADC_EXT_EV_EXTI11 instead. */ +#define ADC_ADC12_EXTI11 ADC_EXT_EV_EXTI11 +/** Deprecated. Use ADC_EXT_EV_ADC12_TIM8_TRGO instead. */ +#define ADC_ADC12_TIM8_TRGO ADC_EXT_EV_ADC12_TIM8_TRGO +/** Deprecated. Use ADC_EXT_EV_SWSTART instead. */ +#define ADC_ADC12_SWSTART ADC_EXT_EV_SWSTART +/** Deprecated. Use ADC_EXT_EV_TIM1_CC1 instead. */ +#define ADC_ADC3_TIM3_CC1 ADC_EXT_EV_TIM1_CC1 +/** Deprecated. Use ADC_EXT_EV_TIM1_CC2 instead. */ +#define ADC_ADC3_TIM2_CC3 ADC_EXT_EV_TIM1_CC2 +/** Deprecated. Use ADC_EXT_EV_TIM1_CC3 instead. */ +#define ADC_ADC3_TIM1_CC3 ADC_EXT_EV_TIM1_CC3 +/** Deprecated. Use ADC_EXT_EV_TIM2_CC2 instead. */ +#define ADC_ADC3_TIM8_CC1 ADC_EXT_EV_TIM2_CC2 +/** Deprecated. Use ADC_EXT_EV_TIM3_TRGO instead. */ +#define ADC_ADC3_TIM8_TRGO ADC_EXT_EV_TIM3_TRGO +/** Deprecated. Use ADC_EXT_EV_TIM4_CC4 instead. */ +#define ADC_ADC3_TIM5_CC1 ADC_EXT_EV_TIM4_CC4 +/** Deprecated. Use ADC_EXT_EV_EXTI11 instead. */ +#define ADC_ADC3_TIM5_CC3 ADC_EXT_EV_EXTI11 +/** Deprecated. Use ADC_EXT_EV_TIM8_TRGO instead. */ +#define ADC_ADC3_SWSTART ADC_EXT_EV_TIM8_TRGO +/** Deprecated. Use ADC_EXT_EV_SWSTART instead. */ +#define ADC_SWSTART ADC_EXT_EV_SWSTART + +/** + * @brief STM32F1 sample times, in ADC clock cycles. + * + * These control the amount of time spent sampling the input voltage. + * + * IMPORTANT: maximum external impedance must be below 0.4kOhms for + * 1.5 cycle sampling time. At 55.5 cycles/sample, the external input + * impedance must be at most 50kOhms. See your device's datasheet for + * more information. + */ +typedef enum adc_smp_rate { + 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; + +/** + * @brief STM32F1 ADC prescalers, as divisors of PCLK2. + */ +typedef enum adc_prescaler { + ADC_PRE_PCLK2_DIV_2 = RCC_ADCPRE_PCLK_DIV_2, /** PCLK2 divided by 2 */ + ADC_PRE_PCLK2_DIV_4 = RCC_ADCPRE_PCLK_DIV_4, /** PCLK2 divided by 4 */ + ADC_PRE_PCLK2_DIV_6 = RCC_ADCPRE_PCLK_DIV_6, /** PCLK2 divided by 6 */ + ADC_PRE_PCLK2_DIV_8 = RCC_ADCPRE_PCLK_DIV_8, /** PCLK2 divided by 8 */ +} adc_prescaler; + +/* + * Routines + */ + +void adc_calibrate(const adc_dev *dev); + +/** + * @brief Set external trigger conversion mode event for regular channels + * + * Availability: STM32F1. + * + * @param dev ADC device + * @param enable If 1, conversion on external events is enabled; if 0, + * disabled. + */ +static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { + *bb_perip(&dev->regs->CR2, ADC_CR2_EXTTRIG_BIT) = !!enable; +} + +#endif diff --git a/libmaple/stm32f1/rules.mk b/libmaple/stm32f1/rules.mk index bdff00e..c0d6344 100644 --- a/libmaple/stm32f1/rules.mk +++ b/libmaple/stm32f1/rules.mk @@ -11,7 +11,8 @@ CFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -We sSRCS_$(d) := isrs_performance.S sSRCS_$(d) += vector_table_performance.S -cSRCS_$(d) := bkp.c +cSRCS_$(d) := adc.c +cSRCS_$(d) += bkp.c cSRCS_$(d) += fsmc.c cSRCS_$(d) += gpio.c cSRCS_$(d) += rcc.c diff --git a/libmaple/stm32f2/adc.c b/libmaple/stm32f2/adc.c new file mode 100644 index 0000000..fbe1618 --- /dev/null +++ b/libmaple/stm32f2/adc.c @@ -0,0 +1,84 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/adc.c + * @brief STM32F2 ADC header. + */ + +#include <libmaple/adc.h> +#include <libmaple/gpio.h> + +/* + * Devices + */ + +static adc_dev adc1 = { + .regs = ADC1_BASE, + .clk_id = RCC_ADC1, +}; +/** ADC1 device. */ +const adc_dev *ADC1 = &adc1; + +static adc_dev adc2 = { + .regs = ADC2_BASE, + .clk_id = RCC_ADC2, +}; +/** ADC2 device. */ +const adc_dev *ADC2 = &adc2; + +adc_dev adc3 = { + .regs = ADC3_BASE, + .clk_id = RCC_ADC3, +}; +/** ADC3 device. */ +const adc_dev *ADC3 = &adc3; + +/* + * Common routines + */ + +void adc_set_prescaler(adc_prescaler pre) { + uint32 ccr = ADC_COMMON_BASE->CCR; + ccr &= ~ADC_CCR_ADCPRE; + ccr |= (uint32)pre; + ADC_COMMON_BASE->CCR = ccr; +} + +void adc_foreach(void (*fn)(const adc_dev*)) { + fn(ADC1); + fn(ADC2); + fn(ADC3); +} + +void adc_gpio_cfg(gpio_dev *gdev, uint8 bit) { + gpio_set_modef(gdev, bit, GPIO_MODE_ANALOG, GPIO_MODEF_PUPD_NONE); +} + +void adc_enable_single_swstart(const adc_dev *dev) { + adc_init(dev); + adc_enable(dev); +} diff --git a/libmaple/stm32f2/include/series/adc.h b/libmaple/stm32f2/include/series/adc.h new file mode 100644 index 0000000..4f0cd6b --- /dev/null +++ b/libmaple/stm32f2/include/series/adc.h @@ -0,0 +1,331 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file stm32f2/include/series/adc.h + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * @brief STM32F2 ADC header. + */ + +#ifndef _LIBMAPLE_STM32F2_ADC_H_ +#define _LIBMAPLE_STM32F2_ADC_H_ + +#include <libmaple/libmaple_types.h> + +/* + * Devices + */ + +extern const struct adc_dev *ADC1; +extern const struct adc_dev *ADC2; +extern const struct adc_dev *ADC3; + +/* + * Common register map + */ + +/** ADC common register map type */ +typedef struct adc_common_reg_map { + __io uint32 CSR; /**< Common status register */ + __io uint32 CCR; /**< Common control register */ + __io uint32 CDR; /**< + * @brief Common regular data register + * for dual and triple modes */ +} adc_common_reg_map; + +/* + * Register map base pointers + */ + +/** ADC1 register map base pointer. */ +#define ADC1_BASE ((struct adc_reg_map*)0x40012000) +/** ADC2 register map base pointer. */ +#define ADC2_BASE ((struct adc_reg_map*)0x40012100) +/** ADC3 register map base pointer. */ +#define ADC3_BASE ((struct adc_reg_map*)0x40012200) +/** ADC common register map base pointer. */ +#define ADC_COMMON_BASE ((struct adc_common_reg_map*)0x40012300) + +/* + * Register bit definitions + */ + +/* Status register */ + +/** Overrun bit. */ +#define ADC_SR_OVR_BIT 5 +/** Overrun. */ +#define ADC_SR_OVR (1U << ADC_SR_OVR_BIT) + +/* Control register 1 */ + +/** Overrun interrupt enable bit. */ +#define ADC_CR1_OVRIE_BIT 26 + +/** Overrun interrupt error enable. */ +#define ADC_CR1_OVRIE (1U << ADC_CR1_OVRIE_BIT) +/** Conversion resolution. */ +#define ADC_CR1_RES (0x3U << 24) +/** Conversion resolution: 12 bit (at least 15 ADCCLK cycles). */ +#define ADC_CR1_RES_12BIT (0x0U << 24) +/** Conversion resolution: 10 bit (at least 13 ADCCLK cycles). */ +#define ADC_CR1_RES_10BIT (0x1U << 24) +/** Conversion resolution: 8 bit (at least 11 ADCCLK cycles). */ +#define ADC_CR1_RES_8BIT (0x2U << 24) +/** Conversion resolution: 6 bit (at least 9 ADCCLK cycles). */ +#define ADC_CR1_RES_6BIT (0x3U << 24) + +/* Control register 2 */ + +#define ADC_CR2_SWSTART_BIT 30 +#define ADC_CR2_JSWSTART_BIT 22 +#define ADC_CR2_ALIGN_BIT 11 +#define ADC_CR2_EOCS_BIT 10 +#define ADC_CR2_DDS_BIT 9 +#define ADC_CR2_DMA_BIT 8 +#define ADC_CR2_CONT_BIT 1 +#define ADC_CR2_ADON_BIT 0 + +#define ADC_CR2_SWSTART (1U << ADC_CR2_SWSTART_BIT) +#define ADC_CR2_EXTEN (0x3 << 28) +#define ADC_CR2_EXTEN_DISABLED (0x0 << 28) +#define ADC_CR2_EXTEN_RISE (0x1 << 28) +#define ADC_CR2_EXTEN_FALL (0x2 << 28) +#define ADC_CR2_EXTEN_RISE_FALL (0x3 << 28) +#define ADC_CR2_EXTSEL (0xF << 24) +#define ADC_CR2_EXTSEL_TIM1_CC1 (0x0 << 24) +#define ADC_CR2_EXTSEL_TIM1_CC2 (0x1 << 24) +#define ADC_CR2_EXTSEL_TIM1_CC3 (0x2 << 24) +#define ADC_CR2_EXTSEL_TIM2_CC2 (0x3 << 24) +#define ADC_CR2_EXTSEL_TIM2_CC3 (0x4 << 24) +#define ADC_CR2_EXTSEL_TIM2_CC4 (0x5 << 24) +#define ADC_CR2_EXTSEL_TIM1_TRGO (0x6 << 24) +#define ADC_CR2_EXTSEL_TIM3_CC1 (0x7 << 24) +#define ADC_CR2_EXTSEL_TIM3_TRGO (0x8 << 24) +#define ADC_CR2_EXTSEL_TIM4_CC4 (0x9 << 24) +#define ADC_CR2_EXTSEL_TIM5_CC1 (0xA << 24) +#define ADC_CR2_EXTSEL_TIM5_CC2 (0xB << 24) +#define ADC_CR2_EXTSEL_TIM5_CC3 (0xC << 24) +#define ADC_CR2_EXTSEL_TIM8_CC1 (0xD << 24) +#define ADC_CR2_EXTSEL_TIM8_TRGO (0xE << 24) +#define ADC_CR2_EXTSEL_TIM1_EXTI11 (0xF << 24) +#define ADC_CR2_JSWSTART (1U << ADC_CR2_JSWSTART_BIT) +#define ADC_CR2_JEXTEN (0x3 << 20) +#define ADC_CR2_JEXTEN_DISABLED (0x0 << 20) +#define ADC_CR2_JEXTEN_RISE (0x1 << 20) +#define ADC_CR2_JEXTEN_FALL (0x2 << 20) +#define ADC_CR2_JEXTEN_RISE_FALL (0x3 << 20) +#define ADC_CR2_JEXTSEL (0xF << 16) +#define ADC_CR2_JEXTSEL_TIM1_CC4 (0x0 << 16) +#define ADC_CR2_JEXTSEL_TIM1_TRGO (0x1 << 16) +#define ADC_CR2_JEXTSEL_TIM2_CC1 (0x2 << 16) +#define ADC_CR2_JEXTSEL_TIM2_TRGO (0x3 << 16) +#define ADC_CR2_JEXTSEL_TIM3_CC2 (0x4 << 16) +#define ADC_CR2_JEXTSEL_TIM3_CC4 (0x5 << 16) +#define ADC_CR2_JEXTSEL_TIM4_CC1 (0x6 << 16) +#define ADC_CR2_JEXTSEL_TIM4_CC2 (0x7 << 16) +#define ADC_CR2_JEXTSEL_TIM4_CC3 (0x8 << 16) +#define ADC_CR2_JEXTSEL_TIM4_TRGO (0x9 << 16) +#define ADC_CR2_JEXTSEL_TIM5_CC4 (0xA << 16) +#define ADC_CR2_JEXTSEL_TIM5_TRGO (0xB << 16) +#define ADC_CR2_JEXTSEL_TIM8_CC2 (0xC << 16) +#define ADC_CR2_JEXTSEL_TIM8_CC3 (0xD << 16) +#define ADC_CR2_JEXTSEL_TIM8_CC4 (0xE << 16) +#define ADC_CR2_JEXTSEL_TIM1_EXTI15 (0xF << 16) +#define ADC_CR2_ALIGN (1U << ADC_CR2_ALIGN_BIT) +#define ADC_CR2_ALIGN_RIGHT (0U << ADC_CR2_ALIGN_BIT) +#define ADC_CR2_ALIGN_LEFT (1U << ADC_CR2_ALIGN_BIT) +#define ADC_CR2_EOCS (1U << ADC_CR2_EOCS_BIT) +#define ADC_CR2_EOCS_SEQUENCE (0U << ADC_CR2_EOCS_BIT) +#define ADC_CR2_EOCS_CONVERSION (1U << ADC_CR2_EOCS_BIT) +#define ADC_CR2_DDS (1U << ADC_CR2_DDS_BIT) +#define ADC_CR2_DMA (1U << ADC_CR2_DMA_BIT) +#define ADC_CR2_CONT (1U << ADC_CR2_CONT_BIT) +#define ADC_CR2_ADON (1U << ADC_CR2_ADON_BIT) + +/* Common status register */ + +#define ADC_CSR_OVR3_BIT 21 +#define ADC_CSR_STRT3_BIT 20 +#define ADC_CSR_JSTRT3_BIT 19 +#define ADC_CSR_JEOC3_BIT 18 +#define ADC_CSR_EOC3_BIT 17 +#define ADC_CSR_AWD3_BIT 16 +#define ADC_CSR_OVR2_BIT 13 +#define ADC_CSR_STRT2_BIT 12 +#define ADC_CSR_JSTRT2_BIT 11 +#define ADC_CSR_JEOC2_BIT 10 +#define ADC_CSR_EOC2_BIT 9 +#define ADC_CSR_AWD2_BIT 8 +#define ADC_CSR_OVR1_BIT 5 +#define ADC_CSR_STRT1_BIT 4 +#define ADC_CSR_JSTRT1_BIT 3 +#define ADC_CSR_JEOC1_BIT 2 +#define ADC_CSR_EOC1_BIT 1 +#define ADC_CSR_AWD1_BIT 0 + +#define ADC_CSR_OVR3 (1U << ADC_CSR_OVR3_BIT) +#define ADC_CSR_STRT3 (1U << ADC_CSR_STRT3_BIT) +#define ADC_CSR_JSTRT3 (1U << ADC_CSR_JSTRT3_BIT) +#define ADC_CSR_JEOC3 (1U << ADC_CSR_JEOC3_BIT) +#define ADC_CSR_EOC3 (1U << ADC_CSR_EOC3_BIT) +#define ADC_CSR_AWD3 (1U << ADC_CSR_AWD3_BIT) +#define ADC_CSR_OVR2 (1U << ADC_CSR_OVR2_BIT) +#define ADC_CSR_STRT2 (1U << ADC_CSR_STRT2_BIT) +#define ADC_CSR_JSTRT2 (1U << ADC_CSR_JSTRT2_BIT) +#define ADC_CSR_JEOC2 (1U << ADC_CSR_JEOC2_BIT) +#define ADC_CSR_EOC2 (1U << ADC_CSR_EOC2_BIT) +#define ADC_CSR_AWD2 (1U << ADC_CSR_AWD2_BIT) +#define ADC_CSR_OVR1 (1U << ADC_CSR_OVR1_BIT) +#define ADC_CSR_STRT1 (1U << ADC_CSR_STRT1_BIT) +#define ADC_CSR_JSTRT1 (1U << ADC_CSR_JSTRT1_BIT) +#define ADC_CSR_JEOC1 (1U << ADC_CSR_JEOC1_BIT) +#define ADC_CSR_EOC1 (1U << ADC_CSR_EOC1_BIT) +#define ADC_CSR_AWD1 (1U << ADC_CSR_AWD1_BIT) + +/* Common control register */ + +#define ADC_CCR_TSVREFE_BIT 23 +#define ADC_CCR_VBATE_BIT 22 +#define ADC_CCR_DDS_BIT 13 + +#define ADC_CCR_TSVREFE (1U << ADC_CCR_TSVREFE_BIT) +#define ADC_CCR_VBATE (1U << ADC_CCR_VBATE_BIT) +#define ADC_CCR_ADCPRE (0x3 << 16) +#define ADC_CCR_ADCPRE_PCLK2_DIV_2 (0x0 << 16) +#define ADC_CCR_ADCPRE_PCLK2_DIV_4 (0x1 << 16) +#define ADC_CCR_ADCPRE_PCLK2_DIV_6 (0x2 << 16) +#define ADC_CCR_ADCPRE_PCLK2_DIV_8 (0x3 << 16) +#define ADC_CCR_DMA (0x3 << 14) +#define ADC_CCR_DMA_DIS (0x0 << 14) +#define ADC_CCR_DMA_MODE_1 (0x1 << 14) +#define ADC_CCR_DMA_MODE_2 (0x2 << 14) +#define ADC_CCR_DMA_MODE_3 (0x3 << 14) +#define ADC_CCR_DDS (1U << ADC_CCR_DDS_BIT) +#define ADC_CCR_DELAY (0xF << 8) +#define ADC_CCR_DELAY_5 (0x0 << 8) +#define ADC_CCR_DELAY_6 (0x1 << 8) +#define ADC_CCR_DELAY_7 (0x2 << 8) +#define ADC_CCR_DELAY_8 (0x3 << 8) +#define ADC_CCR_DELAY_9 (0x4 << 8) +#define ADC_CCR_DELAY_10 (0x5 << 8) +#define ADC_CCR_DELAY_11 (0x6 << 8) +#define ADC_CCR_DELAY_12 (0x7 << 8) +#define ADC_CCR_DELAY_13 (0x8 << 8) +#define ADC_CCR_DELAY_14 (0x9 << 8) +#define ADC_CCR_DELAY_15 (0xA << 8) +#define ADC_CCR_DELAY_16 (0xB << 8) +#define ADC_CCR_DELAY_17 (0xC << 8) +#define ADC_CCR_DELAY_18 (0xD << 8) +#define ADC_CCR_DELAY_19 (0xE << 8) +#define ADC_CCR_DELAY_20 (0xF << 8) +/** Multi ADC mode selection. */ +#define ADC_CCR_MULTI 0x1F +/** All ADCs independent. */ +#define ADC_CCR_MULTI_INDEPENDENT 0x0 +/** Dual mode: combined regular simultaneous/injected simultaneous. */ +#define ADC_CCR_MULTI_DUAL_REG_SIM_INJ_SIM 0x1 +/** Dual mode: combined regular simultaneous/alternate trigger. */ +#define ADC_CCR_MULTI_DUAL_REG_SIM_ALT_TRIG 0x2 +/** Dual mode: injected simultaneous mode only. */ +#define ADC_CCR_MULTI_DUAL_INJ_SIM 0x5 +/** Dual mode: regular simultaneous mode only. */ +#define ADC_CCR_MULTI_DUAL_REG_SIM 0x6 +/** Dual mode: interleaved mode only. */ +#define ADC_CCR_MULTI_DUAL_INTER 0x7 +/** Dual mode: alternate trigger mode only. */ +#define ADC_CCR_MULTI_DUAL_ALT_TRIG 0x9 +/** Triple mode: combined regular simultaneous/injected simultaneous. */ +#define ADC_CCR_MULTI_TRIPLE_REG_SIM_INJ_SIM 0x10 +/** Triple mode: combined regular simultaneous/alternate trigger. */ +#define ADC_CCR_MULTI_TRIPLE_REG_SIM_ALT_TRIG 0x11 +/** Triple mode: injected simultaneous mode only. */ +#define ADC_CCR_MULTI_TRIPLE_INJ_SIM 0x12 +/** Triple mode: regular simultaneous mode only. */ +#define ADC_CCR_MULTI_TRIPLE_REG_SIM 0x15 +/** Triple mode: interleaved mode only. */ +#define ADC_CCR_MULTI_TRIPLE_INTER 0x17 +/** Triple mode: alternate trigger mode only. */ +#define ADC_CCR_MULTI_TRIPLE_ALT_TRIG 0x19 + +/* Common regular data register for dual and triple modes */ + +#define ADC_CDR_DATA2 0xFFFF0000 +#define ADC_CDR_DATA1 0xFFFF + +/* + * Other types + */ + +/** + * @brief STM32F2 external event selectors for regular group + * conversion. + * @see adc_set_extsel() + */ +typedef enum adc_extsel_event { + ADC_EXT_EV_TIM1_CC1 = ADC_CR2_EXTSEL_TIM1_CC1, + ADC_EXT_EV_TIM1_CC2 = ADC_CR2_EXTSEL_TIM1_CC2, + ADC_EXT_EV_TIM1_CC3 = ADC_CR2_EXTSEL_TIM1_CC3, + ADC_EXT_EV_TIM2_CC2 = ADC_CR2_EXTSEL_TIM2_CC2, + ADC_EXT_EV_TIM2_CC3 = ADC_CR2_EXTSEL_TIM2_CC3, + ADC_EXT_EV_TIM2_CC4 = ADC_CR2_EXTSEL_TIM2_CC4, + ADC_EXT_EV_TIM1_TRGO = ADC_CR2_EXTSEL_TIM1_TRGO, + ADC_EXT_EV_TIM3_CC1 = ADC_CR2_EXTSEL_TIM3_CC1, + ADC_EXT_EV_TIM3_TRGO = ADC_CR2_EXTSEL_TIM3_TRGO, + ADC_EXT_EV_TIM4_CC4 = ADC_CR2_EXTSEL_TIM4_CC4, + ADC_EXT_EV_TIM5_CC1 = ADC_CR2_EXTSEL_TIM5_CC1, + ADC_EXT_EV_TIM5_CC2 = ADC_CR2_EXTSEL_TIM5_CC2, + ADC_EXT_EV_TIM5_CC3 = ADC_CR2_EXTSEL_TIM5_CC3, + ADC_EXT_EV_TIM8_CC1 = ADC_CR2_EXTSEL_TIM8_CC1, + ADC_EXT_EV_TIM8_TRGO = ADC_CR2_EXTSEL_TIM8_TRGO, + ADC_EXT_EV_TIM1_EXTI11 = ADC_CR2_EXTSEL_TIM1_EXTI11, +} adc_extsel_event; + +/** + * @brief STM32F2 sample times, in ADC clock cycles. + */ +typedef enum adc_smp_rate { + ADC_SMPR_3, /**< 3 ADC cycles */ + ADC_SMPR_15, /**< 15 ADC cycles */ + ADC_SMPR_28, /**< 28 ADC cycles */ + ADC_SMPR_56, /**< 56 ADC cycles */ + ADC_SMPR_84, /**< 84 ADC cycles */ + ADC_SMPR_112, /**< 112 ADC cycles */ + ADC_SMPR_144, /**< 144 ADC cycles */ + ADC_SMPR_480, /**< 480 ADC cycles */ +} adc_smp_rate; + +/** + * @brief STM32F2 ADC prescalers, as divisors of PCLK2. + */ +typedef enum adc_prescaler { + ADC_PRE_PCLK2_DIV_2 = ADC_CCR_ADCPRE_PCLK2_DIV_2, /** PCLK2 divided by 2 */ + ADC_PRE_PCLK2_DIV_4 = ADC_CCR_ADCPRE_PCLK2_DIV_4, /** PCLK2 divided by 4 */ + ADC_PRE_PCLK2_DIV_6 = ADC_CCR_ADCPRE_PCLK2_DIV_6, /** PCLK2 divided by 6 */ + ADC_PRE_PCLK2_DIV_8 = ADC_CCR_ADCPRE_PCLK2_DIV_8, /** PCLK2 divided by 8 */ +} adc_prescaler; + +#endif diff --git a/libmaple/stm32f2/rules.mk b/libmaple/stm32f2/rules.mk index a46f8d1..5951b94 100644 --- a/libmaple/stm32f2/rules.mk +++ b/libmaple/stm32f2/rules.mk @@ -11,6 +11,7 @@ CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) $(LIBMAPLE_PRIVATE_INCLUDES) -Wall -We sSRCS_$(d) := isrs.S sSRCS_$(d) += vector_table.S +cSRCS_$(d) := adc.c cSRCS_$(d) += fsmc.c cSRCS_$(d) += gpio.c cSRCS_$(d) += rcc.c diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 04b359f..54807d3 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -54,6 +54,7 @@ static void setup_flash(void); static void setup_clocks(void); static void setup_nvic(void); +static void setup_adcs(void); /* * Exported functions @@ -65,7 +66,7 @@ void init(void) { setup_nvic(); systick_init(SYSTICK_RELOAD_VAL); wirish::priv::board_setup_gpio(); - wirish::priv::board_setup_adc(); + setup_adcs(); wirish::priv::board_setup_timers(); wirish::priv::board_setup_usb(); boardInit(); @@ -124,7 +125,7 @@ static void setup_clocks(void) { // Configure AHBx, APBx, etc. prescalers and the main PLL. wirish::priv::board_setup_clock_prescalers(); - rcc_configure_pll(&wirish::priv::board_pll_cfg); + rcc_configure_pll(&wirish::priv::w_board_pll_cfg); // Enable the PLL, and wait until it's ready. rcc_turn_on_clk(RCC_CLK_PLL); @@ -146,3 +147,13 @@ static void setup_nvic(void) { #error "You must select a base address for the vector table." #endif } + +static void adc_default_config(const adc_dev *dev) { + adc_enable_single_swstart(dev); + adc_set_sample_rate(dev, wirish::priv::w_adc_smp); +} + +static void setup_adcs(void) { + adc_set_prescaler(wirish::priv::w_adc_pre); + adc_foreach(adc_default_config); +} diff --git a/wirish/boards_private.h b/wirish/boards_private.h index a4101c9..e32f298 100644 --- a/wirish/boards_private.h +++ b/wirish/boards_private.h @@ -28,11 +28,18 @@ * @file wirish/boards_private.h * @author Marti Bolivar <mbolivar@leaflabs.com> * @brief Private board support header. + * + * This file declares chip-specific variables and functions which + * determine how init() behaves. It is not part of the public Wirish + * API, and can change without notice. */ #ifndef _WIRISH_BOARDS_PRIVATE_H_ #define _WIRISH_BOARDS_PRIVATE_H_ +#include <libmaple/rcc.h> +#include <libmaple/adc.h> + namespace wirish { namespace priv { @@ -40,7 +47,9 @@ namespace wirish { * Chip-specific initialization data */ - extern rcc_pll_cfg board_pll_cfg; + extern rcc_pll_cfg w_board_pll_cfg; + extern adc_prescaler w_adc_pre; + extern adc_smp_rate w_adc_smp; /* * Chip-specific initialization routines and helper functions. @@ -49,7 +58,6 @@ namespace wirish { void board_reset_pll(void); void board_setup_clock_prescalers(void); void board_setup_gpio(void); - void board_setup_adc(void); void board_setup_timers(void); void board_setup_usb(void); diff --git a/wirish/stm32f1/boards_setup.cpp b/wirish/stm32f1/boards_setup.cpp index 4ee292a..8e16009 100644 --- a/wirish/stm32f1/boards_setup.cpp +++ b/wirish/stm32f1/boards_setup.cpp @@ -28,11 +28,15 @@ * @file wirish/stm32f1/boards_setup.cpp * @author Marti Bolivar <mbolivar@leaflabs.com> * @brief STM32F1 chip setup. + * + * This file controls how init() behaves on the STM32F1. Be very + * careful when changing anything here. Many of these values depend + * upon each other. */ -#include <libmaple/rcc.h> +#include "boards_private.h" + #include <libmaple/gpio.h> -#include <libmaple/adc.h> #include <libmaple/timer.h> #include <libmaple/usb_cdcacm.h> @@ -45,12 +49,11 @@ namespace wirish { namespace priv { static stm32f1_rcc_pll_data pll_data = {RCC_PLLMUL_9}; - rcc_pll_cfg board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; + rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; + adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6; + adc_smp_rate w_adc_smp = ADC_SMPR_55_5; -#if 0 - static void config_adc(const adc_dev* dev); static void config_timer(timer_dev*); -#endif void board_reset_pll(void) { // TODO @@ -69,17 +72,8 @@ namespace wirish { afio_init(); } - void board_setup_adc(void) { -#if 0 - rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); - adc_foreach(config_adc); -#endif - } - void board_setup_timers(void) { -#if 0 timer_foreach(config_timer); -#endif } void board_setup_usb(void) { @@ -92,19 +86,8 @@ namespace wirish { * Auxiliary routines */ -#if 0 - static void config_adc(const adc_dev *dev) { - adc_init(dev); - - adc_set_extsel(dev, ADC_SWSTART); - adc_set_exttrig(dev, true); - - adc_enable(dev); - adc_calibrate(dev); - adc_set_sample_rate(dev, ADC_SMPR_55_5); - } - static void config_timer(timer_dev *dev) { +#if 0 timer_adv_reg_map *regs = (dev->regs).adv; const uint16 full_overflow = 0xFFFF; const uint16 half_duty = 0x8FFF; @@ -135,7 +118,7 @@ namespace wirish { } timer_resume(dev); - } #endif + } } } diff --git a/wirish/stm32f2/boards_setup.cpp b/wirish/stm32f2/boards_setup.cpp index b3c690c..e1bf1fd 100644 --- a/wirish/stm32f2/boards_setup.cpp +++ b/wirish/stm32f2/boards_setup.cpp @@ -28,11 +28,18 @@ * @file wirish/stm32f2/boards_setup.cpp * @author Marti Bolivar <mbolivar@leaflabs.com> * @brief STM32F2 chip setup. + * + * This file controls how init() behaves on the STM32F2. Be very + * careful when changing anything here. Many of these values depend + * upon each other. */ -#include <libmaple/rcc.h> +#include "boards_private.h" + #include <libmaple/gpio.h> +#include <wirish/wirish_types.h> +// PLL configuration for 25 MHz external oscillator --> 120 MHz SYSCLK. #define PLL_Q 5 #define PLL_P 2 #define PLL_N 240 @@ -41,7 +48,18 @@ static stm32f2_rcc_pll_data pll_data = {PLL_Q, PLL_P, PLL_N, PLL_M}; namespace wirish { namespace priv { - rcc_pll_cfg board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; + // PLL clocked off of HSE, with above configuration data. + rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data}; + // As f_APB2 = 60 MHz (see board_setup_clock_prescalers), + // we need f_ADC = f_PCLK2 / 2 to get the (maximum) + // f_ADC = 30 MHz. + adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_2; + // With clocks as specified here (i.e. f_ADC = 30 MHz), this + // ADC sample rate allows for error less than 1/4 LSB with a + // 50 KOhm input impedance, assuming an internal sample and + // hold capacitance C_ADC at most 8.8 pF. See Equation 1 and + // Table 61 in the F2 datasheet for more details. + adc_smp_rate w_adc_smp = ADC_SMPR_144; void board_reset_pll(void) { // Set PLLCFGR to its reset value. @@ -49,8 +67,13 @@ namespace wirish { } void board_setup_clock_prescalers(void) { + // With f_SYSCLK = 120 MHz (as determined by board_pll_cfg), + // + // f_AHB = f_SYSCLK / 1 = 120 MHz rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1); + // f_APB1 = f_AHB / 4 = 30 MHz rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_4); + // f_APB2 = f_AHB / 2 = 60 MHz rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_2); } @@ -58,10 +81,6 @@ namespace wirish { gpio_init_all(); } - void board_setup_adc(void) { - // TODO - } - void board_setup_timers(void) { // TODO } @@ -72,4 +91,3 @@ namespace wirish { } } - |