aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple')
-rw-r--r--libmaple/adc.c78
-rw-r--r--libmaple/dac.c28
-rw-r--r--libmaple/dac.h168
-rw-r--r--libmaple/delay.h30
-rw-r--r--libmaple/dma.c363
-rw-r--r--libmaple/dma.h453
-rw-r--r--libmaple/dma_private.h61
-rw-r--r--libmaple/exti.c63
-rw-r--r--libmaple/exti_private.h34
-rw-r--r--libmaple/flash.c22
-rw-r--r--libmaple/gpio.c157
-rw-r--r--libmaple/i2c.c488
-rw-r--r--libmaple/i2c_private.h79
-rw-r--r--libmaple/include/libmaple/adc.h (renamed from libmaple/adc.h)193
-rw-r--r--libmaple/include/libmaple/bitband.h (renamed from libmaple/bitband.h)22
-rw-r--r--libmaple/include/libmaple/bkp.h (renamed from libmaple/bkp.h)14
-rw-r--r--libmaple/include/libmaple/dac.h158
-rw-r--r--libmaple/include/libmaple/delay.h (renamed from libmaple/exti.h)59
-rw-r--r--libmaple/include/libmaple/dma.h444
-rw-r--r--libmaple/include/libmaple/dma_common.h114
-rw-r--r--libmaple/include/libmaple/exti.h138
-rw-r--r--libmaple/include/libmaple/flash.h106
-rw-r--r--libmaple/include/libmaple/fsmc.h (renamed from libmaple/fsmc.h)108
-rw-r--r--libmaple/include/libmaple/gpio.h121
-rw-r--r--libmaple/include/libmaple/i2c.h (renamed from libmaple/i2c.h)393
-rw-r--r--libmaple/include/libmaple/i2c_common.h95
-rw-r--r--libmaple/include/libmaple/iwdg.h (renamed from libmaple/iwdg.h)15
-rw-r--r--libmaple/include/libmaple/libmaple.h (renamed from libmaple/libmaple.h)21
-rw-r--r--libmaple/include/libmaple/libmaple_types.h (renamed from libmaple/libmaple_types.h)23
-rw-r--r--libmaple/include/libmaple/nvic.h155
-rw-r--r--libmaple/include/libmaple/pwr.h (renamed from libmaple/pwr.h)56
-rw-r--r--libmaple/include/libmaple/rcc.h175
-rw-r--r--libmaple/include/libmaple/ring_buffer.h (renamed from libmaple/ring_buffer.h)11
-rw-r--r--libmaple/include/libmaple/scb.h (renamed from libmaple/scb.h)16
-rw-r--r--libmaple/include/libmaple/spi.h (renamed from libmaple/spi.h)169
-rw-r--r--libmaple/include/libmaple/stm32.h237
-rw-r--r--libmaple/include/libmaple/syscfg.h151
-rw-r--r--libmaple/include/libmaple/systick.h (renamed from libmaple/systick.h)16
-rw-r--r--libmaple/include/libmaple/timer.h (renamed from libmaple/timer.h)646
-rw-r--r--libmaple/include/libmaple/usart.h (renamed from libmaple/usart.h)259
-rw-r--r--libmaple/include/libmaple/usb.h (renamed from libmaple/usb.h)12
-rw-r--r--libmaple/include/libmaple/usb_cdcacm.h (renamed from libmaple/usb/usb_cdcacm.h)10
-rw-r--r--libmaple/include/libmaple/util.h (renamed from libmaple/util.h)16
-rw-r--r--libmaple/iwdg.c4
-rw-r--r--libmaple/nvic.c34
-rw-r--r--libmaple/pwr.c6
-rw-r--r--libmaple/rcc.c269
-rw-r--r--libmaple/rcc_private.h67
-rw-r--r--libmaple/rules.mk54
-rw-r--r--libmaple/spi.c84
-rw-r--r--libmaple/spi_private.h37
-rw-r--r--libmaple/stm32.h191
-rw-r--r--libmaple/stm32_private.h45
-rw-r--r--libmaple/stm32f1/adc.c112
-rw-r--r--libmaple/stm32f1/bkp.c (renamed from libmaple/bkp.c)12
-rw-r--r--libmaple/stm32f1/dma.c412
-rw-r--r--libmaple/stm32f1/exti.c32
-rw-r--r--libmaple/stm32f1/fsmc.c (renamed from libmaple/fsmc.c)20
-rw-r--r--libmaple/stm32f1/gpio.c166
-rw-r--r--libmaple/stm32f1/i2c.c129
-rw-r--r--libmaple/stm32f1/include/series/adc.h254
-rw-r--r--libmaple/stm32f1/include/series/dac.h71
-rw-r--r--libmaple/stm32f1/include/series/dma.h565
-rw-r--r--libmaple/stm32f1/include/series/exti.h46
-rw-r--r--libmaple/stm32f1/include/series/flash.h (renamed from libmaple/flash.h)85
-rw-r--r--libmaple/stm32f1/include/series/gpio.h (renamed from libmaple/gpio.h)456
-rw-r--r--libmaple/stm32f1/include/series/i2c.h85
-rw-r--r--libmaple/stm32f1/include/series/nvic.h (renamed from libmaple/nvic.h)182
-rw-r--r--libmaple/stm32f1/include/series/pwr.h52
-rw-r--r--libmaple/stm32f1/include/series/rcc.h (renamed from libmaple/rcc.h)489
-rw-r--r--libmaple/stm32f1/include/series/spi.h99
-rw-r--r--libmaple/stm32f1/include/series/stm32.h212
-rw-r--r--libmaple/stm32f1/include/series/timer.h128
-rw-r--r--libmaple/stm32f1/include/series/usart.h76
-rw-r--r--libmaple/stm32f1/performance/isrs.S (renamed from libmaple/stm32f1/isrs_performance.S)28
-rw-r--r--libmaple/stm32f1/performance/vector_table.S (renamed from libmaple/stm32f1/vector_table_performance.S)28
-rw-r--r--libmaple/stm32f1/rcc.c164
-rw-r--r--libmaple/stm32f1/rules.mk27
-rw-r--r--libmaple/stm32f1/spi.c84
-rw-r--r--libmaple/stm32f1/timer.c124
-rw-r--r--libmaple/stm32f1/usart.c170
-rw-r--r--libmaple/stm32f1/value/isrs.S270
-rw-r--r--libmaple/stm32f1/value/vector_table.S116
-rw-r--r--libmaple/stm32f2/adc.c84
-rw-r--r--libmaple/stm32f2/dma.c504
-rw-r--r--libmaple/stm32f2/exti.c33
-rw-r--r--libmaple/stm32f2/fsmc.c90
-rw-r--r--libmaple/stm32f2/gpio.c194
-rw-r--r--libmaple/stm32f2/include/series/adc.h331
-rw-r--r--libmaple/stm32f2/include/series/dac.h94
-rw-r--r--libmaple/stm32f2/include/series/dma.h810
-rw-r--r--libmaple/stm32f2/include/series/exti.h46
-rw-r--r--libmaple/stm32f2/include/series/flash.h202
-rw-r--r--libmaple/stm32f2/include/series/gpio.h264
-rw-r--r--libmaple/stm32f2/include/series/nvic.h160
-rw-r--r--libmaple/stm32f2/include/series/pwr.h73
-rw-r--r--libmaple/stm32f2/include/series/rcc.h951
-rw-r--r--libmaple/stm32f2/include/series/spi.h88
-rw-r--r--libmaple/stm32f2/include/series/stm32.h77
-rw-r--r--libmaple/stm32f2/include/series/timer.h176
-rw-r--r--libmaple/stm32f2/include/series/usart.h111
-rw-r--r--libmaple/stm32f2/isrs.S322
-rw-r--r--libmaple/stm32f2/rcc.c175
-rw-r--r--libmaple/stm32f2/rules.mk40
-rw-r--r--libmaple/stm32f2/spi.c88
-rw-r--r--libmaple/stm32f2/syscfg.c78
-rw-r--r--libmaple/stm32f2/timer.c148
-rw-r--r--libmaple/stm32f2/usart.c204
-rw-r--r--libmaple/stm32f2/vector_table.S135
-rw-r--r--libmaple/syscalls.c167
-rw-r--r--libmaple/systick.c6
-rw-r--r--libmaple/timer.c476
-rw-r--r--libmaple/timer_private.h235
-rw-r--r--libmaple/usart.c144
-rw-r--r--libmaple/usart_private.c41
-rw-r--r--libmaple/usart_private.h53
-rw-r--r--libmaple/usb/README69
-rw-r--r--libmaple/usb/rules.mk45
-rw-r--r--libmaple/usb/stm32f1/usb.c (renamed from libmaple/usb/usb.c)12
-rw-r--r--libmaple/usb/stm32f1/usb_cdcacm.c (renamed from libmaple/usb/usb_cdcacm.c)26
-rw-r--r--libmaple/usb/stm32f1/usb_descriptors.h (renamed from libmaple/usb/usb_descriptors.h)2
-rw-r--r--libmaple/usb/stm32f1/usb_lib_globals.h (renamed from libmaple/usb/usb_lib_globals.h)1
-rw-r--r--libmaple/usb/stm32f1/usb_reg_map.c (renamed from libmaple/usb/usb_reg_map.c)0
-rw-r--r--libmaple/usb/stm32f1/usb_reg_map.h (renamed from libmaple/usb/usb_reg_map.h)4
-rw-r--r--libmaple/util.c123
125 files changed, 14124 insertions, 4220 deletions
diff --git a/libmaple/adc.c b/libmaple/adc.c
index 2bd2ad1..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.h"
-#include "rcc.h"
-#include "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
+#include <libmaple/adc.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
/**
* @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/dac.c b/libmaple/dac.c
index 15e944f..d802d2b 100644
--- a/libmaple/dac.c
+++ b/libmaple/dac.c
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Bryan Newbold.
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,25 +26,20 @@
*****************************************************************************/
/**
- * @file dac.c
+ * @file libmaple/dac.c
* @brief Digital to analog converter support.
*/
-#include "libmaple.h"
-#include "gpio.h"
-#include "dac.h"
-
-#ifdef STM32_HIGH_DENSITY
-
-/**
- * @brief DAC peripheral routines.
- */
+#include <libmaple/dac.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/gpio.h>
+#if STM32_HAVE_DAC
dac_dev dac = {
.regs = DAC_BASE,
};
-/** DAC device. */
const dac_dev *DAC = &dac;
+#endif
/**
* @brief Initialize the digital to analog converter
@@ -92,16 +88,16 @@ void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val) {
*/
void dac_enable_channel(const dac_dev *dev, uint8 channel) {
/*
- * Setup ANALOG mode on PA4 and PA5. This mapping is consistent across
- * all STM32 chips with a DAC. See RM0008 12.2.
+ * Setup ANALOG mode on PA4 and PA5. This mapping is consistent
+ * across all supported STM32s with a DAC.
*/
switch (channel) {
case 1:
- gpio_set_mode(GPIOA, 4, GPIO_INPUT_ANALOG);
+ gpio_set_mode(GPIOA, 4, GPIO_MODE_ANALOG);
dev->regs->CR |= DAC_CR_EN1;
break;
case 2:
- gpio_set_mode(GPIOA, 5, GPIO_INPUT_ANALOG);
+ gpio_set_mode(GPIOA, 5, GPIO_MODE_ANALOG);
dev->regs->CR |= DAC_CR_EN2;
break;
}
@@ -122,5 +118,3 @@ void dac_disable_channel(const dac_dev *dev, uint8 channel) {
break;
}
}
-
-#endif /* STM32_HIGH_DENSITY */
diff --git a/libmaple/dac.h b/libmaple/dac.h
deleted file mode 100644
index aa04981..0000000
--- a/libmaple/dac.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/******************************************************************************
- * The MIT License
- *
- * Copyright (c) 2010 Bryan Newbold.
- *
- * 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 dac.h
- * @brief Digital to analog converter support.
- */
-
-/* See notes/dac.txt for more info */
-
-#ifndef _DAC_H_
-#define _DAC_H_
-
-#include "rcc.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-/*
- * Register maps
- */
-
-/** DAC register map. */
-typedef struct dac_reg_map {
- __io uint32 CR; /**< Control register */
- __io uint32 SWTRIGR; /**< Software trigger register */
- __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data
- holding register */
- __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data
- holding register */
- __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data
- holding register */
- __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data
- holding register */
- __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data
- holding register */
- __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data
- holding register */
- __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data
- holding register */
- __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data
- holding register */
- __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding
- register */
- __io uint32 DOR1; /**< Channel 1 data output register */
- __io uint32 DOR2; /**< Channel 2 data output register */
-} dac_reg_map;
-
-/** DAC register map base address */
-#define DAC_BASE ((struct dac_reg_map*)0x40007400)
-
-/*
- * Devices
- */
-
-/** DAC device type. */
-typedef struct dac_dev {
- dac_reg_map *regs; /**< Register map */
-} dac_dev;
-
-extern const dac_dev *DAC;
-
-/*
- * Register bit definitions
- */
-
-/* Control register */
-/* Channel 1 control */
-#define DAC_CR_EN1 BIT(0) /* Enable */
-#define DAC_CR_BOFF1 BIT(1) /* Output buffer disable */
-#define DAC_CR_TEN1 BIT(2) /* Trigger enable */
-#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */
-#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave enable */
-#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */
-#define DAC_CR_DMAEN1 BIT(12) /* DMA enable */
-/* Channel 2 control */
-#define DAC_CR_EN2 BIT(16) /* Enable */
-#define DAC_CR_BOFF2 BIT(17) /* Output buffer disable */
-#define DAC_CR_TEN2 BIT(18) /* Trigger enable */
-#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */
-#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave generation*/
-#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */
-#define DAC_CR_DMAEN2 BIT(28) /* DMA enable */
-
-/* Software trigger register */
-#define DAC_SWTRIGR_SWTRIG1 BIT(0) /* Channel 1 software trigger */
-#define DAC_SWTRIGR_SWTRIG2 BIT(1) /* Channel 2 software trigger */
-
-/* Channel 1 12-bit right-aligned data holding register */
-#define DAC_DHR12R1_DACC1DHR 0x00000FFF
-
-/* Channel 1 12-bit left-aligned data holding register */
-#define DAC_DHR12L1_DACC1DHR 0x0000FFF0
-
-/* Channel 1 8-bit left-aligned data holding register */
-#define DAC_DHR8R1_DACC1DHR 0x000000FF
-
-/* Channel 2 12-bit right-aligned data holding register */
-#define DAC_DHR12R2_DACC2DHR 0x00000FFF
-
-/* Channel 2 12-bit left-aligned data holding register */
-#define DAC_DHR12L2_DACC2DHR 0x0000FFF0
-
-/* Channel 2 8-bit left-aligned data holding register */
-#define DAC_DHR8R2_DACC2DHR 0x000000FF
-
-/* Dual DAC 12-bit right-aligned data holding register */
-#define DAC_DHR12RD_DACC1DHR 0x00000FFF
-#define DAC_DHR12RD_DACC2DHR 0x0FFF0000
-
-/* Dual DAC 12-bit left-aligned data holding register */
-#define DAC_DHR12LD_DACC1DHR 0x0000FFF0
-#define DAC_DHR12LD_DACC2DHR 0xFFF00000
-
-/* Dual DAC 8-bit left-aligned data holding register */
-#define DAC_DHR8RD_DACC1DHR 0x000000FF
-#define DAC_DHR8RD_DACC2DHR 0x0000FF00
-
-/* Channel 1 data output register */
-#define DAC_DOR1_DACC1DOR 0x00000FFF
-
-/* Channel 1 data output register */
-#define DAC_DOR2_DACC2DOR 0x00000FFF
-
-/*
- * Convenience functions
- */
-
-/* We take the dev argument in these convenience functions for
- * future-proofing */
-
-#define DAC_CH1 0x1
-#define DAC_CH2 0x2
-void dac_init(const dac_dev *dev, uint32 flags);
-
-void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val);
-void dac_enable_channel(const dac_dev *dev, uint8 channel);
-void dac_disable_channel(const dac_dev *dev, uint8 channel);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif
diff --git a/libmaple/delay.h b/libmaple/delay.h
deleted file mode 100644
index 6f8b8ba..0000000
--- a/libmaple/delay.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @file delay.h
- * @brief Delay implementation
- */
-
-#include "libmaple_types.h"
-#include "stm32.h"
-
-#ifndef _DELAY_H_
-#define _DELAY_H_
-
-/**
- * @brief Delay the given number of microseconds.
- *
- * @param us Number of microseconds to delay.
- */
-static inline void delay_us(uint32 us) {
- us *= STM32_DELAY_US_MULT;
-
- /* fudge for function call overhead */
- us--;
- asm volatile(" mov r0, %[us] \n\t"
- "1: subs r0, #1 \n\t"
- " bhi 1b \n\t"
- :
- : [us] "r" (us)
- : "r0");
-}
-#endif
-
diff --git a/libmaple/dma.c b/libmaple/dma.c
index 60f4d47..d13de10 100644
--- a/libmaple/dma.c
+++ b/libmaple/dma.c
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Michael Hope.
+ * Copyright (c) 2012 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,47 +26,15 @@
*****************************************************************************/
/**
- * @file dma.c
+ * @file libmaple/dma.c
* @author Marti Bolivar <mbolivar@leaflabs.com>;
* Original implementation by Michael Hope
- * @brief Direct Memory Access peripheral support
+ * @brief Portable DMA routines.
*/
-#include "dma.h"
-#include "bitband.h"
-#include "util.h"
-
-/*
- * Devices
- */
-
-static dma_dev dma1 = {
- .regs = DMA1_BASE,
- .clk_id = RCC_DMA1,
- .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 },
- { .handler = NULL, .irq_line = NVIC_DMA_CH2 },
- { .handler = NULL, .irq_line = NVIC_DMA_CH3 },
- { .handler = NULL, .irq_line = NVIC_DMA_CH4 },
- { .handler = NULL, .irq_line = NVIC_DMA_CH5 },
- { .handler = NULL, .irq_line = NVIC_DMA_CH6 },
- { .handler = NULL, .irq_line = NVIC_DMA_CH7 }}
-};
-/** DMA1 device */
-dma_dev *DMA1 = &dma1;
-
-#ifdef STM32_HIGH_DENSITY
-static dma_dev dma2 = {
- .regs = DMA2_BASE,
- .clk_id = RCC_DMA2,
- .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 },
- { .handler = NULL, .irq_line = NVIC_DMA2_CH2 },
- { .handler = NULL, .irq_line = NVIC_DMA2_CH3 },
- { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 },
- { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }} /* !@#$ */
-};
-/** DMA2 device */
-dma_dev *DMA2 = &dma2;
-#endif
+#include <libmaple/dma.h>
+#include "dma_private.h"
+#include "stm32_private.h"
/*
* Convenience routines
@@ -79,301 +48,35 @@ void dma_init(dma_dev *dev) {
rcc_clk_enable(dev->clk_id);
}
-/**
- * @brief Set up a DMA transfer.
- *
- * The channel will be disabled before being reconfigured. The
- * transfer will have low priority by default. You may choose another
- * priority before the transfer begins using dma_set_priority(), as
- * well as performing any other configuration you desire. When the
- * channel is configured to your liking, enable it using dma_enable().
- *
- * @param dev DMA device.
- * @param channel DMA channel.
- * @param peripheral_address Base address of peripheral data register
- * involved in the transfer.
- * @param peripheral_size Peripheral data transfer size.
- * @param memory_address Base memory address involved in the transfer.
- * @param memory_size Memory data transfer size.
- * @param mode Logical OR of dma_mode_flags
- * @sideeffect Disables the given DMA channel.
- * @see dma_xfer_size
- * @see dma_mode_flags
- * @see dma_set_num_transfers()
- * @see dma_set_priority()
- * @see dma_attach_interrupt()
- * @see dma_enable()
- */
-void dma_setup_transfer(dma_dev *dev,
- dma_channel channel,
- __io void *peripheral_address,
- dma_xfer_size peripheral_size,
- __io void *memory_address,
- dma_xfer_size memory_size,
- uint32 mode) {
- dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel);
-
- dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */
- channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode;
- channel_regs->CMAR = (uint32)memory_address;
- channel_regs->CPAR = (uint32)peripheral_address;
-}
-
-/**
- * @brief Set the number of data to be transferred on a DMA channel.
- *
- * You may not call this function while the channel is enabled.
- *
- * @param dev DMA device
- * @param channel Channel through which the transfer occurs.
- * @param num_transfers
- */
-void dma_set_num_transfers(dma_dev *dev,
- dma_channel channel,
- uint16 num_transfers) {
- dma_channel_reg_map *channel_regs;
-
- ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
-
- channel_regs = dma_channel_regs(dev, channel);
- channel_regs->CNDTR = num_transfers;
-}
-
-/**
- * @brief Set the priority of a DMA transfer.
- *
- * You may not call this function while the channel is enabled.
- *
- * @param dev DMA device
- * @param channel DMA channel
- * @param priority priority to set.
- */
-void dma_set_priority(dma_dev *dev,
- dma_channel channel,
- dma_priority priority) {
- dma_channel_reg_map *channel_regs;
- uint32 ccr;
-
- ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
-
- channel_regs = dma_channel_regs(dev, channel);
- ccr = channel_regs->CCR;
- ccr &= ~DMA_CCR_PL;
- ccr |= priority;
- channel_regs->CCR = ccr;
-}
-
-/**
- * @brief Attach an interrupt to a DMA transfer.
- *
- * Interrupts are enabled using appropriate mode flags in
- * dma_setup_transfer().
- *
- * @param dev DMA device
- * @param channel Channel to attach handler to
- * @param handler Interrupt handler to call when channel interrupt fires.
- * @see dma_setup_transfer()
- * @see dma_get_irq_cause()
- * @see dma_detach_interrupt()
- */
-void dma_attach_interrupt(dma_dev *dev,
- dma_channel channel,
- void (*handler)(void)) {
- dev->handlers[channel - 1].handler = handler;
- nvic_irq_enable(dev->handlers[channel - 1].irq_line);
-}
-
-/**
- * @brief Detach a DMA transfer interrupt handler.
- *
- * After calling this function, the given channel's interrupts will be
- * disabled.
- *
- * @param dev DMA device
- * @param channel Channel whose handler to detach
- * @sideeffect Clears interrupt enable bits in the channel's CCR register.
- * @see dma_attach_interrupt()
- */
-void dma_detach_interrupt(dma_dev *dev, dma_channel channel) {
- /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */
- dma_channel_regs(dev, channel)->CCR &= ~0xF;
- dev->handlers[channel - 1].handler = NULL;
-}
-
-/**
- * @brief Discover the reason why a DMA interrupt was called.
- *
- * You may only call this function within an attached interrupt
- * handler for the given channel.
- *
- * This function resets the internal DMA register state which encodes
- * the cause of the interrupt; consequently, it can only be called
- * once per interrupt handler invocation.
- *
- * @param dev DMA device
- * @param channel Channel whose interrupt is being handled.
- * @return Reason why the interrupt fired.
- * @sideeffect Clears channel status flags in dev->regs->ISR.
- * @see dma_attach_interrupt()
- * @see dma_irq_cause
- */
-dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) {
- uint8 status_bits = dma_get_isr_bits(dev, channel);
-
- /* If the channel global interrupt flag is cleared, then
- * something's very wrong. */
- ASSERT(status_bits & BIT(0));
-
- dma_clear_isr_bits(dev, channel);
-
- /* ISR flags get set even if the corresponding interrupt enable
- * bits in the channel's configuration register are cleared, so we
- * can't use a switch here.
- *
- * Don't change the order of these if statements. */
- if (status_bits & BIT(3)) {
- return DMA_TRANSFER_ERROR;
- } else if (status_bits & BIT(1)) {
- return DMA_TRANSFER_COMPLETE;
- } else if (status_bits & BIT(2)) {
- return DMA_TRANSFER_HALF_COMPLETE;
- } else if (status_bits & BIT(0)) {
- /* Shouldn't happen (unless someone messed up an IFCR write). */
- throb();
- }
-#if DEBUG_LEVEL < DEBUG_ALL
- else {
- /* We shouldn't have been called, but the debug level is too
- * low for the above ASSERT() to have had any effect. In
- * order to fail fast, mimic the DMA controller's behavior
- * when an error occurs. */
- dma_disable(dev, channel);
- }
-#endif
- return DMA_TRANSFER_ERROR;
-}
-
-/**
- * @brief Enable a DMA channel.
- * @param dev DMA device
- * @param channel Channel to enable
- */
-void dma_enable(dma_dev *dev, dma_channel channel) {
- dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel);
- bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1);
-}
-
-/**
- * @brief Disable a DMA channel.
- * @param dev DMA device
- * @param channel Channel to disable
- */
-void dma_disable(dma_dev *dev, dma_channel channel) {
- dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel);
- bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0);
-}
-
-/**
- * @brief Set the base memory address where data will be read from or
- * written to.
- *
- * You must not call this function while the channel is enabled.
- *
- * If the DMA memory size is 16 bits, the address is automatically
- * aligned to a half-word. If the DMA memory size is 32 bits, the
- * address is aligned to a word.
- *
- * @param dev DMA Device
- * @param channel Channel whose base memory address to set.
- * @param addr Memory base address to use.
- */
-void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) {
- dma_channel_reg_map *chan_regs;
-
- ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
-
- chan_regs = dma_channel_regs(dev, channel);
- chan_regs->CMAR = (uint32)addr;
-}
-
-/**
- * @brief Set the base peripheral address where data will be read from
- * or written to.
- *
- * You must not call this function while the channel is enabled.
- *
- * If the DMA peripheral size is 16 bits, the address is automatically
- * aligned to a half-word. If the DMA peripheral size is 32 bits, the
- * address is aligned to a word.
- *
- * @param dev DMA Device
- * @param channel Channel whose peripheral data register base address to set.
- * @param addr Peripheral memory base address to use.
- */
-void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) {
- dma_channel_reg_map *chan_regs;
-
- ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
-
- chan_regs = dma_channel_regs(dev, channel);
- chan_regs->CPAR = (uint32)addr;
-}
-
/*
- * IRQ handlers
+ * Private API
*/
-static inline void dispatch_handler(dma_dev *dev, dma_channel channel) {
- void (*handler)(void) = dev->handlers[channel - 1].handler;
- if (handler) {
- handler();
- dma_clear_isr_bits(dev, channel); /* in case handler doesn't */
+enum dma_atype _dma_addr_type(__io void *addr) {
+ switch (stm32_block_purpose((void*)addr)) {
+ /* Notice we're treating the code block as memory here. That's
+ * correct for addresses in Flash and in [0x0, 0x7FFFFFF]
+ * (provided that those addresses are aliased to Flash, SRAM, or
+ * FSMC, depending on BOOT[01] and possibly SYSCFG_MEMRMP). It's
+ * not correct for other addresses in the code block, but those
+ * will (hopefully) just fail-fast with transfer or bus errors. If
+ * lots of people get confused, it might be worth being more
+ * careful here. */
+ case STM32_BLOCK_CODE: /* Fall through */
+ case STM32_BLOCK_SRAM: /* ... */
+ case STM32_BLOCK_FSMC_1_2: /* ... */
+ case STM32_BLOCK_FSMC_3_4:
+ return DMA_ATYPE_MEM;
+ case STM32_BLOCK_PERIPH:
+ return DMA_ATYPE_PER;
+ case STM32_BLOCK_FSMC_REG: /* Fall through */
+ /* Is this right? I can't think of a reason to DMA into or out
+ * of the FSMC registers. [mbolivar] */
+ case STM32_BLOCK_UNUSED: /* ... */
+ case STM32_BLOCK_CORTEX_INTERNAL: /* ... */
+ return DMA_ATYPE_OTHER;
+ default:
+ ASSERT(0); /* Can't happen */
+ return DMA_ATYPE_OTHER;
}
}
-
-void __irq_dma1_channel1(void) {
- dispatch_handler(DMA1, DMA_CH1);
-}
-
-void __irq_dma1_channel2(void) {
- dispatch_handler(DMA1, DMA_CH2);
-}
-
-void __irq_dma1_channel3(void) {
- dispatch_handler(DMA1, DMA_CH3);
-}
-
-void __irq_dma1_channel4(void) {
- dispatch_handler(DMA1, DMA_CH4);
-}
-
-void __irq_dma1_channel5(void) {
- dispatch_handler(DMA1, DMA_CH5);
-}
-
-void __irq_dma1_channel6(void) {
- dispatch_handler(DMA1, DMA_CH6);
-}
-
-void __irq_dma1_channel7(void) {
- dispatch_handler(DMA1, DMA_CH7);
-}
-
-#ifdef STM32_HIGH_DENSITY
-void __irq_dma2_channel1(void) {
- dispatch_handler(DMA2, DMA_CH1);
-}
-
-void __irq_dma2_channel2(void) {
- dispatch_handler(DMA2, DMA_CH2);
-}
-
-void __irq_dma2_channel3(void) {
- dispatch_handler(DMA2, DMA_CH3);
-}
-
-void __irq_dma2_channel4_5(void) {
- dispatch_handler(DMA2, DMA_CH4);
- dispatch_handler(DMA2, DMA_CH5);
-}
-#endif
diff --git a/libmaple/dma.h b/libmaple/dma.h
deleted file mode 100644
index 6e8087f..0000000
--- a/libmaple/dma.h
+++ /dev/null
@@ -1,453 +0,0 @@
-/******************************************************************************
- * The MIT License
- *
- * Copyright (c) 2010 Michael Hope.
- *
- * 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 dma.h
- *
- * @author Marti Bolivar <mbolivar@leaflabs.com>;
- * Original implementation by Michael Hope
- *
- * @brief Direct Memory Access peripheral support
- */
-
-/*
- * See /notes/dma.txt for more information.
- */
-
-#ifndef _DMA_H_
-#define _DMA_H_
-
-#include "libmaple_types.h"
-#include "rcc.h"
-#include "nvic.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-/*
- * Register maps
- */
-
-/**
- * @brief DMA register map type.
- *
- * Note that DMA controller 2 (register map base pointer DMA2_BASE)
- * only supports channels 1--5.
- */
-typedef struct dma_reg_map {
- __io uint32 ISR; /**< Interrupt status register */
- __io uint32 IFCR; /**< Interrupt flag clear register */
- __io uint32 CCR1; /**< Channel 1 configuration register */
- __io uint32 CNDTR1; /**< Channel 1 number of data register */
- __io uint32 CPAR1; /**< Channel 1 peripheral address register */
- __io uint32 CMAR1; /**< Channel 1 memory address register */
- const uint32 RESERVED1; /**< Reserved. */
- __io uint32 CCR2; /**< Channel 2 configuration register */
- __io uint32 CNDTR2; /**< Channel 2 number of data register */
- __io uint32 CPAR2; /**< Channel 2 peripheral address register */
- __io uint32 CMAR2; /**< Channel 2 memory address register */
- const uint32 RESERVED2; /**< Reserved. */
- __io uint32 CCR3; /**< Channel 3 configuration register */
- __io uint32 CNDTR3; /**< Channel 3 number of data register */
- __io uint32 CPAR3; /**< Channel 3 peripheral address register */
- __io uint32 CMAR3; /**< Channel 3 memory address register */
- const uint32 RESERVED3; /**< Reserved. */
- __io uint32 CCR4; /**< Channel 4 configuration register */
- __io uint32 CNDTR4; /**< Channel 4 number of data register */
- __io uint32 CPAR4; /**< Channel 4 peripheral address register */
- __io uint32 CMAR4; /**< Channel 4 memory address register */
- const uint32 RESERVED4; /**< Reserved. */
- __io uint32 CCR5; /**< Channel 5 configuration register */
- __io uint32 CNDTR5; /**< Channel 5 number of data register */
- __io uint32 CPAR5; /**< Channel 5 peripheral address register */
- __io uint32 CMAR5; /**< Channel 5 memory address register */
- const uint32 RESERVED5; /**< Reserved. */
- __io uint32 CCR6; /**< Channel 6 configuration register */
- __io uint32 CNDTR6; /**< Channel 6 number of data register */
- __io uint32 CPAR6; /**< Channel 6 peripheral address register */
- __io uint32 CMAR6; /**< Channel 6 memory address register */
- const uint32 RESERVED6; /**< Reserved. */
- __io uint32 CCR7; /**< Channel 7 configuration register */
- __io uint32 CNDTR7; /**< Channel 7 number of data register */
- __io uint32 CPAR7; /**< Channel 7 peripheral address register */
- __io uint32 CMAR7; /**< Channel 7 memory address register */
- const uint32 RESERVED7; /**< Reserved. */
-} dma_reg_map;
-
-/** DMA controller 1 register map base pointer */
-#define DMA1_BASE ((struct dma_reg_map*)0x40020000)
-
-#ifdef STM32_HIGH_DENSITY
-/** DMA controller 2 register map base pointer */
-#define DMA2_BASE ((struct dma_reg_map*)0x40020400)
-#endif
-
-/*
- * Register bit definitions
- */
-
-/* Interrupt status register */
-
-#define DMA_ISR_TEIF7_BIT 27
-#define DMA_ISR_HTIF7_BIT 26
-#define DMA_ISR_TCIF7_BIT 25
-#define DMA_ISR_GIF7_BIT 24
-#define DMA_ISR_TEIF6_BIT 23
-#define DMA_ISR_HTIF6_BIT 22
-#define DMA_ISR_TCIF6_BIT 21
-#define DMA_ISR_GIF6_BIT 20
-#define DMA_ISR_TEIF5_BIT 19
-#define DMA_ISR_HTIF5_BIT 18
-#define DMA_ISR_TCIF5_BIT 17
-#define DMA_ISR_GIF5_BIT 16
-#define DMA_ISR_TEIF4_BIT 15
-#define DMA_ISR_HTIF4_BIT 14
-#define DMA_ISR_TCIF4_BIT 13
-#define DMA_ISR_GIF4_BIT 12
-#define DMA_ISR_TEIF3_BIT 11
-#define DMA_ISR_HTIF3_BIT 10
-#define DMA_ISR_TCIF3_BIT 9
-#define DMA_ISR_GIF3_BIT 8
-#define DMA_ISR_TEIF2_BIT 7
-#define DMA_ISR_HTIF2_BIT 6
-#define DMA_ISR_TCIF2_BIT 5
-#define DMA_ISR_GIF2_BIT 4
-#define DMA_ISR_TEIF1_BIT 3
-#define DMA_ISR_HTIF1_BIT 2
-#define DMA_ISR_TCIF1_BIT 1
-#define DMA_ISR_GIF1_BIT 0
-
-#define DMA_ISR_TEIF7 BIT(DMA_ISR_TEIF7_BIT)
-#define DMA_ISR_HTIF7 BIT(DMA_ISR_HTIF7_BIT)
-#define DMA_ISR_TCIF7 BIT(DMA_ISR_TCIF7_BIT)
-#define DMA_ISR_GIF7 BIT(DMA_ISR_GIF7_BIT)
-#define DMA_ISR_TEIF6 BIT(DMA_ISR_TEIF6_BIT)
-#define DMA_ISR_HTIF6 BIT(DMA_ISR_HTIF6_BIT)
-#define DMA_ISR_TCIF6 BIT(DMA_ISR_TCIF6_BIT)
-#define DMA_ISR_GIF6 BIT(DMA_ISR_GIF6_BIT)
-#define DMA_ISR_TEIF5 BIT(DMA_ISR_TEIF5_BIT)
-#define DMA_ISR_HTIF5 BIT(DMA_ISR_HTIF5_BIT)
-#define DMA_ISR_TCIF5 BIT(DMA_ISR_TCIF5_BIT)
-#define DMA_ISR_GIF5 BIT(DMA_ISR_GIF5_BIT)
-#define DMA_ISR_TEIF4 BIT(DMA_ISR_TEIF4_BIT)
-#define DMA_ISR_HTIF4 BIT(DMA_ISR_HTIF4_BIT)
-#define DMA_ISR_TCIF4 BIT(DMA_ISR_TCIF4_BIT)
-#define DMA_ISR_GIF4 BIT(DMA_ISR_GIF4_BIT)
-#define DMA_ISR_TEIF3 BIT(DMA_ISR_TEIF3_BIT)
-#define DMA_ISR_HTIF3 BIT(DMA_ISR_HTIF3_BIT)
-#define DMA_ISR_TCIF3 BIT(DMA_ISR_TCIF3_BIT)
-#define DMA_ISR_GIF3 BIT(DMA_ISR_GIF3_BIT)
-#define DMA_ISR_TEIF2 BIT(DMA_ISR_TEIF2_BIT)
-#define DMA_ISR_HTIF2 BIT(DMA_ISR_HTIF2_BIT)
-#define DMA_ISR_TCIF2 BIT(DMA_ISR_TCIF2_BIT)
-#define DMA_ISR_GIF2 BIT(DMA_ISR_GIF2_BIT)
-#define DMA_ISR_TEIF1 BIT(DMA_ISR_TEIF1_BIT)
-#define DMA_ISR_HTIF1 BIT(DMA_ISR_HTIF1_BIT)
-#define DMA_ISR_TCIF1 BIT(DMA_ISR_TCIF1_BIT)
-#define DMA_ISR_GIF1 BIT(DMA_ISR_GIF1_BIT)
-
-/* Interrupt flag clear register */
-
-#define DMA_IFCR_CTEIF7_BIT 27
-#define DMA_IFCR_CHTIF7_BIT 26
-#define DMA_IFCR_CTCIF7_BIT 25
-#define DMA_IFCR_CGIF7_BIT 24
-#define DMA_IFCR_CTEIF6_BIT 23
-#define DMA_IFCR_CHTIF6_BIT 22
-#define DMA_IFCR_CTCIF6_BIT 21
-#define DMA_IFCR_CGIF6_BIT 20
-#define DMA_IFCR_CTEIF5_BIT 19
-#define DMA_IFCR_CHTIF5_BIT 18
-#define DMA_IFCR_CTCIF5_BIT 17
-#define DMA_IFCR_CGIF5_BIT 16
-#define DMA_IFCR_CTEIF4_BIT 15
-#define DMA_IFCR_CHTIF4_BIT 14
-#define DMA_IFCR_CTCIF4_BIT 13
-#define DMA_IFCR_CGIF4_BIT 12
-#define DMA_IFCR_CTEIF3_BIT 11
-#define DMA_IFCR_CHTIF3_BIT 10
-#define DMA_IFCR_CTCIF3_BIT 9
-#define DMA_IFCR_CGIF3_BIT 8
-#define DMA_IFCR_CTEIF2_BIT 7
-#define DMA_IFCR_CHTIF2_BIT 6
-#define DMA_IFCR_CTCIF2_BIT 5
-#define DMA_IFCR_CGIF2_BIT 4
-#define DMA_IFCR_CTEIF1_BIT 3
-#define DMA_IFCR_CHTIF1_BIT 2
-#define DMA_IFCR_CTCIF1_BIT 1
-#define DMA_IFCR_CGIF1_BIT 0
-
-#define DMA_IFCR_CTEIF7 BIT(DMA_IFCR_CTEIF7_BIT)
-#define DMA_IFCR_CHTIF7 BIT(DMA_IFCR_CHTIF7_BIT)
-#define DMA_IFCR_CTCIF7 BIT(DMA_IFCR_CTCIF7_BIT)
-#define DMA_IFCR_CGIF7 BIT(DMA_IFCR_CGIF7_BIT)
-#define DMA_IFCR_CTEIF6 BIT(DMA_IFCR_CTEIF6_BIT)
-#define DMA_IFCR_CHTIF6 BIT(DMA_IFCR_CHTIF6_BIT)
-#define DMA_IFCR_CTCIF6 BIT(DMA_IFCR_CTCIF6_BIT)
-#define DMA_IFCR_CGIF6 BIT(DMA_IFCR_CGIF6_BIT)
-#define DMA_IFCR_CTEIF5 BIT(DMA_IFCR_CTEIF5_BIT)
-#define DMA_IFCR_CHTIF5 BIT(DMA_IFCR_CHTIF5_BIT)
-#define DMA_IFCR_CTCIF5 BIT(DMA_IFCR_CTCIF5_BIT)
-#define DMA_IFCR_CGIF5 BIT(DMA_IFCR_CGIF5_BIT)
-#define DMA_IFCR_CTEIF4 BIT(DMA_IFCR_CTEIF4_BIT)
-#define DMA_IFCR_CHTIF4 BIT(DMA_IFCR_CHTIF4_BIT)
-#define DMA_IFCR_CTCIF4 BIT(DMA_IFCR_CTCIF4_BIT)
-#define DMA_IFCR_CGIF4 BIT(DMA_IFCR_CGIF4_BIT)
-#define DMA_IFCR_CTEIF3 BIT(DMA_IFCR_CTEIF3_BIT)
-#define DMA_IFCR_CHTIF3 BIT(DMA_IFCR_CHTIF3_BIT)
-#define DMA_IFCR_CTCIF3 BIT(DMA_IFCR_CTCIF3_BIT)
-#define DMA_IFCR_CGIF3 BIT(DMA_IFCR_CGIF3_BIT)
-#define DMA_IFCR_CTEIF2 BIT(DMA_IFCR_CTEIF2_BIT)
-#define DMA_IFCR_CHTIF2 BIT(DMA_IFCR_CHTIF2_BIT)
-#define DMA_IFCR_CTCIF2 BIT(DMA_IFCR_CTCIF2_BIT)
-#define DMA_IFCR_CGIF2 BIT(DMA_IFCR_CGIF2_BIT)
-#define DMA_IFCR_CTEIF1 BIT(DMA_IFCR_CTEIF1_BIT)
-#define DMA_IFCR_CHTIF1 BIT(DMA_IFCR_CHTIF1_BIT)
-#define DMA_IFCR_CTCIF1 BIT(DMA_IFCR_CTCIF1_BIT)
-#define DMA_IFCR_CGIF1 BIT(DMA_IFCR_CGIF1_BIT)
-
-/* Channel configuration register */
-
-#define DMA_CCR_MEM2MEM_BIT 14
-#define DMA_CCR_MINC_BIT 7
-#define DMA_CCR_PINC_BIT 6
-#define DMA_CCR_CIRC_BIT 5
-#define DMA_CCR_DIR_BIT 4
-#define DMA_CCR_TEIE_BIT 3
-#define DMA_CCR_HTIE_BIT 2
-#define DMA_CCR_TCIE_BIT 1
-#define DMA_CCR_EN_BIT 0
-
-#define DMA_CCR_MEM2MEM BIT(DMA_CCR_MEM2MEM_BIT)
-#define DMA_CCR_PL (0x3 << 12)
-#define DMA_CCR_PL_LOW (0x0 << 12)
-#define DMA_CCR_PL_MEDIUM (0x1 << 12)
-#define DMA_CCR_PL_HIGH (0x2 << 12)
-#define DMA_CCR_PL_VERY_HIGH (0x3 << 12)
-#define DMA_CCR_MSIZE (0x3 << 10)
-#define DMA_CCR_MSIZE_8BITS (0x0 << 10)
-#define DMA_CCR_MSIZE_16BITS (0x1 << 10)
-#define DMA_CCR_MSIZE_32BITS (0x2 << 10)
-#define DMA_CCR_PSIZE (0x3 << 8)
-#define DMA_CCR_PSIZE_8BITS (0x0 << 8)
-#define DMA_CCR_PSIZE_16BITS (0x1 << 8)
-#define DMA_CCR_PSIZE_32BITS (0x2 << 8)
-#define DMA_CCR_MINC BIT(DMA_CCR_MINC_BIT)
-#define DMA_CCR_PINC BIT(DMA_CCR_PINC_BIT)
-#define DMA_CCR_CIRC BIT(DMA_CCR_CIRC_BIT)
-#define DMA_CCR_DIR BIT(DMA_CCR_DIR_BIT)
-#define DMA_CCR_TEIE BIT(DMA_CCR_TEIE_BIT)
-#define DMA_CCR_HTIE BIT(DMA_CCR_HTIE_BIT)
-#define DMA_CCR_TCIE BIT(DMA_CCR_TCIE_BIT)
-#define DMA_CCR_EN BIT(DMA_CCR_EN_BIT)
-
-/*
- * Devices
- */
-
-/** Encapsulates state related to a DMA channel interrupt. */
-typedef struct dma_handler_config {
- void (*handler)(void); /**< User-specified channel interrupt
- handler */
- nvic_irq_num irq_line; /**< Channel's NVIC interrupt number */
-} dma_handler_config;
-
-/** DMA device type */
-typedef struct dma_dev {
- dma_reg_map *regs; /**< Register map */
- rcc_clk_id clk_id; /**< Clock ID */
- dma_handler_config handlers[]; /**<
- * @brief IRQ handlers and NVIC numbers.
- *
- * @see dma_attach_interrupt()
- * @see dma_detach_interrupt()
- */
-} dma_dev;
-
-extern dma_dev *DMA1;
-#ifdef STM32_HIGH_DENSITY
-extern dma_dev *DMA2;
-#endif
-
-/*
- * Convenience functions
- */
-
-void dma_init(dma_dev *dev);
-
-/** Flags for DMA transfer configuration. */
-typedef enum dma_mode_flags {
- DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */
- DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */
- DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */
- DMA_CIRC_MODE = 1 << 5, /**< Circular mode */
- DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */
- DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */
- DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */
- DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */
-} dma_mode_flags;
-
-/** Source and destination transfer sizes. */
-typedef enum dma_xfer_size {
- DMA_SIZE_8BITS = 0, /**< 8-bit transfers */
- DMA_SIZE_16BITS = 1, /**< 16-bit transfers */
- DMA_SIZE_32BITS = 2 /**< 32-bit transfers */
-} dma_xfer_size;
-
-/** DMA channel */
-typedef enum dma_channel {
- DMA_CH1 = 1, /**< Channel 1 */
- DMA_CH2 = 2, /**< Channel 2 */
- DMA_CH3 = 3, /**< Channel 3 */
- DMA_CH4 = 4, /**< Channel 4 */
- DMA_CH5 = 5, /**< Channel 5 */
- DMA_CH6 = 6, /**< Channel 6 */
- DMA_CH7 = 7, /**< Channel 7 */
-} dma_channel;
-
-void dma_setup_transfer(dma_dev *dev,
- dma_channel channel,
- __io void *peripheral_address,
- dma_xfer_size peripheral_size,
- __io void *memory_address,
- dma_xfer_size memory_size,
- uint32 mode);
-
-void dma_set_num_transfers(dma_dev *dev,
- dma_channel channel,
- uint16 num_transfers);
-
-/** DMA transfer priority. */
-typedef enum dma_priority {
- DMA_PRIORITY_LOW = DMA_CCR_PL_LOW, /**< Low priority */
- DMA_PRIORITY_MEDIUM = DMA_CCR_PL_MEDIUM, /**< Medium priority */
- DMA_PRIORITY_HIGH = DMA_CCR_PL_HIGH, /**< High priority */
- DMA_PRIORITY_VERY_HIGH = DMA_CCR_PL_VERY_HIGH /**< Very high priority */
-} dma_priority;
-
-void dma_set_priority(dma_dev *dev,
- dma_channel channel,
- dma_priority priority);
-
-void dma_attach_interrupt(dma_dev *dev,
- dma_channel channel,
- void (*handler)(void));
-void dma_detach_interrupt(dma_dev *dev, dma_channel channel);
-
-/**
- * Encodes the reason why a DMA interrupt was called.
- * @see dma_get_irq_cause()
- */
-typedef enum dma_irq_cause {
- DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */
- DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */
- DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */
-} dma_irq_cause;
-
-dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel);
-
-void dma_enable(dma_dev *dev, dma_channel channel);
-void dma_disable(dma_dev *dev, dma_channel channel);
-
-void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *address);
-void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *address);
-
-/**
- * @brief DMA channel register map type.
- *
- * Provides access to an individual channel's registers.
- */
-typedef struct dma_channel_reg_map {
- __io uint32 CCR; /**< Channel configuration register */
- __io uint32 CNDTR; /**< Channel number of data register */
- __io uint32 CPAR; /**< Channel peripheral address register */
- __io uint32 CMAR; /**< Channel memory address register */
-} dma_channel_reg_map;
-
-#define DMA_CHANNEL_NREGS 5
-
-/**
- * @brief Obtain a pointer to an individual DMA channel's registers.
- *
- * For example, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1.
- *
- * @param dev DMA device
- * @param channel DMA channel whose channel register map to obtain.
- */
-static inline dma_channel_reg_map* dma_channel_regs(dma_dev *dev,
- dma_channel channel) {
- __io uint32 *ccr1 = &dev->regs->CCR1;
- return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (channel - 1));
-}
-
-/**
- * @brief Check if a DMA channel is enabled
- * @param dev DMA device
- * @param channel Channel whose enabled bit to check.
- */
-static inline uint8 dma_is_channel_enabled(dma_dev *dev, dma_channel channel) {
- return (uint8)(dma_channel_regs(dev, channel)->CCR & DMA_CCR_EN);
-}
-
-/**
- * @brief Get the ISR status bits for a DMA channel.
- *
- * The bits are returned right-aligned, in the following order:
- * transfer error flag, half-transfer flag, transfer complete flag,
- * global interrupt flag.
- *
- * If you're attempting to figure out why a DMA interrupt fired; you
- * may find dma_get_irq_cause() more convenient.
- *
- * @param dev DMA device
- * @param channel Channel whose ISR bits to return.
- * @see dma_get_irq_cause().
- */
-static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_channel channel) {
- uint8 shift = (channel - 1) * 4;
- return (dev->regs->ISR >> shift) & 0xF;
-}
-
-/**
- * @brief Clear the ISR status bits for a given DMA channel.
- *
- * If you're attempting to clean up after yourself in a DMA interrupt,
- * you may find dma_get_irq_cause() more convenient.
- *
- * @param dev DMA device
- * @param channel Channel whose ISR bits to clear.
- * @see dma_get_irq_cause()
- */
-static inline void dma_clear_isr_bits(dma_dev *dev, dma_channel channel) {
- dev->regs->IFCR = BIT(4 * (channel - 1));
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif
diff --git a/libmaple/dma_private.h b/libmaple/dma_private.h
new file mode 100644
index 0000000..b25ded2
--- /dev/null
+++ b/libmaple/dma_private.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * 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.
+*****************************************************************************/
+
+#ifndef _LIBMAPLE_DMA_PRIVATE_H_
+#define _LIBMAPLE_DMA_PRIVATE_H_
+
+#include <libmaple/dma.h>
+#include <libmaple/libmaple_types.h>
+
+/*
+ * IRQ handling
+ */
+
+/* Wrap this in an ifdef to shut up GCC. (We provide DMA_GET_HANDLER
+ * in the series support files, which need dma_irq_handler().) */
+#ifdef DMA_GET_HANDLER
+static __always_inline void dma_irq_handler(dma_dev *dev, dma_tube tube) {
+ void (*handler)(void) = DMA_GET_HANDLER(dev, tube);
+ if (handler) {
+ handler();
+ dma_clear_isr_bits(dev, tube); /* in case handler doesn't */
+ }
+}
+#endif
+
+/*
+ * Conveniences for dealing with tube sources/destinations
+ */
+
+enum dma_atype {
+ DMA_ATYPE_MEM,
+ DMA_ATYPE_PER,
+ DMA_ATYPE_OTHER,
+};
+
+enum dma_atype _dma_addr_type(__io void *addr);
+
+#endif
diff --git a/libmaple/exti.c b/libmaple/exti.c
index 1fcc35b..9023782 100644
--- a/libmaple/exti.c
+++ b/libmaple/exti.c
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,14 +26,14 @@
*****************************************************************************/
/**
- * @file exti.c
+ * @file libmaple/exti.c
* @brief External interrupt control routines
*/
-#include "exti.h"
-#include "libmaple.h"
-#include "nvic.h"
-#include "bitband.h"
+#include <libmaple/exti.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/nvic.h>
+#include <libmaple/bitband.h>
static inline void dispatch_single_exti(uint32 exti_num);
static inline void dispatch_extis(uint32 start, uint32 stop);
@@ -66,7 +67,7 @@ static exti_channel exti_channels[] = {
};
/*
- * Convenience routines
+ * Portable routines
*/
/**
@@ -80,13 +81,13 @@ static exti_channel exti_channels[] = {
* @param handler Function handler to execute when interrupt is triggered.
* @param mode Type of transition to trigger on, one of:
* EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING.
- * @see afio_exti_num
- * @see afio_exti_port
+ * @see exti_num
+ * @see exti_cfg
* @see voidFuncPtr
* @see exti_trigger_mode
*/
-void exti_attach_interrupt(afio_exti_num num,
- afio_exti_port port,
+void exti_attach_interrupt(exti_num num,
+ exti_cfg port,
voidFuncPtr handler,
exti_trigger_mode mode) {
ASSERT(handler);
@@ -108,8 +109,8 @@ void exti_attach_interrupt(afio_exti_num num,
break;
}
- /* Map num to port */
- afio_exti_select(num, port);
+ /* Use the chip-specific exti_select() to map num to port */
+ exti_select(num, port);
/* Unmask external interrupt request */
bb_peri_set_bit(&EXTI_BASE->IMR, num, 1);
@@ -120,10 +121,10 @@ void exti_attach_interrupt(afio_exti_num num,
/**
* @brief Unregister an external interrupt handler
- * @param num Number of the external interrupt line to disable.
- * @see afio_exti_num
+ * @param num External interrupt line to disable.
+ * @see exti_num
*/
-void exti_detach_interrupt(afio_exti_num num) {
+void exti_detach_interrupt(exti_num num) {
/* First, mask the interrupt request */
bb_peri_set_bit(&EXTI_BASE->IMR, num, 0);
@@ -136,27 +137,39 @@ void exti_detach_interrupt(afio_exti_num num) {
}
/*
+ * Private routines
+ */
+
+void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port) {
+ uint32 shift = 4 * (num % 4);
+ uint32 cr = *exti_cr;
+ cr &= ~(0xF << shift);
+ cr |= port << shift;
+ *exti_cr = cr;
+}
+
+/*
* Interrupt handlers
*/
void __irq_exti0(void) {
- dispatch_single_exti(AFIO_EXTI_0);
+ dispatch_single_exti(EXTI0);
}
void __irq_exti1(void) {
- dispatch_single_exti(AFIO_EXTI_1);
+ dispatch_single_exti(EXTI1);
}
void __irq_exti2(void) {
- dispatch_single_exti(AFIO_EXTI_2);
+ dispatch_single_exti(EXTI2);
}
void __irq_exti3(void) {
- dispatch_single_exti(AFIO_EXTI_3);
+ dispatch_single_exti(EXTI3);
}
void __irq_exti4(void) {
- dispatch_single_exti(AFIO_EXTI_4);
+ dispatch_single_exti(EXTI4);
}
void __irq_exti9_5(void) {
@@ -177,7 +190,7 @@ void __irq_exti15_10(void) {
* won't actually be cleared in time and the ISR will fire again. To
* compensate, this function NOPs for 2 cycles after clearing the
* pending bits to ensure it takes effect. */
-static inline void clear_pending_msk(uint32 exti_msk) {
+static __always_inline void clear_pending_msk(uint32 exti_msk) {
EXTI_BASE->PR = exti_msk;
asm volatile("nop");
asm volatile("nop");
@@ -185,7 +198,7 @@ static inline void clear_pending_msk(uint32 exti_msk) {
/* This dispatch routine is for non-multiplexed EXTI lines only; i.e.,
* it doesn't check EXTI_PR. */
-static inline void dispatch_single_exti(uint32 exti) {
+static __always_inline void dispatch_single_exti(uint32 exti) {
voidFuncPtr handler = exti_channels[exti].handler;
if (!handler) {
@@ -193,18 +206,18 @@ static inline void dispatch_single_exti(uint32 exti) {
}
handler();
- clear_pending_msk(BIT(exti));
+ clear_pending_msk(1U << exti);
}
/* Dispatch routine for EXTIs which share an IRQ. */
-static inline void dispatch_extis(uint32 start, uint32 stop) {
+static __always_inline void dispatch_extis(uint32 start, uint32 stop) {
uint32 pr = EXTI_BASE->PR;
uint32 handled_msk = 0;
uint32 exti;
/* Dispatch user handlers for pending EXTIs. */
for (exti = start; exti <= stop; exti++) {
- uint32 eb = BIT(exti);
+ uint32 eb = (1U << exti);
if (pr & eb) {
voidFuncPtr handler = exti_channels[exti].handler;
if (handler) {
diff --git a/libmaple/exti_private.h b/libmaple/exti_private.h
new file mode 100644
index 0000000..4f0a4cf
--- /dev/null
+++ b/libmaple/exti_private.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * 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.
+*****************************************************************************/
+
+#ifndef _LIBMAPLE_EXTI_PRIVATE_H_
+#define _LIBMAPLE_EXTI_PRIVATE_H_
+
+#include <libmaple/exti.h>
+
+void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port);
+
+#endif
diff --git a/libmaple/flash.c b/libmaple/flash.c
index a22fbd3..0cdff59 100644
--- a/libmaple/flash.c
+++ b/libmaple/flash.c
@@ -25,30 +25,24 @@
*****************************************************************************/
/**
- * @file flash.c
+ * @file libmaple/flash.c
* @brief Flash management functions
*/
-#include "libmaple.h"
-#include "flash.h"
-#include "bitband.h"
-
-/**
- * @brief Turn on the hardware prefetcher.
- */
-void flash_enable_prefetch(void) {
- *bb_perip(&FLASH_BASE->ACR, FLASH_ACR_PRFTBE_BIT) = 1;
-}
+#include <libmaple/libmaple_types.h>
+#include <libmaple/flash.h>
/**
* @brief Set flash wait states
*
- * See ST PM0042, section 3.1 for restrictions on the acceptable value
- * of wait_states for a given SYSCLK configuration.
+ * Note that not all wait states are available on every MCU. See the
+ * Flash programming manual for your MCU for restrictions on the
+ * allowed value of wait_states for a given system clock (SYSCLK)
+ * frequency.
*
* @param wait_states number of wait states (one of
* FLASH_WAIT_STATE_0, FLASH_WAIT_STATE_1,
- * FLASH_WAIT_STATE_2).
+ * ..., FLASH_WAIT_STATE_7).
*/
void flash_set_latency(uint32 wait_states) {
uint32 val = FLASH_BASE->ACR;
diff --git a/libmaple/gpio.c b/libmaple/gpio.c
index e643873..898007a 100644
--- a/libmaple/gpio.c
+++ b/libmaple/gpio.c
@@ -25,77 +25,15 @@
*****************************************************************************/
/**
- * @file gpio.c
- * @brief GPIO initialization routine
+ * @file libmaple/gpio.c
+ * @brief Generic STM32 GPIO support.
*/
-#include "gpio.h"
-#include "rcc.h"
+#include <libmaple/gpio.h>
+#include <libmaple/rcc.h>
/*
- * GPIO devices
- */
-
-gpio_dev gpioa = {
- .regs = GPIOA_BASE,
- .clk_id = RCC_GPIOA,
- .exti_port = AFIO_EXTI_PA,
-};
-/** GPIO port A device. */
-gpio_dev* const GPIOA = &gpioa;
-
-gpio_dev gpiob = {
- .regs = GPIOB_BASE,
- .clk_id = RCC_GPIOB,
- .exti_port = AFIO_EXTI_PB,
-};
-/** GPIO port B device. */
-gpio_dev* const GPIOB = &gpiob;
-
-gpio_dev gpioc = {
- .regs = GPIOC_BASE,
- .clk_id = RCC_GPIOC,
- .exti_port = AFIO_EXTI_PC,
-};
-/** GPIO port C device. */
-gpio_dev* const GPIOC = &gpioc;
-
-gpio_dev gpiod = {
- .regs = GPIOD_BASE,
- .clk_id = RCC_GPIOD,
- .exti_port = AFIO_EXTI_PD,
-};
-/** GPIO port D device. */
-gpio_dev* const GPIOD = &gpiod;
-
-#ifdef STM32_HIGH_DENSITY
-gpio_dev gpioe = {
- .regs = GPIOE_BASE,
- .clk_id = RCC_GPIOE,
- .exti_port = AFIO_EXTI_PE,
-};
-/** GPIO port E device. */
-gpio_dev* const GPIOE = &gpioe;
-
-gpio_dev gpiof = {
- .regs = GPIOF_BASE,
- .clk_id = RCC_GPIOF,
- .exti_port = AFIO_EXTI_PF,
-};
-/** GPIO port F device. */
-gpio_dev* const GPIOF = &gpiof;
-
-gpio_dev gpiog = {
- .regs = GPIOG_BASE,
- .clk_id = RCC_GPIOG,
- .exti_port = AFIO_EXTI_PG,
-};
-/** GPIO port G device. */
-gpio_dev* const GPIOG = &gpiog;
-#endif
-
-/*
- * GPIO convenience routines
+ * GPIO routines
*/
/**
@@ -109,88 +47,3 @@ void gpio_init(gpio_dev *dev) {
rcc_clk_enable(dev->clk_id);
rcc_reset_dev(dev->clk_id);
}
-
-/**
- * Initialize and reset all available GPIO devices.
- */
-void gpio_init_all(void) {
- gpio_init(GPIOA);
- gpio_init(GPIOB);
- gpio_init(GPIOC);
- gpio_init(GPIOD);
-#ifdef STM32_HIGH_DENSITY
- gpio_init(GPIOE);
- gpio_init(GPIOF);
- gpio_init(GPIOG);
-#endif
-}
-
-/**
- * Set the mode of a GPIO pin.
- *
- * @param dev GPIO device.
- * @param pin Pin on the device whose mode to set, 0--15.
- * @param mode General purpose or alternate function mode to set the pin to.
- * @see gpio_pin_mode
- */
-void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) {
- gpio_reg_map *regs = dev->regs;
- __io uint32 *cr = &regs->CRL + (pin >> 3);
- uint32 shift = (pin & 0x7) * 4;
- uint32 tmp = *cr;
-
- tmp &= ~(0xF << shift);
- tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift;
- *cr = tmp;
-
- if (mode == GPIO_INPUT_PD) {
- regs->ODR &= ~BIT(pin);
- } else if (mode == GPIO_INPUT_PU) {
- regs->ODR |= BIT(pin);
- }
-}
-
-/*
- * AFIO
- */
-
-/**
- * @brief Initialize the AFIO clock, and reset the AFIO registers.
- */
-void afio_init(void) {
- rcc_clk_enable(RCC_AFIO);
- rcc_reset_dev(RCC_AFIO);
-}
-
-#define AFIO_EXTI_SEL_MASK 0xF
-
-/**
- * @brief Select a source input for an external interrupt.
- *
- * @param exti External interrupt.
- * @param gpio_port Port which contains pin to use as source input.
- * @see afio_exti_num
- * @see afio_exti_port
- */
-void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) {
- __io uint32 *exti_cr = &AFIO_BASE->EXTICR1 + exti / 4;
- uint32 shift = 4 * (exti % 4);
- uint32 cr = *exti_cr;
-
- cr &= ~(AFIO_EXTI_SEL_MASK << shift);
- cr |= gpio_port << shift;
- *exti_cr = cr;
-}
-
-/**
- * @brief Perform an alternate function remap.
- * @param remapping Remapping to perform.
- */
-void afio_remap(afio_remap_peripheral remapping) {
- if (remapping & AFIO_REMAP_USE_MAPR2) {
- remapping &= ~AFIO_REMAP_USE_MAPR2;
- AFIO_BASE->MAPR2 |= remapping;
- } else {
- AFIO_BASE->MAPR |= remapping;
- }
-}
diff --git a/libmaple/i2c.c b/libmaple/i2c.c
index e3f3199..9c93d3f 100644
--- a/libmaple/i2c.c
+++ b/libmaple/i2c.c
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2012 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,49 +26,28 @@
*****************************************************************************/
/**
- * @file i2c.c
+ * @file libmaple/i2c.c
+ * @author Perry Hung <perry@leaflabs.com>
* @brief Inter-Integrated Circuit (I2C) support.
*
* Currently, only master mode is supported.
*/
-#include "libmaple.h"
-#include "rcc.h"
-#include "gpio.h"
-#include "nvic.h"
-#include "i2c.h"
-#include "string.h"
-#include "systick.h"
-
-static i2c_dev i2c_dev1 = {
- .regs = I2C1_BASE,
- .gpio_port = &gpiob,
- .sda_pin = 7,
- .scl_pin = 6,
- .clk_id = RCC_I2C1,
- .ev_nvic_line = NVIC_I2C1_EV,
- .er_nvic_line = NVIC_I2C1_ER,
- .state = I2C_STATE_DISABLED
-};
-/** I2C1 device */
-i2c_dev* const I2C1 = &i2c_dev1;
-
-static i2c_dev i2c_dev2 = {
- .regs = I2C2_BASE,
- .gpio_port = &gpiob,
- .sda_pin = 11,
- .scl_pin = 10,
- .clk_id = RCC_I2C2,
- .ev_nvic_line = NVIC_I2C2_EV,
- .er_nvic_line = NVIC_I2C2_ER,
- .state = I2C_STATE_DISABLED
-};
-/** I2C2 device */
-i2c_dev* const I2C2 = &i2c_dev2;
+#include "i2c_private.h"
+
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
+#include <libmaple/gpio.h>
+#include <libmaple/nvic.h>
+#include <libmaple/i2c.h>
+#include <libmaple/systick.h>
+
+#include <string.h>
static inline int32 wait_for_state_change(i2c_dev *dev,
i2c_state state,
uint32 timeout);
+static void set_ccr_trise(i2c_dev *dev, uint32 flags);
/**
* @brief Fill data register with slave address
@@ -125,10 +105,191 @@ enum {
};
/**
- * @brief IRQ handler for I2C master. Handles transmission/reception.
+ * @brief Reset an I2C bus.
+ *
+ * Reset is accomplished by clocking out pulses until any hung slaves
+ * release SDA and SCL, then generating a START condition, then a STOP
+ * condition.
+ *
+ * @param dev I2C device
+ */
+void i2c_bus_reset(const i2c_dev *dev) {
+ /* Release both lines */
+ i2c_master_release_bus(dev);
+
+ /*
+ * Make sure the bus is free by clocking it until any slaves release the
+ * bus.
+ */
+ while (!gpio_read_bit(sda_port(dev), dev->sda_pin)) {
+ /* Wait for any clock stretching to finish */
+ while (!gpio_read_bit(scl_port(dev), dev->scl_pin))
+ ;
+ delay_us(10);
+
+ /* Pull low */
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 0);
+ delay_us(10);
+
+ /* Release high again */
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
+ delay_us(10);
+ }
+
+ /* Generate start then stop condition */
+ gpio_write_bit(sda_port(dev), dev->sda_pin, 0);
+ delay_us(10);
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 0);
+ delay_us(10);
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
+ delay_us(10);
+ gpio_write_bit(sda_port(dev), dev->sda_pin, 1);
+}
+
+/**
+ * @brief Initialize an I2C device and reset its registers to their
+ * default values.
+ * @param dev Device to initialize.
+ */
+void i2c_init(i2c_dev *dev) {
+ rcc_reset_dev(dev->clk_id);
+ rcc_clk_enable(dev->clk_id);
+}
+
+/* Hack for deprecated bit of STM32F1 functionality */
+#ifndef _I2C_HAVE_DEPRECATED_I2C_REMAP
+#define _i2c_handle_remap(dev, flags) ((void)0)
+#endif
+
+/**
+ * @brief Initialize an I2C device as bus master
+ * @param dev Device to enable
+ * @param flags Bitwise or of the following I2C options:
+ * I2C_FAST_MODE: 400 khz operation,
+ * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for
+ * fast mode),
+ * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on
+ * initialization,
+ * I2C_10BIT_ADDRESSING: Enable 10-bit addressing,
+ * I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8
+ * SDA/PB9.
+ */
+void i2c_master_enable(i2c_dev *dev, uint32 flags) {
+ /* PE must be disabled to configure the device */
+ ASSERT(!(dev->regs->CR1 & I2C_CR1_PE));
+
+ /* Ugh */
+ _i2c_handle_remap(dev, flags);
+
+ /* Reset the bus. Clock out any hung slaves. */
+ if (flags & I2C_BUS_RESET) {
+ i2c_bus_reset(dev);
+ }
+
+ /* Turn on clock and set GPIO modes */
+ i2c_init(dev);
+ i2c_config_gpios(dev);
+
+ /* Configure clock and rise time */
+ set_ccr_trise(dev, flags);
+
+ /* Enable event and buffer interrupts */
+ nvic_irq_enable(dev->ev_nvic_line);
+ nvic_irq_enable(dev->er_nvic_line);
+ i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR);
+
+ /* Make it go! */
+ i2c_peripheral_enable(dev);
+
+ dev->state = I2C_STATE_IDLE;
+}
+
+/**
+ * @brief Process an i2c transaction.
+ *
+ * Transactions are composed of one or more i2c_msg's, and may be read
+ * or write tranfers. Multiple i2c_msg's will generate a repeated
+ * start in between messages.
+ *
* @param dev I2C device
+ * @param msgs Messages to send/receive
+ * @param num Number of messages to send/receive
+ * @param timeout Bus idle timeout in milliseconds before aborting the
+ * transfer. 0 denotes no timeout.
+ * @return 0 on success,
+ * I2C_ERROR_PROTOCOL if there was a protocol error,
+ * I2C_ERROR_TIMEOUT if the transfer timed out.
*/
-static void i2c_irq_handler(i2c_dev *dev) {
+int32 i2c_master_xfer(i2c_dev *dev,
+ i2c_msg *msgs,
+ uint16 num,
+ uint32 timeout) {
+ int32 rc;
+
+ ASSERT(dev->state == I2C_STATE_IDLE);
+
+ dev->msg = msgs;
+ dev->msgs_left = num;
+ dev->timestamp = systick_uptime();
+ dev->state = I2C_STATE_BUSY;
+
+ i2c_enable_irq(dev, I2C_IRQ_EVENT);
+ i2c_start_condition(dev);
+
+ rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE, timeout);
+ if (rc < 0) {
+ goto out;
+ }
+
+ dev->state = I2C_STATE_IDLE;
+out:
+ return rc;
+}
+
+/**
+ * @brief Wait for an I2C event, or time out in case of error.
+ * @param dev I2C device
+ * @param state I2C_state state to wait for
+ * @param timeout Timeout, in milliseconds
+ * @return 0 if target state is reached, a negative value on error.
+ */
+static inline int32 wait_for_state_change(i2c_dev *dev,
+ i2c_state state,
+ uint32 timeout) {
+ i2c_state tmp;
+
+ while (1) {
+ tmp = dev->state;
+
+ if (tmp == I2C_STATE_ERROR) {
+ return I2C_STATE_ERROR;
+ }
+
+ if (tmp == state) {
+ return 0;
+ }
+
+ if (timeout) {
+ if (systick_uptime() > (dev->timestamp + timeout)) {
+ /* TODO: overflow? */
+ /* TODO: racy? */
+ return I2C_ERROR_TIMEOUT;
+ }
+ }
+ }
+}
+
+/*
+ * Private API
+ */
+
+/*
+ * IRQ handler for I2C master. Handles transmission/reception.
+ */
+void _i2c_irq_handler(i2c_dev *dev) {
+ /* WTFs:
+ * - Where is I2C_MSG_10BIT_ADDR handled?
+ */
i2c_msg *msg = dev->msg;
uint8 read = msg->flags & I2C_MSG_READ;
@@ -214,7 +375,7 @@ static void i2c_irq_handler(i2c_dev *dev) {
/*
* This should be impossible...
*/
- throb();
+ ASSERT(0);
}
sr1 = sr2 = 0;
}
@@ -288,20 +449,11 @@ static void i2c_irq_handler(i2c_dev *dev) {
}
}
-void __irq_i2c1_ev(void) {
- i2c_irq_handler(&i2c_dev1);
-}
-
-void __irq_i2c2_ev(void) {
- i2c_irq_handler(&i2c_dev2);
-}
-
-/**
- * @brief Interrupt handler for I2C error conditions
- * @param dev I2C device
- * @sideeffect Aborts any pending I2C transactions
+/*
+ * Interrupt handler for I2C error conditions. Aborts any pending I2C
+ * transactions.
*/
-static void i2c_irq_error_handler(i2c_dev *dev) {
+void _i2c_irq_error_handler(i2c_dev *dev) {
I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2);
dev->error_flags = dev->regs->SR2 & (I2C_SR1_BERR |
@@ -317,125 +469,34 @@ static void i2c_irq_error_handler(i2c_dev *dev) {
dev->state = I2C_STATE_ERROR;
}
-void __irq_i2c1_er(void) {
- i2c_irq_error_handler(&i2c_dev1);
-}
-
-void __irq_i2c2_er(void) {
- i2c_irq_error_handler(&i2c_dev2);
-}
-
-/**
- * @brief Reset an I2C bus.
- *
- * Reset is accomplished by clocking out pulses until any hung slaves
- * release SDA and SCL, then generating a START condition, then a STOP
- * condition.
- *
- * @param dev I2C device
- */
-void i2c_bus_reset(const i2c_dev *dev) {
- /* Release both lines */
- gpio_write_bit(dev->gpio_port, dev->scl_pin, 1);
- gpio_write_bit(dev->gpio_port, dev->sda_pin, 1);
- gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_OUTPUT_OD);
- gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_OUTPUT_OD);
-
- /*
- * Make sure the bus is free by clocking it until any slaves release the
- * bus.
- */
- while (!gpio_read_bit(dev->gpio_port, dev->sda_pin)) {
- /* Wait for any clock stretching to finish */
- while (!gpio_read_bit(dev->gpio_port, dev->scl_pin))
- ;
- delay_us(10);
-
- /* Pull low */
- gpio_write_bit(dev->gpio_port, dev->scl_pin, 0);
- delay_us(10);
-
- /* Release high again */
- gpio_write_bit(dev->gpio_port, dev->scl_pin, 1);
- delay_us(10);
- }
-
- /* Generate start then stop condition */
- gpio_write_bit(dev->gpio_port, dev->sda_pin, 0);
- delay_us(10);
- gpio_write_bit(dev->gpio_port, dev->scl_pin, 0);
- delay_us(10);
- gpio_write_bit(dev->gpio_port, dev->scl_pin, 1);
- delay_us(10);
- gpio_write_bit(dev->gpio_port, dev->sda_pin, 1);
-}
-
-/**
- * @brief Initialize an I2C device and reset its registers to their
- * default values.
- * @param dev Device to initialize.
+/*
+ * CCR/TRISE configuration helper
*/
-void i2c_init(i2c_dev *dev) {
- rcc_reset_dev(dev->clk_id);
- rcc_clk_enable(dev->clk_id);
-}
+static void set_ccr_trise(i2c_dev *dev, uint32 flags) {
+ uint32 ccr = 0;
+ uint32 trise = 0;
+ uint32 clk_mhz = _i2c_bus_clk(dev);
+ uint32 clk_hz = clk_mhz * (1000 * 1000);
-/**
- * @brief Initialize an I2C device as bus master
- * @param dev Device to enable
- * @param flags Bitwise or of the following I2C options:
- * I2C_FAST_MODE: 400 khz operation,
- * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for
- * fast mode),
- * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on
- * initialization,
- * I2C_10BIT_ADDRESSING: Enable 10-bit addressing,
- * I2C_REMAP: Remap I2C1 to SCL/PB8 SDA/PB9.
- */
-void i2c_master_enable(i2c_dev *dev, uint32 flags) {
-#define I2C_CLK (STM32_PCLK1/1000000)
- uint32 ccr = 0;
- uint32 trise = 0;
-
- /* PE must be disabled to configure the device */
- ASSERT(!(dev->regs->CR1 & I2C_CR1_PE));
-
- if ((dev == I2C1) && (flags & I2C_REMAP)) {
- afio_remap(AFIO_REMAP_I2C1);
- I2C1->sda_pin = 9;
- I2C1->scl_pin = 8;
- }
-
- /* Reset the bus. Clock out any hung slaves. */
- if (flags & I2C_BUS_RESET) {
- i2c_bus_reset(dev);
- }
-
- /* Turn on clock and set GPIO modes */
- i2c_init(dev);
- gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_AF_OUTPUT_OD);
- gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD);
-
- /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */
- i2c_set_input_clk(dev, I2C_CLK);
+ i2c_set_input_clk(dev, clk_mhz);
if (flags & I2C_FAST_MODE) {
ccr |= I2C_CCR_FS;
if (flags & I2C_DUTY_16_9) {
/* Tlow/Thigh = 16/9 */
- ccr |= I2C_CCR_DUTY;
- ccr |= STM32_PCLK1/(400000 * 25);
+ ccr |= I2C_CCR_DUTY_16_9;
+ ccr |= clk_hz / (400000 * 25);
} else {
/* Tlow/Thigh = 2 */
- ccr |= STM32_PCLK1/(400000 * 3);
+ ccr |= clk_hz / (400000 * 3);
}
- trise = (300 * (I2C_CLK)/1000) + 1;
+ trise = (300 * clk_mhz / 1000) + 1;
} else {
/* Tlow/Thigh = 1 */
- ccr = STM32_PCLK1/(100000 * 2);
- trise = I2C_CLK + 1;
+ ccr = clk_hz / (100000 * 2);
+ trise = clk_mhz + 1;
}
/* Set minimum required value if CCR < 1*/
@@ -445,121 +506,4 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) {
i2c_set_clk_control(dev, ccr);
i2c_set_trise(dev, trise);
-
- /* Enable event and buffer interrupts */
- nvic_irq_enable(dev->ev_nvic_line);
- nvic_irq_enable(dev->er_nvic_line);
- i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR);
-
- /*
- * Important STM32 Errata:
- *
- * See STM32F10xx8 and STM32F10xxB Errata sheet (Doc ID 14574 Rev 8),
- * Section 2.11.1, 2.11.2.
- *
- * 2.11.1:
- * When the EV7, EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events are not
- * managed before the current byte is being transferred, problems may be
- * encountered such as receiving an extra byte, reading the same data twice
- * or missing data.
- *
- * 2.11.2:
- * In Master Receiver mode, when closing the communication using
- * method 2, the content of the last read data can be corrupted.
- *
- * If the user software is not able to read the data N-1 before the STOP
- * condition is generated on the bus, the content of the shift register
- * (data N) will be corrupted. (data N is shifted 1-bit to the left).
- *
- * ----------------------------------------------------------------------
- *
- * In order to ensure that events are not missed, the i2c interrupt must
- * not be preempted. We set the i2c interrupt priority to be the highest
- * interrupt in the system (priority level 0). All other interrupts have
- * been initialized to priority level 16. See nvic_init().
- */
- nvic_irq_set_priority(dev->ev_nvic_line, 0);
- nvic_irq_set_priority(dev->er_nvic_line, 0);
-
- /* Make it go! */
- i2c_peripheral_enable(dev);
-
- dev->state = I2C_STATE_IDLE;
-}
-
-
-/**
- * @brief Process an i2c transaction.
- *
- * Transactions are composed of one or more i2c_msg's, and may be read
- * or write tranfers. Multiple i2c_msg's will generate a repeated
- * start in between messages.
- *
- * @param dev I2C device
- * @param msgs Messages to send/receive
- * @param num Number of messages to send/receive
- * @param timeout Bus idle timeout in milliseconds before aborting the
- * transfer. 0 denotes no timeout.
- * @return 0 on success,
- * I2C_ERROR_PROTOCOL if there was a protocol error,
- * I2C_ERROR_TIMEOUT if the transfer timed out.
- */
-int32 i2c_master_xfer(i2c_dev *dev,
- i2c_msg *msgs,
- uint16 num,
- uint32 timeout) {
- int32 rc;
-
- ASSERT(dev->state == I2C_STATE_IDLE);
-
- dev->msg = msgs;
- dev->msgs_left = num;
- dev->timestamp = systick_uptime();
- dev->state = I2C_STATE_BUSY;
-
- i2c_enable_irq(dev, I2C_IRQ_EVENT);
- i2c_start_condition(dev);
-
- rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE, timeout);
- if (rc < 0) {
- goto out;
- }
-
- dev->state = I2C_STATE_IDLE;
-out:
- return rc;
-}
-
-
-/**
- * @brief Wait for an I2C event, or time out in case of error.
- * @param dev I2C device
- * @param state I2C_state state to wait for
- * @param timeout Timeout, in milliseconds
- * @return 0 if target state is reached, a negative value on error.
- */
-static inline int32 wait_for_state_change(i2c_dev *dev,
- i2c_state state,
- uint32 timeout) {
- i2c_state tmp;
-
- while (1) {
- tmp = dev->state;
-
- if (tmp == I2C_STATE_ERROR) {
- return I2C_STATE_ERROR;
- }
-
- if (tmp == state) {
- return 0;
- }
-
- if (timeout) {
- if (systick_uptime() > (dev->timestamp + timeout)) {
- /* TODO: overflow? */
- /* TODO: racy? */
- return I2C_ERROR_TIMEOUT;
- }
- }
- }
}
diff --git a/libmaple/i2c_private.h b/libmaple/i2c_private.h
new file mode 100644
index 0000000..5b79516
--- /dev/null
+++ b/libmaple/i2c_private.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#ifndef _LIBMAPLE_I2C_PRIVATE_H_
+#define _LIBMAPLE_I2C_PRIVATE_H_
+
+#include <libmaple/i2c_common.h>
+
+/* For old-style definitions (SDA/SCL on same GPIO device) */
+#define I2C_DEV_OLD(num, port, sda, scl) \
+ { \
+ .regs = I2C##num##_BASE, \
+ .gpio_port = port, \
+ .scl_port = NULL, \
+ .sda_port = NULL, \
+ .sda_pin = sda, \
+ .scl_pin = scl, \
+ .clk_id = RCC_I2C##num, \
+ .ev_nvic_line = NVIC_I2C##num##_EV, \
+ .er_nvic_line = NVIC_I2C##num##_ER, \
+ .state = I2C_STATE_DISABLED, \
+ }
+
+/* For new-style definitions (SDA/SCL may be on different GPIO devices) */
+#define I2C_DEV_NEW(num, sdaport, sdabit, sclport, sclbit) \
+ { \
+ .regs = I2C##num##_BASE, \
+ .gpio_port = NULL, \
+ .scl_port = sclport, \
+ .scl_pin = sclbit, \
+ .sda_port = sdaport, \
+ .sda_pin = sdabit, \
+ .clk_id = RCC_I2C##num, \
+ .ev_nvic_line = NVIC_I2C##num##_EV, \
+ .er_nvic_line = NVIC_I2C##num##_ER, \
+ .state = I2C_STATE_DISABLED, \
+ }
+
+void _i2c_irq_handler(i2c_dev *dev);
+void _i2c_irq_error_handler(i2c_dev *dev);
+
+struct gpio_dev;
+
+static inline struct gpio_dev* scl_port(const i2c_dev *dev) {
+ return (dev->gpio_port == NULL) ? dev->scl_port : dev->gpio_port;
+}
+
+static inline struct gpio_dev* sda_port(const i2c_dev *dev) {
+ return (dev->gpio_port == NULL) ? dev->sda_port : dev->gpio_port;
+}
+
+/* Auxiliary procedure for enabling an I2C peripheral; `flags' as for
+ * i2c_master_enable(). */
+void _i2c_set_ccr_trise(i2c_dev *dev, uint32 flags);
+
+#endif /* _LIBMAPLE_I2C_PRIVATE_H_ */
diff --git a/libmaple/adc.h b/libmaple/include/libmaple/adc.h
index d0b85fa..a500af7 100644
--- a/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,22 +26,29 @@
*****************************************************************************/
/**
- * @file adc.h
- *
- * @brief Analog-to-Digital Conversion (ADC) header.
+ * @file libmaple/include/libmaple/adc.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief Analog-to-Digital Conversion (ADC) header.
*/
-#ifndef _ADC_H_
-#define _ADC_H_
-
-#include "libmaple.h"
-#include "bitband.h"
-#include "rcc.h"
+#ifndef _LIBMAPLE_ADC_H_
+#define _LIBMAPLE_ADC_H_
#ifdef __cplusplus
extern "C"{
#endif
+#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 {
__io uint32 SR; ///< Status register
@@ -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,51 @@ extern const adc_dev *ADC3;
#define ADC_DR_ADC2DATA (0xFFFF << 16)
#define ADC_DR_DATA 0xFFFF
+/*
+ * Routines
+ */
+
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 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;
+extern void adc_set_prescaler(adc_prescaler pre);
-void adc_set_extsel(const adc_dev *dev, adc_extsel_event event);
-void adc_foreach(void (*fn)(const adc_dev*));
+/**
+ * @brief Call a function on all ADC devices.
+ * @param fn Function to call on each ADC device.
+ */
+extern void adc_foreach(void (*fn)(const adc_dev*));
+struct gpio_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 dev ADC device to use for conversion (currently ignored on
+ * all targets).
+ * @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;
+extern void adc_config_gpio(const struct adc_dev *dev,
+ 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()
+ */
+extern void adc_enable_single_swstart(const adc_dev* dev);
/**
* @brief Set the regular channel sequence length.
@@ -325,16 +300,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/bitband.h b/libmaple/include/libmaple/bitband.h
index 73941b0..6e77991 100644
--- a/libmaple/bitband.h
+++ b/libmaple/include/libmaple/bitband.h
@@ -25,15 +25,19 @@
*****************************************************************************/
/**
- * @file bitband.h
+ * @file libmaple/include/libmaple/bitband.h
*
* @brief Bit-banding utility functions
*/
-#include "libmaple_types.h"
+#ifndef _LIBMAPLE_BITBAND_H_
+#define _LIBMAPLE_BITBAND_H_
-#ifndef _BITBAND_H_
-#define _BITBAND_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
#define BB_SRAM_REF 0x20000000
#define BB_SRAM_BASE 0x22000000
@@ -47,7 +51,7 @@ static inline volatile uint32* __bb_addr(volatile void*,
/**
* @brief Obtain a pointer to the bit-band address corresponding to a
- * bit in a volatile SRAM address.
+ * bit in a volatile SRAM address.
* @param address Address in the bit-banded SRAM region
* @param bit Bit in address to bit-band
*/
@@ -79,7 +83,7 @@ static inline void bb_sram_set_bit(volatile void *address,
/**
* @brief Obtain a pointer to the bit-band address corresponding to a
- * bit in a peripheral address.
+ * bit in a peripheral address.
* @param address Address in the bit-banded peripheral region
* @param bit Bit in address to bit-band
*/
@@ -117,4 +121,8 @@ static inline volatile uint32* __bb_addr(volatile void *address,
bit * 4);
}
-#endif /* _BITBAND_H_ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/bkp.h b/libmaple/include/libmaple/bkp.h
index a81267d..bb63a2f 100644
--- a/libmaple/bkp.h
+++ b/libmaple/include/libmaple/bkp.h
@@ -25,19 +25,19 @@
*****************************************************************************/
/**
- * @file bkp.h
- * @brief Backup register support.
+ * @file libmaple/include/libmaple/bkp.h
+ * @brief Backup register support (STM32F1 only).
*/
-#ifndef _BKP_H_
-#define _BKP_H_
-
-#include "libmaple.h"
+#ifndef _LIBMAPLE_BKP_H_
+#define _LIBMAPLE_BKP_H_
#ifdef __cplusplus
extern "C" {
#endif
+#include <libmaple/libmaple.h>
+
#if defined(STM32_MEDIUM_DENSITY)
#define BKP_NR_DATA_REGS 10
#elif defined(STM32_HIGH_DENSITY)
@@ -60,7 +60,7 @@ typedef struct bkp_reg_map {
__io uint32 RTCCR; ///< RTC control register
__io uint32 CR; ///< Control register
__io uint32 CSR; ///< Control and status register
-#ifdef STM32_HIGH_DENSITY
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
const uint32 RESERVED2; ///< Reserved
const uint32 RESERVED3; ///< Reserved
__io uint32 DR11; ///< Data register 11
diff --git a/libmaple/include/libmaple/dac.h b/libmaple/include/libmaple/dac.h
new file mode 100644
index 0000000..56bfdc4
--- /dev/null
+++ b/libmaple/include/libmaple/dac.h
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
+ * Copyright (c) 2010 Bryan Newbold.
+ *
+ * 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/include/libmaple/dac.h
+ * @brief Digital to analog converter support.
+ */
+
+/* See notes/dac.txt for more info */
+
+#ifndef _LIBMAPLE_DAC_H_
+#define _LIBMAPLE_DAC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <series/dac.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+#include <libmaple/stm32.h>
+
+/*
+ * Register map base and device pointers.
+ *
+ * The DACs are the same on all supported targets, so it's not worth
+ * repeating these in the series headers.
+ */
+
+#define DAC_BASE ((struct dac_reg_map*)0x40007400)
+
+/** DAC device type. */
+typedef struct dac_dev {
+ dac_reg_map *regs; /**< Register map */
+} dac_dev;
+
+#if STM32_HAVE_DAC
+extern const dac_dev *DAC;
+#endif
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+
+/* Channel 1 control */
+#define DAC_CR_EN1 (1U << 0) /* Enable */
+#define DAC_CR_BOFF1 (1U << 1) /* Output buffer disable */
+#define DAC_CR_TEN1 (1U << 2) /* Trigger enable */
+#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */
+#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave */
+#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */
+#define DAC_CR_DMAEN1 (1U << 12) /* DMA enable */
+/* Channel 2 control */
+#define DAC_CR_EN2 (1U << 16) /* Enable */
+#define DAC_CR_BOFF2 (1U << 17) /* Output buffer disable */
+#define DAC_CR_TEN2 (1U << 18) /* Trigger enable */
+#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */
+#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave */
+#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */
+#define DAC_CR_DMAEN2 (1U << 28) /* DMA enable */
+
+/* Software trigger register */
+
+#define DAC_SWTRIGR_SWTRIG1 (1U << 0) /* Channel 1 software trigger */
+#define DAC_SWTRIGR_SWTRIG2 (1U << 1) /* Channel 2 software trigger */
+
+/* Channel 1 12-bit right-aligned data holding register */
+
+#define DAC_DHR12R1_DACC1DHR 0x00000FFF
+
+/* Channel 1 12-bit left-aligned data holding register */
+
+#define DAC_DHR12L1_DACC1DHR 0x0000FFF0
+
+/* Channel 1 8-bit left-aligned data holding register */
+
+#define DAC_DHR8R1_DACC1DHR 0x000000FF
+
+/* Channel 2 12-bit right-aligned data holding register */
+
+#define DAC_DHR12R2_DACC2DHR 0x00000FFF
+
+/* Channel 2 12-bit left-aligned data holding register */
+
+#define DAC_DHR12L2_DACC2DHR 0x0000FFF0
+
+/* Channel 2 8-bit left-aligned data holding register */
+
+#define DAC_DHR8R2_DACC2DHR 0x000000FF
+
+/* Dual DAC 12-bit right-aligned data holding register */
+
+#define DAC_DHR12RD_DACC1DHR 0x00000FFF
+#define DAC_DHR12RD_DACC2DHR 0x0FFF0000
+
+/* Dual DAC 12-bit left-aligned data holding register */
+
+#define DAC_DHR12LD_DACC1DHR 0x0000FFF0
+#define DAC_DHR12LD_DACC2DHR 0xFFF00000
+
+/* Dual DAC 8-bit left-aligned data holding register */
+
+#define DAC_DHR8RD_DACC1DHR 0x000000FF
+#define DAC_DHR8RD_DACC2DHR 0x0000FF00
+
+/* Channel 1 data output register */
+
+#define DAC_DOR1_DACC1DOR 0x00000FFF
+
+/* Channel 1 data output register */
+
+#define DAC_DOR2_DACC2DOR 0x00000FFF
+
+/*
+ * Routines
+ */
+
+/* We take the dev argument in these for future-proofing */
+
+#define DAC_CH1 0x1
+#define DAC_CH2 0x2
+void dac_init(const dac_dev *dev, uint32 flags);
+
+void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val);
+void dac_enable_channel(const dac_dev *dev, uint8 channel);
+void dac_disable_channel(const dac_dev *dev, uint8 channel);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/exti.h b/libmaple/include/libmaple/delay.h
index f225844..472a208 100644
--- a/libmaple/exti.h
+++ b/libmaple/include/libmaple/delay.h
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,50 +26,40 @@
*****************************************************************************/
/**
- * @file exti.h
- * @brief External interrupt control prototypes and defines
+ * @file libmaple/include/libmaple/delay.h
+ * @brief Delay implementation
*/
-/* See notes/exti.txt for more info */
-
-#include "libmaple.h"
-#include "gpio.h"
-
-#ifndef _EXTI_H_
-#define _EXTI_H_
+#ifndef _LIBMAPLE_DELAY_H_
+#define _LIBMAPLE_DELAY_H_
#ifdef __cplusplus
-extern "C"{
+extern "C" {
#endif
-/** EXTI register map type */
-typedef struct exti_reg_map {
- __io uint32 IMR; /**< Interrupt mask register */
- __io uint32 EMR; /**< Event mask register */
- __io uint32 RTSR; /**< Rising trigger selection register */
- __io uint32 FTSR; /**< Falling trigger selection register */
- __io uint32 SWIER; /**< Software interrupt event register */
- __io uint32 PR; /**< Pending register */
-} exti_reg_map;
-
-/** EXTI register map base pointer */
-#define EXTI_BASE ((struct exti_reg_map*)0x40010400)
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.h>
-/** External interrupt trigger mode */
-typedef enum exti_trigger_mode {
- EXTI_RISING, /**< Trigger on the rising edge */
- EXTI_FALLING, /**< Trigger on the falling edge */
- EXTI_RISING_FALLING /**< Trigger on both the rising and falling edges */
-} exti_trigger_mode;
+/**
+ * @brief Delay the given number of microseconds.
+ *
+ * @param us Number of microseconds to delay.
+ */
+static inline void delay_us(uint32 us) {
+ us *= STM32_DELAY_US_MULT;
-void exti_attach_interrupt(afio_exti_num num,
- afio_exti_port port,
- voidFuncPtr handler,
- exti_trigger_mode mode);
-void exti_detach_interrupt(afio_exti_num num);
+ /* fudge for function call overhead */
+ us--;
+ asm volatile(" mov r0, %[us] \n\t"
+ "1: subs r0, #1 \n\t"
+ " bhi 1b \n\t"
+ :
+ : [us] "r" (us)
+ : "r0");
+}
#ifdef __cplusplus
-} // extern "C"
+}
#endif
#endif
diff --git a/libmaple/include/libmaple/dma.h b/libmaple/include/libmaple/dma.h
new file mode 100644
index 0000000..0b1ec4c
--- /dev/null
+++ b/libmaple/include/libmaple/dma.h
@@ -0,0 +1,444 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ * 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/include/libmaple/dma.h
+ *
+ * @author Marti Bolivar <mbolivar@leaflabs.com>;
+ * Original implementation by Michael Hope
+ *
+ * @brief Direct Memory Access peripheral support
+ */
+
+#ifndef _LIBMAPLE_DMA_H_
+#define _LIBMAPLE_DMA_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* <series/dma.h> provides:
+ *
+ * - An opaque dma_tube type, and predefined rvalues for each tube
+ * supported by the series.
+ *
+ * A "DMA tube" is a series-specific (hopefully integer) datatype
+ * that abstracts the conduit through which DMA-ed data flow.
+ *
+ * Examples: On STM32F1, dma_tube is just an alias for dma_channel,
+ * and the tube values are just DMA_CH1 (=1), DMA_CH2 (=2), etc.
+ *
+ * Note that a dma_tube doesn't have to be an enum, and its values
+ * don't have to be integral. They _do_ need to be cheap to pass as
+ * arguments, though.
+ *
+ * - struct dma_tube_reg_map (and typedef to dma_tube_reg_map). DMA
+ * register maps tend to be split into global registers and per-tube
+ * registers. It's convenient to pass around pointers to a tube's
+ * registers, since that makes it possible to configure or otherwise
+ * mess with a tube without knowing which one you're dealing with.
+ *
+ * - Base pointers to the various dma_tube_reg_maps.
+ *
+ * Examples: On STM32F1, these are DMAxCHy_BASE. You can access
+ * registers like DMAxCHy_BASE->CPAR, etc.
+ *
+ * - enum dma_request_src (and typedef to dma_request_src). This
+ * specifies the peripheral DMA request sources (e.g. USART TX DMA
+ * requests, etc.).
+ *
+ * - enum dma_mode_flags (and typedef to dma_mode_flags). Used in
+ * dma_tube_config. If two series both support the same mode flags,
+ * they must use the same enumerator names for those flags (the
+ * values of those enumerators are of course allowed to differ).
+ *
+ * - Normal stuff: dma_reg_map and base pointers, register bit
+ * definitions, dma_dev pointer declarations, and any other
+ * convenience functions useful for the series. */
+#include <series/dma.h>
+/* <libmaple/dma_common.h> buys us dma_dev and other necessities. */
+#include <libmaple/dma_common.h>
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Declarations/documentation for some of the series-provided types.
+ */
+
+/**
+ * @brief (Series-dependent) DMA request sources.
+ *
+ * These specify the various pieces of peripheral functionality which
+ * may make DMA requests. Use them to set up a DMA transfer (see
+ * struct dma_tube_config, dma_tube_cfg()).
+ */
+enum dma_request_src;
+
+/**
+ * @brief (Series-dependent) DMA tube configuration flags.
+ * These specify miscellaneous bits of configuration for a DMA tube.
+ * @see struct dma_mode_config
+ */
+enum dma_cfg_flags;
+
+/**
+ * @brief (Series-dependent) DMA tube register map type.
+ * This allows you to access a tube's registers as a group.
+ * @see dma_tube_regs()
+ */
+struct dma_tube_reg_map;
+
+/*
+ * Convenience functions
+ */
+
+/* Initialization */
+
+void dma_init(dma_dev *dev);
+
+/* dma_tube configuration
+ *
+ * Use these types and functions to set up DMA transfers, handle
+ * interrupts, etc. The main function of interest is dma_tube_cfg(),
+ * which the various series implement separately. */
+
+/**
+ * @brief Specifies a DMA tube configuration.
+ *
+ * Use one of these to set up a DMA transfer by passing it to
+ * dma_tube_cfg().
+ *
+ * @see dma_tube_cfg()
+ * @see dma_xfer_size
+ */
+typedef struct dma_tube_config {
+ /** Source of data */
+ __io void *tube_src;
+ /** Source transfer size */
+ dma_xfer_size tube_src_size;
+
+ /** Destination of data */
+ __io void *tube_dst;
+ /** Destination transfer size */
+ dma_xfer_size tube_dst_size;
+
+ /**
+ * Number of data to transfer (0 to 65,535).
+ *
+ * Note that this is NOT measured in bytes; it's measured in
+ * number of data, which occur in multiples of tube_src_size. For
+ * example, if tube_src_size is DMA_SIZE_32BITS and tube_nr_xfers
+ * is 2, then 8 total bytes will be transferred.
+ */
+ unsigned tube_nr_xfers;
+
+ /**
+ * Target-specific configuration flags.
+ *
+ * These are an OR of series-specific enum dma_mode_flags values.
+ * Consult the documentation for your target for what flags you
+ * can use here.
+ *
+ * Typical flag examples: DMA_CFG_SRC_INC, DMA_CFG_DST_INC,
+ * DMA_CFG_CIRC, DMA_CFG_CMPLT_IE, etc.
+ */
+ unsigned tube_flags;
+
+ /**
+ * Currently unused. You must set this to 0 or something valid for
+ * your target. */
+ void *target_data;
+
+ /**
+ * Hardware DMA request source.
+ *
+ * This is ignored for memory-to-memory transfers.
+ */
+ enum dma_request_src tube_req_src;
+} dma_tube_config;
+
+#define DMA_TUBE_CFG_SUCCESS 0
+#define DMA_TUBE_CFG_EREQ 1
+#define DMA_TUBE_CFG_ENDATA 2
+#define DMA_TUBE_CFG_EDEV 3
+#define DMA_TUBE_CFG_ESRC 4
+#define DMA_TUBE_CFG_EDST 5
+#define DMA_TUBE_CFG_EDIR 6
+#define DMA_TUBE_CFG_ESIZE 7
+#define DMA_TUBE_CFG_ECFG 0xFF
+/**
+ * @brief Configure a DMA tube.
+ *
+ * Use this function to set up a DMA transfer. The tube will be
+ * disabled before being reconfigured. The transfer will have low
+ * priority by default. You can choose another priority before the
+ * transfer begins using dma_set_priority(). You can manage your
+ * interrupt handlers for the tube using dma_attach_interrupt() and
+ * dma_detach_interrupt().
+ *
+ * After calling dma_tube_cfg() and performing any other desired
+ * configuration, start the transfer using dma_enable().
+ *
+ * @param dev DMA device.
+ * @param tube DMA tube to configure.
+ * @param cfg Configuration to apply to tube.
+ *
+ * @return DMA_TUBE_CFG_SUCCESS (0) on success, <0 on failure. On
+ * failure, returned value will be the opposite (-) of one of:
+ *
+ * - DMA_TUBE_CFG_EREQ: tube doesn't work with cfg->tube_req_src
+ * - DMA_TUBE_CFG_ENDATA: cfg->tube_[src,dst]_size are
+ * incompatible with cfg->tube_nr_xfers, or cfg->tube_nr_xfers
+ * is out of bounds.
+ * - DMA_TUBE_CFG_EDEV: dev does not support cfg
+ * - DMA_TUBE_CFG_ESRC: bad cfg->tube_src
+ * - DMA_TUBE_CFG_EDST: bad cfg->tube_dst
+ * - DMA_TUBE_CFG_EDIR: dev can't transfer from cfg->tube_src to
+ * cfg->tube_dst
+ * - DMA_TUBE_CFG_ESIZE: something ended up wrong due to MSIZE/PSIZE
+ * - DMA_TUBE_CFG_ECFG: generic "something's wrong"
+ *
+ * @sideeffect Disables tube. May alter tube's registers even when an
+ * error occurs.
+ * @see struct dma_tube_config
+ * @see dma_attach_interrupt()
+ * @see dma_detach_interrupt()
+ * @see dma_enable()
+ */
+extern int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg);
+
+/* Other tube configuration functions. You can use these if
+ * dma_tube_cfg() isn't enough, or to adjust parts of an existing tube
+ * configuration. */
+
+/** DMA transfer priority. */
+typedef enum dma_priority {
+ DMA_PRIORITY_LOW = 0, /**< Low priority */
+ DMA_PRIORITY_MEDIUM = 1, /**< Medium priority */
+ DMA_PRIORITY_HIGH = 2, /**< High priority */
+ DMA_PRIORITY_VERY_HIGH = 3, /**< Very high priority */
+} dma_priority;
+
+/**
+ * @brief Set the priority of a DMA transfer.
+ *
+ * You may not call this function while the tube is enabled.
+ *
+ * @param dev DMA device
+ * @param tube DMA tube
+ * @param priority priority to set.
+ */
+extern void dma_set_priority(dma_dev *dev, dma_tube tube,
+ dma_priority priority);
+
+/**
+ * @brief Set the number of data transfers on a DMA tube.
+ *
+ * You may not call this function while the tube is enabled.
+ *
+ * @param dev DMA device
+ * @param tube Tube through which the transfer will occur.
+ * @param num_transfers Number of DMA transactions to set.
+ */
+extern void dma_set_num_transfers(dma_dev *dev, dma_tube tube,
+ uint16 num_transfers);
+
+/**
+ * @brief Set the base memory address where data will be read from or
+ * written to.
+ *
+ * You must not call this function while the tube is enabled.
+ *
+ * If the DMA memory size is 16 bits, the address is automatically
+ * aligned to a half-word. If the DMA memory size is 32 bits, the
+ * address is aligned to a word.
+ *
+ * @param dev DMA Device
+ * @param tube Tube whose base memory address to set.
+ * @param address Memory base address to use.
+ */
+extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address);
+
+/**
+ * @brief Set the base peripheral address where data will be read from
+ * or written to.
+ *
+ * You must not call this function while the channel is enabled.
+ *
+ * If the DMA peripheral size is 16 bits, the address is automatically
+ * aligned to a half-word. If the DMA peripheral size is 32 bits, the
+ * address is aligned to a word.
+ *
+ * @param dev DMA Device
+ * @param tube Tube whose peripheral data register base address to set.
+ * @param addr Peripheral memory base address to use.
+ */
+extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address);
+
+/* Interrupt handling */
+
+/**
+ * @brief Attach an interrupt to a DMA transfer.
+ *
+ * Interrupts are enabled using series-specific mode flags in
+ * dma_tube_cfg().
+ *
+ * @param dev DMA device
+ * @param tube Tube to attach handler to
+ * @param handler Interrupt handler to call when tube interrupt fires.
+ * @see dma_tube_cfg()
+ * @see dma_get_irq_cause()
+ * @see dma_detach_interrupt()
+ */
+extern void dma_attach_interrupt(dma_dev *dev, dma_tube tube,
+ void (*handler)(void));
+
+
+/**
+ * @brief Detach a DMA transfer interrupt handler.
+ *
+ * After calling this function, the given tube's interrupts will be
+ * disabled.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose handler to detach
+ * @sideeffect Clears the tube's interrupt enable bits.
+ * @see dma_attach_interrupt()
+ */
+extern void dma_detach_interrupt(dma_dev *dev, dma_tube tube);
+
+/* Tube enable/disable */
+
+/**
+ * @brief Enable a DMA tube.
+ *
+ * If the tube has been properly configured, calling this function
+ * allows it to start serving DMA requests.
+ *
+ * @param dev DMA device
+ * @param tube Tube to enable
+ * @see dma_tube_cfg()
+ */
+extern void dma_enable(dma_dev *dev, dma_tube tube);
+
+/**
+ * @brief Disable a DMA channel.
+ *
+ * Calling this function makes the tube stop serving DMA requests.
+ *
+ * @param dev DMA device
+ * @param tube Tube to disable
+ */
+extern void dma_disable(dma_dev *dev, dma_tube tube);
+
+/**
+ * @brief Check if a DMA tube is enabled.
+ * @param dev DMA device.
+ * @param tube Tube to check.
+ * @return 0 if the tube is disabled, >0 if it is enabled.
+ */
+static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube);
+
+/* Other conveniences */
+
+/**
+ * @brief Obtain a pointer to an individual DMA tube's registers.
+ *
+ * Examples:
+ *
+ * - On STM32F1, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1.
+ *
+ * @param dev DMA device.
+ * @param tube DMA tube whose register map to obtain.
+ * @return (Series-specific) tube register map.
+ */
+static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube);
+
+/**
+ * Encodes the reason why a DMA interrupt was called.
+ * @see dma_get_irq_cause()
+ */
+typedef enum dma_irq_cause {
+ DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */
+ DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */
+ DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */
+ DMA_TRANSFER_DME_ERROR, /**<
+ * @brief Direct mode error occurred during
+ * transfer. */
+ DMA_TRANSFER_FIFO_ERROR, /**< FIFO error occurred during transfer. */
+} dma_irq_cause;
+
+/**
+ * @brief Discover the reason why a DMA interrupt was called.
+ *
+ * You may only call this function within an attached interrupt
+ * handler for the given channel.
+ *
+ * This function resets the internal DMA register state which encodes
+ * the cause of the interrupt; consequently, it can only be called
+ * once per interrupt handler invocation.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose interrupt is being handled.
+ * @return Reason why the interrupt fired.
+ * @sideeffect Clears flags in dev's interrupt status registers.
+ * @see dma_attach_interrupt()
+ * @see dma_irq_cause
+ */
+extern dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube);
+
+/**
+ * @brief Get the ISR status bits for a DMA channel.
+ *
+ * The bits are returned right-aligned, in the order they appear in
+ * the corresponding ISR register.
+ *
+ * If you're trying to figure out why a DMA interrupt fired, you may
+ * find dma_get_irq_cause() more convenient.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose ISR bits to return.
+ * @see dma_get_irq_cause().
+ */
+static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube);
+
+/**
+ * @brief Clear the ISR status bits for a given DMA tube.
+ *
+ * If you're trying to clean up after yourself in a DMA interrupt, you
+ * may find dma_get_irq_cause() more convenient.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose ISR bits to clear.
+ * @see dma_get_irq_cause()
+ */
+static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/dma_common.h b/libmaple/include/libmaple/dma_common.h
new file mode 100644
index 0000000..67475f7
--- /dev/null
+++ b/libmaple/include/libmaple/dma_common.h
@@ -0,0 +1,114 @@
+/******************************************************************************
+ * 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/include/libmaple/dma_common.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Common DMA sub-header for <series/dma.h> and <libmaple/dma.h>.
+ *
+ * WARNING: CONTENTS UNSTABLE
+ *
+ * The existence of this file is an implementation detail. Its
+ * contents are not stable, so never include it directly. If you need
+ * something from here, #include <libmaple/dma.h> instead.
+ */
+
+/*
+ * There's a fair amount of common DMA functionality needed by each
+ * <series/dma.h> and <libmaple/dma.h>. This header exists in order
+ * to provide it to both, avoiding some hacks and circular
+ * dependencies.
+ */
+
+#ifndef _LIBMAPLE_DMA_COMMON_H_
+#define _LIBMAPLE_DMA_COMMON_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/nvic.h>
+#include <libmaple/rcc.h>
+
+/*
+ * Devices
+ */
+
+struct dma_reg_map;
+
+/* Encapsulates state related to user interrupt handlers. You
+ * shouldn't touch these directly; use dma_attach_interrupt() and
+ * dma_detach_interupt() instead. */
+typedef struct dma_handler_config {
+ void (*handler)(void); /* User handler */
+ nvic_irq_num irq_line; /* IRQ line for interrupt */
+} dma_handler_config;
+
+/** DMA device type */
+typedef struct dma_dev {
+ struct dma_reg_map *regs; /**< Register map */
+ rcc_clk_id clk_id; /**< Clock ID */
+ struct dma_handler_config handlers[]; /**< For internal use */
+} dma_dev;
+
+/**
+ * @brief DMA channels
+ *
+ * Notes:
+ * - This is also the dma_tube type for STM32F1.
+ * - Channel 0 is not available on all STM32 series.
+ *
+ * @see dma_tube
+ */
+typedef enum dma_channel {
+ DMA_CH0 = 0, /**< Channel 0 */
+ DMA_CH1 = 1, /**< Channel 1 */
+ DMA_CH2 = 2, /**< Channel 2 */
+ DMA_CH3 = 3, /**< Channel 3 */
+ DMA_CH4 = 4, /**< Channel 4 */
+ DMA_CH5 = 5, /**< Channel 5 */
+ DMA_CH6 = 6, /**< Channel 6 */
+ DMA_CH7 = 7, /**< Channel 7 */
+} dma_channel;
+
+/**
+ * @brief Source and destination transfer sizes.
+ * Use these when initializing a struct dma_tube_config.
+ * @see struct dma_tube_config
+ * @see dma_tube_cfg
+ */
+typedef enum dma_xfer_size {
+ DMA_SIZE_8BITS = 0, /**< 8-bit transfers */
+ DMA_SIZE_16BITS = 1, /**< 16-bit transfers */
+ DMA_SIZE_32BITS = 2, /**< 32-bit transfers */
+} dma_xfer_size;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/exti.h b/libmaple/include/libmaple/exti.h
new file mode 100644
index 0000000..3800b4a
--- /dev/null
+++ b/libmaple/include/libmaple/exti.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * 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/include/libmaple/exti.h
+ * @brief External interrupt control
+ */
+
+/* See notes/exti.txt for more info */
+
+#ifndef _LIBMAPLE_EXTI_H_
+#define _LIBMAPLE_EXTI_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <series/exti.h> /* provides EXTI_BASE */
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map and base pointer.
+ */
+
+/** EXTI register map type */
+typedef struct exti_reg_map {
+ __io uint32 IMR; /**< Interrupt mask register */
+ __io uint32 EMR; /**< Event mask register */
+ __io uint32 RTSR; /**< Rising trigger selection register */
+ __io uint32 FTSR; /**< Falling trigger selection register */
+ __io uint32 SWIER; /**< Software interrupt event register */
+ __io uint32 PR; /**< Pending register */
+} exti_reg_map;
+
+/*
+ * Types: exti_num, exti_cfg, exti_trigger_mode.
+ *
+ * A combination of these three specifies an external interrupt
+ * configuration (see exti_attach_interrupt()).
+ */
+
+/** EXTI line. */
+typedef enum exti_num {
+ EXTI0, /**< EXTI line 0 */
+ EXTI1, /**< EXTI line 1 */
+ EXTI2, /**< EXTI line 2 */
+ EXTI3, /**< EXTI line 3 */
+ EXTI4, /**< EXTI line 4 */
+ EXTI5, /**< EXTI line 5 */
+ EXTI6, /**< EXTI line 6 */
+ EXTI7, /**< EXTI line 7 */
+ EXTI8, /**< EXTI line 8 */
+ EXTI9, /**< EXTI line 9 */
+ EXTI10, /**< EXTI line 10 */
+ EXTI11, /**< EXTI line 11 */
+ EXTI12, /**< EXTI line 12 */
+ EXTI13, /**< EXTI line 13 */
+ EXTI14, /**< EXTI line 14 */
+ EXTI15, /**< EXTI line 15 */
+} exti_num;
+
+/**
+ * @brief EXTI port configuration
+ *
+ * These specify which GPIO port an external interrupt line should be
+ * connected to.
+ */
+typedef enum exti_cfg {
+ EXTI_PA, /**< Use PAx pin */
+ EXTI_PB, /**< Use PBx pin */
+ EXTI_PC, /**< Use PCx pin */
+ EXTI_PD, /**< Use PDx pin */
+ EXTI_PE, /**< Use PEx pin */
+ EXTI_PF, /**< Use PFx pin */
+ EXTI_PG, /**< Use PGx pin */
+ EXTI_PH, /**< Use PHx pin */
+ EXTI_PI, /**< Use PIx pin */
+} exti_cfg;
+
+/** External interrupt trigger mode */
+typedef enum exti_trigger_mode {
+ EXTI_RISING, /**< Trigger on the rising edge */
+ EXTI_FALLING, /**< Trigger on the falling edge */
+ EXTI_RISING_FALLING /**< Trigger on both the rising and falling edges */
+} exti_trigger_mode;
+
+/*
+ * Routines
+ */
+
+void exti_attach_interrupt(exti_num num,
+ exti_cfg port,
+ voidFuncPtr handler,
+ exti_trigger_mode mode);
+void exti_detach_interrupt(exti_num num);
+
+/**
+ * @brief Set the GPIO port for an EXTI line.
+ *
+ * This is a low-level routine that most users will not
+ * need. exti_attach_interrupt() handles calling this function
+ * appropriately.
+ *
+ * @param num EXTI line
+ * @param port EXTI configuration for GPIO port to connect to num.
+ * @see exti_num
+ * @see exti_cfg
+ */
+extern void exti_select(exti_num num, exti_cfg port);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/flash.h b/libmaple/include/libmaple/flash.h
new file mode 100644
index 0000000..943e466
--- /dev/null
+++ b/libmaple/include/libmaple/flash.h
@@ -0,0 +1,106 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * 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/include/libmaple/flash.h
+ * @brief Flash support.
+ */
+
+#ifndef _LIBMAPLE_FLASH_H_
+#define _LIBMAPLE_FLASH_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+#define FLASH_WAIT_STATE_0 0x0
+#define FLASH_WAIT_STATE_1 0x1
+#define FLASH_WAIT_STATE_2 0x2
+#define FLASH_WAIT_STATE_3 0x3
+#define FLASH_WAIT_STATE_4 0x4
+#define FLASH_WAIT_STATE_5 0x5
+#define FLASH_WAIT_STATE_6 0x6
+#define FLASH_WAIT_STATE_7 0x7
+
+/* The series header must define:
+ *
+ * - FLASH_SAFE_WAIT_STATES, the smallest number of wait states that
+ * it is safe to use when SYSCLK is at its fastest documented rate
+ * and the MCU is powered at 3.3V (i.e. this doesn't consider
+ * overclocking or low voltage operation).
+ *
+ * - The following bit flags, for flash_enable_features():
+ *
+ * -- FLASH_PREFETCH: prefetcher
+ * -- FLASH_ICACHE: instruction cache
+ * -- FLASH_DCACHE: data cache
+ *
+ * See that function's Doxygen for more restrictions.
+ */
+#include <series/flash.h>
+
+#ifdef __DOXYGEN__
+/** Flash register map base pointer. */
+#define FLASH_BASE
+#endif
+
+/*
+ * Flash routines
+ */
+
+void flash_set_latency(uint32 wait_states);
+
+/**
+ * @brief Enable Flash memory features
+ *
+ * If the target MCU doesn't provide a feature (e.g. instruction and
+ * data caches on the STM32F1), the flag will be ignored. This allows
+ * using these flags unconditionally, with the desired effect taking
+ * place on targets that support them.
+ *
+ * @param feature_flags Bitwise OR of the following:
+ * FLASH_PREFETCH (turns on prefetcher),
+ * FLASH_ICACHE (turns on instruction cache),
+ * FLASH_DCACHE (turns on data cache).
+ */
+static inline void flash_enable_features(uint32 feature_flags) {
+ FLASH_BASE->ACR |= feature_flags;
+}
+
+/**
+ * @brief Deprecated. Use flash_enable_features(FLASH_PREFETCH) instead.
+ */
+static inline void flash_enable_prefetch(void) {
+ flash_enable_features(FLASH_PREFETCH);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/fsmc.h b/libmaple/include/libmaple/fsmc.h
index ef82b08..6225fee 100644
--- a/libmaple/fsmc.h
+++ b/libmaple/include/libmaple/fsmc.h
@@ -25,7 +25,7 @@
*****************************************************************************/
/**
- * @file fsmc.h
+ * @file libmaple/include/libmaple/fsmc.h
* @brief Flexible static memory controller support.
*/
@@ -33,20 +33,19 @@
* See ../notes/fsmc.txt for more info
*/
-#include "libmaple_types.h"
-
-/**
- * @file fsmc.h
- */
-
-#ifndef _FSMC_H_
-#define _FSMC_H_
+#ifndef _LIBMAPLE_FSMC_H_
+#define _LIBMAPLE_FSMC_H_
#ifdef __cplusplus
extern "C"{
#endif
-#ifdef STM32_HIGH_DENSITY
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.h>
+
+#if !STM32_HAVE_FSMC
+#error "FSMC is unavailable on your MCU"
+#endif
/*
* Register maps and devices
@@ -136,16 +135,16 @@ typedef struct fsmc_nor_psram_reg_map {
#define FSMC_BCR_MUXEN_BIT 1
#define FSMC_BCR_MBKEN_BIT 0
-#define FSMC_BCR_CBURSTRW BIT(FSMC_BCR_CBURSTRW_BIT)
-#define FSMC_BCR_ASYNCWAIT BIT(FSMC_BCR_ASYNCWAIT_BIT)
-#define FSMC_BCR_EXTMOD BIT(FSMC_BCR_EXTMOD_BIT)
-#define FSMC_BCR_WAITEN BIT(FSMC_BCR_WAITEN_BIT)
-#define FSMC_BCR_WREN BIT(FSMC_BCR_WREN_BIT)
-#define FSMC_BCR_WAITCFG BIT(FSMC_BCR_WAITCFG_BIT)
-#define FSMC_BCR_WRAPMOD BIT(FSMC_BCR_WRAPMOD_BIT)
-#define FSMC_BCR_WAITPOL BIT(FSMC_BCR_WAITPOL_BIT)
-#define FSMC_BCR_BURSTEN BIT(FSMC_BCR_BURSTEN_BIT)
-#define FSMC_BCR_FACCEN BIT(FSMC_BCR_FACCEN_BIT)
+#define FSMC_BCR_CBURSTRW (1U << FSMC_BCR_CBURSTRW_BIT)
+#define FSMC_BCR_ASYNCWAIT (1U << FSMC_BCR_ASYNCWAIT_BIT)
+#define FSMC_BCR_EXTMOD (1U << FSMC_BCR_EXTMOD_BIT)
+#define FSMC_BCR_WAITEN (1U << FSMC_BCR_WAITEN_BIT)
+#define FSMC_BCR_WREN (1U << FSMC_BCR_WREN_BIT)
+#define FSMC_BCR_WAITCFG (1U << FSMC_BCR_WAITCFG_BIT)
+#define FSMC_BCR_WRAPMOD (1U << FSMC_BCR_WRAPMOD_BIT)
+#define FSMC_BCR_WAITPOL (1U << FSMC_BCR_WAITPOL_BIT)
+#define FSMC_BCR_BURSTEN (1U << FSMC_BCR_BURSTEN_BIT)
+#define FSMC_BCR_FACCEN (1U << FSMC_BCR_FACCEN_BIT)
#define FSMC_BCR_MWID (0x3 << 4)
#define FSMC_BCR_MWID_8BITS (0x0 << 4)
#define FSMC_BCR_MWID_16BITS (0x1 << 4)
@@ -153,8 +152,8 @@ typedef struct fsmc_nor_psram_reg_map {
#define FSMC_BCR_MTYP_SRAM (0x0 << 2)
#define FSMC_BCR_MTYP_PSRAM (0x1 << 2)
#define FSMC_BCR_MTYP_NOR_FLASH (0x2 << 2)
-#define FSMC_BCR_MUXEN BIT(FSMC_BCR_MUXEN_BIT)
-#define FSMC_BCR_MBKEN BIT(FSMC_BCR_MBKEN_BIT)
+#define FSMC_BCR_MUXEN (1U << FSMC_BCR_MUXEN_BIT)
+#define FSMC_BCR_MBKEN (1U << FSMC_BCR_MBKEN_BIT)
/* SRAM/NOR-Flash chip-select timing registers */
@@ -199,15 +198,15 @@ typedef struct fsmc_nor_psram_reg_map {
#define FSMC_PCR_ECCPS_8192B (0x5 << 17)
#define FSMC_PCR_TAR (0xF << 13)
#define FSMC_PCR_TCLR (0xF << 9)
-#define FSMC_PCR_ECCEN BIT(FSMC_PCR_ECCEN_BIT)
+#define FSMC_PCR_ECCEN (1U << FSMC_PCR_ECCEN_BIT)
#define FSMC_PCR_PWID (0x3 << 4)
#define FSMC_PCR_PWID_8BITS (0x0 << 4)
#define FSMC_PCR_PWID_16BITS (0x1 << 4)
-#define FSMC_PCR_PTYP BIT(FSMC_PCR_PTYP_BIT)
+#define FSMC_PCR_PTYP (1U << FSMC_PCR_PTYP_BIT)
#define FSMC_PCR_PTYP_PC_CF_PCMCIA (0x0 << FSMC_PCR_PTYP_BIT)
#define FSMC_PCR_PTYP_NAND (0x1 << FSMC_PCR_PTYP_BIT)
-#define FSMC_PCR_PBKEN BIT(FSMC_PCR_PBKEN_BIT)
-#define FSMC_PCR_PWAITEN BIT(FSMC_PCR_PWAITEN_BIT)
+#define FSMC_PCR_PBKEN (1U << FSMC_PCR_PBKEN_BIT)
+#define FSMC_PCR_PWAITEN (1U << FSMC_PCR_PWAITEN_BIT)
/* FIFO status and interrupt registers */
@@ -219,13 +218,13 @@ typedef struct fsmc_nor_psram_reg_map {
#define FSMC_SR_ILS_BIT 1
#define FSMC_SR_IRS_BIT 0
-#define FSMC_SR_FEMPT BIT(FSMC_SR_FEMPT_BIT)
-#define FSMC_SR_IFEN BIT(FSMC_SR_IFEN_BIT)
-#define FSMC_SR_ILEN BIT(FSMC_SR_ILEN_BIT)
-#define FSMC_SR_IREN BIT(FSMC_SR_IREN_BIT)
-#define FSMC_SR_IFS BIT(FSMC_SR_IFS_BIT)
-#define FSMC_SR_ILS BIT(FSMC_SR_ILS_BIT)
-#define FSMC_SR_IRS BIT(FSMC_SR_IRS_BIT)
+#define FSMC_SR_FEMPT (1U << FSMC_SR_FEMPT_BIT)
+#define FSMC_SR_IFEN (1U << FSMC_SR_IFEN_BIT)
+#define FSMC_SR_ILEN (1U << FSMC_SR_ILEN_BIT)
+#define FSMC_SR_IREN (1U << FSMC_SR_IREN_BIT)
+#define FSMC_SR_IFS (1U << FSMC_SR_IFS_BIT)
+#define FSMC_SR_ILS (1U << FSMC_SR_ILS_BIT)
+#define FSMC_SR_IRS (1U << FSMC_SR_IRS_BIT)
/* Common memory space timing registers */
@@ -252,35 +251,58 @@ typedef struct fsmc_nor_psram_reg_map {
* Memory bank boundary addresses
*/
-/** Pointer to base address of FSMC memory bank 1 (split into 4
- * regions, each supporting 1 NOR Flash, SRAM, or PSRAM chip) */
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1 (NOR/PSRAM).
+ *
+ * This bank is split into 4 regions. Each region supports interfacing
+ * with 1 NOR Flash, SRAM, or PSRAM chip. The base addresses of these
+ * regions are FSMC_NOR_PSRAM_REGIONx, for x = 1, 2, 3, 4.
+ */
#define FSMC_BANK1 ((void*)0x60000000)
-/** Pointer to base address of FSMC memory bank 1, region 1 (for NOR/PSRAM) */
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 1
+ * (NOR/PSRAM).
+ */
#define FSMC_NOR_PSRAM_REGION1 FSMC_BANK1
-/** Pointer to base address of FSMC memory bank 1, region 2 (for NOR/PSRAM) */
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 2
+ * (NOR/PSRAM).
+ */
#define FSMC_NOR_PSRAM_REGION2 ((void*)0x64000000)
-/** Pointer to base address of FSMC memory bank 1, region 3 (for NOR/PSRAM) */
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 3
+ * (NOR/PSRAM).
+ */
#define FSMC_NOR_PSRAM_REGION3 ((void*)0x68000000)
-/** Pointer to base address of FSMC memory bank 1, region 4 (for NOR/PSRAM) */
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 4
+ * (NOR/PSRAM).
+ */
#define FSMC_NOR_PSRAM_REGION4 ((void*)0x6C000000)
-/** Pointer to base address of FSMC memory bank 2 (for NAND Flash) */
+/** Void pointer to base address of FSMC memory bank 2 (NAND Flash). */
#define FSMC_BANK2 ((void*)0x70000000)
-/** Pointer to base address of FSMC memory bank 3 (for NAND Flash) */
+/** Void pointer to base address of FSMC memory bank 3 (NAND Flash). */
#define FSMC_BANK3 ((void*)0x80000000)
-/** Pointer to base address of FSMC memory bank 4 (for PC card devices */
+/**
+ * @brief Void pointer to base address of FSMC memory bank 4 (PC card
+ * devices).
+ */
#define FSMC_BANK4 ((void*)0x90000000)
/*
* SRAM/NOR Flash routines
*/
+/**
+ * @brief Configure FSMC GPIOs for use with SRAM.
+ */
void fsmc_sram_init_gpios(void);
/**
@@ -311,8 +333,6 @@ static inline void fsmc_nor_psram_set_addset(fsmc_nor_psram_reg_map *regs,
regs->BTR |= addset & 0xF;
}
-#endif /* STM32_HIGH_DENSITY */
-
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/libmaple/include/libmaple/gpio.h b/libmaple/include/libmaple/gpio.h
new file mode 100644
index 0000000..0cc3746
--- /dev/null
+++ b/libmaple/include/libmaple/gpio.h
@@ -0,0 +1,121 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 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/include/libmaple/gpio.h
+ * @brief General Purpose I/O (GPIO) interace.
+ */
+
+#ifndef _LIBMAPLE_GPIO_H_
+#define _LIBMAPLE_GPIO_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/*
+ * Note: Series header must define:
+ * - enum gpio_pin_mode (TODO think harder about portability here)
+ */
+#include <series/gpio.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+#include <libmaple/exti.h>
+
+/*
+ * Device type
+ */
+
+/** GPIO device type */
+typedef struct gpio_dev {
+ gpio_reg_map *regs; /**< Register map */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ /**
+ * @brief (Deprecated) External interrupt port.
+ * Instead of dev->exti_port, use gpio_exti_port(dev).
+ */
+ exti_cfg exti_port;
+} gpio_dev;
+
+/*
+ * Portable routines
+ */
+
+void gpio_init(gpio_dev *dev);
+void gpio_init_all(void);
+/* TODO flags argument version? */
+void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode);
+
+/**
+ * @brief Get a GPIO port's corresponding EXTI port configuration.
+ * @param dev GPIO port whose exti_cfg to return.
+ */
+static inline exti_cfg gpio_exti_port(gpio_dev *dev) {
+ return (exti_cfg)(EXTI_PA + (dev->clk_id - RCC_GPIOA));
+}
+
+/**
+ * Set or reset a GPIO pin.
+ *
+ * Pin must have previously been configured to output mode.
+ *
+ * @param dev GPIO device whose pin to set.
+ * @param pin Pin on to set or reset
+ * @param val If true, set the pin. If false, reset the pin.
+ */
+static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) {
+ val = !val; /* "set" bits are lower than "reset" bits */
+ dev->regs->BSRR = (1U << pin) << (16 * val);
+}
+
+/**
+ * Determine whether or not a GPIO pin is set.
+ *
+ * Pin must have previously been configured to input mode.
+ *
+ * @param dev GPIO device whose pin to test.
+ * @param pin Pin on dev to test.
+ * @return True if the pin is set, false otherwise.
+ */
+static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) {
+ return dev->regs->IDR & (1U << pin);
+}
+
+/**
+ * Toggle a pin configured as output push-pull.
+ * @param dev GPIO device.
+ * @param pin Pin on dev to toggle.
+ */
+static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) {
+ dev->regs->ODR = dev->regs->ODR ^ (1U << pin);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/i2c.h b/libmaple/include/libmaple/i2c.h
index 4c60ad7..ff1c313 100644
--- a/libmaple/i2c.h
+++ b/libmaple/include/libmaple/i2c.h
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2012 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,17 +26,51 @@
*****************************************************************************/
/**
- * @file i2c.h
+ * @file libmaple/include/libmaple/i2c.h
* @brief Inter-Integrated Circuit (I2C) peripheral support
+ *
+ * Currently master-only. Usage notes:
+ *
+ * - Enable an I2C device with i2c_master_enable().
+ * - Initialize an array of struct i2c_msg to suit the bus
+ * transactions (reads/writes) you wish to perform.
+ * - Call i2c_master_xfer() to do the work.
*/
-#include "libmaple_types.h"
-#include "rcc.h"
-#include "nvic.h"
-#include "gpio.h"
+#ifndef _LIBMAPLE_I2C_H_
+#define _LIBMAPLE_I2C_H_
-#ifndef _I2C_H_
-#define _I2C_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Series header must provide:
+ *
+ * - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in
+ * MHz. (This is for internal use only).
+ *
+ * - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1.
+ * This is for internal use only. It's a hack to work around a
+ * silicon bug related to I2C IRQ pre-emption on some targets. If 1,
+ * the series header must also declare and implement a routine with
+ * this signature (it may also be provided as a macro):
+ *
+ * void _i2c_irq_priority_fixup(i2c_dev*)
+ *
+ * This will be called by i2c_enable_irq() before actually enabling
+ * I2C interrupts.
+ *
+ * - Reg. map base pointers, device pointer declarations.
+ */
+
+#include <series/i2c.h>
+#include <libmaple/i2c_common.h>
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+#include <libmaple/nvic.h>
+#include <libmaple/gpio.h>
/** I2C register map type */
typedef struct i2c_reg_map {
@@ -50,136 +85,118 @@ typedef struct i2c_reg_map {
__io uint32 TRISE; /**< TRISE (rise time) register */
} i2c_reg_map;
-/** I2C device states */
-typedef enum i2c_state {
- I2C_STATE_DISABLED = 0, /**< Disabled */
- I2C_STATE_IDLE = 1, /**< Idle */
- I2C_STATE_XFER_DONE = 2, /**< Done with transfer */
- I2C_STATE_BUSY = 3, /**< Busy */
- I2C_STATE_ERROR = -1 /**< Error occurred */
-} i2c_state;
-
/**
* @brief I2C message type
*/
typedef struct i2c_msg {
uint16 addr; /**< Address */
+
#define I2C_MSG_READ 0x1
#define I2C_MSG_10BIT_ADDR 0x2
- uint16 flags; /**< Bitwise OR of I2C_MSG_READ and
- I2C_MSG_10BIT_ADDR */
+ /**
+ * Bitwise OR of:
+ * - I2C_MSG_READ (write is default)
+ * - I2C_MSG_10BIT_ADDR (7-bit is default) */
+ uint16 flags;
+
uint16 length; /**< Message length */
uint16 xferred; /**< Messages transferred */
uint8 *data; /**< Data */
} i2c_msg;
-/**
- * @brief I2C device type.
- */
-typedef struct i2c_dev {
- i2c_reg_map *regs; /**< Register map */
- gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */
- uint8 sda_pin; /**< SDA bit on gpio_port */
- uint8 scl_pin; /**< SCL bit on gpio_port */
- rcc_clk_id clk_id; /**< RCC clock information */
- nvic_irq_num ev_nvic_line; /**< Event IRQ number */
- nvic_irq_num er_nvic_line; /**< Error IRQ number */
- volatile i2c_state state; /**< Device state */
- uint16 msgs_left; /**< Messages left */
- i2c_msg *msg; /**< Messages */
- volatile uint32 timestamp; /**< For internal use */
- uint32 error_flags; /**< Error flags, set on I2C error condition */
-} i2c_dev;
-
-/*
- * Devices
- */
-
-extern i2c_dev* const I2C1;
-extern i2c_dev* const I2C2;
-
-/*
- * Register map base pointers
- */
-
-/** I2C1 register map base pointer */
-#define I2C1_BASE ((struct i2c_reg_map*)0x40005400)
-/** I2C2 register map base pointer */
-#define I2C2_BASE ((struct i2c_reg_map*)0x40005800)
-
/*
* Register bit definitions
*/
/* Control register 1 */
-#define I2C_CR1_SWRST BIT(15) // Software reset
-#define I2C_CR1_ALERT BIT(13) // SMBus alert
-#define I2C_CR1_PEC BIT(12) // Packet error checking
-#define I2C_CR1_POS BIT(11) // Acknowledge/PEC position
-#define I2C_CR1_ACK BIT(10) // Acknowledge enable
-#define I2C_CR1_START BIT(8) // Start generation
-#define I2C_CR1_STOP BIT(9) // Stop generation
-#define I2C_CR1_PE BIT(0) // Peripheral Enable
+#define I2C_CR1_SWRST (1U << 15) // Software reset
+#define I2C_CR1_ALERT (1U << 13) // SMBus alert
+#define I2C_CR1_PEC (1U << 12) // Packet error checking
+#define I2C_CR1_POS (1U << 11) // Acknowledge/PEC position
+#define I2C_CR1_ACK (1U << 10) // Acknowledge enable
+#define I2C_CR1_STOP (1U << 9) // Stop generation
+#define I2C_CR1_START (1U << 8) // Start generation
+#define I2C_CR1_NOSTRETCH (1U << 7) // Clock stretching disable
+#define I2C_CR1_ENGC (1U << 6) // General call enable
+#define I2C_CR1_ENPEC (1U << 5) // PEC enable
+#define I2C_CR1_ENARP (1U << 4) // ARP enable
+#define I2C_CR1_SMBTYPE (1U << 3) // SMBus type
+#define I2C_CR1_SMBTYPE_DEVICE (0U << 3) // SMBus type: device
+#define I2C_CR1_SMBTYPE_HOST (1U << 3) // SMBus type: host
+#define I2C_CR1_SMBUS (1U << 1) // SMBus mode
+#define I2C_CR1_SMBUS_I2C (0U << 1) // SMBus mode: I2C
+#define I2C_CR1_SMBUS_SMBUS (1U << 1) // SMBus mode: SMBus
+#define I2C_CR1_PE (1U << 0) // Peripheral Enable
/* Control register 2 */
-#define I2C_CR2_LAST BIT(12) // DMA last transfer
-#define I2C_CR2_DMAEN BIT(11) // DMA requests enable
-#define I2C_CR2_ITBUFEN BIT(10) // Buffer interrupt enable
-#define I2C_CR2_ITEVTEN BIT(9) // Event interupt enable
-#define I2C_CR2_ITERREN BIT(8) // Error interupt enable
-#define I2C_CR2_FREQ 0xFFF // Peripheral input frequency
+#define I2C_CR2_LAST (1U << 12) // DMA last transfer
+#define I2C_CR2_DMAEN (1U << 11) // DMA requests enable
+#define I2C_CR2_ITBUFEN (1U << 10) // Buffer interrupt enable
+#define I2C_CR2_ITEVTEN (1U << 9) // Event interupt enable
+#define I2C_CR2_ITERREN (1U << 8) // Error interupt enable
+#define I2C_CR2_FREQ 0x3F // Peripheral input frequency
-/* Clock control register */
+/* Own address register 1 */
-#define I2C_CCR_FS BIT(15) // Fast mode selection
-#define I2C_CCR_DUTY BIT(14) // 16/9 duty ratio
-#define I2C_CCR_CCR 0xFFF // Clock control bits
+#define I2C_OAR1_ADDMODE (1U << 15) // Addressing mode
+#define I2C_OAR1_ADDMODE_7_BIT (0U << 15) // Addressing mode: 7-bit
+#define I2C_OAR1_ADDMODE_10_BIT (1U << 15) // Addressing mode: 10-bit
+#define I2C_OAR1_ADD 0x3FF // Interface address
+
+/* Own address register 2 */
+
+#define I2C_OAR2_ADD2 0xFE // Interface address
+#define I2C_OAR2_ENDUAL 1U // Dual addressing mode enable
/* Status register 1 */
-#define I2C_SR1_SB BIT(0) // Start bit
-#define I2C_SR1_ADDR BIT(1) // Address sent/matched
-#define I2C_SR1_BTF BIT(2) // Byte transfer finished
-#define I2C_SR1_ADD10 BIT(3) // 10-bit header sent
-#define I2C_SR1_STOPF BIT(4) // Stop detection
-#define I2C_SR1_RXNE BIT(6) // Data register not empty
-#define I2C_SR1_TXE BIT(7) // Data register empty
-#define I2C_SR1_BERR BIT(8) // Bus error
-#define I2C_SR1_ARLO BIT(9) // Arbitration lost
-#define I2C_SR1_AF BIT(10) // Acknowledge failure
-#define I2C_SR1_OVR BIT(11) // Overrun/underrun
-#define I2C_SR1_PECERR BIT(12) // PEC Error in reception
-#define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error
-#define I2C_SR1_SMBALERT BIT(15) // SMBus alert
+#define I2C_SR1_SMBALERT (1U << 15) // SMBus alert
+#define I2C_SR1_TIMEOUT (1U << 14) // Timeout or Tlow error
+#define I2C_SR1_PECERR (1U << 12) // PEC Error in reception
+#define I2C_SR1_OVR (1U << 11) // Overrun/underrun
+#define I2C_SR1_AF (1U << 10) // Acknowledge failure
+#define I2C_SR1_ARLO (1U << 9) // Arbitration lost
+#define I2C_SR1_BERR (1U << 8) // Bus error
+#define I2C_SR1_TXE (1U << 7) // Data register empty
+#define I2C_SR1_RXNE (1U << 6) // Data register not empty
+#define I2C_SR1_STOPF (1U << 4) // Stop detection
+#define I2C_SR1_ADD10 (1U << 3) // 10-bit header sent
+#define I2C_SR1_BTF (1U << 2) // Byte transfer finished
+#define I2C_SR1_ADDR (1U << 1) // Address sent/matched
+#define I2C_SR1_SB (1U << 0) // Start bit
/* Status register 2 */
-#define I2C_SR2_MSL BIT(0) // Master/slave
-#define I2C_SR2_BUSY BIT(1) // Bus busy
-#define I2C_SR2_TRA BIT(2) // Transmitter/receiver
-#define I2C_SR2_GENCALL BIT(4) // General call address
-#define I2C_SR2_SMBDEFAULT BIT(5) // SMBus device default address
-#define I2C_SR2_SMBHOST BIT(6) // SMBus host header
-#define I2C_SR2_DUALF BIT(7) // Dual flag
#define I2C_SR2_PEC 0xFF00 // Packet error checking register
+#define I2C_SR2_DUALF (1U << 7) // Dual flag
+#define I2C_SR2_SMBHOST (1U << 6) // SMBus host header
+#define I2C_SR2_SMBDEFAULT (1U << 5) // SMBus device default address
+#define I2C_SR2_GENCALL (1U << 4) // General call address
+#define I2C_SR2_TRA (1U << 2) // Transmitter/receiver
+#define I2C_SR2_BUSY (1U << 1) // Bus busy
+#define I2C_SR2_MSL (1U << 0) // Master/slave
+
+/* Clock control register */
+
+#define I2C_CCR_FS (1U << 15) // Fast mode selection
+#define I2C_CCR_DUTY (1U << 14) // Fast mode duty cycle
+#define I2C_CCR_DUTY_2_1 (0U << 14) // Fast mode duty: 2/1
+#define I2C_CCR_DUTY_16_9 (1U << 14) // Fast mode duty: 16/9
+#define I2C_CCR_CCR 0xFFF // Clock control bits
/*
* Convenience routines
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void i2c_init(i2c_dev *dev);
+/* Main I2C API */
/* I2C enable options */
-#define I2C_FAST_MODE BIT(0) // 400 khz
-#define I2C_DUTY_16_9 BIT(1) // 16/9 duty ratio
-#define I2C_REMAP BIT(2) // Use alternate pin mapping
-#define I2C_BUS_RESET BIT(3) // Perform a bus reset
+#define I2C_FAST_MODE 0x1 // 400 khz
+#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio
+/* Flag 0x4 is reserved; DO NOT USE. */
+#define I2C_BUS_RESET 0x8 // Perform a bus reset
void i2c_master_enable(i2c_dev *dev, uint32 flags);
#define I2C_ERROR_PROTOCOL (-1)
@@ -201,67 +218,7 @@ static inline void i2c_disable(i2c_dev *dev) {
dev->state = I2C_STATE_DISABLED;
}
-/**
- * @brief Turn on an I2C peripheral
- * @param dev Device to enable
- */
-static inline void i2c_peripheral_enable(i2c_dev *dev) {
- dev->regs->CR1 |= I2C_CR1_PE;
-}
-
-/**
- * @brief Turn off an I2C peripheral
- * @param dev Device to turn off
- */
-static inline void i2c_peripheral_disable(i2c_dev *dev) {
- dev->regs->CR1 &= ~I2C_CR1_PE;
-}
-
-/**
- * @brief Fill transmit register
- * @param dev I2C device
- * @param byte Byte to write
- */
-static inline void i2c_write(i2c_dev *dev, uint8 byte) {
- dev->regs->DR = byte;
-}
-
-/**
- * @brief Set input clock frequency, in MHz
- * @param dev I2C device
- * @param freq Frequency in megahertz (2-36)
- */
-static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) {
- uint32 cr2 = dev->regs->CR2;
- cr2 &= ~I2C_CR2_FREQ;
- cr2 |= freq;
- dev->regs->CR2 = freq;
-}
-
-/**
- * @brief Set I2C clock control register. See RM008
- * @param dev I2C device
- * @param val Value to use for clock control register (in
- * Fast/Standard mode)
- */
-static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) {
- uint32 ccr = dev->regs->CCR;
- ccr &= ~I2C_CCR_CCR;
- ccr |= val;
- dev->regs->CCR = ccr;
-}
-
-
-/**
- * @brief Set SCL rise time
- * @param dev I2C device
- * @param trise Maximum rise time in fast/standard mode (see RM0008
- * for relevant formula).
- */
-static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) {
- dev->regs->TRISE = trise;
-}
-
+/* Start/stop conditions */
/**
* @brief Generate a start condition on the bus.
@@ -297,6 +254,17 @@ static inline void i2c_stop_condition(i2c_dev *dev) {
}
+/* IRQ enable/disable */
+
+#ifndef _I2C_HAVE_IRQ_FIXUP
+/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined,
+ * but we need it either way. */
+#define _i2c_irq_priority_fixup(dev) ((void)0)
+#endif
+
+#define I2C_IRQ_ERROR I2C_CR2_ITERREN
+#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN
+#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN
/**
* @brief Enable one or more I2C interrupts
* @param dev I2C device
@@ -305,10 +273,8 @@ static inline void i2c_stop_condition(i2c_dev *dev) {
* I2C_IRQ_EVENT (event interrupt), and
* I2C_IRQ_BUFFER (buffer interrupt).
*/
-#define I2C_IRQ_ERROR I2C_CR2_ITERREN
-#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN
-#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN
static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) {
+ _i2c_irq_priority_fixup(dev);
dev->regs->CR2 |= irqs;
}
@@ -324,6 +290,7 @@ static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) {
dev->regs->CR2 &= ~irqs;
}
+/* ACK/NACK */
/**
* @brief Enable I2C acknowledgment
@@ -341,6 +308,104 @@ static inline void i2c_disable_ack(i2c_dev *dev) {
dev->regs->CR1 &= ~I2C_CR1_ACK;
}
+/* GPIO control */
+
+/**
+ * @brief Configure device GPIOs.
+ *
+ * Configure GPIO bits dev->sda_pin and dev->scl_pin on GPIO device
+ * dev->gpio_port for use with I2C device dev.
+ *
+ * @param dev I2C Device
+ * @see i2c_release_gpios()
+ */
+extern void i2c_config_gpios(const i2c_dev *dev);
+
+/**
+ * @brief Release GPIOs controlling an I2C bus
+ *
+ * Releases the I2C bus controlled by dev as master, and disconnects
+ * GPIO bits dev->sda_pin and dev->scl_pin on GPIO device
+ * dev->gpio_port from I2C device dev.
+ *
+ * @param dev I2C device
+ * @see i2c_config_gpios()
+ */
+extern void i2c_master_release_bus(const i2c_dev *dev);
+
+/* Miscellaneous low-level routines */
+
+void i2c_init(i2c_dev *dev);
+
+/**
+ * @brief Turn on an I2C peripheral
+ * @param dev Device to enable
+ */
+static inline void i2c_peripheral_enable(i2c_dev *dev) {
+ dev->regs->CR1 |= I2C_CR1_PE;
+}
+
+/**
+ * @brief Turn off an I2C peripheral
+ * @param dev Device to turn off
+ */
+static inline void i2c_peripheral_disable(i2c_dev *dev) {
+ dev->regs->CR1 &= ~I2C_CR1_PE;
+}
+
+/**
+ * @brief Fill transmit register
+ * @param dev I2C device
+ * @param byte Byte to write
+ */
+static inline void i2c_write(i2c_dev *dev, uint8 byte) {
+ dev->regs->DR = byte;
+}
+
+/**
+ * @brief Set input clock frequency, in MHz
+ * @param dev I2C device
+ * @param freq Frequency, in MHz. This must be at least 2, and at most
+ * the APB frequency of dev's bus. (For example, if
+ * rcc_dev_clk(dev) == RCC_APB1, freq must be at most
+ * PCLK1, in MHz). There is an additional limit of 46 MHz.
+ */
+static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) {
+#define I2C_MAX_FREQ_MHZ 46
+ ASSERT(2 <= freq && freq <= _i2c_bus_clk(dev) && freq <= I2C_MAX_FREQ_MHZ);
+ uint32 cr2 = dev->regs->CR2;
+ cr2 &= ~I2C_CR2_FREQ;
+ cr2 |= freq;
+ dev->regs->CR2 = freq;
+#undef I2C_MAX_FREQ_MHZ
+}
+
+/**
+ * @brief Set I2C clock control register.
+ *
+ * See the chip reference manual for the details.
+ *
+ * @param dev I2C device
+ * @param val Value to use for clock control register (in
+ * Fast/Standard mode)
+ */
+static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) {
+ uint32 ccr = dev->regs->CCR;
+ ccr &= ~I2C_CCR_CCR;
+ ccr |= val;
+ dev->regs->CCR = ccr;
+}
+
+/**
+ * @brief Set SCL rise time
+ * @param dev I2C device
+ * @param trise Maximum rise time in fast/standard mode (see chip
+ * reference manual for the relevant formulas).
+ */
+static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) {
+ dev->regs->TRISE = trise;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/libmaple/include/libmaple/i2c_common.h b/libmaple/include/libmaple/i2c_common.h
new file mode 100644
index 0000000..5d99530
--- /dev/null
+++ b/libmaple/include/libmaple/i2c_common.h
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung (from <libmaple/i2c.h>).
+ * 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/include/libmaple/i2c_common.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief This file is an implementation detail
+ *
+ * WARNING: CONTENTS UNSTABLE
+ *
+ * The existence of this file is an implementation detail. Its
+ * contents are not stable, so never include it directly. If you need
+ * something from here, #include <libmaple/i2c.h> instead.
+ */
+
+#ifndef _LIBMAPLE_I2C_COMMON_H_
+#define _LIBMAPLE_I2C_COMMON_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/nvic.h>
+#include <libmaple/rcc.h>
+
+struct gpio_dev;
+struct i2c_reg_map;
+struct i2c_msg;
+
+/** I2C device states */
+typedef enum i2c_state {
+ I2C_STATE_DISABLED = 0, /**< Disabled */
+ I2C_STATE_IDLE = 1, /**< Idle */
+ I2C_STATE_XFER_DONE = 2, /**< Done with transfer */
+ I2C_STATE_BUSY = 3, /**< Busy */
+ I2C_STATE_ERROR = -1 /**< Error occurred */
+} i2c_state;
+
+/**
+ * @brief I2C device type.
+ */
+typedef struct i2c_dev {
+ struct i2c_reg_map *regs; /**< Register map */
+ struct i2c_msg *msg; /**< Messages */
+ uint32 error_flags; /**< Error flags, set on I2C error condition */
+ volatile uint32 timestamp; /**< For internal use */
+
+ /**
+ * @brief Deprecated. Use .scl_port or .sda_port instead.
+ * If non-null, this will be used as SDA, SCL pins' GPIO port. If
+ * null, then .sda_port will be used for SDA, and .sda_port for
+ * SDA. */
+ struct gpio_dev *gpio_port;
+
+ /**
+ * @brief SDA GPIO device (but see .gpio_port).
+ */
+ struct gpio_dev *sda_port;
+
+ /**
+ * @brief SCL GPIO device (but see .gpio_port).
+ */
+ struct gpio_dev *scl_port;
+
+ uint16 msgs_left; /**< Messages left */
+ uint8 sda_pin; /**< SDA bit on gpio_port */
+ uint8 scl_pin; /**< SCL bit on gpio_port */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ nvic_irq_num ev_nvic_line; /**< Event IRQ number */
+ nvic_irq_num er_nvic_line; /**< Error IRQ number */
+ volatile i2c_state state; /**< Device state */
+} i2c_dev;
+
+#endif
diff --git a/libmaple/iwdg.h b/libmaple/include/libmaple/iwdg.h
index 59e8e18..3a16c55 100644
--- a/libmaple/iwdg.h
+++ b/libmaple/include/libmaple/iwdg.h
@@ -25,7 +25,7 @@
*****************************************************************************/
/**
- * @file iwdg.h
+ * @file libmaple/include/libmaple/iwdg.h
* @author Michael Hope, Marti Bolivar <mbolivar@leaflabs.com>
* @brief Independent watchdog support.
*
@@ -38,16 +38,15 @@
* Once started, the independent watchdog cannot be turned off.
*/
-#ifndef _IWDG_H_
-#define _IWDG_H_
-
-#include "libmaple_types.h"
-#include "util.h"
+#ifndef _LIBMAPLE_IWDG_H_
+#define _LIBMAPLE_IWDG_H_
#ifdef __cplusplus
extern "C"{
#endif
+#include <libmaple/libmaple_types.h>
+
/*
* Register map
*/
@@ -88,8 +87,8 @@ typedef struct iwdg_reg_map {
#define IWDG_SR_RVU_BIT 1
#define IWDG_SR_PVU_BIT 0
-#define IWDG_SR_RVU BIT(IWDG_SR_RVU_BIT)
-#define IWDG_SR_PVU BIT(IWDG_SR_PVU_BIT)
+#define IWDG_SR_RVU (1U << IWDG_SR_RVU_BIT)
+#define IWDG_SR_PVU (1U << IWDG_SR_PVU_BIT)
/**
* @brief Independent watchdog prescalers.
diff --git a/libmaple/libmaple.h b/libmaple/include/libmaple/libmaple.h
index c509f5d..f1a595e 100644
--- a/libmaple/libmaple.h
+++ b/libmaple/include/libmaple/libmaple.h
@@ -25,17 +25,21 @@
*****************************************************************************/
/**
- * @file libmaple.h
+ * @file libmaple/include/libmaple/libmaple.h
* @brief General include file for libmaple
*/
-#ifndef _LIBMAPLE_H_
-#define _LIBMAPLE_H_
+#ifndef _LIBMAPLE_LIBMAPLE_H_
+#define _LIBMAPLE_LIBMAPLE_H_
-#include "libmaple_types.h"
-#include "stm32.h"
-#include "util.h"
-#include "delay.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.h>
+#include <libmaple/util.h>
+#include <libmaple/delay.h>
/*
* Where to put usercode, based on space reserved for bootloader.
@@ -46,5 +50,8 @@
#define USER_ADDR_RAM 0x20000C00
#define STACK_TOP 0x20000800
+#ifdef __cplusplus
+}
#endif
+#endif
diff --git a/libmaple/libmaple_types.h b/libmaple/include/libmaple/libmaple_types.h
index 08adaff..9e1fbb3 100644
--- a/libmaple/libmaple_types.h
+++ b/libmaple/include/libmaple/libmaple_types.h
@@ -25,13 +25,17 @@
*****************************************************************************/
/**
- * @file libmaple_types.h
+ * @file libmaple/include/libmaple/libmaple_types.h
*
- * @brief libmaple types
+ * @brief libmaple's types, and operations on types.
*/
-#ifndef _LIBMAPLE_TYPES_H_
-#define _LIBMAPLE_TYPES_H_
+#ifndef _LIBMAPLE_LIBMAPLE_TYPES_H_
+#define _LIBMAPLE_LIBMAPLE_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
typedef unsigned char uint8;
typedef unsigned short uint16;
@@ -48,10 +52,21 @@ typedef void (*voidFuncPtr)(void);
#define __io volatile
#define __attr_flash __attribute__((section (".USER_FLASH")))
#define __packed __attribute__((__packed__))
+#define __deprecated __attribute__((__deprecated__))
+#define __weak __attribute__((weak))
+#define __always_inline inline __attribute__((always_inline))
+#define __unused __attribute__((unused))
#ifndef NULL
#define NULL 0
#endif
+#ifndef offsetof
+#define offsetof(type, member) __builtin_offsetof(type, member)
#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/nvic.h b/libmaple/include/libmaple/nvic.h
new file mode 100644
index 0000000..ac102d9
--- /dev/null
+++ b/libmaple/include/libmaple/nvic.h
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * 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/include/libmaple/nvic.h
+ * @brief Nested vectored interrupt controller support.
+ *
+ * Basic usage:
+ *
+ * @code
+ * // Initialise the interrupt controller and point to the vector
+ * // table at the start of flash.
+ * nvic_init(0x08000000, 0);
+ * // Bind in a timer interrupt handler
+ * timer_attach_interrupt(TIMER_CC1_INTERRUPT, handler);
+ * // Optionally set the priority
+ * nvic_irq_set_priority(NVIC_TIMER1_CC, 5);
+ * // All done, enable all interrupts
+ * nvic_globalirq_enable();
+ * @endcode
+ */
+
+#ifndef _LIBMAPLE_NVIC_H_
+#define _LIBMAPLE_NVIC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
+
+/** NVIC register map type. */
+typedef struct nvic_reg_map {
+ __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */
+ /** Reserved */
+ uint32 RESERVED0[24];
+
+ __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */
+ /** Reserved */
+ uint32 RESERVED1[24];
+
+ __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */
+ /** Reserved */
+ uint32 RESERVED2[24];
+
+ __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */
+ /** Reserved */
+ uint32 RESERVED3[24];
+
+ __io uint32 IABR[8]; /**< Interrupt Active bit Registers */
+ /** Reserved */
+ uint32 RESERVED4[56];
+
+ __io uint8 IP[240]; /**< Interrupt Priority Registers */
+ /** Reserved */
+ uint32 RESERVED5[644];
+
+ __io uint32 STIR; /**< Software Trigger Interrupt Registers */
+} nvic_reg_map;
+
+/** NVIC register map base pointer. */
+#define NVIC_BASE ((struct nvic_reg_map*)0xE000E100)
+
+/*
+ * Note: The series header must define enum nvic_irq_num, which gives
+ * descriptive names to the interrupts and exceptions from NMI (-14)
+ * to the largest interrupt available in the series, where the value
+ * for nonnegative enumerators corresponds to its position in the
+ * vector table.
+ *
+ * It also must define a static inline nvic_irq_disable_all(), which
+ * writes 0xFFFFFFFF to all ICE registers available in the series. (We
+ * place the include here to give the series header access to
+ * NVIC_BASE, in order to let it do so).
+ */
+#include <series/nvic.h>
+
+void nvic_init(uint32 address, uint32 offset);
+void nvic_set_vector_table(uint32 address, uint32 offset);
+void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority);
+void nvic_sys_reset();
+
+/**
+ * Enables interrupts and configurable fault handlers (clear PRIMASK).
+ */
+static inline void nvic_globalirq_enable() {
+ asm volatile("cpsie i");
+}
+
+/**
+ * Disable interrupts and configurable fault handlers (set PRIMASK).
+ */
+static inline void nvic_globalirq_disable() {
+ asm volatile("cpsid i");
+}
+
+/**
+ * @brief Enable interrupt irq_num
+ * @param irq_num Interrupt to enable
+ */
+static inline void nvic_irq_enable(nvic_irq_num irq_num) {
+ if (irq_num < 0) {
+ return;
+ }
+ NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32);
+}
+
+/**
+ * @brief Disable interrupt irq_num
+ * @param irq_num Interrupt to disable
+ */
+static inline void nvic_irq_disable(nvic_irq_num irq_num) {
+ if (irq_num < 0) {
+ return;
+ }
+ NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32);
+}
+
+/**
+ * @brief Quickly disable all interrupts.
+ *
+ * Calling this function is significantly faster than calling
+ * nvic_irq_disable() in a loop.
+ */
+static inline void nvic_irq_disable_all(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/pwr.h b/libmaple/include/libmaple/pwr.h
index 88b49c0..e4b5b0d 100644
--- a/libmaple/pwr.h
+++ b/libmaple/include/libmaple/pwr.h
@@ -25,16 +25,20 @@
*****************************************************************************/
/**
- * @file pwr.h
- * @brief Power control (PWR) defines.
+ * @file libmaple/include/libmaple/pwr.h
+ * @brief Power control (PWR).
*/
-#include "libmaple.h"
+#ifndef _LIBMAPLE_PWR_H_
+#define _LIBMAPLE_PWR_H_
#ifdef __cplusplus
extern "C" {
#endif
+#include <libmaple/libmaple.h>
+#include <series/pwr.h>
+
/** Power interface register map. */
typedef struct pwr_reg_map {
__io uint32 CR; /**< Control register */
@@ -51,28 +55,52 @@ typedef struct pwr_reg_map {
/* Control register */
/** Disable backup domain write protection bit */
-#define PWR_CR_DBP 8
+#define PWR_CR_DBP_BIT 8
/** Power voltage detector enable bit */
-#define PWR_CR_PVDE 4
+#define PWR_CR_PVDE_BIT 4
/** Clear standby flag bit */
-#define PWR_CR_CSBF 3
+#define PWR_CR_CSBF_BIT 3
/** Clear wakeup flag bit */
-#define PWR_CR_CWUF 2
+#define PWR_CR_CWUF_BIT 2
/** Power down deepsleep bit */
-#define PWR_CR_PDDS 1
+#define PWR_CR_PDDS_BIT 1
/** Low-power deepsleep bit */
-#define PWR_CR_LPDS 0
+#define PWR_CR_LPDS_BIT 0
+
+/** Disable backup domain write protection */
+#define PWR_CR_DBP (1U << PWR_CR_DBP_BIT)
+/** Power voltage detector (PVD) level selection */
+#define PWR_CR_PLS (0x7 << 5)
+/** Power voltage detector enable */
+#define PWR_CR_PVDE (1U << PWR_CR_PVDE_BIT)
+/** Clear standby flag */
+#define PWR_CR_CSBF (1U << PWR_CR_CSBF_BIT)
+/** Clear wakeup flag */
+#define PWR_CR_CWUF (1U << PWR_CR_CWUF_BIT)
+/** Power down deepsleep */
+#define PWR_CR_PDDS (1U << PWR_CR_PDDS_BIT)
+/** Low-power deepsleep */
+#define PWR_CR_LPDS (1U << PWR_CR_LPDS_BIT)
/* Control and status register */
/** Enable wakeup pin bit */
-#define PWR_CSR_EWUP 8
+#define PWR_CSR_EWUP_BIT 8
/** PVD output bit */
-#define PWR_CSR_PVDO 2
+#define PWR_CSR_PVDO_BIT 2
/** Standby flag bit */
-#define PWR_CSR_SBF 1
+#define PWR_CSR_SBF_BIT 1
/** Wakeup flag bit */
-#define PWR_CSR_WUF 0
+#define PWR_CSR_WUF_BIT 0
+
+/** Enable wakeup pin */
+#define PWR_CSR_EWUP (1U << PWR_CSR_EWUP_BIT)
+/** PVD output */
+#define PWR_CSR_PVDO (1U << PWR_CSR_PVDO_BIT)
+/** Standby flag */
+#define PWR_CSR_SBF (1U << PWR_CSR_SBF_BIT)
+/** Wakeup flag */
+#define PWR_CSR_WUF (1U << PWR_CSR_WUF_BIT)
/*
* Convenience functions
@@ -83,3 +111,5 @@ void pwr_init(void);
#ifdef __cplusplus
}
#endif
+
+#endif
diff --git a/libmaple/include/libmaple/rcc.h b/libmaple/include/libmaple/rcc.h
new file mode 100644
index 0000000..ea16803
--- /dev/null
+++ b/libmaple/include/libmaple/rcc.h
@@ -0,0 +1,175 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * 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/include/libmaple/rcc.h
+ * @brief Reset and Clock Control (RCC) interface.
+ */
+
+#ifndef _LIBMAPLE_RCC_H_
+#define _LIBMAPLE_RCC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/* Put the SYSCLK sources before the series header is included, as it
+ * might need them. */
+/**
+ * @brief SYSCLK sources
+ * @see rcc_switch_sysclk()
+ */
+typedef enum rcc_sysclk_src {
+ RCC_CLKSRC_HSI = 0x0,
+ RCC_CLKSRC_HSE = 0x1,
+ RCC_CLKSRC_PLL = 0x2,
+} rcc_sysclk_src;
+
+#include <series/rcc.h>
+
+/* Note: Beyond the usual (registers, etc.), it's up to the series
+ * header to define the following types:
+ *
+ * - enum rcc_clk: Available system and secondary clock sources,
+ * e.g. RCC_CLK_HSE, RCC_CLK_PLL, RCC_CLK_LSE.
+ *
+ * Note that the inclusion of secondary clock sources (like LSI and
+ * LSE) makes enum rcc_clk different from the SYSCLK sources, which
+ * are defined in this header as enum rcc_sysclk_src.
+ *
+ * IMPORTANT NOTE TO IMPLEMENTORS: If you are adding support for a
+ * new STM32 series, see the comment near rcc_clk_reg() in
+ * libmaple/rcc.c for information on how to choose these values so
+ * that rcc_turn_on_clk() etc. will work on your series.
+ *
+ * - enum rcc_clk_id: For each available peripheral. These are widely used
+ * as unique IDs (TODO extricate from RCC?). Peripherals which are
+ * common across STM32 series should use the same token for their
+ * rcc_clk_id in each series header.
+ *
+ * - enum rcc_clk_domain: For each clock domain. This is returned by
+ * rcc_dev_clk(). For instance, each AHB and APB is a clock domain.
+ *
+ * - enum rcc_prescaler: And a suitable set of dividers for
+ * rcc_set_prescaler().
+ *
+ * - enum rcc_pllsrc: For each PLL source. Same source, same token.
+ *
+ * - A target-dependent type to be pointed to by the data field in a
+ * struct rcc_pll_cfg.
+ */
+
+#ifdef __DOXYGEN__
+/** RCC register map base pointer */
+#define RCC_BASE
+#endif
+
+/* Clock prescaler management. */
+
+/**
+ * @brief Set the divider on a peripheral prescaler
+ * @param prescaler prescaler to set
+ * @param divider prescaler divider
+ */
+extern void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider);
+
+/* SYSCLK. */
+
+void rcc_switch_sysclk(rcc_sysclk_src sysclk_src);
+
+/* PLL configuration */
+
+/**
+ * @brief Specifies a configuration for the main PLL.
+ */
+typedef struct rcc_pll_cfg {
+ rcc_pllsrc pllsrc; /**< PLL source */
+
+ /** Series-specific configuration data. */
+ void *data;
+} rcc_pll_cfg;
+
+/**
+ * @brief Configure the main PLL.
+ *
+ * You may only call this function while the PLL is disabled.
+ *
+ * @param pll_cfg Desired PLL configuration. The contents of this
+ * struct depend entirely on the target.
+ */
+extern void rcc_configure_pll(rcc_pll_cfg *pll_cfg);
+
+/* System and secondary clock sources. */
+
+void rcc_turn_on_clk(rcc_clk clock);
+void rcc_turn_off_clk(rcc_clk clock);
+int rcc_is_clk_on(rcc_clk clock);
+int rcc_is_clk_ready(rcc_clk clock);
+
+/* Peripheral clock lines and clock domains. */
+
+/**
+ * @brief Turn on the clock line on a peripheral
+ * @param id Clock ID of the peripheral to turn on.
+ */
+extern void rcc_clk_enable(rcc_clk_id id);
+
+/**
+ * @brief Reset a peripheral.
+ *
+ * Caution: not all rcc_clk_id values refer to a peripheral which can
+ * be reset. (Only rcc_clk_ids for peripherals with bits in an RCC
+ * reset register can be used here.)
+ *
+ * @param id Clock ID of the peripheral to reset.
+ */
+extern void rcc_reset_dev(rcc_clk_id id);
+
+rcc_clk_domain rcc_dev_clk(rcc_clk_id id);
+
+/* Clock security system */
+
+/**
+ * @brief Enable the clock security system (CSS).
+ */
+static inline void rcc_enable_css() {
+ RCC_BASE->CR |= RCC_CR_CSSON;
+}
+
+/**
+ * @brief Disable the clock security system (CSS).
+ */
+static inline void rcc_disable_css() {
+ RCC_BASE->CR &= ~RCC_CR_CSSON;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/ring_buffer.h b/libmaple/include/libmaple/ring_buffer.h
index c443bc3..e02e6e7 100644
--- a/libmaple/ring_buffer.h
+++ b/libmaple/include/libmaple/ring_buffer.h
@@ -25,22 +25,22 @@
*****************************************************************************/
/**
- * @file ring_buffer.h
+ * @file libmaple/include/libmaple/ring_buffer.h
* @brief Simple circular buffer
*
* This implementation is not thread-safe. In particular, none of
* these functions is guaranteed re-entrant.
*/
-#ifndef _RING_BUFFER_H_
-#define _RING_BUFFER_H_
-
-#include "libmaple_types.h"
+#ifndef _LIBMAPLE_RING_BUFFER_H_
+#define _LIBMAPLE_RING_BUFFER_H_
#ifdef __cplusplus
extern "C"{
#endif
+#include <libmaple/libmaple_types.h>
+
/**
* Ring buffer type.
*
@@ -186,4 +186,3 @@ static inline void rb_reset(ring_buffer *rb) {
#endif
#endif
-
diff --git a/libmaple/scb.h b/libmaple/include/libmaple/scb.h
index feacaa5..1c7c5d7 100644
--- a/libmaple/scb.h
+++ b/libmaple/include/libmaple/scb.h
@@ -25,14 +25,18 @@
*****************************************************************************/
/**
- * @file scb.h
+ * @file libmaple/include/libmaple/scb.h
* @brief System control block header
*/
-#include "libmaple_types.h"
+#ifndef _LIBMAPLE_SCB_H_
+#define _LIBMAPLE_SCB_H_
-#ifndef _SCB_H_
-#define _SCB_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
/*
* Register map and base pointer
@@ -198,4 +202,8 @@ typedef struct scb_reg_map {
#define SCB_DFSR_BKPT BIT(1)
#define SCB_DFSR_HALTED BIT(0)
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/libmaple/spi.h b/libmaple/include/libmaple/spi.h
index f4fa4b7..fab643f 100644
--- a/libmaple/spi.h
+++ b/libmaple/include/libmaple/spi.h
@@ -1,6 +1,7 @@
/******************************************************************************
* The MIT License
*
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
* Copyright (c) 2010 Perry Hung.
*
* Permission is hereby granted, free of charge, to any person
@@ -25,7 +26,7 @@
*****************************************************************************/
/**
- * @file spi.h
+ * @file libmaple/include/libmaple/spi.h
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Serial Peripheral Interface (SPI) and Integrated
* Interchip Sound (I2S) peripheral support.
@@ -33,19 +34,18 @@
* I2S support is currently limited to register maps and bit definitions.
*/
-#ifndef _SPI_H_
-#define _SPI_H_
-
-#include "libmaple_types.h"
-#include "rcc.h"
-#include "nvic.h"
-#include "gpio.h"
-#include "util.h"
+#ifndef _LIBMAPLE_SPI_H_
+#define _LIBMAPLE_SPI_H_
#ifdef __cplusplus
extern "C" {
#endif
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+#include <libmaple/nvic.h>
+#include <series/spi.h>
+
/*
* Register maps
*/
@@ -63,13 +63,6 @@ typedef struct spi_reg_map {
__io uint32 I2SPR; /**< I2S prescaler register */
} spi_reg_map;
-/** SPI1 register map base pointer */
-#define SPI1_BASE ((struct spi_reg_map*)0x40013000)
-/** SPI2 register map base pointer */
-#define SPI2_BASE ((struct spi_reg_map*)0x40003800)
-/** SPI3 register map base pointer */
-#define SPI3_BASE ((struct spi_reg_map*)0x40003C00)
-
/*
* Register bit definitions
*/
@@ -90,20 +83,20 @@ typedef struct spi_reg_map {
#define SPI_CR1_CPOL_BIT 1
#define SPI_CR1_CPHA_BIT 0
-#define SPI_CR1_BIDIMODE BIT(SPI_CR1_BIDIMODE_BIT)
+#define SPI_CR1_BIDIMODE (1U << SPI_CR1_BIDIMODE_BIT)
#define SPI_CR1_BIDIMODE_2_LINE (0x0 << SPI_CR1_BIDIMODE_BIT)
#define SPI_CR1_BIDIMODE_1_LINE (0x1 << SPI_CR1_BIDIMODE_BIT)
-#define SPI_CR1_BIDIOE BIT(SPI_CR1_BIDIOE_BIT)
-#define SPI_CR1_CRCEN BIT(SPI_CR1_CRCEN_BIT)
-#define SPI_CR1_CRCNEXT BIT(SPI_CR1_CRCNEXT_BIT)
-#define SPI_CR1_DFF BIT(SPI_CR1_DFF_BIT)
+#define SPI_CR1_BIDIOE (1U << SPI_CR1_BIDIOE_BIT)
+#define SPI_CR1_CRCEN (1U << SPI_CR1_CRCEN_BIT)
+#define SPI_CR1_CRCNEXT (1U << SPI_CR1_CRCNEXT_BIT)
+#define SPI_CR1_DFF (1U << SPI_CR1_DFF_BIT)
#define SPI_CR1_DFF_8_BIT (0x0 << SPI_CR1_DFF_BIT)
#define SPI_CR1_DFF_16_BIT (0x1 << SPI_CR1_DFF_BIT)
-#define SPI_CR1_RXONLY BIT(SPI_CR1_RXONLY_BIT)
-#define SPI_CR1_SSM BIT(SPI_CR1_SSM_BIT)
-#define SPI_CR1_SSI BIT(SPI_CR1_SSI_BIT)
-#define SPI_CR1_LSBFIRST BIT(SPI_CR1_LSBFIRST_BIT)
-#define SPI_CR1_SPE BIT(SPI_CR1_SPE_BIT)
+#define SPI_CR1_RXONLY (1U << SPI_CR1_RXONLY_BIT)
+#define SPI_CR1_SSM (1U << SPI_CR1_SSM_BIT)
+#define SPI_CR1_SSI (1U << SPI_CR1_SSI_BIT)
+#define SPI_CR1_LSBFIRST (1U << SPI_CR1_LSBFIRST_BIT)
+#define SPI_CR1_SPE (1U << SPI_CR1_SPE_BIT)
#define SPI_CR1_BR (0x7 << 3)
#define SPI_CR1_BR_PCLK_DIV_2 (0x0 << 3)
#define SPI_CR1_BR_PCLK_DIV_4 (0x1 << 3)
@@ -113,17 +106,14 @@ typedef struct spi_reg_map {
#define SPI_CR1_BR_PCLK_DIV_64 (0x5 << 3)
#define SPI_CR1_BR_PCLK_DIV_128 (0x6 << 3)
#define SPI_CR1_BR_PCLK_DIV_256 (0x7 << 3)
-#define SPI_CR1_MSTR BIT(SPI_CR1_MSTR_BIT)
-#define SPI_CR1_CPOL BIT(SPI_CR1_CPOL_BIT)
+#define SPI_CR1_MSTR (1U << SPI_CR1_MSTR_BIT)
+#define SPI_CR1_CPOL (1U << SPI_CR1_CPOL_BIT)
#define SPI_CR1_CPOL_LOW (0x0 << SPI_CR1_CPOL_BIT)
#define SPI_CR1_CPOL_HIGH (0x1 << SPI_CR1_CPOL_BIT)
-#define SPI_CR1_CPHA BIT(SPI_CR1_CPHA_BIT)
+#define SPI_CR1_CPHA (1U << SPI_CR1_CPHA_BIT)
/* Control register 2 */
-/* RM0008-ism: SPI CR2 has "TXDMAEN" and "RXDMAEN" bits, while the
- * USARTs have CR3 "DMAR" and "DMAT" bits. */
-
#define SPI_CR2_TXEIE_BIT 7
#define SPI_CR2_RXNEIE_BIT 6
#define SPI_CR2_ERRIE_BIT 5
@@ -131,12 +121,12 @@ typedef struct spi_reg_map {
#define SPI_CR2_TXDMAEN_BIT 1
#define SPI_CR2_RXDMAEN_BIT 0
-#define SPI_CR2_TXEIE BIT(SPI_CR2_TXEIE_BIT)
-#define SPI_CR2_RXNEIE BIT(SPI_CR2_RXNEIE_BIT)
-#define SPI_CR2_ERRIE BIT(SPI_CR2_ERRIE_BIT)
-#define SPI_CR2_SSOE BIT(SPI_CR2_SSOE_BIT)
-#define SPI_CR2_TXDMAEN BIT(SPI_CR2_TXDMAEN_BIT)
-#define SPI_CR2_RXDMAEN BIT(SPI_CR2_RXDMAEN_BIT)
+#define SPI_CR2_TXEIE (1U << SPI_CR2_TXEIE_BIT)
+#define SPI_CR2_RXNEIE (1U << SPI_CR2_RXNEIE_BIT)
+#define SPI_CR2_ERRIE (1U << SPI_CR2_ERRIE_BIT)
+#define SPI_CR2_SSOE (1U << SPI_CR2_SSOE_BIT)
+#define SPI_CR2_TXDMAEN (1U << SPI_CR2_TXDMAEN_BIT)
+#define SPI_CR2_RXDMAEN (1U << SPI_CR2_RXDMAEN_BIT)
/* Status register */
@@ -149,37 +139,35 @@ typedef struct spi_reg_map {
#define SPI_SR_TXE_BIT 1
#define SPI_SR_RXNE_BIT 0
-#define SPI_SR_BSY BIT(SPI_SR_BSY_BIT)
-#define SPI_SR_OVR BIT(SPI_SR_OVR_BIT)
-#define SPI_SR_MODF BIT(SPI_SR_MODF_BIT)
-#define SPI_SR_CRCERR BIT(SPI_SR_CRCERR_BIT)
-#define SPI_SR_UDR BIT(SPI_SR_UDR_BIT)
-#define SPI_SR_CHSIDE BIT(SPI_SR_CHSIDE_BIT)
+#define SPI_SR_BSY (1U << SPI_SR_BSY_BIT)
+#define SPI_SR_OVR (1U << SPI_SR_OVR_BIT)
+#define SPI_SR_MODF (1U << SPI_SR_MODF_BIT)
+#define SPI_SR_CRCERR (1U << SPI_SR_CRCERR_BIT)
+#define SPI_SR_UDR (1U << SPI_SR_UDR_BIT)
+#define SPI_SR_CHSIDE (1U << SPI_SR_CHSIDE_BIT)
#define SPI_SR_CHSIDE_LEFT (0x0 << SPI_SR_CHSIDE_BIT)
#define SPI_SR_CHSIDE_RIGHT (0x1 << SPI_SR_CHSIDE_BIT)
-#define SPI_SR_TXE BIT(SPI_SR_TXE_BIT)
-#define SPI_SR_RXNE BIT(SPI_SR_RXNE_BIT)
+#define SPI_SR_TXE (1U << SPI_SR_TXE_BIT)
+#define SPI_SR_RXNE (1U << SPI_SR_RXNE_BIT)
/* I2S configuration register */
-/* RM0008-ism: CR1 has "CPOL", I2SCFGR has "CKPOL". */
-
#define SPI_I2SCFGR_I2SMOD_BIT 11
#define SPI_I2SCFGR_I2SE_BIT 10
#define SPI_I2SCFGR_PCMSYNC_BIT 7
#define SPI_I2SCFGR_CKPOL_BIT 3
#define SPI_I2SCFGR_CHLEN_BIT 0
-#define SPI_I2SCFGR_I2SMOD BIT(SPI_I2SCFGR_I2SMOD_BIT)
+#define SPI_I2SCFGR_I2SMOD (1U << SPI_I2SCFGR_I2SMOD_BIT)
#define SPI_I2SCFGR_I2SMOD_SPI (0x0 << SPI_I2SCFGR_I2SMOD_BIT)
#define SPI_I2SCFGR_I2SMOD_I2S (0x1 << SPI_I2SCFGR_I2SMOD_BIT)
-#define SPI_I2SCFGR_I2SE BIT(SPI_I2SCFGR_I2SE_BIT)
+#define SPI_I2SCFGR_I2SE (1U << SPI_I2SCFGR_I2SE_BIT)
#define SPI_I2SCFGR_I2SCFG (0x3 << 8)
#define SPI_I2SCFGR_I2SCFG_SLAVE_TX (0x0 << 8)
#define SPI_I2SCFGR_I2SCFG_SLAVE_RX (0x1 << 8)
#define SPI_I2SCFGR_I2SCFG_MASTER_TX (0x2 << 8)
#define SPI_I2SCFGR_I2SCFG_MASTER_RX (0x3 << 8)
-#define SPI_I2SCFGR_PCMSYNC BIT(SPI_I2SCFGR_PCMSYNC_BIT)
+#define SPI_I2SCFGR_PCMSYNC (1U << SPI_I2SCFGR_PCMSYNC_BIT)
#define SPI_I2SCFGR_PCMSYNC_SHORT (0x0 << SPI_I2SCFGR_PCMSYNC_BIT)
#define SPI_I2SCFGR_PCMSYNC_LONG (0x1 << SPI_I2SCFGR_PCMSYNC_BIT)
#define SPI_I2SCFGR_I2SSTD (0x3 << 4)
@@ -187,17 +175,26 @@ typedef struct spi_reg_map {
#define SPI_I2SCFGR_I2SSTD_MSB (0x1 << 4)
#define SPI_I2SCFGR_I2SSTD_LSB (0x2 << 4)
#define SPI_I2SCFGR_I2SSTD_PCM (0x3 << 4)
-#define SPI_I2SCFGR_CKPOL BIT(SPI_I2SCFGR_CKPOL_BIT)
+#define SPI_I2SCFGR_CKPOL (1U << SPI_I2SCFGR_CKPOL_BIT)
#define SPI_I2SCFGR_CKPOL_LOW (0x0 << SPI_I2SCFGR_CKPOL_BIT)
#define SPI_I2SCFGR_CKPOL_HIGH (0x1 << SPI_I2SCFGR_CKPOL_BIT)
#define SPI_I2SCFGR_DATLEN (0x3 << 1)
#define SPI_I2SCFGR_DATLEN_16_BIT (0x0 << 1)
#define SPI_I2SCFGR_DATLEN_24_BIT (0x1 << 1)
#define SPI_I2SCFGR_DATLEN_32_BIT (0x2 << 1)
-#define SPI_I2SCFGR_CHLEN BIT(SPI_I2SCFGR_CHLEN_BIT)
+#define SPI_I2SCFGR_CHLEN (1U << SPI_I2SCFGR_CHLEN_BIT)
#define SPI_I2SCFGR_CHLEN_16_BIT (0x0 << SPI_I2SCFGR_CHLEN_BIT)
#define SPI_I2SCFGR_CHLEN_32_BIT (0x1 << SPI_I2SCFGR_CHLEN_BIT)
+/* I2S prescaler register */
+
+#define SPI_I2SPR_MCKOE_BIT 9
+#define SPI_I2SPR_ODD_BIT 8
+
+#define SPI_I2SPR_MCKOE (1U << SPI_I2SPR_MCKOE_BIT)
+#define SPI_I2SPR_ODD (1U << SPI_I2SPR_ODD_BIT)
+#define SPI_I2SPR_I2SDIV 0xFF
+
/*
* Devices
*/
@@ -209,42 +206,54 @@ typedef struct spi_dev {
nvic_irq_num irq_num; /**< NVIC interrupt number */
} spi_dev;
-extern spi_dev *SPI1;
-extern spi_dev *SPI2;
-#ifdef STM32_HIGH_DENSITY
-extern spi_dev *SPI3;
-#endif
-
/*
* SPI Convenience functions
*/
void spi_init(spi_dev *dev);
-void spi_gpio_cfg(uint8 as_master,
- gpio_dev *nss_dev,
- uint8 nss_bit,
- gpio_dev *comm_dev,
- uint8 sck_bit,
- uint8 miso_bit,
- uint8 mosi_bit);
+struct gpio_dev;
+/**
+ * @brief Configure GPIO bit modes for use as a SPI port's pins.
+ * @param as_master If true, configure bits for use as a bus master.
+ * Otherwise, configure bits for use as slave.
+ * @param nss_dev NSS pin's GPIO device
+ * @param comm_dev SCK, MISO, MOSI pins' GPIO device
+ * @param nss_bit NSS pin's GPIO bit on nss_dev
+ * @param sck_bit SCK pin's GPIO bit on comm_dev
+ * @param miso_bit MISO pin's GPIO bit on comm_dev
+ * @param mosi_bit MOSI pin's GPIO bit on comm_dev
+ */
+extern void spi_config_gpios(spi_dev *dev,
+ uint8 as_master,
+ struct gpio_dev *nss_dev,
+ uint8 nss_bit,
+ struct gpio_dev *comm_dev,
+ uint8 sck_bit,
+ uint8 miso_bit,
+ uint8 mosi_bit);
/**
* @brief SPI mode configuration.
*
- * Determines a combination of clock polarity (CPOL), which determines
- * idle state of the clock line, and clock phase (CPHA), which
- * determines which clock edge triggers data capture.
+ * A SPI mode determines a combination of the idle state of the clock
+ * line (the clock polarity, or "CPOL"), and which clock edge triggers
+ * data capture (the clock phase, or "CPHA").
*/
typedef enum spi_mode {
- SPI_MODE_0, /**< Clock line idles low (0), data capture on first
- clock transition. */
- SPI_MODE_1, /**< Clock line idles low (0), data capture on second
- clock transition */
- SPI_MODE_2, /**< Clock line idles high (1), data capture on first
- clock transition. */
- SPI_MODE_3 /**< Clock line idles high (1), data capture on
- second clock transition. */
+ /** Clock idles low, data captured on rising edge (first transition) */
+ SPI_MODE_LOW_RISING = 0,
+ /** Clock idles low, data captured on falling edge (second transition) */
+ SPI_MODE_LOW_FALLING = 1,
+ /** Clock idles high, data captured on falling edge (first transition) */
+ SPI_MODE_HIGH_FALLING = 2,
+ /** Clock idles high, data captured on rising edge (second transition) */
+ SPI_MODE_HIGH_RISING = 3,
+
+ SPI_MODE_0 = SPI_MODE_LOW_RISING, /**< Same as SPI_MODE_LOW_RISING */
+ SPI_MODE_1 = SPI_MODE_LOW_FALLING, /**< Same as SPI_MODE_LOW_FALLING */
+ SPI_MODE_2 = SPI_MODE_HIGH_FALLING, /**< Same as SPI_MODE_HIGH_FALLING */
+ SPI_MODE_3 = SPI_MODE_HIGH_RISING, /**< Same as SPI_MODE_HIGH_RISING */
} spi_mode;
/**
@@ -299,7 +308,11 @@ void spi_slave_enable(spi_dev *dev,
uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len);
-void spi_foreach(void (*fn)(spi_dev (*dev)));
+/**
+ * @brief Call a function on each SPI port
+ * @param fn Function to call.
+ */
+extern void spi_foreach(void (*fn)(spi_dev*));
void spi_peripheral_enable(spi_dev *dev);
void spi_peripheral_disable(spi_dev *dev);
diff --git a/libmaple/include/libmaple/stm32.h b/libmaple/include/libmaple/stm32.h
new file mode 100644
index 0000000..3845cab
--- /dev/null
+++ b/libmaple/include/libmaple/stm32.h
@@ -0,0 +1,237 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, 2011, 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/include/libmaple/stm32.h
+ * @brief STM32 chip header
+ *
+ * This header supplies various chip-specific values for the current
+ * build target. It's useful both to abstract away hardware details
+ * (e.g. through use of STM32_NR_INTERRUPTS) and to decide what to do
+ * when you want something nonportable (e.g. by checking
+ * STM32_MCU_SERIES).
+ */
+
+#ifndef _LIBMAPLE_STM32_H_
+#define _LIBMAPLE_STM32_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * STM32 series identifiers.
+ *
+ * Don't make these into an enum; the preprocessor needs them.
+ */
+
+/** STM32F1 series. */
+#define STM32_SERIES_F1 0
+/** STM32F2 series. */
+#define STM32_SERIES_F2 1
+/** STM32L1 series. */
+#define STM32_SERIES_L1 2
+/** STM32F4 series. */
+#define STM32_SERIES_F4 3
+
+/* The series header is responsible for defining:
+ *
+ * - Everything in the following __DOXYGEN__ conditional block.
+ *
+ * - STM32_HAVE_FSMC: 1 if the MCU has the FSMC peripheral, and 0
+ * otherwise.
+ *
+ * - STM32_HAVE_USB: 1 if the MCU has a USB peripheral, and 0
+ * otherwise.
+ */
+#include <series/stm32.h>
+
+/* Ensure the series header isn't broken. */
+#if (!defined(STM32_PCLK1) || \
+ !defined(STM32_PCLK2) || \
+ !defined(STM32_MCU_SERIES) || \
+ !defined(STM32_NR_INTERRUPTS) || \
+ !defined(STM32_NR_GPIO_PORTS) || \
+ !defined(STM32_TIMER_MASK) || \
+ !defined(STM32_DELAY_US_MULT) || \
+ !defined(STM32_SRAM_END) || \
+ !defined(STM32_HAVE_DAC) || \
+ !defined(STM32_HAVE_FSMC) || \
+ !defined(STM32_HAVE_USB))
+#error "Bad STM32F1 configuration. Check <series/stm32.h> header for your MCU."
+#endif
+
+/*
+ * Derived macros
+ */
+
+/* FIXME [0.0.13] add this to ReST API page */
+/**
+ * @brief Statically determine whether a timer is present.
+ *
+ * Given a constant timer number n (starting from 1), this macro has a
+ * nonzero value exactly when TIMERn is available.
+ */
+#define STM32_HAVE_TIMER(n) (STM32_TIMER_MASK & (1 << (n)))
+
+/*
+ * Doxygen for functionality provided by series header.
+ */
+
+#ifdef __DOXYGEN__
+
+/*
+ * Clock configuration.
+ *
+ * These defines depend upon how the MCU is configured. Because of
+ * the potential for a mismatch between them and the actual clock
+ * configuration, keep their number to a minimum.
+ */
+
+/**
+ * @brief APB1 clock speed, in Hz.
+ */
+#define STM32_PCLK1
+
+/**
+ * @brief APB2 clock speed, in Hz.
+ */
+#define STM32_PCLK2
+
+/** @brief Deprecated. Use STM32_PCLK1 instead. */
+#define PCLK1
+/** @brief Deprecated. Use STM32_PCLK2 instead. */
+#define PCLK2
+
+/*
+ * Series- and MCU-specific values.
+ */
+
+/**
+ * @brief STM32 series value for the MCU being targeted.
+ *
+ * At time of writing, allowed values are: STM32_SERIES_F1,
+ * STM32_SERIES_F2. This set of values will expand as libmaple adds
+ * support for more STM32 series MCUs.
+ */
+#define STM32_MCU_SERIES
+
+/**
+ * @brief Number of interrupts in the vector table.
+ *
+ * This does not include Cortex-M interrupts (NMI, HardFault, etc.).
+ */
+#define STM32_NR_INTERRUPTS
+
+/**
+ * Number of GPIO ports.
+ */
+#define STM32_NR_GPIO_PORTS
+
+/* FIXME [0.0.13] add this to ReST API page */
+/**
+ * @brief Bitmask of timers available on the MCU.
+ *
+ * That is, if TIMERn is available, then STM32_TIMER_MASK & (1 << n)
+ * will be nonzero. For example, a nonzero value of "STM32_TIMER_MASK
+ * & 0x2" means TIMER1 is available.
+ *
+ * A bitmask is necessary as some STM32 MCUs have "holes" in the range
+ * of available timers.
+ */
+#define STM32_TIMER_MASK
+
+/**
+ * @brief Multiplier to convert microseconds into loop iterations
+ * in delay_us().
+ *
+ * @see delay_us()
+ */
+#define STM32_DELAY_US_MULT
+
+/**
+ * @brief Pointer to end of built-in SRAM.
+ *
+ * Points to the address which is 1 byte past the last valid
+ * SRAM address.
+ */
+#define STM32_SRAM_END
+
+/**
+ * @brief 1 if the target MCU has a DAC, and 0 otherwise.
+ */
+#define STM32_HAVE_DAC
+
+/**
+ * @brief 1 if the target MCU has the FSMC peripheral, and 0 otherwise.
+ *
+ * Note that the feature set of the FSMC peripheral is restricted on
+ * some MCUs.
+ */
+#define STM32_HAVE_FSMC
+
+/**
+ * @brief 1 if the target MCU has a USB peripheral, and 0 otherwise.
+ *
+ * Note that a variety of USB peripherals are available across the
+ * different series, with widely varying feature sets and programming
+ * interfaces. This macro will be 1 if any such peripheral is present.
+ */
+#define STM32_HAVE_USB
+
+#endif /* __DOXYGEN__ */
+
+/*
+ * The following are for backwards compatibility only.
+ */
+
+/* PCLK1 and PCLK2 are for backwards compatibility only; don't use in
+ * new code. */
+#ifndef PCLK1
+#define PCLK1 STM32_PCLK1
+#endif
+#if PCLK1 != STM32_PCLK1
+#error "PCLK1 (which is deprecated) differs from STM32_PCLK1."
+#endif
+#ifndef PCLK2
+#define PCLK2 STM32_PCLK2
+#endif
+#if PCLK2 != STM32_PCLK2
+#error "PCLK2 (which is deprecated) differs from STM32_PCLK2."
+#endif
+
+/** @brief Deprecated. Use STM32_NR_INTERRUPTS instead. */
+#define NR_INTERRUPTS STM32_NR_INTERRUPTS
+/** @brief Deprecated. Use STM32_NR_GPIO_PORTS instead. */
+#define NR_GPIO_PORTS STM32_NR_GPIO_PORTS
+/** @brief Deprecated. Use STM32_DELAY_US_MULT instead. */
+#define DELAY_US_MULT STM32_DELAY_US_MULT
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/syscfg.h b/libmaple/include/libmaple/syscfg.h
new file mode 100644
index 0000000..6b375d3
--- /dev/null
+++ b/libmaple/include/libmaple/syscfg.h
@@ -0,0 +1,151 @@
+/******************************************************************************
+ * 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/include/libmaple/syscfg.h
+ * @brief System configuration controller (SYSCFG)
+ *
+ * Availability: STM32F2, STM32F4.
+ */
+
+#ifndef _LIBMAPLE_SYSCFG_H_
+#define _LIBMAPLE_SYSCFG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map and base pointer
+ */
+
+/**
+ * @brief SYSCFG register map type.
+ */
+typedef struct syscfg_reg_map {
+ __io uint32 MEMRMP; /**< Memory remap register */
+ __io uint32 PMC; /**< Peripheral mode configuration */
+ __io uint32 EXTICR[4]; /**< External interrupt configuration registers */
+ const uint32 RESERVED1;
+ const uint32 RESERVED2;
+ __io uint32 CMPCR; /**< Compensation cell control register */
+} syscfg_reg_map;
+
+/** SYSCFG register map base pointer */
+#define SYSCFG_BASE ((struct syscfg_reg_map*)0x40013800)
+
+/*
+ * Register bit definitions
+ */
+
+/* Memory remap register */
+
+#define SYSCFG_MEMRMP_MEM_MODE 0x3
+#define SYSCFG_MEMRMP_MEM_MODE_FLASH 0x0
+#define SYSCFG_MEMRMP_MEM_MODE_SYS_FLASH 0x1
+#define SYSCFG_MEMRMP_MEM_MODE_FSMC_1 0x2
+#define SYSCFG_MEMRMP_MEM_MODE_EMB_SRAM 0x3
+
+/* Peripheral mode configuration register */
+
+#define SYSCFG_PMC_MII_RMII_SEL_BIT 23
+
+#define SYSCFG_PMC_MII_RMII_SEL (1U << SYSCFG_PMC_MII_RMII_SEL_BIT)
+#define SYSCFG_PMC_MII_RMII_SEL_MII (0U << SYSCFG_PMC_MII_RMII_SEL_BIT)
+#define SYSCFG_PMC_MII_RMII_SEL_RMII (1U << SYSCFG_PMC_MII_RMII_SEL_BIT)
+
+/* External interrupt configuration register 1 */
+
+#define SYSCFG_EXTICR1_EXTI0 0xF
+#define SYSCFG_EXTICR1_EXTI1 0xF0
+#define SYSCFG_EXTICR1_EXTI2 0xF00
+#define SYSCFG_EXTICR1_EXTI3 0xF000
+
+/* External interrupt configuration register 2 */
+
+#define SYSCFG_EXTICR2_EXTI4 0xF
+#define SYSCFG_EXTICR2_EXTI5 0xF0
+#define SYSCFG_EXTICR2_EXTI6 0xF00
+#define SYSCFG_EXTICR2_EXTI7 0xF000
+
+/* External interrupt configuration register 3 */
+
+#define SYSCFG_EXTICR3_EXTI8 0xF
+#define SYSCFG_EXTICR3_EXTI9 0xF0
+#define SYSCFG_EXTICR3_EXTI10 0xF00
+#define SYSCFG_EXTICR3_EXTI11 0xF000
+
+/* External interrupt configuration register 4 */
+
+#define SYSCFG_EXTICR4_EXTI12 0xF
+#define SYSCFG_EXTICR4_EXTI13 0xF0
+#define SYSCFG_EXTICR4_EXTI14 0xF00
+#define SYSCFG_EXTICR4_EXTI15 0xF000
+
+/* Compensation cell control register */
+
+#define SYSCFG_CMPCR_READY_BIT 8
+#define SYSCFG_CMPCR_CMP_PD_BIT 0
+
+#define SYSCFG_CMPCR_READY (1U << SYSCFG_CMPCR_READY_BIT)
+#define SYSCFG_CMPCR_CMP_PD (1U << SYSCFG_CMPCR_CMP_PD_BIT)
+#define SYSCFG_CMPCR_CMP_PD_PDWN (0U << SYSCFG_CMPCR_CMP_PD_BIT)
+#define SYSCFG_CMPCR_CMP_PD_ENABLE (1U << SYSCFG_CMPCR_CMP_PD_BIT)
+
+/*
+ * Routines
+ */
+
+void syscfg_init(void);
+
+void syscfg_enable_io_compensation(void);
+void syscfg_disable_io_compensation(void);
+
+/**
+ * @brief System memory mode
+ * These values specify what memory to map to address 0x00000000.
+ * @see syscfg_set_mem_mode
+ */
+typedef enum syscfg_mem_mode {
+ /** Main flash memory is mapped at 0x0. */
+ SYCFG_MEM_MODE_FLASH = SYSCFG_MEMRMP_MEM_MODE_FLASH,
+ /** System flash (i.e. ST's baked-in bootloader) is mapped at 0x0. */
+ SYCFG_MEM_MODE_SYSTEM_FLASH = SYSCFG_MEMRMP_MEM_MODE_SYS_FLASH,
+ /** FSMC bank 1 (NOR/PSRAM 1 and 2) is mapped at 0x0. */
+ SYCFG_MEM_MODE_FSMC_BANK_1 = SYSCFG_MEMRMP_MEM_MODE_FSMC_1,
+ /** Embedded SRAM (i.e., not backup SRAM) is mapped at 0x0. */
+ SYCFG_MEM_MODE_SRAM = SYSCFG_MEMRMP_MEM_MODE_EMB_SRAM,
+} syscfg_mem_mode;
+
+void syscfg_set_mem_mode(syscfg_mem_mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/systick.h b/libmaple/include/libmaple/systick.h
index 6ec3364..551f800 100644
--- a/libmaple/systick.h
+++ b/libmaple/include/libmaple/systick.h
@@ -25,21 +25,20 @@
*****************************************************************************/
/**
- * @file systick.h
- *
- * @brief Various system timer definitions
+ * @file libmaple/include/libmaple/systick.h
+ * @brief System timer definitions
*/
-#ifndef _SYSTICK_H_
-#define _SYSTICK_H_
-
-#include "libmaple_types.h"
-#include "util.h"
+#ifndef _LIBMAPLE_SYSTICK_H_
+#define _LIBMAPLE_SYSTICK_H_
#ifdef __cplusplus
extern "C"{
#endif
+#include <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
+
/** SysTick register map type */
typedef struct systick_reg_map {
__io uint32 CSR; /**< Control and status register */
@@ -114,4 +113,3 @@ static inline uint32 systick_check_underflow(void) {
#endif
#endif
-
diff --git a/libmaple/timer.h b/libmaple/include/libmaple/timer.h
index 53e2547..995f868 100644
--- a/libmaple/timer.h
+++ b/libmaple/include/libmaple/timer.h
@@ -1,7 +1,7 @@
/******************************************************************************
* The MIT License
*
- * Copyright (c) 2011 LeafLabs, LLC.
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,27 +25,26 @@
*****************************************************************************/
/**
- * @file timer.h
+ * @file libmaple/include/libmaple/timer.h
* @author Marti Bolivar <mbolivar@leaflabs.com>
- * @brief New-style timer interface.
- *
- * Replaces old timers.h implementation.
+ * @brief Timer interface.
*/
-#ifndef _TIMERS_H_
-#define _TIMERS_H_
-
-#include "libmaple.h"
-#include "rcc.h"
-#include "nvic.h"
-#include "bitband.h"
+#ifndef _LIBMAPLE_TIMER_H_
+#define _LIBMAPLE_TIMER_H_
#ifdef __cplusplus
extern "C"{
#endif
+#include <series/timer.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
+#include <libmaple/nvic.h>
+#include <libmaple/bitband.h>
+
/*
- * Register maps and devices
+ * Register maps
*/
/** Advanced control timer register map type */
@@ -53,7 +52,7 @@ typedef struct timer_adv_reg_map {
__io uint32 CR1; /**< Control register 1 */
__io uint32 CR2; /**< Control register 2 */
__io uint32 SMCR; /**< Slave mode control register */
- __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 DIER; /**< DMA/interrupt enable register */
__io uint32 SR; /**< Status register */
__io uint32 EGR; /**< Event generation register */
__io uint32 CCMR1; /**< Capture/compare mode register 1 */
@@ -72,36 +71,17 @@ typedef struct timer_adv_reg_map {
__io uint32 DMAR; /**< DMA address for full transfer */
} timer_adv_reg_map;
-/** General purpose timer register map type */
-typedef struct timer_gen_reg_map {
- __io uint32 CR1; /**< Control register 1 */
- __io uint32 CR2; /**< Control register 2 */
- __io uint32 SMCR; /**< Slave mode control register */
- __io uint32 DIER; /**< DMA/Interrupt enable register */
- __io uint32 SR; /**< Status register */
- __io uint32 EGR; /**< Event generation register */
- __io uint32 CCMR1; /**< Capture/compare mode register 1 */
- __io uint32 CCMR2; /**< Capture/compare mode register 2 */
- __io uint32 CCER; /**< Capture/compare enable register */
- __io uint32 CNT; /**< Counter */
- __io uint32 PSC; /**< Prescaler */
- __io uint32 ARR; /**< Auto-reload register */
- const uint32 RESERVED1; /**< Reserved */
- __io uint32 CCR1; /**< Capture/compare register 1 */
- __io uint32 CCR2; /**< Capture/compare register 2 */
- __io uint32 CCR3; /**< Capture/compare register 3 */
- __io uint32 CCR4; /**< Capture/compare register 4 */
- const uint32 RESERVED2; /**< Reserved */
- __io uint32 DCR; /**< DMA control register */
- __io uint32 DMAR; /**< DMA address for full transfer */
-} timer_gen_reg_map;
+/* General purpose timer register map type: intentionally omitted.
+ *
+ * General purpose timers differ slightly across series, so leave it
+ * up to the series header to define struct timer_gen_reg_map. */
/** Basic timer register map type */
typedef struct timer_bas_reg_map {
__io uint32 CR1; /**< Control register 1 */
__io uint32 CR2; /**< Control register 2 */
const uint32 RESERVED1; /**< Reserved */
- __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 DIER; /**< DMA/interrupt enable register */
__io uint32 SR; /**< Status register */
__io uint32 EGR; /**< Event generation register */
const uint32 RESERVED2; /**< Reserved */
@@ -112,25 +92,6 @@ typedef struct timer_bas_reg_map {
__io uint32 ARR; /**< Auto-reload register */
} timer_bas_reg_map;
-/** Timer 1 register map base pointer */
-#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00)
-/** Timer 2 register map base pointer */
-#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000)
-/** Timer 3 register map base pointer */
-#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400)
-/** Timer 4 register map base pointer */
-#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800)
-#ifdef STM32_HIGH_DENSITY
-/** Timer 5 register map base pointer */
-#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00)
-/** Timer 6 register map base pointer */
-#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000)
-/** Timer 7 register map base pointer */
-#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400)
-/** Timer 8 register map base pointer */
-#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400)
-#endif
-
/*
* Timer devices
*/
@@ -157,7 +118,7 @@ typedef union timer_reg_map {
typedef enum timer_type {
TIMER_ADVANCED, /**< Advanced type */
TIMER_GENERAL, /**< General purpose type */
- TIMER_BASIC /**< Basic type */
+ TIMER_BASIC, /**< Basic type */
} timer_type;
/** Timer device type */
@@ -165,19 +126,54 @@ typedef struct timer_dev {
timer_reg_map regs; /**< Register map */
rcc_clk_id clk_id; /**< RCC clock information */
timer_type type; /**< Timer's type */
- voidFuncPtr handlers[]; /**< User IRQ handlers */
+ voidFuncPtr handlers[]; /**<
+ * Don't touch these. Use these instead:
+ * @see timer_attach_interrupt()
+ * @see timer_detach_interrupt() */
} timer_dev;
+#if STM32_HAVE_TIMER(1)
extern timer_dev *TIMER1;
+#endif
+#if STM32_HAVE_TIMER(2)
extern timer_dev *TIMER2;
+#endif
+#if STM32_HAVE_TIMER(3)
extern timer_dev *TIMER3;
+#endif
+#if STM32_HAVE_TIMER(4)
extern timer_dev *TIMER4;
-#ifdef STM32_HIGH_DENSITY
+#endif
+#if STM32_HAVE_TIMER(5)
extern timer_dev *TIMER5;
+#endif
+#if STM32_HAVE_TIMER(6)
extern timer_dev *TIMER6;
+#endif
+#if STM32_HAVE_TIMER(7)
extern timer_dev *TIMER7;
+#endif
+#if STM32_HAVE_TIMER(8)
extern timer_dev *TIMER8;
#endif
+#if STM32_HAVE_TIMER(9)
+extern timer_dev *TIMER9;
+#endif
+#if STM32_HAVE_TIMER(10)
+extern timer_dev *TIMER10;
+#endif
+#if STM32_HAVE_TIMER(11)
+extern timer_dev *TIMER11;
+#endif
+#if STM32_HAVE_TIMER(12)
+extern timer_dev *TIMER12;
+#endif
+#if STM32_HAVE_TIMER(13)
+extern timer_dev *TIMER13;
+#endif
+#if STM32_HAVE_TIMER(14)
+extern timer_dev *TIMER14;
+#endif
/*
* Register bit definitions
@@ -196,17 +192,17 @@ extern timer_dev *TIMER8;
#define TIMER_CR1_CKD_1TCKINT (0x0 << 8)
#define TIMER_CR1_CKD_2TCKINT (0x1 << 8)
#define TIMER_CR1_CKD_4TICKINT (0x2 << 8)
-#define TIMER_CR1_ARPE BIT(TIMER_CR1_ARPE_BIT)
+#define TIMER_CR1_ARPE (1U << TIMER_CR1_ARPE_BIT)
#define TIMER_CR1_CKD_CMS (0x3 << 5)
#define TIMER_CR1_CKD_CMS_EDGE (0x0 << 5)
#define TIMER_CR1_CKD_CMS_CENTER1 (0x1 << 5)
#define TIMER_CR1_CKD_CMS_CENTER2 (0x2 << 5)
#define TIMER_CR1_CKD_CMS_CENTER3 (0x3 << 5)
-#define TIMER_CR1_DIR BIT(TIMER_CR1_DIR_BIT)
-#define TIMER_CR1_OPM BIT(TIMER_CR1_OPM_BIT)
-#define TIMER_CR1_URS BIT(TIMER_CR1_URS_BIT)
-#define TIMER_CR1_UDIS BIT(TIMER_CR1_UDIS_BIT)
-#define TIMER_CR1_CEN BIT(TIMER_CR1_CEN_BIT)
+#define TIMER_CR1_DIR (1U << TIMER_CR1_DIR_BIT)
+#define TIMER_CR1_OPM (1U << TIMER_CR1_OPM_BIT)
+#define TIMER_CR1_URS (1U << TIMER_CR1_URS_BIT)
+#define TIMER_CR1_UDIS (1U << TIMER_CR1_UDIS_BIT)
+#define TIMER_CR1_CEN (1U << TIMER_CR1_CEN_BIT)
/* Control register 2 (CR2) */
@@ -217,19 +213,19 @@ extern timer_dev *TIMER8;
#define TIMER_CR2_OIS2_BIT 10
#define TIMER_CR2_OIS1N_BIT 9
#define TIMER_CR2_OIS1_BIT 8
-#define TIMER_CR2_TI1S_BIT 7 /* tills? yikes */
+#define TIMER_CR2_TI1S_BIT 7
#define TIMER_CR2_CCDS_BIT 3
#define TIMER_CR2_CCUS_BIT 2
#define TIMER_CR2_CCPC_BIT 0
-#define TIMER_CR2_OIS4 BIT(TIMER_CR2_OIS4_BIT)
-#define TIMER_CR2_OIS3N BIT(TIMER_CR2_OIS3N_BIT)
-#define TIMER_CR2_OIS3 BIT(TIMER_CR2_OIS3_BIT)
-#define TIMER_CR2_OIS2N BIT(TIMER_CR2_OIS2N_BIT)
-#define TIMER_CR2_OIS2 BIT(TIMER_CR2_OIS2_BIT)
-#define TIMER_CR2_OIS1N BIT(TIMER_CR2_OIS1N_BIT)
-#define TIMER_CR2_OIS1 BIT(TIMER_CR2_OIS1_BIT)
-#define TIMER_CR2_TI1S BIT(TIMER_CR2_TI1S_BIT)
+#define TIMER_CR2_OIS4 (1U << TIMER_CR2_OIS4_BIT)
+#define TIMER_CR2_OIS3N (1U << TIMER_CR2_OIS3N_BIT)
+#define TIMER_CR2_OIS3 (1U << TIMER_CR2_OIS3_BIT)
+#define TIMER_CR2_OIS2N (1U << TIMER_CR2_OIS2N_BIT)
+#define TIMER_CR2_OIS2 (1U << TIMER_CR2_OIS2_BIT)
+#define TIMER_CR2_OIS1N (1U << TIMER_CR2_OIS1N_BIT)
+#define TIMER_CR2_OIS1 (1U << TIMER_CR2_OIS1_BIT)
+#define TIMER_CR2_TI1S (1U << TIMER_CR2_TI1S_BIT)
#define TIMER_CR2_MMS (0x7 << 4)
#define TIMER_CR2_MMS_RESET (0x0 << 4)
#define TIMER_CR2_MMS_ENABLE (0x1 << 4)
@@ -239,9 +235,9 @@ extern timer_dev *TIMER8;
#define TIMER_CR2_MMS_COMPARE_OC2REF (0x5 << 4)
#define TIMER_CR2_MMS_COMPARE_OC3REF (0x6 << 4)
#define TIMER_CR2_MMS_COMPARE_OC4REF (0x7 << 4)
-#define TIMER_CR2_CCDS BIT(TIMER_CR2_CCDS_BIT)
-#define TIMER_CR2_CCUS BIT(TIMER_CR2_CCUS_BIT)
-#define TIMER_CR2_CCPC BIT(TIMER_CR2_CCPC_BIT)
+#define TIMER_CR2_CCDS (1U << TIMER_CR2_CCDS_BIT)
+#define TIMER_CR2_CCUS (1U << TIMER_CR2_CCUS_BIT)
+#define TIMER_CR2_CCPC (1U << TIMER_CR2_CCPC_BIT)
/* Slave mode control register (SMCR) */
@@ -249,15 +245,15 @@ extern timer_dev *TIMER8;
#define TIMER_SMCR_ECE_BIT 14
#define TIMER_SMCR_MSM_BIT 7
-#define TIMER_SMCR_ETP BIT(TIMER_SMCR_ETP_BIT)
-#define TIMER_SMCR_ECE BIT(TIMER_SMCR_ECE_BIT)
+#define TIMER_SMCR_ETP (1U << TIMER_SMCR_ETP_BIT)
+#define TIMER_SMCR_ECE (1U << TIMER_SMCR_ECE_BIT)
#define TIMER_SMCR_ETPS (0x3 << 12)
#define TIMER_SMCR_ETPS_OFF (0x0 << 12)
#define TIMER_SMCR_ETPS_DIV2 (0x1 << 12)
#define TIMER_SMCR_ETPS_DIV4 (0x2 << 12)
#define TIMER_SMCR_ETPS_DIV8 (0x3 << 12)
#define TIMER_SMCR_ETF (0xF << 12)
-#define TIMER_SMCR_MSM BIT(TIMER_SMCR_MSM_BIT)
+#define TIMER_SMCR_MSM (1U << TIMER_SMCR_MSM_BIT)
#define TIMER_SMCR_TS (0x3 << 4)
#define TIMER_SMCR_TS_ITR0 (0x0 << 4)
#define TIMER_SMCR_TS_ITR1 (0x1 << 4)
@@ -280,30 +276,36 @@ extern timer_dev *TIMER8;
/* DMA/Interrupt enable register (DIER) */
#define TIMER_DIER_TDE_BIT 14
+#define TIMER_DIER_COMDE_BIT 13
#define TIMER_DIER_CC4DE_BIT 12
#define TIMER_DIER_CC3DE_BIT 11
#define TIMER_DIER_CC2DE_BIT 10
#define TIMER_DIER_CC1DE_BIT 9
#define TIMER_DIER_UDE_BIT 8
+#define TIMER_DIER_BIE_BIT 7
#define TIMER_DIER_TIE_BIT 6
+#define TIMER_DIER_COMIE_BIT 5
#define TIMER_DIER_CC4IE_BIT 4
#define TIMER_DIER_CC3IE_BIT 3
#define TIMER_DIER_CC2IE_BIT 2
#define TIMER_DIER_CC1IE_BIT 1
#define TIMER_DIER_UIE_BIT 0
-#define TIMER_DIER_TDE BIT(TIMER_DIER_TDE_BIT)
-#define TIMER_DIER_CC4DE BIT(TIMER_DIER_CC4DE_BIT)
-#define TIMER_DIER_CC3DE BIT(TIMER_DIER_CC3DE_BIT)
-#define TIMER_DIER_CC2DE BIT(TIMER_DIER_CC2DE_BIT)
-#define TIMER_DIER_CC1DE BIT(TIMER_DIER_CC1DE_BIT)
-#define TIMER_DIER_UDE BIT(TIMER_DIER_UDE_BIT)
-#define TIMER_DIER_TIE BIT(TIMER_DIER_TIE_BIT)
-#define TIMER_DIER_CC4IE BIT(TIMER_DIER_CC4IE_BIT)
-#define TIMER_DIER_CC3IE BIT(TIMER_DIER_CC3IE_BIT)
-#define TIMER_DIER_CC2IE BIT(TIMER_DIER_CC2IE_BIT)
-#define TIMER_DIER_CC1IE BIT(TIMER_DIER_CC1IE_BIT)
-#define TIMER_DIER_UIE BIT(TIMER_DIER_UIE_BIT)
+#define TIMER_DIER_TDE (1U << TIMER_DIER_TDE_BIT)
+#define TIMER_DIER_COMDE (1U << TIMER_DIER_COMDE_BIT)
+#define TIMER_DIER_CC4DE (1U << TIMER_DIER_CC4DE_BIT)
+#define TIMER_DIER_CC3DE (1U << TIMER_DIER_CC3DE_BIT)
+#define TIMER_DIER_CC2DE (1U << TIMER_DIER_CC2DE_BIT)
+#define TIMER_DIER_CC1DE (1U << TIMER_DIER_CC1DE_BIT)
+#define TIMER_DIER_UDE (1U << TIMER_DIER_UDE_BIT)
+#define TIMER_DIER_BIE (1U << TIMER_DIER_BIE_BIT)
+#define TIMER_DIER_TIE (1U << TIMER_DIER_TIE_BIT)
+#define TIMER_DIER_COMIE (1U << TIMER_DIER_COMIE_BIT)
+#define TIMER_DIER_CC4IE (1U << TIMER_DIER_CC4IE_BIT)
+#define TIMER_DIER_CC3IE (1U << TIMER_DIER_CC3IE_BIT)
+#define TIMER_DIER_CC2IE (1U << TIMER_DIER_CC2IE_BIT)
+#define TIMER_DIER_CC1IE (1U << TIMER_DIER_CC1IE_BIT)
+#define TIMER_DIER_UIE (1U << TIMER_DIER_UIE_BIT)
/* Status register (SR) */
@@ -320,34 +322,38 @@ extern timer_dev *TIMER8;
#define TIMER_SR_CC1IF_BIT 1
#define TIMER_SR_UIF_BIT 0
-#define TIMER_SR_CC4OF BIT(TIMER_SR_CC4OF_BIT)
-#define TIMER_SR_CC3OF BIT(TIMER_SR_CC3OF_BIT)
-#define TIMER_SR_CC2OF BIT(TIMER_SR_CC2OF_BIT)
-#define TIMER_SR_CC1OF BIT(TIMER_SR_CC1OF_BIT)
-#define TIMER_SR_BIF BIT(TIMER_SR_BIF_BIT)
-#define TIMER_SR_TIF BIT(TIMER_SR_TIF_BIT)
-#define TIMER_SR_COMIF BIT(TIMER_SR_COMIF_BIT)
-#define TIMER_SR_CC4IF BIT(TIMER_SR_CC4IF_BIT)
-#define TIMER_SR_CC3IF BIT(TIMER_SR_CC3IF_BIT)
-#define TIMER_SR_CC2IF BIT(TIMER_SR_CC2IF_BIT)
-#define TIMER_SR_CC1IF BIT(TIMER_SR_CC1IF_BIT)
-#define TIMER_SR_UIF BIT(TIMER_SR_UIF_BIT)
+#define TIMER_SR_CC4OF (1U << TIMER_SR_CC4OF_BIT)
+#define TIMER_SR_CC3OF (1U << TIMER_SR_CC3OF_BIT)
+#define TIMER_SR_CC2OF (1U << TIMER_SR_CC2OF_BIT)
+#define TIMER_SR_CC1OF (1U << TIMER_SR_CC1OF_BIT)
+#define TIMER_SR_BIF (1U << TIMER_SR_BIF_BIT)
+#define TIMER_SR_TIF (1U << TIMER_SR_TIF_BIT)
+#define TIMER_SR_COMIF (1U << TIMER_SR_COMIF_BIT)
+#define TIMER_SR_CC4IF (1U << TIMER_SR_CC4IF_BIT)
+#define TIMER_SR_CC3IF (1U << TIMER_SR_CC3IF_BIT)
+#define TIMER_SR_CC2IF (1U << TIMER_SR_CC2IF_BIT)
+#define TIMER_SR_CC1IF (1U << TIMER_SR_CC1IF_BIT)
+#define TIMER_SR_UIF (1U << TIMER_SR_UIF_BIT)
/* Event generation register (EGR) */
+#define TIMER_EGR_BG_BIT 7
#define TIMER_EGR_TG_BIT 6
+#define TIMER_EGR_COMG_BIT 5
#define TIMER_EGR_CC4G_BIT 4
#define TIMER_EGR_CC3G_BIT 3
#define TIMER_EGR_CC2G_BIT 2
#define TIMER_EGR_CC1G_BIT 1
#define TIMER_EGR_UG_BIT 0
-#define TIMER_EGR_TG BIT(TIMER_EGR_TG_BIT)
-#define TIMER_EGR_CC4G BIT(TIMER_EGR_CC4G_BIT)
-#define TIMER_EGR_CC3G BIT(TIMER_EGR_CC3G_BIT)
-#define TIMER_EGR_CC2G BIT(TIMER_EGR_CC2G_BIT)
-#define TIMER_EGR_CC1G BIT(TIMER_EGR_CC1G_BIT)
-#define TIMER_EGR_UG BIT(TIMER_EGR_UG_BIT)
+#define TIMER_EGR_BG (1U << TIMER_EGR_BG_BIT)
+#define TIMER_EGR_TG (1U << TIMER_EGR_TG_BIT)
+#define TIMER_EGR_COMG (1U << TIMER_EGR_COMG_BIT)
+#define TIMER_EGR_CC4G (1U << TIMER_EGR_CC4G_BIT)
+#define TIMER_EGR_CC3G (1U << TIMER_EGR_CC3G_BIT)
+#define TIMER_EGR_CC2G (1U << TIMER_EGR_CC2G_BIT)
+#define TIMER_EGR_CC1G (1U << TIMER_EGR_CC1G_BIT)
+#define TIMER_EGR_UG (1U << TIMER_EGR_UG_BIT)
/* Capture/compare mode registers, common values */
@@ -365,22 +371,22 @@ extern timer_dev *TIMER8;
#define TIMER_CCMR1_OC1PE_BIT 3
#define TIMER_CCMR1_OC1FE_BIT 2
-#define TIMER_CCMR1_OC2CE BIT(TIMER_CCMR1_OC2CE_BIT)
+#define TIMER_CCMR1_OC2CE (1U << TIMER_CCMR1_OC2CE_BIT)
#define TIMER_CCMR1_OC2M (0x3 << 12)
#define TIMER_CCMR1_IC2F (0xF << 12)
-#define TIMER_CCMR1_OC2PE BIT(TIMER_CCMR1_OC2PE_BIT)
-#define TIMER_CCMR1_OC2FE BIT(TIMER_CCMR1_OC2FE_BIT)
+#define TIMER_CCMR1_OC2PE (1U << TIMER_CCMR1_OC2PE_BIT)
+#define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT)
#define TIMER_CCMR1_IC2PSC (0x3 << 10)
#define TIMER_CCMR1_CC2S (0x3 << 8)
#define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8)
#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8)
#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8)
#define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8)
-#define TIMER_CCMR1_OC1CE BIT(TIMER_CCMR1_OC1CE_BIT)
+#define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT)
#define TIMER_CCMR1_OC1M (0x3 << 4)
#define TIMER_CCMR1_IC1F (0xF << 4)
-#define TIMER_CCMR1_OC1PE BIT(TIMER_CCMR1_OC1PE_BIT)
-#define TIMER_CCMR1_OC1FE BIT(TIMER_CCMR1_OC1FE_BIT)
+#define TIMER_CCMR1_OC1PE (1U << TIMER_CCMR1_OC1PE_BIT)
+#define TIMER_CCMR1_OC1FE (1U << TIMER_CCMR1_OC1FE_BIT)
#define TIMER_CCMR1_IC1PSC (0x3 << 2)
#define TIMER_CCMR1_CC1S 0x3
#define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT
@@ -397,48 +403,60 @@ extern timer_dev *TIMER8;
#define TIMER_CCMR2_OC3PE_BIT 3
#define TIMER_CCMR2_OC3FE_BIT 2
-#define TIMER_CCMR2_OC4CE BIT(TIMER_CCMR2_OC4CE_BIT)
+#define TIMER_CCMR2_OC4CE (1U << TIMER_CCMR2_OC4CE_BIT)
#define TIMER_CCMR2_OC4M (0x3 << 12)
-#define TIMER_CCMR2_IC2F (0xF << 12)
-#define TIMER_CCMR2_OC4PE BIT(TIMER_CCMR2_OC4PE_BIT)
-#define TIMER_CCMR2_OC4FE BIT(TIMER_CCMR2_OC4FE_BIT)
-#define TIMER_CCMR2_IC2PSC (0x3 << 10)
+#define TIMER_CCMR2_IC4F (0xF << 12)
+#define TIMER_CCMR2_OC4PE (1U << TIMER_CCMR2_OC4PE_BIT)
+#define TIMER_CCMR2_OC4FE (1U << TIMER_CCMR2_OC4FE_BIT)
+#define TIMER_CCMR2_IC4PSC (0x3 << 10)
#define TIMER_CCMR2_CC4S (0x3 << 8)
-#define TIMER_CCMR1_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8)
-#define TIMER_CCMR1_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8)
-#define TIMER_CCMR1_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8)
-#define TIMER_CCMR1_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8)
-#define TIMER_CCMR2_OC3CE BIT(TIMER_CCMR2_OC3CE_BIT)
+#define TIMER_CCMR2_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8)
+#define TIMER_CCMR2_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8)
+#define TIMER_CCMR2_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8)
+#define TIMER_CCMR2_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8)
+#define TIMER_CCMR2_OC3CE (1U << TIMER_CCMR2_OC3CE_BIT)
#define TIMER_CCMR2_OC3M (0x3 << 4)
-#define TIMER_CCMR2_IC1F (0xF << 4)
-#define TIMER_CCMR2_OC3PE BIT(TIMER_CCMR2_OC3PE_BIT)
-#define TIMER_CCMR2_OC3FE BIT(TIMER_CCMR2_OC3FE_BIT)
-#define TIMER_CCMR2_IC1PSC (0x3 << 2)
+#define TIMER_CCMR2_IC3F (0xF << 4)
+#define TIMER_CCMR2_OC3PE (1U << TIMER_CCMR2_OC3PE_BIT)
+#define TIMER_CCMR2_OC3FE (1U << TIMER_CCMR2_OC3FE_BIT)
+#define TIMER_CCMR2_IC3PSC (0x3 << 2)
#define TIMER_CCMR2_CC3S 0x3
-#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT
-#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
-#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
-#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
+#define TIMER_CCMR2_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT
+#define TIMER_CCMR2_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
+#define TIMER_CCMR2_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
+#define TIMER_CCMR2_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
/* Capture/compare enable register (CCER) */
#define TIMER_CCER_CC4P_BIT 13
#define TIMER_CCER_CC4E_BIT 12
+#define TIMER_CCER_CC3NP_BIT 11
+#define TIMER_CCER_CC3NE_BIT 10
#define TIMER_CCER_CC3P_BIT 9
#define TIMER_CCER_CC3E_BIT 8
+#define TIMER_CCER_CC2NP_BIT 7
+#define TIMER_CCER_CC2NE_BIT 6
#define TIMER_CCER_CC2P_BIT 5
#define TIMER_CCER_CC2E_BIT 4
+#define TIMER_CCER_CC1NP_BIT 3
+#define TIMER_CCER_CC1NE_BIT 2
#define TIMER_CCER_CC1P_BIT 1
#define TIMER_CCER_CC1E_BIT 0
-#define TIMER_CCER_CC4P BIT(TIMER_CCER_CC4P_BIT)
-#define TIMER_CCER_CC4E BIT(TIMER_CCER_CC4E_BIT)
-#define TIMER_CCER_CC3P BIT(TIMER_CCER_CC3P_BIT)
-#define TIMER_CCER_CC3E BIT(TIMER_CCER_CC3E_BIT)
-#define TIMER_CCER_CC2P BIT(TIMER_CCER_CC2P_BIT)
-#define TIMER_CCER_CC2E BIT(TIMER_CCER_CC2E_BIT)
-#define TIMER_CCER_CC1P BIT(TIMER_CCER_CC1P_BIT)
-#define TIMER_CCER_CC1E BIT(TIMER_CCER_CC1E_BIT)
+#define TIMER_CCER_CC4P (1U << TIMER_CCER_CC4P_BIT)
+#define TIMER_CCER_CC4E (1U << TIMER_CCER_CC4E_BIT)
+#define TIMER_CCER_CC3NP (1U << TIMER_CCER_CC3NP_BIT)
+#define TIMER_CCER_CC3NE (1U << TIMER_CCER_CC3NE_BIT)
+#define TIMER_CCER_CC3P (1U << TIMER_CCER_CC3P_BIT)
+#define TIMER_CCER_CC3E (1U << TIMER_CCER_CC3E_BIT)
+#define TIMER_CCER_CC2NP (1U << TIMER_CCER_CC2NP_BIT)
+#define TIMER_CCER_CC2NE (1U << TIMER_CCER_CC2NE_BIT)
+#define TIMER_CCER_CC2P (1U << TIMER_CCER_CC2P_BIT)
+#define TIMER_CCER_CC2E (1U << TIMER_CCER_CC2E_BIT)
+#define TIMER_CCER_CC1NP (1U << TIMER_CCER_CC1NP_BIT)
+#define TIMER_CCER_CC1NE (1U << TIMER_CCER_CC1NE_BIT)
+#define TIMER_CCER_CC1P (1U << TIMER_CCER_CC1P_BIT)
+#define TIMER_CCER_CC1E (1U << TIMER_CCER_CC1E_BIT)
/* Break and dead-time register (BDTR) */
@@ -449,12 +467,12 @@ extern timer_dev *TIMER8;
#define TIMER_BDTR_OSSR_BIT 11
#define TIMER_BDTR_OSSI_BIT 10
-#define TIMER_BDTR_MOE BIT(TIMER_BDTR_MOE_BIT)
-#define TIMER_BDTR_AOE BIT(TIMER_BDTR_AOE_BIT)
-#define TIMER_BDTR_BKP BIT(TIMER_BDTR_BKP_BIT)
-#define TIMER_BDTR_BKE BIT(TIMER_BDTR_BKE_BIT)
-#define TIMER_BDTR_OSSR BIT(TIMER_BDTR_OSSR_BIT)
-#define TIMER_BDTR_OSSI BIT(TIMER_BDTR_OSSI_BIT)
+#define TIMER_BDTR_MOE (1U << TIMER_BDTR_MOE_BIT)
+#define TIMER_BDTR_AOE (1U << TIMER_BDTR_AOE_BIT)
+#define TIMER_BDTR_BKP (1U << TIMER_BDTR_BKP_BIT)
+#define TIMER_BDTR_BKE (1U << TIMER_BDTR_BKE_BIT)
+#define TIMER_BDTR_OSSR (1U << TIMER_BDTR_OSSR_BIT)
+#define TIMER_BDTR_OSSI (1U << TIMER_BDTR_OSSI_BIT)
#define TIMER_BDTR_LOCK (0x3 << 8)
#define TIMER_BDTR_LOCK_OFF (0x0 << 8)
#define TIMER_BDTR_LOCK_LEVEL1 (0x1 << 8)
@@ -465,24 +483,24 @@ extern timer_dev *TIMER8;
/* DMA control register (DCR) */
#define TIMER_DCR_DBL (0x1F << 8)
-#define TIMER_DCR_DBL_1BYTE (0x0 << 8)
-#define TIMER_DCR_DBL_2BYTE (0x1 << 8)
-#define TIMER_DCR_DBL_3BYTE (0x2 << 8)
-#define TIMER_DCR_DBL_4BYTE (0x3 << 8)
-#define TIMER_DCR_DBL_5BYTE (0x4 << 8)
-#define TIMER_DCR_DBL_6BYTE (0x5 << 8)
-#define TIMER_DCR_DBL_7BYTE (0x6 << 8)
-#define TIMER_DCR_DBL_8BYTE (0x7 << 8)
-#define TIMER_DCR_DBL_9BYTE (0x8 << 8)
-#define TIMER_DCR_DBL_10BYTE (0x9 << 8)
-#define TIMER_DCR_DBL_11BYTE (0xA << 8)
-#define TIMER_DCR_DBL_12BYTE (0xB << 8)
-#define TIMER_DCR_DBL_13BYTE (0xC << 8)
-#define TIMER_DCR_DBL_14BYTE (0xD << 8)
-#define TIMER_DCR_DBL_15BYTE (0xE << 8)
-#define TIMER_DCR_DBL_16BYTE (0xF << 8)
-#define TIMER_DCR_DBL_17BYTE (0x10 << 8)
-#define TIMER_DCR_DBL_18BYTE (0x11 << 8)
+#define TIMER_DCR_DBL_1_XFER (0x0 << 8)
+#define TIMER_DCR_DBL_2_XFER (0x1 << 8)
+#define TIMER_DCR_DBL_3_XFER (0x2 << 8)
+#define TIMER_DCR_DBL_4_XFER (0x3 << 8)
+#define TIMER_DCR_DBL_5_XFER (0x4 << 8)
+#define TIMER_DCR_DBL_6_XFER (0x5 << 8)
+#define TIMER_DCR_DBL_7_XFER (0x6 << 8)
+#define TIMER_DCR_DBL_8_XFER (0x7 << 8)
+#define TIMER_DCR_DBL_9_XFER (0x8 << 8)
+#define TIMER_DCR_DBL_10_XFER (0x9 << 8)
+#define TIMER_DCR_DBL_11_XFER (0xA << 8)
+#define TIMER_DCR_DBL_12_XFER (0xB << 8)
+#define TIMER_DCR_DBL_13_XFER (0xC << 8)
+#define TIMER_DCR_DBL_14_XFER (0xD << 8)
+#define TIMER_DCR_DBL_15_XFER (0xE << 8)
+#define TIMER_DCR_DBL_16_XFER (0xF << 8)
+#define TIMER_DCR_DBL_17_XFER (0x10 << 8)
+#define TIMER_DCR_DBL_18_XFER (0x11 << 8)
#define TIMER_DCR_DBA 0x1F
#define TIMER_DCR_DBA_CR1 0x0
#define TIMER_DCR_DBA_CR2 0x1
@@ -510,27 +528,32 @@ extern timer_dev *TIMER8;
*/
/**
- * Used to configure the behavior of a timer channel. Note that not
- * all timers can be configured in every mode.
+ * @brief Used to configure the behavior of a timer channel.
+ *
+ * Be careful: not all timers can be configured in every mode.
*/
-/* TODO TIMER_PWM_CENTER_ALIGNED, TIMER_INPUT_CAPTURE, TIMER_ONE_PULSE */
typedef enum timer_mode {
- TIMER_DISABLED, /**< In this mode, the timer stops counting,
- channel interrupts are detached, and no state
- changes are output. */
- TIMER_PWM, /**< PWM output mode. This is the default mode for pins
- after initialization. */
- /* TIMER_PWM_CENTER_ALIGNED, /\**< Center-aligned PWM output mode. *\/ */
- TIMER_OUTPUT_COMPARE, /**< In this mode, the timer counts from 0
- to its reload value repeatedly; every
- time the counter value reaches one of
- the channel compare values, the
- corresponding interrupt is fired. */
- /* TIMER_INPUT_CAPTURE, /\**< In this mode, the timer can measure the */
- /* pulse lengths of input signals. *\/ */
- /* TIMER_ONE_PULSE /\**< In this mode, the timer can generate a single */
- /* pulse on a GPIO pin for a specified amount of */
- /* time. *\/ */
+ /**
+ * The timer stops counting, channel interrupts are detached, and
+ * no state changes are output. */
+ TIMER_DISABLED,
+
+ /** PWM output. */
+ TIMER_PWM,
+
+ /* TIMER_PWM_CENTER_ALIGNED, TODO: Center-aligned PWM output mode. */
+
+ /**
+ * The timer counts from 0 to its reload value repeatedly; every
+ * time the counter value reaches one of the channel compare
+ * values, the corresponding interrupt is fired. */
+ TIMER_OUTPUT_COMPARE,
+
+ /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the
+ * pulse lengths of input signals */
+ /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single
+ * pulse on a GPIO pin for a specified amount of
+ * time. */
} timer_mode;
/** Timer channel numbers */
@@ -555,27 +578,26 @@ void timer_init(timer_dev *dev);
void timer_disable(timer_dev *dev);
void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode);
void timer_foreach(void (*fn)(timer_dev*));
+int timer_has_cc_channel(timer_dev *dev, uint8 channel);
/**
* @brief Timer interrupt number.
*
- * Not all timers support all of these values; see the descriptions
- * for each value.
+ * Not all timers support all of these values. All timers support
+ * TIMER_UPDATE_INTERRUPT. "General purpose" timers can be a special
+ * nuisance in this regard, as they individually support different
+ * subsets of the available interupts. Consult your target's reference
+ * manual for the details.
*/
typedef enum timer_interrupt_id {
- TIMER_UPDATE_INTERRUPT, /**< Update interrupt, available on all timers. */
- TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt, available
- on general and advanced timers only. */
- TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt, general and
- advanced timers only. */
- TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt, general and
- advanced timers only. */
- TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt, general and
- advanced timers only. */
- TIMER_COM_INTERRUPT, /**< COM interrupt, advanced timers only */
- TIMER_TRG_INTERRUPT, /**< Trigger interrupt, general and advanced
- timers only */
- TIMER_BREAK_INTERRUPT /**< Break interrupt, advanced timers only. */
+ TIMER_UPDATE_INTERRUPT, /**< Update interrupt. */
+ TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt. */
+ TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt. */
+ TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt. */
+ TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt. */
+ TIMER_COM_INTERRUPT, /**< COM interrupt. */
+ TIMER_TRG_INTERRUPT, /**< Trigger interrupt. */
+ TIMER_BREAK_INTERRUPT, /**< Break interrupt. */
} timer_interrupt_id;
void timer_attach_interrupt(timer_dev *dev,
@@ -843,18 +865,19 @@ static inline void timer_cc_set_pol(timer_dev *dev, uint8 channel, uint8 pol) {
/**
* @brief Get a timer's DMA burst length.
* @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
- * @return Number of bytes to be transferred per DMA request, from 1 to 18.
+ * @return Number of transfers per read or write to timer DMA register,
+ * from 1 to 18.
*/
static inline uint8 timer_dma_get_burst_len(timer_dev *dev) {
uint32 dbl = ((dev->regs).gen->DCR & TIMER_DCR_DBL) >> 8;
- return dbl + 1; /* 0 means 1 byte, etc. */
+ return dbl + 1; /* 0 means 1 transfer, etc. */
}
/**
* @brief Set a timer's DMA burst length.
* @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
- * @param length DMA burst length; i.e., number of bytes to transfer
- * per DMA request, from 1 to 18.
+ * @param length DMA burst length; i.e., number of DMA transfers per
+ * read/write to timer DMA register, from 1 to 18.
*/
static inline void timer_dma_set_burst_len(timer_dev *dev, uint8 length) {
uint32 tmp = (dev->regs).gen->DCR;
@@ -869,47 +892,52 @@ static inline void timer_dma_set_burst_len(timer_dev *dev, uint8 length) {
* Defines the base address for DMA transfers.
*/
typedef enum timer_dma_base_addr {
- TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1, /**< Base is control register 1 */
- TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2, /**< Base is control register 2 */
- TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR, /**< Base is slave mode
- control register */
- TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER, /**< Base is DMA interrupt enable
- register */
- TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR, /**< Base is status register */
- TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR, /**< Base is event generation
- register */
- TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1, /**< Base is capture/compare
- mode register 1 */
- TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2, /**< Base is capture/compare
- mode register 2 */
- TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER, /**< Base is capture/compare
- enable register */
- TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT, /**< Base is counter */
- TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC, /**< Base is prescaler */
- TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR, /**< Base is auto-reload
- register */
- TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR, /**< Base is repetition
- counter register */
- TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1, /**< Base is capture/compare
- register 1 */
- TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2, /**< Base is capture/compare
- register 2 */
- TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3, /**< Base is capture/compare
- register 3 */
- TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4, /**< Base is capture/compare
- register 4 */
- TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR, /**< Base is break and
- dead-time register */
- TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR, /**< Base is DMA control
- register */
- TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR /**< Base is DMA address for
- full transfer */
+ /** Base is control register 1 */
+ TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1,
+ /** Base is control register 2 */
+ TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2,
+ /** Base is slave mode control register */
+ TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR,
+ /** Base is DMA interrupt enable register */
+ TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER,
+ /** Base is status register */
+ TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR,
+ /** Base is event generation register */
+ TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR,
+ /** Base is capture/compare mode register 1 */
+ TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1,
+ /** Base is capture/compare mode register 2 */
+ TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2,
+ /** Base is capture/compare enable register */
+ TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER,
+ /** Base is counter */
+ TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT,
+ /** Base is prescaler */
+ TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC,
+ /** Base is auto-reload register */
+ TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR,
+ /** Base is repetition counter register */
+ TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR,
+ /** Base is capture/compare register 1 */
+ TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1,
+ /** Base is capture/compare register 2 */
+ TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2,
+ /** Base is capture/compare register 3 */
+ TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3,
+ /** Base is capture/compare register 4 */
+ TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4,
+ /** Base is break and dead-time register */
+ TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR,
+ /** Base is DMA control register */
+ TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR,
+ /** Base is DMA address for full transfer */
+ TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR,
} timer_dma_base_addr;
/**
* @brief Get the timer's DMA base address.
*
- * Some restrictions apply; see ST RM0008.
+ * Some restrictions apply; see the reference manual for your chip.
*
* @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
* @return DMA base address
@@ -922,7 +950,7 @@ static inline timer_dma_base_addr timer_dma_get_base_addr(timer_dev *dev) {
/**
* @brief Set the timer's DMA base address.
*
- * Some restrictions apply; see ST RM0008.
+ * Some restrictions apply; see the reference manual for your chip.
*
* @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
* @param dma_base DMA base address.
@@ -939,35 +967,38 @@ static inline void timer_dma_set_base_addr(timer_dev *dev,
* Timer output compare modes.
*/
typedef enum timer_oc_mode {
- TIMER_OC_MODE_FROZEN = 0 << 4, /**< Frozen: comparison between output
- compare register and counter has no
- effect on the outputs. */
- TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4, /**< OCxREF signal is forced
- high when the count matches
- the channel capture/compare
- register. */
- TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4, /**< OCxREF signal is forced
- low when the counter matches
- the channel capture/compare
- register. */
- TIMER_OC_MODE_TOGGLE = 3 << 4, /**< OCxREF toggles when counter
- matches the cannel capture/compare
- register. */
- TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4, /**< OCxREF is forced low. */
- TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4, /**< OCxREF is forced high. */
- TIMER_OC_MODE_PWM_1 = 6 << 4, /**< PWM mode 1. In upcounting, channel is
- active as long as count is less than
- channel capture/compare register, else
- inactive. In downcounting, channel is
- inactive as long as count exceeds
- capture/compare register, else
- active. */
- TIMER_OC_MODE_PWM_2 = 7 << 4 /**< PWM mode 2. In upcounting, channel is
- inactive as long as count is less than
- capture/compare register, else active.
- In downcounting, channel is active as
- long as count exceeds capture/compare
- register, else inactive. */
+ /**
+ * Frozen: comparison between output compare register and counter
+ * has no effect on the outputs. */
+ TIMER_OC_MODE_FROZEN = 0 << 4,
+ /**
+ * OCxREF signal is forced high when the count matches the channel
+ * capture/compare register. */
+ TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4,
+ /**
+ * OCxREF signal is forced low when the counter matches the
+ * channel capture/compare register. */
+ TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4,
+ /**
+ * OCxREF toggles when counter matches the channel capture/compare
+ * register. */
+ TIMER_OC_MODE_TOGGLE = 3 << 4,
+ /** OCxREF is forced low. */
+ TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4,
+ /** OCxREF is forced high. */
+ TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4,
+ /**
+ * PWM mode 1. In upcounting, channel is active as long as count
+ * is less than channel capture/compare register, else inactive.
+ * In downcounting, channel is inactive as long as count exceeds
+ * capture/compare register, else active. */
+ TIMER_OC_MODE_PWM_1 = 6 << 4,
+ /**
+ * PWM mode 2. In upcounting, channel is inactive as long as count
+ * is less than capture/compare register, else active. In
+ * downcounting, channel is active as long as count exceeds
+ * capture/compare register, else inactive. */
+ TIMER_OC_MODE_PWM_2 = 7 << 4,
} timer_oc_mode;
/**
@@ -975,9 +1006,9 @@ typedef enum timer_oc_mode {
* @see timer_oc_set_mode()
*/
typedef enum timer_oc_mode_flags {
- TIMER_OC_CE = BIT(7), /**< Output compare clear enable. */
- TIMER_OC_PE = BIT(3), /**< Output compare preload enable. */
- TIMER_OC_FE = BIT(2) /**< Output compare fast enable. */
+ TIMER_OC_CE = 1U << 7, /**< Output compare clear enable. */
+ TIMER_OC_PE = 1U << 3, /**< Output compare preload enable. */
+ TIMER_OC_FE = 1U << 2, /**< Output compare fast enable. */
} timer_oc_mode_flags;
/**
@@ -1005,6 +1036,73 @@ static inline void timer_oc_set_mode(timer_dev *dev,
*ccmr = tmp;
}
+/*
+ * Old, erroneous bit definitions from previous releases, kept for
+ * backwards compatibility:
+ */
+
+/** Deprecated. Use TIMER_CCMR1_CC4S_OUTPUT instead. */
+#define TIMER_CCMR1_CC4S_OUTPUT TIMER_CCMR2_CC4S_OUTPUT
+/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI1 instead. */
+#define TIMER_CCMR1_CC4S_INPUT_TI1 TIMER_CCMR2_CC4S_INPUT_TI1
+/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI2 instead. */
+#define TIMER_CCMR1_CC4S_INPUT_TI2 TIMER_CCMR2_CC4S_INPUT_TI2
+/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TRC instead. */
+#define TIMER_CCMR1_CC4S_INPUT_TRC TIMER_CCMR2_CC4S_INPUT_TRC
+/** Deprecated. Use TIMER_CCMR2_IC4F instead. */
+#define TIMER_CCMR2_IC2F TIMER_CCMR2_IC4F
+/** Deprecated. Use TIMER_CCMR2_IC4PSC instead. */
+#define TIMER_CCMR2_IC2PSC TIMER_CCMR2_IC4PSC
+/** Deprecated. Use TIMER_CCMR2_IC3F instead. */
+#define TIMER_CCMR2_IC1F TIMER_CCMR2_IC3F
+/** Deprecated. Use TIMER_CCMR2_IC3PSC instead. */
+#define TIMER_CCMR2_IC1PSC TIMER_CCMR2_IC3PSC
+/** Deprecated. Use TIMER_CCMR1_CC3S_OUTPUT instead. */
+#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR2_CC3S_OUTPUT
+/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI1 instead. */
+#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR2_CC3S_INPUT_TI1
+/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI2 instead. */
+#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR2_CC3S_INPUT_TI2
+/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TRC instead. */
+#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR2_CC3S_INPUT_TRC
+
+/** Deprecated. Use TIMER_DCR_DBL_1_XFER instead. */
+#define TIMER_DCR_DBL_1BYTE TIMER_DCR_DBL_1_XFER
+/** Deprecated. Use TIMER_DCR_DBL_2_XFER instead. */
+#define TIMER_DCR_DBL_2BYTE TIMER_DCR_DBL_2_XFER
+/** Deprecated. Use TIMER_DCR_DBL_3_XFER instead. */
+#define TIMER_DCR_DBL_3BYTE TIMER_DCR_DBL_3_XFER
+/** Deprecated. Use TIMER_DCR_DBL_4_XFER instead. */
+#define TIMER_DCR_DBL_4BYTE TIMER_DCR_DBL_4_XFER
+/** Deprecated. Use TIMER_DCR_DBL_5_XFER instead. */
+#define TIMER_DCR_DBL_5BYTE TIMER_DCR_DBL_5_XFER
+/** Deprecated. Use TIMER_DCR_DBL_6_XFER instead. */
+#define TIMER_DCR_DBL_6BYTE TIMER_DCR_DBL_6_XFER
+/** Deprecated. Use TIMER_DCR_DBL_7_XFER instead. */
+#define TIMER_DCR_DBL_7BYTE TIMER_DCR_DBL_7_XFER
+/** Deprecated. Use TIMER_DCR_DBL_8_XFER instead. */
+#define TIMER_DCR_DBL_8BYTE TIMER_DCR_DBL_8_XFER
+/** Deprecated. Use TIMER_DCR_DBL_9_XFER instead. */
+#define TIMER_DCR_DBL_9BYTE TIMER_DCR_DBL_9_XFER
+/** Deprecated. Use TIMER_DCR_DBL_10_XFER instead. */
+#define TIMER_DCR_DBL_10BYTE TIMER_DCR_DBL_10_XFER
+/** Deprecated. Use TIMER_DCR_DBL_11_XFER instead. */
+#define TIMER_DCR_DBL_11BYTE TIMER_DCR_DBL_11_XFER
+/** Deprecated. Use TIMER_DCR_DBL_12_XFER instead. */
+#define TIMER_DCR_DBL_12BYTE TIMER_DCR_DBL_12_XFER
+/** Deprecated. Use TIMER_DCR_DBL_13_XFER instead. */
+#define TIMER_DCR_DBL_13BYTE TIMER_DCR_DBL_13_XFER
+/** Deprecated. Use TIMER_DCR_DBL_14_XFER instead. */
+#define TIMER_DCR_DBL_14BYTE TIMER_DCR_DBL_14_XFER
+/** Deprecated. Use TIMER_DCR_DBL_15_XFER instead. */
+#define TIMER_DCR_DBL_15BYTE TIMER_DCR_DBL_15_XFER
+/** Deprecated. Use TIMER_DCR_DBL_16_XFER instead. */
+#define TIMER_DCR_DBL_16BYTE TIMER_DCR_DBL_16_XFER
+/** Deprecated. Use TIMER_DCR_DBL_17_XFER instead. */
+#define TIMER_DCR_DBL_17BYTE TIMER_DCR_DBL_17_XFER
+/** Deprecated. Use TIMER_DCR_DBL_18_XFER instead. */
+#define TIMER_DCR_DBL_18BYTE TIMER_DCR_DBL_18_XFER
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libmaple/usart.h b/libmaple/include/libmaple/usart.h
index ed00e16..26a64d3 100644
--- a/libmaple/usart.h
+++ b/libmaple/include/libmaple/usart.h
@@ -25,27 +25,28 @@
*****************************************************************************/
/**
- * @file usart.h
+ * @file libmaple/include/libmaple/usart.h
* @author Marti Bolivar <mbolivar@leaflabs.com>,
* Perry Hung <perry@leaflabs.com>
* @brief USART definitions and prototypes
*/
-#ifndef _USART_H_
-#define _USART_H_
-
-#include "libmaple_types.h"
-#include "util.h"
-#include "rcc.h"
-#include "nvic.h"
-#include "ring_buffer.h"
+#ifndef _LIBMAPLE_USART_H_
+#define _LIBMAPLE_USART_H_
#ifdef __cplusplus
extern "C"{
#endif
+#include <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
+#include <libmaple/rcc.h>
+#include <libmaple/nvic.h>
+#include <libmaple/ring_buffer.h>
+#include <series/usart.h>
+
/*
- * Register maps and devices
+ * Register map (common across supported STM32 series).
*/
/** USART register map type */
@@ -59,169 +60,315 @@ typedef struct usart_reg_map {
__io uint32 GTPR; /**< Guard time and prescaler register */
} usart_reg_map;
-/** USART1 register map base pointer */
-#define USART1_BASE ((struct usart_reg_map*)0x40013800)
-/** USART2 register map base pointer */
-#define USART2_BASE ((struct usart_reg_map*)0x40004400)
-/** USART3 register map base pointer */
-#define USART3_BASE ((struct usart_reg_map*)0x40004800)
-#ifdef STM32_HIGH_DENSITY
-/** UART4 register map base pointer */
-#define UART4_BASE ((struct usart_reg_map*)0x40004C00)
-/** UART5 register map base pointer */
-#define UART5_BASE ((struct usart_reg_map*)0x40005000)
-#endif
-
/*
* Register bit definitions
*/
/* Status register */
+/** Clear to send bit */
#define USART_SR_CTS_BIT 9
+/** Line break detection bit */
#define USART_SR_LBD_BIT 8
+/** Transmit data register empty bit */
#define USART_SR_TXE_BIT 7
+/** Transmission complete bit */
#define USART_SR_TC_BIT 6
+/** Read data register not empty bit */
#define USART_SR_RXNE_BIT 5
+/** IDLE line detected bit */
#define USART_SR_IDLE_BIT 4
+/** Overrun error bit */
#define USART_SR_ORE_BIT 3
+/** Noise error bit */
#define USART_SR_NE_BIT 2
+/**
+ * @brief Synonym for USART_SR_NE_BIT.
+ *
+ * Some series (e.g. STM32F2) use "NF" for "noise flag" instead of the
+ * original "NE" for "noise error". The meaning of the bit is
+ * unchanged, but the NF flag can be disabled when the line is
+ * noise-free.
+ *
+ * @see USART_SR_NE_BIT
+ */
+#define USART_SR_NF_BIT USART_SR_NE_BIT
+/** Framing error bit */
#define USART_SR_FE_BIT 1
+/** Parity error bit */
#define USART_SR_PE_BIT 0
+/** Clear to send mask */
#define USART_SR_CTS BIT(USART_SR_CTS_BIT)
+/** Line break detected mask */
#define USART_SR_LBD BIT(USART_SR_LBD_BIT)
+/** Transmit data register empty mask */
#define USART_SR_TXE BIT(USART_SR_TXE_BIT)
+/** Transmission complete mask */
#define USART_SR_TC BIT(USART_SR_TC_BIT)
+/** Read data register not empty mask */
#define USART_SR_RXNE BIT(USART_SR_RXNE_BIT)
+/** IDLE line detected mask */
#define USART_SR_IDLE BIT(USART_SR_IDLE_BIT)
+/** Overrun error mask */
#define USART_SR_ORE BIT(USART_SR_ORE_BIT)
+/** Noise error mask */
#define USART_SR_NE BIT(USART_SR_NE_BIT)
+/**
+ * @brief Synonym for USART_SR_NE.
+ * @see USART_SR_NF_BIT
+ */
+#define USART_SR_NF USART_SR_NE
+/** Framing error mask */
#define USART_SR_FE BIT(USART_SR_FE_BIT)
+/** Parity error mask */
#define USART_SR_PE BIT(USART_SR_PE_BIT)
/* Data register */
+/** Data register data value mask */
#define USART_DR_DR 0xFF
/* Baud rate register */
+/** Mantissa of USARTDIV mask */
#define USART_BRR_DIV_MANTISSA (0xFFF << 4)
+/** Fraction of USARTDIV mask */
#define USART_BRR_DIV_FRACTION 0xF
/* Control register 1 */
+/** USART enable bit */
#define USART_CR1_UE_BIT 13
+/** Word length bit */
#define USART_CR1_M_BIT 12
+/** Wakeup method bit */
#define USART_CR1_WAKE_BIT 11
+/** Parity control enable bit */
#define USART_CR1_PCE_BIT 10
+/** Parity selection bit */
#define USART_CR1_PS_BIT 9
+/** Parity error interrupt enable bit */
#define USART_CR1_PEIE_BIT 8
+/** Transmit data regsiter not empty interrupt enable bit */
#define USART_CR1_TXEIE_BIT 7
+/** Transmission complete interrupt enable bit */
#define USART_CR1_TCIE_BIT 6
+/** RXNE interrupt enable bit */
#define USART_CR1_RXNEIE_BIT 5
+/** IDLE interrupt enable bit */
#define USART_CR1_IDLEIE_BIT 4
+/** Transmitter enable bit */
#define USART_CR1_TE_BIT 3
+/** Receiver enable bit */
#define USART_CR1_RE_BIT 2
+/** Receiver wakeup bit */
#define USART_CR1_RWU_BIT 1
+/** Send break bit */
#define USART_CR1_SBK_BIT 0
+/** USART enable mask */
#define USART_CR1_UE BIT(USART_CR1_UE_BIT)
+/** Word length mask */
#define USART_CR1_M BIT(USART_CR1_M_BIT)
+/** Word length: 1 start bit, 8 data bits, n stop bit */
+#define USART_CR1_M_8N1 (0 << USART_CR1_M_BIT)
+/** Word length: 1 start bit, 9 data bits, n stop bit */
+#define USART_CR1_M_9N1 (1 << USART_CR1_M_BIT)
+/** Wakeup method mask */
#define USART_CR1_WAKE BIT(USART_CR1_WAKE_BIT)
+/** Wakeup on idle line */
#define USART_CR1_WAKE_IDLE (0 << USART_CR1_WAKE_BIT)
+/** Wakeup on address mark */
#define USART_CR1_WAKE_ADDR (1 << USART_CR1_WAKE_BIT)
+/** Parity control enable mask */
#define USART_CR1_PCE BIT(USART_CR1_PCE_BIT)
+/** Parity selection mask */
#define USART_CR1_PS BIT(USART_CR1_PS_BIT)
+/** Parity selection: even parity */
#define USART_CR1_PS_EVEN (0 << USART_CR1_PS_BIT)
+/** Parity selection: odd parity */
#define USART_CR1_PS_ODD (1 << USART_CR1_PS_BIT)
+/** Parity error interrupt enable mask */
#define USART_CR1_PEIE BIT(USART_CR1_PEIE_BIT)
+/** Transmit data register empty interrupt enable mask */
#define USART_CR1_TXEIE BIT(USART_CR1_TXEIE_BIT)
+/** Transmission complete interrupt enable mask */
#define USART_CR1_TCIE BIT(USART_CR1_TCIE_BIT)
+/** RXNE interrupt enable mask */
#define USART_CR1_RXNEIE BIT(USART_CR1_RXNEIE_BIT)
+/** IDLE line interrupt enable mask */
#define USART_CR1_IDLEIE BIT(USART_CR1_IDLEIE_BIT)
+/** Transmitter enable mask */
#define USART_CR1_TE BIT(USART_CR1_TE_BIT)
+/** Receiver enable mask */
#define USART_CR1_RE BIT(USART_CR1_RE_BIT)
+/** Receiver wakeup mask */
#define USART_CR1_RWU BIT(USART_CR1_RWU_BIT)
+/** Receiver wakeup: receiver in active mode */
#define USART_CR1_RWU_ACTIVE (0 << USART_CR1_RWU_BIT)
+/** Receiver wakeup: receiver in mute mode */
#define USART_CR1_RWU_MUTE (1 << USART_CR1_RWU_BIT)
+/** Send break */
#define USART_CR1_SBK BIT(USART_CR1_SBK_BIT)
/* Control register 2 */
+/** LIN mode enable bit */
#define USART_CR2_LINEN_BIT 14
+/** Clock enable bit */
#define USART_CR2_CLKEN_BIT 11
+/** Clock polarity bit */
#define USART_CR2_CPOL_BIT 10
+/** Clock phase bit */
#define USART_CR2_CPHA_BIT 9
+/** Last bit clock pulse bit */
#define USART_CR2_LBCL_BIT 8
+/** LIN break detection interrupt enable bit */
#define USART_CR2_LBDIE_BIT 6
+/** LIN break detection length bit */
#define USART_CR2_LBDL_BIT 5
+/** LIN mode enable mask */
#define USART_CR2_LINEN BIT(USART_CR2_LINEN_BIT)
+/** STOP bits mask */
#define USART_CR2_STOP (0x3 << 12)
+/** STOP bits: 1 stop bit */
#define USART_CR2_STOP_BITS_1 (0x0 << 12)
-/* Not on UART4, UART5 */
+/**
+ * @brief STOP bits: 0.5 stop bits
+ * Not available on UART4, UART5. */
#define USART_CR2_STOP_BITS_POINT_5 (0x1 << 12)
-/* Not on UART4, UART5 */
-#define USART_CR2_STOP_BITS_1_POINT_5 (0x3 << 12)
+/** STOP bits: 2 stop bits */
#define USART_CR2_STOP_BITS_2 (0x2 << 12)
+/**
+ * @brief STOP bits: 1.5 stop bits
+ * Not available on UART4, UART5. */
+#define USART_CR2_STOP_BITS_1_POINT_5 (0x3 << 12)
+/**
+ * @brief Clock enable.
+ * Not available on UART4, UART5 */
#define USART_CR2_CLKEN BIT(USART_CR2_CLKEN_BIT)
-/* Not on UART4, UART5 */
+/**
+ * @brief Clock polarity mask.
+ * Not available on UART4, UART5 */
#define USART_CR2_CPOL BIT(USART_CR2_CPOL_BIT)
+/** Clock polarity: low */
#define USART_CR2_CPOL_LOW (0x0 << USART_CR2_CLKEN_BIT)
+/** Clock polarity: high */
#define USART_CR2_CPOL_HIGH (0x1 << USART_CR2_CLKEN_BIT)
-/* Not on UART4, UART5 */
+/**
+ * @brief Clock phase mask.
+ * Not available on UART4, UART5 */
#define USART_CR2_CPHA BIT(USART_CR2_CPHA_BIT)
+/**
+ * @brief Clock phase: first
+ * First clock transition is the first data capture edge. */
#define USART_CR2_CPHA_FIRST (0x0 << USART_CR2_CPHA_BIT)
+/**
+ * @brief Clock phase: second
+ * Second clock transition is the first data capture edge. */
#define USART_CR2_CPHA_SECOND (0x1 << USART_CR2_CPHA_BIT)
-/* Not on UART4, UART5 */
+/**
+ * @brief Last bit clock pulse mask.
+ *
+ * When set, the last bit transmitted causes a clock pulse in
+ * synchronous mode.
+ *
+ * Not available on UART4, UART5 */
#define USART_CR2_LBCL BIT(USART_CR2_LBCL_BIT)
+/** LIN break detection interrupt enable mask. */
#define USART_CR2_LBDIE BIT(USART_CR2_LBDIE_BIT)
+/** LIN break detection length. */
#define USART_CR2_LBDL BIT(USART_CR2_LBDL_BIT)
+/** LIN break detection length: 10 bits */
#define USART_CR2_LBDL_10_BIT (0 << USART_CR2_LBDL_BIT)
+/** LIN break detection length: 11 bits */
#define USART_CR2_LBDL_11_BIT (1 << USART_CR2_LBDL_BIT)
+/**
+ * @brief Address of the USART node
+ * This is useful during multiprocessor communication. */
#define USART_CR2_ADD 0xF
/* Control register 3 */
+/** Clear to send interrupt enable bit */
#define USART_CR3_CTSIE_BIT 10
+/** Clear to send enable bit */
#define USART_CR3_CTSE_BIT 9
+/** Ready to send enable bit */
#define USART_CR3_RTSE_BIT 8
+/** DMA enable transmitter bit */
#define USART_CR3_DMAT_BIT 7
+/** DMA enable receiver bit */
#define USART_CR3_DMAR_BIT 6
+/** Smartcard mode enable bit */
#define USART_CR3_SCEN_BIT 5
+/** Smartcard NACK enable bit */
#define USART_CR3_NACK_BIT 4
+/** Half-duplex selection bit */
#define USART_CR3_HDSEL_BIT 3
+/** IrDA low power bit */
#define USART_CR3_IRLP_BIT 2
+/** IrDA mode enable bit */
#define USART_CR3_IREN_BIT 1
+/** Error interrupt enable bit */
#define USART_CR3_EIE_BIT 0
-/* Not on UART4, UART5 */
+/**
+ * @brief Clear to send interrupt enable
+ * Not available on UART4, UART5. */
#define USART_CR3_CTSIE BIT(USART_CR3_CTSIE_BIT)
-/* Not on UART4, UART5 */
+/**
+ * @brief Clear to send enable
+ * Not available on UART4, UART5. */
#define USART_CR3_CTSE BIT(USART_CR3_CTSE_BIT)
-/* Not on UART4, UART5 */
+/**
+ * @brief Ready to send enable
+ * Not available on UART4, UART5. */
#define USART_CR3_RTSE BIT(USART_CR3_RTSE_BIT)
-/* Not on UART5 */
+/**
+ * @brief DMA enable transmitter
+ * Not available on UART5. */
#define USART_CR3_DMAT BIT(USART_CR3_DMAT_BIT)
-/* Not on UART5 */
+/**
+ * @brief DMA enable receiver
+ * Not available on UART5. */
#define USART_CR3_DMAR BIT(USART_CR3_DMAR_BIT)
-/* Not on UART4, UART5 */
+/**
+ * @brief Smartcard mode enable
+ * Not available on UART4, UART5. */
#define USART_CR3_SCEN BIT(USART_CR3_SCEN_BIT)
-/* Not on UART4, UART5 */
+/**
+ * @brief Smartcard NACK enable
+ * Not available on UART4, UART5. */
#define USART_CR3_NACK BIT(USART_CR3_NACK_BIT)
+/**
+ * @brief Half-duplex selection
+ * When set, single-wire half duplex mode is selected.
+ */
#define USART_CR3_HDSEL BIT(USART_CR3_HDSEL_BIT)
+/** IrDA low power mode */
#define USART_CR3_IRLP BIT(USART_CR3_IRLP_BIT)
-#define USART_CR3_IRLP_NORMAL (0 << USART_CR3_IRLP_BIT)
-#define USART_CR3_IRLP_LOW_POWER (1 << USART_CR3_IRLP_BIT)
+/** IrDA mode: normal */
+#define USART_CR3_IRLP_NORMAL (0U << USART_CR3_IRLP_BIT)
+/** IrDA mode: low power */
+#define USART_CR3_IRLP_LOW_POWER (1U << USART_CR3_IRLP_BIT)
+/** IrDA mode enable */
#define USART_CR3_IREN BIT(USART_CR3_IREN_BIT)
+/** Error interrupt enable */
#define USART_CR3_EIE BIT(USART_CR3_EIE_BIT)
/* Guard time and prescaler register */
-/* Not on UART4, UART5 */
+/**
+ * @brief Guard time value mask
+ * Used in Smartcard mode. Not available on UART4, UART5. */
#define USART_GTPR_GT (0xFF << 8)
-/* Not on UART4, UART5 */
+/**
+ * @brief Prescaler value mask
+ * Restrictions on this value apply, depending on the USART mode. Not
+ * available on UART4, UART5. */
#define USART_GTPR_PSC 0xFF
/*
@@ -236,7 +383,8 @@ typedef struct usart_reg_map {
typedef struct usart_dev {
usart_reg_map *regs; /**< Register map */
ring_buffer *rb; /**< RX ring buffer */
- uint32 max_baud; /**< Maximum baud */
+ uint32 max_baud; /**< @brief Deprecated.
+ * Maximum baud rate. */
uint8 rx_buf[USART_RX_BUF_SIZE]; /**< @brief Deprecated.
* Actual RX buffer used by rb.
* This field will be removed in
@@ -245,16 +393,27 @@ typedef struct usart_dev {
nvic_irq_num irq_num; /**< USART NVIC interrupt */
} usart_dev;
-extern usart_dev *USART1;
-extern usart_dev *USART2;
-extern usart_dev *USART3;
-#ifdef STM32_HIGH_DENSITY
-extern usart_dev *UART4;
-extern usart_dev *UART5;
-#endif
-
void usart_init(usart_dev *dev);
+
+struct gpio_dev; /* forward declaration */
+/* FIXME [PRE 0.0.13] decide if flags are necessary */
+/**
+ * @brief Configure GPIOs for use as USART TX/RX.
+ * @param udev USART device to use
+ * @param rx_dev RX pin gpio_dev
+ * @param rx RX pin bit on rx_dev
+ * @param tx_dev TX pin gpio_dev
+ * @param tx TX pin bit on tx_dev
+ * @param flags Currently ignored
+ */
+extern void usart_config_gpios_async(usart_dev *udev,
+ struct gpio_dev *rx_dev, uint8 rx,
+ struct gpio_dev *tx_dev, uint8 tx,
+ unsigned flags);
+
+#define USART_USE_PCLK 0
void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud);
+
void usart_enable(usart_dev *dev);
void usart_disable(usart_dev *dev);
void usart_foreach(void (*fn)(usart_dev *dev));
@@ -333,4 +492,4 @@ static inline void usart_reset_rx(usart_dev *dev) {
} // extern "C"
#endif
-#endif // _USART_H_
+#endif
diff --git a/libmaple/usb.h b/libmaple/include/libmaple/usb.h
index 94579ea..8555aca 100644
--- a/libmaple/usb.h
+++ b/libmaple/include/libmaple/usb.h
@@ -1,7 +1,7 @@
/******************************************************************************
* The MIT License
*
- * Copyright (c) 2010 LeafLabs LLC.
+ * Copyright (c) 2010, 2011 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -28,16 +28,16 @@
* NOTE: This API is _unstable_ and will change drastically over time.
*/
-#ifndef _USB_H_
-#define _USB_H_
-
-#include "libmaple_types.h"
-#include "rcc.h"
+#ifndef _LIBMAPLE_USB_H_
+#define _LIBMAPLE_USB_H_
#ifdef __cplusplus
extern "C" {
#endif
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h>
+
#ifndef USB_ISR_MSK
/* Handle CTRM, WKUPM, SUSPM, ERRM, SOFM, ESOFM, RESETM */
#define USB_ISR_MSK 0xBF00
diff --git a/libmaple/usb/usb_cdcacm.h b/libmaple/include/libmaple/usb_cdcacm.h
index 8ca1c68..9d70758 100644
--- a/libmaple/usb/usb_cdcacm.h
+++ b/libmaple/include/libmaple/usb_cdcacm.h
@@ -25,15 +25,15 @@
*****************************************************************************/
/**
- * @file usb_cdcacm.h
+ * @file libmaple/include/libmaple/usb_cdcacm.h
* @brief USB CDC ACM (virtual serial terminal) support
*/
-#ifndef _USB_CDCACM_H_
-#define _USB_CDCACM_H_
+#ifndef _LIBMAPLE_USB_CDCACM_H_
+#define _LIBMAPLE_USB_CDCACM_H_
-#include "libmaple_types.h"
-#include "gpio.h"
+#include <libmaple/libmaple_types.h>
+#include <libmaple/gpio.h>
#ifdef __cplusplus
extern "C" {
diff --git a/libmaple/util.h b/libmaple/include/libmaple/util.h
index 7b41769..5a70348 100644
--- a/libmaple/util.h
+++ b/libmaple/include/libmaple/util.h
@@ -25,30 +25,30 @@
*****************************************************************************/
/**
- * @file util.h
+ * @file libmaple/include/libmaple/util.h
* @brief Miscellaneous utility macros and procedures.
*/
-#include "libmaple_types.h"
-
-#ifndef _UTIL_H_
-#define _UTIL_H_
+#ifndef _LIBMAPLE_UTIL_H_
+#define _LIBMAPLE_UTIL_H_
#ifdef __cplusplus
extern "C"{
#endif
+#include <libmaple/libmaple_types.h>
+
/*
* Bit manipulation
*/
-/** 1 << the bit number */
+/** 1UL shifted left by 'shift' */
#define BIT(shift) (1UL << (shift))
-/** Mask shifted left by 'shift' */
+/** 'Mask' shifted left by 'shift' */
#define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift))
/** Bits m to n of x */
#define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m)))
-/** True if v is a power of two (1, 2, 4, 8, ...) */
+/** True iff v is a power of two (1, 2, 4, 8, ...) */
#define IS_POWER_OF_TWO(v) ((v) && !((v) & ((v) - 1)))
/*
diff --git a/libmaple/iwdg.c b/libmaple/iwdg.c
index 63c1b2b..2456235 100644
--- a/libmaple/iwdg.c
+++ b/libmaple/iwdg.c
@@ -25,11 +25,11 @@
*****************************************************************************/
/**
- * @file iwdg.c
+ * @file libmaple/iwdg.c
* @brief Independent watchdog (IWDG) support
*/
-#include "iwdg.h"
+#include <libmaple/iwdg.h>
/**
* @brief Initialise and start the watchdog
diff --git a/libmaple/nvic.c b/libmaple/nvic.c
index 345c850..fe7c7bc 100644
--- a/libmaple/nvic.c
+++ b/libmaple/nvic.c
@@ -25,13 +25,13 @@
*****************************************************************************/
/**
- * @file nvic.c
+ * @file libmaple/nvic.c
* @brief Nested vector interrupt controller support.
*/
-#include "nvic.h"
-#include "scb.h"
-#include "stm32.h"
+#include <libmaple/nvic.h>
+#include <libmaple/scb.h>
+#include <libmaple/stm32.h>
/**
* @brief Set interrupt priority for an interrupt line
@@ -46,7 +46,7 @@
*/
void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) {
if (irqn < 0) {
- /* This interrupt is in the system handler block */
+ /* This interrupt is in the system handler block */
SCB_BASE->SHP[((uint32)irqn & 0xF) - 4] = (priority & 0xF) << 4;
} else {
NVIC_BASE->IP[irqn] = (priority & 0xF) << 4;
@@ -54,16 +54,12 @@ void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) {
}
/**
- * @brief Initialize the NVIC
- * @param vector_table_address Vector table base address.
- * @param offset Offset from vector_table_address. Some restrictions
- * apply to the use of nonzero offsets; see ST RM0008
- * and the ARM Cortex M3 Technical Reference Manual.
+ * @brief Initialize the NVIC, setting interrupts to a default priority.
*/
-void nvic_init(uint32 vector_table_address, uint32 offset) {
+void nvic_init(uint32 address, uint32 offset) {
uint32 i;
- nvic_set_vector_table(vector_table_address, offset);
+ nvic_set_vector_table(address, offset);
/*
* Lower priority level for all peripheral interrupts to lowest
@@ -78,10 +74,18 @@ void nvic_init(uint32 vector_table_address, uint32 offset) {
}
/**
- * Reset the vector table address.
+ * @brief Set the vector table base address.
+ *
+ * For stand-alone products, the vector table base address is normally
+ * the start of Flash (0x08000000).
+ *
+ * @param address Vector table base address.
+ * @param offset Offset from address. Some restrictions apply to the
+ * use of nonzero offsets; see the ARM Cortex M3
+ * Technical Reference Manual.
*/
-void nvic_set_vector_table(uint32 addr, uint32 offset) {
- SCB_BASE->VTOR = addr | (offset & 0x1FFFFF80);
+void nvic_set_vector_table(uint32 address, uint32 offset) {
+ SCB_BASE->VTOR = address | (offset & 0x1FFFFF80);
}
/**
diff --git a/libmaple/pwr.c b/libmaple/pwr.c
index ead8b64..3cf170f 100644
--- a/libmaple/pwr.c
+++ b/libmaple/pwr.c
@@ -25,12 +25,12 @@
*****************************************************************************/
/**
- * @file pwr.c
+ * @file libmaple/pwr.c
* @brief Power control (PWR) support.
*/
-#include "pwr.h"
-#include "rcc.h"
+#include <libmaple/pwr.h>
+#include <libmaple/rcc.h>
/**
* Enables the power interface clock, and resets the power device.
diff --git a/libmaple/rcc.c b/libmaple/rcc.c
index 65abfb6..8e7d1ea 100644
--- a/libmaple/rcc.c
+++ b/libmaple/rcc.c
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,182 +26,144 @@
*****************************************************************************/
/**
- * @file rcc.c
- * @brief Implements pretty much only the basic clock setup on the
- * stm32, clock enable/disable and peripheral reset commands.
+ * @file libmaple/rcc.c
+ * @brief Portable RCC routines.
*/
-#include "libmaple.h"
-#include "flash.h"
-#include "rcc.h"
-#include "bitband.h"
-
-#define APB1 RCC_APB1
-#define APB2 RCC_APB2
-#define AHB RCC_AHB
-
-struct rcc_dev_info {
- const rcc_clk_domain clk_domain;
- const uint8 line_num;
-};
-
-/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset
- * register bit numbers. */
-static const struct rcc_dev_info rcc_dev_table[] = {
- [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 },
- [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 },
- [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 },
- [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 },
- [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 },
- [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 },
- [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 },
- [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 },
- [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 },
- [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 },
- [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 },
- [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 },
- [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 },
- [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 },
- [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 },
- [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 },
- [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 },
- [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 },
- [RCC_PWR] = { .clk_domain = APB1, .line_num = 28},
- [RCC_BKP] = { .clk_domain = APB1, .line_num = 27},
- [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 },
- [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 },
- [RCC_CRC] = { .clk_domain = AHB, .line_num = 6},
- [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4},
- [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2},
- [RCC_USB] = { .clk_domain = APB1, .line_num = 23},
-#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
- [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 },
- [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 },
- [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 },
- [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 },
- [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 },
- [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 },
- [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 },
- [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 },
- [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 },
- [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 },
- [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 },
- [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 },
- [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 },
- [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 },
-#endif
-#ifdef STM32_XL_DENSITY
- [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 },
- [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 },
- [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 },
- [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 },
- [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 },
- [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 },
-#endif
-};
+#include <libmaple/rcc.h>
+
+#include "rcc_private.h"
/**
- * @brief Initialize the clock control system. Initializes the system
- * clock source to use the PLL driven by an external oscillator
- * @param sysclk_src system clock source, must be PLL
- * @param pll_src pll clock source, must be HSE
- * @param pll_mul pll multiplier
+ * @brief Get a peripheral's clock domain
+ * @param id Clock ID of the peripheral whose clock domain to return
+ * @return Clock source for the given clock ID
*/
-void rcc_clk_init(rcc_sysclk_src sysclk_src,
- rcc_pllsrc pll_src,
- rcc_pll_multiplier pll_mul) {
- uint32 cfgr = 0;
- uint32 cr;
-
- /* Assume that we're going to clock the chip off the PLL, fed by
- * the HSE */
- ASSERT(sysclk_src == RCC_CLKSRC_PLL &&
- pll_src == RCC_PLLSRC_HSE);
-
- RCC_BASE->CFGR = pll_src | pll_mul;
-
- /* Turn on the HSE */
- cr = RCC_BASE->CR;
- cr |= RCC_CR_HSEON;
- RCC_BASE->CR = cr;
- while (!(RCC_BASE->CR & RCC_CR_HSERDY))
- ;
-
- /* Now the PLL */
- cr |= RCC_CR_PLLON;
- RCC_BASE->CR = cr;
- while (!(RCC_BASE->CR & RCC_CR_PLLRDY))
- ;
+rcc_clk_domain rcc_dev_clk(rcc_clk_id id) {
+ return rcc_dev_table[id].clk_domain;
+}
- /* Finally, let's switch over to the PLL */
+/**
+ * @brief Switch the clock used as the source of the system clock.
+ *
+ * After switching the source, this function blocks until the new
+ * clock source is in use.
+ *
+ * @param sysclk_src New system clock source.
+ * @see rcc_sysclk_src
+ */
+void rcc_switch_sysclk(rcc_sysclk_src sysclk_src) {
+ uint32 cfgr = RCC_BASE->CFGR;
cfgr &= ~RCC_CFGR_SW;
- cfgr |= RCC_CFGR_SW_PLL;
+ cfgr |= sysclk_src;
+
+ /* Switch SYSCLK source. */
RCC_BASE->CFGR = cfgr;
- while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
+
+ /* Wait for new source to come into use. */
+ while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != (sysclk_src << 2))
;
}
-/**
- * @brief Turn on the clock line on a peripheral
- * @param id Clock ID of the peripheral to turn on.
+/*
+ * Turning clocks off and on, querying their status.
*/
-void rcc_clk_enable(rcc_clk_id id) {
- static const __io uint32* enable_regs[] = {
- [APB1] = &RCC_BASE->APB1ENR,
- [APB2] = &RCC_BASE->APB2ENR,
- [AHB] = &RCC_BASE->AHBENR,
- };
-
- rcc_clk_domain clk_domain = rcc_dev_clk(id);
- __io uint32* enr = (__io uint32*)enable_regs[clk_domain];
- uint8 lnum = rcc_dev_table[id].line_num;
-
- bb_peri_set_bit(enr, lnum, 1);
+
+/* IMPORTANT NOTE FOR IMPLEMENTORS:
+ *
+ * libmaple assumes that enum rcc_clk enumerators are two-byte
+ * values, stored in a uint16, in the following way:
+ *
+ * - The high-order byte is the byte offset (from RCC_BASE) of the register
+ * to touch when turning on or off the given clock.
+ *
+ * - The low-order byte is the bit in that register that turns the
+ * clock on or off.
+ *
+ * Example for STM32F1: Turning on the high-speed external clock (HSE)
+ * involves setting HSEON, bit 16, of RCC_CR. The high-order byte is
+ * then offsetof(struct rcc_reg_map, CR) = 0, and the low-order byte
+ * is 16.
+ *
+ * The corresponding value of RCC_CLK_HSE is thus (0 << 8) | 16 = 16.
+ *
+ * On all known STM32 series, this encoding has the property that
+ * adding one to the low byte also gives the bit to check to determine
+ * if the clock is ready. For example, on STM32F1, RCC_CR_HSERDY is
+ * bit 17. If that's not the case on your series, rcc_is_clk_ready()
+ * won't work for you. */
+
+/* Returns the RCC register which controls the clock source. */
+static inline __io uint32* rcc_clk_reg(rcc_clk clock) {
+ return (__io uint32*)((__io uint8*)RCC_BASE + (clock >> 8));
+}
+
+/* Returns a mask in rcc_clk_reg(clock) to be used for turning the
+ * clock on and off */
+static inline uint32 rcc_clk_on_mask(rcc_clk clock) {
+ return 1 << (clock & 0xFF);
+}
+
+/* Returns a mask in rcc_clk_reg(clock) to be used when checking the
+ * readiness of the clock. */
+static inline uint32 rcc_clk_ready_mask(rcc_clk clock) {
+ return rcc_clk_on_mask(clock) << 1;
}
/**
- * @brief Reset a peripheral.
- * @param id Clock ID of the peripheral to reset.
+ * @brief Turn on a clock source.
+ *
+ * After this routine exits, callers should ensure that the clock
+ * source is ready by waiting until rcc_is_clk_ready(clock) returns
+ * true.
+ *
+ * @param clock Clock to turn on.
+ * @see rcc_turn_off_clk()
+ * @see rcc_is_clk_ready()
*/
-void rcc_reset_dev(rcc_clk_id id) {
- static const __io uint32* reset_regs[] = {
- [APB1] = &RCC_BASE->APB1RSTR,
- [APB2] = &RCC_BASE->APB2RSTR,
- };
-
- rcc_clk_domain clk_domain = rcc_dev_clk(id);
- __io void* addr = (__io void*)reset_regs[clk_domain];
- uint8 lnum = rcc_dev_table[id].line_num;
-
- bb_peri_set_bit(addr, lnum, 1);
- bb_peri_set_bit(addr, lnum, 0);
+void rcc_turn_on_clk(rcc_clk clock) {
+ *rcc_clk_reg(clock) |= rcc_clk_on_mask(clock);
}
/**
- * @brief Get a peripheral's clock domain
- * @param id Clock ID of the peripheral whose clock domain to return
- * @return Clock source for the given clock ID
+ * @brief Turn off a clock source.
+ *
+ * In certain configurations, certain clock sources cannot be safely
+ * turned off. (For example, the main PLL on STM32F1 devices cannot be
+ * turned off if it has been selected as the SYSCLK source). Consult
+ * the reference material for your MCU to ensure it is safe to call
+ * this function.
+ *
+ * @param clock Clock to turn off.
+ * @see rcc_turn_on_clk()
+ * @see rcc_is_clk_ready()
*/
-rcc_clk_domain rcc_dev_clk(rcc_clk_id id) {
- return rcc_dev_table[id].clk_domain;
+void rcc_turn_off_clk(rcc_clk clock) {
+ *rcc_clk_reg(clock) &= ~rcc_clk_on_mask(clock);
}
/**
- * @brief Set the divider on a peripheral prescaler
- * @param prescaler prescaler to set
- * @param divider prescaler divider
+ * @brief Check if a clock is on.
+ * @param clock Clock to check.
+ * @return 1 if the clock is on, 0 if the clock is off.
*/
-void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) {
- static const uint32 masks[] = {
- [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE,
- [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1,
- [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2,
- [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE,
- [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE,
- };
+int rcc_is_clk_on(rcc_clk clock) {
+ return !!(*rcc_clk_reg(clock) & rcc_clk_on_mask(clock));
+}
- uint32 cfgr = RCC_BASE->CFGR;
- cfgr &= ~masks[prescaler];
- cfgr |= divider;
- RCC_BASE->CFGR = cfgr;
+/**
+ * @brief Check if a clock source is ready.
+ *
+ * In general, it is not safe to rely on a clock source unless this
+ * function returns nonzero. Also note that this function may return
+ * nonzero for a short period of time after a clock has been turned
+ * off. Consult the reference material for your MCU for more details.
+ *
+ * @param clock Clock whose readiness to check for.
+ * @return Nonzero if the clock is ready, zero otherwise.
+ * @see rcc_turn_on_clk()
+ * @see rcc_turn_off_clk()
+ */
+int rcc_is_clk_ready(rcc_clk clock) {
+ return (int)(*rcc_clk_reg(clock) & rcc_clk_ready_mask(clock));
}
diff --git a/libmaple/rcc_private.h b/libmaple/rcc_private.h
new file mode 100644
index 0000000..66eaf00
--- /dev/null
+++ b/libmaple/rcc_private.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/*
+ * RCC private header.
+ */
+
+#ifndef _LIBMAPLE_PRIVATE_RCC_H_
+#define _LIBMAPLE_PRIVATE_RCC_H_
+
+#include <libmaple/bitband.h>
+
+struct rcc_dev_info {
+ const rcc_clk_domain clk_domain;
+ const uint8 line_num;
+};
+
+extern const struct rcc_dev_info rcc_dev_table[];
+
+static inline void rcc_do_clk_enable(__io uint32** enable_regs,
+ rcc_clk_id id) {
+ __io uint32 *enable_reg = enable_regs[rcc_dev_clk(id)];
+ uint8 line_num = rcc_dev_table[id].line_num;
+ bb_peri_set_bit(enable_reg, line_num, 1);
+}
+
+static inline void rcc_do_reset_dev(__io uint32** reset_regs,
+ rcc_clk_id id) {
+ __io uint32 *reset_reg = reset_regs[rcc_dev_clk(id)];
+ uint8 line_num = rcc_dev_table[id].line_num;
+ bb_peri_set_bit(reset_reg, line_num, 1);
+ bb_peri_set_bit(reset_reg, line_num, 0);
+}
+
+static inline void rcc_do_set_prescaler(const uint32 *masks,
+ rcc_prescaler prescaler,
+ uint32 divider) {
+ uint32 cfgr = RCC_BASE->CFGR;
+ cfgr &= ~masks[prescaler];
+ cfgr |= divider;
+ RCC_BASE->CFGR = cfgr;
+}
+
+#endif
diff --git a/libmaple/rules.mk b/libmaple/rules.mk
index 1ee611d..71979f0 100644
--- a/libmaple/rules.mk
+++ b/libmaple/rules.mk
@@ -3,43 +3,35 @@ sp := $(sp).x
dirstack_$(sp) := $(d)
d := $(dir)
BUILDDIRS += $(BUILD_PATH)/$(d)
-BUILDDIRS += $(BUILD_PATH)/$(d)/usb
-BUILDDIRS += $(BUILD_PATH)/$(d)/usb/usb_lib
-LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usb -I$(LIBMAPLE_PATH)/usb/usb_lib
+LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH)/include -I$(LIBMAPLE_MODULE_SERIES)/include
+LIBMAPLE_PRIVATE_INCLUDES := -I$(LIBMAPLE_PATH)
# Local flags
-CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) -Wall -Werror
+CFLAGS_$(d) = $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror
# Local rules and targets
-cSRCS_$(d) := adc.c \
- bkp.c \
- dac.c \
- dma.c \
- exti.c \
- flash.c \
- fsmc.c \
- gpio.c \
- iwdg.c \
- nvic.c \
- pwr.c \
- i2c.c \
- rcc.c \
- spi.c \
- syscalls.c \
- systick.c \
- timer.c \
- usart.c \
- util.c \
- usb/usb.c \
- usb/usb_reg_map.c \
- usb/usb_cdcacm.c \
- usb/usb_lib/usb_core.c \
- usb/usb_lib/usb_init.c \
- usb/usb_lib/usb_mem.c \
- usb/usb_lib/usb_regs.c
-
+cSRCS_$(d) := adc.c
+cSRCS_$(d) += dac.c
+cSRCS_$(d) += dma.c
+cSRCS_$(d) += exti.c
+cSRCS_$(d) += flash.c
+cSRCS_$(d) += gpio.c
+cSRCS_$(d) += iwdg.c
+cSRCS_$(d) += nvic.c
+cSRCS_$(d) += pwr.c
+cSRCS_$(d) += rcc.c
+cSRCS_$(d) += spi.c
+cSRCS_$(d) += systick.c
+cSRCS_$(d) += timer.c
+cSRCS_$(d) += usart.c
+cSRCS_$(d) += usart_private.c
+cSRCS_$(d) += util.c
sSRCS_$(d) := exc.S
+# I2C support must be ported to F2:
+ifeq ($(MCU_SERIES),stm32f1)
+cSRCS_$(d) += i2c.c
+endif
cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
diff --git a/libmaple/spi.c b/libmaple/spi.c
index 1c68529..194a82e 100644
--- a/libmaple/spi.c
+++ b/libmaple/spi.c
@@ -1,6 +1,7 @@
/******************************************************************************
* The MIT License
*
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
* Copyright (c) 2010 Perry Hung.
*
* Permission is hereby granted, free of charge, to any person
@@ -25,48 +26,18 @@
*****************************************************************************/
/**
- * @file spi.c
+ * @file libmaple/spi.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Serial Peripheral Interface (SPI) support.
* Currently, there is no Integrated Interchip Sound (I2S) support.
*/
-#include "spi.h"
-#include "bitband.h"
+#include <libmaple/spi.h>
+#include <libmaple/bitband.h>
static void spi_reconfigure(spi_dev *dev, uint32 cr1_config);
/*
- * SPI devices
- */
-
-static spi_dev spi1 = {
- .regs = SPI1_BASE,
- .clk_id = RCC_SPI1,
- .irq_num = NVIC_SPI1,
-};
-/** SPI device 1 */
-spi_dev *SPI1 = &spi1;
-
-static spi_dev spi2 = {
- .regs = SPI2_BASE,
- .clk_id = RCC_SPI2,
- .irq_num = NVIC_SPI2,
-};
-/** SPI device 2 */
-spi_dev *SPI2 = &spi2;
-
-#ifdef STM32_HIGH_DENSITY
-static spi_dev spi3 = {
- .regs = SPI3_BASE,
- .clk_id = RCC_SPI3,
- .irq_num = NVIC_SPI3,
-};
-/** SPI device 3 */
-spi_dev *SPI3 = &spi3;
-#endif
-
-/*
* SPI convenience routines
*/
@@ -80,37 +51,6 @@ void spi_init(spi_dev *dev) {
}
/**
- * @brief Configure GPIO bit modes for use as a SPI port's pins.
- * @param as_master If true, configure bits for use as a bus master.
- * Otherwise, configure bits for use as slave.
- * @param nss_dev NSS pin's GPIO device
- * @param comm_dev SCK, MISO, MOSI pins' GPIO device
- * @param nss_bit NSS pin's GPIO bit on nss_dev
- * @param sck_bit SCK pin's GPIO bit on comm_dev
- * @param miso_bit MISO pin's GPIO bit on comm_dev
- * @param mosi_bit MOSI pin's GPIO bit on comm_dev
- */
-void spi_gpio_cfg(uint8 as_master,
- gpio_dev *nss_dev,
- uint8 nss_bit,
- gpio_dev *comm_dev,
- uint8 sck_bit,
- uint8 miso_bit,
- uint8 mosi_bit) {
- if (as_master) {
- gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP);
- gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP);
- gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING);
- gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP);
- } else {
- gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING);
- gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING);
- gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP);
- gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING);
- }
-}
-
-/**
* @brief Configure and enable a SPI device as bus master.
*
* The device's peripheral will be disabled before being reconfigured.
@@ -165,18 +105,6 @@ uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) {
}
/**
- * @brief Call a function on each SPI port
- * @param fn Function to call.
- */
-void spi_foreach(void (*fn)(spi_dev*)) {
- fn(SPI1);
- fn(SPI2);
-#ifdef STM32_HIGH_DENSITY
- fn(SPI3);
-#endif
-}
-
-/**
* @brief Enable a SPI peripheral
* @param dev Device to enable
*/
@@ -234,7 +162,3 @@ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) {
dev->regs->CR1 = cr1_config;
spi_peripheral_enable(dev);
}
-
-/*
- * IRQ handlers (TODO)
- */
diff --git a/libmaple/spi_private.h b/libmaple/spi_private.h
new file mode 100644
index 0000000..f0e0bd1
--- /dev/null
+++ b/libmaple/spi_private.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+#ifndef _LIBMAPLE_SPI_PRIVATE_H_
+#define _LIBMAPLE_SPI_PRIVATE_H_
+
+#define SPI_DEV(num) \
+ { \
+ .regs = SPI##num##_BASE, \
+ .clk_id = RCC_SPI##num, \
+ .irq_num = NVIC_SPI##num, \
+ }
+
+#endif
diff --git a/libmaple/stm32.h b/libmaple/stm32.h
deleted file mode 100644
index 3b54dbc..0000000
--- a/libmaple/stm32.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/******************************************************************************
- * The MIT License
- *
- * Copyright (c) 2010 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 stm32.h
- * @brief STM32 chip-specific definitions
- */
-
-#ifndef _STM32_H_
-#define _STM32_H_
-
-/*
- * User-specific configuration.
- *
- * The #defines here depend upon how libmaple is used. Because of the
- * potential for a mismatch between them and the actual libmaple
- * usage, you should try to keep their number to an absolute minimum.
- */
-
-#ifdef __DOXYGEN_PREDEFINED_HACK
-
- /** @brief APB1 clock speed, in Hz. */
- #define STM32_PCLK1
- /** @brief APB2 clock speed, in Hz. */
- #define STM32_PCLK2
-
- /** Deprecated. Use STM32_PCLK1 instead. */
- #define PCLK1
- /** Deprecated. Use STM32_PCLK2 instead. */
- #define PCLK2
-
-#endif
-
-#ifndef STM32_PCLK1
-#define STM32_PCLK1 36000000U
-#endif
-#ifndef PCLK1
-#define PCLK1 STM32_PCLK1
-#endif
-#if PCLK1 != STM32_PCLK1
-#error "(Deprecated) PCLK1 differs from STM32_PCLK1"
-#endif
-
-#ifndef STM32_PCLK2
-#define STM32_PCLK2 72000000U
-#endif
-#ifndef PCLK2
-#define PCLK2 STM32_PCLK2
-#endif
-#if PCLK2 != STM32_PCLK2
-#error "(Deprecated) PCLK2 differs from STM32_PCLK2"
-#endif
-
-/*
- * Density-specific configuration.
- */
-
-#ifdef __DOXYGEN_PREDEFINED_HACK
-
- /**
- * @brief Number of interrupts in the NVIC.
- *
- * This define is automatically generated whenever the proper
- * density is defined (currently, this is restricted to defining
- * one of STM32_MEDIUM_DENSITY and STM32_HIGH_DENSITY).
- */
- #define STM32_NR_INTERRUPTS
-
- /** Deprecated. Use STM32_NR_INTERRUPTS instead. */
- #define NR_INTERRUPTS
-
-#endif
-
-#ifdef STM32_MEDIUM_DENSITY
- #define STM32_NR_INTERRUPTS 43
-#elif defined(STM32_HIGH_DENSITY)
- #define STM32_NR_INTERRUPTS 60
-#else
-#error "No STM32 board type defined!"
-#endif
-
-#define NR_INTERRUPTS STM32_NR_INTERRUPTS
-
-/*
- * MCU-specific configuration.
- */
-
-#ifdef __DOXYGEN_PREDEFINED_HACK
-
- /**
- * Number of GPIO ports.
- */
- #define STM32_NR_GPIO_PORTS
-
- /**
- * @brief Multiplier to convert microseconds into loop iterations
- * in delay_us().
- *
- * @see delay_us()
- */
- #define STM32_DELAY_US_MULT
-
- /**
- * @brief Pointer to end of built-in SRAM.
- *
- * Points to the address which is 1 byte past the last valid
- * SRAM address.
- */
- #define STM32_SRAM_END
-
- /** Deprecated. Use STM32_NR_GPIO_PORTS instead. */
- #define NR_GPIO_PORTS
- /** Deprecated. Use STM32_DELAY_US_MULT instead. */
- #define DELAY_US_MULT
-
-#endif
-
-#if defined(MCU_STM32F103RB)
- /* e.g., LeafLabs Maple */
-
- #define STM32_NR_GPIO_PORTS 4
- #define STM32_DELAY_US_MULT 12
- #define STM32_SRAM_END ((void*)0x20005000)
-
- #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS
- #define DELAY_US_MULT STM32_DELAY_US_MULT
-
-#elif defined(MCU_STM32F103ZE)
- /* e.g., LeafLabs Maple Native */
-
- #define STM32_NR_GPIO_PORTS 7
- #define STM32_DELAY_US_MULT 12
- #define STM32_SRAM_END ((void*)0x20010000)
-
- #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS
- #define DELAY_US_MULT STM32_DELAY_US_MULT
-
-#elif defined(MCU_STM32F103CB)
- /* e.g., LeafLabs Maple Mini */
-
- /* This STM32_NR_GPIO_PORTS value is not, strictly speaking, true.
- * But only pins 0 and 1 exist, and they're used for OSC on the
- * Mini, so we'll live with this for now. */
- #define STM32_NR_GPIO_PORTS 3
- #define STM32_DELAY_US_MULT 12
- #define STM32_SRAM_END ((void*)0x20005000)
-
- #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS
- #define DELAY_US_MULT STM32_DELAY_US_MULT
-
-#elif defined(MCU_STM32F103RE)
- /* e.g., LeafLabs Maple RET6 edition */
-
- #define STM32_NR_GPIO_PORTS 4
- #define STM32_DELAY_US_MULT 12
- #define STM32_SRAM_END ((void*)0x20010000)
-
- #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS
- #define DELAY_US_MULT STM32_DELAY_US_MULT
-
-#else
-
-#error "No MCU type specified. Add something like -DMCU_STM32F103RB " \
- "to your compiler arguments (probably in a Makefile)."
-
-#endif
-
-#endif /* _STM32_H_ */
diff --git a/libmaple/stm32_private.h b/libmaple/stm32_private.h
new file mode 100644
index 0000000..427417a
--- /dev/null
+++ b/libmaple/stm32_private.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * 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.
+*****************************************************************************/
+
+#ifndef _LIBMAPLE_STM32_PRIVATE_H_
+#define _LIBMAPLE_STM32_PRIVATE_H_
+
+typedef enum stm32_mem_block_purpose {
+ STM32_BLOCK_CODE,
+ STM32_BLOCK_SRAM,
+ STM32_BLOCK_PERIPH,
+ STM32_BLOCK_FSMC_1_2,
+ STM32_BLOCK_FSMC_3_4,
+ STM32_BLOCK_FSMC_REG,
+ STM32_BLOCK_UNUSED,
+ STM32_BLOCK_CORTEX_INTERNAL,
+} stm32_mem_block_purpose;
+
+static inline stm32_mem_block_purpose stm32_block_purpose(void *addr) {
+ return (stm32_mem_block_purpose)((unsigned)addr >> 29);
+}
+
+#endif
diff --git a/libmaple/stm32f1/adc.c b/libmaple/stm32f1/adc.c
new file mode 100644
index 0000000..ecfbc1c
--- /dev/null
+++ b/libmaple/stm32f1/adc.c
@@ -0,0 +1,112 @@
+/******************************************************************************
+ * 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/adc.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief STM32F1 ADC support.
+ */
+
+#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;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static 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);
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ fn(ADC3);
+#endif
+}
+
+void adc_config_gpio(const adc_dev *ignored, 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/bkp.c b/libmaple/stm32f1/bkp.c
index 7d1ad7f..f435ff1 100644
--- a/libmaple/bkp.c
+++ b/libmaple/stm32f1/bkp.c
@@ -25,14 +25,14 @@
*****************************************************************************/
/**
- * @file bkp.c
- * @brief Backup register support.
+ * @file libmaple/stm32f1/bkp.c
+ * @brief STM32F1 Backup register support.
*/
-#include "bkp.h"
-#include "pwr.h"
-#include "rcc.h"
-#include "bitband.h"
+#include <libmaple/bkp.h>
+#include <libmaple/pwr.h>
+#include <libmaple/rcc.h>
+#include <libmaple/bitband.h>
static inline __io uint32* data_register(uint8 reg);
diff --git a/libmaple/stm32f1/dma.c b/libmaple/stm32f1/dma.c
new file mode 100644
index 0000000..5364a04
--- /dev/null
+++ b/libmaple/stm32f1/dma.c
@@ -0,0 +1,412 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ * 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/stm32f1/dma.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>;
+ * Original implementation by Michael Hope
+ * @brief STM32F1 DMA support.
+ */
+
+#include <libmaple/dma.h>
+#include <libmaple/bitband.h>
+
+/* Hack to ensure inlining in dma_irq_handler() */
+#define DMA_GET_HANDLER(dev, tube) (dev->handlers[tube - 1].handler)
+#include "dma_private.h"
+
+/*
+ * Devices
+ */
+
+static dma_dev dma1 = {
+ .regs = DMA1_BASE,
+ .clk_id = RCC_DMA1,
+ .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH2 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH3 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH4 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH5 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH6 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH7 }},
+};
+/** STM32F1 DMA1 device */
+dma_dev *DMA1 = &dma1;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static dma_dev dma2 = {
+ .regs = DMA2_BASE,
+ .clk_id = RCC_DMA2,
+ .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_CH2 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_CH3 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }}, /* !@#$ */
+};
+/** STM32F1 DMA2 device */
+dma_dev *DMA2 = &dma2;
+#endif
+
+/*
+ * Auxiliary routines
+ */
+
+/* Can channel serve cfg->tube_req_src? */
+static int cfg_req_ok(dma_channel channel, dma_tube_config *cfg) {
+ return (cfg->tube_req_src & 0x7) == channel;
+}
+
+/* Can dev serve cfg->tube_req_src? */
+static int cfg_dev_ok(dma_dev *dev, dma_tube_config *cfg) {
+ return (rcc_clk_id)(cfg->tube_req_src >> 3) == dev->clk_id;
+}
+
+/* Is addr acceptable for use as DMA src/dst? */
+static int cfg_mem_ok(__io void *addr) {
+ enum dma_atype atype = _dma_addr_type(addr);
+ return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER;
+}
+
+/* Is the direction implied by src->dst supported? */
+static int cfg_dir_ok(dma_tube_config *cfg) {
+ /* We can't do peripheral->peripheral transfers. */
+ return ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) ||
+ (_dma_addr_type(cfg->tube_dst) == DMA_ATYPE_MEM));
+}
+
+static int preconfig_check(dma_dev *dev, dma_channel channel,
+ dma_tube_config *cfg) {
+ if (!cfg_req_ok(channel, cfg)) {
+ return -DMA_TUBE_CFG_EREQ;
+ }
+ if (cfg->tube_nr_xfers > 65535) {
+ return -DMA_TUBE_CFG_ENDATA;
+ }
+ if (!cfg_dev_ok(dev, cfg)) {
+ return -DMA_TUBE_CFG_EDEV;
+ }
+ if (!cfg_mem_ok(cfg->tube_src)) {
+ return -DMA_TUBE_CFG_ESRC;
+ }
+ if (!cfg_mem_ok(cfg->tube_dst)) {
+ return -DMA_TUBE_CFG_EDST;
+ }
+ if (!cfg_dir_ok(cfg)) {
+ return -DMA_TUBE_CFG_EDIR;
+ }
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+static inline void set_ccr(dma_tube_reg_map *chregs,
+ dma_xfer_size msize, int minc,
+ dma_xfer_size psize, int pinc,
+ uint32 other_flags) {
+ chregs->CCR = ((msize << 10) | (psize << 8) |
+ (minc ? DMA_CCR_MINC : 0) | (pinc ? DMA_CCR_PINC : 0) |
+ other_flags);
+}
+
+static inline uint32 cfg_ccr_flags(unsigned tube_flags) {
+ /* DMA_CFG_SRC_INC and DMA_CFG_DST_INC are special */
+ return tube_flags & ~(DMA_CFG_SRC_INC | DMA_CFG_DST_INC);
+}
+
+/* Configure chregs according to cfg, where cfg->tube_dst is peripheral. */
+static int config_to_per(dma_tube_reg_map *chregs, dma_tube_config *cfg) {
+ /* Check that ->tube_src is memory (if it's anything else, we
+ * shouldn't have been called). */
+ ASSERT(_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM);
+
+ set_ccr(chregs,
+ cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC,
+ cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC,
+ (cfg_ccr_flags(cfg->tube_flags) | DMA_CCR_DIR_FROM_MEM));
+ chregs->CMAR = (uint32)cfg->tube_src;
+ chregs->CPAR = (uint32)cfg->tube_dst;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Configure chregs according to cfg, where cfg->tube_dst is memory. */
+static int config_to_mem(dma_tube_reg_map *chregs, dma_tube_config *cfg) {
+ uint32 mem2mem;
+
+ if ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) &&
+ (cfg->tube_flags & DMA_CFG_CIRC)) {
+ /* Can't do mem-to-mem and circular mode */
+ return -DMA_TUBE_CFG_ECFG;
+ }
+
+ mem2mem = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ?
+ DMA_CCR_MEM2MEM : 0);
+ set_ccr(chregs,
+ cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC,
+ cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC,
+ (cfg_ccr_flags(cfg->tube_flags) |
+ DMA_CCR_DIR_FROM_PER |
+ mem2mem));
+ chregs->CNDTR = cfg->tube_nr_xfers;
+ chregs->CMAR = (uint32)cfg->tube_dst;
+ chregs->CPAR = (uint32)cfg->tube_src;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/*
+ * Routines
+ */
+
+int dma_tube_cfg(dma_dev *dev, dma_channel channel, dma_tube_config *cfg) {
+ dma_tube_reg_map *chregs;
+ int ret = preconfig_check(dev, channel, cfg);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ dma_disable(dev, channel); /* Must disable before reconfiguring */
+ dma_clear_isr_bits(dev, channel); /* For sanity and consistency
+ * with STM32F2. */
+
+ chregs = dma_tube_regs(dev, channel);
+ switch (_dma_addr_type(cfg->tube_dst)) {
+ case DMA_ATYPE_PER:
+ ret = config_to_per(chregs, cfg);
+ break;
+ case DMA_ATYPE_MEM:
+ ret = config_to_mem(chregs, cfg);
+ break;
+ default:
+ /* Can't happen */
+ ASSERT(0);
+ return -DMA_TUBE_CFG_ECFG;
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ chregs->CNDTR = cfg->tube_nr_xfers;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+void dma_set_priority(dma_dev *dev,
+ dma_channel channel,
+ dma_priority priority) {
+ dma_channel_reg_map *channel_regs;
+ uint32 ccr;
+
+ ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
+
+ channel_regs = dma_channel_regs(dev, channel);
+ ccr = channel_regs->CCR;
+ ccr &= ~DMA_CCR_PL;
+ ccr |= (priority << 12);
+ channel_regs->CCR = ccr;
+}
+
+void dma_set_num_transfers(dma_dev *dev,
+ dma_channel channel,
+ uint16 num_transfers) {
+ dma_channel_reg_map *channel_regs;
+
+ ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
+
+ channel_regs = dma_channel_regs(dev, channel);
+ channel_regs->CNDTR = num_transfers;
+}
+
+void dma_attach_interrupt(dma_dev *dev, dma_channel channel,
+ void (*handler)(void)) {
+ DMA_GET_HANDLER(dev, channel) = handler;
+ nvic_irq_enable(dev->handlers[channel - 1].irq_line);
+}
+
+void dma_detach_interrupt(dma_dev *dev, dma_channel channel) {
+ /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */
+ dma_channel_regs(dev, channel)->CCR &= ~0xF;
+ DMA_GET_HANDLER(dev, channel) = NULL;
+}
+
+void dma_enable(dma_dev *dev, dma_channel channel) {
+ dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel);
+ bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1);
+}
+
+void dma_disable(dma_dev *dev, dma_channel channel) {
+ dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel);
+ bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0);
+}
+
+dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) {
+ /* Grab and clear the ISR bits. */
+ uint8 status_bits = dma_get_isr_bits(dev, channel);
+ dma_clear_isr_bits(dev, channel);
+
+ /* If the channel global interrupt flag is cleared, then
+ * something's very wrong. */
+ ASSERT(status_bits & 0x1);
+ /* If GIF is set, then some other flag should be set, barring
+ * something unexpected (e.g. the user making an unforeseen IFCR
+ * write). */
+ ASSERT(status_bits != 0x1);
+
+ /* ISR flags get set even if the corresponding interrupt enable
+ * bits in the channel's configuration register are cleared, so we
+ * can't use a switch here.
+ *
+ * Don't change the order of these if statements. */
+ if (status_bits & 0x8) {
+ return DMA_TRANSFER_ERROR;
+ } else if (status_bits & 0x2) {
+ return DMA_TRANSFER_COMPLETE;
+ } else if (status_bits & 0x4) {
+ return DMA_TRANSFER_HALF_COMPLETE;
+ }
+
+ /* If we get here, one of our assumptions has been violated, but
+ * the debug level is too low for the above ASSERTs() to have had
+ * any effect. In order to fail fast, mimic the DMA controller's
+ * behavior when an error occurs. */
+ dma_disable(dev, channel);
+ return DMA_TRANSFER_ERROR;
+}
+
+void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) {
+ dma_channel_reg_map *chan_regs;
+
+ ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
+
+ chan_regs = dma_channel_regs(dev, channel);
+ chan_regs->CMAR = (uint32)addr;
+}
+
+void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) {
+ dma_channel_reg_map *chan_regs;
+
+ ASSERT_FAULT(!dma_is_channel_enabled(dev, channel));
+
+ chan_regs = dma_channel_regs(dev, channel);
+ chan_regs->CPAR = (uint32)addr;
+}
+
+/**
+ * @brief Deprecated. Use dma_tube_cfg() instead.
+ *
+ * Set up a DMA transfer.
+ *
+ * The channel will be disabled before being reconfigured. The
+ * transfer will have low priority by default. You may choose another
+ * priority before the transfer begins using dma_set_priority(), as
+ * well as performing any other configuration you desire. When the
+ * channel is configured to your liking, enable it using dma_enable().
+ *
+ * @param dev DMA device.
+ * @param channel DMA channel.
+ * @param peripheral_address Base address of peripheral data register
+ * involved in the transfer.
+ * @param peripheral_size Peripheral data transfer size.
+ * @param memory_address Base memory address involved in the transfer.
+ * @param memory_size Memory data transfer size.
+ * @param mode Logical OR of dma_mode_flags
+ *
+ * @see dma_tube_cfg()
+ *
+ * @sideeffect Disables the given DMA channel.
+ * @see dma_xfer_size
+ * @see dma_mode_flags
+ * @see dma_set_num_transfers()
+ * @see dma_set_priority()
+ * @see dma_attach_interrupt()
+ * @see dma_enable()
+ */
+__deprecated
+void dma_setup_transfer(dma_dev *dev,
+ dma_channel channel,
+ __io void *peripheral_address,
+ dma_xfer_size peripheral_size,
+ __io void *memory_address,
+ dma_xfer_size memory_size,
+ uint32 mode) {
+ dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel);
+
+ dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */
+ channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode;
+ channel_regs->CMAR = (uint32)memory_address;
+ channel_regs->CPAR = (uint32)peripheral_address;
+}
+
+/*
+ * IRQ handlers
+ */
+
+void __irq_dma1_channel1(void) {
+ dma_irq_handler(DMA1, DMA_CH1);
+}
+
+void __irq_dma1_channel2(void) {
+ dma_irq_handler(DMA1, DMA_CH2);
+}
+
+void __irq_dma1_channel3(void) {
+ dma_irq_handler(DMA1, DMA_CH3);
+}
+
+void __irq_dma1_channel4(void) {
+ dma_irq_handler(DMA1, DMA_CH4);
+}
+
+void __irq_dma1_channel5(void) {
+ dma_irq_handler(DMA1, DMA_CH5);
+}
+
+void __irq_dma1_channel6(void) {
+ dma_irq_handler(DMA1, DMA_CH6);
+}
+
+void __irq_dma1_channel7(void) {
+ dma_irq_handler(DMA1, DMA_CH7);
+}
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+void __irq_dma2_channel1(void) {
+ dma_irq_handler(DMA2, DMA_CH1);
+}
+
+void __irq_dma2_channel2(void) {
+ dma_irq_handler(DMA2, DMA_CH2);
+}
+
+void __irq_dma2_channel3(void) {
+ dma_irq_handler(DMA2, DMA_CH3);
+}
+
+void __irq_dma2_channel4_5(void) {
+ if ((DMA2_BASE->CCR4 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF4)) {
+ dma_irq_handler(DMA2, DMA_CH4);
+ }
+ if ((DMA2_BASE->CCR5 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF5)) {
+ dma_irq_handler(DMA2, DMA_CH5);
+ }
+}
+#endif
diff --git a/libmaple/stm32f1/exti.c b/libmaple/stm32f1/exti.c
new file mode 100644
index 0000000..b9ff401
--- /dev/null
+++ b/libmaple/stm32f1/exti.c
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * 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.
+*****************************************************************************/
+
+#include <libmaple/gpio.h>
+#include "exti_private.h"
+
+void exti_select(exti_num num, exti_cfg port) {
+ exti_do_select(&AFIO_BASE->EXTICR1 + num / 4, num, port);
+}
diff --git a/libmaple/fsmc.c b/libmaple/stm32f1/fsmc.c
index 06ca7df..210f0be 100644
--- a/libmaple/fsmc.c
+++ b/libmaple/stm32f1/fsmc.c
@@ -1,6 +1,7 @@
/******************************************************************************
* The MIT License
*
+ * Copyright (c) 2012 LeafLabs, LLC.
* Copyright (c) 2010 Bryan Newbold.
*
* Permission is hereby granted, free of charge, to any person
@@ -25,18 +26,19 @@
*****************************************************************************/
/**
- * @file fsmc.c
- * @brief Flexible static memory controller support.
+ * @file libmaple/stm32f1/fsmc.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Bryan Newbold <bnewbold@robocracy.org>
+ * @brief STM32F1 FSMC support.
*/
-#include "fsmc.h"
-#include "gpio.h"
+#include <libmaple/stm32.h>
-#ifdef STM32_HIGH_DENSITY
+#if STM32_HAVE_FSMC /* Don't try building the rest for MCUs without FSMC */
+
+#include <libmaple/fsmc.h>
+#include <libmaple/gpio.h>
-/**
- * Configure FSMC GPIOs for use with SRAM.
- */
void fsmc_sram_init_gpios(void) {
/* Data lines... */
gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP);
@@ -90,4 +92,4 @@ void fsmc_sram_init_gpios(void) {
gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1
}
-#endif /* STM32_HIGH_DENSITY */
+#endif /* STM32_HAVE_FSMC */
diff --git a/libmaple/stm32f1/gpio.c b/libmaple/stm32f1/gpio.c
new file mode 100644
index 0000000..4b596e9
--- /dev/null
+++ b/libmaple/stm32f1/gpio.c
@@ -0,0 +1,166 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * 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/gpio.c
+ * @brief STM32F1 GPIO support.
+ */
+
+#include <libmaple/gpio.h>
+#include <libmaple/rcc.h>
+
+/*
+ * GPIO devices
+ */
+
+gpio_dev gpioa = {
+ .regs = GPIOA_BASE,
+ .clk_id = RCC_GPIOA,
+ .exti_port = EXTI_PA,
+};
+/** GPIO port A device. */
+gpio_dev* const GPIOA = &gpioa;
+
+gpio_dev gpiob = {
+ .regs = GPIOB_BASE,
+ .clk_id = RCC_GPIOB,
+ .exti_port = EXTI_PB,
+};
+/** GPIO port B device. */
+gpio_dev* const GPIOB = &gpiob;
+
+gpio_dev gpioc = {
+ .regs = GPIOC_BASE,
+ .clk_id = RCC_GPIOC,
+ .exti_port = EXTI_PC,
+};
+/** GPIO port C device. */
+gpio_dev* const GPIOC = &gpioc;
+
+gpio_dev gpiod = {
+ .regs = GPIOD_BASE,
+ .clk_id = RCC_GPIOD,
+ .exti_port = EXTI_PD,
+};
+/** GPIO port D device. */
+gpio_dev* const GPIOD = &gpiod;
+
+#ifdef STM32_HIGH_DENSITY
+gpio_dev gpioe = {
+ .regs = GPIOE_BASE,
+ .clk_id = RCC_GPIOE,
+ .exti_port = EXTI_PE,
+};
+/** GPIO port E device. */
+gpio_dev* const GPIOE = &gpioe;
+
+gpio_dev gpiof = {
+ .regs = GPIOF_BASE,
+ .clk_id = RCC_GPIOF,
+ .exti_port = EXTI_PF,
+};
+/** GPIO port F device. */
+gpio_dev* const GPIOF = &gpiof;
+
+gpio_dev gpiog = {
+ .regs = GPIOG_BASE,
+ .clk_id = RCC_GPIOG,
+ .exti_port = EXTI_PG,
+};
+/** GPIO port G device. */
+gpio_dev* const GPIOG = &gpiog;
+#endif
+
+/*
+ * GPIO routines
+ */
+
+/**
+ * Initialize and reset all available GPIO devices.
+ */
+void gpio_init_all(void) {
+ gpio_init(GPIOA);
+ gpio_init(GPIOB);
+ gpio_init(GPIOC);
+ gpio_init(GPIOD);
+#ifdef STM32_HIGH_DENSITY
+ gpio_init(GPIOE);
+ gpio_init(GPIOF);
+ gpio_init(GPIOG);
+#endif
+}
+
+/**
+ * Set the mode of a GPIO pin.
+ *
+ * @param dev GPIO device.
+ * @param pin Pin on the device whose mode to set, 0--15.
+ * @param mode General purpose or alternate function mode to set the pin to.
+ * @see gpio_pin_mode
+ */
+void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) {
+ gpio_reg_map *regs = dev->regs;
+ __io uint32 *cr = &regs->CRL + (pin >> 3);
+ uint32 shift = (pin & 0x7) * 4;
+ uint32 tmp = *cr;
+
+ tmp &= ~(0xF << shift);
+ tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift;
+ *cr = tmp;
+
+ if (mode == GPIO_INPUT_PD) {
+ regs->ODR &= ~(1U << pin);
+ } else if (mode == GPIO_INPUT_PU) {
+ regs->ODR |= (1U << pin);
+ }
+}
+
+/*
+ * AFIO
+ */
+
+/**
+ * @brief Initialize the AFIO clock, and reset the AFIO registers.
+ */
+void afio_init(void) {
+ rcc_clk_enable(RCC_AFIO);
+ rcc_reset_dev(RCC_AFIO);
+}
+
+#define AFIO_EXTI_SEL_MASK 0xF
+
+/**
+ * @brief Perform an alternate function remap.
+ * @param remapping Remapping to perform.
+ */
+void afio_remap(afio_remap_peripheral remapping) {
+ if (remapping & AFIO_REMAP_USE_MAPR2) {
+ remapping &= ~AFIO_REMAP_USE_MAPR2;
+ AFIO_BASE->MAPR2 |= remapping;
+ } else {
+ AFIO_BASE->MAPR |= remapping;
+ }
+}
diff --git a/libmaple/stm32f1/i2c.c b/libmaple/stm32f1/i2c.c
new file mode 100644
index 0000000..8439793
--- /dev/null
+++ b/libmaple/stm32f1/i2c.c
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * 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/stm32f1/i2c.c
+ * @brief STM32F1 I2C support
+ */
+
+#include "i2c_private.h"
+#include <libmaple/i2c.h>
+
+/*
+ * Devices
+ */
+
+static i2c_dev i2c1 = I2C_DEV_OLD(1, &gpiob, 7, 6);
+static i2c_dev i2c2 = I2C_DEV_OLD(2, &gpiob, 11, 10);
+
+/** STM32F1 I2C device 1 */
+i2c_dev* const I2C1 = &i2c1;
+/** STM32F1 I2C device 2 */
+i2c_dev* const I2C2 = &i2c2;
+
+/*
+ * Routines
+ */
+
+static int i2c1_wants_remap(const i2c_dev *dev) {
+ /* Check if we've got I2C1 configured for SDA/SCL remap on PB9/PB8 */
+ return (dev->clk_id == RCC_I2C1) &&
+ (scl_port(dev)->clk_id == RCC_GPIOB) &&
+ (sda_port(dev)->clk_id == RCC_GPIOB) &&
+ (dev->sda_pin == 9) &&
+ (dev->scl_pin == 8);
+}
+
+void i2c_config_gpios(const i2c_dev *dev) {
+ if (i2c1_wants_remap(dev)) {
+ afio_remap(AFIO_REMAP_I2C1);
+ }
+ gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_AF_OUTPUT_OD);
+ gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_AF_OUTPUT_OD);
+}
+
+void i2c_master_release_bus(const i2c_dev *dev) {
+ gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
+ gpio_write_bit(sda_port(dev), dev->sda_pin, 1);
+ gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_OUTPUT_OD);
+ gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_OUTPUT_OD);
+}
+
+/*
+ * IRQ handlers
+ */
+
+void __irq_i2c1_ev(void) {
+ _i2c_irq_handler(I2C1);
+}
+
+void __irq_i2c2_ev(void) {
+ _i2c_irq_handler(I2C2);
+}
+
+void __irq_i2c1_er(void) {
+ _i2c_irq_error_handler(I2C1);
+}
+
+void __irq_i2c2_er(void) {
+ _i2c_irq_error_handler(I2C2);
+}
+
+/*
+ * Internal APIs
+ */
+
+void _i2c_irq_priority_fixup(i2c_dev *dev) {
+ /*
+ * Important STM32 Errata:
+ *
+ * See STM32F10xx8 and STM32F10xxB Errata sheet (Doc ID 14574 Rev 8),
+ * Section 2.11.1, 2.11.2.
+ *
+ * 2.11.1:
+ * When the EV7, EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events are not
+ * managed before the current byte is being transferred, problems may be
+ * encountered such as receiving an extra byte, reading the same data twice
+ * or missing data.
+ *
+ * 2.11.2:
+ * In Master Receiver mode, when closing the communication using
+ * method 2, the content of the last read data can be corrupted.
+ *
+ * If the user software is not able to read the data N-1 before the STOP
+ * condition is generated on the bus, the content of the shift register
+ * (data N) will be corrupted. (data N is shifted 1-bit to the left).
+ *
+ * ----------------------------------------------------------------------
+ *
+ * In order to ensure that events are not missed, the i2c interrupt must
+ * not be preempted. We set the i2c interrupt priority to be the highest
+ * interrupt in the system (priority level 0). All other interrupts have
+ * been initialized to priority level 16. See nvic_init().
+ */
+ nvic_irq_set_priority(dev->ev_nvic_line, 0);
+ nvic_irq_set_priority(dev->er_nvic_line, 0);
+}
diff --git a/libmaple/stm32f1/include/series/adc.h b/libmaple/stm32f1/include/series/adc.h
new file mode 100644
index 0000000..774c97c
--- /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 libmaple/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/bitband.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/rcc.h> /* For the prescalers */
+
+/*
+ * Devices
+ */
+
+extern const struct adc_dev *ADC1;
+extern const struct adc_dev *ADC2;
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_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)
+/** ADC3 register map base pointer. */
+#define ADC3_BASE ((struct adc_reg_map*)0x40013C00)
+
+/*
+ * 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/include/series/dac.h b/libmaple/stm32f1/include/series/dac.h
new file mode 100644
index 0000000..c0d026b
--- /dev/null
+++ b/libmaple/stm32f1/include/series/dac.h
@@ -0,0 +1,71 @@
+/******************************************************************************
+ * 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/stm32f1/include/series/dac.h
+ * @brief STM32F1 DAC support
+ */
+
+#ifndef _LIBMAPLE_STM32F1_DAC_H_
+#define _LIBMAPLE_STM32F1_DAC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/** STM32F1 DAC register map type. */
+typedef struct dac_reg_map {
+ __io uint32 CR; /**< Control register */
+ __io uint32 SWTRIGR; /**< Software trigger register */
+ __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding
+ register */
+ __io uint32 DOR1; /**< Channel 1 data output register */
+ __io uint32 DOR2; /**< Channel 2 data output register */
+} dac_reg_map;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/dma.h b/libmaple/stm32f1/include/series/dma.h
new file mode 100644
index 0000000..3b19e2b
--- /dev/null
+++ b/libmaple/stm32f1/include/series/dma.h
@@ -0,0 +1,565 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ * 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/stm32f1/include/series/dma.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>;
+ * Original implementation by Michael Hope
+ * @brief STM32F1 DMA series header.
+ */
+
+/*
+ * See /notes/dma-stm32f1.txt for more information.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_DMA_H_
+#define _LIBMAPLE_STM32F1_DMA_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/dma_common.h>
+
+/*
+ * Register maps and base pointers
+ */
+
+/**
+ * @brief STM32F1 DMA register map type.
+ *
+ * Note that DMA controller 2 (register map base pointer DMA2_BASE)
+ * only supports channels 1--5.
+ */
+typedef struct dma_reg_map {
+ __io uint32 ISR; /**< Interrupt status register */
+ __io uint32 IFCR; /**< Interrupt flag clear register */
+ __io uint32 CCR1; /**< Channel 1 configuration register */
+ __io uint32 CNDTR1; /**< Channel 1 number of data register */
+ __io uint32 CPAR1; /**< Channel 1 peripheral address register */
+ __io uint32 CMAR1; /**< Channel 1 memory address register */
+ const uint32 RESERVED1; /**< Reserved. */
+ __io uint32 CCR2; /**< Channel 2 configuration register */
+ __io uint32 CNDTR2; /**< Channel 2 number of data register */
+ __io uint32 CPAR2; /**< Channel 2 peripheral address register */
+ __io uint32 CMAR2; /**< Channel 2 memory address register */
+ const uint32 RESERVED2; /**< Reserved. */
+ __io uint32 CCR3; /**< Channel 3 configuration register */
+ __io uint32 CNDTR3; /**< Channel 3 number of data register */
+ __io uint32 CPAR3; /**< Channel 3 peripheral address register */
+ __io uint32 CMAR3; /**< Channel 3 memory address register */
+ const uint32 RESERVED3; /**< Reserved. */
+ __io uint32 CCR4; /**< Channel 4 configuration register */
+ __io uint32 CNDTR4; /**< Channel 4 number of data register */
+ __io uint32 CPAR4; /**< Channel 4 peripheral address register */
+ __io uint32 CMAR4; /**< Channel 4 memory address register */
+ const uint32 RESERVED4; /**< Reserved. */
+ __io uint32 CCR5; /**< Channel 5 configuration register */
+ __io uint32 CNDTR5; /**< Channel 5 number of data register */
+ __io uint32 CPAR5; /**< Channel 5 peripheral address register */
+ __io uint32 CMAR5; /**< Channel 5 memory address register */
+ const uint32 RESERVED5; /**< Reserved. */
+ __io uint32 CCR6; /**< Channel 6 configuration register */
+ __io uint32 CNDTR6; /**< Channel 6 number of data register */
+ __io uint32 CPAR6; /**< Channel 6 peripheral address register */
+ __io uint32 CMAR6; /**< Channel 6 memory address register */
+ const uint32 RESERVED6; /**< Reserved. */
+ __io uint32 CCR7; /**< Channel 7 configuration register */
+ __io uint32 CNDTR7; /**< Channel 7 number of data register */
+ __io uint32 CPAR7; /**< Channel 7 peripheral address register */
+ __io uint32 CMAR7; /**< Channel 7 memory address register */
+ const uint32 RESERVED7; /**< Reserved. */
+} dma_reg_map;
+
+/** DMA controller 1 register map base pointer */
+#define DMA1_BASE ((struct dma_reg_map*)0x40020000)
+/** DMA controller 2 register map base pointer */
+#define DMA2_BASE ((struct dma_reg_map*)0x40020400)
+
+/**
+ * @brief STM32F1 DMA channel (i.e. tube) register map type.
+ * Provides access to an individual channel's registers.
+ * @see dma_tube_regs()
+ */
+typedef struct dma_tube_reg_map {
+ __io uint32 CCR; /**< Channel configuration register */
+ __io uint32 CNDTR; /**< Channel number of data register */
+ __io uint32 CPAR; /**< Channel peripheral address register */
+ __io uint32 CMAR; /**< Channel memory address register */
+} dma_tube_reg_map;
+
+/** DMA1 channel 1 register map base pointer */
+#define DMA1CH1_BASE ((struct dma_tube_reg_map*)0x40020008)
+/** DMA1 channel 2 register map base pointer */
+#define DMA1CH2_BASE ((struct dma_tube_reg_map*)0x4002001C)
+/** DMA1 channel 3 register map base pointer */
+#define DMA1CH3_BASE ((struct dma_tube_reg_map*)0x40020030)
+/** DMA1 channel 4 register map base pointer */
+#define DMA1CH4_BASE ((struct dma_tube_reg_map*)0x40020044)
+/** DMA1 channel 5 register map base pointer */
+#define DMA1CH5_BASE ((struct dma_tube_reg_map*)0x40020058)
+/** DMA1 channel 6 register map base pointer */
+#define DMA1CH6_BASE ((struct dma_tube_reg_map*)0x4002006C)
+/** DMA1 channel 7 register map base pointer */
+#define DMA1CH7_BASE ((struct dma_tube_reg_map*)0x40020080)
+
+/** DMA2 channel 1 register map base pointer */
+#define DMA2CH1_BASE ((struct dma_tube_reg_map*)0x40020408)
+/** DMA2 channel 2 register map base pointer */
+#define DMA2CH2_BASE ((struct dma_tube_reg_map*)0x4002041C)
+/** DMA2 channel 3 register map base pointer */
+#define DMA2CH3_BASE ((struct dma_tube_reg_map*)0x40020430)
+/** DMA2 channel 4 register map base pointer */
+#define DMA2CH4_BASE ((struct dma_tube_reg_map*)0x40020444)
+/** DMA2 channel 5 register map base pointer */
+#define DMA2CH5_BASE ((struct dma_tube_reg_map*)0x40020458)
+
+/*
+ * Register bit definitions
+ */
+
+/* Interrupt status register */
+
+#define DMA_ISR_TEIF7_BIT 27
+#define DMA_ISR_HTIF7_BIT 26
+#define DMA_ISR_TCIF7_BIT 25
+#define DMA_ISR_GIF7_BIT 24
+#define DMA_ISR_TEIF6_BIT 23
+#define DMA_ISR_HTIF6_BIT 22
+#define DMA_ISR_TCIF6_BIT 21
+#define DMA_ISR_GIF6_BIT 20
+#define DMA_ISR_TEIF5_BIT 19
+#define DMA_ISR_HTIF5_BIT 18
+#define DMA_ISR_TCIF5_BIT 17
+#define DMA_ISR_GIF5_BIT 16
+#define DMA_ISR_TEIF4_BIT 15
+#define DMA_ISR_HTIF4_BIT 14
+#define DMA_ISR_TCIF4_BIT 13
+#define DMA_ISR_GIF4_BIT 12
+#define DMA_ISR_TEIF3_BIT 11
+#define DMA_ISR_HTIF3_BIT 10
+#define DMA_ISR_TCIF3_BIT 9
+#define DMA_ISR_GIF3_BIT 8
+#define DMA_ISR_TEIF2_BIT 7
+#define DMA_ISR_HTIF2_BIT 6
+#define DMA_ISR_TCIF2_BIT 5
+#define DMA_ISR_GIF2_BIT 4
+#define DMA_ISR_TEIF1_BIT 3
+#define DMA_ISR_HTIF1_BIT 2
+#define DMA_ISR_TCIF1_BIT 1
+#define DMA_ISR_GIF1_BIT 0
+
+#define DMA_ISR_TEIF7 (1U << DMA_ISR_TEIF7_BIT)
+#define DMA_ISR_HTIF7 (1U << DMA_ISR_HTIF7_BIT)
+#define DMA_ISR_TCIF7 (1U << DMA_ISR_TCIF7_BIT)
+#define DMA_ISR_GIF7 (1U << DMA_ISR_GIF7_BIT)
+#define DMA_ISR_TEIF6 (1U << DMA_ISR_TEIF6_BIT)
+#define DMA_ISR_HTIF6 (1U << DMA_ISR_HTIF6_BIT)
+#define DMA_ISR_TCIF6 (1U << DMA_ISR_TCIF6_BIT)
+#define DMA_ISR_GIF6 (1U << DMA_ISR_GIF6_BIT)
+#define DMA_ISR_TEIF5 (1U << DMA_ISR_TEIF5_BIT)
+#define DMA_ISR_HTIF5 (1U << DMA_ISR_HTIF5_BIT)
+#define DMA_ISR_TCIF5 (1U << DMA_ISR_TCIF5_BIT)
+#define DMA_ISR_GIF5 (1U << DMA_ISR_GIF5_BIT)
+#define DMA_ISR_TEIF4 (1U << DMA_ISR_TEIF4_BIT)
+#define DMA_ISR_HTIF4 (1U << DMA_ISR_HTIF4_BIT)
+#define DMA_ISR_TCIF4 (1U << DMA_ISR_TCIF4_BIT)
+#define DMA_ISR_GIF4 (1U << DMA_ISR_GIF4_BIT)
+#define DMA_ISR_TEIF3 (1U << DMA_ISR_TEIF3_BIT)
+#define DMA_ISR_HTIF3 (1U << DMA_ISR_HTIF3_BIT)
+#define DMA_ISR_TCIF3 (1U << DMA_ISR_TCIF3_BIT)
+#define DMA_ISR_GIF3 (1U << DMA_ISR_GIF3_BIT)
+#define DMA_ISR_TEIF2 (1U << DMA_ISR_TEIF2_BIT)
+#define DMA_ISR_HTIF2 (1U << DMA_ISR_HTIF2_BIT)
+#define DMA_ISR_TCIF2 (1U << DMA_ISR_TCIF2_BIT)
+#define DMA_ISR_GIF2 (1U << DMA_ISR_GIF2_BIT)
+#define DMA_ISR_TEIF1 (1U << DMA_ISR_TEIF1_BIT)
+#define DMA_ISR_HTIF1 (1U << DMA_ISR_HTIF1_BIT)
+#define DMA_ISR_TCIF1 (1U << DMA_ISR_TCIF1_BIT)
+#define DMA_ISR_GIF1 (1U << DMA_ISR_GIF1_BIT)
+
+/* Interrupt flag clear register */
+
+#define DMA_IFCR_CTEIF7_BIT 27
+#define DMA_IFCR_CHTIF7_BIT 26
+#define DMA_IFCR_CTCIF7_BIT 25
+#define DMA_IFCR_CGIF7_BIT 24
+#define DMA_IFCR_CTEIF6_BIT 23
+#define DMA_IFCR_CHTIF6_BIT 22
+#define DMA_IFCR_CTCIF6_BIT 21
+#define DMA_IFCR_CGIF6_BIT 20
+#define DMA_IFCR_CTEIF5_BIT 19
+#define DMA_IFCR_CHTIF5_BIT 18
+#define DMA_IFCR_CTCIF5_BIT 17
+#define DMA_IFCR_CGIF5_BIT 16
+#define DMA_IFCR_CTEIF4_BIT 15
+#define DMA_IFCR_CHTIF4_BIT 14
+#define DMA_IFCR_CTCIF4_BIT 13
+#define DMA_IFCR_CGIF4_BIT 12
+#define DMA_IFCR_CTEIF3_BIT 11
+#define DMA_IFCR_CHTIF3_BIT 10
+#define DMA_IFCR_CTCIF3_BIT 9
+#define DMA_IFCR_CGIF3_BIT 8
+#define DMA_IFCR_CTEIF2_BIT 7
+#define DMA_IFCR_CHTIF2_BIT 6
+#define DMA_IFCR_CTCIF2_BIT 5
+#define DMA_IFCR_CGIF2_BIT 4
+#define DMA_IFCR_CTEIF1_BIT 3
+#define DMA_IFCR_CHTIF1_BIT 2
+#define DMA_IFCR_CTCIF1_BIT 1
+#define DMA_IFCR_CGIF1_BIT 0
+
+#define DMA_IFCR_CTEIF7 (1U << DMA_IFCR_CTEIF7_BIT)
+#define DMA_IFCR_CHTIF7 (1U << DMA_IFCR_CHTIF7_BIT)
+#define DMA_IFCR_CTCIF7 (1U << DMA_IFCR_CTCIF7_BIT)
+#define DMA_IFCR_CGIF7 (1U << DMA_IFCR_CGIF7_BIT)
+#define DMA_IFCR_CTEIF6 (1U << DMA_IFCR_CTEIF6_BIT)
+#define DMA_IFCR_CHTIF6 (1U << DMA_IFCR_CHTIF6_BIT)
+#define DMA_IFCR_CTCIF6 (1U << DMA_IFCR_CTCIF6_BIT)
+#define DMA_IFCR_CGIF6 (1U << DMA_IFCR_CGIF6_BIT)
+#define DMA_IFCR_CTEIF5 (1U << DMA_IFCR_CTEIF5_BIT)
+#define DMA_IFCR_CHTIF5 (1U << DMA_IFCR_CHTIF5_BIT)
+#define DMA_IFCR_CTCIF5 (1U << DMA_IFCR_CTCIF5_BIT)
+#define DMA_IFCR_CGIF5 (1U << DMA_IFCR_CGIF5_BIT)
+#define DMA_IFCR_CTEIF4 (1U << DMA_IFCR_CTEIF4_BIT)
+#define DMA_IFCR_CHTIF4 (1U << DMA_IFCR_CHTIF4_BIT)
+#define DMA_IFCR_CTCIF4 (1U << DMA_IFCR_CTCIF4_BIT)
+#define DMA_IFCR_CGIF4 (1U << DMA_IFCR_CGIF4_BIT)
+#define DMA_IFCR_CTEIF3 (1U << DMA_IFCR_CTEIF3_BIT)
+#define DMA_IFCR_CHTIF3 (1U << DMA_IFCR_CHTIF3_BIT)
+#define DMA_IFCR_CTCIF3 (1U << DMA_IFCR_CTCIF3_BIT)
+#define DMA_IFCR_CGIF3 (1U << DMA_IFCR_CGIF3_BIT)
+#define DMA_IFCR_CTEIF2 (1U << DMA_IFCR_CTEIF2_BIT)
+#define DMA_IFCR_CHTIF2 (1U << DMA_IFCR_CHTIF2_BIT)
+#define DMA_IFCR_CTCIF2 (1U << DMA_IFCR_CTCIF2_BIT)
+#define DMA_IFCR_CGIF2 (1U << DMA_IFCR_CGIF2_BIT)
+#define DMA_IFCR_CTEIF1 (1U << DMA_IFCR_CTEIF1_BIT)
+#define DMA_IFCR_CHTIF1 (1U << DMA_IFCR_CHTIF1_BIT)
+#define DMA_IFCR_CTCIF1 (1U << DMA_IFCR_CTCIF1_BIT)
+#define DMA_IFCR_CGIF1 (1U << DMA_IFCR_CGIF1_BIT)
+
+/* Channel configuration register */
+
+#define DMA_CCR_MEM2MEM_BIT 14
+#define DMA_CCR_MINC_BIT 7
+#define DMA_CCR_PINC_BIT 6
+#define DMA_CCR_CIRC_BIT 5
+#define DMA_CCR_DIR_BIT 4
+#define DMA_CCR_TEIE_BIT 3
+#define DMA_CCR_HTIE_BIT 2
+#define DMA_CCR_TCIE_BIT 1
+#define DMA_CCR_EN_BIT 0
+
+#define DMA_CCR_MEM2MEM (1U << DMA_CCR_MEM2MEM_BIT)
+#define DMA_CCR_PL (0x3 << 12)
+#define DMA_CCR_PL_LOW (0x0 << 12)
+#define DMA_CCR_PL_MEDIUM (0x1 << 12)
+#define DMA_CCR_PL_HIGH (0x2 << 12)
+#define DMA_CCR_PL_VERY_HIGH (0x3 << 12)
+#define DMA_CCR_MSIZE (0x3 << 10)
+#define DMA_CCR_MSIZE_8BITS (0x0 << 10)
+#define DMA_CCR_MSIZE_16BITS (0x1 << 10)
+#define DMA_CCR_MSIZE_32BITS (0x2 << 10)
+#define DMA_CCR_PSIZE (0x3 << 8)
+#define DMA_CCR_PSIZE_8BITS (0x0 << 8)
+#define DMA_CCR_PSIZE_16BITS (0x1 << 8)
+#define DMA_CCR_PSIZE_32BITS (0x2 << 8)
+#define DMA_CCR_MINC (1U << DMA_CCR_MINC_BIT)
+#define DMA_CCR_PINC (1U << DMA_CCR_PINC_BIT)
+#define DMA_CCR_CIRC (1U << DMA_CCR_CIRC_BIT)
+#define DMA_CCR_DIR (1U << DMA_CCR_DIR_BIT)
+#define DMA_CCR_DIR_FROM_PER (0U << DMA_CCR_DIR_BIT)
+#define DMA_CCR_DIR_FROM_MEM (1U << DMA_CCR_DIR_BIT)
+#define DMA_CCR_TEIE (1U << DMA_CCR_TEIE_BIT)
+#define DMA_CCR_HTIE (1U << DMA_CCR_HTIE_BIT)
+#define DMA_CCR_TCIE (1U << DMA_CCR_TCIE_BIT)
+#define DMA_CCR_EN (1U << DMA_CCR_EN_BIT)
+
+/*
+ * Devices
+ */
+
+extern dma_dev *DMA1;
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+extern dma_dev *DMA2;
+#endif
+
+/*
+ * Other types needed by, or useful for, <libmaple/dma.h>.
+ */
+
+/**
+ * @brief STM32F1 dma_tube.
+ * On STM32F1, DMA tubes are just channels.
+ */
+#define dma_tube dma_channel
+
+/**
+ * @brief On STM32F1, dma_channel_reg_map is an alias for dma_tube_reg_map.
+ * This is for backwards compatibility. */
+#define dma_channel_reg_map dma_tube_reg_map
+
+/**
+ * @brief STM32F1 configuration flags for dma_tube_config
+ * @see struct dma_tube_config
+ */
+typedef enum dma_cfg_flags {
+ /**
+ * Source address increment mode
+ *
+ * If this flag is set, the source address is incremented (by the
+ * source size) after each DMA transfer.
+ */
+ DMA_CFG_SRC_INC = 1U << 31,
+
+ /**
+ * Destination address increment mode
+ *
+ * If this flag is set, the destination address is incremented (by
+ * the destination size) after each DMA transfer.
+ */
+ DMA_CFG_DST_INC = 1U << 30,
+
+ /**
+ * Circular mode
+ *
+ * This mode is not available for memory-to-memory transfers.
+ */
+ DMA_CFG_CIRC = DMA_CCR_CIRC,
+
+ /** Transfer complete interrupt enable */
+ DMA_CFG_CMPLT_IE = DMA_CCR_TCIE,
+ /** Transfer half-complete interrupt enable */
+ DMA_CFG_HALF_CMPLT_IE = DMA_CCR_HTIE,
+ /** Transfer error interrupt enable */
+ DMA_CFG_ERR_IE = DMA_CCR_TEIE,
+} dma_cfg_flags;
+
+/**
+ * @brief STM32F1 DMA request sources.
+ *
+ * IMPORTANT:
+ *
+ * 1. On STM32F1, each dma_request_src can only be used by a
+ * particular tube on a particular DMA controller. For example,
+ * DMA_REQ_SRC_ADC1 belongs to DMA1, tube 1. DMA2 cannot serve
+ * requests from ADC1, nor can DMA1 tube 2, etc. If you try to use a
+ * request source with the wrong DMA controller or tube on STM32F1,
+ * dma_tube_cfg() will fail.
+ *
+ * 2. In general, a DMA tube can only serve a single request source at
+ * a time, and on STM32F1, Terrible Super-Bad Things will happen if
+ * two request sources are active for a single tube.
+ *
+ * To make all this easier to sort out, these dma_request_src
+ * enumerators are grouped by DMA controller and tube.
+ *
+ * @see struct dma_tube_config
+ * @see dma_tube_cfg()
+ */
+typedef enum dma_request_src {
+ /* Each request source encodes the DMA controller and channel it
+ * belongs to, for error checking in dma_tube_cfg(). */
+
+ /* DMA1 request sources */
+
+ /**@{*/
+ /** (DMA1, tube 1) */
+ DMA_REQ_SRC_ADC1 = (RCC_DMA1 << 3) | 1,
+ DMA_REQ_SRC_TIM2_CH3 = (RCC_DMA1 << 3) | 1,
+ DMA_REQ_SRC_TIM4_CH1 = (RCC_DMA1 << 3) | 1,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 2)*/
+ DMA_REQ_SRC_SPI1_RX = (RCC_DMA1 << 3) | 2,
+ DMA_REQ_SRC_USART3_TX = (RCC_DMA1 << 3) | 2,
+ DMA_REQ_SRC_TIM1_CH1 = (RCC_DMA1 << 3) | 2,
+ DMA_REQ_SRC_TIM2_UP = (RCC_DMA1 << 3) | 2,
+ DMA_REQ_SRC_TIM3_CH3 = (RCC_DMA1 << 3) | 2,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 3)*/
+ DMA_REQ_SRC_SPI1_TX = (RCC_DMA1 << 3) | 3,
+ DMA_REQ_SRC_USART3_RX = (RCC_DMA1 << 3) | 3,
+ DMA_REQ_SRC_TIM1_CH2 = (RCC_DMA1 << 3) | 3,
+ DMA_REQ_SRC_TIM3_CH4 = (RCC_DMA1 << 3) | 3,
+ DMA_REQ_SRC_TIM3_UP = (RCC_DMA1 << 3) | 3,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 4)*/
+ DMA_REQ_SRC_SPI2_RX = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_I2S2_RX = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_USART1_TX = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_I2C2_TX = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_TIM1_CH4 = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_TIM1_TRIG = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_TIM1_COM = (RCC_DMA1 << 3) | 4,
+ DMA_REQ_SRC_TIM4_CH2 = (RCC_DMA1 << 3) | 4,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 5)*/
+ DMA_REQ_SRC_SPI2_TX = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_I2S2_TX = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_USART1_RX = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_I2C2_RX = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_TIM1_UP = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_TIM2_CH1 = (RCC_DMA1 << 3) | 5,
+ DMA_REQ_SRC_TIM4_CH3 = (RCC_DMA1 << 3) | 5,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA1, tube 6)*/
+ DMA_REQ_SRC_USART2_RX = (RCC_DMA1 << 3) | 6,
+ DMA_REQ_SRC_I2C1_TX = (RCC_DMA1 << 3) | 6,
+ DMA_REQ_SRC_TIM1_CH3 = (RCC_DMA1 << 3) | 6,
+ DMA_REQ_SRC_TIM3_CH1 = (RCC_DMA1 << 3) | 6,
+ DMA_REQ_SRC_TIM3_TRIG = (RCC_DMA1 << 3) | 6,
+ /**@}*/
+
+ /**@{*/
+ /* Tube 7 */
+ DMA_REQ_SRC_USART2_TX = (RCC_DMA1 << 3) | 7,
+ DMA_REQ_SRC_I2C1_RX = (RCC_DMA1 << 3) | 7,
+ DMA_REQ_SRC_TIM2_CH2 = (RCC_DMA1 << 3) | 7,
+ DMA_REQ_SRC_TIM2_CH4 = (RCC_DMA1 << 3) | 7,
+ DMA_REQ_SRC_TIM4_UP = (RCC_DMA1 << 3) | 7,
+ /**@}*/
+
+ /* DMA2 request sources */
+
+ /**@{*/
+ /** (DMA2, tube 1)*/
+ DMA_REQ_SRC_SPI3_RX = (RCC_DMA2 << 3) | 1,
+ DMA_REQ_SRC_I2S3_RX = (RCC_DMA2 << 3) | 1,
+ DMA_REQ_SRC_TIM5_CH4 = (RCC_DMA2 << 3) | 1,
+ DMA_REQ_SRC_TIM5_TRIG = (RCC_DMA2 << 3) | 1,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA2, tube 2)*/
+ DMA_REQ_SRC_SPI3_TX = (RCC_DMA2 << 3) | 2,
+ DMA_REQ_SRC_I2S3_TX = (RCC_DMA2 << 3) | 2,
+ DMA_REQ_SRC_TIM5_CH3 = (RCC_DMA2 << 3) | 2,
+ DMA_REQ_SRC_TIM5_UP = (RCC_DMA2 << 3) | 2,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA2, tube 3)*/
+ DMA_REQ_SRC_UART4_RX = (RCC_DMA2 << 3) | 3,
+ DMA_REQ_SRC_TIM6_UP = (RCC_DMA2 << 3) | 3,
+ DMA_REQ_SRC_DAC_CH1 = (RCC_DMA2 << 3) | 3,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA2, tube 4)*/
+ DMA_REQ_SRC_SDIO = (RCC_DMA2 << 3) | 4,
+ DMA_REQ_SRC_TIM5_CH2 = (RCC_DMA2 << 3) | 4,
+ /**@}*/
+
+ /**@{*/
+ /** (DMA2, tube 5)*/
+ DMA_REQ_SRC_ADC3 = (RCC_DMA2 << 3) | 5,
+ DMA_REQ_SRC_UART4_TX = (RCC_DMA2 << 3) | 5,
+ DMA_REQ_SRC_TIM5_CH1 = (RCC_DMA2 << 3) | 5,
+ /**@}*/
+} dma_request_src;
+
+/*
+ * Convenience routines.
+ */
+
+/**
+ * @brief On STM32F1, dma_is_channel_enabled() is an alias for
+ * dma_is_enabled().
+ * This is for backwards compatibility.
+ */
+#define dma_is_channel_enabled dma_is_enabled
+
+#define DMA_CHANNEL_NREGS 5 /* accounts for reserved word */
+static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube) {
+ __io uint32 *ccr1 = &dev->regs->CCR1;
+ return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (tube - 1));
+}
+
+/**
+ * @brief On STM32F1, dma_channel_regs() is an alias for dma_tube_regs().
+ * This is for backwards compatibility. */
+#define dma_channel_regs(dev, ch) dma_tube_regs(dev, ch)
+
+static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube) {
+ return (uint8)(dma_tube_regs(dev, tube)->CCR & DMA_CCR_EN);
+}
+
+static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube) {
+ uint8 shift = (tube - 1) * 4;
+ return (dev->regs->ISR >> shift) & 0xF;
+}
+
+static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) {
+ dev->regs->IFCR = (1U << (4 * (tube - 1)));
+}
+
+/**
+ * @brief Deprecated
+ * STM32F1 mode flags for dma_setup_xfer(). Use dma_tube_cfg() instead.
+ * @see dma_tube_cfg()
+ */
+typedef enum dma_mode_flags {
+ DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */
+ DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */
+ DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */
+ DMA_CIRC_MODE = 1 << 5, /**< Circular mode */
+ DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */
+ DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */
+ DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */
+ DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */
+} dma_mode_flags;
+
+/* Keep this around for backwards compatibility, but it's deprecated.
+ * New code should use dma_tube_cfg() instead.
+ *
+ * (It's not possible to fully configure a DMA stream on F2 with just
+ * this information, so this interface is too tied to the F1.) */
+__deprecated
+void dma_setup_transfer(dma_dev *dev,
+ dma_channel channel,
+ __io void *peripheral_address,
+ dma_xfer_size peripheral_size,
+ __io void *memory_address,
+ dma_xfer_size memory_size,
+ uint32 mode);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/exti.h b/libmaple/stm32f1/include/series/exti.h
new file mode 100644
index 0000000..1ece664
--- /dev/null
+++ b/libmaple/stm32f1/include/series/exti.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * 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/stm32f1/include/series/exti.h
+ * @brief STM32F1 external interrupts
+ */
+
+#ifndef _LIBMAPLE_STM32F1_EXTI_H_
+#define _LIBMAPLE_STM32F1_EXTI_H_
+
+#ifdef __cpluspus
+extern "C" {
+#endif
+
+struct exti_reg_map;
+#define EXTI_BASE ((struct exti_reg_map*)0x40010400)
+
+#ifdef __cpluspus
+}
+#endif
+
+#endif
diff --git a/libmaple/flash.h b/libmaple/stm32f1/include/series/flash.h
index 0b4e49b..24efb0b 100644
--- a/libmaple/flash.h
+++ b/libmaple/stm32f1/include/series/flash.h
@@ -25,21 +25,28 @@
*****************************************************************************/
/**
- * @file flash.h
- * @brief STM32 Medium and high density Flash register map and setup
- * routines
+ * @file libmaple/stm32f1/include/series/flash.h
+ * @brief STM32F1 Flash header.
+ *
+ * Provides register map, base pointer, and register bit definitions
+ * for the Flash controller on the STM32F1 line, along with
+ * series-specific configuration values.
*/
-#include "libmaple_types.h"
-
-#ifndef _FLASH_H_
-#define _FLASH_H_
+#ifndef _LIBMAPLE_STM32F1_FLASH_H_
+#define _LIBMAPLE_STM32F1_FLASH_H_
#ifdef __cplusplus
extern "C"{
#endif
-/** Flash register map type */
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** @brief STM32F1 Flash register map type */
typedef struct flash_reg_map {
__io uint32 ACR; /**< Access control register */
__io uint32 KEYR; /**< Key register */
@@ -51,7 +58,6 @@ typedef struct flash_reg_map {
__io uint32 WRPR; /**< Write protection register */
} flash_reg_map;
-/** Flash register map base pointer */
#define FLASH_BASE ((struct flash_reg_map*)0x40022000)
/*
@@ -64,9 +70,9 @@ typedef struct flash_reg_map {
#define FLASH_ACR_PRFTBE_BIT 4
#define FLASH_ACR_HLFCYA_BIT 3
-#define FLASH_ACR_PRFTBS BIT(FLASH_ACR_PRFTBS_BIT)
-#define FLASH_ACR_PRFTBE BIT(FLASH_ACR_PRFTBE_BIT)
-#define FLASH_ACR_HLFCYA BIT(FLASH_ACR_HLFCYA_BIT)
+#define FLASH_ACR_PRFTBS (1U << FLASH_ACR_PRFTBS_BIT)
+#define FLASH_ACR_PRFTBE (1U << FLASH_ACR_PRFTBE_BIT)
+#define FLASH_ACR_HLFCYA (1U << FLASH_ACR_HLFCYA_BIT)
#define FLASH_ACR_LATENCY 0x7
/* Status register */
@@ -76,10 +82,10 @@ typedef struct flash_reg_map {
#define FLASH_SR_PGERR_BIT 2
#define FLASH_SR_BSY_BIT 0
-#define FLASH_SR_EOP BIT(FLASH_SR_EOP_BIT)
-#define FLASH_SR_WRPRTERR BIT(FLASH_SR_WRPRTERR_BIT)
-#define FLASH_SR_PGERR BIT(FLASH_SR_PGERR_BIT)
-#define FLASH_SR_BSY BIT(FLASH_SR_BSY_BIT)
+#define FLASH_SR_EOP (1U << FLASH_SR_EOP_BIT)
+#define FLASH_SR_WRPRTERR (1U << FLASH_SR_WRPRTERR_BIT)
+#define FLASH_SR_PGERR (1U << FLASH_SR_PGERR_BIT)
+#define FLASH_SR_BSY (1U << FLASH_SR_BSY_BIT)
/* Control register */
@@ -94,16 +100,16 @@ typedef struct flash_reg_map {
#define FLASH_CR_PER_BIT 1
#define FLASH_CR_PG_BIT 0
-#define FLASH_CR_EOPIE BIT(FLASH_CR_EOPIE_BIT)
-#define FLASH_CR_ERRIE BIT(FLASH_CR_ERRIE_BIT)
-#define FLASH_CR_OPTWRE BIT(FLASH_CR_OPTWRE_BIT)
-#define FLASH_CR_LOCK BIT(FLASH_CR_LOCK_BIT)
-#define FLASH_CR_STRT BIT(FLASH_CR_STRT_BIT)
-#define FLASH_CR_OPTER BIT(FLASH_CR_OPTER_BIT)
-#define FLASH_CR_OPTPG BIT(FLASH_CR_OPTPG_BIT)
-#define FLASH_CR_MER BIT(FLASH_CR_MER_BIT)
-#define FLASH_CR_PER BIT(FLASH_CR_PER_BIT)
-#define FLASH_CR_PG BIT(FLASH_CR_PG_BIT)
+#define FLASH_CR_EOPIE (1U << FLASH_CR_EOPIE_BIT)
+#define FLASH_CR_ERRIE (1U << FLASH_CR_ERRIE_BIT)
+#define FLASH_CR_OPTWRE (1U << FLASH_CR_OPTWRE_BIT)
+#define FLASH_CR_LOCK (1U << FLASH_CR_LOCK_BIT)
+#define FLASH_CR_STRT (1U << FLASH_CR_STRT_BIT)
+#define FLASH_CR_OPTER (1U << FLASH_CR_OPTER_BIT)
+#define FLASH_CR_OPTPG (1U << FLASH_CR_OPTPG_BIT)
+#define FLASH_CR_MER (1U << FLASH_CR_MER_BIT)
+#define FLASH_CR_PER (1U << FLASH_CR_PER_BIT)
+#define FLASH_CR_PG (1U << FLASH_CR_PG_BIT)
/* Option byte register */
@@ -116,27 +122,28 @@ typedef struct flash_reg_map {
#define FLASH_OBR_DATA1 (0xFF << 18)
#define FLASH_OBR_DATA0 (0xFF << 10)
#define FLASH_OBR_USER 0x3FF
-#define FLASH_OBR_nRST_STDBY BIT(FLASH_OBR_nRST_STDBY_BIT)
-#define FLASH_OBR_nRST_STOP BIT(FLASH_OBR_nRST_STOP_BIT)
-#define FLASH_OBR_WDG_SW BIT(FLASH_OBR_WDG_SW_BIT)
-#define FLASH_OBR_RDPRT BIT(FLASH_OBR_RDPRT_BIT)
-#define FLASH_OBR_OPTERR BIT(FLASH_OBR_OPTERR_BIT)
+#define FLASH_OBR_nRST_STDBY (1U << FLASH_OBR_nRST_STDBY_BIT)
+#define FLASH_OBR_nRST_STOP (1U << FLASH_OBR_nRST_STOP_BIT)
+#define FLASH_OBR_WDG_SW (1U << FLASH_OBR_WDG_SW_BIT)
+#define FLASH_OBR_RDPRT (1U << FLASH_OBR_RDPRT_BIT)
+#define FLASH_OBR_OPTERR (1U << FLASH_OBR_OPTERR_BIT)
/*
- * Setup routines
+ * Series-specific configuration values.
*/
-#define FLASH_WAIT_STATE_0 0x0
-#define FLASH_WAIT_STATE_1 0x1
-#define FLASH_WAIT_STATE_2 0x2
+#define FLASH_SAFE_WAIT_STATES FLASH_WAIT_STATE_2
-void flash_enable_prefetch(void);
-void flash_set_latency(uint32 wait_states);
+/* Flash memory features available via ACR */
+enum {
+ FLASH_PREFETCH = 0x10,
+ FLASH_HALF_CYCLE = 0x8,
+ FLASH_ICACHE = 0x0, /* Not available on STM32F1 */
+ FLASH_DCACHE = 0x0, /* Not available on STM32F1 */
+};
#ifdef __cplusplus
}
#endif
#endif
-
-
diff --git a/libmaple/gpio.h b/libmaple/stm32f1/include/series/gpio.h
index a7859a7..aecf911 100644
--- a/libmaple/gpio.h
+++ b/libmaple/stm32f1/include/series/gpio.h
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011, 2012 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,22 +26,22 @@
*****************************************************************************/
/**
- * @file gpio.h
- *
- * @brief General purpose I/O (GPIO) and Alternate Function I/O
- * (AFIO) prototypes, defines, and inlined access functions.
+ * @file libmaple/stm32f1/include/series/gpio.h
+ * @brief STM32F1 GPIO and AFIO support.
+ * General purpose I/O (GPIO) and Alternate Function I/O (AFIO).
*/
-#ifndef _GPIO_H_
-#define _GPIO_H_
-
-#include "libmaple.h"
-#include "rcc.h"
+#ifndef _LIBMAPLE_STM32F1_GPIO_H_
+#define _LIBMAPLE_STM32F1_GPIO_H_
#ifdef __cplusplus
extern "C"{
#endif
+#include <libmaple/stm32.h>
+#include <libmaple/libmaple_types.h>
+#include <libmaple/exti.h>
+
/*
* GPIO register maps and devices
*/
@@ -56,46 +57,22 @@ typedef struct gpio_reg_map {
__io uint32 LCKR; /**< Port configuration lock register */
} gpio_reg_map;
-/**
- * @brief External interrupt line port selector.
- *
- * Used to determine which GPIO port to map an external interrupt line
- * onto. */
-/* (See AFIO sections, below) */
-typedef enum afio_exti_port {
- AFIO_EXTI_PA, /**< Use port A (PAx) pin. */
- AFIO_EXTI_PB, /**< Use port B (PBx) pin. */
- AFIO_EXTI_PC, /**< Use port C (PCx) pin. */
- AFIO_EXTI_PD, /**< Use port D (PDx) pin. */
-#ifdef STM32_HIGH_DENSITY
- AFIO_EXTI_PE, /**< Use port E (PEx) pin. */
- AFIO_EXTI_PF, /**< Use port F (PFx) pin. */
- AFIO_EXTI_PG, /**< Use port G (PGx) pin. */
-#endif
-} afio_exti_port;
-
-/** GPIO device type */
-typedef struct gpio_dev {
- gpio_reg_map *regs; /**< Register map */
- rcc_clk_id clk_id; /**< RCC clock information */
- afio_exti_port exti_port; /**< AFIO external interrupt port value */
-} gpio_dev;
-
-extern gpio_dev gpioa;
-extern gpio_dev* const GPIOA;
-extern gpio_dev gpiob;
-extern gpio_dev* const GPIOB;
-extern gpio_dev gpioc;
-extern gpio_dev* const GPIOC;
-extern gpio_dev gpiod;
-extern gpio_dev* const GPIOD;
+struct gpio_dev;
+extern struct gpio_dev gpioa;
+extern struct gpio_dev* const GPIOA;
+extern struct gpio_dev gpiob;
+extern struct gpio_dev* const GPIOB;
+extern struct gpio_dev gpioc;
+extern struct gpio_dev* const GPIOC;
+extern struct gpio_dev gpiod;
+extern struct gpio_dev* const GPIOD;
#ifdef STM32_HIGH_DENSITY
-extern gpio_dev gpioe;
-extern gpio_dev* const GPIOE;
-extern gpio_dev gpiof;
-extern gpio_dev* const GPIOF;
-extern gpio_dev gpiog;
-extern gpio_dev* const GPIOG;
+extern struct gpio_dev gpioe;
+extern struct gpio_dev* const GPIOE;
+extern struct gpio_dev gpiof;
+extern struct gpio_dev* const GPIOF;
+extern struct gpio_dev gpiog;
+extern struct gpio_dev* const GPIOG;
#endif
/** GPIO port A register map base pointer */
@@ -106,14 +83,12 @@ extern gpio_dev* const GPIOG;
#define GPIOC_BASE ((struct gpio_reg_map*)0x40011000)
/** GPIO port D register map base pointer */
#define GPIOD_BASE ((struct gpio_reg_map*)0x40011400)
-#ifdef STM32_HIGH_DENSITY
/** GPIO port E register map base pointer */
#define GPIOE_BASE ((struct gpio_reg_map*)0x40011800)
/** GPIO port F register map base pointer */
#define GPIOF_BASE ((struct gpio_reg_map*)0x40011C00)
/** GPIO port G register map base pointer */
#define GPIOG_BASE ((struct gpio_reg_map*)0x40012000)
-#endif
/*
* GPIO register bit definitions
@@ -136,86 +111,33 @@ extern gpio_dev* const GPIOG;
#define GPIO_CR_MODE_OUTPUT_50MHZ 0x3
/**
- * @brief GPIO Pin modes.
+ * @brief GPIO pin modes.
*
* These only allow for 50MHZ max output speeds; if you want slower,
* use direct register access.
*/
typedef enum gpio_pin_mode {
- GPIO_OUTPUT_PP = (GPIO_CR_CNF_OUTPUT_PP |
- GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output push-pull. */
- GPIO_OUTPUT_OD = (GPIO_CR_CNF_OUTPUT_OD |
- GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output open-drain. */
- GPIO_AF_OUTPUT_PP = (GPIO_CR_CNF_AF_OUTPUT_PP |
- GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function
- output push-pull. */
- GPIO_AF_OUTPUT_OD = (GPIO_CR_CNF_AF_OUTPUT_OD |
- GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function
- output open drain. */
- GPIO_INPUT_ANALOG = (GPIO_CR_CNF_INPUT_ANALOG |
- GPIO_CR_MODE_INPUT), /**< Analog input. */
- GPIO_INPUT_FLOATING = (GPIO_CR_CNF_INPUT_FLOATING |
- GPIO_CR_MODE_INPUT), /**< Input floating. */
- GPIO_INPUT_PD = (GPIO_CR_CNF_INPUT_PU_PD |
- GPIO_CR_MODE_INPUT), /**< Input pull-down. */
- GPIO_INPUT_PU /**< Input pull-up. */
- /* GPIO_INPUT_PU treated as a special case, for ODR twiddling */
+ /** Output push-pull. */
+ GPIO_OUTPUT_PP = GPIO_CR_CNF_OUTPUT_PP | GPIO_CR_MODE_OUTPUT_50MHZ,
+ /** Output open-drain. */
+ GPIO_OUTPUT_OD = GPIO_CR_CNF_OUTPUT_OD | GPIO_CR_MODE_OUTPUT_50MHZ,
+ /** Alternate function output push-pull. */
+ GPIO_AF_OUTPUT_PP = GPIO_CR_CNF_AF_OUTPUT_PP | GPIO_CR_MODE_OUTPUT_50MHZ,
+ /** Alternate function output open drain. */
+ GPIO_AF_OUTPUT_OD = GPIO_CR_CNF_AF_OUTPUT_OD | GPIO_CR_MODE_OUTPUT_50MHZ,
+ /** Analog input. */
+ GPIO_INPUT_ANALOG = GPIO_CR_CNF_INPUT_ANALOG | GPIO_CR_MODE_INPUT,
+ /** Input floating. */
+ GPIO_INPUT_FLOATING = GPIO_CR_CNF_INPUT_FLOATING | GPIO_CR_MODE_INPUT,
+ /** Input pull-down. */
+ GPIO_INPUT_PD = GPIO_CR_CNF_INPUT_PU_PD | GPIO_CR_MODE_INPUT,
+ /** Input pull-up. */
+ GPIO_INPUT_PU, /* (treated a special case, for ODR twiddling) */
} gpio_pin_mode;
-/*
- * GPIO Convenience routines
- */
-
-void gpio_init(gpio_dev *dev);
-void gpio_init_all(void);
-void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode);
-
-/**
- * @brief Get a GPIO port's corresponding afio_exti_port.
- * @param dev GPIO device whose afio_exti_port to return.
- */
-static inline afio_exti_port gpio_exti_port(gpio_dev *dev) {
- return dev->exti_port;
-}
-
-/**
- * Set or reset a GPIO pin.
- *
- * Pin must have previously been configured to output mode.
- *
- * @param dev GPIO device whose pin to set.
- * @param pin Pin on to set or reset
- * @param val If true, set the pin. If false, reset the pin.
- */
-static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) {
- if (val) {
- dev->regs->BSRR = BIT(pin);
- } else {
- dev->regs->BRR = BIT(pin);
- }
-}
-
-/**
- * Determine whether or not a GPIO pin is set.
- *
- * Pin must have previously been configured to input mode.
- *
- * @param dev GPIO device whose pin to test.
- * @param pin Pin on dev to test.
- * @return True if the pin is set, false otherwise.
- */
-static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) {
- return dev->regs->IDR & BIT(pin);
-}
-
-/**
- * Toggle a pin configured as output push-pull.
- * @param dev GPIO device.
- * @param pin Pin on dev to toggle.
- */
-static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) {
- dev->regs->ODR = dev->regs->ODR ^ BIT(pin);
-}
+/* Hacks for F2: */
+#define GPIO_MODE_ANALOG GPIO_INPUT_ANALOG
+#define GPIO_MODE_OUTPUT GPIO_OUTPUT_PP
/*
* AFIO register map
@@ -223,19 +145,14 @@ static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) {
/** AFIO register map */
typedef struct afio_reg_map {
- __io uint32 EVCR; /**< Event control register. */
- __io uint32 MAPR; /**< AF remap and debug I/O configuration
- register. */
- __io uint32 EXTICR1; /**< External interrupt configuration
- register 1. */
- __io uint32 EXTICR2; /**< External interrupt configuration
- register 2. */
- __io uint32 EXTICR3; /**< External interrupt configuration
- register 3. */
- __io uint32 EXTICR4; /**< External interrupt configuration
- register 4. */
- __io uint32 MAPR2; /**< AF remap and debug I/O configuration
- register 2. */
+ __io uint32 EVCR; /**< Event control register. */
+ __io uint32 MAPR; /**< AF remap and debug I/O configuration register. */
+ __io uint32 EXTICR1; /**< External interrupt configuration register 1. */
+ __io uint32 EXTICR2; /**< External interrupt configuration register 2. */
+ __io uint32 EXTICR3; /**< External interrupt configuration register 3. */
+ __io uint32 EXTICR4; /**< External interrupt configuration register 4. */
+ __io uint32 MAPR2; /**<
+ * AF remap and debug I/O configuration register 2. */
} afio_reg_map;
/** AFIO register map base pointer. */
@@ -277,17 +194,17 @@ typedef struct afio_reg_map {
#define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24)
#define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24)
#define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24)
-#define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20)
-#define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19)
-#define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18)
-#define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17)
-#define AFIO_MAPR_TIM5CH4_IREMAP BIT(16)
-#define AFIO_MAPR_PD01_REMAP BIT(15)
+#define AFIO_MAPR_ADC2_ETRGREG_REMAP (1U << 20)
+#define AFIO_MAPR_ADC2_ETRGINJ_REMAP (1U << 19)
+#define AFIO_MAPR_ADC1_ETRGREG_REMAP (1U << 18)
+#define AFIO_MAPR_ADC1_ETRGINJ_REMAP (1U << 17)
+#define AFIO_MAPR_TIM5CH4_IREMAP (1U << 16)
+#define AFIO_MAPR_PD01_REMAP (1U << 15)
#define AFIO_MAPR_CAN_REMAP (0x3 << 13)
#define AFIO_MAPR_CAN_REMAP_NONE (0x0 << 13)
#define AFIO_MAPR_CAN_REMAP_PB8_PB9 (0x2 << 13)
#define AFIO_MAPR_CAN_REMAP_PD0_PD1 (0x3 << 13)
-#define AFIO_MAPR_TIM4_REMAP BIT(12)
+#define AFIO_MAPR_TIM4_REMAP (1U << 12)
#define AFIO_MAPR_TIM3_REMAP (0x3 << 10)
#define AFIO_MAPR_TIM3_REMAP_NONE (0x0 << 10)
#define AFIO_MAPR_TIM3_REMAP_PARTIAL (0x2 << 10)
@@ -305,10 +222,10 @@ typedef struct afio_reg_map {
#define AFIO_MAPR_USART3_REMAP_NONE (0x0 << 4)
#define AFIO_MAPR_USART3_REMAP_PARTIAL (0x1 << 4)
#define AFIO_MAPR_USART3_REMAP_FULL (0x3 << 4)
-#define AFIO_MAPR_USART2_REMAP BIT(3)
-#define AFIO_MAPR_USART1_REMAP BIT(2)
-#define AFIO_MAPR_I2C1_REMAP BIT(1)
-#define AFIO_MAPR_SPI1_REMAP BIT(0)
+#define AFIO_MAPR_USART2_REMAP (1U << 3)
+#define AFIO_MAPR_USART1_REMAP (1U << 2)
+#define AFIO_MAPR_I2C1_REMAP (1U << 1)
+#define AFIO_MAPR_SPI1_REMAP (1U << 0)
/* External interrupt configuration register 1 */
@@ -382,12 +299,12 @@ typedef struct afio_reg_map {
/* AF remap and debug I/O configuration register 2 */
-#define AFIO_MAPR2_FSMC_NADV BIT(10)
-#define AFIO_MAPR2_TIM14_REMAP BIT(9)
-#define AFIO_MAPR2_TIM13_REMAP BIT(8)
-#define AFIO_MAPR2_TIM11_REMAP BIT(7)
-#define AFIO_MAPR2_TIM10_REMAP BIT(6)
-#define AFIO_MAPR2_TIM9_REMAP BIT(5)
+#define AFIO_MAPR2_FSMC_NADV (1U << 10)
+#define AFIO_MAPR2_TIM14_REMAP (1U << 9)
+#define AFIO_MAPR2_TIM13_REMAP (1U << 8)
+#define AFIO_MAPR2_TIM11_REMAP (1U << 7)
+#define AFIO_MAPR2_TIM10_REMAP (1U << 6)
+#define AFIO_MAPR2_TIM9_REMAP (1U << 5)
/*
* AFIO convenience routines
@@ -395,95 +312,67 @@ typedef struct afio_reg_map {
void afio_init(void);
-/**
- * External interrupt line numbers.
- */
-typedef enum afio_exti_num {
- AFIO_EXTI_0, /**< External interrupt line 0. */
- AFIO_EXTI_1, /**< External interrupt line 1. */
- AFIO_EXTI_2, /**< External interrupt line 2. */
- AFIO_EXTI_3, /**< External interrupt line 3. */
- AFIO_EXTI_4, /**< External interrupt line 4. */
- AFIO_EXTI_5, /**< External interrupt line 5. */
- AFIO_EXTI_6, /**< External interrupt line 6. */
- AFIO_EXTI_7, /**< External interrupt line 7. */
- AFIO_EXTI_8, /**< External interrupt line 8. */
- AFIO_EXTI_9, /**< External interrupt line 9. */
- AFIO_EXTI_10, /**< External interrupt line 10. */
- AFIO_EXTI_11, /**< External interrupt line 11. */
- AFIO_EXTI_12, /**< External interrupt line 12. */
- AFIO_EXTI_13, /**< External interrupt line 13. */
- AFIO_EXTI_14, /**< External interrupt line 14. */
- AFIO_EXTI_15, /**< External interrupt line 15. */
-} afio_exti_num;
-
-void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port);
-
/* HACK: Use upper bit to denote MAPR2, Bit 31 is reserved and
* not used in either MAPR or MAPR2 */
-#define AFIO_REMAP_USE_MAPR2 (1 << 31)
+#define AFIO_REMAP_USE_MAPR2 (1U << 31)
/**
* @brief Available peripheral remaps.
* @see afio_remap()
*/
typedef enum afio_remap_peripheral {
- AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP, /**<
- ADC 2 external trigger regular conversion remapping */
- AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP, /**<
- ADC 2 external trigger injected conversion remapping */
- AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP, /**<
- ADC 1 external trigger regular conversion remapping */
- AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP, /**<
- ADC 1 external trigger injected conversion remapping */
- AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP, /**<
- Timer 5 channel 4 internal remapping */
- AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP, /**<
- Port D0/Port D1 mapping on OSC_IN/OSC_OUT */
- AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9, /**<
- CAN alternate function remapping 1 (RX on PB8, TX on PB9) */
- AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1, /**<
- CAN alternate function remapping 2 (RX on PD0, TX on PD1) */
- AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP, /**<
- Timer 4 remapping */
- AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL, /**<
- Timer 3 partial remapping */
- AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL, /**<
- Timer 3 full remapping */
- AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3, /**<
- Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3, CH3
- on PA2, CH4 on PA3) */
- AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, /**<
- Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, CH3
- on PB10, CH4 on PB11) */
- AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /**<
- Timer 2 full remapping */
- AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP, /**<
- USART 2 remapping */
- AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP, /**<
- USART 1 remapping */
- AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP, /**<
- I2C 1 remapping */
- AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP, /**<
- SPI 1 remapping */
- AFIO_REMAP_FSMC_NADV = (AFIO_MAPR2_FSMC_NADV |
- AFIO_REMAP_USE_MAPR2), /**<
- NADV signal not connected */
- AFIO_REMAP_TIM14 = (AFIO_MAPR2_TIM14_REMAP |
- AFIO_REMAP_USE_MAPR2), /**<
- Timer 14 remapping */
- AFIO_REMAP_TIM13 = (AFIO_MAPR2_TIM13_REMAP |
- AFIO_REMAP_USE_MAPR2), /**<
- Timer 13 remapping */
- AFIO_REMAP_TIM11 = (AFIO_MAPR2_TIM11_REMAP |
- AFIO_REMAP_USE_MAPR2), /**<
- Timer 11 remapping */
- AFIO_REMAP_TIM10 = (AFIO_MAPR2_TIM10_REMAP |
- AFIO_REMAP_USE_MAPR2), /**<
- Timer 10 remapping */
- AFIO_REMAP_TIM9 = (AFIO_MAPR2_TIM9_REMAP |
- AFIO_REMAP_USE_MAPR2) /**<
- Timer 9 */
+ /** ADC 2 external trigger regular conversion remapping */
+ AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP,
+ /** ADC 2 external trigger injected conversion remapping */
+ AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP,
+ /** ADC 1 external trigger regular conversion remapping */
+ AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP,
+ /** ADC 1 external trigger injected conversion remapping */
+ AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP,
+ /** Timer 5 channel 4 internal remapping */
+ AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP,
+ /** Port D0/Port D1 mapping on OSC_IN/OSC_OUT */
+ AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP,
+ /** CAN alternate function remapping 1 (RX on PB8, TX on PB9) */
+ AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9,
+ /** CAN alternate function remapping 2 (RX on PD0, TX on PD1) */
+ AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1,
+ /** Timer 4 remapping */
+ AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP,
+ /** Timer 3 partial remapping */
+ AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL,
+ /** Timer 3 full remapping */
+ AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL,
+ /**
+ * Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3,
+ * CH3 on PA2, CH4 on PA3) */
+ AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3,
+ /**
+ * Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1,
+ * CH3 on PB10, CH4 on PB11) */
+ AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11,
+ /** Timer 2 full remapping */
+ AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL,
+ /** USART 2 remapping */
+ AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP,
+ /** USART 1 remapping */
+ AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP,
+ /** I2C 1 remapping */
+ AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP,
+ /** SPI 1 remapping */
+ AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP,
+ /** NADV signal not connected */
+ AFIO_REMAP_FSMC_NADV = AFIO_MAPR2_FSMC_NADV | AFIO_REMAP_USE_MAPR2,
+ /** Timer 14 remapping */
+ AFIO_REMAP_TIM14 = AFIO_MAPR2_TIM14_REMAP | AFIO_REMAP_USE_MAPR2,
+ /** Timer 13 remapping */
+ AFIO_REMAP_TIM13 = AFIO_MAPR2_TIM13_REMAP | AFIO_REMAP_USE_MAPR2,
+ /** Timer 11 remapping */
+ AFIO_REMAP_TIM11 = AFIO_MAPR2_TIM11_REMAP | AFIO_REMAP_USE_MAPR2,
+ /** Timer 10 remapping */
+ AFIO_REMAP_TIM10 = AFIO_MAPR2_TIM10_REMAP | AFIO_REMAP_USE_MAPR2,
+ /** Timer 9 remapping */
+ AFIO_REMAP_TIM9 = AFIO_MAPR2_TIM9_REMAP | AFIO_REMAP_USE_MAPR2,
} afio_remap_peripheral;
void afio_remap(afio_remap_peripheral p);
@@ -497,16 +386,14 @@ void afio_remap(afio_remap_peripheral p);
* @see afio_cfg_debug_ports()
*/
typedef enum afio_debug_cfg {
- AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, /**<
- Full Serial Wire and JTAG debug */
- AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, /**<
- Full Serial Wire and JTAG, but no NJTRST. */
- AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, /**<
- Serial Wire debug only (JTAG-DP disabled,
- SW-DP enabled) */
- AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW /**<
- No debug; all JTAG and SW pins are free
- for use as GPIOs. */
+ /** Full Serial Wire and JTAG debug */
+ AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ,
+ /** Full Serial Wire and JTAG, but no NJTRST. */
+ AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST,
+ /** Serial Wire debug only (JTAG-DP disabled, SW-DP enabled) */
+ AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW,
+ /** No debug; all JTAG and SW pins are free for use as GPIOs. */
+ AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW,
} afio_debug_cfg;
/**
@@ -519,9 +406,88 @@ static inline void afio_cfg_debug_ports(afio_debug_cfg config) {
*mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config;
}
+/*
+ * Deprecated bits
+ */
+
+/**
+ * @brief Deprecated. Use exti_cfg instead.
+ *
+ * In previous versions of libmaple, exti_attach_interrupt() took an
+ * afio_exti_port argument; afio_exti_port was also a member of struct
+ * gpio_dev. This isn't portable, so we now use exti_cfg
+ * instead. This typedef (and the macros AFIO_EXTI_PA, ...,
+ * AFIO_EXTI_PG) exist to preserve backwards compatibility.
+ */
+typedef exti_cfg afio_exti_port;
+
+/** Deprecated. Use EXTI_PA instead. */
+#define AFIO_EXTI_PA EXTI_PA
+/** Deprecated. Use EXTI_PB instead. */
+#define AFIO_EXTI_PB EXTI_PB
+/** Deprecated. Use EXTI_PC instead. */
+#define AFIO_EXTI_PC EXTI_PC
+/** Deprecated. Use EXTI_PD instead. */
+#define AFIO_EXTI_PD EXTI_PD
+/** Deprecated. Use EXTI_PE instead. */
+#define AFIO_EXTI_PE EXTI_PE
+/** Deprecated. Use EXTI_PF instead. */
+#define AFIO_EXTI_PF EXTI_PF
+/** Deprecated. Use EXTI_PG instead. */
+#define AFIO_EXTI_PG EXTI_PG
+
+/**
+ * @brief Deprecated. Use exti_num instead.
+ *
+ * In previous versions of libmaple, exti_attach_interrupt() took an
+ * afio_exti_num argument. This isn't portable, so we use exti_num
+ * instead. This typedef (and the macros AFIO_EXTI_0, ...,
+ * AFIO_EXTI_15) exist to preserve backwards compatibility.
+ */
+typedef exti_num afio_exti_num;
+
+/** Deprecated. Use EXTI0 instead. */
+#define AFIO_EXTI_0 EXTI0
+/** Deprecated. Use EXTI1 instead. */
+#define AFIO_EXTI_1 EXTI1
+/** Deprecated. Use EXTI2 instead. */
+#define AFIO_EXTI_2 EXTI2
+/** Deprecated. Use EXTI3 instead. */
+#define AFIO_EXTI_3 EXTI3
+/** Deprecated. Use EXTI4 instead. */
+#define AFIO_EXTI_4 EXTI4
+/** Deprecated. Use EXTI5 instead. */
+#define AFIO_EXTI_5 EXTI5
+/** Deprecated. Use EXTI6 instead. */
+#define AFIO_EXTI_6 EXTI6
+/** Deprecated. Use EXTI7 instead. */
+#define AFIO_EXTI_7 EXTI7
+/** Deprecated. Use EXTI8 instead. */
+#define AFIO_EXTI_8 EXTI8
+/** Deprecated. Use EXTI9 instead. */
+#define AFIO_EXTI_9 EXTI9
+/** Deprecated. Use EXTI10 instead. */
+#define AFIO_EXTI_10 EXTI10
+/** Deprecated. Use EXTI11 instead. */
+#define AFIO_EXTI_11 EXTI11
+/** Deprecated. Use EXTI12 instead. */
+#define AFIO_EXTI_12 EXTI12
+/** Deprecated. Use EXTI13 instead. */
+#define AFIO_EXTI_13 EXTI13
+/** Deprecated. Use EXTI14 instead. */
+#define AFIO_EXTI_14 EXTI14
+/** Deprecated. Use EXTI15 instead. */
+#define AFIO_EXTI_15 EXTI15
+
+/**
+ * @brief Deprecated. Use exti_select(exti, port) instead.
+ */
+static __always_inline void afio_exti_select(exti_num exti, exti_cfg port) {
+ exti_select(exti, port);
+}
+
#ifdef __cplusplus
}
#endif
#endif
-
diff --git a/libmaple/stm32f1/include/series/i2c.h b/libmaple/stm32f1/include/series/i2c.h
new file mode 100644
index 0000000..a0822e8
--- /dev/null
+++ b/libmaple/stm32f1/include/series/i2c.h
@@ -0,0 +1,85 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung (from <libmaple/i2c.h>).
+ * 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/include/stm32f1/include/series/i2c.h
+ * @brief STM32F1 I2C
+ */
+
+#ifndef _LIBMAPLE_STM32F1_I2C_H_
+#define _LIBMAPLE_STM32F1_I2C_H_
+
+#include <libmaple/i2c_common.h>
+#include <libmaple/gpio.h>
+#include <libmaple/stm32.h>
+
+/*
+ * Register maps
+ */
+
+struct i2c_reg_map;
+
+/** STM32F1 I2C1 register map base pointer */
+#define I2C1_BASE ((struct i2c_reg_map*)0x40005400)
+/** STM32F1 I2C2 register map base pointer */
+#define I2C2_BASE ((struct i2c_reg_map*)0x40005800)
+
+/*
+ * Devices
+ */
+
+extern i2c_dev* const I2C1;
+extern i2c_dev* const I2C2;
+
+/*
+ * For internal use
+ */
+
+static inline uint32 _i2c_bus_clk(i2c_dev *dev) {
+ /* Both I2C peripherals are on APB1 */
+ return STM32_PCLK1 / (1000 * 1000);
+}
+
+#define _I2C_HAVE_IRQ_FIXUP 1
+void _i2c_irq_priority_fixup(i2c_dev *dev);
+
+/*
+ * Deprecated functionality
+ */
+
+/* Flag to use alternate pin mapping in i2c_master_enable(). */
+#define _I2C_HAVE_DEPRECATED_I2C_REMAP 1
+#define I2C_REMAP 0x4
+static inline void _i2c_handle_remap(i2c_dev *dev, uint32 flags) {
+ if ((dev == I2C1) && (flags & I2C_REMAP)) {
+ afio_remap(AFIO_REMAP_I2C1);
+ I2C1->sda_pin = 9;
+ I2C1->scl_pin = 8;
+ }
+}
+
+#endif /* _LIBMAPLE_STM32F1_I2C_H_ */
diff --git a/libmaple/nvic.h b/libmaple/stm32f1/include/series/nvic.h
index feb7335..cdac737 100644
--- a/libmaple/nvic.h
+++ b/libmaple/stm32f1/include/series/nvic.h
@@ -25,63 +25,23 @@
*****************************************************************************/
/**
- * @file nvic.h
- * @brief Nested vector interrupt controller support.
- *
- * Basic usage:
- *
- * @code
- * // Initialise the interrupt controller and point to the vector
- * // table at the start of flash.
- * nvic_init(0x08000000, 0);
- * // Bind in a timer interrupt handler
- * timer_attach_interrupt(TIMER_CC1_INTERRUPT, handler);
- * // Optionally set the priority
- * nvic_irq_set_priority(NVIC_TIMER1_CC, 5);
- * // All done, enable all interrupts
- * nvic_globalirq_enable();
- * @endcode
+ * @file libmaple/stm32f1/include/series/nvic.h
+ * @brief STM32F1 Nested Vectored Interrupt Controller (NVIC) support.
*/
-#ifndef _NVIC_H_
-#define _NVIC_H_
-
-#include "libmaple_types.h"
-#include "util.h"
+#ifndef _LIBMAPLE_STM32F1_NVIC_H_
+#define _LIBMAPLE_STM32F1_NVIC_H_
#ifdef __cplusplus
extern "C"{
#endif
-/** NVIC register map type. */
-typedef struct nvic_reg_map {
- __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */
- uint32 RESERVED0[24]; /**< Reserved */
- __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */
- uint32 RSERVED1[24]; /**< Reserved */
- __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */
- uint32 RESERVED2[24]; /**< Reserved */
- __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */
- uint32 RESERVED3[24]; /**< Reserved */
- __io uint32 IABR[8]; /**< Interrupt Active bit Registers */
- uint32 RESERVED4[56]; /**< Reserved */
- __io uint8 IP[240]; /**< Interrupt Priority Registers */
- uint32 RESERVED5[644]; /**< Reserved */
- __io uint32 STIR; /**< Software Trigger Interrupt Registers */
-} nvic_reg_map;
-
-/** NVIC register map base pointer. */
-#define NVIC_BASE ((struct nvic_reg_map*)0xE000E100)
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.h>
/**
- * @brief Interrupt vector table interrupt numbers.
- *
- * Each positive-valued enumerator is the position of the
- * corresponding interrupt in the vector table. Negative-valued
- * enumerators correspond to interrupts controlled by the system
- * handler block.
- *
- * @see scb.h
+ * @brief STM32F1 interrupt vector table interrupt numbers.
+ * @see <libmaple/scb.h>
*/
typedef enum nvic_irq_num {
NVIC_NMI = -14, /**< Non-maskable interrupt */
@@ -119,9 +79,11 @@ typedef enum nvic_irq_num {
NVIC_CAN_RX1 = 21, /**< CAN RX1 */
NVIC_CAN_SCE = 22, /**< CAN SCE */
NVIC_EXTI_9_5 = 23, /**< EXTI line [9:5] */
- NVIC_TIMER1_BRK = 24, /**< Timer 1 break */
- NVIC_TIMER1_UP = 25, /**< Timer 1 update */
- NVIC_TIMER1_TRG_COM = 26, /**< Timer 1 trigger and commutation */
+ NVIC_TIMER1_BRK_TIMER9 = 24, /**< Timer 1 break, Timer 9. */
+ NVIC_TIMER1_UP_TIMER10 = 25, /**< Timer 1 update, Timer 10. */
+ NVIC_TIMER1_TRG_COM_TIMER11 = 26, /**<
+ * Timer 1 trigger and commutation,
+ * Timer 11. */
NVIC_TIMER1_CC = 27, /**< Timer 1 capture/compare */
NVIC_TIMER2 = 28, /**< Timer 2 */
NVIC_TIMER3 = 29, /**< Timer 3 */
@@ -139,11 +101,12 @@ typedef enum nvic_irq_num {
NVIC_RTCALARM = 41, /**< RTC alarm through EXTI line */
NVIC_USBWAKEUP = 42, /**< USB wakeup from suspend through
EXTI line */
- NVIC_TIMER8_BRK = 43, /**< Timer 8 break */
- NVIC_TIMER8_UP = 44, /**< Timer 8 update */
- NVIC_TIMER8_TRG_COM = 45, /**< Timer 8 trigger and commutation */
+ NVIC_TIMER8_BRK_TIMER12 = 43, /**< Timer 8 break, timer 12 */
+ NVIC_TIMER8_UP_TIMER13 = 44, /**< Timer 8 update, timer 13 */
+ NVIC_TIMER8_TRG_COM_TIMER14 = 45, /**<
+ * Timer 8 trigger and commutation,
+ * Timer 14. */
NVIC_TIMER8_CC = 46, /**< Timer 8 capture/compare */
-#ifdef STM32_HIGH_DENSITY
NVIC_ADC3 = 47, /**< ADC3 */
NVIC_FSMC = 48, /**< FSMC */
NVIC_SDIO = 49, /**< SDIO */
@@ -157,81 +120,50 @@ typedef enum nvic_irq_num {
NVIC_DMA2_CH2 = 57, /**< DMA2 channel 2 */
NVIC_DMA2_CH3 = 58, /**< DMA2 channel 3 */
NVIC_DMA2_CH_4_5 = 59, /**< DMA2 channels 4 and 5 */
-#endif
-} nvic_irq_num;
-
-/*
- * Initialises the interrupt controller and sets all interrupts to the
- * lowest priority.
- *
- * For stand-alone products, the base address is normally the start of
- * flash (0x08000000).
- *
- * @param vector_table_address base address of the vector table
- */
-void nvic_init(uint32 vector_table_address, uint32 offset);
-
-/**
- * Sets the base address of the vector table.
- */
-void nvic_set_vector_table(uint32 address, uint32 offset);
-
-void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority);
-void nvic_sys_reset();
-
-/**
- * Enables interrupts and configurable fault handlers (clear PRIMASK).
- */
-static inline void nvic_globalirq_enable() {
- asm volatile("cpsie i");
-}
-
-/**
- * Disable interrupts and configurable fault handlers (set PRIMASK).
- */
-static inline void nvic_globalirq_disable() {
- asm volatile("cpsid i");
-}
-
-/**
- * @brief Enable interrupt irq_num
- * @param irq_num Interrupt to enable
- */
-static inline void nvic_irq_enable(nvic_irq_num irq_num) {
- if (irq_num < 0) {
- return;
- }
- NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32);
-}
-/**
- * @brief Disable interrupt irq_num
- * @param irq_num Interrupt to disable
- */
-static inline void nvic_irq_disable(nvic_irq_num irq_num) {
- if (irq_num < 0) {
- return;
- }
- NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32);
-}
+ /* Old enumerators kept around for backwards compatibility: */
+ NVIC_TIMER1_BRK =
+ NVIC_TIMER1_BRK_TIMER9, /**< @brief (Deprecated) Timer 1 break
+ *
+ * For backwards compatibility only.
+ * Use NVIC_TIMER1_BRK_TIMER9 instead. */
+ NVIC_TIMER1_UP =
+ NVIC_TIMER1_UP_TIMER10, /**< @brief (Deprecated) Timer 1 update.
+ *
+ * For backwards compatibility only.
+ * Use NVIC_TIMER1_UP_TIMER10 instead. */
+ NVIC_TIMER1_TRG_COM =
+ NVIC_TIMER1_TRG_COM_TIMER11, /**< @brief (deprecated) Timer 1 trigger
+ * and commutation.
+ *
+ * For backwards compatibility only.
+ * Use NVIC_TIMER1_TRG_COM_TIMER11
+ * instead. */
+ NVIC_TIMER8_BRK =
+ NVIC_TIMER8_BRK_TIMER12, /**< @brief (deprecated) Timer 8 break
+ *
+ * For backwards compatibility only.
+ * Use NVIC_TIMER8_BRK_TIMER12 instead. */
+ NVIC_TIMER8_UP =
+ NVIC_TIMER8_UP_TIMER13, /**< @brief (deprecated) Timer 8 update
+ * For backwards compatibility only.
+ * Use NVIC_TIMER8_UP_TIMER13 instead. */
+ NVIC_TIMER8_TRG_COM =
+ NVIC_TIMER8_TRG_COM_TIMER14, /**< @brief (deprecated) Timer 8 trigger
+ * and commutation.
+ * For backwards compatibility only.
+ * Use NVIC_TIMER8_TRG_COM_TIMER14
+ * instead. */
+} nvic_irq_num;
-/**
- * @brief Quickly disable all interrupts.
- *
- * Calling this function is significantly faster than calling
- * nvic_irq_disable() in a loop.
- */
static inline void nvic_irq_disable_all(void) {
- /* Note: This only works up to XL density. The fix for
- * connectivity line is:
- *
- * NVIC_BASE->ICER[2] = 0xF;
- *
- * We don't support connectivity line devices (yet), so leave it
- * alone for now.
- */
+ /* Even low-density devices have over 32 interrupt lines. */
NVIC_BASE->ICER[0] = 0xFFFFFFFF;
NVIC_BASE->ICER[1] = 0xFFFFFFFF;
+#if STM32_NR_INTERRUPTS > 64
+ /* Only some have over 64; e.g. connectivity line MCUs. */
+ NVIC_BASE->ICER[2] = 0xFFFFFFFF;
+#endif
}
#ifdef __cplusplus
diff --git a/libmaple/stm32f1/include/series/pwr.h b/libmaple/stm32f1/include/series/pwr.h
new file mode 100644
index 0000000..e143a8c
--- /dev/null
+++ b/libmaple/stm32f1/include/series/pwr.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * 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/stm32f1/include/series/pwr.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 Power control (PWR) support.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_PWR_H_
+#define _LIBMAPLE_STM32F1_PWR_H_
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+
+/* PVD level selection */
+#define PWR_CR_PLS_2_2V (0x0 << 5)
+#define PWR_CR_PLS_2_3V (0x1 << 5)
+#define PWR_CR_PLS_2_4V (0x2 << 5)
+#define PWR_CR_PLS_2_5V (0x3 << 5)
+#define PWR_CR_PLS_2_6V (0x4 << 5)
+#define PWR_CR_PLS_2_7V (0x5 << 5)
+#define PWR_CR_PLS_2_8V (0x6 << 5)
+#define PWR_CR_PLS_2_9V (0x7 << 5)
+
+#endif
diff --git a/libmaple/rcc.h b/libmaple/stm32f1/include/series/rcc.h
index c50686c..225ca49 100644
--- a/libmaple/rcc.h
+++ b/libmaple/stm32f1/include/series/rcc.h
@@ -2,6 +2,7 @@
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,20 +26,24 @@
*****************************************************************************/
/**
- * @file rcc.h
- * @brief reset and clock control definitions and prototypes
+ * @file libmaple/stm32f1/include/series/rcc.h
+ * @brief STM32F1 reset and clock control (RCC) support.
*/
-#include "libmaple_types.h"
-
-#ifndef _RCC_H_
-#define _RCC_H_
+#ifndef _LIBMAPLE_STM32F1_RCC_H_
+#define _LIBMAPLE_STM32F1_RCC_H_
#ifdef __cplusplus
extern "C"{
#endif
-/** RCC register map type */
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** STM32F1 RCC register map type */
typedef struct rcc_reg_map {
__io uint32 CR; /**< Clock control register */
__io uint32 CFGR; /**< Clock configuration register */
@@ -52,7 +57,6 @@ typedef struct rcc_reg_map {
__io uint32 CSR; /**< Control/status register */
} rcc_reg_map;
-/** RCC register map base pointer */
#define RCC_BASE ((struct rcc_reg_map*)0x40021000)
/*
@@ -70,16 +74,16 @@ typedef struct rcc_reg_map {
#define RCC_CR_HSIRDY_BIT 1
#define RCC_CR_HSION_BIT 0
-#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT)
-#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT)
-#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT)
-#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT)
-#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT)
-#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT)
+#define RCC_CR_PLLRDY (1U << RCC_CR_PLLRDY_BIT)
+#define RCC_CR_PLLON (1U << RCC_CR_PLLON_BIT)
+#define RCC_CR_CSSON (1U << RCC_CR_CSSON_BIT)
+#define RCC_CR_HSEBYP (1U << RCC_CR_HSEBYP_BIT)
+#define RCC_CR_HSERDY (1U << RCC_CR_HSERDY_BIT)
+#define RCC_CR_HSEON (1U << RCC_CR_HSEON_BIT)
#define RCC_CR_HSICAL (0xFF << 8)
#define RCC_CR_HSITRIM (0x1F << 3)
-#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT)
-#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT)
+#define RCC_CR_HSIRDY (1U << RCC_CR_HSIRDY_BIT)
+#define RCC_CR_HSION (1U << RCC_CR_HSION_BIT)
/* Clock configuration register */
@@ -88,10 +92,10 @@ typedef struct rcc_reg_map {
#define RCC_CFGR_PLLSRC_BIT 16
#define RCC_CFGR_MCO (0x3 << 24)
-#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT)
+#define RCC_CFGR_USBPRE (1U << RCC_CFGR_USBPRE_BIT)
#define RCC_CFGR_PLLMUL (0xF << 18)
-#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT)
-#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT)
+#define RCC_CFGR_PLLXTPRE (1U << RCC_CFGR_PLLXTPRE_BIT)
+#define RCC_CFGR_PLLSRC (1U << RCC_CFGR_PLLSRC_BIT)
#define RCC_CFGR_ADCPRE (0x3 << 14)
#define RCC_CFGR_PPRE2 (0x7 << 11)
#define RCC_CFGR_PPRE1 (0x7 << 8)
@@ -123,23 +127,23 @@ typedef struct rcc_reg_map {
#define RCC_CIR_LSERDYF_BIT 1
#define RCC_CIR_LSIRDYF_BIT 0
-#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT)
-#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT)
-#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT)
-#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT)
-#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT)
-#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT)
-#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT)
-#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT)
-#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT)
-#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT)
-#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT)
-#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT)
-#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT)
-#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT)
-#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT)
-#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT)
-#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT)
+#define RCC_CIR_CSSC (1U << RCC_CIR_CSSC_BIT)
+#define RCC_CIR_PLLRDYC (1U << RCC_CIR_PLLRDYC_BIT)
+#define RCC_CIR_HSERDYC (1U << RCC_CIR_HSERDYC_BIT)
+#define RCC_CIR_HSIRDYC (1U << RCC_CIR_HSIRDYC_BIT)
+#define RCC_CIR_LSERDYC (1U << RCC_CIR_LSERDYC_BIT)
+#define RCC_CIR_LSIRDYC (1U << RCC_CIR_LSIRDYC_BIT)
+#define RCC_CIR_PLLRDYIE (1U << RCC_CIR_PLLRDYIE_BIT)
+#define RCC_CIR_HSERDYIE (1U << RCC_CIR_HSERDYIE_BIT)
+#define RCC_CIR_HSIRDYIE (1U << RCC_CIR_HSIRDYIE_BIT)
+#define RCC_CIR_LSERDYIE (1U << RCC_CIR_LSERDYIE_BIT)
+#define RCC_CIR_LSIRDYIE (1U << RCC_CIR_LSIRDYIE_BIT)
+#define RCC_CIR_CSSF (1U << RCC_CIR_CSSF_BIT)
+#define RCC_CIR_PLLRDYF (1U << RCC_CIR_PLLRDYF_BIT)
+#define RCC_CIR_HSERDYF (1U << RCC_CIR_HSERDYF_BIT)
+#define RCC_CIR_HSIRDYF (1U << RCC_CIR_HSIRDYF_BIT)
+#define RCC_CIR_LSERDYF (1U << RCC_CIR_LSERDYF_BIT)
+#define RCC_CIR_LSIRDYF (1U << RCC_CIR_LSIRDYF_BIT)
/* APB2 peripheral reset register */
@@ -162,24 +166,24 @@ typedef struct rcc_reg_map {
#define RCC_APB2RSTR_IOPARST_BIT 2
#define RCC_APB2RSTR_AFIORST_BIT 0
-#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT)
-#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT)
-#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT)
-#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT)
-#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT)
-#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT)
-#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT)
-#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT)
-#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT)
-#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT)
-#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT)
-#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT)
-#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT)
-#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT)
-#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT)
-#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT)
-#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT)
-#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT)
+#define RCC_APB2RSTR_TIM11RST (1U << RCC_APB2RSTR_TIM11RST_BIT)
+#define RCC_APB2RSTR_TIM10RST (1U << RCC_APB2RSTR_TIM10RST_BIT)
+#define RCC_APB2RSTR_TIM9RST (1U << RCC_APB2RSTR_TIM9RST_BIT)
+#define RCC_APB2RSTR_ADC3RST (1U << RCC_APB2RSTR_ADC3RST_BIT)
+#define RCC_APB2RSTR_USART1RST (1U << RCC_APB2RSTR_USART1RST_BIT)
+#define RCC_APB2RSTR_TIM8RST (1U << RCC_APB2RSTR_TIM8RST_BIT)
+#define RCC_APB2RSTR_SPI1RST (1U << RCC_APB2RSTR_SPI1RST_BIT)
+#define RCC_APB2RSTR_TIM1RST (1U << RCC_APB2RSTR_TIM1RST_BIT)
+#define RCC_APB2RSTR_ADC2RST (1U << RCC_APB2RSTR_ADC2RST_BIT)
+#define RCC_APB2RSTR_ADC1RST (1U << RCC_APB2RSTR_ADC1RST_BIT)
+#define RCC_APB2RSTR_IOPGRST (1U << RCC_APB2RSTR_IOPGRST_BIT)
+#define RCC_APB2RSTR_IOPFRST (1U << RCC_APB2RSTR_IOPFRST_BIT)
+#define RCC_APB2RSTR_IOPERST (1U << RCC_APB2RSTR_IOPERST_BIT)
+#define RCC_APB2RSTR_IOPDRST (1U << RCC_APB2RSTR_IOPDRST_BIT)
+#define RCC_APB2RSTR_IOPCRST (1U << RCC_APB2RSTR_IOPCRST_BIT)
+#define RCC_APB2RSTR_IOPBRST (1U << RCC_APB2RSTR_IOPBRST_BIT)
+#define RCC_APB2RSTR_IOPARST (1U << RCC_APB2RSTR_IOPARST_BIT)
+#define RCC_APB2RSTR_AFIORST (1U << RCC_APB2RSTR_AFIORST_BIT)
/* APB1 peripheral reset register */
@@ -207,29 +211,29 @@ typedef struct rcc_reg_map {
#define RCC_APB1RSTR_TIM3RST_BIT 1
#define RCC_APB1RSTR_TIM2RST_BIT 0
-#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT)
-#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT)
-#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT)
-#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT)
-#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT)
-#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT)
-#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT)
-#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT)
-#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT)
-#define RCC_APB1RSTR_USART3RST BIT(RCC_APB1RSTR_USART3RST_BIT)
-#define RCC_APB1RSTR_USART2RST BIT(RCC_APB1RSTR_USART2RST_BIT)
-#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT)
-#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT)
-#define RCC_APB1RSTR_WWDRST BIT(RCC_APB1RSTR_WWDRST_BIT)
-#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT)
-#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT)
-#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT)
-#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT)
-#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT)
-#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT)
-#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT)
-#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT)
-#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT)
+#define RCC_APB1RSTR_DACRST (1U << RCC_APB1RSTR_DACRST_BIT)
+#define RCC_APB1RSTR_PWRRST (1U << RCC_APB1RSTR_PWRRST_BIT)
+#define RCC_APB1RSTR_BKPRST (1U << RCC_APB1RSTR_BKPRST_BIT)
+#define RCC_APB1RSTR_CANRST (1U << RCC_APB1RSTR_CANRST_BIT)
+#define RCC_APB1RSTR_USBRST (1U << RCC_APB1RSTR_USBRST_BIT)
+#define RCC_APB1RSTR_I2C2RST (1U << RCC_APB1RSTR_I2C2RST_BIT)
+#define RCC_APB1RSTR_I2C1RST (1U << RCC_APB1RSTR_I2C1RST_BIT)
+#define RCC_APB1RSTR_UART5RST (1U << RCC_APB1RSTR_UART5RST_BIT)
+#define RCC_APB1RSTR_UART4RST (1U << RCC_APB1RSTR_UART4RST_BIT)
+#define RCC_APB1RSTR_USART3RST (1U << RCC_APB1RSTR_USART3RST_BIT)
+#define RCC_APB1RSTR_USART2RST (1U << RCC_APB1RSTR_USART2RST_BIT)
+#define RCC_APB1RSTR_SPI3RST (1U << RCC_APB1RSTR_SPI3RST_BIT)
+#define RCC_APB1RSTR_SPI2RST (1U << RCC_APB1RSTR_SPI2RST_BIT)
+#define RCC_APB1RSTR_WWDRST (1U << RCC_APB1RSTR_WWDRST_BIT)
+#define RCC_APB1RSTR_TIM14RST (1U << RCC_APB1RSTR_TIM14RST_BIT)
+#define RCC_APB1RSTR_TIM13RST (1U << RCC_APB1RSTR_TIM13RST_BIT)
+#define RCC_APB1RSTR_TIM12RST (1U << RCC_APB1RSTR_TIM12RST_BIT)
+#define RCC_APB1RSTR_TIM7RST (1U << RCC_APB1RSTR_TIM7RST_BIT)
+#define RCC_APB1RSTR_TIM6RST (1U << RCC_APB1RSTR_TIM6RST_BIT)
+#define RCC_APB1RSTR_TIM5RST (1U << RCC_APB1RSTR_TIM5RST_BIT)
+#define RCC_APB1RSTR_TIM4RST (1U << RCC_APB1RSTR_TIM4RST_BIT)
+#define RCC_APB1RSTR_TIM3RST (1U << RCC_APB1RSTR_TIM3RST_BIT)
+#define RCC_APB1RSTR_TIM2RST (1U << RCC_APB1RSTR_TIM2RST_BIT)
/* AHB peripheral clock enable register */
@@ -241,13 +245,13 @@ typedef struct rcc_reg_map {
#define RCC_AHBENR_DMA2EN_BIT 1
#define RCC_AHBENR_DMA1EN_BIT 0
-#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT)
-#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT)
-#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT)
-#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT)
-#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT)
-#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT)
-#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT)
+#define RCC_AHBENR_SDIOEN (1U << RCC_AHBENR_SDIOEN_BIT)
+#define RCC_AHBENR_FSMCEN (1U << RCC_AHBENR_FSMCEN_BIT)
+#define RCC_AHBENR_CRCEN (1U << RCC_AHBENR_CRCEN_BIT)
+#define RCC_AHBENR_FLITFEN (1U << RCC_AHBENR_FLITFEN_BIT)
+#define RCC_AHBENR_SRAMEN (1U << RCC_AHBENR_SRAMEN_BIT)
+#define RCC_AHBENR_DMA2EN (1U << RCC_AHBENR_DMA2EN_BIT)
+#define RCC_AHBENR_DMA1EN (1U << RCC_AHBENR_DMA1EN_BIT)
/* APB2 peripheral clock enable register */
@@ -270,24 +274,24 @@ typedef struct rcc_reg_map {
#define RCC_APB2ENR_IOPAEN_BIT 2
#define RCC_APB2ENR_AFIOEN_BIT 0
-#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT)
-#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT)
-#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT)
-#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT)
-#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT)
-#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT)
-#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT)
-#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT)
-#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT)
-#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT)
-#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT)
-#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT)
-#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT)
-#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT)
-#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT)
-#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT)
-#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT)
-#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT)
+#define RCC_APB2ENR_TIM11EN (1U << RCC_APB2ENR_TIM11EN_BIT)
+#define RCC_APB2ENR_TIM10EN (1U << RCC_APB2ENR_TIM10EN_BIT)
+#define RCC_APB2ENR_TIM9EN (1U << RCC_APB2ENR_TIM9EN_BIT)
+#define RCC_APB2ENR_ADC3EN (1U << RCC_APB2ENR_ADC3EN_BIT)
+#define RCC_APB2ENR_USART1EN (1U << RCC_APB2ENR_USART1EN_BIT)
+#define RCC_APB2ENR_TIM8EN (1U << RCC_APB2ENR_TIM8EN_BIT)
+#define RCC_APB2ENR_SPI1EN (1U << RCC_APB2ENR_SPI1EN_BIT)
+#define RCC_APB2ENR_TIM1EN (1U << RCC_APB2ENR_TIM1EN_BIT)
+#define RCC_APB2ENR_ADC2EN (1U << RCC_APB2ENR_ADC2EN_BIT)
+#define RCC_APB2ENR_ADC1EN (1U << RCC_APB2ENR_ADC1EN_BIT)
+#define RCC_APB2ENR_IOPGEN (1U << RCC_APB2ENR_IOPGEN_BIT)
+#define RCC_APB2ENR_IOPFEN (1U << RCC_APB2ENR_IOPFEN_BIT)
+#define RCC_APB2ENR_IOPEEN (1U << RCC_APB2ENR_IOPEEN_BIT)
+#define RCC_APB2ENR_IOPDEN (1U << RCC_APB2ENR_IOPDEN_BIT)
+#define RCC_APB2ENR_IOPCEN (1U << RCC_APB2ENR_IOPCEN_BIT)
+#define RCC_APB2ENR_IOPBEN (1U << RCC_APB2ENR_IOPBEN_BIT)
+#define RCC_APB2ENR_IOPAEN (1U << RCC_APB2ENR_IOPAEN_BIT)
+#define RCC_APB2ENR_AFIOEN (1U << RCC_APB2ENR_AFIOEN_BIT)
/* APB1 peripheral clock enable register */
@@ -315,29 +319,29 @@ typedef struct rcc_reg_map {
#define RCC_APB1ENR_TIM3EN_BIT 1
#define RCC_APB1ENR_TIM2EN_BIT 0
-#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT)
-#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT)
-#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT)
-#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT)
-#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT)
-#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT)
-#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT)
-#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT)
-#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT)
-#define RCC_APB1ENR_USART3EN BIT(RCC_APB1ENR_USART3EN_BIT)
-#define RCC_APB1ENR_USART2EN BIT(RCC_APB1ENR_USART2EN_BIT)
-#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT)
-#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT)
-#define RCC_APB1ENR_WWDEN BIT(RCC_APB1ENR_WWDEN_BIT)
-#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT)
-#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT)
-#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT)
-#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT)
-#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT)
-#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT)
-#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT)
-#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT)
-#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT)
+#define RCC_APB1ENR_DACEN (1U << RCC_APB1ENR_DACEN_BIT)
+#define RCC_APB1ENR_PWREN (1U << RCC_APB1ENR_PWREN_BIT)
+#define RCC_APB1ENR_BKPEN (1U << RCC_APB1ENR_BKPEN_BIT)
+#define RCC_APB1ENR_CANEN (1U << RCC_APB1ENR_CANEN_BIT)
+#define RCC_APB1ENR_USBEN (1U << RCC_APB1ENR_USBEN_BIT)
+#define RCC_APB1ENR_I2C2EN (1U << RCC_APB1ENR_I2C2EN_BIT)
+#define RCC_APB1ENR_I2C1EN (1U << RCC_APB1ENR_I2C1EN_BIT)
+#define RCC_APB1ENR_UART5EN (1U << RCC_APB1ENR_UART5EN_BIT)
+#define RCC_APB1ENR_UART4EN (1U << RCC_APB1ENR_UART4EN_BIT)
+#define RCC_APB1ENR_USART3EN (1U << RCC_APB1ENR_USART3EN_BIT)
+#define RCC_APB1ENR_USART2EN (1U << RCC_APB1ENR_USART2EN_BIT)
+#define RCC_APB1ENR_SPI3EN (1U << RCC_APB1ENR_SPI3EN_BIT)
+#define RCC_APB1ENR_SPI2EN (1U << RCC_APB1ENR_SPI2EN_BIT)
+#define RCC_APB1ENR_WWDEN (1U << RCC_APB1ENR_WWDEN_BIT)
+#define RCC_APB1ENR_TIM14EN (1U << RCC_APB1ENR_TIM14EN_BIT)
+#define RCC_APB1ENR_TIM13EN (1U << RCC_APB1ENR_TIM13EN_BIT)
+#define RCC_APB1ENR_TIM12EN (1U << RCC_APB1ENR_TIM12EN_BIT)
+#define RCC_APB1ENR_TIM7EN (1U << RCC_APB1ENR_TIM7EN_BIT)
+#define RCC_APB1ENR_TIM6EN (1U << RCC_APB1ENR_TIM6EN_BIT)
+#define RCC_APB1ENR_TIM5EN (1U << RCC_APB1ENR_TIM5EN_BIT)
+#define RCC_APB1ENR_TIM4EN (1U << RCC_APB1ENR_TIM4EN_BIT)
+#define RCC_APB1ENR_TIM3EN (1U << RCC_APB1ENR_TIM3EN_BIT)
+#define RCC_APB1ENR_TIM2EN (1U << RCC_APB1ENR_TIM2EN_BIT)
/* Backup domain control register */
@@ -347,15 +351,15 @@ typedef struct rcc_reg_map {
#define RCC_BDCR_LSERDY_BIT 1
#define RCC_BDCR_LSEON_BIT 0
-#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT)
-#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTC_BIT)
+#define RCC_BDCR_BDRST (1U << RCC_BDCR_BDRST_BIT)
+#define RCC_BDCR_RTCEN (1U << RCC_BDCR_RTC_BIT)
#define RCC_BDCR_RTCSEL (0x3 << 8)
#define RCC_BDCR_RTCSEL_NONE (0x0 << 8)
#define RCC_BDCR_RTCSEL_LSE (0x1 << 8)
#define RCC_BDCR_RTCSEL_HSE (0x3 << 8)
-#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT)
-#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT)
-#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT)
+#define RCC_BDCR_LSEBYP (1U << RCC_BDCR_LSEBYP_BIT)
+#define RCC_BDCR_LSERDY (1U << RCC_BDCR_LSERDY_BIT)
+#define RCC_BDCR_LSEON (1U << RCC_BDCR_LSEON_BIT)
/* Control/status register */
@@ -369,136 +373,93 @@ typedef struct rcc_reg_map {
#define RCC_CSR_LSIRDY_BIT 1
#define RCC_CSR_LSION_BIT 0
-#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT)
-#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT)
-#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT)
-#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT)
-#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT)
-#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT)
-#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT)
-#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT)
-#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT)
+#define RCC_CSR_LPWRRSTF (1U << RCC_CSR_LPWRRSTF_BIT)
+#define RCC_CSR_WWDGRSTF (1U << RCC_CSR_WWDGRSTF_BIT)
+#define RCC_CSR_IWDGRSTF (1U << RCC_CSR_IWDGRSTF_BIT)
+#define RCC_CSR_SFTRSTF (1U << RCC_CSR_SFTRSTF_BIT)
+#define RCC_CSR_PORRSTF (1U << RCC_CSR_PORRSTF_BIT)
+#define RCC_CSR_PINRSTF (1U << RCC_CSR_PINRSTF_BIT)
+#define RCC_CSR_RMVF (1U << RCC_CSR_RMVF_BIT)
+#define RCC_CSR_LSIRDY (1U << RCC_CSR_LSIRDY_BIT)
+#define RCC_CSR_LSION (1U << RCC_CSR_LSION_BIT)
/*
- * Convenience routines
- */
-
-/**
- * SYSCLK sources
- * @see rcc_clk_init()
- */
-typedef enum rcc_sysclk_src {
- RCC_CLKSRC_HSI = 0x0,
- RCC_CLKSRC_HSE = 0x1,
- RCC_CLKSRC_PLL = 0x2,
-} rcc_sysclk_src;
-
-/**
- * PLL entry clock source
- * @see rcc_clk_init()
- */
-typedef enum rcc_pllsrc {
- RCC_PLLSRC_HSE = (0x1 << 16),
- RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16)
-} rcc_pllsrc;
-
-/**
- * PLL multipliers
- * @see rcc_clk_init()
+ * libmaple-mandated enumeration types.
*/
-typedef enum rcc_pll_multiplier {
- RCC_PLLMUL_2 = (0x0 << 18),
- RCC_PLLMUL_3 = (0x1 << 18),
- RCC_PLLMUL_4 = (0x2 << 18),
- RCC_PLLMUL_5 = (0x3 << 18),
- RCC_PLLMUL_6 = (0x4 << 18),
- RCC_PLLMUL_7 = (0x5 << 18),
- RCC_PLLMUL_8 = (0x6 << 18),
- RCC_PLLMUL_9 = (0x7 << 18),
- RCC_PLLMUL_10 = (0x8 << 18),
- RCC_PLLMUL_11 = (0x9 << 18),
- RCC_PLLMUL_12 = (0xA << 18),
- RCC_PLLMUL_13 = (0xB << 18),
- RCC_PLLMUL_14 = (0xC << 18),
- RCC_PLLMUL_15 = (0xD << 18),
- RCC_PLLMUL_16 = (0xE << 18),
-} rcc_pll_multiplier;
/**
- * @brief Identifies bus and clock line for a peripheral.
- *
- * Also generally useful as a unique identifier for that peripheral
- * (or its corresponding device struct).
+ * @brief STM32F1 rcc_clk_id.
*/
typedef enum rcc_clk_id {
- RCC_GPIOA,
- RCC_GPIOB,
- RCC_GPIOC,
- RCC_GPIOD,
- RCC_AFIO,
RCC_ADC1,
RCC_ADC2,
RCC_ADC3,
- RCC_USART1,
- RCC_USART2,
- RCC_USART3,
- RCC_TIMER1,
- RCC_TIMER2,
- RCC_TIMER3,
- RCC_TIMER4,
- RCC_SPI1,
- RCC_SPI2,
- RCC_DMA1,
- RCC_PWR,
+ RCC_AFIO,
RCC_BKP,
- RCC_I2C1,
- RCC_I2C2,
RCC_CRC,
+ RCC_DAC,
+ RCC_DMA1,
+ RCC_DMA2,
RCC_FLITF,
- RCC_SRAM,
- RCC_USB,
-#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ RCC_FSMC,
+ RCC_GPIOA,
+ RCC_GPIOB,
+ RCC_GPIOC,
+ RCC_GPIOD,
RCC_GPIOE,
RCC_GPIOF,
RCC_GPIOG,
- RCC_UART4,
- RCC_UART5,
+ RCC_I2C1,
+ RCC_I2C2,
+ RCC_PWR,
+ RCC_SDIO,
+ RCC_SPI1,
+ RCC_SPI2,
+ RCC_SPI3,
+ RCC_SRAM,
+ RCC_TIMER1,
+ RCC_TIMER2,
+ RCC_TIMER3,
+ RCC_TIMER4,
RCC_TIMER5,
RCC_TIMER6,
RCC_TIMER7,
RCC_TIMER8,
- RCC_FSMC,
- RCC_DAC,
- RCC_DMA2,
- RCC_SDIO,
- RCC_SPI3,
-#endif
-#ifdef STM32_XL_DENSITY
RCC_TIMER9,
RCC_TIMER10,
RCC_TIMER11,
RCC_TIMER12,
RCC_TIMER13,
RCC_TIMER14,
-#endif
+ RCC_USART1,
+ RCC_USART2,
+ RCC_USART3,
+ RCC_UART4,
+ RCC_UART5,
+ RCC_USB,
} rcc_clk_id;
-void rcc_clk_init(rcc_sysclk_src sysclk_src,
- rcc_pllsrc pll_src,
- rcc_pll_multiplier pll_mul);
-void rcc_clk_enable(rcc_clk_id device);
-void rcc_reset_dev(rcc_clk_id device);
+/**
+ * @brief STM32F1 PLL clock sources.
+ * @see rcc_configure_pll()
+ */
+typedef enum rcc_pllsrc {
+ RCC_PLLSRC_HSE = (0x1 << 16),
+ RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16)
+} rcc_pllsrc;
+/**
+ * @brief STM32F1 clock domains.
+ * @see rcc_dev_clk()
+ */
typedef enum rcc_clk_domain {
RCC_APB1,
RCC_APB2,
RCC_AHB
} rcc_clk_domain;
-rcc_clk_domain rcc_dev_clk(rcc_clk_id device);
-
/**
- * Prescaler identifiers
+ * @brief STM32F1 Prescaler identifiers
* @see rcc_set_prescaler()
*/
typedef enum rcc_prescaler {
@@ -510,7 +471,7 @@ typedef enum rcc_prescaler {
} rcc_prescaler;
/**
- * ADC prescaler dividers
+ * @brief STM32F1 ADC prescaler dividers
* @see rcc_set_prescaler()
*/
typedef enum rcc_adc_divider {
@@ -521,7 +482,7 @@ typedef enum rcc_adc_divider {
} rcc_adc_divider;
/**
- * APB1 prescaler dividers
+ * @brief STM32F1 APB1 prescaler dividers
* @see rcc_set_prescaler()
*/
typedef enum rcc_apb1_divider {
@@ -533,7 +494,7 @@ typedef enum rcc_apb1_divider {
} rcc_apb1_divider;
/**
- * APB2 prescaler dividers
+ * @brief STM32F1 APB2 prescaler dividers
* @see rcc_set_prescaler()
*/
typedef enum rcc_apb2_divider {
@@ -545,7 +506,7 @@ typedef enum rcc_apb2_divider {
} rcc_apb2_divider;
/**
- * AHB prescaler dividers
+ * @brief STM32F1 AHB prescaler dividers
* @see rcc_set_prescaler()
*/
typedef enum rcc_ahb_divider {
@@ -561,10 +522,78 @@ typedef enum rcc_ahb_divider {
RCC_AHB_SYSCLK_DIV_512 = 0xF << 4,
} rcc_ahb_divider;
-void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider);
+/**
+ * @brief STM32F1 clock sources.
+ */
+typedef enum rcc_clk {
+ RCC_CLK_PLL = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_PLLON_BIT), /**< Main PLL, clocked by
+ HSI or HSE. */
+ RCC_CLK_HSE = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_HSEON_BIT), /**< High speed external. */
+ RCC_CLK_HSI = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_HSION_BIT), /**< High speed internal. */
+ RCC_CLK_LSE = (uint16)((offsetof(struct rcc_reg_map, BDCR) << 8) |
+ RCC_BDCR_LSEON_BIT), /**< Low-speed external
+ * (32.768 KHz). */
+ RCC_CLK_LSI = (uint16)((offsetof(struct rcc_reg_map, CSR) << 8) |
+ RCC_CSR_LSION_BIT), /**< Low-speed internal
+ * (approximately 32 KHz). */
+} rcc_clk;
+
+/**
+ * @brief STM32F1 PLL multipliers.
+ */
+typedef enum rcc_pll_multiplier {
+ RCC_PLLMUL_2 = (0x0 << 18),
+ RCC_PLLMUL_3 = (0x1 << 18),
+ RCC_PLLMUL_4 = (0x2 << 18),
+ RCC_PLLMUL_5 = (0x3 << 18),
+ RCC_PLLMUL_6 = (0x4 << 18),
+ RCC_PLLMUL_7 = (0x5 << 18),
+ RCC_PLLMUL_8 = (0x6 << 18),
+ RCC_PLLMUL_9 = (0x7 << 18),
+ RCC_PLLMUL_10 = (0x8 << 18),
+ RCC_PLLMUL_11 = (0x9 << 18),
+ RCC_PLLMUL_12 = (0xA << 18),
+ RCC_PLLMUL_13 = (0xB << 18),
+ RCC_PLLMUL_14 = (0xC << 18),
+ RCC_PLLMUL_15 = (0xD << 18),
+ RCC_PLLMUL_16 = (0xE << 18),
+} rcc_pll_multiplier;
+
+/* FIXME [0.0.13] Just have data point to an rcc_pll_multiplier! */
+
+/**
+ * @brief STM32F1 PLL configuration values.
+ * Point to one of these with the "data" field in a struct rcc_pll_cfg.
+ * @see struct rcc_pll_cfg.
+ */
+typedef struct stm32f1_rcc_pll_data {
+ rcc_pll_multiplier pll_mul; /**< PLL multiplication factor. */
+} stm32f1_rcc_pll_data;
+
+/*
+ * Deprecated bits.
+ */
+
+/**
+ * @brief Deprecated; STM32F1 only.
+ *
+ * Initialize the clock control system. Initializes the system
+ * clock source to use the PLL driven by an external oscillator.
+ *
+ * @param sysclk_src system clock source, must be PLL
+ * @param pll_src pll clock source, must be HSE
+ * @param pll_mul pll multiplier
+ */
+__deprecated
+void rcc_clk_init(rcc_sysclk_src sysclk_src,
+ rcc_pllsrc pll_src,
+ rcc_pll_multiplier pll_mul);
#ifdef __cplusplus
-} // extern "C"
+}
#endif
#endif
diff --git a/libmaple/stm32f1/include/series/spi.h b/libmaple/stm32f1/include/series/spi.h
new file mode 100644
index 0000000..d288a0c
--- /dev/null
+++ b/libmaple/stm32f1/include/series/spi.h
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 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/spi.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 SPI/I2S series header.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_SPI_H_
+#define _LIBMAPLE_STM32F1_SPI_H_
+
+#include <libmaple/libmaple_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Register map base pointers
+ */
+
+struct spi_reg_map;
+
+#define SPI1_BASE ((struct spi_reg_map*)0x40013000)
+#define SPI2_BASE ((struct spi_reg_map*)0x40003800)
+#define SPI3_BASE ((struct spi_reg_map*)0x40003C00)
+
+/*
+ * Device pointers
+ */
+
+struct spi_dev;
+
+extern struct spi_dev *SPI1;
+extern struct spi_dev *SPI2;
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+extern struct spi_dev *SPI3;
+#endif
+
+/*
+ * Routines
+ */
+
+/* spi_gpio_cfg(): Backwards compatibility shim to spi_config_gpios() */
+struct gpio_dev;
+extern void spi_config_gpios(struct spi_dev*, uint8,
+ struct gpio_dev*, uint8,
+ struct gpio_dev*, uint8, uint8, uint8);
+/**
+ * @brief Deprecated. Use spi_config_gpios() instead.
+ * @see spi_config_gpios()
+ */
+static __always_inline void spi_gpio_cfg(uint8 as_master,
+ struct gpio_dev *nss_dev,
+ uint8 nss_bit,
+ struct gpio_dev *comm_dev,
+ uint8 sck_bit,
+ uint8 miso_bit,
+ uint8 mosi_bit) {
+ /* We switched style globally to foo_config_gpios() and always
+ * taking a foo_dev* argument (that last bit is the important
+ * part) after this function was written.
+ *
+ * However, spi_config_gpios() just ignores the spi_dev* on F1, so
+ * we can still keep this around for older code. */
+ spi_config_gpios(NULL, as_master, nss_dev, nss_bit,
+ comm_dev, sck_bit, miso_bit, mosi_bit);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/stm32.h b/libmaple/stm32f1/include/series/stm32.h
new file mode 100644
index 0000000..f6e96f8
--- /dev/null
+++ b/libmaple/stm32f1/include/series/stm32.h
@@ -0,0 +1,212 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010, 2011 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/stm32f1/include/series/stm32.h
+ * @brief STM32F1 chip- and series-specific definitions.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_H_
+#define _LIBMAPLE_STM32F1_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define STM32_MCU_SERIES STM32_SERIES_F1
+
+/* The STM32F1 series is subdivided into "lines". libmaple currently
+ * officially supports STM32F103 performance line MCUs (see the
+ * MCU-specific value section below).
+ *
+ * You can use these F1 line defines if porting libmaple to support
+ * MCUs on other lines. */
+/** STM32F1 value line (STM32F100 MCUs). */
+#define STM32_F1_LINE_VALUE 0
+/** STM32F1 access line (STM32F101 MCUs). */
+#define STM32_F1_LINE_ACCESS 1
+/** STM32F1 USB access line (STM32F102 MCUs). */
+#define STM32_F1_LINE_USB_ACCESS 2
+/** STM32F1 performance line (STM32F103 MCUs). */
+#define STM32_F1_LINE_PERFORMANCE 3
+/** STM32F1 connectivity line (STM32F105/F107 MCUs). */
+#define STM32_F1_LINE_CONNECTIVITY 5
+
+/*
+ * MCU-specific values.
+ *
+ * You can use this section to override any of the below settings on a
+ * per-MCU basis. For example, if your MCU has different STM32_PCLK1
+ * or STM32_PCLK2 values, you can set them here and the values for
+ * STM32F103 microcontrollers set below won't take effect.
+ */
+
+#if defined(MCU_STM32F103RB)
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+# define STM32_NR_GPIO_PORTS 4
+# define STM32_SRAM_END ((void*)0x20005000)
+# define STM32_MEDIUM_DENSITY
+
+#elif defined(MCU_STM32F103ZE)
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+# define STM32_NR_GPIO_PORTS 7
+# define STM32_SRAM_END ((void*)0x20010000)
+# define STM32_HIGH_DENSITY
+
+#elif defined(MCU_STM32F103CB)
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+ /* This STM32_NR_GPIO_PORTS is not true, but only pins 0 and
+ * exist, and they're used for OSC (e.g. on LeafLabs' Maple Mini),
+ * so we'll live with this for now. */
+# define STM32_NR_GPIO_PORTS 3
+# define STM32_SRAM_END ((void*)0x20005000)
+# define STM32_MEDIUM_DENSITY
+
+#elif defined(MCU_STM32F103RE)
+# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE
+# define STM32_NR_GPIO_PORTS 4
+# define STM32_SRAM_END ((void*)0x20010000)
+# define STM32_HIGH_DENSITY
+
+#elif defined(MCU_STM32F100RB)
+# define STM32_F1_LINE STM32_F1_LINE_VALUE
+# define STM32_NR_GPIO_PORTS 4
+# define STM32_TIMER_MASK 0x380DE /* Timers: 1-4, 6, 7, 15-17. */
+# define STM32_SRAM_END ((void*)0x20002000)
+# define STM32_MEDIUM_DENSITY
+
+#else
+#warning "Unsupported or unspecified STM32F1 MCU."
+#endif
+
+/*
+ * Derived values.
+ */
+
+#if STM32_F1_LINE == STM32_F1_LINE_PERFORMANCE
+ /* All supported performance line MCUs have a USB peripheral */
+# define STM32_HAVE_USB 1
+
+# ifdef STM32_MEDIUM_DENSITY
+# define STM32_NR_INTERRUPTS 43
+# define STM32_TIMER_MASK 0x1E /* TIMER1--TIMER4 */
+# define STM32_HAVE_FSMC 0
+# define STM32_HAVE_DAC 0
+# elif defined(STM32_HIGH_DENSITY)
+# define STM32_NR_INTERRUPTS 60
+# define STM32_TIMER_MASK 0x1FE /* TIMER1--TIMER8 */
+# define STM32_HAVE_FSMC 1
+# define STM32_HAVE_DAC 1
+# elif defined(STM32_XL_DENSITY)
+# define STM32_NR_INTERRUPTS 60
+# define STM32_TIMER_MASK 0x7FFE /* TIMER1--TIMER14 */
+# define STM32_HAVE_FSMC 1
+# define STM32_HAVE_DAC 1
+# endif
+
+#elif STM32_F1_LINE == STM32_F1_LINE_VALUE
+ /* Value line MCUs don't have USB peripherals. */
+# define STM32_HAVE_USB 0
+
+# ifdef STM32_MEDIUM_DENSITY
+# define STM32_NR_INTERRUPTS 56
+# define STM32_HAVE_FSMC 0
+# define STM32_HAVE_DAC 1
+# elif defined(STM32_HIGH_DENSITY)
+ /* 61 interrupts here counts the possibility for a remapped
+ * DMA2 channel 5 IRQ occurring at NVIC index 60. */
+# define STM32_NR_INTERRUPTS 61
+# define STM32_HAVE_FSMC 1
+# define STM32_HAVE_DAC 1
+# endif
+
+#endif
+
+/*
+ * Clock configuration.
+ *
+ * You can patch these for your line, MCU, clock configuration,
+ * etc. here or by setting cflags when compiling libmaple.
+ */
+
+#if STM32_F1_LINE == STM32_F1_LINE_PERFORMANCE
+# ifndef STM32_PCLK1
+# define STM32_PCLK1 36000000U
+# endif
+# ifndef STM32_PCLK2
+# define STM32_PCLK2 72000000U
+# endif
+# ifndef STM32_DELAY_US_MULT
+# define STM32_DELAY_US_MULT 12 /* FIXME: value is incorrect. */
+# endif
+#elif STM32_F1_LINE == STM32_F1_LINE_VALUE /* TODO */
+# ifndef STM32_PCLK1
+# define STM32_PCLK1 12000000U
+# endif
+# ifndef STM32_PCLK2
+# define STM32_PCLK2 24000000U
+# endif
+# ifndef STM32_DELAY_US_MULT
+# define STM32_DELAY_US_MULT 8 /* FIXME: value is incorrect. */
+# endif
+#elif STM32_F1_LINE == STM32_F1_LINE_ACCESS /* TODO */
+#elif STM32_F1_LINE == STM32_F1_LINE_USB_ACCESS /* TODO */
+#elif STM32_F1_LINE == STM32_F1_LINE_CONNECTIVITY /* TODO */
+#endif
+
+/*
+ * Sanity checks.
+ *
+ * Make sure we have the F1-specific defines we need.
+ * <libmaple/stm32.h> will check that we've defined everything it needs.
+ */
+
+#if !defined(STM32_F1_LINE)
+#error "Bad STM32F1 configuration. Check STM32F1 <series/stm32.h> header."
+#endif
+
+/*
+ * Doxygen
+ */
+
+#ifdef __DOXYGEN__
+
+/**
+ * @brief STM32 line value for the STM32F1 MCU being targeted.
+ *
+ * At time of writing, allowed values are: STM32_F1_LINE_PERFORMANCE,
+ * STM32_F1_LINE_VALUE. This set of values may expand as libmaple adds
+ * support for more STM32F1 lines.
+ */
+#define STM32_F1_LINE
+
+#endif /* __DOXYGEN__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/timer.h b/libmaple/stm32f1/include/series/timer.h
new file mode 100644
index 0000000..cfeb770
--- /dev/null
+++ b/libmaple/stm32f1/include/series/timer.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ * 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/stm32f1/include/series/timer.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 timer support.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_TIMER_H_
+#define _LIBMAPLE_STM32F1_TIMER_H_
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register maps and base pointers
+ */
+
+/** STM32F1 general purpose timer register map type */
+typedef struct timer_gen_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SMCR; /**< Slave mode control register */
+ __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ __io uint32 CCMR1; /**< Capture/compare mode register 1 */
+ __io uint32 CCMR2; /**< Capture/compare mode register 2 */
+ __io uint32 CCER; /**< Capture/compare enable register */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 CCR1; /**< Capture/compare register 1 */
+ __io uint32 CCR2; /**< Capture/compare register 2 */
+ __io uint32 CCR3; /**< Capture/compare register 3 */
+ __io uint32 CCR4; /**< Capture/compare register 4 */
+ const uint32 RESERVED2; /**< Reserved */
+ __io uint32 DCR; /**< DMA control register */
+ __io uint32 DMAR; /**< DMA address for full transfer */
+} timer_gen_reg_map;
+
+struct timer_adv_reg_map;
+struct timer_bas_reg_map;
+
+/** Timer 1 register map base pointer */
+#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00)
+/** Timer 2 register map base pointer */
+#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000)
+/** Timer 3 register map base pointer */
+#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400)
+/** Timer 4 register map base pointer */
+#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800)
+/** Timer 5 register map base pointer */
+#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00)
+/** Timer 6 register map base pointer */
+#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000)
+/** Timer 7 register map base pointer */
+#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400)
+/** Timer 8 register map base pointer */
+#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400)
+/** Timer 9 register map base pointer */
+#define TIMER9_BASE ((struct timer_gen_reg_map*)0x40014C00)
+/** Timer 10 register map base pointer */
+#define TIMER10_BASE ((struct timer_gen_reg_map*)0x40015000)
+/** Timer 11 register map base pointer */
+#define TIMER11_BASE ((struct timer_gen_reg_map*)0x40015400)
+/** Timer 12 register map base pointer */
+#define TIMER12_BASE ((struct timer_gen_reg_map*)0x40001800)
+/** Timer 13 register map base pointer */
+#define TIMER13_BASE ((struct timer_gen_reg_map*)0x40001C00)
+/** Timer 14 register map base pointer */
+#define TIMER14_BASE ((struct timer_gen_reg_map*)0x40002000)
+
+/*
+ * Device pointers
+ *
+ * We only declare device pointers to timers which actually exist on
+ * the target MCU. This helps when porting programs to STM32F1 (or
+ * within F1 to a lower density MCU), as attempts to use nonexistent
+ * timers cause build errors instead of undefined behavior.
+ */
+
+struct timer_dev;
+
+extern struct timer_dev *TIMER1;
+extern struct timer_dev *TIMER2;
+extern struct timer_dev *TIMER3;
+extern struct timer_dev *TIMER4;
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+extern struct timer_dev *TIMER5;
+extern struct timer_dev *TIMER6;
+extern struct timer_dev *TIMER7;
+extern struct timer_dev *TIMER8;
+#endif
+#ifdef STM32_XL_DENSITY
+extern struct timer_dev *TIMER9;
+extern struct timer_dev *TIMER10;
+extern struct timer_dev *TIMER11;
+extern struct timer_dev *TIMER12;
+extern struct timer_dev *TIMER13;
+extern struct timer_dev *TIMER14;
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/include/series/usart.h b/libmaple/stm32f1/include/series/usart.h
new file mode 100644
index 0000000..d12a3e2
--- /dev/null
+++ b/libmaple/stm32f1/include/series/usart.h
@@ -0,0 +1,76 @@
+/******************************************************************************
+ * 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/stm32f1/include/series/usart.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 USART support.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_USART_H_
+#define _LIBMAPLE_STM32F1_USART_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/*
+ * Register map base pointers
+ */
+
+struct usart_reg_map;
+
+/** USART1 register map base pointer */
+#define USART1_BASE ((struct usart_reg_map*)0x40013800)
+/** USART2 register map base pointer */
+#define USART2_BASE ((struct usart_reg_map*)0x40004400)
+/** USART3 register map base pointer */
+#define USART3_BASE ((struct usart_reg_map*)0x40004800)
+#ifdef STM32_HIGH_DENSITY
+/** UART4 register map base pointer */
+#define UART4_BASE ((struct usart_reg_map*)0x40004C00)
+/** UART5 register map base pointer */
+#define UART5_BASE ((struct usart_reg_map*)0x40005000)
+#endif
+
+/*
+ * Devices
+ */
+
+struct usart_dev;
+extern struct usart_dev *USART1;
+extern struct usart_dev *USART2;
+extern struct usart_dev *USART3;
+#ifdef STM32_HIGH_DENSITY
+extern struct usart_dev *UART4;
+extern struct usart_dev *UART5;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f1/isrs_performance.S b/libmaple/stm32f1/performance/isrs.S
index be102e7..a8f0709 100644
--- a/libmaple/stm32f1/isrs_performance.S
+++ b/libmaple/stm32f1/performance/isrs.S
@@ -1,4 +1,30 @@
-/* STM32 ISR weak declarations */
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/* STM32F1 performance line ISR weak declarations */
.thumb
diff --git a/libmaple/stm32f1/vector_table_performance.S b/libmaple/stm32f1/performance/vector_table.S
index 0392a02..b489b94 100644
--- a/libmaple/stm32f1/vector_table_performance.S
+++ b/libmaple/stm32f1/performance/vector_table.S
@@ -1,4 +1,30 @@
-/* STM32 vector table */
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/* STM32F1 performance line vector table */
.section ".stm32.interrupt_vector"
diff --git a/libmaple/stm32f1/rcc.c b/libmaple/stm32f1/rcc.c
new file mode 100644
index 0000000..8d71a41
--- /dev/null
+++ b/libmaple/stm32f1/rcc.c
@@ -0,0 +1,164 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Perry Hung.
+ * Copyright (c) 2011 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/stm32f1/rcc.c
+ * @brief STM32F1 RCC.
+ */
+
+#include <libmaple/rcc.h>
+#include <libmaple/libmaple.h>
+#include <libmaple/bitband.h>
+
+#include "rcc_private.h"
+
+#define APB1 RCC_APB1
+#define APB2 RCC_APB2
+#define AHB RCC_AHB
+
+/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset
+ * register bit numbers. */
+const struct rcc_dev_info rcc_dev_table[] = {
+ [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 },
+ [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 },
+ [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 },
+ [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 },
+ [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 },
+ [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 },
+ [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 },
+ [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 },
+ [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 },
+ [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 },
+ [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 },
+ [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 },
+ [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 },
+ [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 },
+ [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 },
+ [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 },
+ [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 },
+ [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 },
+ [RCC_PWR] = { .clk_domain = APB1, .line_num = 28},
+ [RCC_BKP] = { .clk_domain = APB1, .line_num = 27},
+ [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 },
+ [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 },
+ [RCC_CRC] = { .clk_domain = AHB, .line_num = 6},
+ [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4},
+ [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2},
+ [RCC_USB] = { .clk_domain = APB1, .line_num = 23},
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 },
+ [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 },
+ [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 },
+ [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 },
+ [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 },
+ [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 },
+ [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 },
+ [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 },
+ [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 },
+ [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 },
+ [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 },
+ [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 },
+ [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 },
+ [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 },
+#endif
+#ifdef STM32_XL_DENSITY
+ [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 },
+ [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 },
+ [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 },
+ [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 },
+ [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 },
+ [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 },
+#endif
+};
+
+__deprecated
+void rcc_clk_init(rcc_sysclk_src sysclk_src,
+ rcc_pllsrc pll_src,
+ rcc_pll_multiplier pll_mul) {
+ /* Assume that we're going to clock the chip off the PLL, fed by
+ * the HSE */
+ ASSERT(sysclk_src == RCC_CLKSRC_PLL &&
+ pll_src == RCC_PLLSRC_HSE);
+
+ RCC_BASE->CFGR = pll_src | pll_mul;
+
+ /* Turn on, and wait for, HSE. */
+ rcc_turn_on_clk(RCC_CLK_HSE);
+ while (!rcc_is_clk_ready(RCC_CLK_HSE))
+ ;
+
+ /* Do the same for the main PLL. */
+ rcc_turn_on_clk(RCC_CLK_PLL);
+ while(!rcc_is_clk_ready(RCC_CLK_PLL))
+ ;
+
+ /* Finally, switch over to the PLL. */
+ rcc_switch_sysclk(RCC_CLKSRC_PLL);
+}
+
+/* pll_cfg->data must point to a valid struct stm32f1_rcc_pll_data. */
+void rcc_configure_pll(rcc_pll_cfg *pll_cfg) {
+ stm32f1_rcc_pll_data *data = pll_cfg->data;
+ rcc_pll_multiplier pll_mul = data->pll_mul;
+ uint32 cfgr;
+
+ /* Check that the PLL is disabled. */
+ ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL));
+
+ cfgr = RCC_BASE->CFGR;
+ cfgr &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL);
+ cfgr |= pll_cfg->pllsrc | pll_mul;
+ RCC_BASE->CFGR = cfgr;
+}
+
+void rcc_clk_enable(rcc_clk_id id) {
+ static __io uint32* enable_regs[] = {
+ [APB1] = &RCC_BASE->APB1ENR,
+ [APB2] = &RCC_BASE->APB2ENR,
+ [AHB] = &RCC_BASE->AHBENR,
+ };
+ rcc_do_clk_enable(enable_regs, id);
+}
+
+void rcc_reset_dev(rcc_clk_id id) {
+ static __io uint32* reset_regs[] = {
+ [APB1] = &RCC_BASE->APB1RSTR,
+ [APB2] = &RCC_BASE->APB2RSTR,
+ };
+ rcc_do_reset_dev(reset_regs, id);
+}
+
+void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) {
+ static const uint32 masks[] = {
+ [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE,
+ [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1,
+ [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2,
+ [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE,
+ [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE,
+ };
+ rcc_do_set_prescaler(masks, prescaler, divider);
+}
diff --git a/libmaple/stm32f1/rules.mk b/libmaple/stm32f1/rules.mk
index 5cadefd..3ca0813 100644
--- a/libmaple/stm32f1/rules.mk
+++ b/libmaple/stm32f1/rules.mk
@@ -4,16 +4,37 @@ dirstack_$(sp) := $(d)
d := $(dir)
BUILDDIRS += $(BUILD_PATH)/$(d)
+# Local flags
+CFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror
+
+# Extra BUILDDIRS
+BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_F1_LINE)
+
# Local rules and targets
-sSRCS_$(d) := isrs_performance.S \
- vector_table_performance.S
+sSRCS_$(d) := $(MCU_F1_LINE)/isrs.S
+sSRCS_$(d) += $(MCU_F1_LINE)/vector_table.S
+
+cSRCS_$(d) := adc.c
+cSRCS_$(d) += bkp.c
+cSRCS_$(d) += dma.c
+cSRCS_$(d) += exti.c
+cSRCS_$(d) += fsmc.c
+cSRCS_$(d) += gpio.c
+cSRCS_$(d) += i2c.c
+cSRCS_$(d) += rcc.c
+cSRCS_$(d) += spi.c
+cSRCS_$(d) += timer.c
+cSRCS_$(d) += usart.c
sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
-OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o)
+OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
+ $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o)
DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
$(OBJS_$(d)): TGT_ASFLAGS :=
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
TGT_BIN += $(OBJS_$(d))
diff --git a/libmaple/stm32f1/spi.c b/libmaple/stm32f1/spi.c
new file mode 100644
index 0000000..1c78cc3
--- /dev/null
+++ b/libmaple/stm32f1/spi.c
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 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/spi.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 SPI/I2S.
+ */
+
+#include <libmaple/spi.h>
+#include <libmaple/gpio.h>
+#include "spi_private.h"
+
+/*
+ * Devices
+ */
+
+static spi_dev spi1 = SPI_DEV(1);
+static spi_dev spi2 = SPI_DEV(2);
+
+spi_dev *SPI1 = &spi1;
+spi_dev *SPI2 = &spi2;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static spi_dev spi3 = SPI_DEV(3);
+spi_dev *SPI3 = &spi3;
+#endif
+
+/*
+ * Routines
+ */
+
+void spi_config_gpios(spi_dev *ignored,
+ uint8 as_master,
+ gpio_dev *nss_dev,
+ uint8 nss_bit,
+ gpio_dev *comm_dev,
+ uint8 sck_bit,
+ uint8 miso_bit,
+ uint8 mosi_bit) {
+ if (as_master) {
+ gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING);
+ gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP);
+ } else {
+ gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING);
+ gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING);
+ gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP);
+ gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING);
+ }
+}
+
+void spi_foreach(void (*fn)(spi_dev*)) {
+ fn(SPI1);
+ fn(SPI2);
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ fn(SPI3);
+#endif
+}
diff --git a/libmaple/stm32f1/timer.c b/libmaple/stm32f1/timer.c
new file mode 100644
index 0000000..8b9e976
--- /dev/null
+++ b/libmaple/stm32f1/timer.c
@@ -0,0 +1,124 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 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/stm32f1/timer.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 timer.
+ */
+
+#include <libmaple/timer.h>
+#include <libmaple/stm32.h>
+#include "timer_private.h"
+
+/*
+ * IRQ handlers
+ *
+ * Defer to the timer_private dispatch API.
+ *
+ * FIXME: The names of these handlers are inaccurate since XL-density
+ * devices came out. Update these to match the STM32F2 names, maybe
+ * using some weak symbol magic to preserve backwards compatibility if
+ * possible. Once that's done, we can just move the IRQ handlers into
+ * the top-level libmaple/timer.c, and there will be no need for this
+ * file.
+ */
+
+void __irq_tim1_brk(void) {
+ dispatch_adv_brk(TIMER1);
+#if STM32_HAVE_TIMER(9)
+ dispatch_tim_9_12(TIMER9);
+#endif
+}
+
+void __irq_tim1_up(void) {
+ dispatch_adv_up(TIMER1);
+#if STM32_HAVE_TIMER(10)
+ dispatch_tim_10_11_13_14(TIMER10);
+#endif
+}
+
+void __irq_tim1_trg_com(void) {
+ dispatch_adv_trg_com(TIMER1);
+#if STM32_HAVE_TIMER(11)
+ dispatch_tim_10_11_13_14(TIMER11);
+#endif
+}
+
+void __irq_tim1_cc(void) {
+ dispatch_adv_cc(TIMER1);
+}
+
+void __irq_tim2(void) {
+ dispatch_general(TIMER2);
+}
+
+void __irq_tim3(void) {
+ dispatch_general(TIMER3);
+}
+
+void __irq_tim4(void) {
+ dispatch_general(TIMER4);
+}
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+void __irq_tim5(void) {
+ dispatch_general(TIMER5);
+}
+
+void __irq_tim6(void) {
+ dispatch_basic(TIMER6);
+}
+
+void __irq_tim7(void) {
+ dispatch_basic(TIMER7);
+}
+
+void __irq_tim8_brk(void) {
+ dispatch_adv_brk(TIMER8);
+#if STM32_HAVE_TIMER(12)
+ dispatch_tim_9_12(TIMER12);
+#endif
+}
+
+void __irq_tim8_up(void) {
+ dispatch_adv_up(TIMER8);
+#if STM32_HAVE_TIMER(13)
+ dispatch_tim_10_11_13_14(TIMER13);
+#endif
+}
+
+void __irq_tim8_trg_com(void) {
+ dispatch_adv_trg_com(TIMER8);
+#if STM32_HAVE_TIMER(14)
+ dispatch_tim_10_11_13_14(TIMER14);
+#endif
+}
+
+void __irq_tim8_cc(void) {
+ dispatch_adv_cc(TIMER8);
+}
+#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */
diff --git a/libmaple/stm32f1/usart.c b/libmaple/stm32f1/usart.c
new file mode 100644
index 0000000..b3b849f
--- /dev/null
+++ b/libmaple/stm32f1/usart.c
@@ -0,0 +1,170 @@
+/******************************************************************************
+ * 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/usart.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief STM32F1 USART.
+ */
+
+#include <libmaple/usart.h>
+#include <libmaple/gpio.h>
+#include "usart_private.h"
+
+/*
+ * Devices
+ */
+
+static ring_buffer usart1_rb;
+static usart_dev usart1 = {
+ .regs = USART1_BASE,
+ .rb = &usart1_rb,
+ .max_baud = 4500000UL,
+ .clk_id = RCC_USART1,
+ .irq_num = NVIC_USART1,
+};
+/** USART1 device */
+usart_dev *USART1 = &usart1;
+
+static ring_buffer usart2_rb;
+static usart_dev usart2 = {
+ .regs = USART2_BASE,
+ .rb = &usart2_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_USART2,
+ .irq_num = NVIC_USART2,
+};
+/** USART2 device */
+usart_dev *USART2 = &usart2;
+
+static ring_buffer usart3_rb;
+static usart_dev usart3 = {
+ .regs = USART3_BASE,
+ .rb = &usart3_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_USART3,
+ .irq_num = NVIC_USART3,
+};
+/** USART3 device */
+usart_dev *USART3 = &usart3;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static ring_buffer uart4_rb;
+static usart_dev uart4 = {
+ .regs = UART4_BASE,
+ .rb = &uart4_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_UART4,
+ .irq_num = NVIC_UART4,
+};
+/** UART4 device */
+usart_dev *UART4 = &uart4;
+
+static ring_buffer uart5_rb;
+static usart_dev uart5 = {
+ .regs = UART5_BASE,
+ .rb = &uart5_rb,
+ .max_baud = 2250000UL,
+ .clk_id = RCC_UART5,
+ .irq_num = NVIC_UART5,
+};
+/** UART5 device */
+usart_dev *UART5 = &uart5;
+#endif
+
+/*
+ * Routines
+ */
+
+void usart_config_gpios_async(usart_dev *udev,
+ gpio_dev *rx_dev, uint8 rx,
+ gpio_dev *tx_dev, uint8 tx,
+ unsigned flags) {
+ gpio_set_mode(rx_dev, rx, GPIO_INPUT_FLOATING);
+ gpio_set_mode(tx_dev, tx, GPIO_AF_OUTPUT_PP);
+}
+
+void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) {
+ uint32 integer_part;
+ uint32 fractional_part;
+ uint32 tmp;
+
+ /* Figure out the clock speed, if the user doesn't give one. */
+ if (clock_speed == 0) {
+ clock_speed = _usart_clock_freq(dev);
+ }
+ ASSERT(clock_speed);
+
+ /* Convert desired baud rate to baud rate register setting. */
+ integer_part = (25 * clock_speed) / (4 * baud);
+ tmp = (integer_part / 100) << 4;
+ fractional_part = integer_part - (100 * (tmp >> 4));
+ tmp |= (((fractional_part * 16) + 50) / 100) & ((uint8)0x0F);
+
+ dev->regs->BRR = (uint16)tmp;
+}
+
+/**
+ * @brief Call a function on each USART.
+ * @param fn Function to call.
+ */
+void usart_foreach(void (*fn)(usart_dev*)) {
+ fn(USART1);
+ fn(USART2);
+ fn(USART3);
+#ifdef STM32_HIGH_DENSITY
+ fn(UART4);
+ fn(UART5);
+#endif
+}
+
+/*
+ * Interrupt handlers.
+ */
+
+void __irq_usart1(void) {
+ usart_irq(&usart1_rb, USART1_BASE);
+}
+
+void __irq_usart2(void) {
+ usart_irq(&usart2_rb, USART2_BASE);
+}
+
+void __irq_usart3(void) {
+ usart_irq(&usart3_rb, USART3_BASE);
+}
+
+#ifdef STM32_HIGH_DENSITY
+void __irq_uart4(void) {
+ usart_irq(&uart4_rb, UART4_BASE);
+}
+
+void __irq_uart5(void) {
+ usart_irq(&uart5_rb, UART5_BASE);
+}
+#endif
diff --git a/libmaple/stm32f1/value/isrs.S b/libmaple/stm32f1/value/isrs.S
new file mode 100644
index 0000000..858016b
--- /dev/null
+++ b/libmaple/stm32f1/value/isrs.S
@@ -0,0 +1,270 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 Perry Hung.
+ * 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.
+ *****************************************************************************/
+
+/* STM32F1 value line ISR weak declarations */
+
+ .thumb
+
+/* Default handler for all non-overridden interrupts and exceptions */
+ .globl __default_handler
+ .type __default_handler, %function
+
+__default_handler:
+ b .
+
+ .weak __msp_init
+ .globl __msp_init
+ .set __msp_init, __default_handler
+ .weak __exc_reset
+ .globl __exc_reset
+ .set __exc_reset, __default_handler
+ .weak __exc_nmi
+ .globl __exc_nmi
+ .set __exc_nmi, __default_handler
+ .weak __exc_hardfault
+ .globl __exc_hardfault
+ .set __exc_hardfault, __default_handler
+ .weak __exc_memmanage
+ .globl __exc_memmanage
+ .set __exc_memmanage, __default_handler
+ .weak __exc_busfault
+ .globl __exc_busfault
+ .set __exc_busfault, __default_handler
+ .weak __exc_usagefault
+ .globl __exc_usagefault
+ .set __exc_usagefault, __default_handler
+ .weak __stm32reservedexception7
+ .globl __stm32reservedexception7
+ .set __stm32reservedexception7, __default_handler
+ .weak __stm32reservedexception8
+ .globl __stm32reservedexception8
+ .set __stm32reservedexception8, __default_handler
+ .weak __stm32reservedexception9
+ .globl __stm32reservedexception9
+ .set __stm32reservedexception9, __default_handler
+ .weak __stm32reservedexception10
+ .globl __stm32reservedexception10
+ .set __stm32reservedexception10, __default_handler
+ .weak __exc_svc
+ .globl __exc_svc
+ .set __exc_svc, __default_handler
+ .weak __exc_debug_monitor
+ .globl __exc_debug_monitor
+ .set __exc_debug_monitor, __default_handler
+ .weak __stm32reservedexception13
+ .globl __stm32reservedexception13
+ .set __stm32reservedexception13, __default_handler
+ .weak __exc_pendsv
+ .globl __exc_pendsv
+ .set __exc_pendsv, __default_handler
+ .weak __exc_systick
+ .globl __exc_systick
+ .set __exc_systick, __default_handler
+
+ .weak __irq_wwdg
+ .globl __irq_wwdg
+ .set __irq_wwdg, __default_handler
+ .weak __irq_pvd
+ .globl __irq_pvd
+ .set __irq_pvd, __default_handler
+ .weak __irq_tamper
+ .globl __irq_tamper
+ .set __irq_tamper, __default_handler
+ .weak __irq_rtc
+ .globl __irq_rtc
+ .set __irq_rtc, __default_handler
+ .weak __irq_flash
+ .globl __irq_flash
+ .set __irq_flash, __default_handler
+ .weak __irq_rcc
+ .globl __irq_rcc
+ .set __irq_rcc, __default_handler
+ .weak __irq_exti0
+ .globl __irq_exti0
+ .set __irq_exti0, __default_handler
+ .weak __irq_exti1
+ .globl __irq_exti1
+ .set __irq_exti1, __default_handler
+ .weak __irq_exti2
+ .globl __irq_exti2
+ .set __irq_exti2, __default_handler
+ .weak __irq_exti3
+ .globl __irq_exti3
+ .set __irq_exti3, __default_handler
+ .weak __irq_exti4
+ .globl __irq_exti4
+ .set __irq_exti4, __default_handler
+ .weak __irq_dma1_channel1
+ .globl __irq_dma1_channel1
+ .set __irq_dma1_channel1, __default_handler
+ .weak __irq_dma1_channel2
+ .globl __irq_dma1_channel2
+ .set __irq_dma1_channel2, __default_handler
+ .weak __irq_dma1_channel3
+ .globl __irq_dma1_channel3
+ .set __irq_dma1_channel3, __default_handler
+ .weak __irq_dma1_channel4
+ .globl __irq_dma1_channel4
+ .set __irq_dma1_channel4, __default_handler
+ .weak __irq_dma1_channel5
+ .globl __irq_dma1_channel5
+ .set __irq_dma1_channel5, __default_handler
+ .weak __irq_dma1_channel6
+ .globl __irq_dma1_channel6
+ .set __irq_dma1_channel6, __default_handler
+ .weak __irq_dma1_channel7
+ .globl __irq_dma1_channel7
+ .set __irq_dma1_channel7, __default_handler
+ .weak __irq_adc1
+ .globl __irq_adc1
+ .set __irq_adc1, __default_handler
+ .weak __stm32reservedexception14
+ .globl __stm32reservedexception14
+ .set __stm32reservedexception14, __default_handler
+ .weak __stm32reservedexception15
+ .globl __stm32reservedexception15
+ .set __stm32reservedexception15, __default_handler
+ .weak __stm32reservedexception16
+ .globl __stm32reservedexception16
+ .set __stm32reservedexception16, __default_handler
+ .weak __stm32reservedexception17
+ .globl __stm32reservedexception17
+ .set __stm32reservedexception17, __default_handler
+ .weak __irq_exti9_5
+ .globl __irq_exti9_5
+ .set __irq_exti9_5, __default_handler
+ .weak __irq_tim1_brk
+ .globl __irq_tim1_brk
+ .set __irq_tim1_brk, __default_handler
+ .weak __irq_tim1_up
+ .globl __irq_tim1_up
+ .set __irq_tim1_up, __default_handler
+ .weak __irq_tim1_trg_com
+ .globl __irq_tim1_trg_com
+ .set __irq_tim1_trg_com, __default_handler
+ .weak __irq_tim1_cc
+ .globl __irq_tim1_cc
+ .set __irq_tim1_cc, __default_handler
+ .weak __irq_tim2
+ .globl __irq_tim2
+ .set __irq_tim2, __default_handler
+ .weak __irq_tim3
+ .globl __irq_tim3
+ .set __irq_tim3, __default_handler
+ .weak __irq_tim4
+ .globl __irq_tim4
+ .set __irq_tim4, __default_handler
+ .weak __irq_i2c1_ev
+ .globl __irq_i2c1_ev
+ .set __irq_i2c1_ev, __default_handler
+ .weak __irq_i2c1_er
+ .globl __irq_i2c1_er
+ .set __irq_i2c1_er, __default_handler
+ .weak __irq_i2c2_ev
+ .globl __irq_i2c2_ev
+ .set __irq_i2c2_ev, __default_handler
+ .weak __irq_i2c2_er
+ .globl __irq_i2c2_er
+ .set __irq_i2c2_er, __default_handler
+ .weak __irq_spi1
+ .globl __irq_spi1
+ .set __irq_spi1, __default_handler
+ .weak __irq_spi2
+ .globl __irq_spi2
+ .set __irq_spi2, __default_handler
+ .weak __irq_usart1
+ .globl __irq_usart1
+ .set __irq_usart1, __default_handler
+ .weak __irq_usart2
+ .globl __irq_usart2
+ .set __irq_usart2, __default_handler
+ .weak __irq_usart3
+ .globl __irq_usart3
+ .set __irq_usart3, __default_handler
+ .weak __irq_exti15_10
+ .globl __irq_exti15_10
+ .set __irq_exti15_10, __default_handler
+ .weak __irq_rtcalarm
+ .globl __irq_rtcalarm
+ .set __irq_rtcalarm, __default_handler
+ .weak __irq_cec
+ .globl __irq_cec
+ .set __irq_cec, __default_handler
+ .weak __irq_tim12
+ .globl __irq_tim12
+ .set __irq_tim12, __default_handler
+ .weak __irq_tim13
+ .globl __irq_tim13
+ .set __irq_tim13, __default_handler
+ .weak __irq_tim14
+ .globl __irq_tim14
+ .set __irq_tim14, __default_handler
+ .weak __stm32reservedexception18
+ .globl __stm32reservedexception18
+ .set __stm32reservedexception18, __default_handler
+ .weak __stm32reservedexception19
+ .globl __stm32reservedexception19
+ .set __stm32reservedexception19, __default_handler
+ .weak __irq_fsmc
+ .globl __irq_fsmc
+ .set __irq_fsmc, __default_handler
+ .weak __stm32reservedexception20
+ .globl __stm32reservedexception20
+ .set __stm32reservedexception20, __default_handler
+ .weak __irq_tim5
+ .globl __irq_tim5
+ .set __irq_tim5, __default_handler
+ .weak __irq_spi3
+ .globl __irq_spi3
+ .set __irq_spi3, __default_handler
+ .weak __irq_uart4
+ .globl __irq_uart4
+ .set __irq_uart4, __default_handler
+ .weak __irq_uart5
+ .globl __irq_uart5
+ .set __irq_uart5, __default_handler
+ .weak __irq_tim6
+ .globl __irq_tim6
+ .set __irq_tim6, __default_handler
+ .weak __irq_tim7
+ .globl __irq_tim7
+ .set __irq_tim7, __default_handler
+ .weak __irq_dma2_channel1
+ .globl __irq_dma2_channel1
+ .set __irq_dma2_channel1, __default_handler
+ .weak __irq_dma2_channel2
+ .globl __irq_dma2_channel2
+ .set __irq_dma2_channel2, __default_handler
+ .weak __irq_dma2_channel3
+ .globl __irq_dma2_channel3
+ .set __irq_dma2_channel3, __default_handler
+ .weak __irq_dma2_channel4_5
+ .globl __irq_dma2_channel4_5
+ .set __irq_dma2_channel4_5, __default_handler
+ .weak __irq_dma2_channel5 /* on remap only */
+ .globl __irq_dma2_channel5
+ .set __irq_dma2_channel5, __default_handler
diff --git a/libmaple/stm32f1/value/vector_table.S b/libmaple/stm32f1/value/vector_table.S
new file mode 100644
index 0000000..76a2a6e
--- /dev/null
+++ b/libmaple/stm32f1/value/vector_table.S
@@ -0,0 +1,116 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 Perry Hung.
+ * 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.
+ *****************************************************************************/
+
+/* STM32F1 value line vector table */
+
+ .section ".stm32.interrupt_vector"
+
+ .globl __stm32_vector_table
+ .type __stm32_vector_table, %object
+
+__stm32_vector_table:
+/* CM3 core interrupts */
+ .long __msp_init
+ .long __exc_reset
+ .long __exc_nmi
+ .long __exc_hardfault
+ .long __exc_memmanage
+ .long __exc_busfault
+ .long __exc_usagefault
+ .long __stm32reservedexception7
+ .long __stm32reservedexception8
+ .long __stm32reservedexception9
+ .long __stm32reservedexception10
+ .long __exc_svc
+ .long __exc_debug_monitor
+ .long __stm32reservedexception13
+ .long __exc_pendsv
+ .long __exc_systick
+/* Peripheral interrupts */
+ .long __irq_wwdg
+ .long __irq_pvd
+ .long __irq_tamper
+ .long __irq_rtc
+ .long __irq_flash
+ .long __irq_rcc
+ .long __irq_exti0
+ .long __irq_exti1
+ .long __irq_exti2
+ .long __irq_exti3
+ .long __irq_exti4
+ .long __irq_dma1_channel1
+ .long __irq_dma1_channel2
+ .long __irq_dma1_channel3
+ .long __irq_dma1_channel4
+ .long __irq_dma1_channel5
+ .long __irq_dma1_channel6
+ .long __irq_dma1_channel7
+ .long __irq_adc1
+ .long __stm32reservedexception14
+ .long __stm32reservedexception15
+ .long __stm32reservedexception16
+ .long __stm32reservedexception17
+ .long __irq_exti9_5
+ .long __irq_tim1_brk
+ .long __irq_tim1_up
+ .long __irq_tim1_trg_com
+ .long __irq_tim1_cc
+ .long __irq_tim2
+ .long __irq_tim3
+ .long __irq_tim4
+ .long __irq_i2c1_ev
+ .long __irq_i2c1_er
+ .long __irq_i2c2_ev
+ .long __irq_i2c2_er
+ .long __irq_spi1
+ .long __irq_spi2
+ .long __irq_usart1
+ .long __irq_usart2
+ .long __irq_usart3
+ .long __irq_exti15_10
+ .long __irq_rtcalarm
+ .long __irq_cec
+ .long __irq_tim12
+ .long __irq_tim13
+ .long __irq_tim14
+ .long __stm32reservedexception18
+ .long __stm32reservedexception19
+ .long __irq_fsmc
+ .long __stm32reservedexception20
+ .long __irq_tim5
+ .long __irq_spi3
+ .long __irq_uart4
+ .long __irq_uart5
+ .long __irq_tim6
+ .long __irq_tim7
+ .long __irq_dma2_channel1
+ .long __irq_dma2_channel2
+ .long __irq_dma2_channel3
+ .long __irq_dma2_channel4_5
+ .long __irq_dma2_channel5 /* on remap only */
+
+ .size __stm32_vector_table, . - __stm32_vector_table
diff --git a/libmaple/stm32f2/adc.c b/libmaple/stm32f2/adc.c
new file mode 100644
index 0000000..a400d7b
--- /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/adc.c
+ * @brief STM32F2 ADC.
+ */
+
+#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;
+
+static 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_config_gpio(const adc_dev *ignored, 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/dma.c b/libmaple/stm32f2/dma.c
new file mode 100644
index 0000000..26e87b9
--- /dev/null
+++ b/libmaple/stm32f2/dma.c
@@ -0,0 +1,504 @@
+/******************************************************************************
+ * 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/dma.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 DMA support.
+ */
+
+#include <libmaple/dma.h>
+#include <libmaple/bitband.h>
+#include <libmaple/util.h>
+
+/* Hack to ensure inlining in dma_irq_handler() */
+#define DMA_GET_HANDLER(dev, tube) (dev->handlers[tube].handler)
+#include "dma_private.h"
+
+/*
+ * Devices
+ */
+
+static dma_dev dma1 = {
+ .regs = DMA1_BASE,
+ .clk_id = RCC_DMA1,
+ .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA1_STREAM0 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM1 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM2 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM3 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM4 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM5 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM6 },
+ { .handler = NULL, .irq_line = NVIC_DMA1_STREAM7 }},
+};
+dma_dev *DMA1 = &dma1;
+
+static dma_dev dma2 = {
+ .regs = DMA2_BASE,
+ .clk_id = RCC_DMA2,
+ .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_STREAM0 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM1 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM2 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM3 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM4 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM5 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM6 },
+ { .handler = NULL, .irq_line = NVIC_DMA2_STREAM7 }},
+};
+dma_dev *DMA2 = &dma2;
+
+/*
+ * Helpers for dealing with dma_request_src's bit encoding (see the
+ * comments in the dma_request_src definition).
+ */
+
+/* rcc_clk_id of dma_dev which supports src. */
+static __always_inline rcc_clk_id src_clk_id(dma_request_src src) {
+ return (rcc_clk_id)(((uint32)src >> 3) & 0x3F);
+}
+
+/* Bit vector of streams supporting src (e.g., bit 0 set => DMA_S0 support). */
+static __always_inline uint32 src_stream_mask(dma_request_src src) {
+ return ((uint32)src >> 10) & 0xFF;
+}
+
+/* Channel corresponding to src. */
+static __always_inline dma_channel src_channel(dma_request_src src) {
+ return (dma_channel)(src & 0x7);
+}
+
+/*
+ * Routines
+ */
+
+/* For convenience */
+#define ASSERT_NOT_ENABLED(dev, tube) ASSERT(!dma_is_enabled(dev, tube))
+
+/* Helpers for dma_tube_cfg() */
+static int preconfig_check(dma_dev *dev, dma_tube tube, dma_tube_config *cfg);
+static int postconfig_check(dma_tube_reg_map *dummy, dma_tube_config *cfg);
+static int config_fifo(dma_tube_reg_map *dummy, dma_tube_config *cfg);
+static int config_src_dst(dma_tube_reg_map *dummy, dma_tube_config *cfg);
+static void copy_regs(dma_tube_reg_map *src, dma_tube_reg_map *dst);
+
+int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg) {
+ dma_tube_reg_map dummy_regs;
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ int ret;
+
+ /* Initial error checking. */
+ ret = preconfig_check(dev, tube, cfg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Disable `tube' as per RM0033. */
+ dma_disable(dev, tube);
+ dma_clear_isr_bits(dev, tube);
+
+ /* Don't write to tregs until we've decided `cfg' is really OK,
+ * so as not to make a half-formed mess if we have to error out. */
+ copy_regs(tregs, &dummy_regs);
+
+ /* Try to reconfigure `tube', bailing on error. */
+ ret = config_fifo(&dummy_regs, cfg);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = config_src_dst(&dummy_regs, cfg);
+ if (ret < 0) {
+ return ret;
+ }
+ dummy_regs.SNDTR = cfg->tube_nr_xfers;
+ ret = postconfig_check(&dummy_regs, cfg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Ok, we're good. Commit to the new configuration. */
+ copy_regs(&dummy_regs, tregs);
+ return ret;
+}
+
+void dma_set_priority(dma_dev *dev, dma_stream stream, dma_priority priority) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, stream);
+ uint32 scr;
+ ASSERT_NOT_ENABLED(dev, stream);
+ scr = tregs->SCR;
+ scr &= ~DMA_SCR_PL;
+ scr |= (priority << 16);
+ tregs->SCR = scr;
+}
+
+void dma_set_num_transfers(dma_dev *dev, dma_tube tube, uint16 num_transfers) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ ASSERT_NOT_ENABLED(dev, tube);
+ tregs->SNDTR = num_transfers;
+}
+
+/**
+ * @brief Set memory 0 or memory 1 address.
+ *
+ * This is a general function for setting one of the two memory
+ * addresses available on the double-buffered STM32F2 DMA controllers.
+ *
+ * @param dev DMA device
+ * @param tube Tube on dev.
+ * @param n If 0, set memory 0 address. If 1, set memory 1 address.
+ * @param address Address to set
+ */
+void dma_set_mem_n_addr(dma_dev *dev, dma_tube tube, int n,
+ __io void *address) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ uint32 addr = (uint32)address;
+
+ ASSERT_NOT_ENABLED(dev, tube);
+ if (n) {
+ tregs->SM1AR = addr;
+ } else {
+ tregs->SM0AR = addr;
+ }
+}
+
+void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ ASSERT_NOT_ENABLED(dev, tube);
+ tregs->SPAR = (uint32)address;
+}
+
+/**
+ * @brief Enable a stream's FIFO.
+ *
+ * You may only call this function when the stream is disabled.
+ *
+ * @param dev DMA device
+ * @param tube Stream whose FIFO to enable.
+ */
+void dma_enable_fifo(dma_dev *dev, dma_tube tube) {
+ ASSERT_NOT_ENABLED(dev, tube);
+ bb_peri_set_bit(&(dma_tube_regs(dev, tube)->SFCR), DMA_SFCR_DMDIS_BIT, 1);
+}
+
+/**
+ * @brief Disable a stream's FIFO.
+ *
+ * You may only call this function when the stream is disabled.
+ *
+ * @param dev DMA device
+ * @param tube Stream whose FIFO to disable.
+ */
+void dma_disable_fifo(dma_dev *dev, dma_tube tube) {
+ ASSERT_NOT_ENABLED(dev, tube);
+ bb_peri_set_bit(&(dma_tube_regs(dev, tube)->SFCR), DMA_SFCR_DMDIS_BIT, 0);
+}
+
+void dma_attach_interrupt(dma_dev *dev, dma_tube tube,
+ void (*handler)(void)) {
+ dev->handlers[tube].handler = handler;
+ nvic_irq_enable(dev->handlers[tube].irq_line);
+}
+
+void dma_detach_interrupt(dma_dev *dev, dma_tube tube) {
+ nvic_irq_disable(dev->handlers[tube].irq_line);
+ dev->handlers[tube].handler = NULL;
+}
+
+void dma_enable(dma_dev *dev, dma_tube tube) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ bb_peri_set_bit(&tregs->SCR, DMA_SCR_EN_BIT, 1);
+}
+
+void dma_disable(dma_dev *dev, dma_tube tube) {
+ dma_tube_reg_map *tregs = dma_tube_regs(dev, tube);
+ bb_peri_set_bit(&tregs->SCR, DMA_SCR_EN_BIT, 0);
+ /* The stream might not get disabled immediately, so wait. */
+ while (tregs->SCR & DMA_SCR_EN)
+ ;
+}
+
+dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube) {
+ /* TODO: does it still make sense to have this function? We should
+ * probably just be returning the ISR bits, with some defines to
+ * pull the flags out. The lack of masked status bits is an
+ * annoyance that would require documentation to solve, though. */
+ uint8 status_bits = dma_get_isr_bits(dev, tube);
+ dma_clear_isr_bits(dev, tube);
+ ASSERT(status_bits); /* Or something's very wrong */
+ /* Don't change the order of these if statements. */
+ if (status_bits & 0x0) {
+ return DMA_TRANSFER_FIFO_ERROR;
+ } else if (status_bits & 0x4) {
+ return DMA_TRANSFER_DME_ERROR;
+ } else if (status_bits & 0x8) {
+ return DMA_TRANSFER_ERROR;
+ } else if (status_bits & 0x20) {
+ return DMA_TRANSFER_COMPLETE;
+ } else if (status_bits & 0x10) {
+ return DMA_TRANSFER_HALF_COMPLETE;
+ }
+
+ /* Something's wrong; one of those bits should have been set. Fail
+ * an assert, and mimic the error behavior in case of a high debug
+ * level. */
+ ASSERT(0);
+ dma_disable(dev, tube);
+ return DMA_TRANSFER_ERROR;
+}
+
+/*
+ * IRQ handlers
+ */
+
+void __irq_dma1_stream0(void) {
+ dma_irq_handler(DMA1, DMA_S0);
+}
+
+void __irq_dma1_stream1(void) {
+ dma_irq_handler(DMA1, DMA_S1);
+}
+
+void __irq_dma1_stream2(void) {
+ dma_irq_handler(DMA1, DMA_S2);
+}
+
+void __irq_dma1_stream3(void) {
+ dma_irq_handler(DMA1, DMA_S3);
+}
+
+void __irq_dma1_stream4(void) {
+ dma_irq_handler(DMA1, DMA_S4);
+}
+
+void __irq_dma1_stream5(void) {
+ dma_irq_handler(DMA1, DMA_S5);
+}
+
+void __irq_dma1_stream6(void) {
+ dma_irq_handler(DMA1, DMA_S6);
+}
+
+void __irq_dma1_stream7(void) {
+ dma_irq_handler(DMA1, DMA_S7);
+}
+
+void __irq_dma2_stream0(void) {
+ dma_irq_handler(DMA2, DMA_S0);
+}
+
+void __irq_dma2_stream1(void) {
+ dma_irq_handler(DMA2, DMA_S1);
+}
+
+void __irq_dma2_stream2(void) {
+ dma_irq_handler(DMA2, DMA_S2);
+}
+
+void __irq_dma2_stream3(void) {
+ dma_irq_handler(DMA2, DMA_S3);
+}
+
+void __irq_dma2_stream4(void) {
+ dma_irq_handler(DMA2, DMA_S4);
+}
+
+void __irq_dma2_stream5(void) {
+ dma_irq_handler(DMA2, DMA_S5);
+}
+
+void __irq_dma2_stream6(void) {
+ dma_irq_handler(DMA2, DMA_S6);
+}
+
+void __irq_dma2_stream7(void) {
+ dma_irq_handler(DMA2, DMA_S7);
+}
+
+/*
+ * Auxiliary routines for dma_tube_cfg()
+ */
+
+/* Is addr acceptable for use as DMA src/dst? */
+static int cfg_mem_ok(__io void *addr) {
+ enum dma_atype atype = _dma_addr_type(addr);
+ return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER;
+}
+
+/* Is src -> dst a reasonable combination of [MEM,PER] -> [MEM,PER]? */
+static int cfg_dir_ok(dma_dev *dev, __io void *src, __io void *dst) {
+ switch (_dma_addr_type(dst)) {
+ case DMA_ATYPE_MEM:
+ /* Only DMA2 can do memory-to-memory */
+ return ((_dma_addr_type(src) == DMA_ATYPE_PER) ||
+ (dev->clk_id == RCC_DMA2));
+ case DMA_ATYPE_PER:
+ /* Peripheral-to-peripheral is illegal */
+ return _dma_addr_type(src) == DMA_ATYPE_PER;
+ default: /* Can't happen */
+ ASSERT(0);
+ return 0;
+ }
+}
+
+/* Initial sanity check for dma_tube_cfg() */
+static int preconfig_check(dma_dev *dev, dma_tube tube,
+ dma_tube_config *cfg) {
+ if (!(src_stream_mask(cfg->tube_req_src) & (1U << tube))) {
+ /* ->tube_req_src not supported by stream */
+ return -DMA_TUBE_CFG_EREQ;
+ }
+ if (cfg->tube_nr_xfers > 65535) {
+ /* That's too many. */
+ return -DMA_TUBE_CFG_ENDATA;
+ }
+ if (src_clk_id(cfg->tube_req_src) != dev->clk_id) {
+ /* ->tube_req_src not supported by dev */
+ return -DMA_TUBE_CFG_EDEV;
+ }
+ if (!cfg_mem_ok(cfg->tube_src)) {
+ return -DMA_TUBE_CFG_ESRC;
+ }
+ if (!cfg_mem_ok(cfg->tube_dst)) {
+ return -DMA_TUBE_CFG_EDST;
+ }
+ if (!cfg_dir_ok(dev, cfg->tube_src, cfg->tube_dst)) {
+ return -DMA_TUBE_CFG_EDIR;
+ }
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+static int config_fifo(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ /* TODO: FIFO configuration based on cfg->target_data */
+ uint32 sfcr = dummy->SFCR;
+ sfcr &= ~DMA_SFCR_FEIE;
+ sfcr |= (cfg->tube_flags & DMA_CFG_FIFO_ERR_IE) ? DMA_SFCR_FEIE : 0;
+ dummy->SFCR = sfcr;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Helper for configuring (DMA_SxCR) */
+#define BITS_WE_CARE_ABOUT \
+ (DMA_SCR_CHSEL | DMA_SCR_MBURST | DMA_SCR_PBURST | DMA_SCR_PINCOS | \
+ DMA_SCR_MINC | DMA_SCR_PINC | DMA_SCR_CIRC | DMA_SCR_DIR | \
+ DMA_SCR_PFCTRL | DMA_SCR_TCIE | DMA_SCR_HTIE | DMA_SCR_TEIE | \
+ DMA_SCR_DMEIE)
+static inline void config_scr(dma_tube_reg_map *dummy, dma_tube_config *cfg,
+ unsigned src_shift, uint32 src_inc,
+ unsigned dst_shift, uint32 dst_inc,
+ uint32 dir) {
+ /* These would go here if we supported them: MBURST, PBURST,
+ * PINCOS, PFCTRL. We explicitly choose low priority, and double
+ * buffering belongs elsewhere, I think. [mbolivar] */
+ uint32 flags = cfg->tube_flags & BITS_WE_CARE_ABOUT;
+ uint32 scr = dummy->SCR;
+ scr &= ~(BITS_WE_CARE_ABOUT | DMA_SCR_PL);
+ scr |= (/* CHSEL */
+ (src_channel(cfg->tube_req_src) << 25) |
+ /* MSIZE/PSIZE */
+ (cfg->tube_src_size << src_shift) |
+ (cfg->tube_dst_size << dst_shift) |
+ /* MINC/PINC */
+ ((cfg->tube_flags & DMA_CFG_SRC_INC) ? src_inc : 0) |
+ ((cfg->tube_flags & DMA_CFG_DST_INC) ? dst_inc : 0) |
+ /* DIR */
+ dir |
+ /* Other flags carried by cfg->tube_flags */
+ flags);
+ dummy->SCR = scr;
+}
+#undef BITS_WE_CARE_ABOUT
+
+/* Helper for when cfg->tube_dst is memory */
+static int config_to_mem(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ uint32 dir = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ?
+ DMA_SCR_DIR_MEM_TO_MEM : DMA_SCR_DIR_PER_TO_MEM);
+
+ if ((dir == DMA_SCR_DIR_MEM_TO_MEM) && (cfg->tube_flags & DMA_CFG_CIRC)) {
+ return -DMA_TUBE_CFG_ECFG; /* Can't do DMA_CFG_CIRC and mem->mem. */
+ }
+
+ config_scr(dummy, cfg, 11, DMA_SCR_PINC, 13, DMA_SCR_MINC, dir);
+ dummy->SPAR = (uint32)cfg->tube_src;
+ dummy->SM0AR = (uint32)cfg->tube_dst;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Helper for when cfg->tube_src is peripheral */
+static int config_to_per(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ config_scr(dummy, cfg, 13, DMA_SCR_MINC, 11, DMA_SCR_PINC,
+ DMA_SCR_DIR_MEM_TO_PER);
+ dummy->SM0AR = (uint32)cfg->tube_src;
+ dummy->SPAR = (uint32)cfg->tube_dst;
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Configures SCR, SPAR, SM0AR, and checks that the result is OK. */
+static int config_src_dst(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ switch (_dma_addr_type(cfg->tube_dst)) {
+ case DMA_ATYPE_MEM:
+ return config_to_mem(dummy, cfg);
+ case DMA_ATYPE_PER:
+ return config_to_per(dummy, cfg);
+ case DMA_ATYPE_OTHER:
+ default: /* shut up, GCC */
+ /* Can't happen */
+ ASSERT(0);
+ return -DMA_TUBE_CFG_ECFG;
+ }
+}
+
+/* Final checks we can only perform when fully configured */
+static int postconfig_check(dma_tube_reg_map *dummy, dma_tube_config *cfg) {
+ /* TODO add dma_get_[mem,per]_size() and use them here */
+ /* msize and psize are in bytes here: */
+ uint32 scr = dummy->SCR;
+ uint32 msize = 1U << ((scr >> 13) & 0x3);
+ uint32 psize = 1U << ((scr >> 11) & 0x3);
+
+ /* Ensure NDT will work with PSIZE/MSIZE.
+ *
+ * RM0033 specifies that PSIZE, MSIZE, and NDT must be such that
+ * the last transfer completes; i.e. that if PSIZE < MSIZE, then
+ * NDT is a multiple of MSIZE/PSIZE. See e.g. Table 27. */
+ if ((psize < msize) && (cfg->tube_nr_xfers % (msize / psize))) {
+ return -DMA_TUBE_CFG_ENDATA;
+ }
+
+ /* Direct mode is only possible if MSIZE == PSIZE. */
+ if ((msize != psize) && !(dummy->SFCR & DMA_SFCR_DMDIS)) {
+ return -DMA_TUBE_CFG_ESIZE;
+ }
+
+ return DMA_TUBE_CFG_SUCCESS;
+}
+
+/* Convenience for dealing with dummy registers */
+static void copy_regs(dma_tube_reg_map *src, dma_tube_reg_map *dst) {
+ dst->SCR = src->SCR;
+ dst->SNDTR = src->SNDTR;
+ dst->SPAR = src->SPAR;
+ dst->SM0AR = src->SM0AR;
+ dst->SFCR = src->SFCR;
+}
diff --git a/libmaple/stm32f2/exti.c b/libmaple/stm32f2/exti.c
new file mode 100644
index 0000000..208415f
--- /dev/null
+++ b/libmaple/stm32f2/exti.c
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * 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.
+*****************************************************************************/
+
+#include <libmaple/exti.h>
+#include <libmaple/syscfg.h>
+#include "exti_private.h"
+
+void exti_select(exti_num num, exti_cfg cfg) {
+ exti_do_select(&SYSCFG_BASE->EXTICR[num / 4], num, cfg);
+}
diff --git a/libmaple/stm32f2/fsmc.c b/libmaple/stm32f2/fsmc.c
new file mode 100644
index 0000000..ec41720
--- /dev/null
+++ b/libmaple/stm32f2/fsmc.c
@@ -0,0 +1,90 @@
+/******************************************************************************
+ * 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/fsmc.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 FSMC support.
+ */
+
+#include <libmaple/fsmc.h>
+#include <libmaple/gpio.h>
+
+#define CONFIG_GPIO(dev, bit) \
+ do { \
+ gpio_set_modef(dev, bit, GPIO_MODE_AF, GPIO_MODEF_SPEED_HIGH); \
+ gpio_set_af(dev, bit, GPIO_AF_FSMC_SDIO_OTG_FS); \
+ } while (0)
+void fsmc_sram_init_gpios(void) {
+ /* Data lines... */
+ CONFIG_GPIO(GPIOD, 0);
+ CONFIG_GPIO(GPIOD, 1);
+ CONFIG_GPIO(GPIOD, 8);
+ CONFIG_GPIO(GPIOD, 9);
+ CONFIG_GPIO(GPIOD, 10);
+ CONFIG_GPIO(GPIOD, 14);
+ CONFIG_GPIO(GPIOD, 15);
+ CONFIG_GPIO(GPIOE, 7);
+ CONFIG_GPIO(GPIOE, 8);
+ CONFIG_GPIO(GPIOE, 9);
+ CONFIG_GPIO(GPIOE, 10);
+ CONFIG_GPIO(GPIOE, 11);
+ CONFIG_GPIO(GPIOE, 12);
+ CONFIG_GPIO(GPIOE, 13);
+ CONFIG_GPIO(GPIOE, 14);
+ CONFIG_GPIO(GPIOE, 15);
+
+ /* Address lines... */
+ CONFIG_GPIO(GPIOD, 11);
+ CONFIG_GPIO(GPIOD, 12);
+ CONFIG_GPIO(GPIOD, 13);
+ CONFIG_GPIO(GPIOF, 0);
+ CONFIG_GPIO(GPIOF, 1);
+ CONFIG_GPIO(GPIOF, 2);
+ CONFIG_GPIO(GPIOF, 3);
+ CONFIG_GPIO(GPIOF, 4);
+ CONFIG_GPIO(GPIOF, 5);
+ CONFIG_GPIO(GPIOF, 12);
+ CONFIG_GPIO(GPIOF, 13);
+ CONFIG_GPIO(GPIOF, 14);
+ CONFIG_GPIO(GPIOF, 15);
+ CONFIG_GPIO(GPIOG, 0);
+ CONFIG_GPIO(GPIOG, 1);
+ CONFIG_GPIO(GPIOG, 2);
+ CONFIG_GPIO(GPIOG, 3);
+ CONFIG_GPIO(GPIOG, 4);
+ CONFIG_GPIO(GPIOG, 5);
+
+ /* And control lines... */
+ CONFIG_GPIO(GPIOD, 4);
+ CONFIG_GPIO(GPIOD, 5);
+ CONFIG_GPIO(GPIOD, 7);
+ CONFIG_GPIO(GPIOG, 9);
+ CONFIG_GPIO(GPIOG, 10);
+ CONFIG_GPIO(GPIOG, 12);
+ CONFIG_GPIO(GPIOE, 0);
+ CONFIG_GPIO(GPIOE, 1);
+}
diff --git a/libmaple/stm32f2/gpio.c b/libmaple/stm32f2/gpio.c
new file mode 100644
index 0000000..a26edaa
--- /dev/null
+++ b/libmaple/stm32f2/gpio.c
@@ -0,0 +1,194 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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/gpio.c
+ * @brief STM32F2 GPIO.
+ */
+
+#include <libmaple/gpio.h>
+#include <libmaple/rcc.h>
+#include <libmaple/bitband.h>
+
+/*
+ * GPIO devices
+ */
+
+gpio_dev gpioa = {
+ .regs = GPIOA_BASE,
+ .clk_id = RCC_GPIOA,
+ .exti_port = EXTI_PA,
+};
+/** GPIO port A device. */
+gpio_dev* const GPIOA = &gpioa;
+
+gpio_dev gpiob = {
+ .regs = GPIOB_BASE,
+ .clk_id = RCC_GPIOB,
+ .exti_port = EXTI_PB,
+};
+/** GPIO port B device. */
+gpio_dev* const GPIOB = &gpiob;
+
+gpio_dev gpioc = {
+ .regs = GPIOC_BASE,
+ .clk_id = RCC_GPIOC,
+ .exti_port = EXTI_PC,
+};
+/** GPIO port C device. */
+gpio_dev* const GPIOC = &gpioc;
+
+gpio_dev gpiod = {
+ .regs = GPIOD_BASE,
+ .clk_id = RCC_GPIOD,
+ .exti_port = EXTI_PD,
+};
+/** GPIO port D device. */
+gpio_dev* const GPIOD = &gpiod;
+
+gpio_dev gpioe = {
+ .regs = GPIOE_BASE,
+ .clk_id = RCC_GPIOE,
+ .exti_port = EXTI_PE,
+};
+/** GPIO port E device. */
+gpio_dev* const GPIOE = &gpioe;
+
+gpio_dev gpiof = {
+ .regs = GPIOF_BASE,
+ .clk_id = RCC_GPIOF,
+ .exti_port = EXTI_PF,
+};
+/** GPIO port F device. */
+gpio_dev* const GPIOF = &gpiof;
+
+gpio_dev gpiog = {
+ .regs = GPIOG_BASE,
+ .clk_id = RCC_GPIOG,
+ .exti_port = EXTI_PG,
+};
+/** GPIO port G device. */
+gpio_dev* const GPIOG = &gpiog;
+
+gpio_dev gpioh = {
+ .regs = GPIOH_BASE,
+ .clk_id = RCC_GPIOH,
+ .exti_port = EXTI_PH,
+};
+/** GPIO port G device. */
+gpio_dev* const GPIOH = &gpioh;
+
+gpio_dev gpioi = {
+ .regs = GPIOI_BASE,
+ .clk_id = RCC_GPIOI,
+ .exti_port = EXTI_PI,
+};
+/** GPIO port G device. */
+gpio_dev* const GPIOI = &gpioi;
+
+/*
+ * GPIO routines
+ */
+
+/**
+ * Initialize and reset all available GPIO devices.
+ */
+void gpio_init_all(void) {
+ gpio_init(GPIOA);
+ gpio_init(GPIOB);
+ gpio_init(GPIOC);
+ gpio_init(GPIOD);
+ gpio_init(GPIOE);
+ gpio_init(GPIOF);
+ gpio_init(GPIOG);
+ gpio_init(GPIOH);
+ gpio_init(GPIOI);
+}
+
+/**
+ * @brief Set the mode of a GPIO pin.
+ * @param dev GPIO device.
+ * @param bit Bit on dev whose mode to set, 0--15.
+ * @param mode Mode to set the pin to.
+ * @param flags Flags to modify basic mode configuration
+ */
+void gpio_set_modef(gpio_dev *dev,
+ uint8 bit,
+ gpio_pin_mode mode,
+ unsigned flags) {
+ gpio_reg_map *regs = dev->regs;
+ unsigned shift = bit * 2;
+ uint32 tmp;
+
+ /* Mode */
+ tmp = regs->MODER;
+ tmp &= ~(0x3 << shift);
+ tmp |= mode << shift;
+ regs->MODER = tmp;
+
+ /* Output type */
+ bb_peri_set_bit(&regs->OTYPER, bit, flags & 0x1);
+
+ /* Speed */
+ tmp = regs->OSPEEDR;
+ tmp &= ~(0x3 << shift);
+ tmp |= ((flags >> 1) & 0x3) << shift;
+ regs->OSPEEDR = tmp;
+
+ /* Pull-up/pull-down */
+ tmp = regs->PUPDR;
+ tmp &= ~(0x3 << shift);
+ tmp |= ((flags >> 3) & 0x3) << shift;
+ regs->PUPDR = tmp;
+}
+
+/**
+ * @brief Set a pin's alternate function.
+ *
+ * The pin must have its mode set to GPIO_MODE_AF for this to take
+ * effect.
+ *
+ * @param dev Device whose pin to configure.
+ * @param bit Pin whose alternate function to set.
+ * @param af Alternate function to use for pin.
+ * @see gpio_set_modef()
+ */
+void gpio_set_af(gpio_dev *dev, uint8 bit, gpio_af af) {
+ __io uint32 *afr;
+ unsigned shift;
+ uint32 tmp;
+ if (bit >= 8) {
+ afr = &dev->regs->AFRH;
+ shift = 4 * (bit - 8);
+ } else{
+ afr = &dev->regs->AFRL;
+ shift = 4 * bit;
+ }
+ tmp = *afr;
+ tmp &= ~(0xF << shift);
+ tmp |= (af << shift);
+ *afr = tmp;
+}
diff --git a/libmaple/stm32f2/include/series/adc.h b/libmaple/stm32f2/include/series/adc.h
new file mode 100644
index 0000000..714179c
--- /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 libmaple/stm32f2/include/series/adc.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * @brief STM32F2 ADC support.
+ */
+
+#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/include/series/dac.h b/libmaple/stm32f2/include/series/dac.h
new file mode 100644
index 0000000..0a578ca
--- /dev/null
+++ b/libmaple/stm32f2/include/series/dac.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * 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/dac.h
+ * @brief STM32F2 DAC support
+ */
+
+#ifndef _LIBMAPLE_STM32F2_DAC_H_
+#define _LIBMAPLE_STM32F2_DAC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map type
+ */
+
+/** STM32F2 DAC register map type. */
+typedef struct dac_reg_map {
+ __io uint32 CR; /**< Control register */
+ __io uint32 SWTRIGR; /**< Software trigger register */
+ __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding
+ register */
+ __io uint32 DOR1; /**< Channel 1 data output register */
+ __io uint32 DOR2; /**< Channel 2 data output register */
+ __io uint32 SR; /**< Status register */
+} dac_reg_map;
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+
+#define DAC_CR_DMAUDRIE1 (1U << 13) /* Channel 1 DMA underrun
+ * interrupt enable */
+#define DAC_CR_DMAUDRIE2 (1U << 29) /* Channel 2 DMA underrun
+ * interrupt enable */
+
+/* Status register */
+
+#define DAC_SR_DMAUDR1 (1U << 13) /* Channel 1 DMA underrun
+ * occurred */
+#define DAC_SR_DMAUDR2 (1U << 29) /* Channel 2 DMA underrun
+ * ocurred */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/dma.h b/libmaple/stm32f2/include/series/dma.h
new file mode 100644
index 0000000..43bd1a2
--- /dev/null
+++ b/libmaple/stm32f2/include/series/dma.h
@@ -0,0 +1,810 @@
+/******************************************************************************
+ * 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/dma.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 DMA series header
+ */
+
+#ifndef _LIBMAPLE_STM32F2_DMA_H_
+#define _LIBMAPLE_STM32F2_DMA_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/dma_common.h>
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map and base pointers
+ */
+
+/**
+ * @brief STM32F2 DMA register map type.
+ */
+typedef struct dma_reg_map {
+ /* Isn't it nice how on F1, it's CCR1, but on F2, it's S1CR? */
+
+ /* Global DMA registers */
+ __io uint32 LISR; /**< Low interrupt status register */
+ __io uint32 HISR; /**< High interrupt status register */
+ __io uint32 LIFCR; /**< Low interrupt flag clear register */
+ __io uint32 HIFCR; /**< High interrupt flag clear register */
+ /* Stream 0 registers */
+ __io uint32 S0CR; /**< Stream 0 control register */
+ __io uint32 S0NDTR; /**< Stream 0 number of data register */
+ __io uint32 S0PAR; /**< Stream 0 peripheral address register */
+ __io uint32 S0M0AR; /**< Stream 0 memory 0 address register */
+ __io uint32 S0M1AR; /**< Stream 0 memory 1 address register */
+ __io uint32 S0FCR; /**< Stream 0 FIFO control register */
+ /* Stream 1 registers */
+ __io uint32 S1CR; /**< Stream 1 control register */
+ __io uint32 S1NDTR; /**< Stream 1 number of data register */
+ __io uint32 S1PAR; /**< Stream 1 peripheral address register */
+ __io uint32 S1M0AR; /**< Stream 1 memory 0 address register */
+ __io uint32 S1M1AR; /**< Stream 1 memory 1 address register */
+ __io uint32 S1FCR; /**< Stream 1 FIFO control register */
+ /* Stream 2 registers */
+ __io uint32 S2CR; /**< Stream 2 control register */
+ __io uint32 S2NDTR; /**< Stream 2 number of data register */
+ __io uint32 S2PAR; /**< Stream 2 peripheral address register */
+ __io uint32 S2M0AR; /**< Stream 2 memory 0 address register */
+ __io uint32 S2M1AR; /**< Stream 2 memory 1 address register */
+ __io uint32 S2FCR; /**< Stream 2 FIFO control register */
+ /* Stream 3 registers */
+ __io uint32 S3CR; /**< Stream 3 control register */
+ __io uint32 S3NDTR; /**< Stream 3 number of data register */
+ __io uint32 S3PAR; /**< Stream 3 peripheral address register */
+ __io uint32 S3M0AR; /**< Stream 3 memory 0 address register */
+ __io uint32 S3M1AR; /**< Stream 3 memory 1 address register */
+ __io uint32 S3FCR; /**< Stream 3 FIFO control register */
+ /* Stream 4 registers */
+ __io uint32 S4CR; /**< Stream 4 control register */
+ __io uint32 S4NDTR; /**< Stream 4 number of data register */
+ __io uint32 S4PAR; /**< Stream 4 peripheral address register */
+ __io uint32 S4M0AR; /**< Stream 4 memory 0 address register */
+ __io uint32 S4M1AR; /**< Stream 4 memory 1 address register */
+ __io uint32 S4FCR; /**< Stream 4 FIFO control register */
+ /* Stream 5 registers */
+ __io uint32 S5CR; /**< Stream 5 control register */
+ __io uint32 S5NDTR; /**< Stream 5 number of data register */
+ __io uint32 S5PAR; /**< Stream 5 peripheral address register */
+ __io uint32 S5M0AR; /**< Stream 5 memory 0 address register */
+ __io uint32 S5M1AR; /**< Stream 5 memory 1 address register */
+ __io uint32 S5FCR; /**< Stream 5 FIFO control register */
+ /* Stream 6 registers */
+ __io uint32 S6CR; /**< Stream 6 control register */
+ __io uint32 S6NDTR; /**< Stream 6 number of data register */
+ __io uint32 S6PAR; /**< Stream 6 peripheral address register */
+ __io uint32 S6M0AR; /**< Stream 6 memory 0 address register */
+ __io uint32 S6M1AR; /**< Stream 6 memory 1 address register */
+ __io uint32 S6FCR; /**< Stream 6 FIFO control register */
+ /* Stream 7 registers */
+ __io uint32 S7CR; /**< Stream 7 control register */
+ __io uint32 S7NDTR; /**< Stream 7 number of data register */
+ __io uint32 S7PAR; /**< Stream 7 peripheral address register */
+ __io uint32 S7M0AR; /**< Stream 7 memory 0 address register */
+ __io uint32 S7M1AR; /**< Stream 7 memory 1 address register */
+ __io uint32 S7FCR; /**< Stream 7 FIFO control register */
+} dma_reg_map;
+
+/** DMA controller 1 register map base pointer */
+#define DMA1_BASE ((struct dma_reg_map*)0x40026000)
+/** DMA controller 2 register map base pointer */
+#define DMA2_BASE ((struct dma_reg_map*)0x40026400)
+
+/**
+ * @brief STM32F2 DMA stream (i.e. tube) register map type.
+ * Provides access to an individual stream's registers.
+ * @see dma_tube_regs()
+ */
+typedef struct dma_tube_reg_map {
+ __io uint32 SCR; /**< Stream configuration register */
+ __io uint32 SNDTR; /**< Stream number of data register */
+ __io uint32 SPAR; /**< Stream peripheral address register */
+ __io uint32 SM0AR; /**< Stream memory 0 address register */
+ __io uint32 SM1AR; /**< Stream memory 1 address register */
+ __io uint32 SFCR; /**< Stream FIFO control register */
+} dma_tube_reg_map;
+
+/** DMA1 stream 0 register map base pointer */
+#define DMA1S0_BASE ((struct dma_tube_reg_map*)0x40026010)
+/** DMA1 stream 1 register map base pointer */
+#define DMA1S1_BASE ((struct dma_tube_reg_map*)0x40026028)
+/** DMA1 stream 2 register map base pointer */
+#define DMA1S2_BASE ((struct dma_tube_reg_map*)0x40026040)
+/** DMA1 stream 3 register map base pointer */
+#define DMA1S3_BASE ((struct dma_tube_reg_map*)0x40026058)
+/** DMA1 stream 4 register map base pointer */
+#define DMA1S4_BASE ((struct dma_tube_reg_map*)0x40026070)
+/** DMA1 stream 5 register map base pointer */
+#define DMA1S5_BASE ((struct dma_tube_reg_map*)0x40026088)
+/** DMA1 stream 6 register map base pointer */
+#define DMA1S6_BASE ((struct dma_tube_reg_map*)0x400260A0)
+/** DMA1 stream 7 register map base pointer */
+#define DMA1S7_BASE ((struct dma_tube_reg_map*)0x400260B8)
+
+/** DMA2 stream 0 register map base pointer */
+#define DMA2S0_BASE ((struct dma_tube_reg_map*)0x40026410)
+/** DMA2 stream 1 register map base pointer */
+#define DMA2S1_BASE ((struct dma_tube_reg_map*)0x40026028)
+/** DMA2 stream 2 register map base pointer */
+#define DMA2S2_BASE ((struct dma_tube_reg_map*)0x40026040)
+/** DMA2 stream 3 register map base pointer */
+#define DMA2S3_BASE ((struct dma_tube_reg_map*)0x40026058)
+/** DMA2 stream 4 register map base pointer */
+#define DMA2S4_BASE ((struct dma_tube_reg_map*)0x40026070)
+/** DMA2 stream 5 register map base pointer */
+#define DMA2S5_BASE ((struct dma_tube_reg_map*)0x40026088)
+/** DMA2 stream 6 register map base pointer */
+#define DMA2S6_BASE ((struct dma_tube_reg_map*)0x400260A0)
+/** DMA2 stream 7 register map base pointer */
+#define DMA2S7_BASE ((struct dma_tube_reg_map*)0x400260B8)
+
+/*
+ * Register bit definitions
+ */
+
+/* Low interrupt status register */
+
+#define DMA_LISR_TCIF3_BIT 27
+#define DMA_LISR_HTIF3_BIT 26
+#define DMA_LISR_TEIF3_BIT 25
+#define DMA_LISR_DMEIF3_BIT 24
+#define DMA_LISR_FEIF3_BIT 22
+#define DMA_LISR_TCIF2_BIT 21
+#define DMA_LISR_HTIF2_BIT 20
+#define DMA_LISR_TEIF2_BIT 19
+#define DMA_LISR_DMEIF2_BIT 18
+#define DMA_LISR_FEIF2_BIT 16
+#define DMA_LISR_TCIF1_BIT 11
+#define DMA_LISR_HTIF1_BIT 10
+#define DMA_LISR_TEIF1_BIT 9
+#define DMA_LISR_DMEIF1_BIT 8
+#define DMA_LISR_FEIF1_BIT 6
+#define DMA_LISR_TCIF0_BIT 5
+#define DMA_LISR_HTIF0_BIT 4
+#define DMA_LISR_TEIF0_BIT 3
+#define DMA_LISR_DMEIF0_BIT 2
+#define DMA_LISR_FEIF0_BIT 0
+
+#define DMA_LISR_TCIF3 (1U << DMA_LISR_TCIF3_BIT)
+#define DMA_LISR_HTIF3 (1U << DMA_LISR_HTIF3_BIT)
+#define DMA_LISR_TEIF3 (1U << DMA_LISR_TEIF3_BIT)
+#define DMA_LISR_DMEIF3 (1U << DMA_LISR_DMEIF3_BIT)
+#define DMA_LISR_FEIF3 (1U << DMA_LISR_FEIF3_BIT)
+#define DMA_LISR_TCIF2 (1U << DMA_LISR_TCIF2_BIT)
+#define DMA_LISR_HTIF2 (1U << DMA_LISR_HTIF2_BIT)
+#define DMA_LISR_TEIF2 (1U << DMA_LISR_TEIF2_BIT)
+#define DMA_LISR_DMEIF2 (1U << DMA_LISR_DMEIF2_BIT)
+#define DMA_LISR_FEIF2 (1U << DMA_LISR_FEIF2_BIT)
+#define DMA_LISR_TCIF1 (1U << DMA_LISR_TCIF1_BIT)
+#define DMA_LISR_HTIF1 (1U << DMA_LISR_HTIF1_BIT)
+#define DMA_LISR_TEIF1 (1U << DMA_LISR_TEIF1_BIT)
+#define DMA_LISR_DMEIF1 (1U << DMA_LISR_DMEIF1_BIT)
+#define DMA_LISR_FEIF1 (1U << DMA_LISR_FEIF1_BIT)
+#define DMA_LISR_TCIF0 (1U << DMA_LISR_TCIF0_BIT)
+#define DMA_LISR_HTIF0 (1U << DMA_LISR_HTIF0_BIT)
+#define DMA_LISR_TEIF0 (1U << DMA_LISR_TEIF0_BIT)
+#define DMA_LISR_DMEIF0 (1U << DMA_LISR_DMEIF0_BIT)
+#define DMA_LISR_FEIF0 (1U << DMA_LISR_FEIF0_BIT)
+
+/* High interrupt status register */
+
+#define DMA_HISR_TCIF7_BIT 27
+#define DMA_HISR_HTIF7_BIT 26
+#define DMA_HISR_TEIF7_BIT 25
+#define DMA_HISR_DMEIF7_BIT 24
+#define DMA_HISR_FEIF7_BIT 22
+#define DMA_HISR_TCIF6_BIT 21
+#define DMA_HISR_HTIF6_BIT 20
+#define DMA_HISR_TEIF6_BIT 19
+#define DMA_HISR_DMEIF6_BIT 18
+#define DMA_HISR_FEIF6_BIT 16
+#define DMA_HISR_TCIF5_BIT 11
+#define DMA_HISR_HTIF5_BIT 10
+#define DMA_HISR_TEIF5_BIT 9
+#define DMA_HISR_DMEIF5_BIT 8
+#define DMA_HISR_FEIF5_BIT 6
+#define DMA_HISR_TCIF4_BIT 5
+#define DMA_HISR_HTIF4_BIT 4
+#define DMA_HISR_TEIF4_BIT 3
+#define DMA_HISR_DMEIF4_BIT 2
+#define DMA_HISR_FEIF4_BIT 0
+
+#define DMA_HISR_TCIF7 (1U << DMA_HISR_TCIF7_BIT)
+#define DMA_HISR_HTIF7 (1U << DMA_HISR_HTIF7_BIT)
+#define DMA_HISR_TEIF7 (1U << DMA_HISR_TEIF7_BIT)
+#define DMA_HISR_DMEIF7 (1U << DMA_HISR_DMEIF7_BIT)
+#define DMA_HISR_FEIF7 (1U << DMA_HISR_FEIF7_BIT)
+#define DMA_HISR_TCIF6 (1U << DMA_HISR_TCIF6_BIT)
+#define DMA_HISR_HTIF6 (1U << DMA_HISR_HTIF6_BIT)
+#define DMA_HISR_TEIF6 (1U << DMA_HISR_TEIF6_BIT)
+#define DMA_HISR_DMEIF6 (1U << DMA_HISR_DMEIF6_BIT)
+#define DMA_HISR_FEIF6 (1U << DMA_HISR_FEIF6_BIT)
+#define DMA_HISR_TCIF5 (1U << DMA_HISR_TCIF5_BIT)
+#define DMA_HISR_HTIF5 (1U << DMA_HISR_HTIF5_BIT)
+#define DMA_HISR_TEIF5 (1U << DMA_HISR_TEIF5_BIT)
+#define DMA_HISR_DMEIF5 (1U << DMA_HISR_DMEIF5_BIT)
+#define DMA_HISR_FEIF5 (1U << DMA_HISR_FEIF5_BIT)
+#define DMA_HISR_TCIF4 (1U << DMA_HISR_TCIF4_BIT)
+#define DMA_HISR_HTIF4 (1U << DMA_HISR_HTIF4_BIT)
+#define DMA_HISR_TEIF4 (1U << DMA_HISR_TEIF4_BIT)
+#define DMA_HISR_DMEIF4 (1U << DMA_HISR_DMEIF4_BIT)
+#define DMA_HISR_FEIF4 (1U << DMA_HISR_FEIF4_BIT)
+
+/* Low interrupt flag clear register */
+
+#define DMA_LIFCR_CTCIF3_BIT 27
+#define DMA_LIFCR_CHTIF3_BIT 26
+#define DMA_LIFCR_CTEIF3_BIT 25
+#define DMA_LIFCR_CDMEIF3_BIT 24
+#define DMA_LIFCR_CFEIF3_BIT 22
+#define DMA_LIFCR_CTCIF2_BIT 21
+#define DMA_LIFCR_CHTIF2_BIT 20
+#define DMA_LIFCR_CTEIF2_BIT 19
+#define DMA_LIFCR_CDMEIF2_BIT 18
+#define DMA_LIFCR_CFEIF2_BIT 16
+#define DMA_LIFCR_CTCIF1_BIT 11
+#define DMA_LIFCR_CHTIF1_BIT 10
+#define DMA_LIFCR_CTEIF1_BIT 9
+#define DMA_LIFCR_CDMEIF1_BIT 8
+#define DMA_LIFCR_CFEIF1_BIT 6
+#define DMA_LIFCR_CTCIF0_BIT 5
+#define DMA_LIFCR_CHTIF0_BIT 4
+#define DMA_LIFCR_CTEIF0_BIT 3
+#define DMA_LIFCR_CDMEIF0_BIT 2
+#define DMA_LIFCR_CFEIF0_BIT 0
+
+#define DMA_LIFCR_CTCIF3 (1U << DMA_LIFCR_CTCIF3_BIT)
+#define DMA_LIFCR_CHTIF3 (1U << DMA_LIFCR_CHTIF3_BIT)
+#define DMA_LIFCR_CTEIF3 (1U << DMA_LIFCR_CTEIF3_BIT)
+#define DMA_LIFCR_CDMEIF3 (1U << DMA_LIFCR_CDMEIF3_BIT)
+#define DMA_LIFCR_CFEIF3 (1U << DMA_LIFCR_CFEIF3_BIT)
+#define DMA_LIFCR_CTCIF2 (1U << DMA_LIFCR_CTCIF2_BIT)
+#define DMA_LIFCR_CHTIF2 (1U << DMA_LIFCR_CHTIF2_BIT)
+#define DMA_LIFCR_CTEIF2 (1U << DMA_LIFCR_CTEIF2_BIT)
+#define DMA_LIFCR_CDMEIF2 (1U << DMA_LIFCR_CDMEIF2_BIT)
+#define DMA_LIFCR_CFEIF2 (1U << DMA_LIFCR_CFEIF2_BIT)
+#define DMA_LIFCR_CTCIF1 (1U << DMA_LIFCR_CTCIF1_BIT)
+#define DMA_LIFCR_CHTIF1 (1U << DMA_LIFCR_CHTIF1_BIT)
+#define DMA_LIFCR_CTEIF1 (1U << DMA_LIFCR_CTEIF1_BIT)
+#define DMA_LIFCR_CDMEIF1 (1U << DMA_LIFCR_CDMEIF1_BIT)
+#define DMA_LIFCR_CFEIF1 (1U << DMA_LIFCR_CFEIF1_BIT)
+#define DMA_LIFCR_CTCIF0 (1U << DMA_LIFCR_CTCIF0_BIT)
+#define DMA_LIFCR_CHTIF0 (1U << DMA_LIFCR_CHTIF0_BIT)
+#define DMA_LIFCR_CTEIF0 (1U << DMA_LIFCR_CTEIF0_BIT)
+#define DMA_LIFCR_CDMEIF0 (1U << DMA_LIFCR_CDMEIF0_BIT)
+#define DMA_LIFCR_CFEIF0 (1U << DMA_LIFCR_CFEIF0_BIT)
+
+/* High interrupt flag clear regsister */
+
+#define DMA_HIFCR_CTCIF7_BIT 27
+#define DMA_HIFCR_CHTIF7_BIT 26
+#define DMA_HIFCR_CTEIF7_BIT 25
+#define DMA_HIFCR_CDMEIF7_BIT 24
+#define DMA_HIFCR_CFEIF7_BIT 22
+#define DMA_HIFCR_CTCIF6_BIT 21
+#define DMA_HIFCR_CHTIF6_BIT 20
+#define DMA_HIFCR_CTEIF6_BIT 19
+#define DMA_HIFCR_CDMEIF6_BIT 18
+#define DMA_HIFCR_CFEIF6_BIT 16
+#define DMA_HIFCR_CTCIF5_BIT 11
+#define DMA_HIFCR_CHTIF5_BIT 10
+#define DMA_HIFCR_CTEIF5_BIT 9
+#define DMA_HIFCR_CDMEIF5_BIT 8
+#define DMA_HIFCR_CFEIF5_BIT 6
+#define DMA_HIFCR_CTCIF4_BIT 5
+#define DMA_HIFCR_CHTIF4_BIT 4
+#define DMA_HIFCR_CTEIF4_BIT 3
+#define DMA_HIFCR_CDMEIF4_BIT 2
+#define DMA_HIFCR_CFEIF4_BIT 0
+
+#define DMA_HIFCR_CTCIF7 (1U << DMA_HIFCR_CTCIF7_BIT)
+#define DMA_HIFCR_CHTIF7 (1U << DMA_HIFCR_CHTIF7_BIT)
+#define DMA_HIFCR_CTEIF7 (1U << DMA_HIFCR_CTEIF7_BIT)
+#define DMA_HIFCR_CDMEIF7 (1U << DMA_HIFCR_CDMEIF7_BIT)
+#define DMA_HIFCR_CFEIF7 (1U << DMA_HIFCR_CFEIF7_BIT)
+#define DMA_HIFCR_CTCIF6 (1U << DMA_HIFCR_CTCIF6_BIT)
+#define DMA_HIFCR_CHTIF6 (1U << DMA_HIFCR_CHTIF6_BIT)
+#define DMA_HIFCR_CTEIF6 (1U << DMA_HIFCR_CTEIF6_BIT)
+#define DMA_HIFCR_CDMEIF6 (1U << DMA_HIFCR_CDMEIF6_BIT)
+#define DMA_HIFCR_CFEIF6 (1U << DMA_HIFCR_CFEIF6_BIT)
+#define DMA_HIFCR_CTCIF5 (1U << DMA_HIFCR_CTCIF5_BIT)
+#define DMA_HIFCR_CHTIF5 (1U << DMA_HIFCR_CHTIF5_BIT)
+#define DMA_HIFCR_CTEIF5 (1U << DMA_HIFCR_CTEIF5_BIT)
+#define DMA_HIFCR_CDMEIF5 (1U << DMA_HIFCR_CDMEIF5_BIT)
+#define DMA_HIFCR_CFEIF5 (1U << DMA_HIFCR_CFEIF5_BIT)
+#define DMA_HIFCR_CTCIF4 (1U << DMA_HIFCR_CTCIF4_BIT)
+#define DMA_HIFCR_CHTIF4 (1U << DMA_HIFCR_CHTIF4_BIT)
+#define DMA_HIFCR_CTEIF4 (1U << DMA_HIFCR_CTEIF4_BIT)
+#define DMA_HIFCR_CDMEIF4 (1U << DMA_HIFCR_CDMEIF4_BIT)
+#define DMA_HIFCR_CFEIF4 (1U << DMA_HIFCR_CFEIF4_BIT)
+
+/* Stream configuration register */
+
+#define DMA_SCR_CT_BIT 19
+#define DMA_SCR_DBM_BIT 18
+#define DMA_SCR_PINCOS_BIT 15
+#define DMA_SCR_MINC_BIT 10
+#define DMA_SCR_PINC_BIT 9
+#define DMA_SCR_CIRC_BIT 8
+#define DMA_SCR_PFCTRL_BIT 5
+#define DMA_SCR_TCIE_BIT 4
+#define DMA_SCR_HTIE_BIT 3
+#define DMA_SCR_TEIE_BIT 2
+#define DMA_SCR_DMEIE_BIT 1
+#define DMA_SCR_EN_BIT 0
+
+#define DMA_SCR_CHSEL (0x7 << 25)
+#define DMA_SCR_CHSEL_CH_0 (0x0 << 25)
+#define DMA_SCR_CHSEL_CH_1 (0x1 << 25)
+#define DMA_SCR_CHSEL_CH_2 (0x2 << 25)
+#define DMA_SCR_CHSEL_CH_3 (0x3 << 25)
+#define DMA_SCR_CHSEL_CH_4 (0x4 << 25)
+#define DMA_SCR_CHSEL_CH_5 (0x5 << 25)
+#define DMA_SCR_CHSEL_CH_6 (0x6 << 25)
+#define DMA_SCR_CHSEL_CH_7 (0x7 << 25)
+#define DMA_SCR_MBURST (0x3 << 23)
+#define DMA_SCR_MBURST_SINGLE (0x0 << 23)
+#define DMA_SCR_MBURST_INCR4 (0x1 << 23)
+#define DMA_SCR_MBURST_INCR8 (0x2 << 23)
+#define DMA_SCR_MBURST_INCR16 (0x3 << 23)
+#define DMA_SCR_PBURST (0x3 << 21)
+#define DMA_SCR_PBURST_SINGLE (0x0 << 21)
+#define DMA_SCR_PBURST_INCR4 (0x1 << 21)
+#define DMA_SCR_PBURST_INCR8 (0x2 << 21)
+#define DMA_SCR_PBURST_INCR16 (0x3 << 21)
+#define DMA_SCR_CT (1U << DMA_SCR_CT_BIT)
+#define DMA_SCR_DBM (1U << DMA_SCR_DBM_BIT)
+#define DMA_SCR_PL (0x3 << 16)
+#define DMA_SCR_PL_LOW (0x0 << 16)
+#define DMA_SCR_PL_MEDIUM (0x1 << 16)
+#define DMA_SCR_PL_HIGH (0x2 << 16)
+#define DMA_SCR_VERY_HIGH (0x3 << 16)
+#define DMA_SCR_PINCOS (1U << DMA_SCR_PINCOS_BIT)
+#define DMA_SCR_MSIZE (0x3 << 13)
+#define DMA_SCR_MSIZE_8BITS (0x0 << 13)
+#define DMA_SCR_MSIZE_16BITS (0x1 << 13)
+#define DMA_SCR_MSIZE_32BITS (0x2 << 13)
+#define DMA_SCR_PSIZE (0x3 << 11)
+#define DMA_SCR_PSIZE_8BITS (0x0 << 11)
+#define DMA_SCR_PSIZE_16BITS (0x1 << 11)
+#define DMA_SCR_PSIZE_32BITS (0x2 << 11)
+#define DMA_SCR_MINC (1U << DMA_SCR_MINC_BIT)
+#define DMA_SCR_PINC (1U << DMA_SCR_PINC_BIT)
+#define DMA_SCR_CIRC (1U << DMA_SCR_CIRC_BIT)
+#define DMA_SCR_DIR (0x3 << 6)
+#define DMA_SCR_DIR_PER_TO_MEM (0x0 << 6)
+#define DMA_SCR_DIR_MEM_TO_PER (0x1 << 6)
+#define DMA_SCR_DIR_MEM_TO_MEM (0x2 << 6)
+#define DMA_SCR_PFCTRL (1U << DMA_SCR_PFCTRL_BIT)
+#define DMA_SCR_TCIE (1U << DMA_SCR_TCIE_BIT)
+#define DMA_SCR_HTIE (1U << DMA_SCR_HTIE_BIT)
+#define DMA_SCR_TEIE (1U << DMA_SCR_TEIE_BIT)
+#define DMA_SCR_DMEIE (1U << DMA_SCR_DMEIE_BIT)
+#define DMA_SCR_EN (1U << DMA_SCR_EN_BIT)
+
+/* Stream FIFO control register */
+
+#define DMA_SFCR_FEIE_BIT 7
+#define DMA_SFCR_DMDIS_BIT 2
+
+#define DMA_SFCR_FEIE (1U << DMA_SFCR_FEIE_BIT)
+#define DMA_SFCR_FS (0x7 << 3)
+#define DMA_SFCR_FS_ZERO_TO_QUARTER (0x0 << 3)
+#define DMA_SFCR_FS_QUARTER_TO_HALF (0x1 << 3)
+#define DMA_SFCR_FS_HALF_TO_THREE_QUARTERS (0x2 << 3)
+#define DMA_SFCR_FS_THREE_QUARTERS_TO_FULL (0x3 << 3)
+#define DMA_SFCR_FS_EMPTY (0x4 << 3)
+#define DMA_SFCR_FS_FULL (0x5 << 3)
+#define DMA_SFCR_DMDIS (1U << DMA_SFCR_DMDIS_BIT)
+#define DMA_SFCR_FTH (0x3 << 0)
+#define DMA_SFCR_FTH_QUARTER_FULL (0x0 << 3)
+#define DMA_SFCR_FTH_HALF_FULL (0x1 << 3)
+#define DMA_SFCR_FTH_THREE_QUARTERS_FULL (0x2 << 3)
+#define DMA_SFCR_FTH_FULL (0x3 << 3)
+
+/*
+ * Devices
+ */
+
+extern dma_dev *DMA1;
+extern dma_dev *DMA2;
+
+/*
+ * Other types needed by, or useful for, <libmaple/dma.h>
+ */
+
+/**
+ * @brief DMA streams
+ * This is also the dma_tube type for STM32F2.
+ * @see dma_tube
+ */
+typedef enum dma_stream {
+ DMA_S0 = 0,
+ DMA_S1 = 1,
+ DMA_S2 = 2,
+ DMA_S3 = 3,
+ DMA_S4 = 4,
+ DMA_S5 = 5,
+ DMA_S6 = 6,
+ DMA_S7 = 7,
+} dma_stream;
+
+/** STM32F2 dma_tube (=dma_stream) */
+#define dma_tube dma_stream
+
+/**
+ * @brief STM32F2 configuration flags for dma_tube_config.
+ * @see struct dma_tube_config
+ */
+typedef enum dma_cfg_flags {
+ /* NB: flags that aren't SCR bits are treated specially. */
+
+ /**
+ * Source address increment mode
+ *
+ * If this flag is set, the source address is incremented (by the
+ * source size) after each DMA transfer.
+ */
+ DMA_CFG_SRC_INC = 1U << 31,
+
+ /**
+ * Destination address increment mode
+ *
+ * If this flag is set, the destination address is incremented (by
+ * the destination size) after each DMA transfer.
+ */
+ DMA_CFG_DST_INC = 1U << 30,
+
+ /**
+ * Circular mode
+ *
+ * This mode is not available for memory-to-memory transfers.
+ */
+ DMA_CFG_CIRC = DMA_SCR_CIRC,
+
+ /** Transfer complete interrupt enable */
+ DMA_CFG_CMPLT_IE = DMA_SCR_TCIE,
+ /** Transfer half-complete interrupt enable */
+ DMA_CFG_HALF_CMPLT_IE = DMA_SCR_HTIE,
+ /** Transfer error interrupt enable */
+ DMA_CFG_ERR_IE = DMA_SCR_TEIE,
+ /** Direct mode error interrupt enable */
+ DMA_CFG_DM_ERR_IE = DMA_SCR_DMEIE,
+ /** FIFO error interrupt enable */
+ DMA_CFG_FIFO_ERR_IE = (1U << 29),
+} dma_cfg_flags;
+
+/**
+ * @brief STM32F2 DMA request sources.
+ *
+ * IMPORTANT:
+ *
+ * 1. On STM32F2, a particular dma_request_src is always tied to a
+ * single DMA controller, but often can be supported by multiple
+ * streams. For example, DMA requests from ADC1 (DMA_REQ_SRC_ADC1) can
+ * only be handled by DMA2, but they can go to either stream 0 or
+ * stream 4 (though not any other stream). If you try to use a request
+ * source with the wrong DMA controller or the wrong stream on
+ * STM32F2, dma_tube_cfg() will fail.
+ *
+ * 2. A single stream can only handle a single request source at a
+ * time. If you change a stream's request source later, it will stop
+ * serving requests from the old source. However, for some streams,
+ * some sources conflict with one another (when they correspond to the
+ * same channel on that stream), and on STM32F2, Terrible Super-Bad
+ * Things will happen if two conflicting request sources are active at
+ * the same time.
+ *
+ * @see struct dma_tube_config
+ * @see dma_tube_cfg()
+ */
+typedef enum dma_request_src {
+ /* These are constructed like so (though this may change, so user
+ * code shouldn't depend on it):
+ *
+ * Bits 0--2: Channel associated with request source
+ *
+ * Bits 3--9: rcc_clk_id of DMA controller associated with request source
+ *
+ * Bits 10--17: Bit mask of streams which can handle that request
+ * source. (E.g., bit 10 set means stream 0 can
+ * handle the source, bit 11 set means stream 1 can,
+ * etc.)
+ *
+ * Among other things, this is used for error checking in
+ * dma_tube_cfg(). If you change this bit encoding, you need to
+ * update the helper functions in stm32f2/dma.c.
+ */
+#define _DMA_STM32F2_REQ_SRC(stream_mask, clk_id, channel) \
+ (((stream_mask) << 10) | ((clk_id) << 3) | (channel))
+#define _DMA_S(n) (1U << (n))
+
+ /* DMA1 request sources */
+#define _DMA_1_REQ_SRC(stream_mask, channel) \
+ _DMA_STM32F2_REQ_SRC(stream_mask, RCC_DMA1, channel)
+
+ /* Channel 0 */
+ DMA_REQ_SRC_SPI3_RX = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(2), 0),
+ DMA_REQ_SRC_SPI2_RX = _DMA_1_REQ_SRC(_DMA_S(3), 0),
+ DMA_REQ_SRC_SPI2_TX = _DMA_1_REQ_SRC(_DMA_S(4), 0),
+ DMA_REQ_SRC_SPI3_TX = _DMA_1_REQ_SRC(_DMA_S(5) | _DMA_S(7), 0),
+
+ /* Channel 1 */
+ DMA_REQ_SRC_I2C1_RX = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(5), 1),
+ DMA_REQ_SRC_TIM7_UP = _DMA_1_REQ_SRC(_DMA_S(2) | _DMA_S(4), 1),
+ DMA_REQ_SRC_I2C1_TX = _DMA_1_REQ_SRC(_DMA_S(6) | _DMA_S(7), 1),
+
+ /* Channel 2 */
+ DMA_REQ_SRC_TIM4_CH1 = _DMA_1_REQ_SRC(_DMA_S(0), 2),
+ DMA_REQ_SRC_TIM4_CH2 = _DMA_1_REQ_SRC(_DMA_S(3), 2),
+ DMA_REQ_SRC_TIM4_UP = _DMA_1_REQ_SRC(_DMA_S(6), 2),
+ DMA_REQ_SRC_TIM4_CH3 = _DMA_1_REQ_SRC(_DMA_S(7), 2),
+
+ /* Channel 3 */
+ DMA_REQ_SRC_TIM2_UP = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(7), 3),
+ DMA_REQ_SRC_TIM2_CH3 = _DMA_1_REQ_SRC(_DMA_S(1), 3),
+ DMA_REQ_SRC_I2C3_RX = _DMA_1_REQ_SRC(_DMA_S(2), 3),
+ DMA_REQ_SRC_I2C3_TX = _DMA_1_REQ_SRC(_DMA_S(4), 3),
+ DMA_REQ_SRC_TIM2_CH1 = _DMA_1_REQ_SRC(_DMA_S(5), 3),
+ DMA_REQ_SRC_TIM2_CH2 = _DMA_1_REQ_SRC(_DMA_S(6), 3),
+ DMA_REQ_SRC_TIM2_CH4 = _DMA_1_REQ_SRC(_DMA_S(6) | _DMA_S(7), 3),
+
+ /* Channel 4 */
+ DMA_REQ_SRC_UART5_RX = _DMA_1_REQ_SRC(_DMA_S(0), 4),
+ DMA_REQ_SRC_USART3_RX = _DMA_1_REQ_SRC(_DMA_S(1), 4),
+ DMA_REQ_SRC_UART4_RX = _DMA_1_REQ_SRC(_DMA_S(2), 4),
+ DMA_REQ_SRC_USART3_TX = _DMA_1_REQ_SRC(_DMA_S(3), 4),
+ DMA_REQ_SRC_UART4_TX = _DMA_1_REQ_SRC(_DMA_S(4), 4),
+ DMA_REQ_SRC_USART2_RX = _DMA_1_REQ_SRC(_DMA_S(5), 4),
+ DMA_REQ_SRC_USART2_TX = _DMA_1_REQ_SRC(_DMA_S(6), 4),
+ DMA_REQ_SRC_UART5_TX = _DMA_1_REQ_SRC(_DMA_S(7), 4),
+
+ /* Channel 5 */
+ DMA_REQ_SRC_TIM3_CH4 = _DMA_1_REQ_SRC(_DMA_S(2), 5),
+ DMA_REQ_SRC_TIM3_UP = _DMA_1_REQ_SRC(_DMA_S(2), 5),
+ DMA_REQ_SRC_TIM3_CH1 = _DMA_1_REQ_SRC(_DMA_S(4), 5),
+ DMA_REQ_SRC_TIM3_TRIG = _DMA_1_REQ_SRC(_DMA_S(4), 5),
+ DMA_REQ_SRC_TIM3_CH2 = _DMA_1_REQ_SRC(_DMA_S(5), 5),
+ DMA_REQ_SRC_TIM3_CH3 = _DMA_1_REQ_SRC(_DMA_S(7), 5),
+
+ /* Channel 6 */
+ DMA_REQ_SRC_TIM5_CH3 = _DMA_1_REQ_SRC(_DMA_S(0), 6),
+ DMA_REQ_SRC_TIM5_UP = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(6), 6),
+ DMA_REQ_SRC_TIM5_CH4 = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6),
+ DMA_REQ_SRC_TIM5_TRIG = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6),
+ DMA_REQ_SRC_TIM5_CH1 = _DMA_1_REQ_SRC(_DMA_S(2), 6),
+ DMA_REQ_SRC_TIM5_CH2 = _DMA_1_REQ_SRC(_DMA_S(4), 6),
+
+ /* Channel 7 */
+ DMA_REQ_SRC_TIM6_UP = _DMA_1_REQ_SRC(_DMA_S(1), 7),
+ DMA_REQ_SRC_I2C2_RX = _DMA_1_REQ_SRC(_DMA_S(2) | _DMA_S(3), 7),
+ DMA_REQ_SRC_USART3_TX_ALTERNATE = _DMA_1_REQ_SRC(_DMA_S(4), 7),
+ DMA_REQ_SRC_DAC1 = _DMA_1_REQ_SRC(_DMA_S(5), 7),
+ DMA_REQ_SRC_DAC2 = _DMA_1_REQ_SRC(_DMA_S(6), 7),
+ DMA_REQ_SRC_I2C2_TX = _DMA_1_REQ_SRC(_DMA_S(7), 7),
+#undef _DMA_1_REQ_SRC
+
+ /* DMA2 request sources */
+#define _DMA_2_REQ_SRC(stream_mask, channel) \
+ _DMA_STM32F2_REQ_SRC(stream_mask, RCC_DMA2, channel)
+
+ /* Channel 0 */
+ DMA_REQ_SRC_ADC1 = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(4), 0),
+ /* You can use these "DMA_REQ_SRC_TIMx_CHx_ALTERNATE" if you know
+ * what you're doing, but the other ones (for channels 6 and 7),
+ * are better, in that they don't conflict with one another. */
+ DMA_REQ_SRC_TIM8_CH1_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0),
+ DMA_REQ_SRC_TIM8_CH2_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0),
+ DMA_REQ_SRC_TIM8_CH3_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0),
+ DMA_REQ_SRC_TIM1_CH1_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(6), 0),
+ DMA_REQ_SRC_TIM1_CH2_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(6), 0),
+ DMA_REQ_SRC_TIM1_CH3_ALTENRATE = _DMA_2_REQ_SRC(_DMA_S(6), 0),
+
+ /* Channel 1 */
+ DMA_REQ_SRC_DCMI = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(7), 1),
+ DMA_REQ_SRC_ADC2 = _DMA_2_REQ_SRC(_DMA_S(2) | _DMA_S(3), 1),
+
+ /* Channel 2 */
+ DMA_REQ_SRC_ADC3 = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(1), 2),
+ DMA_REQ_SRC_CRYP_OUT = _DMA_2_REQ_SRC(_DMA_S(5), 2),
+ DMA_REQ_SRC_CRYP_IN = _DMA_2_REQ_SRC(_DMA_S(6), 2),
+ DMA_REQ_SRC_HASH_IN = _DMA_2_REQ_SRC(_DMA_S(7), 2),
+
+ /* Channel 3 */
+ DMA_REQ_SRC_SPI1_RX = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(2), 3),
+ DMA_REQ_SRC_SPI1_TX = _DMA_2_REQ_SRC(_DMA_S(3) | _DMA_S(5), 3),
+
+ /* Channel 4 */
+ DMA_REQ_SRC_USART1_RX = _DMA_2_REQ_SRC(_DMA_S(2) | _DMA_S(5), 4),
+ DMA_REQ_SRC_SDIO = _DMA_2_REQ_SRC(_DMA_S(3) | _DMA_S(6), 4),
+ DMA_REQ_SRC_USART1_TX = _DMA_2_REQ_SRC(_DMA_S(7), 4),
+
+ /* Channel 5 */
+ DMA_REQ_SRC_USART6_RX = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(2), 5),
+ DMA_REQ_SRC_USART6_TX = _DMA_2_REQ_SRC(_DMA_S(6) | _DMA_S(7), 5),
+
+ /* Channel 6 */
+ DMA_REQ_SRC_TIM1_TRIG = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(4), 6),
+ DMA_REQ_SRC_TIM1_CH1 = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6),
+ DMA_REQ_SRC_TIM1_CH2 = _DMA_2_REQ_SRC(_DMA_S(3), 6),
+ DMA_REQ_SRC_TIM1_CH4 = _DMA_2_REQ_SRC(_DMA_S(4), 6),
+ DMA_REQ_SRC_TIM1_COM = _DMA_2_REQ_SRC(_DMA_S(4), 6),
+ DMA_REQ_SRC_TIM1_UP = _DMA_2_REQ_SRC(_DMA_S(5), 6),
+ DMA_REQ_SRC_TIM1_CH3 = _DMA_2_REQ_SRC(_DMA_S(6), 6),
+
+ /* Channel 7 */
+ DMA_REQ_SRC_TIM8_UP = _DMA_2_REQ_SRC(_DMA_S(1), 7),
+ DMA_REQ_SRC_TIM8_CH1 = _DMA_2_REQ_SRC(_DMA_S(2), 7),
+ DMA_REQ_SRC_TIM8_CH2 = _DMA_2_REQ_SRC(_DMA_S(3), 7),
+ DMA_REQ_SRC_TIM8_CH3 = _DMA_2_REQ_SRC(_DMA_S(4), 7),
+ DMA_REQ_SRC_TIM8_CH4 = _DMA_2_REQ_SRC(_DMA_S(7), 7),
+ DMA_REQ_SRC_TIM8_TRIG = _DMA_2_REQ_SRC(_DMA_S(7), 7),
+ DMA_REQ_SRC_TIM8_COM = _DMA_2_REQ_SRC(_DMA_S(7), 7),
+#undef _DMA_2_REQ_SRC
+#undef _DMA_S
+} dma_request_src;
+
+/*
+ * Tube conveniences
+ */
+
+static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev,
+ dma_tube tube) {
+ ASSERT(DMA_S0 <= tube && tube <= DMA_S7);
+ switch (dev->clk_id) {
+ case RCC_DMA1:
+ return DMA1S0_BASE + (int)tube;
+ case RCC_DMA2:
+ return DMA2S0_BASE + (int)tube;
+ default:
+ /* Can't happen */
+ ASSERT(0);
+ return 0;
+ }
+}
+
+static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube) {
+ return dma_tube_regs(dev, tube)->SCR & DMA_SCR_EN;
+}
+
+/* F2-only; available because of double-buffering. */
+void dma_set_mem_n_addr(dma_dev *dev, dma_tube tube, int n,
+ __io void *address);
+
+/**
+ * @brief Set memory 0 address.
+ * Availability: STM32F2.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose memory 0 address to set
+ * @param addr Address to use as memory 0
+ */
+static __always_inline void
+dma_set_mem0_addr(dma_dev *dev, dma_tube tube, __io void *addr) {
+ dma_set_mem_n_addr(dev, tube, 0, addr);
+}
+
+/**
+ * @brief Set memory 1 address.
+ * Availability: STM32F2.
+ *
+ * @param dev DMA device
+ * @param tube Tube whose memory 1 address to set
+ * @param addr Address to use as memory 1
+ */
+static __always_inline void
+dma_set_mem1_addr(dma_dev *dev, dma_tube tube, __io void *addr) {
+ dma_set_mem_n_addr(dev, tube, 1, addr);
+}
+
+/* Assume the user means SM0AR in a non-double-buffered configuration. */
+static __always_inline void
+dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *addr) {
+ dma_set_mem0_addr(dev, tube, addr);
+}
+
+/* SM0AR and SM1AR are treated as though they have the same size */
+static inline dma_xfer_size dma_get_mem_size(dma_dev *dev, dma_tube tube) {
+ return (dma_xfer_size)(dma_tube_regs(dev, tube)->SCR >> 13);
+}
+
+static inline dma_xfer_size dma_get_per_size(dma_dev *dev, dma_tube tube) {
+ return (dma_xfer_size)(dma_tube_regs(dev, tube)->SCR >> 11);
+}
+
+void dma_enable_fifo(dma_dev *dev, dma_tube tube);
+void dma_disable_fifo(dma_dev *dev, dma_tube tube);
+
+static __always_inline int dma_is_fifo_enabled(dma_dev *dev, dma_tube tube) {
+ return dma_tube_regs(dev, tube)->SFCR & DMA_SFCR_DMDIS;
+}
+
+/*
+ * TODO:
+ * - Double-buffer configuration function
+ * - FIFO configuration function
+ * - MBURST/PBURST configuration function
+ */
+
+/*
+ * ISR/IFCR conveniences.
+ */
+
+/* (undocumented) helper for reading LISR/HISR and writing
+ * LIFCR/HIFCR. For these registers,
+ *
+ * S0, S4: bits start at bit 0
+ * S1, S5: 6
+ * S2, S6: 16
+ * S3, S7: 22
+ *
+ * I can't imagine why ST didn't just use a byte for each group. The
+ * bits fit, and it would have made functions like these simpler and
+ * faster. Oh well. */
+static __always_inline uint32 _dma_sr_fcr_shift(dma_tube tube) {
+ switch (tube) {
+ case DMA_S0: /* fall through */
+ case DMA_S4:
+ return 0;
+ case DMA_S1: /* fall through */
+ case DMA_S5:
+ return 6;
+ case DMA_S2: /* fall through */
+ case DMA_S6:
+ return 16;
+ case DMA_S3: /* fall through */
+ case DMA_S7:
+ return 22;
+ }
+ /* Can't happen */
+ ASSERT(0);
+ return 0;
+}
+
+static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube) {
+ dma_reg_map *regs = dev->regs;
+ __io uint32 *isr = tube > DMA_S3 ? &regs->HISR : &regs->LISR;
+ return (*isr >> _dma_sr_fcr_shift(tube)) & 0x3D;
+}
+
+static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) {
+ dma_reg_map *regs = dev->regs;
+ __io uint32 *ifcr = tube > DMA_S3 ? &regs->HIFCR : &regs->LIFCR;
+ *ifcr = (0x3D << _dma_sr_fcr_shift(tube));
+}
+
+#undef _DMA_IRQ_BIT_SHIFT
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/exti.h b/libmaple/stm32f2/include/series/exti.h
new file mode 100644
index 0000000..4643fcf
--- /dev/null
+++ b/libmaple/stm32f2/include/series/exti.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * 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/stm32f1/include/series/exti.h
+ * @brief STM32F2 external interrupts
+ */
+
+#ifndef _LIBMAPLE_STM32F2_EXTI_H_
+#define _LIBMAPLE_STM32F2_EXTI_H_
+
+#ifdef __cpluspus
+extern "C" {
+#endif
+
+struct exti_reg_map;
+#define EXTI_BASE ((struct exti_reg_map*)0x40013C00)
+
+#ifdef __cpluspus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/flash.h b/libmaple/stm32f2/include/series/flash.h
new file mode 100644
index 0000000..a3c3933
--- /dev/null
+++ b/libmaple/stm32f2/include/series/flash.h
@@ -0,0 +1,202 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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/flash.h
+ * @brief STM32F2 Flash header.
+ *
+ * Provides register map, base pointer, and register bit definitions
+ * for the Flash controller on the STM32F2 series, along with
+ * series-specific configuration values.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_FLASH_H_
+#define _LIBMAPLE_STM32F2_FLASH_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** @brief STM32F2 Flash register map type */
+typedef struct flash_reg_map {
+ __io uint32 ACR; /**< Access control register */
+ __io uint32 KEYR; /**< Key register */
+ __io uint32 OPTKEYR; /**< Option key register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 CR; /**< Control register */
+ __io uint32 OPTCR; /**< Option control register */
+} flash_reg_map;
+
+#define FLASH_BASE ((struct flash_reg_map*)0x40023C00)
+
+/*
+ * Register bit definitions
+ */
+
+/* Access control register */
+
+#define FLASH_ACR_DCRST_BIT 12
+#define FLASH_ACR_ICRST_BIT 11
+#define FLASH_ACR_DCEN_BIT 10
+#define FLASH_ACR_ICEN_BIT 9
+#define FLASH_ACR_PRFTEN_BIT 8
+
+#define FLASH_ACR_DCRST (1U << FLASH_ACR_DCRST_BIT)
+#define FLASH_ACR_ICRST (1U << FLASH_ACR_ICRST_BIT)
+#define FLASH_ACR_DCEN (1U << FLASH_ACR_DCEN_BIT)
+#define FLASH_ACR_ICEN (1U << FLASH_ACR_ICEN_BIT)
+#define FLASH_ACR_PRFTEN (1U << FLASH_ACR_PRFTEN_BIT)
+#define FLASH_ACR_LATENCY 0x7
+#define FLASH_ACR_LATENCY_0WS 0x0
+#define FLASH_ACR_LATENCY_1WS 0x1
+#define FLASH_ACR_LATENCY_2WS 0x2
+#define FLASH_ACR_LATENCY_3WS 0x3
+#define FLASH_ACR_LATENCY_4WS 0x4
+#define FLASH_ACR_LATENCY_5WS 0x5
+#define FLASH_ACR_LATENCY_6WS 0x6
+#define FLASH_ACR_LATENCY_7WS 0x7
+
+/* Key register */
+
+#define FLASH_KEYR_KEY1 0x45670123
+#define FLASH_KEYR_KEY2 0xCDEF89AB
+
+/* Option key register */
+
+#define FLASH_OPTKEYR_OPTKEY1 0x08192A3B
+#define FLASH_OPTKEYR_OPTKEY2 0x4C5D6E7F
+
+/* Status register */
+
+#define FLASH_SR_BSY_BIT 16
+#define FLASH_SR_PGSERR_BIT 7
+#define FLASH_SR_PGPERR_BIT 6
+#define FLASH_SR_PGAERR_BIT 5
+#define FLASH_SR_WRPERR_BIT 4
+#define FLASH_SR_OPERR_BIT 1
+#define FLASH_SR_EOP_BIT 0
+
+#define FLASH_SR_BSY (1U << FLASH_SR_BSY_BIT)
+#define FLASH_SR_PGSERR (1U << FLASH_SR_PGSERR_BIT)
+#define FLASH_SR_PGPERR (1U << FLASH_SR_PGPERR_BIT)
+#define FLASH_SR_PGAERR (1U << FLASH_SR_PGAERR_BIT)
+#define FLASH_SR_WRPERR (1U << FLASH_SR_WRPERR_BIT)
+#define FLASH_SR_OPERR (1U << FLASH_SR_OPERR_BIT)
+#define FLASH_SR_EOP (1U << FLASH_SR_EOP_BIT)
+
+/* Control register */
+
+#define FLASH_CR_LOCK_BIT 31
+#define FLASH_CR_ERRIE_BIT 25
+#define FLASH_CR_EOPIE_BIT 24
+#define FLASH_CR_STRT_BIT 16
+#define FLASH_CR_MER_BIT 2
+#define FLASH_CR_SER_BIT 1
+#define FLASH_CR_PG_BIT 0
+
+#define FLASH_CR_LOCK (1U << FLASH_CR_LOCK_BIT)
+#define FLASH_CR_ERRIE (1U << FLASH_CR_ERRIE_BIT)
+#define FLASH_CR_EOPIE (1U << FLASH_CR_EOPIE_BIT)
+#define FLASH_CR_STRT (1U << FLASH_CR_STRT_BIT)
+
+#define FLASH_CR_PSIZE (0x3 << 8)
+#define FLASH_CR_PSIZE_MUL8 (0x0 << 8)
+#define FLASH_CR_PSIZE_MUL16 (0x1 << 8)
+#define FLASH_CR_PSIZE_MUL32 (0x2 << 8)
+#define FLASH_CR_PSIZE_MUL64 (0x3 << 8)
+
+#define FLASH_CR_SNB (0xF << 3)
+#define FLASH_CR_SNB_0 (0x0 << 3)
+#define FLASH_CR_SNB_1 (0x1 << 3)
+#define FLASH_CR_SNB_2 (0x2 << 3)
+#define FLASH_CR_SNB_3 (0x3 << 3)
+#define FLASH_CR_SNB_4 (0x4 << 3)
+#define FLASH_CR_SNB_5 (0x5 << 3)
+#define FLASH_CR_SNB_6 (0x6 << 3)
+#define FLASH_CR_SNB_7 (0x7 << 3)
+#define FLASH_CR_SNB_8 (0x8 << 3)
+#define FLASH_CR_SNB_9 (0x9 << 3)
+#define FLASH_CR_SNB_10 (0xA << 3)
+#define FLASH_CR_SNB_11 (0xB << 3)
+
+#define FLASH_CR_MER (1U << FLASH_CR_MER_BIT)
+#define FLASH_CR_SER (1U << FLASH_CR_SER_BIT)
+#define FLASH_CR_PG (1U << FLASH_CR_PG_BIT)
+
+/* Option control register */
+
+#define FLASH_OPTCR_NRST_STDBY_BIT 7
+#define FLASH_OPTCR_NRST_STOP_BIT 6
+#define FLASH_OPTCR_WDG_SW_BIT 5
+#define FLASH_OPTCR_OPTSTRT_BIT 1
+#define FLASH_OPTCR_OPTLOCK_BIT 0
+
+#define FLASH_OPTCR_NWRP (0x3FF << 16)
+
+/* Excluded: The many level 1 values */
+#define FLASH_OPTCR_RDP (0xFF << 8)
+#define FLASH_OPTCR_RDP_LEVEL0 (0xAA << 8)
+#define FLASH_OPTCR_RDP_LEVEL2 (0xCC << 8)
+
+#define FLASH_OPTCR_USER (0x7 << 5)
+#define FLASH_OPTCR_nRST_STDBY (1U << FLASH_OPTCR_nRST_STDBY_BIT)
+#define FLASH_OPTCR_nRST_STOP (1U << FLASH_OPTCR_nRST_STOP_BIT)
+#define FLASH_OPTCR_WDG_SW (1U << FLASH_OPTCR_WDG_SW_BIT)
+
+#define FLASH_OPTCR_BOR_LEV (0x3 << 2)
+#define FLASH_OPTCR_BOR_LEVEL3 (0x0 << 2)
+#define FLASH_OPTCR_BOR_LEVEL2 (0x1 << 2)
+#define FLASH_OPTCR_BOR_LEVEL1 (0x2 << 2)
+#define FLASH_OPTCR_BOR_OFF (0x3 << 2)
+
+#define FLASH_OPTCR_OPTSTRT (1U << FLASH_OPTCR_OPTSTRT_BIT)
+#define FLASH_OPTCR_OPTLOCK (1U << FLASH_OPTCR_OPTLOCK_BIT)
+
+/*
+ * Series-specific configuration values
+ */
+
+/* Note that this value depends on a 2.7V--3.6V supply voltage */
+#define FLASH_SAFE_WAIT_STATES FLASH_WAIT_STATE_3
+
+/* Flash memory features available via ACR. */
+enum {
+ FLASH_PREFETCH = 0x100,
+ FLASH_ICACHE = 0x200,
+ FLASH_DCACHE = 0x400,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/gpio.h b/libmaple/stm32f2/include/series/gpio.h
new file mode 100644
index 0000000..1496e8e
--- /dev/null
+++ b/libmaple/stm32f2/include/series/gpio.h
@@ -0,0 +1,264 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 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/gpio.h
+ * @brief STM32F2 GPIO support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_GPIO_H_
+#define _LIBMAPLE_STM32F2_GPIO_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * GPIO register maps and devices
+ */
+
+/** GPIO register map type */
+typedef struct gpio_reg_map {
+ __io uint32 MODER; /**< Mode register */
+ __io uint32 OTYPER; /**< Output type register */
+ __io uint32 OSPEEDR; /**< Output speed register */
+ __io uint32 PUPDR; /**< Pull-up/pull-down register */
+ __io uint32 IDR; /**< Input data register */
+ __io uint32 ODR; /**< Output data register */
+ __io uint32 BSRR; /**< Bit set/reset register */
+ __io uint32 LCKR; /**< Configuration lock register */
+ __io uint32 AFRL; /**< Alternate function low register */
+ __io uint32 AFRH; /**< Alternate function high register */
+} gpio_reg_map;
+
+/** GPIO port A register map base pointer */
+#define GPIOA_BASE ((struct gpio_reg_map*)0x40020000)
+/** GPIO port B register map base pointer */
+#define GPIOB_BASE ((struct gpio_reg_map*)0x40020400)
+/** GPIO port C register map base pointer */
+#define GPIOC_BASE ((struct gpio_reg_map*)0x40020800)
+/** GPIO port D register map base pointer */
+#define GPIOD_BASE ((struct gpio_reg_map*)0x40020C00)
+/** GPIO port E register map base pointer */
+#define GPIOE_BASE ((struct gpio_reg_map*)0x40021000)
+/** GPIO port F register map base pointer */
+#define GPIOF_BASE ((struct gpio_reg_map*)0x40021400)
+/** GPIO port G register map base pointer */
+#define GPIOG_BASE ((struct gpio_reg_map*)0x40021800)
+/** GPIO port H register map base pointer */
+#define GPIOH_BASE ((struct gpio_reg_map*)0x40021C00)
+/** GPIO port I register map base pointer */
+#define GPIOI_BASE ((struct gpio_reg_map*)0x40022000)
+
+struct gpio_dev;
+extern struct gpio_dev* const GPIOA;
+extern struct gpio_dev gpioa;
+extern struct gpio_dev* const GPIOB;
+extern struct gpio_dev gpiob;
+extern struct gpio_dev* const GPIOC;
+extern struct gpio_dev gpioc;
+extern struct gpio_dev* const GPIOD;
+extern struct gpio_dev gpiod;
+extern struct gpio_dev* const GPIOE;
+extern struct gpio_dev gpioe;
+extern struct gpio_dev* const GPIOF;
+extern struct gpio_dev gpiof;
+extern struct gpio_dev* const GPIOG;
+extern struct gpio_dev gpiog;
+extern struct gpio_dev* const GPIOH;
+extern struct gpio_dev gpioh;
+extern struct gpio_dev* const GPIOI;
+extern struct gpio_dev gpioi;
+
+/*
+ * Register bit definitions
+ *
+ * Currently, we only provide masks to be used for shifting for some
+ * registers, rather than repeating the same values 16 times.
+ */
+
+/* Mode register */
+
+#define GPIO_MODER_INPUT 0x0
+#define GPIO_MODER_OUTPUT 0x1
+#define GPIO_MODER_AF 0x2
+#define GPIO_MODER_ANALOG 0x3
+
+/* Output type register */
+
+#define GPIO_OTYPER_PP 0x0
+#define GPIO_OTYPER_OD 0x1
+
+/* Output speed register */
+
+#define GPIO_OSPEEDR_LOW 0x0
+#define GPIO_OSPEEDR_MED 0x1
+#define GPIO_OSPEEDR_FAST 0x2
+#define GPIO_OSPEEDR_HIGH 0x3
+
+/* Pull-up/pull-down register */
+
+#define GPIO_PUPDR_NOPUPD 0x0
+#define GPIO_PUPDR_PU 0x1
+#define GPIO_PUPDR_PD 0x2
+
+/* Alternate function register low */
+
+#define GPIO_AFRL_AF0 (0xFU << 0)
+#define GPIO_AFRL_AF1 (0xFU << 4)
+#define GPIO_AFRL_AF2 (0xFU << 8)
+#define GPIO_AFRL_AF3 (0xFU << 12)
+#define GPIO_AFRL_AF4 (0xFU << 16)
+#define GPIO_AFRL_AF5 (0xFU << 20)
+#define GPIO_AFRL_AF6 (0xFU << 24)
+#define GPIO_AFRL_AF7 (0xFU << 28)
+
+/* Alternate function register high */
+
+#define GPIO_AFRH_AF8 (0xFU << 0)
+#define GPIO_AFRH_AF9 (0xFU << 4)
+#define GPIO_AFRH_AF10 (0xFU << 8)
+#define GPIO_AFRH_AF11 (0xFU << 12)
+#define GPIO_AFRH_AF12 (0xFU << 16)
+#define GPIO_AFRH_AF13 (0xFU << 20)
+#define GPIO_AFRH_AF14 (0xFU << 24)
+#define GPIO_AFRH_AF15 (0xFU << 28)
+
+/*
+ * GPIO routines
+ */
+
+/**
+ * @brief GPIO pin modes
+ */
+typedef enum gpio_pin_mode {
+ GPIO_MODE_INPUT = GPIO_MODER_INPUT, /**< Input mode */
+ GPIO_MODE_OUTPUT = GPIO_MODER_OUTPUT, /**< Output mode */
+ GPIO_MODE_AF = GPIO_MODER_AF, /**< Alternate function mode */
+ GPIO_MODE_ANALOG = GPIO_MODER_ANALOG, /**< Analog mode */
+} gpio_pin_mode;
+
+/**
+ * @brief Additional flags to be used when setting a pin's mode.
+ *
+ * Beyond the basic modes (input, general purpose output, alternate
+ * function, and analog), there are three parameters that can affect a
+ * pin's mode:
+ *
+ * 1. Output type: push/pull or open-drain. This only has an effect
+ * for output modes. Choices are: GPIO_MODEF_TYPE_PP (the default)
+ * and GPIO_MODEF_TYPE_OD.
+ *
+ * 2. Output speed: specifies the frequency at which a pin changes
+ * state. This only has an effect for output modes. Choices are:
+ * GPIO_MODEF_SPEED_LOW (default), GPIO_MODEF_SPEED_MED,
+ * GPIO_MODEF_SPEED_FAST, and GPIO_MODEF_SPEED_HIGH.
+ *
+ * 3. Push/pull setting: All GPIO pins have weak pull-up and pull-down
+ * resistors that can be enabled when the pin's mode is
+ * set. Choices are: GPIO_MODEF_PUPD_NONE (default),
+ * GPIO_MODEF_PUPD_PU, and GPIO_MODEF_PUPD_PD.
+ */
+typedef enum gpio_mode_flags {
+ /* Output type in bit 0 */
+ GPIO_MODEF_TYPE_PP = GPIO_OTYPER_PP, /**< Output push/pull (default).
+ Applies only when the mode
+ specifies output. */
+ GPIO_MODEF_TYPE_OD = GPIO_OTYPER_OD, /**< Output open drain.
+ Applies only when the mode
+ specifies output. */
+
+ /* Speed in bits 2:1 */
+ GPIO_MODEF_SPEED_LOW = GPIO_OSPEEDR_LOW << 1, /**< Low speed (default):
+ 2 MHz. */
+ GPIO_MODEF_SPEED_MED = GPIO_OSPEEDR_MED << 1, /**< Medium speed: 25 MHz. */
+ GPIO_MODEF_SPEED_FAST = GPIO_OSPEEDR_FAST << 1, /**< Fast speed: 50 MHz. */
+ GPIO_MODEF_SPEED_HIGH = GPIO_OSPEEDR_HIGH << 1, /**< High speed:
+ 100 MHz on 30 pF,
+ 80 MHz on 15 pF. */
+
+ /* Pull-up/pull-down in bits 4:3 */
+ GPIO_MODEF_PUPD_NONE = GPIO_PUPDR_NOPUPD << 3, /**< No pull-up/pull-down
+ (default). */
+ GPIO_MODEF_PUPD_PU = GPIO_PUPDR_PU << 3, /**< Pull-up */
+ GPIO_MODEF_PUPD_PD = GPIO_PUPDR_PD << 3, /**< Pull-down */
+} gpio_mode_flags;
+
+void gpio_set_modef(struct gpio_dev *dev,
+ uint8 bit,
+ gpio_pin_mode mode,
+ unsigned flags);
+
+/**
+ * @brief Set the mode of a GPIO pin.
+ *
+ * Calling this function is equivalent to calling gpio_set_modef(dev,
+ * pin, mode, GPIO_MODE_SPEED_HIGH). Note that this overrides the
+ * default speed.
+ *
+ * @param dev GPIO device.
+ * @param pin Pin on the device whose mode to set, 0--15.
+ * @param mode Mode to set the pin to.
+ */
+static inline void gpio_set_mode(struct gpio_dev *dev,
+ uint8 bit,
+ gpio_pin_mode mode) {
+ gpio_set_modef(dev, bit, mode, GPIO_MODEF_SPEED_HIGH);
+}
+
+/**
+ * @brief GPIO alternate functions.
+ * Use these to select an alternate function for a pin.
+ * @see gpio_set_af()
+ */
+typedef enum gpio_af {
+ GPIO_AF_SYS = 0, /**< System. */
+ GPIO_AF_TIM_1_2 = 1, /**< Timers 1 and 2. */
+ GPIO_AF_TIM_3_4_5 = 2, /**< Timers 3, 4, and 5. */
+ GPIO_AF_TIM_8_9_10_11 = 3, /**< Timers 8 through 11. */
+ GPIO_AF_I2C = 4, /**< I2C 1, 2, and 3. */
+ GPIO_AF_SPI_1_2 = 5, /**< SPI1, SPI2/I2S2. */
+ GPIO_AF_SPI3 = 6, /**< SPI3/I2S3. */
+ GPIO_AF_USART_1_2_3 = 7, /**< USART 1, 2, and 3. */
+ GPIO_AF_USART_4_5_6 = 8, /**< UART 4 and 5, USART 6. */
+ GPIO_AF_CAN_1_2_TIM_12_13_14 = 9, /**<
+ * CAN 1 and 2, timers 12, 13, and 14. */
+ GPIO_AF_USB_OTG_FS_HS = 10, /**< USB OTG HS and FS. */
+ GPIO_AF_ETH = 11, /**< Ethernet MII and RMII. */
+ GPIO_AF_FSMC_SDIO_OTG_FS = 12, /**< FSMC, SDIO, and USB OTG FS. */
+ GPIO_AF_DCMI = 13, /**< DCMI. */
+ GPIO_AF_EVENTOUT = 15, /**< EVENTOUT. */
+} gpio_af;
+
+void gpio_set_af(struct gpio_dev *dev, uint8 bit, gpio_af af);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/nvic.h b/libmaple/stm32f2/include/series/nvic.h
new file mode 100644
index 0000000..dc03806
--- /dev/null
+++ b/libmaple/stm32f2/include/series/nvic.h
@@ -0,0 +1,160 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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/nvic.h
+ * @brief STM32F2 nested vectored interrupt controller (NVIC) header.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_NVIC_H_
+#define _LIBMAPLE_STM32F2_NVIC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/**
+ * @brief STM32F2 interrupt vector table interrupt numbers.
+ */
+typedef enum nvic_irq_num {
+ NVIC_NMI = -14, /**< Non-maskable interrupt */
+ NVIC_HARDFAULT = -13, /**< Hard fault (all class of fault) */
+ NVIC_MEM_MANAGE = -12, /**< Memory management */
+ NVIC_BUS_FAULT = -11, /**< Bus fault: prefetch fault, memory
+ access fault. */
+ NVIC_USAGE_FAULT = -10, /**< Usage fault: Undefined instruction
+ or illegal state. */
+ NVIC_SVC = -5, /**< System service call via SWI
+ instruction */
+ NVIC_DEBUG_MON = -4, /**< Debug monitor */
+ NVIC_PEND_SVC = -2, /**< Pendable request for system
+ service */
+ NVIC_SYSTICK = -1, /**< System tick timer */
+ NVIC_WWDG = 0, /**< Window watchdog interrupt */
+ NVIC_PVD = 1, /**< PVD through EXTI line detection */
+ NVIC_TAMP_STAMP = 2, /**< Tamper and TimeStamp */
+ NVIC_RTC_WKUP = 3, /**< Real-time clock wakeup */
+ NVIC_FLASH = 4, /**< Flash */
+ NVIC_RCC = 5, /**< Reset and clock control */
+ NVIC_EXTI0 = 6, /**< EXTI line 0 */
+ NVIC_EXTI1 = 7, /**< EXTI line 1 */
+ NVIC_EXTI2 = 8, /**< EXTI line 2 */
+ NVIC_EXTI3 = 9, /**< EXTI line 3 */
+ NVIC_EXTI4 = 10, /**< EXTI line 4 */
+ NVIC_DMA1_STREAM0 = 11, /**< DMA1 stream 0 */
+ NVIC_DMA1_STREAM1 = 12, /**< DMA1 stream 1 */
+ NVIC_DMA1_STREAM2 = 13, /**< DMA1 stream 2 */
+ NVIC_DMA1_STREAM3 = 14, /**< DMA1 stream 3 */
+ NVIC_DMA1_STREAM4 = 15, /**< DMA1 stream 4 */
+ NVIC_DMA1_STREAM5 = 16, /**< DMA1 stream 5 */
+ NVIC_DMA1_STREAM6 = 17, /**< DMA1 stream 6 */
+ NVIC_ADC = 18, /**< ADC */
+ NVIC_CAN1_TX = 19, /**< CAN1 TX */
+ NVIC_CAN1_RX0 = 20, /**< CAN1 RX0 */
+ NVIC_CAN1_RX1 = 21, /**< CAN1 RX1 */
+ NVIC_CAN1_SCE = 22, /**< CAN1 SCE */
+ NVIC_EXTI_9_5 = 23, /**< EXTI lines [9:5] */
+ NVIC_TIMER1_BRK_TIMER9 = 24, /**< Timer 1 break and timer 9 */
+ NVIC_TIMER1_UP_TIMER10 = 25, /**< Timer 1 update and timer 10 */
+ NVIC_TIMER1_TRG_COM_TIMER11 = 26, /**< Timer 1 trigger and commutation and
+ timer 11.*/
+ NVIC_TIMER1_CC = 27, /**< Timer 1 capture and compare */
+ NVIC_TIMER2 = 28, /**< Timer 2 */
+ NVIC_TIMER3 = 29, /**< Timer 3 */
+ NVIC_TIMER4 = 30, /**< Timer 4 */
+ NVIC_I2C1_EV = 31, /**< I2C1 event */
+ NVIC_I2C1_ER = 32, /**< I2C2 error */
+ NVIC_I2C2_EV = 33, /**< I2C2 event */
+ NVIC_I2C2_ER = 34, /**< I2C2 error */
+ NVIC_SPI1 = 35, /**< SPI1 */
+ NVIC_SPI2 = 36, /**< SPI2 */
+ NVIC_USART1 = 37, /**< USART1 */
+ NVIC_USART2 = 38, /**< USART2 */
+ NVIC_USART3 = 39, /**< USART3 */
+ NVIC_EXTI_15_10 = 40, /**< EXTI lines [15:10] */
+ NVIC_RTCALARM = 41, /**< RTC alarms A and B through EXTI */
+ NVIC_OTG_FS_WKUP = 42, /**< USB on-the-go full-speed wakeup
+ through EXTI*/
+ NVIC_TIMER8_BRK_TIMER12 = 43, /**< Timer 8 break and timer 12 */
+ NVIC_TIMER8_UP_TIMER13 = 44, /**< Timer 8 update and timer 13 */
+ NVIC_TIMER8_TRG_COM_TIMER14 = 45, /**< Timer 8 trigger and commutation and
+ timer 14 */
+ NVIC_TIMER8_CC = 46, /**< Timer 8 capture and compare */
+ NVIC_DMA1_STREAM7 = 47, /**< DMA1 stream 7 */
+ NVIC_FSMC = 48, /**< FSMC */
+ NVIC_SDIO = 49, /**< SDIO */
+ NVIC_TIMER5 = 50, /**< Timer 5 */
+ NVIC_SPI3 = 51, /**< SPI3 */
+ NVIC_UART4 = 52, /**< UART4 */
+ NVIC_UART5 = 53, /**< UART5 */
+ NVIC_TIMER6_DAC = 54, /**< Timer 6 and DAC underrun */
+ NVIC_TIMER7 = 55, /**< Timer 7 */
+ NVIC_DMA2_STREAM0 = 56, /**< DMA2 stream 0 */
+ NVIC_DMA2_STREAM1 = 57, /**< DMA2 stream 1 */
+ NVIC_DMA2_STREAM2 = 58, /**< DMA2 stream 2 */
+ NVIC_DMA2_STREAM3 = 59, /**< DMA2 stream 3 */
+ NVIC_DMA2_STREAM4 = 60, /**< DMA2 stream 4 */
+ NVIC_ETH = 61, /**< Ethernet */
+ NVIC_ETH_WKUP = 62, /**< Ethernet wakeup through EXTI */
+ NVIC_CAN2_TX = 63, /**< CAN2 TX */
+ NVIC_CAN2_RX0 = 64, /**< CAN2 RX0 */
+ NVIC_CAN2_RX1 = 65, /**< CAN2 RX1 */
+ NVIC_CAN2_SCE = 66, /**< CAN2 SCE */
+ NVIC_OTG_FS = 67, /**< USB on-the-go full-speed */
+ NVIC_DMA2_STREAM5 = 68, /**< DMA2 stream 5 */
+ NVIC_DMA2_STREAM6 = 69, /**< DMA2 stream 6 */
+ NVIC_DMA2_STREAM7 = 70, /**< DMA2 stream 7 */
+ NVIC_USART6 = 71, /**< USART6 */
+ NVIC_I2C3_EV = 72, /**< I2C3 event */
+ NVIC_I2C3_ER = 73, /**< I2C3 error */
+ NVIC_OTG_HS_EP1_OUT = 74, /**< USB on-the-go high-speed
+ endpoint 1 OUT */
+ NVIC_OTG_HS_EP1_IN = 75, /**< USB on-the-go high-speed
+ endpoint 1 IN */
+ NVIC_OTG_HS_WKUP = 76, /**< USB on-the-go high-speed wakeup
+ through EXTI*/
+ NVIC_OTG_HS = 77, /**< USB on-the-go high-speed */
+ NVIC_DCMI = 78, /**< DCMI */
+ NVIC_CRYP = 79, /**< Cryptographic processor */
+ NVIC_HASH_RNG = 80, /**< Hash and random number
+ generation */
+
+ /* Fake enumerator values, for compatiblity with F1.
+ * TODO decide if this is actually a good idea. */
+ NVIC_TIMER6 = NVIC_TIMER6_DAC, /**< For compatibility with STM32F1. */
+} nvic_irq_num;
+
+static inline void nvic_irq_disable_all(void) {
+ NVIC_BASE->ICER[0] = 0xFFFFFFFF;
+ NVIC_BASE->ICER[1] = 0xFFFFFFFF;
+ NVIC_BASE->ICER[2] = 0xFFFFFFFF;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/pwr.h b/libmaple/stm32f2/include/series/pwr.h
new file mode 100644
index 0000000..96353a4
--- /dev/null
+++ b/libmaple/stm32f2/include/series/pwr.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * 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/pwr.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 Power control (PWR) support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_PWR_H_
+#define _LIBMAPLE_STM32F2_PWR_H_
+
+/*
+ * Additional register bits
+ */
+
+/* Control register */
+
+/**
+ * @brief Flash power down in stop mode bit.
+ * Availability: STM32F2 */
+#define PWR_CR_FPDS_BIT 9
+/**
+ * @brief Flash power down in stop mode.
+ * Availability: STM32F2 */
+#define PWR_CR_FPDS (1U << PWR_CR_FPDS_BIT)
+
+/* PVD level selection */
+#define PWR_CR_PLS_2_0V (0x0 << 5)
+#define PWR_CR_PLS_2_1V (0x1 << 5)
+#define PWR_CR_PLS_2_3V (0x2 << 5)
+#define PWR_CR_PLS_2_5V (0x3 << 5)
+#define PWR_CR_PLS_2_6V (0x4 << 5)
+#define PWR_CR_PLS_2_7V (0x5 << 5)
+#define PWR_CR_PLS_2_8V (0x6 << 5)
+#define PWR_CR_PLS_2_9V (0x7 << 5)
+
+/* Control/Status register */
+
+/** Backup regulator enable bit. */
+#define PWR_CSR_BRE_BIT 9
+/** Backup regulator ready bit. */
+#define PWR_CSR_BRR_BIT 3
+
+/** Backup regulator enable. */
+#define PWR_CSR_BRE (1U << PWR_CSR_BRE_BIT)
+/** Backup regulator ready. */
+#define PWR_CSR_BRR (1U << PWR_CSR_BRR_BIT)
+
+#endif
diff --git a/libmaple/stm32f2/include/series/rcc.h b/libmaple/stm32f2/include/series/rcc.h
new file mode 100644
index 0000000..441a5a8
--- /dev/null
+++ b/libmaple/stm32f2/include/series/rcc.h
@@ -0,0 +1,951 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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/rcc.h
+ * @brief STM32F2 reset and clock control (RCC) support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_RCC_H_
+#define _LIBMAPLE_STM32F2_RCC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** STM32F2 RCC register map type */
+typedef struct rcc_reg_map {
+ __io uint32 CR; /**< Clock control register */
+ __io uint32 PLLCFGR; /**< PLL configuration register */
+ __io uint32 CFGR; /**< Clock configuration register */
+ __io uint32 CIR; /**< Clock interrupt register */
+ __io uint32 AHB1RSTR; /**< AHB1 peripheral reset register */
+ __io uint32 AHB2RSTR; /**< AHB2 peripheral reset register */
+ __io uint32 AHB3RSTR; /**< AHB3 peripheral reset register */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 APB1RSTR; /**< APB1 peripheral reset register */
+ __io uint32 APB2RSTR; /**< APB2 peripheral reset register */
+ const uint32 RESERVED2; /**< Reserved */
+ const uint32 RESERVED3; /**< Reserved */
+ __io uint32 AHB1ENR; /**< AHB1 peripheral clock enable register */
+ __io uint32 AHB2ENR; /**< AHB2 peripheral clock enable register */
+ __io uint32 AHB3ENR; /**< AHB3 peripheral clock enable register */
+ const uint32 RESERVED4; /**< Reserved */
+ __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */
+ __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */
+ const uint32 RESERVED5; /**< Reserved */
+ const uint32 RESERVED6; /**< Reserved */
+ __io uint32 AHB1LPENR; /**< AHB1 peripheral clock enable in
+ low power mode register */
+ __io uint32 AHB2LPENR; /**< AHB2 peripheral clock enable in
+ low power mode register */
+ __io uint32 AHB3LPENR; /**< AHB3 peripheral clock enable in
+ low power mode register */
+ const uint32 RESERVED7; /**< Reserved */
+ __io uint32 APB1LPENR; /**< APB1 peripheral clock enable in
+ low power mode register */
+ __io uint32 APB2LPENR; /**< APB2 peripheral clock enable in
+ low power mode register */
+ const uint32 RESERVED8; /**< Reserved */
+ const uint32 RESERVED9; /**< Reserved */
+ __io uint32 BDCR; /**< Backup domain control register */
+ __io uint32 CSR; /**< Clock control and status register */
+ const uint32 RESERVED10; /**< Reserved */
+ const uint32 RESERVED11; /**< Reserved */
+ __io uint32 SSCGR; /**< Spread spectrum clock generation
+ register */
+ __io uint32 PLLI2SCFGR; /**< PLLI2S configuration register */
+} rcc_reg_map;
+
+#define RCC_BASE ((struct rcc_reg_map*)0x40023800)
+
+/*
+ * Register bit definitions
+ */
+
+/* Clock control register */
+
+#define RCC_CR_PLLI2SRDY_BIT 27
+#define RCC_CR_PLLI2SON_BIT 26
+#define RCC_CR_PLLRDY_BIT 25
+#define RCC_CR_PLLON_BIT 24
+#define RCC_CR_CSSON_BIT 19
+#define RCC_CR_HSEBYP_BIT 18
+#define RCC_CR_HSERDY_BIT 17
+#define RCC_CR_HSEON_BIT 16
+#define RCC_CR_HSIRDY_BIT 1
+#define RCC_CR_HSION_BIT 0
+
+#define RCC_CR_PLLI2SRDY (1U << RCC_CR_PLLI2SRDY_BIT)
+#define RCC_CR_PLLI2SON (1U << RCC_CR_PLLI2SON_BIT)
+#define RCC_CR_PLLRDY (1U << RCC_CR_PLLRDY_BIT)
+#define RCC_CR_PLLON (1U << RCC_CR_PLLON_BIT)
+#define RCC_CR_CSSON (1U << RCC_CR_CSSON_BIT)
+#define RCC_CR_HSEBYP (1U << RCC_CR_HSEBYP_BIT)
+#define RCC_CR_HSERDY (1U << RCC_CR_HSERDY_BIT)
+#define RCC_CR_HSEON (1U << RCC_CR_HSEON_BIT)
+#define RCC_CR_HSICAL (0xFF << 8)
+#define RCC_CR_HSITRIM (0x1F << 3)
+#define RCC_CR_HSIRDY (1U << RCC_CR_HSIRDY_BIT)
+#define RCC_CR_HSION (1U << RCC_CR_HSION_BIT)
+
+/* PLL configuration register */
+
+#define RCC_PLLCFGR_PLLSRC_BIT 22
+
+#define RCC_PLLCFGR_PLLQ (0xF << 24)
+#define RCC_PLLCFGR_PLLSRC (1U << RCC_PLLCFGR_PLLSRC_BIT)
+#define RCC_PLLCFGR_PLLSRC_HSI (0x0 << RCC_PLLCFGR_PLLSRC_BIT)
+#define RCC_PLLCFGR_PLLSRC_HSE (0x1 << RCC_PLLCFGR_PLLSRC_BIT)
+#define RCC_PLLCFGR_PLLP (0x3 << 16)
+#define RCC_PLLCFGR_PLLN (0x1FF << 6)
+#define RCC_PLLCFGR_PLLM 0x1F
+
+/* Clock configuration register */
+
+#define RCC_CFGR_I2SSRC_BIT 23
+
+#define RCC_CFGR_MCO2 (0x3 << 30)
+#define RCC_CFGR_MCO2_SYSCLK (0x0 << 30)
+#define RCC_CFGR_MCO2_PLLI2S (0x1 << 30)
+#define RCC_CFGR_MCO2_HSE (0x2 << 30)
+#define RCC_CFGR_MCO2_PLL (0x3 << 30)
+
+#define RCC_CFGR_MCO2PRE (0x7 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_1 (0x0 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_2 (0x4 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_3 (0x5 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_4 (0x6 << 27)
+#define RCC_CFGR_MCO2PRE_DIV_5 (0x7 << 27)
+
+#define RCC_CFGR_MCO1PRE (0x7 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_1 (0x0 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_2 (0x4 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_3 (0x5 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_4 (0x6 << 24)
+#define RCC_CFGR_MCO1PRE_DIV_5 (0x7 << 24)
+
+#define RCC_CFGR_I2SSRC (1U << RCC_CFGR_I2SSRC_BIT)
+#define RCC_CFGR_I2SSRC_PLLI2S (0 << RCC_CFGR_I2SSRC_BIT)
+#define RCC_CFGR_I2SSRC_I2S_CKIN (1 << RCC_CFGR_I2SSRC_BIT)
+
+#define RCC_CFGR_MCO1 (0x3 << 21)
+#define RCC_CFGR_MCO1_HSI (0x0 << 21)
+#define RCC_CFGR_MCO1_LSE (0x1 << 21)
+#define RCC_CFGR_MCO1_HSE (0x2 << 21)
+#define RCC_CFGR_MCO1_PLL (0x3 << 21)
+
+#define RCC_CFGR_RTCPRE (0x1F << 16)
+
+/* Skipped: all the 0b0xx values meaning "not divided" */
+#define RCC_CFGR_PPRE2 (0x7 << 13)
+#define RCC_CFGR_PPRE2_AHB_DIV_2 (0x4 << 13)
+#define RCC_CFGR_PPRE2_AHB_DIV_4 (0x5 << 13)
+#define RCC_CFGR_PPRE2_AHB_DIV_8 (0x6 << 13)
+#define RCC_CFGR_PPRE2_AHB_DIV_16 (0x7 << 13)
+
+/* Skipped: all the 0b0xx values meaning "not divided" */
+#define RCC_CFGR_PPRE1 (0x7 << 10)
+#define RCC_CFGR_PPRE1_AHB_DIV_2 (0x4 << 10)
+#define RCC_CFGR_PPRE1_AHB_DIV_4 (0x5 << 10)
+#define RCC_CFGR_PPRE1_AHB_DIV_8 (0x6 << 10)
+#define RCC_CFGR_PPRE1_AHB_DIV_16 (0x7 << 10)
+
+/* Skipped: all the 0b0xxx values meaning "not divided" */
+#define RCC_CFGR_HPRE (0xF << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_2 (0x8 << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_4 (0x9 << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_8 (0xA << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_16 (0xB << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_64 (0xC << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_128 (0xD << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_256 (0xE << 4)
+#define RCC_CFGR_HPRE_SYSCLK_DIV_512 (0xF << 4)
+
+#define RCC_CFGR_SWS (0x3 << 2)
+#define RCC_CFGR_SWS_HSI (0x0 << 2)
+#define RCC_CFGR_SWS_HSE (0x1 << 2)
+#define RCC_CFGR_SWS_PLL (0x2 << 2)
+
+#define RCC_CFGR_SW 0x3
+#define RCC_CFGR_SW_HSI 0x0
+#define RCC_CFGR_SW_HSE 0x1
+#define RCC_CFGR_SW_PLL 0x2
+
+/* Clock interrupt register */
+
+#define RCC_CIR_CSSC_BIT 23
+
+#define RCC_CIR_PLLI2SRDYC_BIT 21
+#define RCC_CIR_PLLRDYC_BIT 20
+#define RCC_CIR_HSERDYC_BIT 19
+#define RCC_CIR_HSIRDYC_BIT 18
+#define RCC_CIR_LSERDYC_BIT 17
+#define RCC_CIR_LSIRDYC_BIT 16
+
+#define RCC_CIR_PLLI2SRDYIE_BIT 13
+#define RCC_CIR_PLLRDYIE_BIT 12
+#define RCC_CIR_HSERDYIE_BIT 11
+#define RCC_CIR_HSIRDYIE_BIT 10
+#define RCC_CIR_LSERDYIE_BIT 9
+#define RCC_CIR_LSIRDYIE_BIT 8
+
+#define RCC_CIR_CSSF_BIT 7
+
+#define RCC_CIR_PLLI2SRDYF_BIT 5
+#define RCC_CIR_PLLRDYF_BIT 4
+#define RCC_CIR_HSERDYF_BIT 3
+#define RCC_CIR_HSIRDYF_BIT 2
+#define RCC_CIR_LSERDYF_BIT 1
+#define RCC_CIR_LSIRDYF_BIT 0
+
+#define RCC_CIR_CSSC (1U << RCC_CIR_CSSC_BIT)
+
+#define RCC_CIR_PLLI2SRDYC (1U << RCC_CIR_PLLI2SRDYC_BIT)
+#define RCC_CIR_PLLRDYC (1U << RCC_CIR_PLLRDYC_BIT)
+#define RCC_CIR_HSERDYC (1U << RCC_CIR_HSERDYC_BIT)
+#define RCC_CIR_HSIRDYC (1U << RCC_CIR_HSIRDYC_BIT)
+#define RCC_CIR_LSERDYC (1U << RCC_CIR_LSERDYC_BIT)
+#define RCC_CIR_LSIRDYC (1U << RCC_CIR_LSIRDYC_BIT)
+
+#define RCC_CIR_PLLI2SRDYIE (1U << RCC_CIR_PLLI2SRDYIE_BIT)
+#define RCC_CIR_PLLRDYIE (1U << RCC_CIR_PLLRDYIE_BIT)
+#define RCC_CIR_HSERDYIE (1U << RCC_CIR_HSERDYIE_BIT)
+#define RCC_CIR_HSIRDYIE (1U << RCC_CIR_HSIRDYIE_BIT)
+#define RCC_CIR_LSERDYIE (1U << RCC_CIR_LSERDYIE_BIT)
+#define RCC_CIR_LSIRDYIE (1U << RCC_CIR_LSIRDYIE_BIT)
+
+#define RCC_CIR_CSSF (1U << RCC_CIR_CSSF_BIT)
+
+#define RCC_CIR_PLLI2SRDYF (1U << RCC_CIR_PLLI2SRDYF_BIT)
+#define RCC_CIR_PLLRDYF (1U << RCC_CIR_PLLRDYF_BIT)
+#define RCC_CIR_HSERDYF (1U << RCC_CIR_HSERDYF_BIT)
+#define RCC_CIR_HSIRDYF (1U << RCC_CIR_HSIRDYF_BIT)
+#define RCC_CIR_LSERDYF (1U << RCC_CIR_LSERDYF_BIT)
+#define RCC_CIR_LSIRDYF (1U << RCC_CIR_LSIRDYF_BIT)
+
+/* AHB1 peripheral reset register */
+
+#define RCC_AHB1RSTR_OTGHSRST_BIT 29
+#define RCC_AHB1RSTR_ETHMACRST_BIT 25
+#define RCC_AHB1RSTR_DMA2RST_BIT 22
+#define RCC_AHB1RSTR_DMA1RST_BIT 21
+#define RCC_AHB1RSTR_CRCRST_BIT 12
+#define RCC_AHB1RSTR_GPIOIRST_BIT 8
+#define RCC_AHB1RSTR_GPIOHRST_BIT 7
+#define RCC_AHB1RSTR_GPIOGRST_BIT 6
+#define RCC_AHB1RSTR_GPIOFRST_BIT 5
+#define RCC_AHB1RSTR_GPIOERST_BIT 4
+#define RCC_AHB1RSTR_GPIODRST_BIT 3
+#define RCC_AHB1RSTR_GPIOCRST_BIT 2
+#define RCC_AHB1RSTR_GPIOBRST_BIT 1
+#define RCC_AHB1RSTR_GPIOARST_BIT 0
+
+#define RCC_AHB1RSTR_OTGHSRST (1U << RCC_AHB1RSTR_OTGHSRST_BIT)
+#define RCC_AHB1RSTR_ETHMACRST (1U << RCC_AHB1RSTR_ETHMACRST_BIT)
+#define RCC_AHB1RSTR_DMA2RST (1U << RCC_AHB1RSTR_DMA2RST_BIT)
+#define RCC_AHB1RSTR_DMA1RST (1U << RCC_AHB1RSTR_DMA1RST_BIT)
+#define RCC_AHB1RSTR_CRCRST (1U << RCC_AHB1RSTR_CRCRST_BIT)
+#define RCC_AHB1RSTR_GPIOIRST (1U << RCC_AHB1RSTR_GPIOIRST_BIT)
+#define RCC_AHB1RSTR_GPIOHRST (1U << RCC_AHB1RSTR_GPIOHRST_BIT)
+#define RCC_AHB1RSTR_GPIOGRST (1U << RCC_AHB1RSTR_GPIOGRST_BIT)
+#define RCC_AHB1RSTR_GPIOFRST (1U << RCC_AHB1RSTR_GPIOFRST_BIT)
+#define RCC_AHB1RSTR_GPIOERST (1U << RCC_AHB1RSTR_GPIOERST_BIT)
+#define RCC_AHB1RSTR_GPIODRST (1U << RCC_AHB1RSTR_GPIODRST_BIT)
+#define RCC_AHB1RSTR_GPIOCRST (1U << RCC_AHB1RSTR_GPIOCRST_BIT)
+#define RCC_AHB1RSTR_GPIOBRST (1U << RCC_AHB1RSTR_GPIOBRST_BIT)
+#define RCC_AHB1RSTR_GPIOARST (1U << RCC_AHB1RSTR_GPIOARST_BIT)
+
+/* AHB2 peripheral reset register */
+
+#define RCC_AHB2RSTR_OTGFSRST_BIT 7
+#define RCC_AHB2RSTR_RNGRST_BIT 6
+#define RCC_AHB2RSTR_HASHRST_BIT 5
+#define RCC_AHB2RSTR_CRYPRST_BIT 4
+#define RCC_AHB2RSTR_DCMIRST_BIT 0
+
+#define RCC_AHB2RSTR_OTGFSRST (1U << RCC_AHB2RSTR_OTGFSRST_BIT)
+#define RCC_AHB2RSTR_RNGRST (1U << RCC_AHB2RSTR_RNGRST_BIT)
+#define RCC_AHB2RSTR_HASHRST (1U << RCC_AHB2RSTR_HASHRST_BIT)
+#define RCC_AHB2RSTR_CRYPRST (1U << RCC_AHB2RSTR_CRYPRST_BIT)
+#define RCC_AHB2RSTR_DCMIRST (1U << RCC_AHB2RSTR_DCMIRST_BIT)
+
+/* AHB3 peripheral reset register */
+
+#define RCC_AHB3RSTR_FSMCRST_BIT 0
+
+#define RCC_AHB3RSTR_FSMCRST (1U << RCC_AHB3RSTR_FSMCRST_BIT)
+
+/* APB1 peripheral reset register */
+
+#define RCC_APB1RSTR_DACRST_BIT 29
+#define RCC_APB1RSTR_PWRRST_BIT 28
+#define RCC_APB1RSTR_CAN2RST_BIT 26
+#define RCC_APB1RSTR_CAN1RST_BIT 25
+#define RCC_APB1RSTR_I2C3RST_BIT 23
+#define RCC_APB1RSTR_I2C2RST_BIT 22
+#define RCC_APB1RSTR_I2C1RST_BIT 21
+#define RCC_APB1RSTR_UART5RST_BIT 20
+#define RCC_APB1RSTR_UART4RST_BIT 19
+#define RCC_APB1RSTR_UART3RST_BIT 18
+#define RCC_APB1RSTR_UART2RST_BIT 17
+#define RCC_APB1RSTR_SPI3RST_BIT 15
+#define RCC_APB1RSTR_SPI2RST_BIT 14
+#define RCC_APB1RSTR_WWDGRST_BIT 11
+#define RCC_APB1RSTR_TIM14RST_BIT 8
+#define RCC_APB1RSTR_TIM13RST_BIT 7
+#define RCC_APB1RSTR_TIM12RST_BIT 6
+#define RCC_APB1RSTR_TIM7RST_BIT 5
+#define RCC_APB1RSTR_TIM6RST_BIT 4
+#define RCC_APB1RSTR_TIM5RST_BIT 3
+#define RCC_APB1RSTR_TIM4RST_BIT 2
+#define RCC_APB1RSTR_TIM3RST_BIT 1
+#define RCC_APB1RSTR_TIM2RST_BIT 0
+
+#define RCC_APB1RSTR_DACRST (1U << RCC_APB1RSTR_DACRST_BIT)
+#define RCC_APB1RSTR_PWRRST (1U << RCC_APB1RSTR_PWRRST_BIT)
+#define RCC_APB1RSTR_CAN2RST (1U << RCC_APB1RSTR_CAN2RST_BIT)
+#define RCC_APB1RSTR_CAN1RST (1U << RCC_APB1RSTR_CAN1RST_BIT)
+#define RCC_APB1RSTR_I2C3RST (1U << RCC_APB1RSTR_I2C3RST_BIT)
+#define RCC_APB1RSTR_I2C2RST (1U << RCC_APB1RSTR_I2C2RST_BIT)
+#define RCC_APB1RSTR_I2C1RST (1U << RCC_APB1RSTR_I2C1RST_BIT)
+#define RCC_APB1RSTR_UART5RST (1U << RCC_APB1RSTR_UART5RST_BIT)
+#define RCC_APB1RSTR_UART4RST (1U << RCC_APB1RSTR_UART4RST_BIT)
+#define RCC_APB1RSTR_UART3RST (1U << RCC_APB1RSTR_UART3RST_BIT)
+#define RCC_APB1RSTR_UART2RST (1U << RCC_APB1RSTR_UART2RST_BIT)
+#define RCC_APB1RSTR_SPI3RST (1U << RCC_APB1RSTR_SPI3RST_BIT)
+#define RCC_APB1RSTR_SPI2RST (1U << RCC_APB1RSTR_SPI2RST_BIT)
+#define RCC_APB1RSTR_WWDGRST (1U << RCC_APB1RSTR_WWDGRST_BIT)
+#define RCC_APB1RSTR_TIM14RST (1U << RCC_APB1RSTR_TIM14RST_BIT)
+#define RCC_APB1RSTR_TIM13RST (1U << RCC_APB1RSTR_TIM13RST_BIT)
+#define RCC_APB1RSTR_TIM12RST (1U << RCC_APB1RSTR_TIM12RST_BIT)
+#define RCC_APB1RSTR_TIM7RST (1U << RCC_APB1RSTR_TIM7RST_BIT)
+#define RCC_APB1RSTR_TIM6RST (1U << RCC_APB1RSTR_TIM6RST_BIT)
+#define RCC_APB1RSTR_TIM5RST (1U << RCC_APB1RSTR_TIM5RST_BIT)
+#define RCC_APB1RSTR_TIM4RST (1U << RCC_APB1RSTR_TIM4RST_BIT)
+#define RCC_APB1RSTR_TIM3RST (1U << RCC_APB1RSTR_TIM3RST_BIT)
+#define RCC_APB1RSTR_TIM2RST (1U << RCC_APB1RSTR_TIM2RST_BIT)
+
+/* APB2 peripheral reset register */
+
+#define RCC_APB2RSTR_TIM11RST_BIT 18
+#define RCC_APB2RSTR_TIM10RST_BIT 17
+#define RCC_APB2RSTR_TIM9RST_BIT 16
+#define RCC_APB2RSTR_SYSCFGRST_BIT 14
+#define RCC_APB2RSTR_SPI1RST_BIT 12
+#define RCC_APB2RSTR_SDIORST_BIT 11
+#define RCC_APB2RSTR_ADCRST_BIT 8
+#define RCC_APB2RSTR_USART6RST_BIT 5
+#define RCC_APB2RSTR_USART1RST_BIT 4
+#define RCC_APB2RSTR_TIM8RST_BIT 1
+#define RCC_APB2RSTR_TIM1RST_BIT 0
+
+#define RCC_APB2RSTR_TIM11RST (1U << RCC_APB2RSTR_TIM11RST_BIT)
+#define RCC_APB2RSTR_TIM10RST (1U << RCC_APB2RSTR_TIM10RST_BIT)
+#define RCC_APB2RSTR_TIM9RST (1U << RCC_APB2RSTR_TIM9RST_BIT)
+#define RCC_APB2RSTR_SYSCFGRST (1U << RCC_APB2RSTR_SYSCFGRST_BIT)
+#define RCC_APB2RSTR_SPI1RST (1U << RCC_APB2RSTR_SPI1RST_BIT)
+#define RCC_APB2RSTR_SDIORST (1U << RCC_APB2RSTR_SDIORST_BIT)
+#define RCC_APB2RSTR_ADCRST (1U << RCC_APB2RSTR_ADCRST_BIT)
+#define RCC_APB2RSTR_USART6RST (1U << RCC_APB2RSTR_USART6RST_BIT)
+#define RCC_APB2RSTR_USART1RST (1U << RCC_APB2RSTR_USART1RST_BIT)
+#define RCC_APB2RSTR_TIM8RST (1U << RCC_APB2RSTR_TIM8RST_BIT)
+#define RCC_APB2RSTR_TIM1RST (1U << RCC_APB2RSTR_TIM1RST_BIT)
+
+/* AHB1 peripheral clock enable register */
+
+#define RCC_AHB1ENR_OTGHSULPIEN_BIT 30
+#define RCC_AHB1ENR_OTGHSEN_BIT 29
+#define RCC_AHB1ENR_ETHMACPTPEN_BIT 28
+#define RCC_AHB1ENR_ETHMACRXEN_BIT 27
+#define RCC_AHB1ENR_ETHMACTXEN_BIT 26
+#define RCC_AHB1ENR_ETHMACEN_BIT 25
+#define RCC_AHB1ENR_DMA2EN_BIT 22
+#define RCC_AHB1ENR_DMA1EN_BIT 21
+#define RCC_AHB1ENR_BKPSRAMEN_BIT 18
+#define RCC_AHB1ENR_CRCEN_BIT 12
+#define RCC_AHB1ENR_GPIOIEN_BIT 8
+#define RCC_AHB1ENR_GPIOHEN_BIT 7
+#define RCC_AHB1ENR_GPIOGEN_BIT 6
+#define RCC_AHB1ENR_GPIOFEN_BIT 5
+#define RCC_AHB1ENR_GPIOEEN_BIT 4
+#define RCC_AHB1ENR_GPIODEN_BIT 3
+#define RCC_AHB1ENR_GPIOCEN_BIT 2
+#define RCC_AHB1ENR_GPIOBEN_BIT 1
+#define RCC_AHB1ENR_GPIOAEN_BIT 0
+
+#define RCC_AHB1ENR_OTGHSULPIEN (1U << RCC_AHB1ENR_OTGHSULPIEN_BIT)
+#define RCC_AHB1ENR_OTGHSEN (1U << RCC_AHB1ENR_OTGHSEN_BIT)
+#define RCC_AHB1ENR_ETHMACPTPEN (1U << RCC_AHB1ENR_ETHMACPTPEN_BIT)
+#define RCC_AHB1ENR_ETHMACRXEN (1U << RCC_AHB1ENR_ETHMACRXEN_BIT)
+#define RCC_AHB1ENR_ETHMACTXEN (1U << RCC_AHB1ENR_ETHMACTXEN_BIT)
+#define RCC_AHB1ENR_ETHMACEN (1U << RCC_AHB1ENR_ETHMACEN_BIT)
+#define RCC_AHB1ENR_DMA2EN (1U << RCC_AHB1ENR_DMA2EN_BIT)
+#define RCC_AHB1ENR_DMA1EN (1U << RCC_AHB1ENR_DMA1EN_BIT)
+#define RCC_AHB1ENR_BKPSRAMEN (1U << RCC_AHB1ENR_BKPSRAMEN_BIT)
+#define RCC_AHB1ENR_CRCEN (1U << RCC_AHB1ENR_CRCEN_BIT)
+#define RCC_AHB1ENR_GPIOIEN (1U << RCC_AHB1ENR_GPIOIEN_BIT)
+#define RCC_AHB1ENR_GPIOHEN (1U << RCC_AHB1ENR_GPIOHEN_BIT)
+#define RCC_AHB1ENR_GPIOGEN (1U << RCC_AHB1ENR_GPIOGEN_BIT)
+#define RCC_AHB1ENR_GPIOFEN (1U << RCC_AHB1ENR_GPIOFEN_BIT)
+#define RCC_AHB1ENR_GPIOEEN (1U << RCC_AHB1ENR_GPIOEEN_BIT)
+#define RCC_AHB1ENR_GPIODEN (1U << RCC_AHB1ENR_GPIODEN_BIT)
+#define RCC_AHB1ENR_GPIOCEN (1U << RCC_AHB1ENR_GPIOCEN_BIT)
+#define RCC_AHB1ENR_GPIOBEN (1U << RCC_AHB1ENR_GPIOBEN_BIT)
+#define RCC_AHB1ENR_GPIOAEN (1U << RCC_AHB1ENR_GPIOAEN_BIT)
+
+/* AHB2 peripheral clock enable register */
+
+#define RCC_AHB2ENR_OTGFSEN_BIT 7
+#define RCC_AHB2ENR_RNGEN_BIT 6
+#define RCC_AHB2ENR_HASHEN_BIT 5
+#define RCC_AHB2ENR_CRYPEN_BIT 4
+#define RCC_AHB2ENR_DCMIEN_BIT 0
+
+#define RCC_AHB2ENR_OTGFSEN (1U << RCC_AHB2ENR_OTGFSEN_BIT)
+#define RCC_AHB2ENR_RNGEN (1U << RCC_AHB2ENR_RNGEN_BIT)
+#define RCC_AHB2ENR_HASHEN (1U << RCC_AHB2ENR_HASHEN_BIT)
+#define RCC_AHB2ENR_CRYPEN (1U << RCC_AHB2ENR_CRYPEN_BIT)
+#define RCC_AHB2ENR_DCMIEN (1U << RCC_AHB2ENR_DCMIEN_BIT)
+
+/* AHB3 peripheral clock enable register */
+
+#define RCC_AHB3ENR_FSMCEN_BIT 0
+
+#define RCC_AHB3ENR_FSMCEN (1U << RCC_AHB3ENR_FSMCEN_BIT)
+
+/* APB1 peripheral clock enable register */
+
+#define RCC_APB1ENR_DACEN_BIT 29
+#define RCC_APB1ENR_PWREN_BIT 28
+#define RCC_APB1ENR_CAN2EN_BIT 26
+#define RCC_APB1ENR_CAN1EN_BIT 25
+#define RCC_APB1ENR_I2C3EN_BIT 23
+#define RCC_APB1ENR_I2C2EN_BIT 22
+#define RCC_APB1ENR_I2C1EN_BIT 21
+#define RCC_APB1ENR_UART5EN_BIT 20
+#define RCC_APB1ENR_UART4EN_BIT 19
+#define RCC_APB1ENR_USART3EN_BIT 18
+#define RCC_APB1ENR_USART2EN_BIT 17
+#define RCC_APB1ENR_SPI3EN_BIT 15
+#define RCC_APB1ENR_SPI2EN_BIT 14
+#define RCC_APB1ENR_WWDGEN_BIT 11
+#define RCC_APB1ENR_TIM14EN_BIT 8
+#define RCC_APB1ENR_TIM13EN_BIT 7
+#define RCC_APB1ENR_TIM12EN_BIT 6
+#define RCC_APB1ENR_TIM7EN_BIT 5
+#define RCC_APB1ENR_TIM6EN_BIT 4
+#define RCC_APB1ENR_TIM5EN_BIT 3
+#define RCC_APB1ENR_TIM4EN_BIT 2
+#define RCC_APB1ENR_TIM3EN_BIT 1
+#define RCC_APB1ENR_TIM2EN_BIT 0
+
+#define RCC_APB1ENR_DACEN (1U << RCC_APB1ENR_DACEN_BIT)
+#define RCC_APB1ENR_PWREN (1U << RCC_APB1ENR_PWREN_BIT)
+#define RCC_APB1ENR_CAN2EN (1U << RCC_APB1ENR_CAN2EN_BIT)
+#define RCC_APB1ENR_CAN1EN (1U << RCC_APB1ENR_CAN1EN_BIT)
+#define RCC_APB1ENR_I2C3EN (1U << RCC_APB1ENR_I2C3EN_BIT)
+#define RCC_APB1ENR_I2C2EN (1U << RCC_APB1ENR_I2C2EN_BIT)
+#define RCC_APB1ENR_I2C1EN (1U << RCC_APB1ENR_I2C1EN_BIT)
+#define RCC_APB1ENR_UART5EN (1U << RCC_APB1ENR_UART5EN_BIT)
+#define RCC_APB1ENR_UART4EN (1U << RCC_APB1ENR_UART4EN_BIT)
+#define RCC_APB1ENR_USART3EN (1U << RCC_APB1ENR_USART3EN_BIT)
+#define RCC_APB1ENR_USART2EN (1U << RCC_APB1ENR_USART2EN_BIT)
+#define RCC_APB1ENR_SPI3EN (1U << RCC_APB1ENR_SPI3EN_BIT)
+#define RCC_APB1ENR_SPI2EN (1U << RCC_APB1ENR_SPI2EN_BIT)
+#define RCC_APB1ENR_WWDGEN (1U << RCC_APB1ENR_WWDGEN_BIT)
+#define RCC_APB1ENR_TIM14EN (1U << RCC_APB1ENR_TIM14EN_BIT)
+#define RCC_APB1ENR_TIM13EN (1U << RCC_APB1ENR_TIM13EN_BIT)
+#define RCC_APB1ENR_TIM12EN (1U << RCC_APB1ENR_TIM12EN_BIT)
+#define RCC_APB1ENR_TIM7EN (1U << RCC_APB1ENR_TIM7EN_BIT)
+#define RCC_APB1ENR_TIM6EN (1U << RCC_APB1ENR_TIM6EN_BIT)
+#define RCC_APB1ENR_TIM5EN (1U << RCC_APB1ENR_TIM5EN_BIT)
+#define RCC_APB1ENR_TIM4EN (1U << RCC_APB1ENR_TIM4EN_BIT)
+#define RCC_APB1ENR_TIM3EN (1U << RCC_APB1ENR_TIM3EN_BIT)
+#define RCC_APB1ENR_TIM2EN (1U << RCC_APB1ENR_TIM2EN_BIT)
+
+/* APB2 peripheral clock enable register */
+
+#define RCC_APB2ENR_TIM11EN_BIT 18
+#define RCC_APB2ENR_TIM10EN_BIT 17
+#define RCC_APB2ENR_TIM9EN_BIT 16
+#define RCC_APB2ENR_SYSCFGEN_BIT 14
+#define RCC_APB2ENR_SPI1EN_BIT 12
+#define RCC_APB2ENR_SDIOEN_BIT 11
+#define RCC_APB2ENR_ADC3EN_BIT 10
+#define RCC_APB2ENR_ADC2EN_BIT 9
+#define RCC_APB2ENR_ADC1EN_BIT 8
+#define RCC_APB2ENR_USART6EN_BIT 5
+#define RCC_APB2ENR_USART1EN_BIT 4
+#define RCC_APB2ENR_TIM8EN_BIT 1
+#define RCC_APB2ENR_TIM1EN_BIT 0
+
+#define RCC_APB2ENR_TIM11EN (1U << RCC_APB2ENR_TIM11EN_BIT)
+#define RCC_APB2ENR_TIM10EN (1U << RCC_APB2ENR_TIM10EN_BIT)
+#define RCC_APB2ENR_TIM9EN (1U << RCC_APB2ENR_TIM9EN_BIT)
+#define RCC_APB2ENR_SYSCFGEN (1U << RCC_APB2ENR_SYSCFGEN_BIT)
+#define RCC_APB2ENR_SPI1EN (1U << RCC_APB2ENR_SPI1EN_BIT)
+#define RCC_APB2ENR_SDIOEN (1U << RCC_APB2ENR_SDIOEN_BIT)
+#define RCC_APB2ENR_ADC3EN (1U << RCC_APB2ENR_ADC3EN_BIT)
+#define RCC_APB2ENR_ADC2EN (1U << RCC_APB2ENR_ADC2EN_BIT)
+#define RCC_APB2ENR_ADC1EN (1U << RCC_APB2ENR_ADC1EN_BIT)
+#define RCC_APB2ENR_USART6EN (1U << RCC_APB2ENR_USART6EN_BIT)
+#define RCC_APB2ENR_USART1EN (1U << RCC_APB2ENR_USART1EN_BIT)
+#define RCC_APB2ENR_TIM8EN (1U << RCC_APB2ENR_TIM8EN_BIT)
+#define RCC_APB2ENR_TIM1EN (1U << RCC_APB2ENR_TIM1EN_BIT)
+
+/* AHB1 peripheral clock enable in low power mode register */
+
+#define RCC_AHB1LPENR_OTGHSULPILPEN_BIT 30
+#define RCC_AHB1LPENR_OTGHSLPEN_BIT 29
+#define RCC_AHB1LPENR_ETHMACPTPLPEN_BIT 28
+#define RCC_AHB1LPENR_ETHMACRXLPEN_BIT 27
+#define RCC_AHB1LPENR_ETHMACTXLPEN_BIT 26
+#define RCC_AHB1LPENR_ETHMACLPEN_BIT 25
+#define RCC_AHB1LPENR_DMA2LPEN_BIT 22
+#define RCC_AHB1LPENR_DMA1LPEN_BIT 21
+#define RCC_AHB1LPENR_BKPSRAMLPEN_BIT 18
+#define RCC_AHB1LPENR_SRAM2LPEN_BIT 17
+#define RCC_AHB1LPENR_SRAM1LPEN_BIT 16
+#define RCC_AHB1LPENR_FLITFLPEN_BIT 15
+#define RCC_AHB1LPENR_CRCLPEN_BIT 12
+#define RCC_AHB1LPENR_GPIOILPEN_BIT 8
+#define RCC_AHB1LPENR_GPIOGLPEN_BIT 6
+#define RCC_AHB1LPENR_GPIOFLPEN_BIT 5
+#define RCC_AHB1LPENR_GPIOELPEN_BIT 4
+#define RCC_AHB1LPENR_GPIODLPEN_BIT 3
+#define RCC_AHB1LPENR_GPIOCLPEN_BIT 2
+#define RCC_AHB1LPENR_GPIOBLPEN_BIT 1
+#define RCC_AHB1LPENR_GPIOALPEN_BIT 0
+
+#define RCC_AHB1LPENR_OTGHSULPILPEN (1U << RCC_AHB1LPENR_OTGHSULPILPEN_BIT)
+#define RCC_AHB1LPENR_OTGHSLPEN (1U << RCC_AHB1LPENR_OTGHSLPEN_BIT)
+#define RCC_AHB1LPENR_ETHMACPTPLPEN (1U << RCC_AHB1LPENR_ETHMACPTPLPEN_BIT)
+#define RCC_AHB1LPENR_ETHMACRXLPEN (1U << RCC_AHB1LPENR_ETHMACRXLPEN_BIT)
+#define RCC_AHB1LPENR_ETHMACTXLPEN (1U << RCC_AHB1LPENR_ETHMACTXLPEN_BIT)
+#define RCC_AHB1LPENR_ETHMACLPEN (1U << RCC_AHB1LPENR_ETHMACLPEN_BIT)
+#define RCC_AHB1LPENR_DMA2LPEN (1U << RCC_AHB1LPENR_DMA2LPEN_BIT)
+#define RCC_AHB1LPENR_DMA1LPEN (1U << RCC_AHB1LPENR_DMA1LPEN_BIT)
+#define RCC_AHB1LPENR_BKPSRAMLPEN (1U << RCC_AHB1LPENR_BKPSRAMLPEN_BIT)
+#define RCC_AHB1LPENR_SRAM2LPEN (1U << RCC_AHB1LPENR_SRAM2LPEN_BIT)
+#define RCC_AHB1LPENR_SRAM1LPEN (1U << RCC_AHB1LPENR_SRAM1LPEN_BIT)
+#define RCC_AHB1LPENR_FLITFLPEN (1U << RCC_AHB1LPENR_FLITFLPEN_BIT)
+#define RCC_AHB1LPENR_CRCLPEN (1U << RCC_AHB1LPENR_CRCLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOILPEN (1U << RCC_AHB1LPENR_GPIOILPEN_BIT)
+#define RCC_AHB1LPENR_GPIOGLPEN (1U << RCC_AHB1LPENR_GPIOGLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOFLPEN (1U << RCC_AHB1LPENR_GPIOFLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOELPEN (1U << RCC_AHB1LPENR_GPIOELPEN_BIT)
+#define RCC_AHB1LPENR_GPIODLPEN (1U << RCC_AHB1LPENR_GPIODLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOCLPEN (1U << RCC_AHB1LPENR_GPIOCLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOBLPEN (1U << RCC_AHB1LPENR_GPIOBLPEN_BIT)
+#define RCC_AHB1LPENR_GPIOALPEN (1U << RCC_AHB1LPENR_GPIOALPEN_BIT)
+
+/* AHB2 peripheral clock enable in low power mode register */
+
+#define RCC_AHB2LPENR_OTGFSLPEN_BIT 7
+#define RCC_AHB2LPENR_RNGLPEN_BIT 6
+#define RCC_AHB2LPENR_HASHLPEN_BIT 5
+#define RCC_AHB2LPENR_CRYPLPEN_BIT 4
+#define RCC_AHB2LPENR_DCMILPEN_BIT 0
+
+#define RCC_AHB2LPENR_OTGFSLPEN (1U << RCC_AHB2LPENR_OTGFSLPEN_BIT)
+#define RCC_AHB2LPENR_RNGLPEN (1U << RCC_AHB2LPENR_RNGLPEN_BIT)
+#define RCC_AHB2LPENR_HASHLPEN (1U << RCC_AHB2LPENR_HASHLPEN_BIT)
+#define RCC_AHB2LPENR_CRYPLPEN (1U << RCC_AHB2LPENR_CRYPLPEN_BIT)
+#define RCC_AHB2LPENR_DCMILPEN (1U << RCC_AHB2LPENR_DCMILPEN_BIT)
+
+/* AHB3 peripheral clock enable in low power mode register */
+
+#define RCC_AHB3LPENR_FSMCLPEN_BIT 0
+
+#define RCC_AHB3LPENR_FSMCLPEN (1U << RCC_AHB3LPENR_FSMCLPEN_BIT)
+
+/* APB1 peripheral clock enable in low power mode register */
+
+#define RCC_APB1LPENR_DACLPEN_BIT 29
+#define RCC_APB1LPENR_PWRLPEN_BIT 28
+#define RCC_APB1LPENR_CAN2LPEN_BIT 26
+#define RCC_APB1LPENR_CAN1LPEN_BIT 25
+#define RCC_APB1LPENR_I2C3LPEN_BIT 23
+#define RCC_APB1LPENR_I2C2LPEN_BIT 22
+#define RCC_APB1LPENR_I2C1LPEN_BIT 21
+#define RCC_APB1LPENR_UART5LPEN_BIT 20
+#define RCC_APB1LPENR_UART4LPEN_BIT 19
+#define RCC_APB1LPENR_USART3LPEN_BIT 18
+#define RCC_APB1LPENR_USART2LPEN_BIT 17
+#define RCC_APB1LPENR_SPI3LPEN_BIT 15
+#define RCC_APB1LPENR_SPI2LPEN_BIT 14
+#define RCC_APB1LPENR_WWDGLPEN_BIT 11
+#define RCC_APB1LPENR_TIM14LPEN_BIT 8
+#define RCC_APB1LPENR_TIM13LPEN_BIT 7
+#define RCC_APB1LPENR_TIM12LPEN_BIT 6
+#define RCC_APB1LPENR_TIM7LPEN_BIT 5
+#define RCC_APB1LPENR_TIM6LPEN_BIT 4
+#define RCC_APB1LPENR_TIM5LPEN_BIT 3
+#define RCC_APB1LPENR_TIM4LPEN_BIT 2
+#define RCC_APB1LPENR_TIM3LPEN_BIT 1
+#define RCC_APB1LPENR_TIM2LPEN_BIT 0
+
+#define RCC_APB1LPENR_DACLPEN (1U << RCC_APB1LPENR_DACLPEN_BIT)
+#define RCC_APB1LPENR_PWRLPEN (1U << RCC_APB1LPENR_PWRLPEN_BIT)
+#define RCC_APB1LPENR_CAN2LPEN (1U << RCC_APB1LPENR_CAN2LPEN_BIT)
+#define RCC_APB1LPENR_CAN1LPEN (1U << RCC_APB1LPENR_CAN1LPEN_BIT)
+#define RCC_APB1LPENR_I2C3LPEN (1U << RCC_APB1LPENR_I2C3LPEN_BIT)
+#define RCC_APB1LPENR_I2C2LPEN (1U << RCC_APB1LPENR_I2C2LPEN_BIT)
+#define RCC_APB1LPENR_I2C1LPEN (1U << RCC_APB1LPENR_I2C1LPEN_BIT)
+#define RCC_APB1LPENR_UART5LPEN (1U << RCC_APB1LPENR_UART5LPEN_BIT)
+#define RCC_APB1LPENR_UART4LPEN (1U << RCC_APB1LPENR_UART4LPEN_BIT)
+#define RCC_APB1LPENR_USART3LPEN (1U << RCC_APB1LPENR_USART3LPEN_BIT)
+#define RCC_APB1LPENR_USART2LPEN (1U << RCC_APB1LPENR_USART2LPEN_BIT)
+#define RCC_APB1LPENR_SPI3LPEN (1U << RCC_APB1LPENR_SPI3LPEN_BIT)
+#define RCC_APB1LPENR_SPI2LPEN (1U << RCC_APB1LPENR_SPI2LPEN_BIT)
+#define RCC_APB1LPENR_WWDGLPEN (1U << RCC_APB1LPENR_WWDGLPEN_BIT)
+#define RCC_APB1LPENR_TIM14LPEN (1U << RCC_APB1LPENR_TIM14LPEN_BIT)
+#define RCC_APB1LPENR_TIM13LPEN (1U << RCC_APB1LPENR_TIM13LPEN_BIT)
+#define RCC_APB1LPENR_TIM12LPEN (1U << RCC_APB1LPENR_TIM12LPEN_BIT)
+#define RCC_APB1LPENR_TIM7LPEN (1U << RCC_APB1LPENR_TIM7LPEN_BIT)
+#define RCC_APB1LPENR_TIM6LPEN (1U << RCC_APB1LPENR_TIM6LPEN_BIT)
+#define RCC_APB1LPENR_TIM5LPEN (1U << RCC_APB1LPENR_TIM5LPEN_BIT)
+#define RCC_APB1LPENR_TIM4LPEN (1U << RCC_APB1LPENR_TIM4LPEN_BIT)
+#define RCC_APB1LPENR_TIM3LPEN (1U << RCC_APB1LPENR_TIM3LPEN_BIT)
+#define RCC_APB1LPENR_TIM2LPEN (1U << RCC_APB1LPENR_TIM2LPEN_BIT)
+
+/* APB2 peripheral clock enable in low power mode register */
+
+#define RCC_APB2LPENR_TIM11LPEN_BIT 18
+#define RCC_APB2LPENR_TIM10LPEN_BIT 17
+#define RCC_APB2LPENR_TIM9LPEN_BIT 16
+#define RCC_APB2LPENR_SYSCFGLPEN_BIT 14
+#define RCC_APB2LPENR_SPI1LPEN_BIT 12
+#define RCC_APB2LPENR_SDIOLPEN_BIT 11
+#define RCC_APB2LPENR_ADC3LPEN_BIT 10
+#define RCC_APB2LPENR_ADC2LPEN_BIT 9
+#define RCC_APB2LPENR_ADC1LPEN_BIT 8
+#define RCC_APB2LPENR_USART6LPEN_BIT 5
+#define RCC_APB2LPENR_USART1LPEN_BIT 4
+#define RCC_APB2LPENR_TIM8LPEN_BIT 1
+#define RCC_APB2LPENR_TIM1LPEN_BIT 0
+
+#define RCC_APB2LPENR_TIM11LPEN (1U << RCC_APB2LPENR_TIM11LPEN_BIT)
+#define RCC_APB2LPENR_TIM10LPEN (1U << RCC_APB2LPENR_TIM10LPEN_BIT)
+#define RCC_APB2LPENR_TIM9LPEN (1U << RCC_APB2LPENR_TIM9LPEN_BIT)
+#define RCC_APB2LPENR_SYSCFGLPEN (1U << RCC_APB2LPENR_SYSCFGLPEN_BIT)
+#define RCC_APB2LPENR_SPI1LPEN (1U << RCC_APB2LPENR_SPI1LPEN_BIT)
+#define RCC_APB2LPENR_SDIOLPEN (1U << RCC_APB2LPENR_SDIOLPEN_BIT)
+#define RCC_APB2LPENR_ADC3LPEN (1U << RCC_APB2LPENR_ADC3LPEN_BIT)
+#define RCC_APB2LPENR_ADC2LPEN (1U << RCC_APB2LPENR_ADC2LPEN_BIT)
+#define RCC_APB2LPENR_ADC1LPEN (1U << RCC_APB2LPENR_ADC1LPEN_BIT)
+#define RCC_APB2LPENR_USART6LPEN (1U << RCC_APB2LPENR_USART6LPEN_BIT)
+#define RCC_APB2LPENR_USART1LPEN (1U << RCC_APB2LPENR_USART1LPEN_BIT)
+#define RCC_APB2LPENR_TIM8LPEN (1U << RCC_APB2LPENR_TIM8LPEN_BIT)
+#define RCC_APB2LPENR_TIM1LPEN (1U << RCC_APB2LPENR_TIM1LPEN_BIT)
+
+/* Backup domain control register */
+
+#define RCC_BDCR_BDRST_BIT 16
+#define RCC_BDCR_RTCEN_BIT 15
+#define RCC_BDCR_LSEBYP_BIT 2
+#define RCC_BDCR_LSERDY_BIT 1
+#define RCC_BDCR_LSEON_BIT 0
+
+#define RCC_BDCR_BDRST (1U << RCC_BDCR_BDRST_BIT)
+#define RCC_BDCR_RTCEN (1U << RCC_BDCR_RTCEN_BIT)
+#define RCC_BDCR_RTCSEL (0x3 << 8)
+#define RCC_BDCR_RTCSEL_NOCLOCK (0x0 << 8)
+#define RCC_BDCR_RTCSEL_LSE (0x1 << 8)
+#define RCC_BDCR_RTCSEL_LSI (0x2 << 8)
+#define RCC_BDCR_RTCSEL_HSE_DIV (0x3 << 8)
+#define RCC_BDCR_LSEBYP (1U << RCC_BDCR_LSEBYP_BIT)
+#define RCC_BDCR_LSERDY (1U << RCC_BDCR_LSERDY_BIT)
+#define RCC_BDCR_LSEON (1U << RCC_BDCR_LSEON_BIT)
+
+/* Clock control and status register */
+
+#define RCC_CSR_LPWRRSTF_BIT 31
+#define RCC_CSR_WWDGRSTF_BIT 30
+#define RCC_CSR_IWDGRSTF_BIT 29
+#define RCC_CSR_SFTRSTF_BIT 28
+#define RCC_CSR_PORRSTF_BIT 27
+#define RCC_CSR_PINRSTF_BIT 26
+#define RCC_CSR_BORRSTF_BIT 25
+#define RCC_CSR_RMVF_BIT 24
+#define RCC_CSR_LSIRDY_BIT 1
+#define RCC_CSR_LSION_BIT 0
+
+#define RCC_CSR_LPWRRSTF (1U << RCC_CSR_LPWRRSTF_BIT)
+#define RCC_CSR_WWDGRSTF (1U << RCC_CSR_WWDGRSTF_BIT)
+#define RCC_CSR_IWDGRSTF (1U << RCC_CSR_IWDGRSTF_BIT)
+#define RCC_CSR_SFTRSTF (1U << RCC_CSR_SFTRSTF_BIT)
+#define RCC_CSR_PORRSTF (1U << RCC_CSR_PORRSTF_BIT)
+#define RCC_CSR_PINRSTF (1U << RCC_CSR_PINRSTF_BIT)
+#define RCC_CSR_BORRSTF (1U << RCC_CSR_BORRSTF_BIT)
+#define RCC_CSR_RMVF (1U << RCC_CSR_RMVF_BIT)
+#define RCC_CSR_LSIRDY (1U << RCC_CSR_LSIRDY_BIT)
+#define RCC_CSR_LSION (1U << RCC_CSR_LSION_BIT)
+
+/* Spread spectrum clock generation register */
+
+#define RCC_SSCGR_SSCGEN_BIT 31
+#define RCC_SSCGR_SPREADSEL_BIT 30
+
+#define RCC_SSCGR_SSCGEN (1U << RCC_SSCGR_SSCGEN_BIT)
+#define RCC_SSCGR_SPREADSEL (1U << RCC_SSCGR_SPREADSEL_BIT)
+#define RCC_SSCGR_SPREADSEL_CENTER (0x0 << RCC_SSCGR_SPREADSEL_BIT)
+#define RCC_SSCGR_SPREADSEL_DOWN (0x1 << RCC_SSCGR_SPREADSEL_BIT)
+#define RCC_SSCGR_INCSTEP (0xFFF << 16)
+#define RCC_SSCGR_MODPER 0xFFFF
+
+/* PLLI2S configuration register */
+
+#define RCC_PLLI2SCFGR_PLLI2SR (0x7 << 28)
+#define RCC_PLLI2SCFGR_PLLI2SN (0x1FF << 6)
+
+/*
+ * Clock sources, domains, and peripheral clock IDs.
+ */
+
+/**
+ * @brief STM32F2 clock sources.
+ */
+typedef enum rcc_clk {
+ RCC_CLK_PLLI2S = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_PLLI2SON_BIT), /**< Dedicated PLL
+ for I2S. */
+ RCC_CLK_PLL = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_PLLON_BIT), /**< Main PLL, clocked by
+ HSI or HSE. */
+ RCC_CLK_HSE = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_HSEON_BIT), /**< High speed external. */
+ RCC_CLK_HSI = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) |
+ RCC_CR_HSION_BIT), /**< High speed internal. */
+ RCC_CLK_LSE = (uint16)((offsetof(struct rcc_reg_map, BDCR) << 8) |
+ RCC_BDCR_LSEON_BIT), /**< Low-speed external
+ * (32.768 KHz). */
+ RCC_CLK_LSI = (uint16)((offsetof(struct rcc_reg_map, CSR) << 8) |
+ RCC_CSR_LSION_BIT), /**< Low-speed internal
+ * (approximately 32 KHz). */
+} rcc_clk;
+
+/**
+ * @brief STM32F2 rcc_clk_id.
+ */
+typedef enum rcc_clk_id {
+ RCC_ADC1,
+ RCC_ADC2,
+ RCC_ADC3,
+ RCC_BKPSRAM,
+ RCC_CAN1,
+ RCC_CAN2,
+ RCC_CRC,
+ RCC_CRYP,
+ RCC_DAC,
+ RCC_DCMI,
+ RCC_DMA1,
+ RCC_DMA2,
+ RCC_ETHMAC,
+ RCC_ETHMACPTP,
+ RCC_ETHMACRX,
+ RCC_ETHMACTX,
+ RCC_FSMC,
+ RCC_GPIOA,
+ RCC_GPIOB,
+ RCC_GPIOC,
+ RCC_GPIOD,
+ RCC_GPIOE,
+ RCC_GPIOF,
+ RCC_GPIOG,
+ RCC_GPIOH,
+ RCC_GPIOI,
+ RCC_HASH,
+ RCC_I2C1,
+ RCC_I2C2,
+ RCC_I2C3,
+ RCC_OTGFS,
+ RCC_OTGHS,
+ RCC_OTGHSULPI,
+ RCC_PWR,
+ RCC_RNG,
+ RCC_SDIO,
+ RCC_SPI1,
+ RCC_SPI2,
+ RCC_SPI3,
+ RCC_SYSCFG,
+ RCC_TIMER1,
+ RCC_TIMER10,
+ RCC_TIMER11,
+ RCC_TIMER12,
+ RCC_TIMER13,
+ RCC_TIMER14,
+ RCC_TIMER2,
+ RCC_TIMER3,
+ RCC_TIMER4,
+ RCC_TIMER5,
+ RCC_TIMER6,
+ RCC_TIMER7,
+ RCC_TIMER8,
+ RCC_TIMER9,
+ RCC_USART1,
+ RCC_USART2,
+ RCC_USART3,
+ RCC_UART4,
+ RCC_UART5,
+ RCC_USART6,
+ RCC_WWDG,
+} rcc_clk_id;
+
+/**
+ * @brief STM32F2 PLL entry clock source
+ * @see rcc_configure_pll()
+ */
+typedef enum rcc_pllsrc {
+ RCC_PLLSRC_HSI = 0,
+ RCC_PLLSRC_HSE = RCC_PLLCFGR_PLLSRC,
+} rcc_pllsrc;
+
+/**
+ * @brief STM32F2 Peripheral clock domains.
+ */
+typedef enum rcc_clk_domain {
+ RCC_APB1,
+ RCC_APB2,
+ RCC_AHB1,
+ RCC_AHB2,
+ RCC_AHB3,
+} rcc_clk_domain;
+
+/*
+ * Prescalers and dividers.
+ */
+
+/**
+ * @brief STM32F2 Prescaler identifiers.
+ */
+typedef enum rcc_prescaler {
+ RCC_PRESCALER_MCO2,
+ RCC_PRESCALER_MCO1,
+ RCC_PRESCALER_RTC,
+ RCC_PRESCALER_APB2,
+ RCC_PRESCALER_APB1,
+ RCC_PRESCALER_AHB
+} rcc_prescaler;
+
+/**
+ * @brief STM32F2 MCO2 prescaler dividers.
+ */
+typedef enum rcc_mco2_divider {
+ RCC_MCO2_DIV_1 = RCC_CFGR_MCO2PRE_DIV_1,
+ RCC_MCO2_DIV_2 = RCC_CFGR_MCO2PRE_DIV_2,
+ RCC_MCO2_DIV_3 = RCC_CFGR_MCO2PRE_DIV_3,
+ RCC_MCO2_DIV_4 = RCC_CFGR_MCO2PRE_DIV_4,
+ RCC_MCO2_DIV_5 = RCC_CFGR_MCO2PRE_DIV_5,
+} rcc_mco2_divider;
+
+/**
+ * @brief STM32F2 MCO1 prescaler dividers.
+ */
+typedef enum rcc_mco1_divider {
+ RCC_MCO1_DIV_1 = RCC_CFGR_MCO1PRE_DIV_1,
+ RCC_MCO1_DIV_2 = RCC_CFGR_MCO1PRE_DIV_2,
+ RCC_MCO1_DIV_3 = RCC_CFGR_MCO1PRE_DIV_3,
+ RCC_MCO1_DIV_4 = RCC_CFGR_MCO1PRE_DIV_4,
+ RCC_MCO1_DIV_5 = RCC_CFGR_MCO1PRE_DIV_5,
+} rcc_mco1_divider;
+
+/**
+ * @brief STM32F2 RTC prescaler dividers.
+ */
+typedef enum rcc_rtc_divider { /* FIXME [0.0.13] TODO */
+ RCC_RTC_DIV_TODO = 0xFFFFFFFF,
+} rcc_rtc_divider;
+
+/**
+ * @brief STM32F2 AP2 prescaler dividers.
+ */
+typedef enum rcc_apb2_divider {
+ RCC_APB2_HCLK_DIV_1 = 0,
+ RCC_APB2_HCLK_DIV_2 = RCC_CFGR_PPRE2_AHB_DIV_2,
+ RCC_APB2_HCLK_DIV_4 = RCC_CFGR_PPRE2_AHB_DIV_4,
+ RCC_APB2_HCLK_DIV_8 = RCC_CFGR_PPRE2_AHB_DIV_8,
+ RCC_APB2_HCLK_DIV_16 = RCC_CFGR_PPRE2_AHB_DIV_16,
+} rcc_apb2_divider;
+
+/**
+ * @brief STM32F2 APB1 prescaler dividers.
+ */
+typedef enum rcc_apb1_divider {
+ RCC_APB1_HCLK_DIV_1 = 0,
+ RCC_APB1_HCLK_DIV_2 = RCC_CFGR_PPRE1_AHB_DIV_2,
+ RCC_APB1_HCLK_DIV_4 = RCC_CFGR_PPRE1_AHB_DIV_4,
+ RCC_APB1_HCLK_DIV_8 = RCC_CFGR_PPRE1_AHB_DIV_8,
+ RCC_APB1_HCLK_DIV_16 = RCC_CFGR_PPRE1_AHB_DIV_16,
+} rcc_apb1_divider;
+
+/**
+ * @brief STM32F2 AHB prescaler dividers.
+ */
+typedef enum rcc_ahb_divider {
+ RCC_AHB_SYSCLK_DIV_1 = 0,
+ RCC_AHB_SYSCLK_DIV_2 = RCC_CFGR_HPRE_SYSCLK_DIV_2,
+ RCC_AHB_SYSCLK_DIV_4 = RCC_CFGR_HPRE_SYSCLK_DIV_4,
+ RCC_AHB_SYSCLK_DIV_8 = RCC_CFGR_HPRE_SYSCLK_DIV_8,
+ RCC_AHB_SYSCLK_DIV_16 = RCC_CFGR_HPRE_SYSCLK_DIV_16,
+ RCC_AHB_SYSCLK_DIV_64 = RCC_CFGR_HPRE_SYSCLK_DIV_64,
+ RCC_AHB_SYSCLK_DIV_128 = RCC_CFGR_HPRE_SYSCLK_DIV_128,
+ RCC_AHB_SYSCLK_DIV_256 = RCC_CFGR_HPRE_SYSCLK_DIV_256,
+ RCC_AHB_SYSCLK_DIV_512 = RCC_CFGR_HPRE_SYSCLK_DIV_512,
+} rcc_ahb_divider;
+
+/**
+ * @brief STM32F2 PLL configuration values.
+ * Point to one of these with the "data" field in a struct rcc_pll_cfg.
+ * @see struct rcc_pll_cfg.
+ */
+typedef struct stm32f2_rcc_pll_data {
+ uint8 pllq; /**<
+ * @brief PLLQ value.
+ * Allowed values: 4, 5, ..., 15. */
+ uint8 pllp; /**<
+ * @brief PLLP value.
+ * Allowed values: 2, 4, 6, 8. */
+ uint16 plln; /**<
+ * @brief PLLN value.
+ * Allowed values: 192, 193, ..., 432. */
+ uint8 pllm; /**<
+ * @brief PLLM value.
+ * Allowed values: 2, 3, ..., 63. */
+} stm32f2_rcc_pll_data;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/spi.h b/libmaple/stm32f2/include/series/spi.h
new file mode 100644
index 0000000..7b9f94a
--- /dev/null
+++ b/libmaple/stm32f2/include/series/spi.h
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * 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/spi.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 SPI/I2S series header.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_SPI_H_
+#define _LIBMAPLE_STM32F2_SPI_H_
+
+#include <libmaple/gpio.h> /* for gpio_af */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Register map base pointers
+ */
+
+struct spi_reg_map;
+
+#define SPI1_BASE ((struct spi_reg_map*)0x40013000)
+#define SPI2_BASE ((struct spi_reg_map*)0x40003800)
+#define SPI3_BASE ((struct spi_reg_map*)0x40003C00)
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 2 */
+
+#define SPI_CR2_FRF_BIT 4
+
+#define SPI_CR2_FRF (1U << SPI_CR2_FRF_BIT)
+
+/* Status register */
+
+#define SPI_SR_TIFRFE_BIT 8
+
+#define SPI_SR_TIFRFE (1U << SPI_SR_TIFRFE_BIT)
+
+/*
+ * Device pointers
+ */
+
+struct spi_dev;
+
+extern struct spi_dev *SPI1;
+extern struct spi_dev *SPI2;
+extern struct spi_dev *SPI3;
+
+/*
+ * Routines
+ */
+
+gpio_af spi_get_af(struct spi_dev *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/stm32.h b/libmaple/stm32f2/include/series/stm32.h
new file mode 100644
index 0000000..180ab30
--- /dev/null
+++ b/libmaple/stm32f2/include/series/stm32.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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/stm32.h
+ * @brief STM32F2 chip- and series-specific definitions.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_STM32_H_
+#define _LIBMAPLE_STM32F2_STM32_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Chip configuration
+ */
+
+#ifndef STM32_PCLK1
+#define STM32_PCLK1 30000000U
+#endif
+
+#ifndef STM32_PCLK2
+#define STM32_PCLK2 60000000U
+#endif
+
+#ifndef STM32_DELAY_US_MULT
+#define STM32_DELAY_US_MULT 20 /* FIXME: dummy value. */
+#endif
+
+/*
+ * Series- and MCU-specific values
+ */
+
+#define STM32_MCU_SERIES STM32_SERIES_F2
+#define STM32_NR_INTERRUPTS 81
+#define STM32_HAVE_FSMC 1
+#define STM32_HAVE_USB 1
+#define STM32_HAVE_DAC 1
+
+#if defined(MCU_STM32F207IC) || defined(MCU_STM32F207IG)
+# define STM32_NR_GPIO_PORTS 9
+# define STM32_TIMER_MASK 0x7FFE /* TIMER1-TIMER14. */
+# define STM32_SRAM_END ((void*)0x20020000)
+#else
+#warning "Unsupported or unspecified STM32F2 MCU."
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/include/series/timer.h b/libmaple/stm32f2/include/series/timer.h
new file mode 100644
index 0000000..a7ac276
--- /dev/null
+++ b/libmaple/stm32f2/include/series/timer.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011,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/timer.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 timer support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_TIMER_H_
+#define _LIBMAPLE_STM32F2_TIMER_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/gpio.h> /* for gpio_af */
+
+/*
+ * Register maps and base pointers
+ */
+
+/**
+ * @brief STM32F2 general purpose timer register map type
+ *
+ * Note that not all general purpose timers have all of these
+ * registers. Consult your chip's reference manual for the details.
+ */
+typedef struct timer_gen_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SMCR; /**< Slave mode control register */
+ __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ __io uint32 CCMR1; /**< Capture/compare mode register 1 */
+ __io uint32 CCMR2; /**< Capture/compare mode register 2 */
+ __io uint32 CCER; /**< Capture/compare enable register */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 CCR1; /**< Capture/compare register 1 */
+ __io uint32 CCR2; /**< Capture/compare register 2 */
+ __io uint32 CCR3; /**< Capture/compare register 3 */
+ __io uint32 CCR4; /**< Capture/compare register 4 */
+ const uint32 RESERVED2; /**< Reserved */
+ __io uint32 DCR; /**< DMA control register */
+ __io uint32 DMAR; /**< DMA address for full transfer */
+ __io uint32 OR; /**< Option register. */
+} timer_gen_reg_map;
+
+struct timer_adv_reg_map;
+struct timer_bas_reg_map;
+
+/** Timer 1 register map base pointer */
+#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000)
+/** Timer 2 register map base pointer */
+#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000)
+/** Timer 3 register map base pointer */
+#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400)
+/** Timer 4 register map base pointer */
+#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800)
+/** Timer 5 register map base pointer */
+#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00)
+/** Timer 6 register map base pointer */
+#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000)
+/** Timer 7 register map base pointer */
+#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400)
+/** Timer 8 register map base pointer */
+#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400)
+/** Timer 9 register map base pointer */
+#define TIMER9_BASE ((struct timer_gen_reg_map*)0x40014000)
+/** Timer 10 register map base pointer */
+#define TIMER10_BASE ((struct timer_gen_reg_map*)0x40014400)
+/** Timer 11 register map base pointer */
+#define TIMER11_BASE ((struct timer_gen_reg_map*)0x40014800)
+/** Timer 12 register map base pointer */
+#define TIMER12_BASE ((struct timer_gen_reg_map*)0x40001800)
+/** Timer 13 register map base pointer */
+#define TIMER13_BASE ((struct timer_gen_reg_map*)0x40001C00)
+/** Timer 14 register map base pointer */
+#define TIMER14_BASE ((struct timer_gen_reg_map*)0x40002000)
+
+/*
+ * Register bit definitions
+ */
+
+/* TIM2 option register */
+
+/** Timer 2 option register internal trigger 1 remap */
+#define TIMER2_OR_ITR1_RMP (0x3 << 10)
+/** Timer 2 OR internal trigger 1: TIM8_TRGOUT */
+#define TIMER2_OR_ITR1_RMP_TIM8_TRGOUT (0x0 << 10)
+/** Timer 2 OR internal trigger 1: Ethernet PTP trigger output */
+#define TIMER2_OR_ITR1_RMP_PTP_TRGOUT (0x1 << 10)
+/** Timer 2 OR internal trigger 1: USB OTG full speed start of frame */
+#define TIMER2_OR_ITR1_RMP_OTG_FS_SOF (0x2 << 10)
+/** Timer 2 OR internal trigger 1: USB OTG high speed start of frame */
+#define TIMER2_OR_ITR1_RMP_OTG_HS_SOF (0x3 << 10)
+
+/* TIM5 option register */
+
+/**
+ * Timer 5 option register input 4 remap.
+ *
+ * These bits control whether TIM5_CH4 is connected to a GPIO or a
+ * clock. Connecting to a GPIO is the normal mode, useful for e.g. PWM
+ * generation or input pulse duration measurement. Connecting to a
+ * clock is useful for calibrating that clock.
+ */
+#define TIMER5_OR_TI4_RMP (0x3 << 6)
+/**
+ * Timer 5 OR input 4: Timer 5 channel 4 connected to GPIO. */
+#define TIMER5_OR_TI4_RMP_GPIO (0x0 << 6)
+/**
+ * Timer 5 OR input 4: low speed internal clock (LSI) is connected to
+ * TIM5_CH4. */
+#define TIMER5_OR_TI4_RMP_LSI (0x1 << 6)
+/**
+ * Timer 5 OR input 4: low speed external clock (LSE) is connected to
+ * TIM5_CH4. */
+#define TIMER5_OR_TI4_RMP_LSE (0x2 << 6)
+/**
+ * Timer 5 OR input 4: real time clock (RTC) output is connected to
+ * TIM5_CH4. */
+#define TIMER5_OR_TI4_RMP_RTC (0x3 << 6)
+
+/*
+ * Device pointers
+ */
+
+struct timer_dev;
+
+extern struct timer_dev *TIMER1;
+extern struct timer_dev *TIMER2;
+extern struct timer_dev *TIMER3;
+extern struct timer_dev *TIMER4;
+extern struct timer_dev *TIMER5;
+extern struct timer_dev *TIMER6;
+extern struct timer_dev *TIMER7;
+extern struct timer_dev *TIMER8;
+extern struct timer_dev *TIMER9;
+extern struct timer_dev *TIMER10;
+extern struct timer_dev *TIMER11;
+extern struct timer_dev *TIMER12;
+extern struct timer_dev *TIMER13;
+extern struct timer_dev *TIMER14;
+
+/*
+ * Routines
+ */
+
+gpio_af timer_get_af(struct timer_dev *dev);
+
+#endif
diff --git a/libmaple/stm32f2/include/series/usart.h b/libmaple/stm32f2/include/series/usart.h
new file mode 100644
index 0000000..8936efa
--- /dev/null
+++ b/libmaple/stm32f2/include/series/usart.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ * 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/usart.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 USART support.
+ */
+
+#ifndef _LIBMAPLE_STM32F2_USART_H_
+#define _LIBMAPLE_STM32F2_USART_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/gpio.h> /* for gpio_af */
+
+/*
+ * Register map base pointers.
+ */
+
+struct usart_reg_map;
+
+/** USART1 register map base pointer */
+#define USART1_BASE ((struct usart_reg_map*)0x40011000)
+/** USART2 register map base pointer */
+#define USART2_BASE ((struct usart_reg_map*)0x40004400)
+/** USART3 register map base pointer */
+#define USART3_BASE ((struct usart_reg_map*)0x40004800)
+/** UART4 register map base pointer */
+#define UART4_BASE ((struct usart_reg_map*)0x40004C00)
+/** UART5 register map base pointer */
+#define UART5_BASE ((struct usart_reg_map*)0x40005000)
+/** USART6 register map base pointer */
+#define USART6_BASE ((struct usart_reg_map*)0x40011400)
+
+/*
+ * F2-only register bit definitions.
+ */
+
+/* Control register 1 */
+
+/**
+ * @brief Oversampling mode bit.
+ * Availability: STM32F2. */
+#define USART_CR1_OVER8_BIT 15
+
+/**
+ * @brief Oversampling mode.
+ * Availability: STM32F2. */
+#define USART_CR1_OVER8 (1U << USART_CR1_OVER8_BIT)
+
+/* Control register 3 */
+
+/** One sample bit method enable bit. */
+#define USART_CR3_ONEBIT_BIT 11
+
+/** One bit sample method enable. */
+#define USART_CR3_ONEBIT (1 << USART_CR3_ONEBIT_BIT)
+/** Sample method: Three sample bit method. */
+#define USART_CR3_ONEBIT_3SAMPLE (0 << USART_CR3_ONEBIT_BIT)
+/** Sample method: One sample bit method. */
+#define USART_CR3_ONEBIT_1SAMPLE (1 << USART_CR3_ONEBIT_BIT)
+
+/*
+ * Devices
+ */
+
+struct usart_dev;
+extern struct usart_dev *USART1;
+extern struct usart_dev *USART2;
+extern struct usart_dev *USART3;
+extern struct usart_dev *UART4;
+extern struct usart_dev *UART5;
+extern struct usart_dev *USART6;
+
+/*
+ * Routines
+ */
+
+gpio_af usart_get_af(struct usart_dev *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/stm32f2/isrs.S b/libmaple/stm32f2/isrs.S
new file mode 100644
index 0000000..5baaf8b
--- /dev/null
+++ b/libmaple/stm32f2/isrs.S
@@ -0,0 +1,322 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/* STM32F2 ISR weak declarations */
+
+ .thumb
+
+/* Default handler, as with STM32F1 */
+ .globl __default_handler
+ .type __default_handler, %function
+
+__default_handler:
+ b .
+
+ .weak __exc_nmi
+ .globl __exc_nmi
+ .set __exc_nmi, __default_handler
+ .weak __exc_hardfault
+ .globl __exc_hardfault
+ .set __exc_hardfault, __default_handler
+ .weak __exc_memmanage
+ .globl __exc_memmanage
+ .set __exc_memmanage, __default_handler
+ .weak __exc_busfault
+ .globl __exc_busfault
+ .set __exc_busfault, __default_handler
+ .weak __exc_usagefault
+ .globl __exc_usagefault
+ .set __exc_usagefault, __default_handler
+ .weak __stm32reservedexception7
+ .globl __stm32reservedexception7
+ .set __stm32reservedexception7, __default_handler
+ .weak __stm32reservedexception8
+ .globl __stm32reservedexception8
+ .set __stm32reservedexception8, __default_handler
+ .weak __stm32reservedexception9
+ .globl __stm32reservedexception9
+ .set __stm32reservedexception9, __default_handler
+ .weak __stm32reservedexception10
+ .globl __stm32reservedexception10
+ .set __stm32reservedexception10, __default_handler
+ .weak __exc_svc
+ .globl __exc_svc
+ .set __exc_svc, __default_handler
+ .weak __exc_debug_monitor
+ .globl __exc_debug_monitor
+ .set __exc_debug_monitor, __default_handler
+ .weak __stm32reservedexception13
+ .globl __stm32reservedexception13
+ .set __stm32reservedexception13, __default_handler
+ .weak __exc_pendsv
+ .globl __exc_pendsv
+ .set __exc_pendsv, __default_handler
+ .weak __exc_systick
+ .globl __exc_systick
+ .set __exc_systick, __default_handler
+ .weak __irq_wwdg
+ .globl __irq_wwdg
+ .set __irq_wwdg, __default_handler
+ .weak __irq_pvd
+ .globl __irq_pvd
+ .set __irq_pvd, __default_handler
+ .weak __irq_tamp_stamp
+ .globl __irq_tamp_stamp
+ .set __irq_tamp_stamp, __default_handler
+ .weak __irq_rtc_wkup
+ .globl __irq_rtc_wkup
+ .set __irq_rtc_wkup, __default_handler
+ .weak __irq_flash
+ .globl __irq_flash
+ .set __irq_flash, __default_handler
+ .weak __irq_rcc
+ .globl __irq_rcc
+ .set __irq_rcc, __default_handler
+ .weak __irq_exti0
+ .globl __irq_exti0
+ .set __irq_exti0, __default_handler
+ .weak __irq_exti1
+ .globl __irq_exti1
+ .set __irq_exti1, __default_handler
+ .weak __irq_exti2
+ .globl __irq_exti2
+ .set __irq_exti2, __default_handler
+ .weak __irq_exti3
+ .globl __irq_exti3
+ .set __irq_exti3, __default_handler
+ .weak __irq_exti4
+ .globl __irq_exti4
+ .set __irq_exti4, __default_handler
+ .weak __irq_dma1_stream0
+ .globl __irq_dma1_stream0
+ .set __irq_dma1_stream0, __default_handler
+ .weak __irq_dma1_stream1
+ .globl __irq_dma1_stream1
+ .set __irq_dma1_stream1, __default_handler
+ .weak __irq_dma1_stream2
+ .globl __irq_dma1_stream2
+ .set __irq_dma1_stream2, __default_handler
+ .weak __irq_dma1_stream3
+ .globl __irq_dma1_stream3
+ .set __irq_dma1_stream3, __default_handler
+ .weak __irq_dma1_stream4
+ .globl __irq_dma1_stream4
+ .set __irq_dma1_stream4, __default_handler
+ .weak __irq_dma1_stream5
+ .globl __irq_dma1_stream5
+ .set __irq_dma1_stream5, __default_handler
+ .weak __irq_dma1_stream6
+ .globl __irq_dma1_stream6
+ .set __irq_dma1_stream6, __default_handler
+ .weak __irq_adc
+ .globl __irq_adc
+ .set __irq_adc, __default_handler
+ .weak __irq_can1_tx
+ .globl __irq_can1_tx
+ .set __irq_can1_tx, __default_handler
+ .weak __irq_can1_rx0
+ .globl __irq_can1_rx0
+ .set __irq_can1_rx0, __default_handler
+ .weak __irq_can1_rx1
+ .globl __irq_can1_rx1
+ .set __irq_can1_rx1, __default_handler
+ .weak __irq_can1_sce
+ .globl __irq_can1_sce
+ .set __irq_can1_sce, __default_handler
+ .weak __irq_exti9_5
+ .globl __irq_exti9_5
+ .set __irq_exti9_5, __default_handler
+ .weak __irq_tim1_brk_tim9
+ .globl __irq_tim1_brk_tim9
+ .set __irq_tim1_brk_tim9, __default_handler
+ .weak __irq_tim1_up_tim10
+ .globl __irq_tim1_up_tim10
+ .set __irq_tim1_up_tim10, __default_handler
+ .weak __irq_tim1_trg_com_tim11
+ .globl __irq_tim1_trg_com_tim11
+ .set __irq_tim1_trg_com_tim11, __default_handler
+ .weak __irq_tim1_cc
+ .globl __irq_tim1_cc
+ .set __irq_tim1_cc, __default_handler
+ .weak __irq_tim2
+ .globl __irq_tim2
+ .set __irq_tim2, __default_handler
+ .weak __irq_tim3
+ .globl __irq_tim3
+ .set __irq_tim3, __default_handler
+ .weak __irq_tim4
+ .globl __irq_tim4
+ .set __irq_tim4, __default_handler
+ .weak __irq_i2c1_ev
+ .globl __irq_i2c1_ev
+ .set __irq_i2c1_ev, __default_handler
+ .weak __irq_i2c1_er
+ .globl __irq_i2c1_er
+ .set __irq_i2c1_er, __default_handler
+ .weak __irq_i2c2_ev
+ .globl __irq_i2c2_ev
+ .set __irq_i2c2_ev, __default_handler
+ .weak __irq_i2c2_er
+ .globl __irq_i2c2_er
+ .set __irq_i2c2_er, __default_handler
+ .weak __irq_spi1
+ .globl __irq_spi1
+ .set __irq_spi1, __default_handler
+ .weak __irq_spi2
+ .globl __irq_spi2
+ .set __irq_spi2, __default_handler
+ .weak __irq_usart1
+ .globl __irq_usart1
+ .set __irq_usart1, __default_handler
+ .weak __irq_usart2
+ .globl __irq_usart2
+ .set __irq_usart2, __default_handler
+ .weak __irq_usart3
+ .globl __irq_usart3
+ .set __irq_usart3, __default_handler
+ .weak __irq_exti15_10
+ .globl __irq_exti15_10
+ .set __irq_exti15_10, __default_handler
+ .weak __irq_rtc_alarm
+ .globl __irq_rtc_alarm
+ .set __irq_rtc_alarm, __default_handler
+ .weak __irq_otg_fs_wkup
+ .globl __irq_otg_fs_wkup
+ .set __irq_otg_fs_wkup, __default_handler
+ .weak __irq_tim8_brk_tim12
+ .globl __irq_tim8_brk_tim12
+ .set __irq_tim8_brk_tim12, __default_handler
+ .weak __irq_tim8_up_tim13
+ .globl __irq_tim8_up_tim13
+ .set __irq_tim8_up_tim13, __default_handler
+ .weak __irq_tim8_trg_com_tim14
+ .globl __irq_tim8_trg_com_tim14
+ .set __irq_tim8_trg_com_tim14, __default_handler
+ .weak __irq_tim8_cc
+ .globl __irq_tim8_cc
+ .set __irq_tim8_cc, __default_handler
+ .weak __irq_dma1_stream7
+ .globl __irq_dma1_stream7
+ .set __irq_dma1_stream7, __default_handler
+ .weak __irq_fsmc
+ .globl __irq_fsmc
+ .set __irq_fsmc, __default_handler
+ .weak __irq_sdio
+ .globl __irq_sdio
+ .set __irq_sdio, __default_handler
+ .weak __irq_tim5
+ .globl __irq_tim5
+ .set __irq_tim5, __default_handler
+ .weak __irq_spi3
+ .globl __irq_spi3
+ .set __irq_spi3, __default_handler
+ .weak __irq_uart4
+ .globl __irq_uart4
+ .set __irq_uart4, __default_handler
+ .weak __irq_uart5
+ .globl __irq_uart5
+ .set __irq_uart5, __default_handler
+ .weak __irq_tim6_dac
+ .globl __irq_tim6_dac
+ .set __irq_tim6_dac, __default_handler
+ .weak __irq_tim7
+ .globl __irq_tim7
+ .set __irq_tim7, __default_handler
+ .weak __irq_dma2_stream0
+ .globl __irq_dma2_stream0
+ .set __irq_dma2_stream0, __default_handler
+ .weak __irq_dma2_stream1
+ .globl __irq_dma2_stream1
+ .set __irq_dma2_stream1, __default_handler
+ .weak __irq_dma2_stream2
+ .globl __irq_dma2_stream2
+ .set __irq_dma2_stream2, __default_handler
+ .weak __irq_dma2_stream3
+ .globl __irq_dma2_stream3
+ .set __irq_dma2_stream3, __default_handler
+ .weak __irq_dma2_stream4
+ .globl __irq_dma2_stream4
+ .set __irq_dma2_stream4, __default_handler
+ .weak __irq_eth
+ .globl __irq_eth
+ .set __irq_eth, __default_handler
+ .weak __irq_eth_wkup
+ .globl __irq_eth_wkup
+ .set __irq_eth_wkup, __default_handler
+ .weak __irq_can2_tx
+ .globl __irq_can2_tx
+ .set __irq_can2_tx, __default_handler
+ .weak __irq_can2_rx0
+ .globl __irq_can2_rx0
+ .set __irq_can2_rx0, __default_handler
+ .weak __irq_can2_rx1
+ .globl __irq_can2_rx1
+ .set __irq_can2_rx1, __default_handler
+ .weak __irq_can2_sce
+ .globl __irq_can2_sce
+ .set __irq_can2_sce, __default_handler
+ .weak __irq_otg_fs
+ .globl __irq_otg_fs
+ .set __irq_otg_fs, __default_handler
+ .weak __irq_dma2_stream5
+ .globl __irq_dma2_stream5
+ .set __irq_dma2_stream5, __default_handler
+ .weak __irq_dma2_stream6
+ .globl __irq_dma2_stream6
+ .set __irq_dma2_stream6, __default_handler
+ .weak __irq_dma2_stream7
+ .globl __irq_dma2_stream7
+ .set __irq_dma2_stream7, __default_handler
+ .weak __irq_usart6
+ .globl __irq_usart6
+ .set __irq_usart6, __default_handler
+ .weak __irq_i2c3_ev
+ .globl __irq_i2c3_ev
+ .set __irq_i2c3_ev, __default_handler
+ .weak __irq_i2c3_er
+ .globl __irq_i2c3_er
+ .set __irq_i2c3_er, __default_handler
+ .weak __irq_otg_hs_ep1_out
+ .globl __irq_otg_hs_ep1_out
+ .set __irq_otg_hs_ep1_out, __default_handler
+ .weak __irq_otg_hs_ep1_in
+ .globl __irq_otg_hs_ep1_in
+ .set __irq_otg_hs_ep1_in, __default_handler
+ .weak __irq_otg_hs_wkup
+ .globl __irq_otg_hs_wkup
+ .set __irq_otg_hs_wkup, __default_handler
+ .weak __irq_otg_hs
+ .globl __irq_otg_hs
+ .set __irq_otg_hs, __default_handler
+ .weak __irq_dcmi
+ .globl __irq_dcmi
+ .set __irq_dcmi, __default_handler
+ .weak __irq_cryp
+ .globl __irq_cryp
+ .set __irq_cryp, __default_handler
+ .weak __irq_hash_rng
+ .globl __irq_hash_rng
+ .set __irq_hash_rng, __default_handler
diff --git a/libmaple/stm32f2/rcc.c b/libmaple/stm32f2/rcc.c
new file mode 100644
index 0000000..7fc7eb0
--- /dev/null
+++ b/libmaple/stm32f2/rcc.c
@@ -0,0 +1,175 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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/rcc.c
+ * @brief STM32F2 RCC.
+ */
+
+#include <libmaple/rcc.h>
+#include <libmaple/libmaple.h>
+
+#include "rcc_private.h"
+
+#define DEV_ENTRY(domain, dev) \
+ {.clk_domain = RCC_##domain, .line_num = RCC_##domain##ENR_##dev##EN_BIT}
+
+const struct rcc_dev_info rcc_dev_table[] = {
+ /* AHB1 */
+ [RCC_OTGHSULPI] = DEV_ENTRY(AHB1, OTGHSULPI),
+ [RCC_OTGHS] = DEV_ENTRY(AHB1, OTGHS),
+ [RCC_ETHMACPTP] = DEV_ENTRY(AHB1, ETHMACPTP),
+ [RCC_ETHMACRX] = DEV_ENTRY(AHB1, ETHMACRX),
+ [RCC_ETHMACTX] = DEV_ENTRY(AHB1, ETHMACTX),
+ [RCC_ETHMAC] = DEV_ENTRY(AHB1, ETHMAC),
+ [RCC_DMA2] = DEV_ENTRY(AHB1, DMA2),
+ [RCC_DMA1] = DEV_ENTRY(AHB1, DMA1),
+ [RCC_BKPSRAM] = DEV_ENTRY(AHB1, BKPSRAM),
+ [RCC_CRC] = DEV_ENTRY(AHB1, CRC),
+ [RCC_GPIOI] = DEV_ENTRY(AHB1, GPIOI),
+ [RCC_GPIOH] = DEV_ENTRY(AHB1, GPIOH),
+ [RCC_GPIOG] = DEV_ENTRY(AHB1, GPIOG),
+ [RCC_GPIOF] = DEV_ENTRY(AHB1, GPIOF),
+ [RCC_GPIOE] = DEV_ENTRY(AHB1, GPIOE),
+ [RCC_GPIOD] = DEV_ENTRY(AHB1, GPIOD),
+ [RCC_GPIOC] = DEV_ENTRY(AHB1, GPIOC),
+ [RCC_GPIOB] = DEV_ENTRY(AHB1, GPIOB),
+ [RCC_GPIOA] = DEV_ENTRY(AHB1, GPIOA),
+
+ /* AHB2 */
+ [RCC_OTGFS] = DEV_ENTRY(AHB2, OTGFS),
+ [RCC_RNG] = DEV_ENTRY(AHB2, RNG),
+ [RCC_HASH] = DEV_ENTRY(AHB2, HASH),
+ [RCC_CRYP] = DEV_ENTRY(AHB2, CRYP),
+ [RCC_DCMI] = DEV_ENTRY(AHB2, DCMI),
+
+ /* AHB3 */
+ [RCC_FSMC] = DEV_ENTRY(AHB3, FSMC),
+
+ /* APB1 */
+ [RCC_DAC] = DEV_ENTRY(APB1, DAC),
+ [RCC_PWR] = DEV_ENTRY(APB1, PWR),
+ [RCC_CAN2] = DEV_ENTRY(APB1, CAN2),
+ [RCC_CAN1] = DEV_ENTRY(APB1, CAN1),
+ [RCC_I2C3] = DEV_ENTRY(APB1, I2C3),
+ [RCC_I2C2] = DEV_ENTRY(APB1, I2C2),
+ [RCC_I2C1] = DEV_ENTRY(APB1, I2C1),
+ [RCC_UART5] = DEV_ENTRY(APB1, UART5),
+ [RCC_UART4] = DEV_ENTRY(APB1, UART4),
+ [RCC_USART3] = DEV_ENTRY(APB1, USART3),
+ [RCC_USART2] = DEV_ENTRY(APB1, USART2),
+ [RCC_SPI3] = DEV_ENTRY(APB1, SPI3),
+ [RCC_SPI2] = DEV_ENTRY(APB1, SPI2),
+ [RCC_WWDG] = DEV_ENTRY(APB1, WWDG),
+ [RCC_TIMER14] = DEV_ENTRY(APB1, TIM14),
+ [RCC_TIMER13] = DEV_ENTRY(APB1, TIM13),
+ [RCC_TIMER12] = DEV_ENTRY(APB1, TIM12),
+ [RCC_TIMER7] = DEV_ENTRY(APB1, TIM7),
+ [RCC_TIMER6] = DEV_ENTRY(APB1, TIM6),
+ [RCC_TIMER5] = DEV_ENTRY(APB1, TIM5),
+ [RCC_TIMER4] = DEV_ENTRY(APB1, TIM4),
+ [RCC_TIMER3] = DEV_ENTRY(APB1, TIM3),
+ [RCC_TIMER2] = DEV_ENTRY(APB1, TIM2),
+
+ /* APB2 */
+ [RCC_TIMER11] = DEV_ENTRY(APB2, TIM11),
+ [RCC_TIMER10] = DEV_ENTRY(APB2, TIM10),
+ [RCC_TIMER9] = DEV_ENTRY(APB2, TIM9),
+ [RCC_SYSCFG] = DEV_ENTRY(APB2, SYSCFG),
+ [RCC_SPI1] = DEV_ENTRY(APB2, SPI1),
+ [RCC_SDIO] = DEV_ENTRY(APB2, SDIO),
+ [RCC_ADC3] = DEV_ENTRY(APB2, ADC3),
+ [RCC_ADC2] = DEV_ENTRY(APB2, ADC2),
+ [RCC_ADC1] = DEV_ENTRY(APB2, ADC1),
+ [RCC_USART6] = DEV_ENTRY(APB2, USART6),
+ [RCC_USART1] = DEV_ENTRY(APB2, USART1),
+ [RCC_TIMER8] = DEV_ENTRY(APB2, TIM8),
+ [RCC_TIMER1] = DEV_ENTRY(APB2, TIM1),
+};
+
+void rcc_clk_enable(rcc_clk_id id) {
+ static __io uint32* enable_regs[] = {
+ [RCC_AHB1] = &RCC_BASE->AHB1ENR,
+ [RCC_AHB2] = &RCC_BASE->AHB2ENR,
+ [RCC_AHB3] = &RCC_BASE->AHB3ENR,
+ [RCC_APB1] = &RCC_BASE->APB1ENR,
+ [RCC_APB2] = &RCC_BASE->APB2ENR,
+ };
+ rcc_do_clk_enable(enable_regs, id);
+}
+
+void rcc_reset_dev(rcc_clk_id id) {
+ static __io uint32* reset_regs[] = {
+ [RCC_AHB1] = &RCC_BASE->AHB1RSTR,
+ [RCC_AHB2] = &RCC_BASE->AHB2RSTR,
+ [RCC_AHB3] = &RCC_BASE->AHB3RSTR,
+ [RCC_APB1] = &RCC_BASE->AHB3RSTR,
+ [RCC_APB2] = &RCC_BASE->AHB3RSTR,
+ };
+ rcc_do_reset_dev(reset_regs, id);
+}
+
+void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) {
+ static const uint32 masks[] = {
+ [RCC_PRESCALER_MCO2] = RCC_CFGR_MCO2PRE,
+ [RCC_PRESCALER_MCO1] = RCC_CFGR_MCO1PRE,
+ [RCC_PRESCALER_RTC] = RCC_CFGR_RTCPRE,
+ [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2,
+ [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1,
+ [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE,
+ };
+ rcc_do_set_prescaler(masks, prescaler, divider);
+}
+
+/* pll_cfg->data must point to a struct stm32f2_rcc_pll_data. */
+void rcc_configure_pll(rcc_pll_cfg *pll_cfg) {
+ stm32f2_rcc_pll_data *data = pll_cfg->data;
+ uint32 pllcfgr;
+
+ /* Check that the PLL is disabled. */
+ ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL));
+
+ /* Sanity-check all the parameters */
+ ASSERT_FAULT((data->pllq >= 4) && (data->pllq <= 15));
+ ASSERT_FAULT((data->pllp >= 2) && (data->pllp <= 8));
+ ASSERT_FAULT(!(data->pllp & 1));
+ ASSERT_FAULT((data->plln >= 192) && (data->plln <= 432));
+ ASSERT_FAULT((data->pllm >= 2) && (data->pllm <= 63));
+
+ /* Update RCC_PLLCFGR to reflect new values. */
+ pllcfgr = RCC_BASE->PLLCFGR;
+ pllcfgr &= ~(RCC_PLLCFGR_PLLQ |
+ RCC_PLLCFGR_PLLP |
+ RCC_PLLCFGR_PLLN |
+ RCC_PLLCFGR_PLLM |
+ RCC_PLLCFGR_PLLSRC);
+ pllcfgr |= (pll_cfg->pllsrc |
+ (data->pllq << 24) |
+ (((data->pllp >> 1) - 1) << 16) |
+ (data->plln << 6) |
+ data->pllm);
+ RCC_BASE->PLLCFGR = pllcfgr;
+}
diff --git a/libmaple/stm32f2/rules.mk b/libmaple/stm32f2/rules.mk
new file mode 100644
index 0000000..4c62cc2
--- /dev/null
+++ b/libmaple/stm32f2/rules.mk
@@ -0,0 +1,40 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) $(LIBMAPLE_PRIVATE_INCLUDES) -Wall -Werror
+
+# Local rules and targets
+sSRCS_$(d) := isrs.S
+sSRCS_$(d) += vector_table.S
+
+cSRCS_$(d) := adc.c
+cSRCS_$(d) += dma.c
+cSRCS_$(d) += exti.c
+cSRCS_$(d) += fsmc.c
+cSRCS_$(d) += gpio.c
+cSRCS_$(d) += rcc.c
+cSRCS_$(d) += spi.c
+cSRCS_$(d) += syscfg.c
+cSRCS_$(d) += timer.c
+cSRCS_$(d) += usart.c
+
+sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
+ $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_ASFLAGS :=
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp))
diff --git a/libmaple/stm32f2/spi.c b/libmaple/stm32f2/spi.c
new file mode 100644
index 0000000..cfd9995
--- /dev/null
+++ b/libmaple/stm32f2/spi.c
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * 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/spi.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 SPI/I2S.
+ */
+
+#include <libmaple/spi.h>
+#include "spi_private.h"
+
+/*
+ * Devices
+ */
+
+static spi_dev spi1 = SPI_DEV(1);
+static spi_dev spi2 = SPI_DEV(2);
+static spi_dev spi3 = SPI_DEV(3);
+
+spi_dev *SPI1 = &spi1;
+spi_dev *SPI2 = &spi2;
+spi_dev *SPI3 = &spi3;
+
+/*
+ * Routines
+ */
+
+void spi_config_gpios(spi_dev *dev,
+ uint8 as_master,
+ gpio_dev *nss_dev,
+ uint8 nss_bit,
+ gpio_dev *comm_dev,
+ uint8 sck_bit,
+ uint8 miso_bit,
+ uint8 mosi_bit) {
+ gpio_af dev_af = spi_get_af(dev);
+ gpio_set_mode(nss_dev, nss_bit, GPIO_MODE_AF);
+ gpio_set_mode(comm_dev, sck_bit, GPIO_MODE_AF);
+ gpio_set_mode(comm_dev, miso_bit, GPIO_MODE_AF);
+ gpio_set_mode(comm_dev, mosi_bit, GPIO_MODE_AF);
+ gpio_set_af(nss_dev, nss_bit, dev_af);
+ gpio_set_af(comm_dev, sck_bit, dev_af);
+ gpio_set_af(comm_dev, miso_bit, dev_af);
+ gpio_set_af(comm_dev, mosi_bit, dev_af);
+}
+
+void spi_foreach(void (*fn)(spi_dev*)) {
+ fn(SPI1);
+ fn(SPI2);
+ fn(SPI3);
+}
+
+gpio_af spi_get_af(spi_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_SPI1: /* Fall through */
+ case RCC_SPI2:
+ return GPIO_AF_SPI_1_2;
+ case RCC_SPI3:
+ return GPIO_AF_SPI3;
+ default:
+ ASSERT(0); /* Can't happen */
+ return (gpio_af)-1;
+ }
+}
diff --git a/libmaple/stm32f2/syscfg.c b/libmaple/stm32f2/syscfg.c
new file mode 100644
index 0000000..19e932e
--- /dev/null
+++ b/libmaple/stm32f2/syscfg.c
@@ -0,0 +1,78 @@
+/******************************************************************************
+ * 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/syscfg.c
+ * @brief SYSCFG routines.
+ */
+
+#include <libmaple/syscfg.h>
+#include <libmaple/bitband.h>
+#include <libmaple/rcc.h>
+
+/**
+ * @brief Initialize the SYSCFG peripheral.
+ */
+void syscfg_init(void) {
+ rcc_clk_enable(RCC_SYSCFG);
+ rcc_reset_dev(RCC_SYSCFG);
+}
+
+/**
+ * @brief Turn on the I/O compensation cell.
+ *
+ * It's only safe to do this when the supply voltage is between 2.4 V
+ * and 3.6 V.
+ */
+void syscfg_enable_io_compensation(void) {
+ bb_peri_set_bit(&SYSCFG_BASE->CMPCR, SYSCFG_CMPCR_CMP_PD_BIT, 1);
+ while (!(SYSCFG_BASE->CMPCR & SYSCFG_CMPCR_READY))
+ ;
+}
+
+/**
+ * @brief Turn off the I/O compensation cell.
+ */
+void syscfg_disable_io_compensation(void) {
+ bb_peri_set_bit(&SYSCFG_BASE->CMPCR, SYSCFG_CMPCR_CMP_PD_BIT, 0);
+}
+
+/**
+ * @brief Set the memory to be mapped at address 0x00000000.
+ *
+ * This function can be used to override the BOOT pin
+ * configuration. Some restrictions apply; see your chip's reference
+ * manual for the details.
+ *
+ * @param mode Mode to set
+ * @see syscfg_mem_mode
+ */
+void syscfg_set_mem_mode(syscfg_mem_mode mode) {
+ uint32 memrmp = SYSCFG_BASE->MEMRMP;
+ memrmp &= ~SYSCFG_MEMRMP_MEM_MODE;
+ memrmp |= (uint32)mode;
+ SYSCFG_BASE->MEMRMP = memrmp;
+}
diff --git a/libmaple/stm32f2/timer.c b/libmaple/stm32f2/timer.c
new file mode 100644
index 0000000..a85bea0
--- /dev/null
+++ b/libmaple/stm32f2/timer.c
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * 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/timer.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 timers.
+ */
+
+#include <libmaple/timer.h>
+#include "timer_private.h"
+
+/*
+ * Routines
+ */
+
+/**
+ * @brief Get the GPIO alternate function corresponding to a timer.
+ *
+ * For example, if dev is TIMER1, this function returns
+ * GPIO_AF_TIM_1_2. This is useful for e.g. using gpio_set_af() to set
+ * a pin's alternate function to a timer.
+ *
+ * @param dev Timer device, must not be TIMER6 or TIMER7.
+ * @return gpio_af corresponding to dev
+ * @see gpio_set_af
+ * @see gpio_af
+ */
+gpio_af timer_get_af(timer_dev *dev) {
+ rcc_clk_id clk_id = dev->clk_id;
+ /* Timers 6 and 7 don't have any capture/compare, so they can't do
+ * PWM (and in fact have no AF values). */
+ ASSERT(clk_id != RCC_TIMER6 && clk_id != RCC_TIMER7);
+ switch(dev->clk_id) {
+ case RCC_TIMER1: // fall-through
+ case RCC_TIMER2:
+ return GPIO_AF_TIM_1_2;
+ case RCC_TIMER3: // fall-through
+ case RCC_TIMER4: // ...
+ case RCC_TIMER5:
+ return GPIO_AF_TIM_3_4_5;
+ case RCC_TIMER8: // fall-through
+ case RCC_TIMER9: // ...
+ case RCC_TIMER10: // ...
+ case RCC_TIMER11:
+ return GPIO_AF_TIM_8_9_10_11;
+ case RCC_TIMER12: // fall-through
+ case RCC_TIMER13: // ...
+ case RCC_TIMER14:
+ return GPIO_AF_CAN_1_2_TIM_12_13_14;
+ default:
+ ASSERT(0); // Can't happen
+ return (gpio_af)-1;
+ }
+}
+
+/*
+ * IRQ handlers
+ *
+ * Defer to the timer_private dispatch API.
+ */
+
+void __irq_tim1_brk_tim9(void) {
+ dispatch_adv_brk(TIMER1);
+ dispatch_tim_9_12(TIMER9);
+}
+
+void __irq_tim1_up_tim10(void) {
+ dispatch_adv_up(TIMER1);
+ dispatch_tim_10_11_13_14(TIMER10);
+}
+
+void __irq_tim1_trg_com_tim11(void) {
+ dispatch_adv_trg_com(TIMER1);
+ dispatch_tim_10_11_13_14(TIMER11);
+}
+
+void __irq_tim1_cc(void) {
+ dispatch_adv_cc(TIMER1);
+}
+
+void __irq_tim2(void) {
+ dispatch_general(TIMER2);
+}
+
+void __irq_tim3(void) {
+ dispatch_general(TIMER3);
+}
+
+void __irq_tim4(void) {
+ dispatch_general(TIMER4);
+}
+
+void __irq_tim5(void) {
+ dispatch_general(TIMER5);
+}
+
+/* FIXME: this is also the DAC DMA underrun interrupt, so it needs a
+ * different name (and to be supported?). */
+void __irq_tim6(void) {
+ dispatch_basic(TIMER6);
+}
+
+void __irq_tim7(void) {
+ dispatch_basic(TIMER7);
+}
+
+void __irq_tim8_brk_tim12(void) {
+ dispatch_adv_brk(TIMER8);
+ dispatch_tim_9_12(TIMER12);
+}
+
+void __irq_tim8_up_tim13(void) {
+ dispatch_adv_up(TIMER8);
+ dispatch_tim_10_11_13_14(TIMER13);
+}
+
+void __irq_tim8_trg_com_tim14(void) {
+ dispatch_adv_trg_com(TIMER8);
+ dispatch_tim_10_11_13_14(TIMER14);
+}
+
+void __irq_tim8_cc(void) {
+ dispatch_adv_cc(TIMER8);
+}
diff --git a/libmaple/stm32f2/usart.c b/libmaple/stm32f2/usart.c
new file mode 100644
index 0000000..1472d13
--- /dev/null
+++ b/libmaple/stm32f2/usart.c
@@ -0,0 +1,204 @@
+/******************************************************************************
+ * 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/usart.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F2 USART.
+ */
+
+#include <libmaple/usart.h>
+#include <libmaple/gpio.h>
+#include "usart_private.h"
+
+/*
+ * Devices
+ */
+
+static ring_buffer usart1_rb;
+static usart_dev usart1 = {
+ .regs = USART1_BASE,
+ .rb = &usart1_rb,
+ .max_baud = 4500000UL, /* TODO: are these correct? */
+ .clk_id = RCC_USART1,
+ .irq_num = NVIC_USART1,
+};
+/** USART1 device */
+usart_dev *USART1 = &usart1;
+
+static ring_buffer usart2_rb;
+static usart_dev usart2 = {
+ .regs = USART2_BASE,
+ .rb = &usart2_rb,
+ .max_baud = 2250000UL, /* TODO: are these correct? */
+ .clk_id = RCC_USART2,
+ .irq_num = NVIC_USART2,
+};
+/** USART2 device */
+usart_dev *USART2 = &usart2;
+
+static ring_buffer usart3_rb;
+static usart_dev usart3 = {
+ .regs = USART3_BASE,
+ .rb = &usart3_rb,
+ .max_baud = 2250000UL, /* TODO: are these correct? */
+ .clk_id = RCC_USART3,
+ .irq_num = NVIC_USART3,
+};
+/** USART3 device */
+usart_dev *USART3 = &usart3;
+
+static ring_buffer uart4_rb;
+static usart_dev uart4 = {
+ .regs = UART4_BASE,
+ .rb = &uart4_rb,
+ .max_baud = 2250000UL, /* TODO: are these correct? */
+ .clk_id = RCC_UART4,
+ .irq_num = NVIC_UART4,
+};
+/** UART4 device */
+usart_dev *UART4 = &uart4;
+
+static ring_buffer uart5_rb;
+static usart_dev uart5 = {
+ .regs = UART5_BASE,
+ .rb = &uart5_rb,
+ .max_baud = 2250000UL, /* TODO: are these correct? */
+ .clk_id = RCC_UART5,
+ .irq_num = NVIC_UART5,
+};
+/** UART5 device */
+usart_dev *UART5 = &uart5;
+
+static ring_buffer usart6_rb;
+static usart_dev usart6 = {
+ .regs = USART6_BASE,
+ .rb = &usart6_rb,
+ .max_baud = 4500000UL, /* TODO: are these correct? */
+ .clk_id = RCC_USART6,
+ .irq_num = NVIC_USART6,
+};
+usart_dev *USART6 = &usart6;
+
+/*
+ * Routines
+ */
+
+void usart_config_gpios_async(usart_dev *udev,
+ gpio_dev *rx_dev, uint8 rx,
+ gpio_dev *tx_dev, uint8 tx,
+ unsigned flags) {
+ gpio_af af = usart_get_af(udev);
+ gpio_set_modef(rx_dev, rx, GPIO_MODE_AF, 0);
+ gpio_set_modef(tx_dev, tx, GPIO_MODE_AF, 0);
+ gpio_set_af(rx_dev, rx, af);
+ gpio_set_af(tx_dev, tx, af);
+}
+
+void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) {
+ uint32 integer_part;
+ uint32 fractional_part;
+ uint32 tmp;
+ uint32 over8 = !!(dev->regs->CR1 & USART_CR1_OVER8);
+
+ ASSERT(!over8); /* OVER8 is currently unsupported. */
+
+ /* Figure out the clock speed, if the user doesn't give one. */
+ if (clock_speed == 0) {
+ clock_speed = _usart_clock_freq(dev);
+ }
+ ASSERT(clock_speed);
+
+ /* Convert desired baud rate to baud rate register setting. */
+ integer_part = (25 * clock_speed) / (2 * (2 - over8) * baud);
+ tmp = (integer_part / 100) << 4;
+ fractional_part = integer_part - (100 * (tmp >> 4));
+ tmp |= ((fractional_part * 16 + 50) / 100) & (uint8)0x0F;
+
+ dev->regs->BRR = tmp;
+}
+
+/**
+ * @brief Call a function on each USART.
+ * @param fn Function to call.
+ */
+void usart_foreach(void (*fn)(usart_dev*)) {
+ fn(USART1);
+ fn(USART2);
+ fn(USART3);
+ fn(UART4);
+ fn(UART5);
+ fn(USART6);
+}
+
+/**
+ * @brief Get GPIO alternate function mode for a USART.
+ * @param dev USART whose gpio_af to get.
+ * @return gpio_af corresponding to dev.
+ */
+gpio_af usart_get_af(usart_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_USART1:
+ case RCC_USART2:
+ case RCC_USART3:
+ return GPIO_AF_USART_1_2_3;
+ case RCC_UART4:
+ case RCC_UART5:
+ case RCC_USART6:
+ return GPIO_AF_USART_4_5_6;
+ default:
+ ASSERT(0); /* Can't happen */
+ return (gpio_af)-1;
+ }
+}
+
+/*
+ * Interrupt handlers.
+ */
+
+void __irq_usart1(void) {
+ usart_irq(&usart1_rb, USART1_BASE);
+}
+
+void __irq_usart2(void) {
+ usart_irq(&usart2_rb, USART2_BASE);
+}
+
+void __irq_usart3(void) {
+ usart_irq(&usart3_rb, USART3_BASE);
+}
+
+void __irq_uart4(void) {
+ usart_irq(&uart4_rb, UART4_BASE);
+}
+
+void __irq_uart5(void) {
+ usart_irq(&uart5_rb, UART5_BASE);
+}
+
+void __irq_usart6(void) {
+ usart_irq(&usart6_rb, USART6_BASE);
+}
diff --git a/libmaple/stm32f2/vector_table.S b/libmaple/stm32f2/vector_table.S
new file mode 100644
index 0000000..147e516
--- /dev/null
+++ b/libmaple/stm32f2/vector_table.S
@@ -0,0 +1,135 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 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.
+ *****************************************************************************/
+
+/* STM32F2 vector table */
+
+ .section ".stm32.interrupt_vector"
+
+ .globl __stm32_vector_table
+ .type __stm32_vector_table, %object
+
+__stm32_vector_table:
+/* CM3 core interrupts */
+ .long __msp_init
+ .long __exc_reset
+ .long __exc_nmi
+ .long __exc_hardfault
+ .long __exc_memmanage
+ .long __exc_busfault
+ .long __exc_usagefault
+ .long __stm32reservedexception7
+ .long __stm32reservedexception8
+ .long __stm32reservedexception9
+ .long __stm32reservedexception10
+ .long __exc_svc
+ .long __exc_debug_monitor
+ .long __stm32reservedexception13
+ .long __exc_pendsv
+ .long __exc_systick
+/* Peripheral interrupts */
+ .long __irq_wwdg
+ .long __irq_pvd
+ .long __irq_tamp_stamp
+ .long __irq_rtc_wkup
+ .long __irq_flash
+ .long __irq_rcc
+ .long __irq_exti0
+ .long __irq_exti1
+ .long __irq_exti2
+ .long __irq_exti3
+ .long __irq_exti4
+ .long __irq_dma1_stream0
+ .long __irq_dma1_stream1
+ .long __irq_dma1_stream2
+ .long __irq_dma1_stream3
+ .long __irq_dma1_stream4
+ .long __irq_dma1_stream5
+ .long __irq_dma1_stream6
+ .long __irq_adc
+ .long __irq_can1_tx
+ .long __irq_can1_rx0
+ .long __irq_can1_rx1
+ .long __irq_can1_sce
+ .long __irq_exti9_5
+ .long __irq_tim1_brk_tim9
+ .long __irq_tim1_up_tim10
+ .long __irq_tim1_trg_com_tim11
+ .long __irq_tim1_cc
+ .long __irq_tim2
+ .long __irq_tim3
+ .long __irq_tim4
+ .long __irq_i2c1_ev
+ .long __irq_i2c1_er
+ .long __irq_i2c2_ev
+ .long __irq_i2c2_er
+ .long __irq_spi1
+ .long __irq_spi2
+ .long __irq_usart1
+ .long __irq_usart2
+ .long __irq_usart3
+ .long __irq_exti15_10
+ .long __irq_rtc_alarm
+ .long __irq_otg_fs_wkup
+ .long __irq_tim8_brk_tim12
+ .long __irq_tim8_up_tim13
+ .long __irq_tim8_trg_com_tim14
+ .long __irq_tim8_cc
+ .long __irq_dma1_stream7
+ .long __irq_fsmc
+ .long __irq_sdio
+ .long __irq_tim5
+ .long __irq_spi3
+ .long __irq_uart4
+ .long __irq_uart5
+ .long __irq_tim6_dac
+ .long __irq_tim7
+ .long __irq_dma2_stream0
+ .long __irq_dma2_stream1
+ .long __irq_dma2_stream2
+ .long __irq_dma2_stream3
+ .long __irq_dma2_stream4
+ .long __irq_eth
+ .long __irq_eth_wkup
+ .long __irq_can2_tx
+ .long __irq_can2_rx0
+ .long __irq_can2_rx1
+ .long __irq_can2_sce
+ .long __irq_otg_fs
+ .long __irq_dma2_stream5
+ .long __irq_dma2_stream6
+ .long __irq_dma2_stream7
+ .long __irq_usart6
+ .long __irq_i2c3_ev
+ .long __irq_i2c3_er
+ .long __irq_otg_hs_ep1_out
+ .long __irq_otg_hs_ep1_in
+ .long __irq_otg_hs_wkup
+ .long __irq_otg_hs
+ .long __irq_dcmi
+ .long __irq_cryp
+ .long __irq_hash_rng
+
+ .size __stm32_vector_table, . - __stm32_vector_table
diff --git a/libmaple/syscalls.c b/libmaple/syscalls.c
deleted file mode 100644
index 8a57945..0000000
--- a/libmaple/syscalls.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/******************************************************************************
- * The MIT License
- *
- * 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 syscalls.c
- * @brief Low level system routines used by Newlib for basic I/O and
- * memory allocation.
- */
-
-#include "libmaple.h"
-
-#include <sys/stat.h>
-#include <errno.h>
-
-/* If CONFIG_HEAP_START (or CONFIG_HEAP_END) isn't defined, then
- * assume _lm_heap_start (resp. _lm_heap_end) is appropriately set by
- * the linker */
-#ifndef CONFIG_HEAP_START
-extern char _lm_heap_start;
-#define CONFIG_HEAP_START ((caddr_t)&_lm_heap_start)
-#endif
-#ifndef CONFIG_HEAP_END
-extern char _lm_heap_end;
-#define CONFIG_HEAP_END ((caddr_t)&_lm_heap_end)
-#endif
-
-/*
- * _sbrk -- Increment the program break.
- *
- * Get incr bytes more RAM (for use by the heap). malloc() and
- * friends call this function behind the scenes.
- */
-caddr_t _sbrk(int incr) {
- static caddr_t pbreak = NULL; /* current program break */
- caddr_t ret;
-
- if (pbreak == NULL) {
- pbreak = CONFIG_HEAP_START;
- }
-
- if ((CONFIG_HEAP_END - pbreak < incr) ||
- (pbreak - CONFIG_HEAP_START < -incr)) {
- errno = ENOMEM;
- return (caddr_t)-1;
- }
-
- ret = pbreak;
- pbreak += incr;
- return ret;
-}
-
-int _open(const char *path, int flags, ...) {
- return 1;
-}
-
-int _close(int fd) {
- return 0;
-}
-
-int _fstat(int fd, struct stat *st) {
- st->st_mode = S_IFCHR;
- return 0;
-}
-
-int _isatty(int fd) {
- return 1;
-}
-
-int isatty(int fd) {
- return 1;
-}
-
-int _lseek(int fd, off_t pos, int whence) {
- return -1;
-}
-
-unsigned char getch(void) {
- return 0;
-}
-
-
-int _read(int fd, char *buf, size_t cnt) {
- *buf = getch();
-
- return 1;
-}
-
-void putch(unsigned char c) {
-}
-
-void cgets(char *s, int bufsize) {
- char *p;
- int c;
- int i;
-
- for (i = 0; i < bufsize; i++) {
- *(s+i) = 0;
- }
-// memset(s, 0, bufsize);
-
- p = s;
-
- for (p = s; p < s + bufsize-1;) {
- c = getch();
- switch (c) {
- case '\r' :
- case '\n' :
- putch('\r');
- putch('\n');
- *p = '\n';
- return;
-
- case '\b' :
- if (p > s) {
- *p-- = 0;
- putch('\b');
- putch(' ');
- putch('\b');
- }
- break;
-
- default :
- putch(c);
- *p++ = c;
- break;
- }
- }
- return;
-}
-
-int _write(int fd, const char *buf, size_t cnt) {
- int i;
-
- for (i = 0; i < cnt; i++)
- putch(buf[i]);
-
- return cnt;
-}
-
-/* Override fgets() in newlib with a version that does line editing */
-char *fgets(char *s, int bufsize, void *f) {
- cgets(s, bufsize);
- return s;
-}
diff --git a/libmaple/systick.c b/libmaple/systick.c
index 9bb5d50..80c0c47 100644
--- a/libmaple/systick.c
+++ b/libmaple/systick.c
@@ -25,11 +25,11 @@
*****************************************************************************/
/**
- * @file systick.c
- * @brief System timer interrupt handler and initialization routines
+ * @file libmaple/systick.c
+ * @brief System timer (SysTick).
*/
-#include "systick.h"
+#include <libmaple/systick.h>
volatile uint32 systick_uptime_millis;
static void (*systick_user_callback)(void);
diff --git a/libmaple/timer.c b/libmaple/timer.c
index 83e9ace..24ae7fa 100644
--- a/libmaple/timer.c
+++ b/libmaple/timer.c
@@ -25,108 +25,150 @@
*****************************************************************************/
/**
- * @file timer.c
+ * @file libmaple/timer.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
- * @brief New-style timer interface
+ * @brief Portable timer routines.
*/
-#include "timer.h"
+#include <libmaple/timer.h>
+#include <libmaple/stm32.h>
+#include "timer_private.h"
-/* Just like the corresponding DIER bits:
- * [0] = Update handler;
- * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively;
- * [5] = COM;
- * [6] = TRG;
- * [7] = BRK. */
-#define NR_ADV_HANDLERS 8
-/* Update, capture/compare 1,2,3,4; <junk>; trigger. */
-#define NR_GEN_HANDLERS 7
-/* Update only. */
-#define NR_BAS_HANDLERS 1
+static void disable_channel(timer_dev *dev, uint8 channel);
+static void pwm_mode(timer_dev *dev, uint8 channel);
+static void output_compare_mode(timer_dev *dev, uint8 channel);
+
+static inline void enable_irq(timer_dev *dev, uint8 interrupt);
-static timer_dev timer1 = {
- .regs = { .adv = TIMER1_BASE },
- .clk_id = RCC_TIMER1,
- .type = TIMER_ADVANCED,
- .handlers = { [NR_ADV_HANDLERS - 1] = 0 },
-};
+/*
+ * Devices
+ *
+ * Defer to the timer_private API for declaring these.
+ */
+
+#if STM32_HAVE_TIMER(1)
+static timer_dev timer1 = ADVANCED_TIMER(1);
/** Timer 1 device (advanced) */
timer_dev *TIMER1 = &timer1;
-
-static timer_dev timer2 = {
- .regs = { .gen = TIMER2_BASE },
- .clk_id = RCC_TIMER2,
- .type = TIMER_GENERAL,
- .handlers = { [NR_GEN_HANDLERS - 1] = 0 },
-};
+#endif
+#if STM32_HAVE_TIMER(2)
+static timer_dev timer2 = GENERAL_TIMER(2);
/** Timer 2 device (general-purpose) */
timer_dev *TIMER2 = &timer2;
-
-static timer_dev timer3 = {
- .regs = { .gen = TIMER3_BASE },
- .clk_id = RCC_TIMER3,
- .type = TIMER_GENERAL,
- .handlers = { [NR_GEN_HANDLERS - 1] = 0 },
-};
+#endif
+#if STM32_HAVE_TIMER(3)
+static timer_dev timer3 = GENERAL_TIMER(3);
/** Timer 3 device (general-purpose) */
timer_dev *TIMER3 = &timer3;
-
-static timer_dev timer4 = {
- .regs = { .gen = TIMER4_BASE },
- .clk_id = RCC_TIMER4,
- .type = TIMER_GENERAL,
- .handlers = { [NR_GEN_HANDLERS - 1] = 0 },
-};
+#endif
+#if STM32_HAVE_TIMER(4)
+static timer_dev timer4 = GENERAL_TIMER(4);
/** Timer 4 device (general-purpose) */
timer_dev *TIMER4 = &timer4;
-
-#ifdef STM32_HIGH_DENSITY
-static timer_dev timer5 = {
- .regs = { .gen = TIMER5_BASE },
- .clk_id = RCC_TIMER5,
- .type = TIMER_GENERAL,
- .handlers = { [NR_GEN_HANDLERS - 1] = 0 },
-};
+#endif
+#if STM32_HAVE_TIMER(5)
+static timer_dev timer5 = GENERAL_TIMER(5);
/** Timer 5 device (general-purpose) */
timer_dev *TIMER5 = &timer5;
-
-static timer_dev timer6 = {
- .regs = { .bas = TIMER6_BASE },
- .clk_id = RCC_TIMER6,
- .type = TIMER_BASIC,
- .handlers = { [NR_BAS_HANDLERS - 1] = 0 },
-};
+#endif
+#if STM32_HAVE_TIMER(6)
+static timer_dev timer6 = BASIC_TIMER(6);
/** Timer 6 device (basic) */
timer_dev *TIMER6 = &timer6;
-
-static timer_dev timer7 = {
- .regs = { .bas = TIMER7_BASE },
- .clk_id = RCC_TIMER7,
- .type = TIMER_BASIC,
- .handlers = { [NR_BAS_HANDLERS - 1] = 0 },
-};
+#endif
+#if STM32_HAVE_TIMER(7)
+static timer_dev timer7 = BASIC_TIMER(7);
/** Timer 7 device (basic) */
timer_dev *TIMER7 = &timer7;
-
-static timer_dev timer8 = {
- .regs = { .adv = TIMER8_BASE },
- .clk_id = RCC_TIMER8,
- .type = TIMER_ADVANCED,
- .handlers = { [NR_ADV_HANDLERS - 1] = 0 },
-};
+#endif
+#if STM32_HAVE_TIMER(8)
+static timer_dev timer8 = ADVANCED_TIMER(8);
/** Timer 8 device (advanced) */
timer_dev *TIMER8 = &timer8;
#endif
+#if STM32_HAVE_TIMER(9)
+static timer_dev timer9 = RESTRICTED_GENERAL_TIMER(9, TIMER_DIER_TIE_BIT);
+/** Timer 9 device (general-purpose) */
+timer_dev *TIMER9 = &timer9;
+#endif
+#if STM32_HAVE_TIMER(10)
+static timer_dev timer10 = RESTRICTED_GENERAL_TIMER(10, TIMER_DIER_CC1IE_BIT);
+/** Timer 10 device (general-purpose) */
+timer_dev *TIMER10 = &timer10;
+#endif
+#if STM32_HAVE_TIMER(11)
+static timer_dev timer11 = RESTRICTED_GENERAL_TIMER(11, TIMER_DIER_CC1IE_BIT);
+/** Timer 11 device (general-purpose) */
+timer_dev *TIMER11 = &timer11;
+#endif
+#if STM32_HAVE_TIMER(12)
+static timer_dev timer12 = RESTRICTED_GENERAL_TIMER(12, TIMER_DIER_TIE_BIT);
+/** Timer 12 device (general-purpose) */
+timer_dev *TIMER12 = &timer12;
+#endif
+#if STM32_HAVE_TIMER(13)
+static timer_dev timer13 = RESTRICTED_GENERAL_TIMER(13, TIMER_DIER_CC1IE_BIT);
+/** Timer 13 device (general-purpose) */
+timer_dev *TIMER13 = &timer13;
+#endif
+#if STM32_HAVE_TIMER(14)
+static timer_dev timer14 = RESTRICTED_GENERAL_TIMER(14, TIMER_DIER_CC1IE_BIT);
+/** Timer 14 device (general-purpose) */
+timer_dev *TIMER14 = &timer14;
+#endif
/*
- * Convenience routines
+ * Routines
*/
-static void disable_channel(timer_dev *dev, uint8 channel);
-static void pwm_mode(timer_dev *dev, uint8 channel);
-static void output_compare_mode(timer_dev *dev, uint8 channel);
-
-static inline void enable_irq(timer_dev *dev, uint8 interrupt);
+/**
+ * @brief Call a function on timer devices.
+ * @param fn Function to call on each timer device.
+ */
+void timer_foreach(void (*fn)(timer_dev*)) {
+#if STM32_HAVE_TIMER(1)
+ fn(TIMER1);
+#endif
+#if STM32_HAVE_TIMER(2)
+ fn(TIMER2);
+#endif
+#if STM32_HAVE_TIMER(3)
+ fn(TIMER3);
+#endif
+#if STM32_HAVE_TIMER(4)
+ fn(TIMER4);
+#endif
+#if STM32_HAVE_TIMER(5)
+ fn(TIMER5);
+#endif
+#if STM32_HAVE_TIMER(6)
+ fn(TIMER6);
+#endif
+#if STM32_HAVE_TIMER(7)
+ fn(TIMER7);
+#endif
+#if STM32_HAVE_TIMER(8)
+ fn(TIMER8);
+#endif
+#if STM32_HAVE_TIMER(9)
+ fn(TIMER9);
+#endif
+#if STM32_HAVE_TIMER(10)
+ fn(TIMER10);
+#endif
+#if STM32_HAVE_TIMER(11)
+ fn(TIMER11);
+#endif
+#if STM32_HAVE_TIMER(12)
+ fn(TIMER12);
+#endif
+#if STM32_HAVE_TIMER(13)
+ fn(TIMER13);
+#endif
+#if STM32_HAVE_TIMER(14)
+ fn(TIMER14);
+#endif
+}
/**
* Initialize a timer, and reset its register map.
@@ -191,20 +233,31 @@ void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) {
}
/**
- * @brief Call a function on timer devices.
- * @param fn Function to call on each timer device.
+ * @brief Determine whether a timer has a particular capture/compare channel.
+ *
+ * Different timers have different numbers of capture/compare channels
+ * (and some have none at all). Use this function to test whether a
+ * given timer/channel combination will work.
+ *
+ * @param dev Timer device
+ * @param channel Capture/compare channel, from 1 to 4
+ * @return Nonzero if dev has channel, zero otherwise.
*/
-void timer_foreach(void (*fn)(timer_dev*)) {
- fn(TIMER1);
- fn(TIMER2);
- fn(TIMER3);
- fn(TIMER4);
-#ifdef STM32_HIGH_DENSITY
- fn(TIMER5);
- fn(TIMER6);
- fn(TIMER7);
- fn(TIMER8);
-#endif
+int timer_has_cc_channel(timer_dev *dev, uint8 channel) {
+ /* On all currently supported series: advanced and "full-featured"
+ * general purpose timers have all four channels. Of the
+ * restricted general timers, timers 9 and 12 have channels 1 and
+ * 2; the others have channel 1 only. Basic timers have none. */
+ rcc_clk_id id = dev->clk_id;
+ ASSERT((1 <= channel) && (channel <= 4));
+ if (id <= RCC_TIMER5 || id == RCC_TIMER8) {
+ return 1; /* 1 and 8 are advanced, 2-5 are "full" general */
+ } else if (id <= RCC_TIMER7) {
+ return 0; /* 6 and 7 are basic */
+ }
+ /* The rest are restricted general. */
+ return (((id == RCC_TIMER9 || id == RCC_TIMER12) && channel <= 2) ||
+ channel == 1);
}
/**
@@ -240,164 +293,6 @@ void timer_detach_interrupt(timer_dev *dev, uint8 interrupt) {
}
/*
- * IRQ handlers
- */
-
-static inline void dispatch_adv_brk(timer_dev *dev);
-static inline void dispatch_adv_up(timer_dev *dev);
-static inline void dispatch_adv_trg_com(timer_dev *dev);
-static inline void dispatch_adv_cc(timer_dev *dev);
-static inline void dispatch_general(timer_dev *dev);
-static inline void dispatch_basic(timer_dev *dev);
-
-void __irq_tim1_brk(void) {
- dispatch_adv_brk(TIMER1);
-}
-
-void __irq_tim1_up(void) {
- dispatch_adv_up(TIMER1);
-}
-
-void __irq_tim1_trg_com(void) {
- dispatch_adv_trg_com(TIMER1);
-}
-
-void __irq_tim1_cc(void) {
- dispatch_adv_cc(TIMER1);
-}
-
-void __irq_tim2(void) {
- dispatch_general(TIMER2);
-}
-
-void __irq_tim3(void) {
- dispatch_general(TIMER3);
-}
-
-void __irq_tim4(void) {
- dispatch_general(TIMER4);
-}
-
-#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
-
-void __irq_tim5(void) {
- dispatch_general(TIMER5);
-}
-
-void __irq_tim6(void) {
- dispatch_basic(TIMER6);
-}
-
-void __irq_tim7(void) {
- dispatch_basic(TIMER7);
-}
-
-void __irq_tim8_brk(void) {
- dispatch_adv_brk(TIMER8);
-}
-
-void __irq_tim8_up(void) {
- dispatch_adv_up(TIMER8);
-}
-
-void __irq_tim8_trg_com(void) {
- dispatch_adv_trg_com(TIMER8);
-}
-
-void __irq_tim8_cc(void) {
- dispatch_adv_cc(TIMER8);
-}
-#endif
-
-/* Note: the following dispatch routines make use of the fact that
- * DIER interrupt enable bits and SR interrupt flags have common bit
- * positions. Thus, ANDing DIER and SR lets us check if an interrupt
- * is enabled and if it has occurred simultaneously.
- */
-
-/* A special-case dispatch routine for single-interrupt NVIC lines.
- * This function assumes that the interrupt corresponding to `iid' has
- * in fact occurred (i.e., it doesn't check DIER & SR). */
-static inline void dispatch_single_irq(timer_dev *dev,
- timer_interrupt_id iid,
- uint32 irq_mask) {
- timer_bas_reg_map *regs = (dev->regs).bas;
- void (*handler)(void) = dev->handlers[iid];
- if (handler) {
- handler();
- regs->SR &= ~irq_mask;
- }
-}
-
-/* For dispatch routines which service multiple interrupts. */
-#define handle_irq(dier_sr, irq_mask, handlers, iid, handled_irq) do { \
- if ((dier_sr) & (irq_mask)) { \
- void (*__handler)(void) = (handlers)[iid]; \
- if (__handler) { \
- __handler(); \
- handled_irq |= (irq_mask); \
- } \
- } \
- } while (0)
-
-static inline void dispatch_adv_brk(timer_dev *dev) {
- dispatch_single_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF);
-}
-
-static inline void dispatch_adv_up(timer_dev *dev) {
- dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
-}
-
-static inline void dispatch_adv_trg_com(timer_dev *dev) {
- timer_adv_reg_map *regs = (dev->regs).adv;
- uint32 dsr = regs->DIER & regs->SR;
- void (**hs)(void) = dev->handlers;
- uint32 handled = 0; /* Logical OR of SR interrupt flags we end up
- * handling. We clear these. User handlers
- * must clear overcapture flags, to avoid
- * wasting time in output mode. */
-
- handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_COMIF, hs, TIMER_COM_INTERRUPT, handled);
-
- regs->SR &= ~handled;
-}
-
-static inline void dispatch_adv_cc(timer_dev *dev) {
- timer_adv_reg_map *regs = (dev->regs).adv;
- uint32 dsr = regs->DIER & regs->SR;
- void (**hs)(void) = dev->handlers;
- uint32 handled = 0;
-
- handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
-
- regs->SR &= ~handled;
-}
-
-static inline void dispatch_general(timer_dev *dev) {
- timer_gen_reg_map *regs = (dev->regs).gen;
- uint32 dsr = regs->DIER & regs->SR;
- void (**hs)(void) = dev->handlers;
- uint32 handled = 0;
-
- handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
- handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled);
-
- regs->SR &= ~handled;
-}
-
-static inline void dispatch_basic(timer_dev *dev) {
- dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
-}
-
-/*
* Utilities
*/
@@ -417,64 +312,101 @@ static void output_compare_mode(timer_dev *dev, uint8 channel) {
timer_cc_enable(dev, channel);
}
-static void enable_advanced_irq(timer_dev *dev, timer_interrupt_id id);
-static void enable_nonmuxed_irq(timer_dev *dev);
+static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id);
+static void enable_bas_gen_irq(timer_dev *dev);
static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid) {
if (dev->type == TIMER_ADVANCED) {
- enable_advanced_irq(dev, iid);
+ enable_adv_irq(dev, iid);
} else {
- enable_nonmuxed_irq(dev);
+ enable_bas_gen_irq(dev);
}
}
-static void enable_advanced_irq(timer_dev *dev, timer_interrupt_id id) {
- uint8 is_timer1 = dev->clk_id == RCC_TIMER1;
-
+/* Advanced control timers have several IRQ lines corresponding to
+ * different timer interrupts.
+ *
+ * Note: This function assumes that the only advanced timers are TIM1
+ * and TIM8, and needs the obvious changes if that assumption is
+ * violated by a later STM32 series. */
+static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id) {
+ uint8 is_tim1 = dev->clk_id == RCC_TIMER1;
+ nvic_irq_num irq_num;
switch (id) {
case TIMER_UPDATE_INTERRUPT:
- nvic_irq_enable(is_timer1 ? NVIC_TIMER1_UP : NVIC_TIMER8_UP);
+ irq_num = (is_tim1 ?
+ NVIC_TIMER1_UP_TIMER10 :
+ NVIC_TIMER8_UP_TIMER13);
break;
- case TIMER_CC1_INTERRUPT:
- case TIMER_CC2_INTERRUPT:
- case TIMER_CC3_INTERRUPT:
+ case TIMER_CC1_INTERRUPT: /* Fall through */
+ case TIMER_CC2_INTERRUPT: /* ... */
+ case TIMER_CC3_INTERRUPT: /* ... */
case TIMER_CC4_INTERRUPT:
- nvic_irq_enable(is_timer1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC);
+ irq_num = is_tim1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC;
break;
- case TIMER_COM_INTERRUPT:
+ case TIMER_COM_INTERRUPT: /* Fall through */
case TIMER_TRG_INTERRUPT:
- nvic_irq_enable(is_timer1 ? NVIC_TIMER1_TRG_COM : NVIC_TIMER8_TRG_COM);
+ irq_num = (is_tim1 ?
+ NVIC_TIMER1_TRG_COM_TIMER11 :
+ NVIC_TIMER8_TRG_COM_TIMER14);
break;
case TIMER_BREAK_INTERRUPT:
- nvic_irq_enable(is_timer1 ? NVIC_TIMER1_BRK : NVIC_TIMER8_BRK);
+ irq_num = (is_tim1 ?
+ NVIC_TIMER1_BRK_TIMER9 :
+ NVIC_TIMER8_BRK_TIMER12);
break;
+ default:
+ /* Can't happen, but placate the compiler */
+ ASSERT(0);
+ return;
}
+ nvic_irq_enable(irq_num);
}
-static void enable_nonmuxed_irq(timer_dev *dev) {
+/* Basic and general purpose timers have a single IRQ line, which is
+ * shared by all interrupts supported by a particular timer. */
+static void enable_bas_gen_irq(timer_dev *dev) {
+ nvic_irq_num irq_num;
switch (dev->clk_id) {
case RCC_TIMER2:
- nvic_irq_enable(NVIC_TIMER2);
+ irq_num = NVIC_TIMER2;
break;
case RCC_TIMER3:
- nvic_irq_enable(NVIC_TIMER3);
+ irq_num = NVIC_TIMER3;
break;
case RCC_TIMER4:
- nvic_irq_enable(NVIC_TIMER4);
+ irq_num = NVIC_TIMER4;
break;
-#ifdef STM32_HIGH_DENSITY
case RCC_TIMER5:
- nvic_irq_enable(NVIC_TIMER5);
+ irq_num = NVIC_TIMER5;
break;
case RCC_TIMER6:
- nvic_irq_enable(NVIC_TIMER6);
+ irq_num = NVIC_TIMER6;
break;
case RCC_TIMER7:
- nvic_irq_enable(NVIC_TIMER7);
+ irq_num = NVIC_TIMER7;
+ break;
+ case RCC_TIMER9:
+ irq_num = NVIC_TIMER1_BRK_TIMER9;
+ break;
+ case RCC_TIMER10:
+ irq_num = NVIC_TIMER1_UP_TIMER10;
+ break;
+ case RCC_TIMER11:
+ irq_num = NVIC_TIMER1_TRG_COM_TIMER11;
+ break;
+ case RCC_TIMER12:
+ irq_num = NVIC_TIMER8_BRK_TIMER12;
+ break;
+ case RCC_TIMER13:
+ irq_num = NVIC_TIMER8_UP_TIMER13;
+ break;
+ case RCC_TIMER14:
+ irq_num = NVIC_TIMER8_TRG_COM_TIMER14;
break;
-#endif
default:
ASSERT_FAULT(0);
- break;
+ return;
}
+ nvic_irq_enable(irq_num);
}
diff --git a/libmaple/timer_private.h b/libmaple/timer_private.h
new file mode 100644
index 0000000..320c636
--- /dev/null
+++ b/libmaple/timer_private.h
@@ -0,0 +1,235 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011, 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/timer_private.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Private, internal timer APIs.
+ */
+
+#ifndef _LIBMAPLE_TIMER_PRIVATE_H_
+#define _LIBMAPLE_TIMER_PRIVATE_H_
+
+/*
+ * Helper macros for declaring timer_devs of various timer_types
+ */
+
+/* The indexes of user handlers in a timer_dev.handlers are just like
+ * the corresponding DIER bits, as follows: */
+
+/* Advanced timers:
+ * [0] = Update handler;
+ * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively;
+ * [5] = COM;
+ * [6] = TRG;
+ * [7] = BRK. */
+#define NR_ADV_HANDLERS 8
+/* General purpose timers:
+ * [0] = update;
+ * [1,2,3,4] = capture/compare 1,2,3,4;
+ * [5] = <junk>;
+ * [6] = trigger. */
+#define NR_GEN_HANDLERS 7
+/* Basic timers:
+ * [0] = update. */
+#define NR_BAS_HANDLERS 1
+
+/* For declaring advanced timers. */
+#define ADVANCED_TIMER(num) \
+ { \
+ .regs = { .adv = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_ADVANCED, \
+ .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, \
+ }
+
+/* For declaring full-featured general purpose timers. */
+#define GENERAL_TIMER(num) \
+ { \
+ .regs = { .gen = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_GENERAL, \
+ .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, \
+ }
+
+/* For declaring general purpose timers with limited interrupt
+ * capability (e.g. timers 9 through 14 on STM32F2 and XL-density
+ * STM32F1). */
+#define RESTRICTED_GENERAL_TIMER(num, max_dier_bit) \
+ { \
+ .regs = { .gen = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_GENERAL, \
+ .handlers = { [max_dier_bit] = 0 }, \
+ }
+
+/* For declaring basic timers (e.g. TIM6 and TIM7). */
+#define BASIC_TIMER(num) \
+ { \
+ .regs = { .bas = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_BASIC, \
+ .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, \
+ }
+
+/*
+ * IRQ handlers
+ *
+ * These decode TIMx_DIER and TIMx_SR, then dispatch to the user-level
+ * IRQ handlers. They also clean up TIMx_SR afterwards, so the user
+ * doesn't have to deal with register details.
+ *
+ * Notes:
+ *
+ * - These dispatch routines make use of the fact that DIER interrupt
+ * enable bits and SR interrupt flags have common bit positions.
+ * Thus, ANDing DIER and SR lets us check if an interrupt is enabled
+ * and if it has occurred simultaneously.
+ *
+ * - We force these routines to inline to avoid call overhead, but
+ * there aren't any measurements to prove that this is actually a
+ * good idea. Profile-directed optimizations are definitely wanted. */
+
+/* A special-case dispatch routine for timers which only serve a
+ * single interrupt on a given IRQ line.
+ *
+ * This function still checks DIER & SR, as in some cases, a timer may
+ * only serve a single interrupt on a particular NVIC line, but that
+ * line may be shared with another timer. For example, the timer 1
+ * update interrupt shares an IRQ line with the timer 10 interrupt on
+ * STM32F1 (XL-density), STM32F2, and STM32F4. */
+static __always_inline void dispatch_single_irq(timer_dev *dev,
+ timer_interrupt_id iid,
+ uint32 irq_mask) {
+ timer_bas_reg_map *regs = (dev->regs).bas;
+ if (regs->DIER & regs->SR & irq_mask) {
+ void (*handler)(void) = dev->handlers[iid];
+ if (handler) {
+ handler();
+ regs->SR &= ~irq_mask;
+ }
+ }
+}
+
+/* Helper macro for dispatch routines which service multiple interrupts. */
+#define handle_irq(dier_sr, irq_mask, handlers, iid, handled_irq) do { \
+ if ((dier_sr) & (irq_mask)) { \
+ void (*__handler)(void) = (handlers)[iid]; \
+ if (__handler) { \
+ __handler(); \
+ handled_irq |= (irq_mask); \
+ } \
+ } \
+ } while (0)
+
+static __always_inline void dispatch_adv_brk(timer_dev *dev) {
+ dispatch_single_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF);
+}
+
+static __always_inline void dispatch_adv_up(timer_dev *dev) {
+ dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
+}
+
+static __always_inline void dispatch_adv_trg_com(timer_dev *dev) {
+ timer_adv_reg_map *regs = (dev->regs).adv;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0; /* Logical OR of SR interrupt flags we end up
+ * handling. We clear these. User handlers
+ * must clear overcapture flags, to avoid
+ * wasting time in output mode. */
+
+ handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_COMIF, hs, TIMER_COM_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+static __always_inline void dispatch_adv_cc(timer_dev *dev) {
+ timer_adv_reg_map *regs = (dev->regs).adv;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0;
+
+ handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+static __always_inline void dispatch_general(timer_dev *dev) {
+ timer_gen_reg_map *regs = (dev->regs).gen;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0;
+
+ handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+/* On F1 (XL-density), F2, and F4, TIM9 and TIM12 are restricted
+ * general-purpose timers with update, CC1, CC2, and TRG interrupts. */
+static __always_inline void dispatch_tim_9_12(timer_dev *dev) {
+ timer_gen_reg_map *regs = (dev->regs).gen;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0;
+
+ handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+/* On F1 (XL-density), F2, and F4, timers 10, 11, 13, and 14 are
+ * restricted general-purpose timers with update and CC1 interrupts. */
+static __always_inline void dispatch_tim_10_11_13_14(timer_dev *dev) {
+ timer_gen_reg_map *regs = (dev->regs).gen;
+ uint32 dsr = regs->DIER & regs->SR;
+ void (**hs)(void) = dev->handlers;
+ uint32 handled = 0;
+
+ handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled);
+ handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled);
+
+ regs->SR &= ~handled;
+}
+
+static __always_inline void dispatch_basic(timer_dev *dev) {
+ dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
+}
+
+#endif
diff --git a/libmaple/usart.c b/libmaple/usart.c
index 0bdc37a..253cf9f 100644
--- a/libmaple/usart.c
+++ b/libmaple/usart.c
@@ -25,74 +25,13 @@
*****************************************************************************/
/**
- * @file usart.c
+ * @file libmaple/usart.c
* @author Marti Bolivar <mbolivar@leaflabs.com>,
* Perry Hung <perry@leaflabs.com>
- * @brief USART control routines
+ * @brief Portable USART routines
*/
-#include "usart.h"
-
-/*
- * Devices
- */
-
-static ring_buffer usart1_rb;
-static usart_dev usart1 = {
- .regs = USART1_BASE,
- .rb = &usart1_rb,
- .max_baud = 4500000UL,
- .clk_id = RCC_USART1,
- .irq_num = NVIC_USART1
-};
-/** USART1 device */
-usart_dev *USART1 = &usart1;
-
-static ring_buffer usart2_rb;
-static usart_dev usart2 = {
- .regs = USART2_BASE,
- .rb = &usart2_rb,
- .max_baud = 2250000UL,
- .clk_id = RCC_USART2,
- .irq_num = NVIC_USART2
-};
-/** USART2 device */
-usart_dev *USART2 = &usart2;
-
-static ring_buffer usart3_rb;
-static usart_dev usart3 = {
- .regs = USART3_BASE,
- .rb = &usart3_rb,
- .max_baud = 2250000UL,
- .clk_id = RCC_USART3,
- .irq_num = NVIC_USART3
-};
-/** USART3 device */
-usart_dev *USART3 = &usart3;
-
-#ifdef STM32_HIGH_DENSITY
-static ring_buffer uart4_rb;
-static usart_dev uart4 = {
- .regs = UART4_BASE,
- .rb = &uart4_rb,
- .max_baud = 2250000UL,
- .clk_id = RCC_UART4,
- .irq_num = NVIC_UART4
-};
-/** UART4 device */
-usart_dev *UART4 = &uart4;
-
-static ring_buffer uart5_rb;
-static usart_dev uart5 = {
- .regs = UART5_BASE,
- .rb = &uart5_rb,
- .max_baud = 2250000UL,
- .clk_id = RCC_UART5,
- .irq_num = NVIC_UART5
-};
-/** UART5 device */
-usart_dev *UART5 = &uart5;
-#endif
+#include <libmaple/usart.h>
/**
* @brief Initialize a serial port.
@@ -105,27 +44,6 @@ void usart_init(usart_dev *dev) {
}
/**
- * @brief Configure a serial port's baud rate.
- *
- * @param dev Serial port to be configured
- * @param clock_speed Clock speed, in megahertz.
- * @param baud Baud rate for transmit/receive.
- */
-void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) {
- uint32 integer_part;
- uint32 fractional_part;
- uint32 tmp;
-
- /* See ST RM0008 for the details on configuring the baud rate register */
- integer_part = (25 * clock_speed) / (4 * baud);
- tmp = (integer_part / 100) << 4;
- fractional_part = integer_part - (100 * (tmp >> 4));
- tmp |= (((fractional_part * 16) + 50) / 100) & ((uint8)0x0F);
-
- dev->regs->BRR = (uint16)tmp;
-}
-
-/**
* @brief Enable a serial port.
*
* USART is enabled in single buffer transmission mode, multibuffer
@@ -138,7 +56,8 @@ void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) {
*/
void usart_enable(usart_dev *dev) {
usart_reg_map *regs = dev->regs;
- regs->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
+ regs->CR1 = (USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE |
+ USART_CR1_M_8N1);
regs->CR1 |= USART_CR1_UE;
}
@@ -147,7 +66,7 @@ void usart_enable(usart_dev *dev) {
* @param dev Serial port to be disabled
*/
void usart_disable(usart_dev *dev) {
- /* FIXME this misbehaves if you try to use PWM on TX afterwards */
+ /* FIXME this misbehaves (on F1) if you try to use PWM on TX afterwards */
usart_reg_map *regs = dev->regs;
/* TC bit must be high before disabling the USART */
@@ -162,20 +81,6 @@ void usart_disable(usart_dev *dev) {
}
/**
- * @brief Call a function on each USART.
- * @param fn Function to call.
- */
-void usart_foreach(void (*fn)(usart_dev*)) {
- fn(USART1);
- fn(USART2);
- fn(USART3);
-#ifdef STM32_HIGH_DENSITY
- fn(UART4);
- fn(UART5);
-#endif
-}
-
-/**
* @brief Nonblocking USART transmit
* @param dev Serial port to transmit over
* @param buf Buffer to transmit
@@ -230,40 +135,3 @@ void usart_putudec(usart_dev *dev, uint32 val) {
usart_putc(dev, digits[i]);
}
}
-
-/*
- * Interrupt handlers.
- */
-
-static inline void usart_irq(usart_dev *dev) {
-#ifdef USART_SAFE_INSERT
- /* If the buffer is full and the user defines USART_SAFE_INSERT,
- * ignore new bytes. */
- rb_safe_insert(dev->rb, (uint8)dev->regs->DR);
-#else
- /* By default, push bytes around in the ring buffer. */
- rb_push_insert(dev->rb, (uint8)dev->regs->DR);
-#endif
-}
-
-void __irq_usart1(void) {
- usart_irq(USART1);
-}
-
-void __irq_usart2(void) {
- usart_irq(USART2);
-}
-
-void __irq_usart3(void) {
- usart_irq(USART3);
-}
-
-#ifdef STM32_HIGH_DENSITY
-void __irq_uart4(void) {
- usart_irq(UART4);
-}
-
-void __irq_uart5(void) {
- usart_irq(UART5);
-}
-#endif
diff --git a/libmaple/usart_private.c b/libmaple/usart_private.c
new file mode 100644
index 0000000..0eaacdf
--- /dev/null
+++ b/libmaple/usart_private.c
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * 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/usart_private.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Private USART routines.
+ */
+
+#include "usart_private.h"
+#include <libmaple/rcc.h>
+#include <libmaple/stm32.h>
+
+uint32 _usart_clock_freq(usart_dev *dev) {
+ rcc_clk_domain domain = rcc_dev_clk(dev->clk_id);
+ return (domain == RCC_APB1 ? STM32_PCLK1 :
+ (domain == RCC_APB2 ? STM32_PCLK2 : 0));
+}
diff --git a/libmaple/usart_private.h b/libmaple/usart_private.h
new file mode 100644
index 0000000..8e8e11b
--- /dev/null
+++ b/libmaple/usart_private.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * 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/usart_private.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Private USART header.
+ */
+
+#ifndef _LIBMAPLE_USART_PRIVATE_H_
+#define _LIBMAPLE_USART_PRIVATE_H_
+
+#include <libmaple/ring_buffer.h>
+#include <libmaple/usart.h>
+
+static __always_inline void usart_irq(ring_buffer *rb, usart_reg_map *regs) {
+#ifdef USART_SAFE_INSERT
+ /* If the buffer is full and the user defines USART_SAFE_INSERT,
+ * ignore new bytes. */
+ rb_safe_insert(rb, (uint8)regs->DR);
+#else
+ /* By default, push bytes around in the ring buffer. */
+ rb_push_insert(rb, (uint8)regs->DR);
+#endif
+}
+
+uint32 _usart_clock_freq(usart_dev *dev);
+
+#endif
diff --git a/libmaple/usb/README b/libmaple/usb/README
index 2c55364..d0fca8d 100644
--- a/libmaple/usb/README
+++ b/libmaple/usb/README
@@ -1,35 +1,24 @@
-The USB submodule of libmaple is responsible for:
-
- Initializing the USB peripheral, scaling the peripheral clocks
- appropriately, enabling the interrupt channels to USB, defining
- the USB IRQ, resetting the USB DISC pin (used to tell the host
- were alive). Additionally, the USB submodule defines the virtual
- COM port interface that is exposed to user sketches via SerialUSB.
-
-To use it:
-
- SerialUSB.print/ln, available(), read(), write() implement the same
- interface as Serial1/2/3.
+The USB submodule of libmaple is a separate piece of the codebase for
+reasons that are largely historical.
Current Status:
- Currently, the USB submodule relies on the low level core library
- provided by ST to implement the USB transfer protocol for control
- endpoint transfers. The high level virtual com port application
- is unfortunately hard to untangle from this low level dependence,
- and when a new USB core library is written (to nix ST dependence)
- changes will likely have to be made to virtual com application
- code. Ideally, the new core library should mimic the form of MyUSB
- (LUFA), since this library (USB for AVR) is growing in popularity
- and in example applications.
+ There's only support for the USB device peripheral found on
+ STM32F103s.
- The virtual com port serves two important purposes.
+ We rely on the low level core library provided by ST to implement
+ the USB transfer protocol for control endpoint transfers.
- 1) It allows serial data transfers between user sketches an a
- host computer.
+ The virtual com port (which is exposed via
+ <libmaple/usb_cdcacm.h>) serves two important purposes.
- 2) It allows the host machine to issue a system reset by
- asserting the DTR signal.
+ 1) It allows serial data transfers between user sketches an a
+ host computer.
+
+ 2) It allows the host PC to issue a system reset into the DFU
+ bootloader with the DTR + RTS + "1EAF" sequence (see
+ leaflabs.com/docs/bootloader.html for more information on
+ this).
After reset, Maple will run the DFU bootloader for a few seconds,
during which the user can begin a DFU upload operation (uploads
@@ -38,11 +27,11 @@ Current Status:
the chip in order to enable the bootloader.
If you would like to develop your own USB application for whatever
- reason (uses faster isochronous enpoints for streaming audio, or
- implements the USB HID or Mass Storage specs for examples) then
+ reason (e.g. to use faster isochronous enpoints for streaming
+ audio, or implement the USB HID or Mass Storage specs), then
ensure that you leave some hook for resetting Maple remotely in
- order to spin up the DFU bootloader. Please make sure to give
- yourself a unique vendor/product ID pair in your application, as
+ order to spin up the DFU bootloader. Please make sure to get
+ yourself a unique vendor/product ID pair for your application, as
some operating systems will assign a host-side driver based on
these tags.
@@ -52,21 +41,23 @@ Current Status:
be a burden from the host driver side, as Windows and *nix handle
compound USB devices quite differently.
- Be mindful that enabling the USB peripheral isnt "free." The
+ Be mindful that enabling the USB peripheral isn't "free." The
device must respond to periodic bus activity (every few
milliseconds) by servicing an ISR. Therefore, the USB application
- should be disabled inside of timing critical applications. In
- order to disconnect the device from the host, the USB_DISC pin can
- be asserted (on Maple this is GPIO C12). Alternatively, the NVIC
+ should be disabled inside of timing critical applications.
+
+ In order to disconnect the device from the host, a USB_DISC pin is
+ asserted (e.g. on Maple, this is PC12). Alternatively, the NVIC
can be directly configured to disable the USB LP/HP IRQ's.
The files inside of usb_lib were provided by ST and are subject to
their own license, all other files were written by the LeafLabs
team and fall under the MIT license.
-Todo:
+TODO:
- - write custom low level USB stack to strip out any remaining
- dependence on ST code
- - add a high level USB application library that would allow users
- to make their own HID/Mass Storage/Audio/Video devices.
+ - Generic USB driver core with series-provided backends, like
+ libopencm3 has.
+ - Strip out ST code.
+ - Integration with a high level USB library (like LUFA/MyUSB) to
+ allow users to write custom USB applications.
diff --git a/libmaple/usb/rules.mk b/libmaple/usb/rules.mk
new file mode 100644
index 0000000..e8ccc15
--- /dev/null
+++ b/libmaple/usb/rules.mk
@@ -0,0 +1,45 @@
+# Standard things
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(dir)
+BUILDDIRS += $(BUILD_PATH)/$(d)
+
+# Local flags
+CFLAGS_$(d) = -I$(d) -I$(d)/$(MCU_SERIES) -I$(d)/usb_lib $(LIBMAPLE_INCLUDES) $(LIBMAPLE_PRIVATE_INCLUDES) -Wall
+
+# Add usblib and series subdirectory to BUILDDIRS.
+BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_SERIES)
+BUILDDIRS += $(BUILD_PATH)/$(d)/usb_lib
+
+# Local rules and targets
+sSRCS_$(d) :=
+cSRCS_$(d) :=
+# We currently only have F1 performance line support. Sigh.
+ifeq ($(MCU_SERIES), stm32f1)
+ifeq ($(MCU_F1_LINE), performance)
+cSRCS_$(d) += $(MCU_SERIES)/usb.c
+cSRCS_$(d) += $(MCU_SERIES)/usb_reg_map.c
+cSRCS_$(d) += $(MCU_SERIES)/usb_cdcacm.c
+cSRCS_$(d) += usb_lib/usb_core.c
+cSRCS_$(d) += usb_lib/usb_init.c
+cSRCS_$(d) += usb_lib/usb_mem.c
+cSRCS_$(d) += usb_lib/usb_regs.c
+endif
+endif
+
+sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
+cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
+
+OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
+ $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o)
+DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
+
+$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
+$(OBJS_$(d)): TGT_ASFLAGS :=
+
+TGT_BIN += $(OBJS_$(d))
+
+# Standard things
+-include $(DEPS_$(d))
+d := $(dirstack_$(sp))
+sp := $(basename $(sp))
diff --git a/libmaple/usb/usb.c b/libmaple/usb/stm32f1/usb.c
index 667b11f..0130bab 100644
--- a/libmaple/usb/usb.c
+++ b/libmaple/usb/stm32f1/usb.c
@@ -25,18 +25,22 @@
*****************************************************************************/
/**
- * @file usb.c
+ * @file libmaple/usb/usb.c
* @brief USB support.
+ *
+ * This is a mess. What we need almost amounts to a ground-up rewrite.
*/
-#include "usb.h"
+#include <libmaple/usb.h>
-#include "libmaple.h"
-#include "rcc.h"
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
+/* Private headers */
#include "usb_reg_map.h"
#include "usb_lib_globals.h"
+/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
diff --git a/libmaple/usb/usb_cdcacm.c b/libmaple/usb/stm32f1/usb_cdcacm.c
index b41753a..6ef4806 100644
--- a/libmaple/usb/usb_cdcacm.c
+++ b/libmaple/usb/stm32f1/usb_cdcacm.c
@@ -25,22 +25,26 @@
*****************************************************************************/
/**
- * @file usb_cdcacm.c
+ * @file libmaple/usb/usb_cdcacm.c
+ * @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM).
*
- * @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM) state and
- * routines.
+ * FIXME: this works on the STM32F1 USB peripherals, and probably no
+ * place else. Nonportable bits really need to be factored out, and
+ * the result made cleaner.
*/
-#include "usb_cdcacm.h"
+#include <libmaple/usb_cdcacm.h>
-#include "nvic.h"
-#include "delay.h"
+#include <libmaple/usb.h>
+#include <libmaple/nvic.h>
+#include <libmaple/delay.h>
-#include "usb.h"
+/* Private headers */
#include "usb_descriptors.h"
#include "usb_lib_globals.h"
#include "usb_reg_map.h"
+/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
@@ -59,12 +63,8 @@
#if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \
defined(BOARD_maple_mini) || defined(BOARD_maple_native))
-
-#warning ("Warning! USB VCOM relies on LeafLabs board-specific " \
- "configuration right now. If you want, you can pretend " \
- "you're one of our boards; i.e., #define BOARD_maple, " \
- "BOARD_maple_mini, etc. according to what matches your MCU " \
- "best."
+#warning USB CDC ACM relies on LeafLabs board-specific configuration.\
+ You may have problems on non-LeafLabs boards.
#endif
static void vcomDataTxCb(void);
diff --git a/libmaple/usb/usb_descriptors.h b/libmaple/usb/stm32f1/usb_descriptors.h
index 405588a..9bcb2b6 100644
--- a/libmaple/usb/usb_descriptors.h
+++ b/libmaple/usb/stm32f1/usb_descriptors.h
@@ -27,7 +27,7 @@
#ifndef _USB_DESCRIPTORS_H_
#define _USB_DESCRIPTORS_H_
-#include "libmaple.h"
+#include <libmaple/libmaple.h>
#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
diff --git a/libmaple/usb/usb_lib_globals.h b/libmaple/usb/stm32f1/usb_lib_globals.h
index a494817..1cd2754 100644
--- a/libmaple/usb/usb_lib_globals.h
+++ b/libmaple/usb/stm32f1/usb_lib_globals.h
@@ -27,6 +27,7 @@
#ifndef _USB_LIB_GLOBALS_H_
#define _USB_LIB_GLOBALS_H_
+/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
diff --git a/libmaple/usb/usb_reg_map.c b/libmaple/usb/stm32f1/usb_reg_map.c
index 75562e1..75562e1 100644
--- a/libmaple/usb/usb_reg_map.c
+++ b/libmaple/usb/stm32f1/usb_reg_map.c
diff --git a/libmaple/usb/usb_reg_map.h b/libmaple/usb/stm32f1/usb_reg_map.h
index 5bf5d96..ce80842 100644
--- a/libmaple/usb/usb_reg_map.h
+++ b/libmaple/usb/stm32f1/usb_reg_map.h
@@ -24,8 +24,8 @@
* SOFTWARE.
*****************************************************************************/
-#include "libmaple_types.h"
-#include "util.h"
+#include <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
#ifndef _USB_REG_MAP_H_
#define _USB_REG_MAP_H_
diff --git a/libmaple/util.c b/libmaple/util.c
index b15d658..2ee5ede 100644
--- a/libmaple/util.c
+++ b/libmaple/util.c
@@ -25,26 +25,18 @@
*****************************************************************************/
/**
- * @file util.c
- * @brief Utility procedures for debugging, mostly an error LED fade
- * and messages dumped over a UART for failed asserts.
+ * @file libmaple/util.c
+ * @brief Utility procedures for debugging
*/
-#include "libmaple.h"
-#include "usart.h"
-#include "gpio.h"
-#include "nvic.h"
-#include "adc.h"
-#include "timer.h"
+#include <libmaple/libmaple.h>
+#include <libmaple/usart.h>
+#include <libmaple/gpio.h>
+#include <libmaple/nvic.h>
-/* Failed ASSERT()s send out a message using this USART config. */
-#ifndef ERROR_USART
-#define ERROR_USART USART2
-#define ERROR_USART_CLK_SPEED STM32_PCLK1
-#define ERROR_USART_BAUD 9600
-#define ERROR_TX_PORT GPIOA
-#define ERROR_TX_PIN 2
-#endif
+/* (Undocumented) hooks used by Wirish to direct our behavior here */
+extern __weak void __lm_error(void);
+extern __weak usart_dev* __lm_enable_error_usart(void);
/* If you define ERROR_LED_PORT and ERROR_LED_PIN, then a failed
* ASSERT() will also throb() an LED connected to that port and pin.
@@ -53,105 +45,82 @@
#define HAVE_ERROR_LED
#endif
-/**
- * @brief Disables all peripheral interrupts except USB and fades the
- * error LED.
- */
/* (Called from exc.S with global interrupts disabled.) */
-void __error(void) {
- /* Turn off peripheral interrupts */
- nvic_irq_disable_all();
-
- /* Turn off timers */
- timer_disable_all();
-
- /* Turn off ADC */
- adc_disable_all();
-
- /* Turn off all USARTs */
- usart_disable_all();
-
- /* Turn the USB interrupt back on so the bootloader keeps on functioning */
- nvic_irq_enable(NVIC_USB_HP_CAN_TX);
- nvic_irq_enable(NVIC_USB_LP_CAN_RX0);
-
+__attribute__((noreturn)) void __error(void) {
+ if (__lm_error) {
+ __lm_error();
+ }
/* Reenable global interrupts */
nvic_globalirq_enable();
throb();
}
-/**
- * @brief Enable the error USART for writing.
- * @sideeffect Configures ERROR_USART appropriately for writing.
- */
-void _enable_error_usart() {
- gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_AF_OUTPUT_PP);
- usart_init(ERROR_USART);
- usart_set_baud_rate(ERROR_USART, ERROR_USART_CLK_SPEED, ERROR_USART_BAUD);
-}
-
-/**
- * @brief Print an error message on a UART upon a failed assertion
- * and throb the error LED, if there is one defined.
+/*
+ * Print an error message on a UART upon a failed assertion (if one is
+ * available), and punt to __error().
+ *
* @param file Source file of failed assertion
* @param line Source line of failed assertion
* @param exp String representation of failed assertion
* @sideeffect Turns of all peripheral interrupts except USB.
*/
void _fail(const char* file, int line, const char* exp) {
- /* Initialize the error USART */
- _enable_error_usart();
-
- /* Print failed assert message */
- usart_putstr(ERROR_USART, "ERROR: FAILED ASSERT(");
- usart_putstr(ERROR_USART, exp);
- usart_putstr(ERROR_USART, "): ");
- usart_putstr(ERROR_USART, file);
- usart_putstr(ERROR_USART, ": ");
- usart_putudec(ERROR_USART, line);
- usart_putc(ERROR_USART, '\n');
- usart_putc(ERROR_USART, '\r');
-
+ if (__lm_enable_error_usart) {
+ /* Initialize the error USART */
+ usart_dev *err_usart = __lm_enable_error_usart();
+
+ /* Print failed assert message */
+ usart_putstr(err_usart, "ERROR: FAILED ASSERT(");
+ usart_putstr(err_usart, exp);
+ usart_putstr(err_usart, "): ");
+ usart_putstr(err_usart, file);
+ usart_putstr(err_usart, ": ");
+ usart_putudec(err_usart, line);
+ usart_putc(err_usart, '\n');
+ usart_putc(err_usart, '\r');
+ }
/* Shutdown and error fade */
__error();
}
-/**
- * @brief Provide an __assert_func handler to libc so that calls to assert() get
- * redirected to _fail.
+/*
+ * Provide an __assert_func handler to libc so that calls to assert()
+ * get redirected to _fail.
*/
void __assert_func(const char* file, int line, const char* method,
const char* expression) {
_fail(file, line, expression);
}
-/**
- * @brief Provide an abort() implementation that aborts execution and enters an
- * error state with the throbbing LED indicator.
+/*
+ * Provide an abort() implementation that aborts execution and punts
+ * to __error().
*/
void abort() {
- /* Initialize the error USART */
- _enable_error_usart();
-
- /* Print abort message. */
- usart_putstr(ERROR_USART, "ERROR: PROGRAM ABORTED VIA abort()\n\r");
+ if (__lm_enable_error_usart) {
+ /* Initialize the error USART */
+ usart_dev *err_usart = __lm_enable_error_usart();
+ /* Print abort message. */
+ usart_putstr(err_usart, "ERROR: PROGRAM ABORTED VIA abort()\r\n");
+ }
/* Shutdown and error fade */
__error();
}
+/* This was public as of v0.0.12, so we've got to keep it public. */
/**
* @brief Fades the error LED on and off
* @sideeffect Sets output push-pull on ERROR_LED_PIN.
*/
-void throb(void) {
+__attribute__((noreturn)) void throb(void) {
#ifdef HAVE_ERROR_LED
int32 slope = 1;
uint32 CC = 0x0000;
uint32 TOP_CNT = 0x0200;
uint32 i = 0;
- gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_OUTPUT_PP);
+ gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT);
/* Error fade. */
while (1) {
if (CC == TOP_CNT) {