aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/include
diff options
context:
space:
mode:
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.h112
-rw-r--r--libmaple/include/libmaple/exti.h143
-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.h93
-rw-r--r--libmaple/include/libmaple/iwdg.h115
-rw-r--r--libmaple/include/libmaple/libmaple.h48
-rw-r--r--libmaple/include/libmaple/libmaple_types.h73
-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.h214
-rw-r--r--libmaple/include/libmaple/spi.h470
-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.h176
-rw-r--r--libmaple/include/libmaple/usb_cdcacm.h179
-rw-r--r--libmaple/include/libmaple/util.h111
30 files changed, 6745 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..e22cdaf
--- /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 address 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..3765cd5
--- /dev/null
+++ b/libmaple/include/libmaple/dma_common.h
@@ -0,0 +1,112 @@
+/******************************************************************************
+ * 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>.
+ *
+ * CONTENTS UNSTABLE. The existence of this file is an implementation
+ * detail. 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..1d201ac
--- /dev/null
+++ b/libmaple/include/libmaple/exti.h
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * 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_attach_callback(exti_num num,
+ exti_cfg port,
+ voidArgumentFuncPtr handler,
+ void *arg,
+ 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..17cabe3
--- /dev/null
+++ b/libmaple/include/libmaple/i2c_common.h
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * 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
+ *
+ * CONTENTS UNSTABLE. The existence of this file is an implementation
+ * detail. 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..c9034d7
--- /dev/null
+++ b/libmaple/include/libmaple/libmaple.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * 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>
+
+#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..60dd2ff
--- /dev/null
+++ b/libmaple/include/libmaple/libmaple_types.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * 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);
+typedef void (*voidArgumentFuncPtr)(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..ffe385d
--- /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 __always_inline void nvic_globalirq_enable() {
+ asm volatile("cpsie i");
+}
+
+/**
+ * Disable interrupts and configurable fault handlers (set PRIMASK).
+ */
+static __always_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..c42a0f2
--- /dev/null
+++ b/libmaple/include/libmaple/scb.h
@@ -0,0 +1,214 @@
+/******************************************************************************
+ * 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/scb.h
+ * @brief System control block header
+ */
+
+/*
+ * FIXME: STM32F2?
+ */
+
+#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 (1U << 31)
+#define SCB_ICSR_PENDSVSET (1U << 28)
+#define SCB_ICSR_PENDSVCLR (1U << 27)
+#define SCB_ICSR_PENDSTSET (1U << 26)
+#define SCB_ICSR_PENDSTCLR (1U << 25)
+#define SCB_ICSR_ISRPENDING (1U << 22)
+#define SCB_ICSR_VECTPENDING (0x3FF << 12)
+#define SCB_ICSR_RETOBASE (1U << 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 (1U << 15)
+#define SCB_AIRCR_PRIGROUP (0x3 << 8)
+#define SCB_AIRCR_SYSRESETREQ (1U << 2)
+#define SCB_AIRCR_VECTCLRACTIVE (1U << 1)
+#define SCB_AIRCR_VECTRESET (1U << 0)
+
+/* System control register (SCB_SCR) */
+
+#define SCB_SCR_SEVONPEND (1U << 4)
+#define SCB_SCR_SLEEPDEEP (1U << 2)
+#define SCB_SCR_SLEEPONEXIT (1U << 1)
+
+/* Configuration and Control Register (SCB_CCR) */
+
+#define SCB_CCR_STKALIGN (1U << 9)
+#define SCB_CCR_BFHFNMIGN (1U << 8)
+#define SCB_CCR_DIV_0_TRP (1U << 4)
+#define SCB_CCR_UNALIGN_TRP (1U << 3)
+#define SCB_CCR_USERSETMPEND (1U << 1)
+#define SCB_CCR_NONBASETHRDENA (1U << 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 (1U << 18)
+#define SCB_SHCSR_BUSFAULTENA (1U << 17)
+#define SCB_SHCSR_MEMFAULTENA (1U << 16)
+#define SCB_SHCSR_SVCALLPENDED (1U << 15)
+#define SCB_SHCSR_BUSFAULTPENDED (1U << 14)
+#define SCB_SHCSR_MEMFAULTPENDED (1U << 13)
+#define SCB_SHCSR_USGFAULTPENDED (1U << 12)
+#define SCB_SHCSR_SYSTICKACT (1U << 11)
+#define SCB_SHCSR_PENDSVACT (1U << 10)
+#define SCB_SHCSR_MONITORACT (1U << 8)
+#define SCB_SHCSR_SVCALLACT (1U << 7)
+#define SCB_SHCSR_USGFAULTACT (1U << 3)
+#define SCB_SHCSR_BUSFAULTACT (1U << 1)
+#define SCB_SHCSR_MEMFAULTACT (1U << 0)
+
+/* Configurable fault status register (SCB_CFSR) */
+
+#define SCB_CFSR_DIVBYZERO (1U << 25)
+#define SCB_CFSR_UNALIGNED (1U << 24)
+#define SCB_CFSR_NOCP (1U << 19)
+#define SCB_CFSR_INVPC (1U << 18)
+#define SCB_CFSR_INVSTATE (1U << 17)
+#define SCB_CFSR_UNDEFINSTR (1U << 16)
+#define SCB_CFSR_BFARVALID (1U << 15)
+#define SCB_CFSR_STKERR (1U << 12)
+#define SCB_CFSR_UNSTKERR (1U << 11)
+#define SCB_CFSR_IMPRECISERR (1U << 10)
+#define SCB_CFSR_PRECISERR (1U << 9)
+#define SCB_CFSR_IBUSERR (1U << 8)
+#define SCB_CFSR_MMARVALID (1U << 7)
+#define SCB_CFSR_MSTKERR (1U << 4)
+#define SCB_CFSR_MUNSTKERR (1U << 3)
+#define SCB_CFSR_DACCVIOL (1U << 1)
+#define SCB_CFSR_IACCVIOL (1U << 0)
+
+/* Hard Fault Status Register (SCB_HFSR) */
+
+#define SCB_HFSR_DEBUG_VT (1U << 31)
+#define SCB_CFSR_FORCED (1U << 30)
+#define SCB_CFSR_VECTTBL (1U << 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 (1U << 4)
+#define SCB_DFSR_VCATCH (1U << 3)
+#define SCB_DFSR_DWTTRAP (1U << 2)
+#define SCB_DFSR_BKPT (1U << 1)
+#define SCB_DFSR_HALTED (1U << 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..4acd230
--- /dev/null
+++ b/libmaple/include/libmaple/spi.h
@@ -0,0 +1,470 @@
+/******************************************************************************
+ * 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 dev SPI device
+ * @param as_master If true, configure as bus master; otherwise, as slave.
+ * @param nss_dev NSS pin's GPIO device
+ * @param nss_bit NSS pin's GPIO bit on nss_dev
+ * @param comm_dev SCK, MISO, MOSI pins' GPIO device
+ * @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..ea24030
--- /dev/null
+++ b/libmaple/include/libmaple/usb.h
@@ -0,0 +1,176 @@
+/******************************************************************************
+ * 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.
+ *****************************************************************************/
+
+/*
+ * 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>
+
+/*
+ * Descriptors and other paraphernalia
+ */
+
+/* Descriptor types */
+
+#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
+#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
+#define USB_DESCRIPTOR_TYPE_STRING 0x03
+#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
+#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
+
+/* Descriptor structs and declaration helpers */
+
+#define USB_DESCRIPTOR_STRING_LEN(x) (2 + (x << 1))
+
+#define USB_DESCRIPTOR_STRING(len) \
+ struct { \
+ uint8 bLength; \
+ uint8 bDescriptorType; \
+ uint16 bString[len]; \
+ } __packed
+
+typedef struct usb_descriptor_device {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint16 bcdUSB;
+ uint8 bDeviceClass;
+ uint8 bDeviceSubClass;
+ uint8 bDeviceProtocol;
+ uint8 bMaxPacketSize0;
+ uint16 idVendor;
+ uint16 idProduct;
+ uint16 bcdDevice;
+ uint8 iManufacturer;
+ uint8 iProduct;
+ uint8 iSerialNumber;
+ uint8 bNumConfigurations;
+} __packed usb_descriptor_device;
+
+typedef struct usb_descriptor_config_header {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint16 wTotalLength;
+ uint8 bNumInterfaces;
+ uint8 bConfigurationValue;
+ uint8 iConfiguration;
+ uint8 bmAttributes;
+ uint8 bMaxPower;
+} __packed usb_descriptor_config_header;
+
+typedef struct usb_descriptor_interface {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint8 bInterfaceNumber;
+ uint8 bAlternateSetting;
+ uint8 bNumEndpoints;
+ uint8 bInterfaceClass;
+ uint8 bInterfaceSubClass;
+ uint8 bInterfaceProtocol;
+ uint8 iInterface;
+} __packed usb_descriptor_interface;
+
+typedef struct usb_descriptor_endpoint {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint8 bEndpointAddress;
+ uint8 bmAttributes;
+ uint16 wMaxPacketSize;
+ uint8 bInterval;
+} __packed usb_descriptor_endpoint;
+
+typedef struct usb_descriptor_string {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint8 bString[];
+} usb_descriptor_string;
+
+/* Common values that go inside descriptors */
+
+#define USB_CONFIG_ATTR_BUSPOWERED 0b10000000
+#define USB_CONFIG_ATTR_SELF_POWERED 0b11000000
+
+#define USB_EP_TYPE_INTERRUPT 0x03
+#define USB_EP_TYPE_BULK 0x02
+
+#define USB_DESCRIPTOR_ENDPOINT_IN 0x80
+#define USB_DESCRIPTOR_ENDPOINT_OUT 0x00
+
+/*
+ * USB module core
+ */
+
+#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;
+ usb_dev_state prevState;
+ 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..5fe832c
--- /dev/null
+++ b/libmaple/include/libmaple/usb_cdcacm.h
@@ -0,0 +1,179 @@
+/******************************************************************************
+ * 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
+ *
+ * IMPORTANT: this API is unstable, and may change without notice.
+ */
+
+#ifndef _LIBMAPLE_USB_CDCACM_H_
+#define _LIBMAPLE_USB_CDCACM_H_
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/gpio.h>
+#include <libmaple/usb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * CDC ACM Requests
+ */
+
+#define USB_CDCACM_SET_LINE_CODING 0x20
+#define USB_CDCACM_GET_LINE_CODING 0x21
+#define USB_CDCACM_SET_COMM_FEATURE 0x02
+#define USB_CDCACM_SET_CONTROL_LINE_STATE 0x22
+#define USB_CDCACM_CONTROL_LINE_DTR (0x01)
+#define USB_CDCACM_CONTROL_LINE_RTS (0x02)
+
+/*
+ * Descriptors, etc.
+ */
+
+#define CDC_FUNCTIONAL_DESCRIPTOR_SIZE(DataSize) (3 + DataSize)
+#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \
+ struct { \
+ uint8 bLength; \
+ uint8 bDescriptorType; \
+ uint8 SubType; \
+ uint8 Data[DataSize]; \
+ } __packed
+
+#define USB_DEVICE_CLASS_CDC 0x02
+#define USB_DEVICE_SUBCLASS_CDC 0x00
+#define USB_INTERFACE_CLASS_CDC 0x02
+#define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02
+#define USB_INTERFACE_CLASS_DIC 0x0A
+
+/*
+ * Endpoint configuration
+ */
+
+#define USB_CDCACM_CTRL_ENDP 0
+#define USB_CDCACM_CTRL_RX_ADDR 0x40
+#define USB_CDCACM_CTRL_TX_ADDR 0x80
+#define USB_CDCACM_CTRL_EPSIZE 0x40
+
+#define USB_CDCACM_TX_ENDP 1
+#define USB_CDCACM_TX_ADDR 0xC0
+#define USB_CDCACM_TX_EPSIZE 0x40
+
+#define USB_CDCACM_MANAGEMENT_ENDP 2
+#define USB_CDCACM_MANAGEMENT_ADDR 0x100
+#define USB_CDCACM_MANAGEMENT_EPSIZE 0x40
+
+#define USB_CDCACM_RX_ENDP 3
+#define USB_CDCACM_RX_ADDR 0x110
+#define USB_CDCACM_RX_EPSIZE 0x40
+
+#ifndef __cplusplus
+#define USB_CDCACM_DECLARE_DEV_DESC(vid, pid) \
+ { \
+ .bLength = sizeof(usb_descriptor_device), \
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, \
+ .bcdUSB = 0x0200, \
+ .bDeviceClass = USB_DEVICE_CLASS_CDC, \
+ .bDeviceSubClass = USB_DEVICE_SUBCLASS_CDC, \
+ .bDeviceProtocol = 0x00, \
+ .bMaxPacketSize0 = 0x40, \
+ .idVendor = vid, \
+ .idProduct = pid, \
+ .bcdDevice = 0x0200, \
+ .iManufacturer = 0x01, \
+ .iProduct = 0x02, \
+ .iSerialNumber = 0x00, \
+ .bNumConfigurations = 0x01, \
+ }
+#endif
+
+/*
+ * CDC ACM interface
+ */
+
+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_peek(uint8* buf, uint32 len);
+
+uint32 usb_cdcacm_data_available(void); /* in RX buffer */
+uint16 usb_cdcacm_get_pending(void);
+uint8 usb_cdcacm_is_transmitting(void);
+
+uint8 usb_cdcacm_get_dtr(void);
+uint8 usb_cdcacm_get_rts(void);
+
+typedef struct usb_cdcacm_line_coding {
+ uint32 dwDTERate; /* Baud rate */
+
+#define USB_CDCACM_STOP_BITS_1 0
+#define USB_CDCACM_STOP_BITS_1_5 1
+#define USB_CDCACM_STOP_BITS_2 2
+ uint8 bCharFormat; /* Stop bits */
+
+#define USB_CDCACM_PARITY_NONE 0
+#define USB_CDCACM_PARITY_ODD 1
+#define USB_CDCACM_PARITY_EVEN 2
+#define USB_CDCACM_PARITY_MARK 3
+#define USB_CDCACM_PARITY_SPACE 4
+ uint8 bParityType; /* Parity type */
+
+ uint8 bDataBits; /* Data bits: 5, 6, 7, 8, or 16 */
+} __packed usb_cdcacm_line_coding;
+
+/* Retrieve a copy of the current line coding structure. */
+void usb_cdcacm_get_line_coding(usb_cdcacm_line_coding*);
+
+/* Line coding conveniences. */
+int usb_cdcacm_get_baud(void); /* dwDTERate */
+int usb_cdcacm_get_stop_bits(void); /* bCharFormat */
+int usb_cdcacm_get_parity(void); /* bParityType */
+int usb_cdcacm_get_n_data_bits(void); /* bDataBits */
+
+/*
+ * Hack: hooks for bootloader reset signalling
+ */
+
+#define USB_CDCACM_HOOK_RX 0x1
+#define USB_CDCACM_HOOK_IFACE_SETUP 0x2
+
+void usb_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*));
+
+static __always_inline void usb_cdcacm_remove_hooks(unsigned hook_flags) {
+ usb_cdcacm_set_hooks(hook_flags, 0);
+}
+
+#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