aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/include
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@leaflabs.com>2012-06-26 18:24:49 -0400
committerMarti Bolivar <mbolivar@leaflabs.com>2012-06-26 18:32:57 -0400
commitf005bd3a5c087e3d5559f2858a1e7898a4f92a8d (patch)
tree0701628a68056f7b5f92d5a5af5f281f58e6a71e /libmaple/include
parent761e059962e8f53f3cceef61d65bf2bf3025319a (diff)
parentc6073e4886da4606679bc3e9d770c9cff9390597 (diff)
downloadlibrambutan-f005bd3a5c087e3d5559f2858a1e7898a4f92a8d.tar.gz
librambutan-f005bd3a5c087e3d5559f2858a1e7898a4f92a8d.zip
Merge branch 'wip-family-support'
Merge the long-lived (too long; future changes like these will need to proceed more incrementally) development branch of libmaple, containing experimental STM32F2 and STM32F1 value line support, into master. This required many changes to the structure of the library. The most important structural reorganizations occurred in: - 954f9e5: moves public headers to include directories - 3efa313: uses "series" instead of "family" - c0d60e3: adds board files to the build system, to make it easier to add new boards - 096d86c: adds build logic for targeting different STM32 series (e.g. STM32F1, STM32F2) This last commit in particular (096d86c) is the basis for the repartitioning of libmaple into portable sections, which work on all supported MCUs, and nonportable sections, which are segregated into separate directories and contain all series-specific code. Moving existing STM32F1-only code into libmaple/stm32f1 and wirish/stm32f1, along with adding equivalents under .../stm32f2 directories, was the principal project of this branch. Important API changes occur in several places. Existing code is still expected to work on STM32F1 targets, but there have been many deprecations. A detailed changelog explaining the situation needs to be prepared. F2 and F1 value line support is not complete; the merge is proceeding prematurely in this respect. We've been getting more libmaple patches from the community lately, and I'm worried that the merge conflicts with the old tree structure will become painful to manage. Conflicts: Makefile Resolved Makefile conflicts manually; this required propagating -Xlinker usage into support/make/target-config.mk. Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
Diffstat (limited to 'libmaple/include')
-rw-r--r--libmaple/include/libmaple/adc.h329
-rw-r--r--libmaple/include/libmaple/bitband.h128
-rw-r--r--libmaple/include/libmaple/bkp.h166
-rw-r--r--libmaple/include/libmaple/dac.h158
-rw-r--r--libmaple/include/libmaple/delay.h65
-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.h340
-rw-r--r--libmaple/include/libmaple/gpio.h121
-rw-r--r--libmaple/include/libmaple/i2c.h413
-rw-r--r--libmaple/include/libmaple/i2c_common.h95
-rw-r--r--libmaple/include/libmaple/iwdg.h115
-rw-r--r--libmaple/include/libmaple/libmaple.h57
-rw-r--r--libmaple/include/libmaple/libmaple_types.h72
-rw-r--r--libmaple/include/libmaple/nvic.h155
-rw-r--r--libmaple/include/libmaple/pwr.h115
-rw-r--r--libmaple/include/libmaple/rcc.h175
-rw-r--r--libmaple/include/libmaple/ring_buffer.h188
-rw-r--r--libmaple/include/libmaple/scb.h209
-rw-r--r--libmaple/include/libmaple/spi.h469
-rw-r--r--libmaple/include/libmaple/stm32.h237
-rw-r--r--libmaple/include/libmaple/syscfg.h151
-rw-r--r--libmaple/include/libmaple/systick.h115
-rw-r--r--libmaple/include/libmaple/timer.h1110
-rw-r--r--libmaple/include/libmaple/usart.h495
-rw-r--r--libmaple/include/libmaple/usb.h82
-rw-r--r--libmaple/include/libmaple/usb_cdcacm.h59
-rw-r--r--libmaple/include/libmaple/util.h111
30 files changed, 6532 insertions, 0 deletions
diff --git a/libmaple/include/libmaple/adc.h b/libmaple/include/libmaple/adc.h
new file mode 100644
index 0000000..a500af7
--- /dev/null
+++ b/libmaple/include/libmaple/adc.h
@@ -0,0 +1,329 @@
+/******************************************************************************
+ * 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/include/libmaple/adc.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief Analog-to-Digital Conversion (ADC) header.
+ */
+
+#ifndef _LIBMAPLE_ADC_H_
+#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
+ __io uint32 CR1; ///< Control register 1
+ __io uint32 CR2; ///< Control register 2
+ __io uint32 SMPR1; ///< Sample time register 1
+ __io uint32 SMPR2; ///< Sample time register 2
+ __io uint32 JOFR1; ///< Injected channel data offset register 1
+ __io uint32 JOFR2; ///< Injected channel data offset register 2
+ __io uint32 JOFR3; ///< Injected channel data offset register 3
+ __io uint32 JOFR4; ///< Injected channel data offset register 4
+ __io uint32 HTR; ///< Watchdog high threshold register
+ __io uint32 LTR; ///< Watchdog low threshold register
+ __io uint32 SQR1; ///< Regular sequence register 1
+ __io uint32 SQR2; ///< Regular sequence register 2
+ __io uint32 SQR3; ///< Regular sequence register 3
+ __io uint32 JSQR; ///< Injected sequence register
+ __io uint32 JDR1; ///< Injected data register 1
+ __io uint32 JDR2; ///< Injected data register 2
+ __io uint32 JDR3; ///< Injected data register 3
+ __io uint32 JDR4; ///< Injected data register 4
+ __io uint32 DR; ///< Regular data register
+} adc_reg_map;
+
+/** ADC device type. */
+typedef struct adc_dev {
+ adc_reg_map *regs; /**< Register map */
+ rcc_clk_id clk_id; /**< RCC clock information */
+} adc_dev;
+
+/* 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.
+ */
+#include <series/adc.h>
+
+/*
+ * Register bit definitions
+ */
+
+/* Status register */
+
+#define ADC_SR_AWD_BIT 0
+#define ADC_SR_EOC_BIT 1
+#define ADC_SR_JEOC_BIT 2
+#define ADC_SR_JSTRT_BIT 3
+#define ADC_SR_STRT_BIT 4
+
+#define ADC_SR_AWD BIT(ADC_SR_AWD_BIT)
+#define ADC_SR_EOC BIT(ADC_SR_EOC_BIT)
+#define ADC_SR_JEOC BIT(ADC_SR_JEOC_BIT)
+#define ADC_SR_JSTRT BIT(ADC_SR_JSTRT_BIT)
+#define ADC_SR_STRT BIT(ADC_SR_STRT_BIT)
+
+/* Control register 1 */
+
+#define ADC_CR1_EOCIE_BIT 5
+#define ADC_CR1_AWDIE_BIT 6
+#define ADC_CR1_JEOCIE_BIT 7
+#define ADC_CR1_SCAN_BIT 8
+#define ADC_CR1_AWDSGL_BIT 9
+#define ADC_CR1_JAUTO_BIT 10
+#define ADC_CR1_DISCEN_BIT 11
+#define ADC_CR1_JDISCEN_BIT 12
+#define ADC_CR1_JAWDEN_BIT 22
+#define ADC_CR1_AWDEN_BIT 23
+
+#define ADC_CR1_AWDCH (0x1F)
+#define ADC_CR1_EOCIE BIT(ADC_CR1_EOCIE_BIT)
+#define ADC_CR1_AWDIE BIT(ADC_CR1_AWDIE_BIT)
+#define ADC_CR1_JEOCIE BIT(ADC_CR1_JEOCIE_BIT)
+#define ADC_CR1_SCAN BIT(ADC_CR1_SCAN_BIT)
+#define ADC_CR1_AWDSGL BIT(ADC_CR1_AWDSGL_BIT)
+#define ADC_CR1_JAUTO BIT(ADC_CR1_JAUTO_BIT)
+#define ADC_CR1_DISCEN BIT(ADC_CR1_DISCEN_BIT)
+#define ADC_CR1_JDISCEN BIT(ADC_CR1_JDISCEN_BIT)
+#define ADC_CR1_DISCNUM (0xE000)
+#define ADC_CR1_JAWDEN BIT(ADC_CR1_JAWDEN_BIT)
+#define ADC_CR1_AWDEN BIT(ADC_CR1_AWDEN_BIT)
+
+/* Control register 2 */
+
+/* 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 */
+
+#define ADC_SMPR1_SMP17 (0x7 << 21)
+#define ADC_SMPR1_SMP16 (0x7 << 18)
+#define ADC_SMPR1_SMP15 (0x7 << 15)
+#define ADC_SMPR1_SMP14 (0x7 << 12)
+#define ADC_SMPR1_SMP13 (0x7 << 9)
+#define ADC_SMPR1_SMP12 (0x7 << 6)
+#define ADC_SMPR1_SMP11 (0x7 << 3)
+#define ADC_SMPR1_SMP10 0x7
+
+/* Sample time register 2 */
+
+#define ADC_SMPR2_SMP9 (0x7 << 27)
+#define ADC_SMPR2_SMP8 (0x7 << 24)
+#define ADC_SMPR2_SMP7 (0x7 << 21)
+#define ADC_SMPR2_SMP6 (0x7 << 18)
+#define ADC_SMPR2_SMP5 (0x7 << 15)
+#define ADC_SMPR2_SMP4 (0x7 << 12)
+#define ADC_SMPR2_SMP3 (0x7 << 9)
+#define ADC_SMPR2_SMP2 (0x7 << 6)
+#define ADC_SMPR2_SMP1 (0x7 << 3)
+#define ADC_SMPR2_SMP0 0x7
+
+/* Injected channel data offset register */
+
+#define ADC_JOFR_JOFFSET 0x3FF
+
+/* Watchdog high threshold register */
+
+#define ADC_HTR_HT 0x3FF
+
+/* Watchdog low threshold register */
+
+#define ADC_LTR_LT 0x3FF
+
+/* Regular sequence register 1 */
+
+#define ADC_SQR1_L (0x1F << 20)
+#define ADC_SQR1_SQ16 (0x1F << 15)
+#define ADC_SQR1_SQ15 (0x1F << 10)
+#define ADC_SQR1_SQ14 (0x1F << 5)
+#define ADC_SQR1_SQ13 0x1F
+
+/* Regular sequence register 2 */
+
+#define ADC_SQR2_SQ12 (0x1F << 25)
+#define ADC_SQR2_SQ11 (0x1F << 20)
+#define ADC_SQR2_SQ10 (0x1F << 16)
+#define ADC_SQR2_SQ9 (0x1F << 10)
+#define ADC_SQR2_SQ8 (0x1F << 5)
+#define ADC_SQR2_SQ7 0x1F
+
+/* Regular sequence register 3 */
+
+#define ADC_SQR3_SQ6 (0x1F << 25)
+#define ADC_SQR3_SQ5 (0x1F << 20)
+#define ADC_SQR3_SQ4 (0x1F << 16)
+#define ADC_SQR3_SQ3 (0x1F << 10)
+#define ADC_SQR3_SQ2 (0x1F << 5)
+#define ADC_SQR3_SQ1 0x1F
+
+/* Injected sequence register */
+
+#define ADC_JSQR_JL (0x3 << 20)
+#define ADC_JSQR_JL_1CONV (0x0 << 20)
+#define ADC_JSQR_JL_2CONV (0x1 << 20)
+#define ADC_JSQR_JL_3CONV (0x2 << 20)
+#define ADC_JSQR_JL_4CONV (0x3 << 20)
+#define ADC_JSQR_JSQ4 (0x1F << 15)
+#define ADC_JSQR_JSQ3 (0x1F << 10)
+#define ADC_JSQR_JSQ2 (0x1F << 5)
+#define ADC_JSQR_JSQ1 0x1F
+
+/* Injected data registers */
+
+#define ADC_JDR_JDATA 0xFFFF
+
+/* Regular data register */
+
+#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 Set the ADC prescaler.
+ *
+ * This determines the ADC clock for all devices.
+ */
+extern void adc_set_prescaler(adc_prescaler pre);
+
+/**
+ * @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 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.
+ */
+extern void adc_config_gpio(const struct adc_dev *dev,
+ struct gpio_dev *gdev,
+ uint8 bit);
+
+/**
+ * @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.
+ *
+ * Defines the total number of conversions in the regular channel
+ * conversion sequence.
+ *
+ * @param dev ADC device.
+ * @param length Regular channel sequence length, from 1 to 16.
+ */
+static inline void adc_set_reg_seqlen(const adc_dev *dev, uint8 length) {
+ uint32 tmp = dev->regs->SQR1;
+ tmp &= ~ADC_SQR1_L;
+ tmp |= (length - 1) << 20;
+ dev->regs->SQR1 = tmp;
+}
+
+/**
+ * @brief Enable an adc peripheral
+ * @param dev ADC device to enable
+ */
+static inline void adc_enable(const adc_dev *dev) {
+ *bb_perip(&dev->regs->CR2, ADC_CR2_ADON_BIT) = 1;
+}
+
+/**
+ * @brief Disable an ADC peripheral
+ * @param dev ADC device to disable
+ */
+static inline void adc_disable(const adc_dev *dev) {
+ *bb_perip(&dev->regs->CR2, ADC_CR2_ADON_BIT) = 0;
+}
+
+/**
+ * @brief Disable all ADC peripherals.
+ */
+static inline void adc_disable_all(void) {
+ adc_foreach(adc_disable);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/bitband.h b/libmaple/include/libmaple/bitband.h
new file mode 100644
index 0000000..6e77991
--- /dev/null
+++ b/libmaple/include/libmaple/bitband.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ * 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/include/libmaple/bitband.h
+ *
+ * @brief Bit-banding utility functions
+ */
+
+#ifndef _LIBMAPLE_BITBAND_H_
+#define _LIBMAPLE_BITBAND_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+#define BB_SRAM_REF 0x20000000
+#define BB_SRAM_BASE 0x22000000
+#define BB_PERI_REF 0x40000000
+#define BB_PERI_BASE 0x42000000
+
+static inline volatile uint32* __bb_addr(volatile void*,
+ uint32,
+ uint32,
+ uint32);
+
+/**
+ * @brief Obtain a pointer to the bit-band address corresponding to a
+ * bit in a volatile SRAM address.
+ * @param address Address in the bit-banded SRAM region
+ * @param bit Bit in address to bit-band
+ */
+static inline volatile uint32* bb_sramp(volatile void *address, uint32 bit) {
+ return __bb_addr(address, bit, BB_SRAM_BASE, BB_SRAM_REF);
+}
+
+/**
+ * @brief Get a bit from an address in the SRAM bit-band region.
+ * @param address Address in the SRAM bit-band region to read from
+ * @param bit Bit in address to read
+ * @return bit's value in address.
+ */
+static inline uint8 bb_sram_get_bit(volatile void *address, uint32 bit) {
+ return *bb_sramp(address, bit);
+}
+
+/**
+ * @brief Set a bit in an address in the SRAM bit-band region.
+ * @param address Address in the SRAM bit-band region to write to
+ * @param bit Bit in address to write to
+ * @param val Value to write for bit, either 0 or 1.
+ */
+static inline void bb_sram_set_bit(volatile void *address,
+ uint32 bit,
+ uint8 val) {
+ *bb_sramp(address, bit) = val;
+}
+
+/**
+ * @brief Obtain a pointer to the bit-band address corresponding to a
+ * bit in a peripheral address.
+ * @param address Address in the bit-banded peripheral region
+ * @param bit Bit in address to bit-band
+ */
+static inline volatile uint32* bb_perip(volatile void *address, uint32 bit) {
+ return __bb_addr(address, bit, BB_PERI_BASE, BB_PERI_REF);
+}
+
+/**
+ * @brief Get a bit from an address in the peripheral bit-band region.
+ * @param address Address in the peripheral bit-band region to read from
+ * @param bit Bit in address to read
+ * @return bit's value in address.
+ */
+static inline uint8 bb_peri_get_bit(volatile void *address, uint32 bit) {
+ return *bb_perip(address, bit);
+}
+
+/**
+ * @brief Set a bit in an address in the peripheral bit-band region.
+ * @param address Address in the peripheral bit-band region to write to
+ * @param bit Bit in address to write to
+ * @param val Value to write for bit, either 0 or 1.
+ */
+static inline void bb_peri_set_bit(volatile void *address,
+ uint32 bit,
+ uint8 val) {
+ *bb_perip(address, bit) = val;
+}
+
+static inline volatile uint32* __bb_addr(volatile void *address,
+ uint32 bit,
+ uint32 bb_base,
+ uint32 bb_ref) {
+ return (volatile uint32*)(bb_base + ((uint32)address - bb_ref) * 32 +
+ bit * 4);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/bkp.h b/libmaple/include/libmaple/bkp.h
new file mode 100644
index 0000000..bb63a2f
--- /dev/null
+++ b/libmaple/include/libmaple/bkp.h
@@ -0,0 +1,166 @@
+/******************************************************************************
+ * 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 libmaple/include/libmaple/bkp.h
+ * @brief Backup register support (STM32F1 only).
+ */
+
+#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)
+#define BKP_NR_DATA_REGS 42
+#endif
+
+/** Backup peripheral register map type. */
+typedef struct bkp_reg_map {
+ const uint32 RESERVED1; ///< Reserved
+ __io uint32 DR1; ///< Data register 1
+ __io uint32 DR2; ///< Data register 2
+ __io uint32 DR3; ///< Data register 3
+ __io uint32 DR4; ///< Data register 4
+ __io uint32 DR5; ///< Data register 5
+ __io uint32 DR6; ///< Data register 6
+ __io uint32 DR7; ///< Data register 7
+ __io uint32 DR8; ///< Data register 8
+ __io uint32 DR9; ///< Data register 9
+ __io uint32 DR10; ///< Data register 10
+ __io uint32 RTCCR; ///< RTC control register
+ __io uint32 CR; ///< Control register
+ __io uint32 CSR; ///< Control and status register
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ const uint32 RESERVED2; ///< Reserved
+ const uint32 RESERVED3; ///< Reserved
+ __io uint32 DR11; ///< Data register 11
+ __io uint32 DR12; ///< Data register 12
+ __io uint32 DR13; ///< Data register 13
+ __io uint32 DR14; ///< Data register 14
+ __io uint32 DR15; ///< Data register 15
+ __io uint32 DR16; ///< Data register 16
+ __io uint32 DR17; ///< Data register 17
+ __io uint32 DR18; ///< Data register 18
+ __io uint32 DR19; ///< Data register 19
+ __io uint32 DR20; ///< Data register 20
+ __io uint32 DR21; ///< Data register 21
+ __io uint32 DR22; ///< Data register 22
+ __io uint32 DR23; ///< Data register 23
+ __io uint32 DR24; ///< Data register 24
+ __io uint32 DR25; ///< Data register 25
+ __io uint32 DR26; ///< Data register 26
+ __io uint32 DR27; ///< Data register 27
+ __io uint32 DR28; ///< Data register 28
+ __io uint32 DR29; ///< Data register 29
+ __io uint32 DR30; ///< Data register 30
+ __io uint32 DR31; ///< Data register 31
+ __io uint32 DR32; ///< Data register 32
+ __io uint32 DR33; ///< Data register 33
+ __io uint32 DR34; ///< Data register 34
+ __io uint32 DR35; ///< Data register 35
+ __io uint32 DR36; ///< Data register 36
+ __io uint32 DR37; ///< Data register 37
+ __io uint32 DR38; ///< Data register 38
+ __io uint32 DR39; ///< Data register 39
+ __io uint32 DR40; ///< Data register 40
+ __io uint32 DR41; ///< Data register 41
+ __io uint32 DR42; ///< Data register 42
+#endif
+} bkp_reg_map;
+
+/** Backup peripheral register map base pointer. */
+#define BKP_BASE ((struct bkp_reg_map*)0x40006C00)
+
+/** Backup peripheral device type. */
+typedef struct bkp_dev {
+ bkp_reg_map *regs; /**< Register map */
+} bkp_dev;
+
+extern const bkp_dev *BKP;
+
+/*
+ * Register bit definitions
+ */
+
+/* Data Registers */
+
+#define BKP_DR_D 0xFFFF
+
+/* RTC Clock Calibration Register */
+
+#define BKP_RTCCR_ASOS_BIT 9
+#define BKP_RTCCR_ASOE_BIT 8
+#define BKP_RTCCR_CCO_BIT 7
+
+#define BKP_RTCCR_ASOS BIT(BKP_RTCCR_ASOS_BIT)
+#define BKP_RTCCR_ASOE BIT(BKP_RTCCR_ASOE_BIT)
+#define BKP_RTCCR_CCO BIT(BKP_RTCCR_CCO_BIT)
+#define BKP_RTCCR_CAL 0x7F
+
+/* Backup control register */
+
+#define BKP_CR_TPAL_BIT 1
+#define BKP_CR_TPE_BIT 0
+
+#define BKP_CR_TPAL BIT(BKP_CR_TPAL_BIT)
+#define BKP_CR_TPE BIT(BKP_CR_TPE_BIT)
+
+/* Backup control/status register */
+
+#define BKP_CSR_TIF_BIT 9
+#define BKP_CSR_TEF_BIT 8
+#define BKP_CSR_TPIE_BIT 2
+#define BKP_CSR_CTI_BIT 1
+#define BKP_CSR_CTE_BIT 0
+
+#define BKP_CSR_TIF BIT(BKP_CSR_TIF_BIT)
+#define BKP_CSR_TEF BIT(BKP_CSR_TEF_BIT)
+#define BKP_CSR_TPIE BIT(BKP_CSR_TPIE_BIT)
+#define BKP_CSR_CTI BIT(BKP_CSR_CTI_BIT)
+#define BKP_CSR_CTE BIT(BKP_CSR_CTE_BIT)
+
+/*
+ * Convenience functions
+ */
+
+void bkp_init(void);
+void bkp_enable_writes(void);
+void bkp_disable_writes(void);
+uint16 bkp_read(uint8 reg);
+void bkp_write(uint8 reg, uint16 val);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
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/include/libmaple/delay.h b/libmaple/include/libmaple/delay.h
new file mode 100644
index 0000000..472a208
--- /dev/null
+++ b/libmaple/include/libmaple/delay.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * 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/include/libmaple/delay.h
+ * @brief Delay implementation
+ */
+
+#ifndef _LIBMAPLE_DELAY_H_
+#define _LIBMAPLE_DELAY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/stm32.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");
+}
+
+#ifdef __cplusplus
+}
+#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/include/libmaple/fsmc.h b/libmaple/include/libmaple/fsmc.h
new file mode 100644
index 0000000..6225fee
--- /dev/null
+++ b/libmaple/include/libmaple/fsmc.h
@@ -0,0 +1,340 @@
+/******************************************************************************
+ * 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 libmaple/include/libmaple/fsmc.h
+ * @brief Flexible static memory controller support.
+ */
+
+/*
+ * See ../notes/fsmc.txt for more info
+ */
+
+#ifndef _LIBMAPLE_FSMC_H_
+#define _LIBMAPLE_FSMC_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#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
+ */
+
+/** FSMC register map type */
+typedef struct fsmc_reg_map {
+ __io uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */
+ __io uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */
+ __io uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */
+ __io uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */
+ __io uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */
+ __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */
+ __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */
+ __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */
+ const uint8 RESERVED1[64]; /**< Reserved */
+ __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */
+ __io uint32 SR2; /**< FIFO status and interrupt register 2 */
+ __io uint32 PMEM2; /**< Common memory space timing register 2 */
+ __io uint32 PATT2; /**< Attribute memory space timing register 2 */
+ const uint8 RESERVED2[4]; /**< Reserved */
+ __io uint32 ECCR2; /**< ECC result register 2 */
+ const uint8 RESERVED3[2];
+ __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */
+ __io uint32 SR3; /**< FIFO status and interrupt register 3 */
+ __io uint32 PMEM3; /**< Common memory space timing register 3 */
+ __io uint32 PATT3; /**< Attribute memory space timing register 3 */
+ const uint32 RESERVED4; /**< Reserved */
+ __io uint32 ECCR3; /**< ECC result register 3 */
+ const uint8 RESERVED5[8]; /**< Reserved */
+ __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */
+ __io uint32 SR4; /**< FIFO status and interrupt register 4 */
+ __io uint32 PMEM4; /**< Common memory space timing register 4 */
+ __io uint32 PATT4; /**< Attribute memory space timing register 4 */
+ __io uint32 PIO4; /**< I/O space timing register 4 */
+ const uint8 RESERVED6[80]; /**< Reserved */
+ __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */
+ const uint32 RESERVED7; /**< Reserved */
+ __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */
+ const uint32 RESERVED8; /**< Reserved */
+ __io uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */
+ const uint32 RESERVED9; /**< Reserved */
+ __io uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */
+} __attribute__((packed)) fsmc_reg_map;
+
+#define __FSMCB 0xA0000000
+
+/** FSMC register map base pointer */
+#define FSMC_BASE ((struct fsmc_reg_map*)__FSMCB)
+
+/** FSMC NOR/PSRAM register map type */
+typedef struct fsmc_nor_psram_reg_map {
+ __io uint32 BCR; /**< Chip-select control register */
+ __io uint32 BTR; /**< Chip-select timing register */
+ const uint8 RESERVED[252]; /**< Reserved */
+ __io uint32 BWTR; /**< Write timing register */
+} fsmc_nor_psram_reg_map;
+
+/** FSMC NOR/PSRAM base pointer 1 */
+#define FSMC_NOR_PSRAM1_BASE ((struct fsmc_nor_psram_reg_map*)__FSMCB)
+
+/** FSMC NOR/PSRAM base pointer 2 */
+#define FSMC_NOR_PSRAM2_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x8))
+
+/** FSMC NOR/PSRAM base pointer 3 */
+#define FSMC_NOR_PSRAM3_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x10))
+
+/** FSMC NOR/PSRAM base pointer 4 */
+#define FSMC_NOR_PSRAM4_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x18))
+
+/*
+ * Register bit definitions
+ */
+
+/* NOR/PSRAM chip-select control registers */
+
+#define FSMC_BCR_CBURSTRW_BIT 19
+#define FSMC_BCR_ASYNCWAIT_BIT 15
+#define FSMC_BCR_EXTMOD_BIT 14
+#define FSMC_BCR_WAITEN_BIT 13
+#define FSMC_BCR_WREN_BIT 12
+#define FSMC_BCR_WAITCFG_BIT 11
+#define FSMC_BCR_WRAPMOD_BIT 10
+#define FSMC_BCR_WAITPOL_BIT 9
+#define FSMC_BCR_BURSTEN_BIT 8
+#define FSMC_BCR_FACCEN_BIT 6
+#define FSMC_BCR_MUXEN_BIT 1
+#define FSMC_BCR_MBKEN_BIT 0
+
+#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)
+#define FSMC_BCR_MTYP (0x3 << 2)
+#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 (1U << FSMC_BCR_MUXEN_BIT)
+#define FSMC_BCR_MBKEN (1U << FSMC_BCR_MBKEN_BIT)
+
+/* SRAM/NOR-Flash chip-select timing registers */
+
+#define FSMC_BTR_ACCMOD (0x3 << 28)
+#define FSMC_BTR_ACCMOD_A (0x0 << 28)
+#define FSMC_BTR_ACCMOD_B (0x1 << 28)
+#define FSMC_BTR_ACCMOD_C (0x2 << 28)
+#define FSMC_BTR_ACCMOD_D (0x3 << 28)
+#define FSMC_BTR_DATLAT (0xF << 24)
+#define FSMC_BTR_CLKDIV (0xF << 20)
+#define FSMC_BTR_BUSTURN (0xF << 16)
+#define FSMC_BTR_DATAST (0xFF << 8)
+#define FSMC_BTR_ADDHLD (0xF << 4)
+#define FSMC_BTR_ADDSET 0xF
+
+/* SRAM/NOR-Flash write timing registers */
+
+#define FSMC_BWTR_ACCMOD (0x3 << 28)
+#define FSMC_BWTR_ACCMOD_A (0x0 << 28)
+#define FSMC_BWTR_ACCMOD_B (0x1 << 28)
+#define FSMC_BWTR_ACCMOD_C (0x2 << 28)
+#define FSMC_BWTR_ACCMOD_D (0x3 << 28)
+#define FSMC_BWTR_DATLAT (0xF << 24)
+#define FSMC_BWTR_CLKDIV (0xF << 20)
+#define FSMC_BWTR_DATAST (0xFF << 8)
+#define FSMC_BWTR_ADDHLD (0xF << 4)
+#define FSMC_BWTR_ADDSET 0xF
+
+/* NAND Flash/PC Card controller registers */
+
+#define FSMC_PCR_ECCEN_BIT 6
+#define FSMC_PCR_PTYP_BIT 3
+#define FSMC_PCR_PBKEN_BIT 2
+#define FSMC_PCR_PWAITEN_BIT 1
+
+#define FSMC_PCR_ECCPS (0x7 << 17)
+#define FSMC_PCR_ECCPS_256B (0x0 << 17)
+#define FSMC_PCR_ECCPS_512B (0x1 << 17)
+#define FSMC_PCR_ECCPS_1024B (0x2 << 17)
+#define FSMC_PCR_ECCPS_2048B (0x3 << 17)
+#define FSMC_PCR_ECCPS_4096B (0x4 << 17)
+#define FSMC_PCR_ECCPS_8192B (0x5 << 17)
+#define FSMC_PCR_TAR (0xF << 13)
+#define FSMC_PCR_TCLR (0xF << 9)
+#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 (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 (1U << FSMC_PCR_PBKEN_BIT)
+#define FSMC_PCR_PWAITEN (1U << FSMC_PCR_PWAITEN_BIT)
+
+/* FIFO status and interrupt registers */
+
+#define FSMC_SR_FEMPT_BIT 6
+#define FSMC_SR_IFEN_BIT 5
+#define FSMC_SR_ILEN_BIT 4
+#define FSMC_SR_IREN_BIT 3
+#define FSMC_SR_IFS_BIT 2
+#define FSMC_SR_ILS_BIT 1
+#define FSMC_SR_IRS_BIT 0
+
+#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 */
+
+#define FSMC_PMEM_MEMHIZ (0xFF << 24)
+#define FSMC_PMEM_MEMHOLD (0xFF << 16)
+#define FSMC_PMEM_MEMWAIT (0xFF << 8)
+#define FSMC_PMEM_MEMSET 0xFF
+
+/* Attribute memory space timing registers */
+
+#define FSMC_PATT_ATTHIZ (0xFF << 24)
+#define FSMC_PATT_ATTHOLD (0xFF << 16)
+#define FSMC_PATT_ATTWAIT (0xFF << 8)
+#define FSMC_PATT_ATTSET 0xFF
+
+/* I/O space timing register 4 */
+
+#define FSMC_PIO_IOHIZ (0xFF << 24)
+#define FSMC_PIO_IOHOLD (0xFF << 16)
+#define FSMC_PIO_IOWAIT (0xFF << 8)
+#define FSMC_PIO_IOSET 0xFF
+
+/*
+ * Memory bank boundary addresses
+ */
+
+/**
+ * @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)
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 1
+ * (NOR/PSRAM).
+ */
+#define FSMC_NOR_PSRAM_REGION1 FSMC_BANK1
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 2
+ * (NOR/PSRAM).
+ */
+#define FSMC_NOR_PSRAM_REGION2 ((void*)0x64000000)
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 3
+ * (NOR/PSRAM).
+ */
+#define FSMC_NOR_PSRAM_REGION3 ((void*)0x68000000)
+
+/**
+ * @brief Void pointer to base address of FSMC memory bank 1, region 4
+ * (NOR/PSRAM).
+ */
+#define FSMC_NOR_PSRAM_REGION4 ((void*)0x6C000000)
+
+/** Void pointer to base address of FSMC memory bank 2 (NAND Flash). */
+#define FSMC_BANK2 ((void*)0x70000000)
+
+/** Void pointer to base address of FSMC memory bank 3 (NAND Flash). */
+#define FSMC_BANK3 ((void*)0x80000000)
+
+/**
+ * @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);
+
+/**
+ * Set the DATAST bits in the given NOR/PSRAM register map's
+ * chip-select timing register (FSMC_BTR).
+ *
+ * @param regs NOR Flash/PSRAM register map whose chip-select timing
+ * register to set.
+ * @param datast Value to use for DATAST bits.
+ */
+static inline void fsmc_nor_psram_set_datast(fsmc_nor_psram_reg_map *regs,
+ uint8 datast) {
+ regs->BTR &= ~FSMC_BTR_DATAST;
+ regs->BTR |= datast << 8;
+}
+
+/**
+ * Set the ADDHLD bits in the given NOR/PSRAM register map's chip
+ * select timing register (FSMC_BTRx).
+ *
+ * @param regs NOR Flash/PSRAM register map whose chip-select timing
+ * register to set.
+ * @param addset Value to use for ADDSET bits.
+ */
+static inline void fsmc_nor_psram_set_addset(fsmc_nor_psram_reg_map *regs,
+ uint8 addset) {
+ regs->BTR &= ~FSMC_BTR_ADDSET;
+ regs->BTR |= addset & 0xF;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#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/include/libmaple/i2c.h b/libmaple/include/libmaple/i2c.h
new file mode 100644
index 0000000..ff1c313
--- /dev/null
+++ b/libmaple/include/libmaple/i2c.h
@@ -0,0 +1,413 @@
+/******************************************************************************
+ * 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
+ * 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.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.
+ */
+
+#ifndef _LIBMAPLE_I2C_H_
+#define _LIBMAPLE_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 {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 OAR1; /**< Own address register 1 */
+ __io uint32 OAR2; /**< Own address register 2 */
+ __io uint32 DR; /**< Data register */
+ __io uint32 SR1; /**< Status register 1 */
+ __io uint32 SR2; /**< Status register 2 */
+ __io uint32 CCR; /**< Clock control register */
+ __io uint32 TRISE; /**< TRISE (rise time) register */
+} i2c_reg_map;
+
+/**
+ * @brief I2C message type
+ */
+typedef struct i2c_msg {
+ uint16 addr; /**< Address */
+
+#define I2C_MSG_READ 0x1
+#define I2C_MSG_10BIT_ADDR 0x2
+ /**
+ * 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;
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 1 */
+
+#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 (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
+
+/* Own address register 1 */
+
+#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_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_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
+ */
+
+/* Main I2C API */
+
+/* I2C enable options */
+#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)
+#define I2C_ERROR_TIMEOUT (-2)
+int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout);
+
+void i2c_bus_reset(const i2c_dev *dev);
+
+/**
+ * @brief Disable an I2C device
+ *
+ * This function disables the corresponding peripheral and marks dev's
+ * state as I2C_STATE_DISABLED.
+ *
+ * @param dev Device to disable.
+ */
+static inline void i2c_disable(i2c_dev *dev) {
+ dev->regs->CR1 &= ~I2C_CR1_PE;
+ dev->state = I2C_STATE_DISABLED;
+}
+
+/* Start/stop conditions */
+
+/**
+ * @brief Generate a start condition on the bus.
+ * @param dev I2C device
+ */
+static inline void i2c_start_condition(i2c_dev *dev) {
+ uint32 cr1;
+ while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
+ I2C_CR1_STOP |
+ I2C_CR1_PEC)) {
+ ;
+ }
+ dev->regs->CR1 |= I2C_CR1_START;
+}
+
+/**
+ * @brief Generate a stop condition on the bus
+ * @param dev I2C device
+ */
+static inline void i2c_stop_condition(i2c_dev *dev) {
+ uint32 cr1;
+ while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
+ I2C_CR1_STOP |
+ I2C_CR1_PEC)) {
+ ;
+ }
+ dev->regs->CR1 |= I2C_CR1_STOP;
+ while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
+ I2C_CR1_STOP |
+ I2C_CR1_PEC)) {
+ ;
+ }
+
+}
+
+/* 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
+ * @param irqs Bitwise or of:
+ * I2C_IRQ_ERROR (error interrupt),
+ * I2C_IRQ_EVENT (event interrupt), and
+ * I2C_IRQ_BUFFER (buffer interrupt).
+ */
+static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) {
+ _i2c_irq_priority_fixup(dev);
+ dev->regs->CR2 |= irqs;
+}
+
+/**
+ * @brief Disable one or more I2C interrupts
+ * @param dev I2C device
+ * @param irqs Bitwise or of:
+ * I2C_IRQ_ERROR (error interrupt),
+ * I2C_IRQ_EVENT (event interrupt), and
+ * I2C_IRQ_BUFFER (buffer interrupt).
+ */
+static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) {
+ dev->regs->CR2 &= ~irqs;
+}
+
+/* ACK/NACK */
+
+/**
+ * @brief Enable I2C acknowledgment
+ * @param dev I2C device
+ */
+static inline void i2c_enable_ack(i2c_dev *dev) {
+ dev->regs->CR1 |= I2C_CR1_ACK;
+}
+
+/**
+ * @brief Disable I2C acknowledgment
+ * @param dev I2C device
+ */
+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
+
+#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/include/libmaple/iwdg.h b/libmaple/include/libmaple/iwdg.h
new file mode 100644
index 0000000..3a16c55
--- /dev/null
+++ b/libmaple/include/libmaple/iwdg.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * 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 libmaple/include/libmaple/iwdg.h
+ * @author Michael Hope, Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Independent watchdog support.
+ *
+ * To use the independent watchdog, first call iwdg_init() with the
+ * appropriate prescaler and IWDG counter reload values for your
+ * application. Afterwards, you must periodically call iwdg_feed()
+ * before the IWDG counter reaches 0 to reset the counter to its
+ * reload value. If you do not, the chip will reset.
+ *
+ * Once started, the independent watchdog cannot be turned off.
+ */
+
+#ifndef _LIBMAPLE_IWDG_H_
+#define _LIBMAPLE_IWDG_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map
+ */
+
+/** Independent watchdog register map type. */
+typedef struct iwdg_reg_map {
+ __io uint32 KR; /**< Key register. */
+ __io uint32 PR; /**< Prescaler register. */
+ __io uint32 RLR; /**< Reload register. */
+ __io uint32 SR; /**< Status register */
+} iwdg_reg_map;
+
+/** Independent watchdog base pointer */
+#define IWDG_BASE ((struct iwdg_reg_map*)0x40003000)
+
+/*
+ * Register bit definitions
+ */
+
+/* Key register */
+
+#define IWDG_KR_UNLOCK 0x5555
+#define IWDG_KR_FEED 0xAAAA
+#define IWDG_KR_START 0xCCCC
+
+/* Prescaler register */
+
+#define IWDG_PR_DIV_4 0x0
+#define IWDG_PR_DIV_8 0x1
+#define IWDG_PR_DIV_16 0x2
+#define IWDG_PR_DIV_32 0x3
+#define IWDG_PR_DIV_64 0x4
+#define IWDG_PR_DIV_128 0x5
+#define IWDG_PR_DIV_256 0x6
+
+/* Status register */
+
+#define IWDG_SR_RVU_BIT 1
+#define IWDG_SR_PVU_BIT 0
+
+#define IWDG_SR_RVU (1U << IWDG_SR_RVU_BIT)
+#define IWDG_SR_PVU (1U << IWDG_SR_PVU_BIT)
+
+/**
+ * @brief Independent watchdog prescalers.
+ *
+ * These divide the 40 kHz IWDG clock.
+ */
+typedef enum iwdg_prescaler {
+ IWDG_PRE_4 = IWDG_PR_DIV_4, /**< Divide by 4 */
+ IWDG_PRE_8 = IWDG_PR_DIV_8, /**< Divide by 8 */
+ IWDG_PRE_16 = IWDG_PR_DIV_16, /**< Divide by 16 */
+ IWDG_PRE_32 = IWDG_PR_DIV_32, /**< Divide by 32 */
+ IWDG_PRE_64 = IWDG_PR_DIV_64, /**< Divide by 64 */
+ IWDG_PRE_128 = IWDG_PR_DIV_128, /**< Divide by 128 */
+ IWDG_PRE_256 = IWDG_PR_DIV_256 /**< Divide by 256 */
+} iwdg_prescaler;
+
+void iwdg_init(iwdg_prescaler prescaler, uint16 reload);
+void iwdg_feed(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/libmaple.h b/libmaple/include/libmaple/libmaple.h
new file mode 100644
index 0000000..f1a595e
--- /dev/null
+++ b/libmaple/include/libmaple/libmaple.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * 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/libmaple.h
+ * @brief General include file for libmaple
+ */
+
+#ifndef _LIBMAPLE_LIBMAPLE_H_
+#define _LIBMAPLE_LIBMAPLE_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.
+ *
+ * FIXME this has no business being here
+ */
+#define USER_ADDR_ROM 0x08005000
+#define USER_ADDR_RAM 0x20000C00
+#define STACK_TOP 0x20000800
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/libmaple_types.h b/libmaple/include/libmaple/libmaple_types.h
new file mode 100644
index 0000000..9e1fbb3
--- /dev/null
+++ b/libmaple/include/libmaple/libmaple_types.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ * 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/libmaple_types.h
+ *
+ * @brief libmaple's types, and operations on types.
+ */
+
+#ifndef _LIBMAPLE_LIBMAPLE_TYPES_H_
+#define _LIBMAPLE_LIBMAPLE_TYPES_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef unsigned long long uint64;
+
+typedef signed char int8;
+typedef short int16;
+typedef int int32;
+typedef long long int64;
+
+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/include/libmaple/pwr.h b/libmaple/include/libmaple/pwr.h
new file mode 100644
index 0000000..e4b5b0d
--- /dev/null
+++ b/libmaple/include/libmaple/pwr.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * 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 libmaple/include/libmaple/pwr.h
+ * @brief Power control (PWR).
+ */
+
+#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 */
+ __io uint32 CSR; /**< Control and status register */
+} pwr_reg_map;
+
+/** Power peripheral register map base pointer. */
+#define PWR_BASE ((struct pwr_reg_map*)0x40007000)
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+
+/** Disable backup domain write protection bit */
+#define PWR_CR_DBP_BIT 8
+/** Power voltage detector enable bit */
+#define PWR_CR_PVDE_BIT 4
+/** Clear standby flag bit */
+#define PWR_CR_CSBF_BIT 3
+/** Clear wakeup flag bit */
+#define PWR_CR_CWUF_BIT 2
+/** Power down deepsleep bit */
+#define PWR_CR_PDDS_BIT 1
+/** Low-power deepsleep bit */
+#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_BIT 8
+/** PVD output bit */
+#define PWR_CSR_PVDO_BIT 2
+/** Standby flag bit */
+#define PWR_CSR_SBF_BIT 1
+/** Wakeup flag bit */
+#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
+ */
+
+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/include/libmaple/ring_buffer.h b/libmaple/include/libmaple/ring_buffer.h
new file mode 100644
index 0000000..e02e6e7
--- /dev/null
+++ b/libmaple/include/libmaple/ring_buffer.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ * 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/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 _LIBMAPLE_RING_BUFFER_H_
+#define _LIBMAPLE_RING_BUFFER_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/**
+ * Ring buffer type.
+ *
+ * The buffer is empty when head == tail.
+ *
+ * The buffer is full when the head is one byte in front of the tail,
+ * modulo buffer length.
+ *
+ * One byte is left free to distinguish empty from full. */
+typedef struct ring_buffer {
+ volatile uint8 *buf; /**< Buffer items are stored into */
+ uint16 head; /**< Index of the next item to remove */
+ uint16 tail; /**< Index where the next item will get inserted */
+ uint16 size; /**< Buffer capacity minus one */
+} ring_buffer;
+
+/**
+ * Initialise a ring buffer.
+ *
+ * @param rb Instance to initialise
+ *
+ * @param size Number of items in buf. The ring buffer will always
+ * leave one element unoccupied, so the maximum number of
+ * elements it can store will be size - 1. Thus, size
+ * must be at least 2.
+ *
+ * @param buf Buffer to store items into
+ */
+static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) {
+ rb->head = 0;
+ rb->tail = 0;
+ rb->size = size - 1;
+ rb->buf = buf;
+}
+
+/**
+ * @brief Return the number of elements stored in the ring buffer.
+ * @param rb Buffer whose elements to count.
+ */
+static inline uint16 rb_full_count(ring_buffer *rb) {
+ __io ring_buffer *arb = rb;
+ int32 size = arb->tail - arb->head;
+ if (arb->tail < arb->head) {
+ size += arb->size + 1;
+ }
+ return (uint16)size;
+}
+
+/**
+ * @brief Returns true if and only if the ring buffer is full.
+ * @param rb Buffer to test.
+ */
+static inline int rb_is_full(ring_buffer *rb) {
+ return (rb->tail + 1 == rb->head) ||
+ (rb->tail == rb->size && rb->head == 0);
+}
+
+/**
+ * @brief Returns true if and only if the ring buffer is empty.
+ * @param rb Buffer to test.
+ */
+static inline int rb_is_empty(ring_buffer *rb) {
+ return rb->head == rb->tail;
+}
+
+/**
+ * Append element onto the end of a ring buffer.
+ * @param rb Buffer to append onto.
+ * @param element Value to append.
+ */
+static inline void rb_insert(ring_buffer *rb, uint8 element) {
+ rb->buf[rb->tail] = element;
+ rb->tail = (rb->tail == rb->size) ? 0 : rb->tail + 1;
+}
+
+/**
+ * @brief Remove and return the first item from a ring buffer.
+ * @param rb Buffer to remove from, must contain at least one element.
+ */
+static inline uint8 rb_remove(ring_buffer *rb) {
+ uint8 ch = rb->buf[rb->head];
+ rb->head = (rb->head == rb->size) ? 0 : rb->head + 1;
+ return ch;
+}
+
+/**
+ * @brief Attempt to remove the first item from a ring buffer.
+ *
+ * If the ring buffer is nonempty, removes and returns its first item.
+ * If it is empty, does nothing and returns a negative value.
+ *
+ * @param rb Buffer to attempt to remove from.
+ */
+static inline int16 rb_safe_remove(ring_buffer *rb) {
+ return rb_is_empty(rb) ? -1 : rb_remove(rb);
+}
+
+/**
+ * @brief Attempt to insert an element into a ring buffer.
+ *
+ * @param rb Buffer to insert into.
+ * @param element Value to insert into rb.
+ * @sideeffect If rb is not full, appends element onto buffer.
+ * @return If element was appended, then true; otherwise, false. */
+static inline int rb_safe_insert(ring_buffer *rb, uint8 element) {
+ if (rb_is_full(rb)) {
+ return 0;
+ }
+ rb_insert(rb, element);
+ return 1;
+}
+
+/**
+ * @brief Append an item onto the end of a non-full ring buffer.
+ *
+ * If the buffer is full, removes its first item, then inserts the new
+ * element at the end.
+ *
+ * @param rb Ring buffer to insert into.
+ * @param element Value to insert into ring buffer.
+ * @return On success, returns -1. If an element was popped, returns
+ * the popped value.
+ */
+static inline int rb_push_insert(ring_buffer *rb, uint8 element) {
+ int ret = -1;
+ if (rb_is_full(rb)) {
+ ret = rb_remove(rb);
+ }
+ rb_insert(rb, element);
+ return ret;
+}
+
+/**
+ * @brief Discard all items from a ring buffer.
+ * @param rb Ring buffer to discard all items from.
+ */
+static inline void rb_reset(ring_buffer *rb) {
+ rb->tail = rb->head;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/scb.h b/libmaple/include/libmaple/scb.h
new file mode 100644
index 0000000..1c7c5d7
--- /dev/null
+++ b/libmaple/include/libmaple/scb.h
@@ -0,0 +1,209 @@
+/******************************************************************************
+ * 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/scb.h
+ * @brief System control block header
+ */
+
+#ifndef _LIBMAPLE_SCB_H_
+#define _LIBMAPLE_SCB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Register map and base pointer
+ */
+
+/** System control block register map type */
+typedef struct scb_reg_map {
+ __io uint32 CPUID; /**< CPU ID Base Register */
+ __io uint32 ICSR; /**< Interrupt Control State Register */
+ __io uint32 VTOR; /**< Vector Table Offset Register */
+ __io uint32 AIRCR; /**< Application Interrupt / Reset Control Register */
+ __io uint32 SCR; /**< System Control Register */
+ __io uint32 CCR; /**< Configuration and Control Register */
+ __io uint8 SHP[12]; /**< System Handler Priority Registers
+ (4-7, 8-11, 12-15) */
+ __io uint32 SHCSR; /**< System Handler Control and State Register */
+ __io uint32 CFSR; /**< Configurable Fault Status Register */
+ __io uint32 HFSR; /**< Hard Fault Status Register */
+ /* DFSR is not documented by ST in PM0056 (as of Revision 4), but
+ * there's a 4 byte hole in the SCB register map docs right where
+ * it belongs. Since it's specified as "always implemented" in
+ * the ARM v7-M ARM, I'm assuming its absence is a bug in the ST
+ * doc, but I haven't proven it. [mbolivar] */
+ __io uint32 DFSR; /**< Debug Fault Status Register */
+ __io uint32 MMFAR; /**< Mem Manage Address Register */
+ __io uint32 BFAR; /**< Bus Fault Address Register */
+#if 0
+ /* The following registers are implementation-defined according to
+ * ARM v7-M, and I can't find evidence of their existence in ST's
+ * docs. I'm removing them. Feel free to yell at me if they do
+ * exist. [mbolivar]
+ */
+ __io uint32 AFSR; /**< Auxiliary Fault Status Register */
+ __io uint32 PFR[2]; /**< Processor Feature Register */
+ __io uint32 DFR; /**< Debug Feature Register */
+ __io uint32 AFR; /**< Auxiliary Feature Register */
+ __io uint32 MMFR[4]; /**< Memory Model Feature Register */
+ __io uint32 ISAR[5]; /**< ISA Feature Register */
+#endif
+} scb_reg_map;
+
+/** System control block register map base pointer */
+#define SCB_BASE ((struct scb_reg_map*)0xE000ED00)
+
+/*
+ * Register bit definitions
+ */
+
+/* No SCB_REG_FIELD_BIT macros as the relevant addresses are not in a
+ * bit-band region. */
+
+/* CPUID base register (SCB_CPUID) */
+
+#define SCB_CPUID_IMPLEMENTER (0xFF << 24)
+#define SCB_CPUID_VARIANT (0xF << 20)
+#define SCB_CPUID_CONSTANT (0xF << 16)
+#define SCB_CPUID_PARTNO (0xFFF << 4)
+#define SCB_CPUID_REVISION 0xF
+
+/* Interrupt control state register (SCB_ICSR) */
+
+#define SCB_ICSR_NMIPENDSET BIT(31)
+#define SCB_ICSR_PENDSVSET BIT(28)
+#define SCB_ICSR_PENDSVCLR BIT(27)
+#define SCB_ICSR_PENDSTSET BIT(26)
+#define SCB_ICSR_PENDSTCLR BIT(25)
+#define SCB_ICSR_ISRPENDING BIT(22)
+#define SCB_ICSR_VECTPENDING (0x3FF << 12)
+#define SCB_ICSR_RETOBASE BIT(11)
+#define SCB_ICSR_VECTACTIVE 0xFF
+
+/* Vector table offset register (SCB_VTOR) */
+
+#define SCB_VTOR_TBLOFF (0x1FFFFF << 9)
+
+/* Application interrupt and reset control register (SCB_AIRCR) */
+
+#define SCB_AIRCR_VECTKEYSTAT (0x5FA << 16)
+#define SCB_AIRCR_VECTKEY (0x5FA << 16)
+#define SCB_AIRCR_ENDIANNESS BIT(15)
+#define SCB_AIRCR_PRIGROUP (0x3 << 8)
+#define SCB_AIRCR_SYSRESETREQ BIT(2)
+#define SCB_AIRCR_VECTCLRACTIVE BIT(1)
+#define SCB_AIRCR_VECTRESET BIT(0)
+
+/* System control register (SCB_SCR) */
+
+#define SCB_SCR_SEVONPEND BIT(4)
+#define SCB_SCR_SLEEPDEEP BIT(2)
+#define SCB_SCR_SLEEPONEXIT BIT(1)
+
+/* Configuration and Control Register (SCB_CCR) */
+
+#define SCB_CCR_STKALIGN BIT(9)
+#define SCB_CCR_BFHFNMIGN BIT(8)
+#define SCB_CCR_DIV_0_TRP BIT(4)
+#define SCB_CCR_UNALIGN_TRP BIT(3)
+#define SCB_CCR_USERSETMPEND BIT(1)
+#define SCB_CCR_NONBASETHRDENA BIT(0)
+
+/* System handler priority registers (SCB_SHPRx) */
+
+#define SCB_SHPR1_PRI6 (0xFF << 16)
+#define SCB_SHPR1_PRI5 (0xFF << 8)
+#define SCB_SHPR1_PRI4 0xFF
+
+#define SCB_SHPR2_PRI11 (0xFF << 24)
+
+#define SCB_SHPR3_PRI15 (0xFF << 24)
+#define SCB_SHPR3_PRI14 (0xFF << 16)
+
+/* System Handler Control and state register (SCB_SHCSR) */
+
+#define SCB_SHCSR_USGFAULTENA BIT(18)
+#define SCB_SHCSR_BUSFAULTENA BIT(17)
+#define SCB_SHCSR_MEMFAULTENA BIT(16)
+#define SCB_SHCSR_SVCALLPENDED BIT(15)
+#define SCB_SHCSR_BUSFAULTPENDED BIT(14)
+#define SCB_SHCSR_MEMFAULTPENDED BIT(13)
+#define SCB_SHCSR_USGFAULTPENDED BIT(12)
+#define SCB_SHCSR_SYSTICKACT BIT(11)
+#define SCB_SHCSR_PENDSVACT BIT(10)
+#define SCB_SHCSR_MONITORACT BIT(8)
+#define SCB_SHCSR_SVCALLACT BIT(7)
+#define SCB_SHCSR_USGFAULTACT BIT(3)
+#define SCB_SHCSR_BUSFAULTACT BIT(1)
+#define SCB_SHCSR_MEMFAULTACT BIT(0)
+
+/* Configurable fault status register (SCB_CFSR) */
+
+#define SCB_CFSR_DIVBYZERO BIT(25)
+#define SCB_CFSR_UNALIGNED BIT(24)
+#define SCB_CFSR_NOCP BIT(19)
+#define SCB_CFSR_INVPC BIT(18)
+#define SCB_CFSR_INVSTATE BIT(17)
+#define SCB_CFSR_UNDEFINSTR BIT(16)
+#define SCB_CFSR_BFARVALID BIT(15)
+#define SCB_CFSR_STKERR BIT(12)
+#define SCB_CFSR_UNSTKERR BIT(11)
+#define SCB_CFSR_IMPRECISERR BIT(10)
+#define SCB_CFSR_PRECISERR BIT(9)
+#define SCB_CFSR_IBUSERR BIT(8)
+#define SCB_CFSR_MMARVALID BIT(7)
+#define SCB_CFSR_MSTKERR BIT(4)
+#define SCB_CFSR_MUNSTKERR BIT(3)
+#define SCB_CFSR_DACCVIOL BIT(1)
+#define SCB_CFSR_IACCVIOL BIT(0)
+
+/* Hard Fault Status Register (SCB_HFSR) */
+
+#define SCB_HFSR_DEBUG_VT BIT(31)
+#define SCB_CFSR_FORCED BIT(30)
+#define SCB_CFSR_VECTTBL BIT(1)
+
+/* Debug Fault Status Register */
+
+/* Not specified by PM0056, but required by ARM. The bit definitions
+ * here are based on the names given in the ARM v7-M ARM. */
+
+#define SCB_DFSR_EXTERNAL BIT(4)
+#define SCB_DFSR_VCATCH BIT(3)
+#define SCB_DFSR_DWTTRAP BIT(2)
+#define SCB_DFSR_BKPT BIT(1)
+#define SCB_DFSR_HALTED BIT(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/spi.h b/libmaple/include/libmaple/spi.h
new file mode 100644
index 0000000..fab643f
--- /dev/null
+++ b/libmaple/include/libmaple/spi.h
@@ -0,0 +1,469 @@
+/******************************************************************************
+ * 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/include/libmaple/spi.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Serial Peripheral Interface (SPI) and Integrated
+ * Interchip Sound (I2S) peripheral support.
+ *
+ * I2S support is currently limited to register maps and bit definitions.
+ */
+
+#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
+ */
+
+/** SPI register map type. */
+typedef struct spi_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SR; /**< Status register */
+ __io uint32 DR; /**< Data register */
+ __io uint32 CRCPR; /**< CRC polynomial register */
+ __io uint32 RXCRCR; /**< RX CRC register */
+ __io uint32 TXCRCR; /**< TX CRC register */
+ __io uint32 I2SCFGR; /**< I2S configuration register */
+ __io uint32 I2SPR; /**< I2S prescaler register */
+} spi_reg_map;
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 1 */
+
+#define SPI_CR1_BIDIMODE_BIT 15
+#define SPI_CR1_BIDIOE_BIT 14
+#define SPI_CR1_CRCEN_BIT 13
+#define SPI_CR1_CRCNEXT_BIT 12
+#define SPI_CR1_DFF_BIT 11
+#define SPI_CR1_RXONLY_BIT 10
+#define SPI_CR1_SSM_BIT 9
+#define SPI_CR1_SSI_BIT 8
+#define SPI_CR1_LSBFIRST_BIT 7
+#define SPI_CR1_SPE_BIT 6
+#define SPI_CR1_MSTR_BIT 2
+#define SPI_CR1_CPOL_BIT 1
+#define SPI_CR1_CPHA_BIT 0
+
+#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 (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 (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)
+#define SPI_CR1_BR_PCLK_DIV_8 (0x2 << 3)
+#define SPI_CR1_BR_PCLK_DIV_16 (0x3 << 3)
+#define SPI_CR1_BR_PCLK_DIV_32 (0x4 << 3)
+#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 (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 (1U << SPI_CR1_CPHA_BIT)
+
+/* Control register 2 */
+
+#define SPI_CR2_TXEIE_BIT 7
+#define SPI_CR2_RXNEIE_BIT 6
+#define SPI_CR2_ERRIE_BIT 5
+#define SPI_CR2_SSOE_BIT 2
+#define SPI_CR2_TXDMAEN_BIT 1
+#define SPI_CR2_RXDMAEN_BIT 0
+
+#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 */
+
+#define SPI_SR_BSY_BIT 7
+#define SPI_SR_OVR_BIT 6
+#define SPI_SR_MODF_BIT 5
+#define SPI_SR_CRCERR_BIT 4
+#define SPI_SR_UDR_BIT 3
+#define SPI_SR_CHSIDE_BIT 2
+#define SPI_SR_TXE_BIT 1
+#define SPI_SR_RXNE_BIT 0
+
+#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 (1U << SPI_SR_TXE_BIT)
+#define SPI_SR_RXNE (1U << SPI_SR_RXNE_BIT)
+
+/* I2S configuration register */
+
+#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 (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 (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 (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)
+#define SPI_I2SCFGR_I2SSTD_PHILLIPS (0x0 << 4)
+#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 (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 (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
+ */
+
+/** SPI device type */
+typedef struct spi_dev {
+ spi_reg_map *regs; /**< Register map */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ nvic_irq_num irq_num; /**< NVIC interrupt number */
+} spi_dev;
+
+/*
+ * SPI Convenience functions
+ */
+
+void spi_init(spi_dev *dev);
+
+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.
+ *
+ * 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 {
+ /** 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;
+
+/**
+ * @brief SPI baud rate configuration, as a divisor of f_PCLK, the
+ * PCLK clock frequency.
+ */
+typedef enum spi_baud_rate {
+ SPI_BAUD_PCLK_DIV_2 = SPI_CR1_BR_PCLK_DIV_2, /**< f_PCLK/2 */
+ SPI_BAUD_PCLK_DIV_4 = SPI_CR1_BR_PCLK_DIV_4, /**< f_PCLK/4 */
+ SPI_BAUD_PCLK_DIV_8 = SPI_CR1_BR_PCLK_DIV_8, /**< f_PCLK/8 */
+ SPI_BAUD_PCLK_DIV_16 = SPI_CR1_BR_PCLK_DIV_16, /**< f_PCLK/16 */
+ SPI_BAUD_PCLK_DIV_32 = SPI_CR1_BR_PCLK_DIV_32, /**< f_PCLK/32 */
+ SPI_BAUD_PCLK_DIV_64 = SPI_CR1_BR_PCLK_DIV_64, /**< f_PCLK/64 */
+ SPI_BAUD_PCLK_DIV_128 = SPI_CR1_BR_PCLK_DIV_128, /**< f_PCLK/128 */
+ SPI_BAUD_PCLK_DIV_256 = SPI_CR1_BR_PCLK_DIV_256, /**< f_PCLK/256 */
+} spi_baud_rate;
+
+/**
+ * @brief SPI initialization flags.
+ * @see spi_master_enable()
+ * @see spi_slave_enable()
+ */
+typedef enum spi_cfg_flag {
+ SPI_BIDIMODE = SPI_CR1_BIDIMODE, /**< Bidirectional mode enable */
+ SPI_BIDIOE = SPI_CR1_BIDIOE, /**< Output enable in bidirectional
+ mode */
+ SPI_CRCEN = SPI_CR1_CRCEN, /**< Cyclic redundancy check (CRC)
+ enable */
+ SPI_DFF_8_BIT = SPI_CR1_DFF_8_BIT, /**< 8-bit data frame format (this is
+ the default) */
+ SPI_DFF_16_BIT = SPI_CR1_DFF_16_BIT, /**< 16-bit data frame format */
+ SPI_RX_ONLY = SPI_CR1_RXONLY, /**< Receive only */
+ SPI_SW_SLAVE = SPI_CR1_SSM, /**< Software slave management */
+ SPI_SOFT_SS = SPI_CR1_SSI, /**< Software (internal) slave
+ select. This flag only has an
+ effect when used in combination
+ with SPI_SW_SLAVE. */
+ SPI_FRAME_LSB = SPI_CR1_LSBFIRST, /**< LSB-first (little-endian) frame
+ format */
+ SPI_FRAME_MSB = 0, /**< MSB-first (big-endian) frame
+ format (this is the default) */
+} spi_cfg_flag;
+
+void spi_master_enable(spi_dev *dev,
+ spi_baud_rate baud,
+ spi_mode mode,
+ uint32 flags);
+
+void spi_slave_enable(spi_dev *dev,
+ spi_mode mode,
+ uint32 flags);
+
+uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len);
+
+/**
+ * @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);
+
+void spi_tx_dma_enable(spi_dev *dev);
+void spi_tx_dma_disable(spi_dev *dev);
+
+void spi_rx_dma_enable(spi_dev *dev);
+void spi_rx_dma_disable(spi_dev *dev);
+
+/**
+ * @brief Determine if a SPI peripheral is enabled.
+ * @param dev SPI device
+ * @return True, if and only if dev's peripheral is enabled.
+ */
+static inline uint8 spi_is_enabled(spi_dev *dev) {
+ return dev->regs->CR1 & SPI_CR1_SPE_BIT;
+}
+
+/**
+ * @brief Disable all SPI peripherals
+ */
+static inline void spi_peripheral_disable_all(void) {
+ spi_foreach(spi_peripheral_disable);
+}
+
+/** Available SPI interrupts */
+typedef enum spi_interrupt {
+ SPI_TXE_INTERRUPT = SPI_CR2_TXEIE, /**< TX buffer empty interrupt */
+ SPI_RXNE_INTERRUPT = SPI_CR2_RXNEIE, /**< RX buffer not empty interrupt */
+ SPI_ERR_INTERRUPT = SPI_CR2_ERRIE /**<
+ * Error interrupt (CRC, overrun,
+ * and mode fault errors for SPI;
+ * underrun, overrun errors for I2S)
+ */
+} spi_interrupt;
+
+/**
+ * @brief Mask for all spi_interrupt values
+ * @see spi_interrupt
+ */
+#define SPI_INTERRUPTS_ALL (SPI_TXE_INTERRUPT | \
+ SPI_RXNE_INTERRUPT | \
+ SPI_ERR_INTERRUPT)
+
+/**
+ * @brief Enable SPI interrupt requests
+ * @param dev SPI device
+ * @param interrupt_flags Bitwise OR of spi_interrupt values to enable
+ * @see spi_interrupt
+ */
+static inline void spi_irq_enable(spi_dev *dev, uint32 interrupt_flags) {
+ dev->regs->CR2 |= interrupt_flags;
+ nvic_irq_enable(dev->irq_num);
+}
+
+/**
+ * @brief Disable SPI interrupt requests
+ * @param dev SPI device
+ * @param interrupt_flags Bitwise OR of spi_interrupt values to disable
+ * @see spi_interrupt
+ */
+static inline void spi_irq_disable(spi_dev *dev, uint32 interrupt_flags) {
+ dev->regs->CR2 &= ~interrupt_flags;
+}
+
+/**
+ * @brief Get the data frame format flags with which a SPI port is
+ * configured.
+ * @param dev SPI device whose data frame format to get.
+ * @return SPI_DFF_8_BIT, if dev has an 8-bit data frame format.
+ * Otherwise, SPI_DFF_16_BIT.
+ */
+static inline spi_cfg_flag spi_dff(spi_dev *dev) {
+ return ((dev->regs->CR1 & SPI_CR1_DFF) == SPI_CR1_DFF_8_BIT ?
+ SPI_DFF_8_BIT :
+ SPI_DFF_16_BIT);
+}
+
+/**
+ * @brief Determine whether the device's peripheral receive (RX)
+ * register is empty.
+ * @param dev SPI device
+ * @return true, iff dev's RX register is empty.
+ */
+static inline uint8 spi_is_rx_nonempty(spi_dev *dev) {
+ return dev->regs->SR & SPI_SR_RXNE;
+}
+
+/**
+ * @brief Retrieve the contents of the device's peripheral receive
+ * (RX) register.
+ *
+ * You may only call this function when the RX register is nonempty.
+ * Calling this function clears the contents of the RX register.
+ *
+ * @param dev SPI device
+ * @return Contents of dev's peripheral RX register
+ * @see spi_is_rx_reg_nonempty()
+ */
+static inline uint16 spi_rx_reg(spi_dev *dev) {
+ return (uint16)dev->regs->DR;
+}
+
+/**
+ * @brief Determine whether the device's peripheral transmit (TX)
+ * register is empty.
+ * @param dev SPI device
+ * @return true, iff dev's TX register is empty.
+ */
+static inline uint8 spi_is_tx_empty(spi_dev *dev) {
+ return dev->regs->SR & SPI_SR_TXE;
+}
+
+/**
+ * @brief Load a value into the device's peripheral transmit (TX) register.
+ *
+ * You may only call this function when the TX register is empty.
+ * Calling this function loads val into the peripheral's TX register.
+ * If the device is properly configured, this will initiate a
+ * transmission, the completion of which will cause the TX register to
+ * be empty again.
+ *
+ * @param dev SPI device
+ * @param val Value to load into the TX register. If the SPI data
+ * frame format is 8 bit, the value must be right-aligned.
+ * @see spi_is_tx_reg_empty()
+ * @see spi_init()
+ * @see spi_master_enable()
+ * @see spi_slave_enable()
+ */
+static inline void spi_tx_reg(spi_dev *dev, uint16 val) {
+ dev->regs->DR = val;
+}
+
+/**
+ * @brief Determine whether the device's peripheral busy (SPI_SR_BSY)
+ * flag is set.
+ * @param dev SPI device
+ * @return true, iff dev's BSY flag is set.
+ */
+static inline uint8 spi_is_busy(spi_dev *dev) {
+ return dev->regs->SR & SPI_SR_BSY;
+}
+
+/*
+ * I2S convenience functions (TODO)
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
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/include/libmaple/systick.h b/libmaple/include/libmaple/systick.h
new file mode 100644
index 0000000..551f800
--- /dev/null
+++ b/libmaple/include/libmaple/systick.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * 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/systick.h
+ * @brief System timer definitions
+ */
+
+#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 */
+ __io uint32 RVR; /**< Reload value register */
+ __io uint32 CNT; /**< Current value register ("count") */
+ __io uint32 CVR; /**< Calibration value register */
+} systick_reg_map;
+
+/** SysTick register map base pointer */
+#define SYSTICK_BASE ((struct systick_reg_map*)0xE000E010)
+
+/*
+ * Register bit definitions.
+ */
+
+/* Control and status register */
+
+#define SYSTICK_CSR_COUNTFLAG BIT(16)
+#define SYSTICK_CSR_CLKSOURCE BIT(2)
+#define SYSTICK_CSR_CLKSOURCE_EXTERNAL 0
+#define SYSTICK_CSR_CLKSOURCE_CORE BIT(2)
+#define SYSTICK_CSR_TICKINT BIT(1)
+#define SYSTICK_CSR_TICKINT_PEND BIT(1)
+#define SYSTICK_CSR_TICKINT_NO_PEND 0
+#define SYSTICK_CSR_ENABLE BIT(0)
+#define SYSTICK_CSR_ENABLE_MULTISHOT BIT(0)
+#define SYSTICK_CSR_ENABLE_DISABLED 0
+
+/* Calibration value register */
+
+#define SYSTICK_CVR_NOREF BIT(31)
+#define SYSTICK_CVR_SKEW BIT(30)
+#define SYSTICK_CVR_TENMS 0xFFFFFF
+
+/** System elapsed time, in milliseconds */
+extern volatile uint32 systick_uptime_millis;
+
+/**
+ * @brief Returns the system uptime, in milliseconds.
+ */
+static inline uint32 systick_uptime(void) {
+ return systick_uptime_millis;
+}
+
+
+void systick_init(uint32 reload_val);
+void systick_disable();
+void systick_enable();
+
+/**
+ * @brief Returns the current value of the SysTick counter.
+ */
+static inline uint32 systick_get_count(void) {
+ return SYSTICK_BASE->CNT;
+}
+
+/**
+ * @brief Check for underflow.
+ *
+ * This function returns 1 if the SysTick timer has counted to 0 since
+ * the last time it was called. However, any reads of any part of the
+ * SysTick Control and Status Register SYSTICK_BASE->CSR will
+ * interfere with this functionality. See the ARM Cortex M3 Technical
+ * Reference Manual for more details (e.g. Table 8-3 in revision r1p1).
+ */
+static inline uint32 systick_check_underflow(void) {
+ return SYSTICK_BASE->CSR & SYSTICK_CSR_COUNTFLAG;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/timer.h b/libmaple/include/libmaple/timer.h
new file mode 100644
index 0000000..995f868
--- /dev/null
+++ b/libmaple/include/libmaple/timer.h
@@ -0,0 +1,1110 @@
+/******************************************************************************
+ * 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/include/libmaple/timer.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief Timer interface.
+ */
+
+#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
+ */
+
+/** Advanced control timer register map type */
+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 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 */
+ __io uint32 RCR; /**< Repetition counter register */
+ __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 */
+ __io uint32 BDTR; /**< Break and dead-time register */
+ __io uint32 DCR; /**< DMA control register */
+ __io uint32 DMAR; /**< DMA address for full transfer */
+} timer_adv_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 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ const uint32 RESERVED2; /**< Reserved */
+ const uint32 RESERVED3; /**< Reserved */
+ const uint32 RESERVED4; /**< Reserved */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+} timer_bas_reg_map;
+
+/*
+ * Timer devices
+ */
+
+/**
+ * @brief Timer register map type.
+ *
+ * Just holds a pointer to the correct type of register map, based on
+ * the timer's type.
+ */
+typedef union timer_reg_map {
+ timer_adv_reg_map *adv; /**< Advanced register map */
+ timer_gen_reg_map *gen; /**< General purpose register map */
+ timer_bas_reg_map *bas; /**< Basic register map */
+} timer_reg_map;
+
+/**
+ * @brief Timer type
+ *
+ * Type marker for timer_dev.
+ *
+ * @see timer_dev
+ */
+typedef enum timer_type {
+ TIMER_ADVANCED, /**< Advanced type */
+ TIMER_GENERAL, /**< General purpose type */
+ TIMER_BASIC, /**< Basic type */
+} timer_type;
+
+/** Timer device type */
+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[]; /**<
+ * 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;
+#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
+ */
+
+/* Control register 1 (CR1) */
+
+#define TIMER_CR1_ARPE_BIT 7
+#define TIMER_CR1_DIR_BIT 4
+#define TIMER_CR1_OPM_BIT 3
+#define TIMER_CR1_URS_BIT 2
+#define TIMER_CR1_UDIS_BIT 1
+#define TIMER_CR1_CEN_BIT 0
+
+#define TIMER_CR1_CKD (0x3 << 8)
+#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 (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 (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) */
+
+#define TIMER_CR2_OIS4_BIT 14
+#define TIMER_CR2_OIS3N_BIT 13
+#define TIMER_CR2_OIS3_BIT 12
+#define TIMER_CR2_OIS2N_BIT 11
+#define TIMER_CR2_OIS2_BIT 10
+#define TIMER_CR2_OIS1N_BIT 9
+#define TIMER_CR2_OIS1_BIT 8
+#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 (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)
+#define TIMER_CR2_MMS_UPDATE (0x2 << 4)
+#define TIMER_CR2_MMS_COMPARE_PULSE (0x3 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC1REF (0x4 << 4)
+#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 (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) */
+
+#define TIMER_SMCR_ETP_BIT 15
+#define TIMER_SMCR_ECE_BIT 14
+#define TIMER_SMCR_MSM_BIT 7
+
+#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 (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)
+#define TIMER_SMCR_TS_ITR2 (0x2 << 4)
+#define TIMER_SMCR_TS_ITR3 (0x3 << 4)
+#define TIMER_SMCR_TS_TI1F_ED (0x4 << 4)
+#define TIMER_SMCR_TS_TI1FP1 (0x5 << 4)
+#define TIMER_SMCR_TS_TI2FP2 (0x6 << 4)
+#define TIMER_SMCR_TS_ETRF (0x7 << 4)
+#define TIMER_SMCR_SMS 0x3
+#define TIMER_SMCR_SMS_DISABLED 0x0
+#define TIMER_SMCR_SMS_ENCODER1 0x1
+#define TIMER_SMCR_SMS_ENCODER2 0x2
+#define TIMER_SMCR_SMS_ENCODER3 0x3
+#define TIMER_SMCR_SMS_RESET 0x4
+#define TIMER_SMCR_SMS_GATED 0x5
+#define TIMER_SMCR_SMS_TRIGGER 0x6
+#define TIMER_SMCR_SMS_EXTERNAL 0x7
+
+/* 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 (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) */
+
+#define TIMER_SR_CC4OF_BIT 12
+#define TIMER_SR_CC3OF_BIT 11
+#define TIMER_SR_CC2OF_BIT 10
+#define TIMER_SR_CC1OF_BIT 9
+#define TIMER_SR_BIF_BIT 7
+#define TIMER_SR_TIF_BIT 6
+#define TIMER_SR_COMIF_BIT 5
+#define TIMER_SR_CC4IF_BIT 4
+#define TIMER_SR_CC3IF_BIT 3
+#define TIMER_SR_CC2IF_BIT 2
+#define TIMER_SR_CC1IF_BIT 1
+#define TIMER_SR_UIF_BIT 0
+
+#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_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 */
+
+#define TIMER_CCMR_CCS_OUTPUT 0x0
+#define TIMER_CCMR_CCS_INPUT_TI1 0x1
+#define TIMER_CCMR_CCS_INPUT_TI2 0x2
+#define TIMER_CCMR_CCS_INPUT_TRC 0x3
+
+/* Capture/compare mode register 1 (CCMR1) */
+
+#define TIMER_CCMR1_OC2CE_BIT 15
+#define TIMER_CCMR1_OC2PE_BIT 11
+#define TIMER_CCMR1_OC2FE_BIT 10
+#define TIMER_CCMR1_OC1CE_BIT 7
+#define TIMER_CCMR1_OC1PE_BIT 3
+#define TIMER_CCMR1_OC1FE_BIT 2
+
+#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 (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 (1U << TIMER_CCMR1_OC1CE_BIT)
+#define TIMER_CCMR1_OC1M (0x3 << 4)
+#define TIMER_CCMR1_IC1F (0xF << 4)
+#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
+#define TIMER_CCMR1_CC1S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
+#define TIMER_CCMR1_CC1S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
+#define TIMER_CCMR1_CC1S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
+
+/* Capture/compare mode register 2 (CCMR2) */
+
+#define TIMER_CCMR2_OC4CE_BIT 15
+#define TIMER_CCMR2_OC4PE_BIT 11
+#define TIMER_CCMR2_OC4FE_BIT 10
+#define TIMER_CCMR2_OC3CE_BIT 7
+#define TIMER_CCMR2_OC3PE_BIT 3
+#define TIMER_CCMR2_OC3FE_BIT 2
+
+#define TIMER_CCMR2_OC4CE (1U << TIMER_CCMR2_OC4CE_BIT)
+#define TIMER_CCMR2_OC4M (0x3 << 12)
+#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_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_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_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 (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) */
+
+#define TIMER_BDTR_MOE_BIT 15
+#define TIMER_BDTR_AOE_BIT 14
+#define TIMER_BDTR_BKP_BIT 13
+#define TIMER_BDTR_BKE_BIT 12
+#define TIMER_BDTR_OSSR_BIT 11
+#define TIMER_BDTR_OSSI_BIT 10
+
+#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)
+#define TIMER_BDTR_LOCK_LEVEL2 (0x2 << 8)
+#define TIMER_BDTR_LOCK_LEVEL3 (0x3 << 8)
+#define TIMER_BDTR_DTG 0xFF
+
+/* DMA control register (DCR) */
+
+#define TIMER_DCR_DBL (0x1F << 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
+#define TIMER_DCR_DBA_SMCR 0x2
+#define TIMER_DCR_DBA_DIER 0x3
+#define TIMER_DCR_DBA_SR 0x4
+#define TIMER_DCR_DBA_EGR 0x5
+#define TIMER_DCR_DBA_CCMR1 0x6
+#define TIMER_DCR_DBA_CCMR2 0x7
+#define TIMER_DCR_DBA_CCER 0x8
+#define TIMER_DCR_DBA_CNT 0x9
+#define TIMER_DCR_DBA_PSC 0xA
+#define TIMER_DCR_DBA_ARR 0xB
+#define TIMER_DCR_DBA_RCR 0xC
+#define TIMER_DCR_DBA_CCR1 0xD
+#define TIMER_DCR_DBA_CCR2 0xE
+#define TIMER_DCR_DBA_CCR3 0xF
+#define TIMER_DCR_DBA_CCR4 0x10
+#define TIMER_DCR_DBA_BDTR 0x11
+#define TIMER_DCR_DBA_DCR 0x12
+#define TIMER_DCR_DBA_DMAR 0x13
+
+/*
+ * Convenience routines
+ */
+
+/**
+ * @brief Used to configure the behavior of a timer channel.
+ *
+ * Be careful: not all timers can be configured in every mode.
+ */
+typedef enum timer_mode {
+ /**
+ * 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 */
+typedef enum timer_channel {
+ TIMER_CH1 = 1, /**< Channel 1 */
+ TIMER_CH2 = 2, /**< Channel 2 */
+ TIMER_CH3 = 3, /**< Channel 3 */
+ TIMER_CH4 = 4 /**< Channel 4 */
+} timer_channel;
+
+/*
+ * Note: Don't require timer_channel arguments! We want to be able to say
+ *
+ * for (int channel = 1; channel <= 4; channel++) {
+ * ...
+ * }
+ *
+ * without the compiler yelling at us.
+ */
+
+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. 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. */
+ 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,
+ uint8 interrupt,
+ voidFuncPtr handler);
+void timer_detach_interrupt(timer_dev *dev, uint8 interrupt);
+
+/**
+ * Initialize all timer devices on the chip.
+ */
+static inline void timer_init_all(void) {
+ timer_foreach(timer_init);
+}
+
+/**
+ * Disables all timers on the device.
+ */
+static inline void timer_disable_all(void) {
+ timer_foreach(timer_disable);
+}
+
+/**
+ * @brief Stop a timer's counter from changing.
+ *
+ * Does not affect the timer's mode or other settings.
+ *
+ * @param dev Device whose counter to pause.
+ */
+static inline void timer_pause(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 0;
+}
+
+/**
+ * @brief Start a timer's counter.
+ *
+ * Does not affect the timer's mode or other settings.
+ *
+ * @param dev Device whose counter to resume
+ */
+static inline void timer_resume(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1;
+}
+
+/**
+ * @brief Returns the timer's counter value.
+ *
+ * This value is likely to be inaccurate if the counter is running
+ * with a low prescaler.
+ *
+ * @param dev Timer whose counter to return
+ */
+static inline uint16 timer_get_count(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->CNT;
+}
+
+/**
+ * @brief Sets the counter value for the given timer.
+ * @param dev Timer whose counter to set
+ * @param value New counter value
+ */
+static inline void timer_set_count(timer_dev *dev, uint16 value) {
+ (dev->regs).bas->CNT = value;
+}
+
+/**
+ * @brief Returns the given timer's prescaler.
+ *
+ * Note that if the timer's prescaler is set (e.g. via
+ * timer_set_prescaler() or accessing a TIMx_PSC register), the value
+ * returned by this function will reflect the new setting, but the
+ * timer's counter will only reflect the new prescaler at the next
+ * update event.
+ *
+ * @param dev Timer whose prescaler to return
+ * @see timer_generate_update()
+ */
+static inline uint16 timer_get_prescaler(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->PSC;
+}
+
+/**
+ * @brief Set a timer's prescale value.
+ *
+ * Divides the input clock by (PSC+1). The new value will not take
+ * effect until the next update event.
+ *
+ * @param dev Timer whose prescaler to set
+ * @param psc New prescaler value
+ * @see timer_generate_update()
+ */
+static inline void timer_set_prescaler(timer_dev *dev, uint16 psc) {
+ (dev->regs).bas->PSC = psc;
+}
+
+/**
+ * @brief Returns a timer's reload value.
+ * @param dev Timer whose reload value to return
+ */
+static inline uint16 timer_get_reload(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->ARR;
+}
+
+/**
+ * @brief Set a timer's reload value.
+ * @param dev Timer whose reload value to set
+ * @param arr New reload value to use. Takes effect at next update event.
+ * @see timer_generate_update()
+ */
+static inline void timer_set_reload(timer_dev *dev, uint16 arr) {
+ (dev->regs).bas->ARR = arr;
+}
+
+/**
+ * @brief Get the compare value for the given timer channel.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose compare value to get.
+ */
+static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) {
+ __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
+ return *ccr;
+}
+
+/**
+ * @brief Set the compare value for the given timer channel.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose compare value to set.
+ * @param value New compare value.
+ */
+static inline void timer_set_compare(timer_dev *dev,
+ uint8 channel,
+ uint16 value) {
+ __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
+ *ccr = value;
+}
+
+/**
+ * @brief Generate an update event for the given timer.
+ *
+ * Normally, this will cause the prescaler and auto-reload values in
+ * the PSC and ARR registers to take immediate effect. However, this
+ * function will do nothing if the UDIS bit is set in the timer's CR1
+ * register (UDIS is cleared by default).
+ *
+ * @param dev Timer device to generate an update for.
+ */
+static inline void timer_generate_update(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->EGR, TIMER_EGR_UG_BIT) = 1;
+}
+
+/**
+ * @brief Enable a timer's trigger DMA request
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ */
+static inline void timer_dma_enable_trg_req(timer_dev *dev) {
+ *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 1;
+}
+
+/**
+ * @brief Disable a timer's trigger DMA request
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ */
+static inline void timer_dma_disable_trg_req(timer_dev *dev) {
+ *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 0;
+}
+
+/**
+ * @brief Enable a timer channel's DMA request.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ * @param channel Channel whose DMA request to enable.
+ */
+static inline void timer_dma_enable_req(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 1;
+}
+
+/**
+ * @brief Disable a timer channel's DMA request.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose DMA request to disable.
+ */
+static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 0;
+}
+
+/**
+ * @brief Enable a timer interrupt.
+ * @param dev Timer device.
+ * @param interrupt Interrupt number to enable; this may be any
+ * timer_interrupt_id value appropriate for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) {
+ *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1;
+}
+
+/**
+ * @brief Disable a timer interrupt.
+ * @param dev Timer device.
+ * @param interrupt Interrupt number to disable; this may be any
+ * timer_interrupt_id value appropriate for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+static inline void timer_disable_irq(timer_dev *dev, uint8 interrupt) {
+ *bb_perip(&(dev->regs).adv->DIER, interrupt) = 0;
+}
+
+/**
+ * @brief Enable a timer channel's capture/compare signal.
+ *
+ * If the channel is configured as output, the corresponding output
+ * compare signal will be output on the corresponding output pin. If
+ * the channel is configured as input, enables capture of the counter
+ * value into the input capture/compare register.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to enable, from 1 to 4.
+ */
+static inline void timer_cc_enable(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 1;
+}
+
+/**
+ * @brief Disable a timer channel's output compare or input capture signal.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to disable, from 1 to 4.
+ * @see timer_cc_enable()
+ */
+static inline void timer_cc_disable(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 0;
+}
+
+/**
+ * @brief Get a channel's capture/compare output polarity
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose capture/compare output polarity to get.
+ * @return Polarity, either 0 or 1.
+ * @see timer_cc_set_polarity()
+ */
+static inline uint8 timer_cc_get_pol(timer_dev *dev, uint8 channel) {
+ return *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1);
+}
+
+/**
+ * @brief Set a timer channel's capture/compare output polarity.
+ *
+ * If the timer channel is configured as output: polarity == 0 means
+ * the output channel will be active high; polarity == 1 means active
+ * low.
+ *
+ * If the timer channel is configured as input: polarity == 0 means
+ * capture is done on the rising edge of ICn; when used as an external
+ * trigger, ICn is non-inverted. polarity == 1 means capture is done
+ * on the falling edge of ICn; when used as an external trigger, ICn
+ * is inverted.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose capture/compare output polarity to set.
+ * @param pol New polarity, 0 or 1.
+ */
+static inline void timer_cc_set_pol(timer_dev *dev, uint8 channel, uint8 pol) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1) = pol;
+}
+
+/**
+ * @brief Get a timer's DMA burst length.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @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 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 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;
+ tmp &= ~TIMER_DCR_DBL;
+ tmp |= (length - 1) << 8;
+ (dev->regs).gen->DCR = tmp;
+}
+
+/**
+ * @brief Timer DMA base address.
+ *
+ * Defines the base address for DMA transfers.
+ */
+typedef enum timer_dma_base_addr {
+ /** 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 the reference manual for your chip.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @return DMA base address
+ */
+static inline timer_dma_base_addr timer_dma_get_base_addr(timer_dev *dev) {
+ uint32 dcr = (dev->regs).gen->DCR;
+ return (timer_dma_base_addr)(dcr & TIMER_DCR_DBA);
+}
+
+/**
+ * @brief Set the timer's DMA base address.
+ *
+ * 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.
+ */
+static inline void timer_dma_set_base_addr(timer_dev *dev,
+ timer_dma_base_addr dma_base) {
+ uint32 tmp = (dev->regs).gen->DCR;
+ tmp &= ~TIMER_DCR_DBA;
+ tmp |= dma_base;
+ (dev->regs).gen->DCR = tmp;
+}
+
+/**
+ * Timer output compare modes.
+ */
+typedef enum timer_oc_mode {
+ /**
+ * 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;
+
+/**
+ * Timer output compare mode flags.
+ * @see timer_oc_set_mode()
+ */
+typedef enum timer_oc_mode_flags {
+ 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;
+
+/**
+ * @brief Configure a channel's output compare mode.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to configure in output compare mode.
+ * @param mode Timer mode to set.
+ * @param flags OR of timer_oc_mode_flags.
+ * @see timer_oc_mode
+ * @see timer_oc_mode_flags
+ */
+static inline void timer_oc_set_mode(timer_dev *dev,
+ uint8 channel,
+ timer_oc_mode mode,
+ uint8 flags) {
+ /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */
+ __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1);
+ /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */
+ uint8 shift = 8 * (1 - (channel & 1));
+
+ uint32 tmp = *ccmr;
+ tmp &= ~(0xFF << shift);
+ tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift;
+ *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
+
+#endif
diff --git a/libmaple/include/libmaple/usart.h b/libmaple/include/libmaple/usart.h
new file mode 100644
index 0000000..26a64d3
--- /dev/null
+++ b/libmaple/include/libmaple/usart.h
@@ -0,0 +1,495 @@
+/******************************************************************************
+ * 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/usart.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>,
+ * Perry Hung <perry@leaflabs.com>
+ * @brief USART definitions and prototypes
+ */
+
+#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 map (common across supported STM32 series).
+ */
+
+/** USART register map type */
+typedef struct usart_reg_map {
+ __io uint32 SR; /**< Status register */
+ __io uint32 DR; /**< Data register */
+ __io uint32 BRR; /**< Baud rate register */
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 CR3; /**< Control register 3 */
+ __io uint32 GTPR; /**< Guard time and prescaler register */
+} usart_reg_map;
+
+/*
+ * 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)
+/**
+ * @brief STOP bits: 0.5 stop bits
+ * Not available on UART4, UART5. */
+#define USART_CR2_STOP_BITS_POINT_5 (0x1 << 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)
+/**
+ * @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)
+/**
+ * @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)
+/**
+ * @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
+
+/**
+ * @brief Clear to send interrupt enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_CTSIE BIT(USART_CR3_CTSIE_BIT)
+/**
+ * @brief Clear to send enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_CTSE BIT(USART_CR3_CTSE_BIT)
+/**
+ * @brief Ready to send enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_RTSE BIT(USART_CR3_RTSE_BIT)
+/**
+ * @brief DMA enable transmitter
+ * Not available on UART5. */
+#define USART_CR3_DMAT BIT(USART_CR3_DMAT_BIT)
+/**
+ * @brief DMA enable receiver
+ * Not available on UART5. */
+#define USART_CR3_DMAR BIT(USART_CR3_DMAR_BIT)
+/**
+ * @brief Smartcard mode enable
+ * Not available on UART4, UART5. */
+#define USART_CR3_SCEN BIT(USART_CR3_SCEN_BIT)
+/**
+ * @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)
+/** 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 */
+
+/**
+ * @brief Guard time value mask
+ * Used in Smartcard mode. Not available on UART4, UART5. */
+#define USART_GTPR_GT (0xFF << 8)
+/**
+ * @brief Prescaler value mask
+ * Restrictions on this value apply, depending on the USART mode. Not
+ * available on UART4, UART5. */
+#define USART_GTPR_PSC 0xFF
+
+/*
+ * Devices
+ */
+
+#ifndef USART_RX_BUF_SIZE
+#define USART_RX_BUF_SIZE 64
+#endif
+
+/** USART device type */
+typedef struct usart_dev {
+ usart_reg_map *regs; /**< Register map */
+ ring_buffer *rb; /**< RX ring buffer */
+ 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
+ * a future release. */
+ rcc_clk_id clk_id; /**< RCC clock information */
+ nvic_irq_num irq_num; /**< USART NVIC interrupt */
+} usart_dev;
+
+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));
+uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len);
+uint32 usart_rx(usart_dev *dev, uint8 *buf, uint32 len);
+void usart_putudec(usart_dev *dev, uint32 val);
+
+/**
+ * @brief Disable all serial ports.
+ */
+static inline void usart_disable_all(void) {
+ usart_foreach(usart_disable);
+}
+
+/**
+ * @brief Transmit one character on a serial port.
+ *
+ * This function blocks until the character has been successfully
+ * transmitted.
+ *
+ * @param dev Serial port to send on.
+ * @param byte Byte to transmit.
+ */
+static inline void usart_putc(usart_dev* dev, uint8 byte) {
+ while (!usart_tx(dev, &byte, 1))
+ ;
+}
+
+/**
+ * @brief Transmit a character string on a serial port.
+ *
+ * This function blocks until str is completely transmitted.
+ *
+ * @param dev Serial port to send on
+ * @param str String to send
+ */
+static inline void usart_putstr(usart_dev *dev, const char* str) {
+ uint32 i = 0;
+ while (str[i] != '\0') {
+ usart_putc(dev, str[i++]);
+ }
+}
+
+/**
+ * @brief Read one character from a serial port.
+ *
+ * It's not safe to call this function if the serial port has no data
+ * available.
+ *
+ * @param dev Serial port to read from
+ * @return byte read
+ * @see usart_data_available()
+ */
+static inline uint8 usart_getc(usart_dev *dev) {
+ return rb_remove(dev->rb);
+}
+
+/**
+ * @brief Return the amount of data available in a serial port's RX buffer.
+ * @param dev Serial port to check
+ * @return Number of bytes in dev's RX buffer.
+ */
+static inline uint32 usart_data_available(usart_dev *dev) {
+ return rb_full_count(dev->rb);
+}
+
+/**
+ * @brief Discard the contents of a serial port's RX buffer.
+ * @param dev Serial port whose buffer to empty.
+ */
+static inline void usart_reset_rx(usart_dev *dev) {
+ rb_reset(dev->rb);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/usb.h b/libmaple/include/libmaple/usb.h
new file mode 100644
index 0000000..8555aca
--- /dev/null
+++ b/libmaple/include/libmaple/usb.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/*
+ * NOTE: This API is _unstable_ and will change drastically over time.
+ */
+
+#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
+#endif
+
+typedef enum usb_dev_state {
+ USB_UNCONNECTED,
+ USB_ATTACHED,
+ USB_POWERED,
+ USB_SUSPENDED,
+ USB_ADDRESSED,
+ USB_CONFIGURED
+} usb_dev_state;
+
+/* Encapsulates global state formerly handled by usb_lib/ */
+typedef struct usblib_dev {
+ uint32 irq_mask;
+ void (**ep_int_in)(void);
+ void (**ep_int_out)(void);
+ usb_dev_state state;
+ rcc_clk_id clk_id;
+} usblib_dev;
+
+extern usblib_dev *USBLIB;
+
+void usb_init_usblib(usblib_dev *dev,
+ void (**ep_int_in)(void),
+ void (**ep_int_out)(void));
+
+static inline uint8 usb_is_connected(usblib_dev *dev) {
+ return dev->state != USB_UNCONNECTED;
+}
+
+static inline uint8 usb_is_configured(usblib_dev *dev) {
+ return dev->state == USB_CONFIGURED;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/usb_cdcacm.h b/libmaple/include/libmaple/usb_cdcacm.h
new file mode 100644
index 0000000..9d70758
--- /dev/null
+++ b/libmaple/include/libmaple/usb_cdcacm.h
@@ -0,0 +1,59 @@
+/******************************************************************************
+ * 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/include/libmaple/usb_cdcacm.h
+ * @brief USB CDC ACM (virtual serial terminal) support
+ */
+
+#ifndef _LIBMAPLE_USB_CDCACM_H_
+#define _LIBMAPLE_USB_CDCACM_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/gpio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void usb_cdcacm_enable(gpio_dev*, uint8);
+void usb_cdcacm_disable(gpio_dev*, uint8);
+
+void usb_cdcacm_putc(char ch);
+uint32 usb_cdcacm_tx(const uint8* buf, uint32 len);
+uint32 usb_cdcacm_rx(uint8* buf, uint32 len);
+
+uint32 usb_cdcacm_data_available(void); /* in RX buffer */
+uint16 usb_cdcacm_get_pending(void);
+
+uint8 usb_cdcacm_get_dtr(void);
+uint8 usb_cdcacm_get_rts(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/include/libmaple/util.h b/libmaple/include/libmaple/util.h
new file mode 100644
index 0000000..5a70348
--- /dev/null
+++ b/libmaple/include/libmaple/util.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ * 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/util.h
+ * @brief Miscellaneous utility macros and procedures.
+ */
+
+#ifndef _LIBMAPLE_UTIL_H_
+#define _LIBMAPLE_UTIL_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include <libmaple/libmaple_types.h>
+
+/*
+ * Bit manipulation
+ */
+
+/** 1UL shifted left by 'shift' */
+#define BIT(shift) (1UL << (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 iff v is a power of two (1, 2, 4, 8, ...) */
+#define IS_POWER_OF_TWO(v) ((v) && !((v) & ((v) - 1)))
+
+/*
+ * Failure routines
+ */
+
+void __error(void);
+void _fail(const char*, int, const char*);
+void throb(void);
+
+/*
+ * Asserts and debug levels
+ */
+
+#define DEBUG_NONE 0
+#define DEBUG_FAULT 1
+#define DEBUG_ALL 2
+
+/**
+ * \def DEBUG_LEVEL
+ *
+ * Controls the level of assertion checking.
+ *
+ * The higher the debug level, the more assertions will be compiled
+ * in. This increases the amount of debugging information, but slows
+ * down (and increases the size of) the binary.
+ *
+ * The debug levels, from lowest to highest, are DEBUG_NONE,
+ * DEBUG_FAULT, and DEBUG_ALL. The default level is DEBUG_ALL.
+ */
+
+#ifndef DEBUG_LEVEL
+#define DEBUG_LEVEL DEBUG_ALL
+#endif
+
+#if DEBUG_LEVEL >= DEBUG_ALL
+#define ASSERT(exp) \
+ if (exp) { \
+ } else { \
+ _fail(__FILE__, __LINE__, #exp); \
+ }
+#else
+#define ASSERT(exp) (void)((0))
+#endif
+
+#if DEBUG_LEVEL >= DEBUG_FAULT
+#define ASSERT_FAULT(exp) \
+ if (exp) { \
+ } else { \
+ _fail(__FILE__, __LINE__, #exp); \
+ }
+#else
+#define ASSERT_FAULT(exp) (void)((0))
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif