diff options
Diffstat (limited to 'libmaple/include')
30 files changed, 6532 insertions, 0 deletions
diff --git a/libmaple/include/libmaple/adc.h b/libmaple/include/libmaple/adc.h new file mode 100644 index 0000000..a500af7 --- /dev/null +++ b/libmaple/include/libmaple/adc.h @@ -0,0 +1,329 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/adc.h + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> + * @brief Analog-to-Digital Conversion (ADC) header. + */ + +#ifndef _LIBMAPLE_ADC_H_ +#define _LIBMAPLE_ADC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple.h> +#include <libmaple/bitband.h> +#include <libmaple/rcc.h> +/* We include the series header below, after defining the register map + * and device structs. */ + +/* + * Register map + */ + +/** ADC register map type. */ +typedef struct adc_reg_map { + __io uint32 SR; ///< Status register + __io uint32 CR1; ///< Control register 1 + __io uint32 CR2; ///< Control register 2 + __io uint32 SMPR1; ///< Sample time register 1 + __io uint32 SMPR2; ///< Sample time register 2 + __io uint32 JOFR1; ///< Injected channel data offset register 1 + __io uint32 JOFR2; ///< Injected channel data offset register 2 + __io uint32 JOFR3; ///< Injected channel data offset register 3 + __io uint32 JOFR4; ///< Injected channel data offset register 4 + __io uint32 HTR; ///< Watchdog high threshold register + __io uint32 LTR; ///< Watchdog low threshold register + __io uint32 SQR1; ///< Regular sequence register 1 + __io uint32 SQR2; ///< Regular sequence register 2 + __io uint32 SQR3; ///< Regular sequence register 3 + __io uint32 JSQR; ///< Injected sequence register + __io uint32 JDR1; ///< Injected data register 1 + __io uint32 JDR2; ///< Injected data register 2 + __io uint32 JDR3; ///< Injected data register 3 + __io uint32 JDR4; ///< Injected data register 4 + __io uint32 DR; ///< Regular data register +} adc_reg_map; + +/** ADC device type. */ +typedef struct adc_dev { + adc_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ +} adc_dev; + +/* Pull in the series header (which may need the above struct + * definitions). + * + * IMPORTANT: The series header must define the following: + * + * - enum adc_extsel_event (and typedef to adc_extsel_event): One per + * external event used to trigger start of conversion of a regular + * group. If two different series support the same event as a + * trigger, they must use the same token for the enumerator for that + * event. (The value of the enumerator is of course allowed to be + * different). + * + * - enum adc_smp_rate (and typedef to adc_smp_rate): One per + * available sampling time. These must be in the form ADC_SMPR_X_Y + * for X.Y cycles (e.g. ADC_SMPR_1_5 means 1.5 cycles), or + * ADC_SMPR_X for X cycles (e.g. ADC_SMPR_3 means 3 cycles). + * + * - enum adc_prescaler (and typedef): One per available prescaler, + * suitable for adc_set_prescaler. Series which have the same + * prescaler dividers (e.g. STM32F1 and STM32F2 both divide PCLK2 by + * 2, 4, 6, or 8) must provide the same tokens as enumerators, for + * portability. + */ +#include <series/adc.h> + +/* + * Register bit definitions + */ + +/* Status register */ + +#define ADC_SR_AWD_BIT 0 +#define ADC_SR_EOC_BIT 1 +#define ADC_SR_JEOC_BIT 2 +#define ADC_SR_JSTRT_BIT 3 +#define ADC_SR_STRT_BIT 4 + +#define ADC_SR_AWD BIT(ADC_SR_AWD_BIT) +#define ADC_SR_EOC BIT(ADC_SR_EOC_BIT) +#define ADC_SR_JEOC BIT(ADC_SR_JEOC_BIT) +#define ADC_SR_JSTRT BIT(ADC_SR_JSTRT_BIT) +#define ADC_SR_STRT BIT(ADC_SR_STRT_BIT) + +/* Control register 1 */ + +#define ADC_CR1_EOCIE_BIT 5 +#define ADC_CR1_AWDIE_BIT 6 +#define ADC_CR1_JEOCIE_BIT 7 +#define ADC_CR1_SCAN_BIT 8 +#define ADC_CR1_AWDSGL_BIT 9 +#define ADC_CR1_JAUTO_BIT 10 +#define ADC_CR1_DISCEN_BIT 11 +#define ADC_CR1_JDISCEN_BIT 12 +#define ADC_CR1_JAWDEN_BIT 22 +#define ADC_CR1_AWDEN_BIT 23 + +#define ADC_CR1_AWDCH (0x1F) +#define ADC_CR1_EOCIE BIT(ADC_CR1_EOCIE_BIT) +#define ADC_CR1_AWDIE BIT(ADC_CR1_AWDIE_BIT) +#define ADC_CR1_JEOCIE BIT(ADC_CR1_JEOCIE_BIT) +#define ADC_CR1_SCAN BIT(ADC_CR1_SCAN_BIT) +#define ADC_CR1_AWDSGL BIT(ADC_CR1_AWDSGL_BIT) +#define ADC_CR1_JAUTO BIT(ADC_CR1_JAUTO_BIT) +#define ADC_CR1_DISCEN BIT(ADC_CR1_DISCEN_BIT) +#define ADC_CR1_JDISCEN BIT(ADC_CR1_JDISCEN_BIT) +#define ADC_CR1_DISCNUM (0xE000) +#define ADC_CR1_JAWDEN BIT(ADC_CR1_JAWDEN_BIT) +#define ADC_CR1_AWDEN BIT(ADC_CR1_AWDEN_BIT) + +/* Control register 2 */ + +/* Because this register varies significantly by series (e.g. some + * bits moved and others disappeared in the F1->F2 transition), its + * definitions are in the series headers. */ + +/* Sample time register 1 */ + +#define ADC_SMPR1_SMP17 (0x7 << 21) +#define ADC_SMPR1_SMP16 (0x7 << 18) +#define ADC_SMPR1_SMP15 (0x7 << 15) +#define ADC_SMPR1_SMP14 (0x7 << 12) +#define ADC_SMPR1_SMP13 (0x7 << 9) +#define ADC_SMPR1_SMP12 (0x7 << 6) +#define ADC_SMPR1_SMP11 (0x7 << 3) +#define ADC_SMPR1_SMP10 0x7 + +/* Sample time register 2 */ + +#define ADC_SMPR2_SMP9 (0x7 << 27) +#define ADC_SMPR2_SMP8 (0x7 << 24) +#define ADC_SMPR2_SMP7 (0x7 << 21) +#define ADC_SMPR2_SMP6 (0x7 << 18) +#define ADC_SMPR2_SMP5 (0x7 << 15) +#define ADC_SMPR2_SMP4 (0x7 << 12) +#define ADC_SMPR2_SMP3 (0x7 << 9) +#define ADC_SMPR2_SMP2 (0x7 << 6) +#define ADC_SMPR2_SMP1 (0x7 << 3) +#define ADC_SMPR2_SMP0 0x7 + +/* Injected channel data offset register */ + +#define ADC_JOFR_JOFFSET 0x3FF + +/* Watchdog high threshold register */ + +#define ADC_HTR_HT 0x3FF + +/* Watchdog low threshold register */ + +#define ADC_LTR_LT 0x3FF + +/* Regular sequence register 1 */ + +#define ADC_SQR1_L (0x1F << 20) +#define ADC_SQR1_SQ16 (0x1F << 15) +#define ADC_SQR1_SQ15 (0x1F << 10) +#define ADC_SQR1_SQ14 (0x1F << 5) +#define ADC_SQR1_SQ13 0x1F + +/* Regular sequence register 2 */ + +#define ADC_SQR2_SQ12 (0x1F << 25) +#define ADC_SQR2_SQ11 (0x1F << 20) +#define ADC_SQR2_SQ10 (0x1F << 16) +#define ADC_SQR2_SQ9 (0x1F << 10) +#define ADC_SQR2_SQ8 (0x1F << 5) +#define ADC_SQR2_SQ7 0x1F + +/* Regular sequence register 3 */ + +#define ADC_SQR3_SQ6 (0x1F << 25) +#define ADC_SQR3_SQ5 (0x1F << 20) +#define ADC_SQR3_SQ4 (0x1F << 16) +#define ADC_SQR3_SQ3 (0x1F << 10) +#define ADC_SQR3_SQ2 (0x1F << 5) +#define ADC_SQR3_SQ1 0x1F + +/* Injected sequence register */ + +#define ADC_JSQR_JL (0x3 << 20) +#define ADC_JSQR_JL_1CONV (0x0 << 20) +#define ADC_JSQR_JL_2CONV (0x1 << 20) +#define ADC_JSQR_JL_3CONV (0x2 << 20) +#define ADC_JSQR_JL_4CONV (0x3 << 20) +#define ADC_JSQR_JSQ4 (0x1F << 15) +#define ADC_JSQR_JSQ3 (0x1F << 10) +#define ADC_JSQR_JSQ2 (0x1F << 5) +#define ADC_JSQR_JSQ1 0x1F + +/* Injected data registers */ + +#define ADC_JDR_JDATA 0xFFFF + +/* Regular data register */ + +#define ADC_DR_ADC2DATA (0xFFFF << 16) +#define ADC_DR_DATA 0xFFFF + +/* + * Routines + */ + +void adc_init(const adc_dev *dev); +void adc_set_extsel(const adc_dev *dev, adc_extsel_event event); +void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); +uint16 adc_read(const adc_dev *dev, uint8 channel); + +/** + * @brief Set the ADC prescaler. + * + * This determines the ADC clock for all devices. + */ +extern void adc_set_prescaler(adc_prescaler pre); + +/** + * @brief Call a function on all ADC devices. + * @param fn Function to call on each ADC device. + */ +extern void adc_foreach(void (*fn)(const adc_dev*)); + +struct gpio_dev; +/** + * @brief Configure a GPIO pin for ADC conversion. + * @param dev ADC device to use for conversion (currently ignored on + * all targets). + * @param gdev GPIO device to configure. + * @param bit Bit on gdev to configure for ADC conversion. + */ +extern void adc_config_gpio(const struct adc_dev *dev, + struct gpio_dev *gdev, + uint8 bit); + +/** + * @brief Enable an ADC and configure it for single conversion mode. + * + * This function performs any initialization necessary to allow the + * ADC device to perform a single synchronous regular software + * triggered conversion, using adc_read(). + * + * @param dev Device to enable. + * @see adc_read() + */ +extern void adc_enable_single_swstart(const adc_dev* dev); + +/** + * @brief Set the regular channel sequence length. + * + * Defines the total number of conversions in the regular channel + * conversion sequence. + * + * @param dev ADC device. + * @param length Regular channel sequence length, from 1 to 16. + */ +static inline void adc_set_reg_seqlen(const adc_dev *dev, uint8 length) { + uint32 tmp = dev->regs->SQR1; + tmp &= ~ADC_SQR1_L; + tmp |= (length - 1) << 20; + dev->regs->SQR1 = tmp; +} + +/** + * @brief Enable an adc peripheral + * @param dev ADC device to enable + */ +static inline void adc_enable(const adc_dev *dev) { + *bb_perip(&dev->regs->CR2, ADC_CR2_ADON_BIT) = 1; +} + +/** + * @brief Disable an ADC peripheral + * @param dev ADC device to disable + */ +static inline void adc_disable(const adc_dev *dev) { + *bb_perip(&dev->regs->CR2, ADC_CR2_ADON_BIT) = 0; +} + +/** + * @brief Disable all ADC peripherals. + */ +static inline void adc_disable_all(void) { + adc_foreach(adc_disable); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/bitband.h b/libmaple/include/libmaple/bitband.h new file mode 100644 index 0000000..6e77991 --- /dev/null +++ b/libmaple/include/libmaple/bitband.h @@ -0,0 +1,128 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/bitband.h + * + * @brief Bit-banding utility functions + */ + +#ifndef _LIBMAPLE_BITBAND_H_ +#define _LIBMAPLE_BITBAND_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> + +#define BB_SRAM_REF 0x20000000 +#define BB_SRAM_BASE 0x22000000 +#define BB_PERI_REF 0x40000000 +#define BB_PERI_BASE 0x42000000 + +static inline volatile uint32* __bb_addr(volatile void*, + uint32, + uint32, + uint32); + +/** + * @brief Obtain a pointer to the bit-band address corresponding to a + * bit in a volatile SRAM address. + * @param address Address in the bit-banded SRAM region + * @param bit Bit in address to bit-band + */ +static inline volatile uint32* bb_sramp(volatile void *address, uint32 bit) { + return __bb_addr(address, bit, BB_SRAM_BASE, BB_SRAM_REF); +} + +/** + * @brief Get a bit from an address in the SRAM bit-band region. + * @param address Address in the SRAM bit-band region to read from + * @param bit Bit in address to read + * @return bit's value in address. + */ +static inline uint8 bb_sram_get_bit(volatile void *address, uint32 bit) { + return *bb_sramp(address, bit); +} + +/** + * @brief Set a bit in an address in the SRAM bit-band region. + * @param address Address in the SRAM bit-band region to write to + * @param bit Bit in address to write to + * @param val Value to write for bit, either 0 or 1. + */ +static inline void bb_sram_set_bit(volatile void *address, + uint32 bit, + uint8 val) { + *bb_sramp(address, bit) = val; +} + +/** + * @brief Obtain a pointer to the bit-band address corresponding to a + * bit in a peripheral address. + * @param address Address in the bit-banded peripheral region + * @param bit Bit in address to bit-band + */ +static inline volatile uint32* bb_perip(volatile void *address, uint32 bit) { + return __bb_addr(address, bit, BB_PERI_BASE, BB_PERI_REF); +} + +/** + * @brief Get a bit from an address in the peripheral bit-band region. + * @param address Address in the peripheral bit-band region to read from + * @param bit Bit in address to read + * @return bit's value in address. + */ +static inline uint8 bb_peri_get_bit(volatile void *address, uint32 bit) { + return *bb_perip(address, bit); +} + +/** + * @brief Set a bit in an address in the peripheral bit-band region. + * @param address Address in the peripheral bit-band region to write to + * @param bit Bit in address to write to + * @param val Value to write for bit, either 0 or 1. + */ +static inline void bb_peri_set_bit(volatile void *address, + uint32 bit, + uint8 val) { + *bb_perip(address, bit) = val; +} + +static inline volatile uint32* __bb_addr(volatile void *address, + uint32 bit, + uint32 bb_base, + uint32 bb_ref) { + return (volatile uint32*)(bb_base + ((uint32)address - bb_ref) * 32 + + bit * 4); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/bkp.h b/libmaple/include/libmaple/bkp.h new file mode 100644 index 0000000..bb63a2f --- /dev/null +++ b/libmaple/include/libmaple/bkp.h @@ -0,0 +1,166 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/bkp.h + * @brief Backup register support (STM32F1 only). + */ + +#ifndef _LIBMAPLE_BKP_H_ +#define _LIBMAPLE_BKP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple.h> + +#if defined(STM32_MEDIUM_DENSITY) +#define BKP_NR_DATA_REGS 10 +#elif defined(STM32_HIGH_DENSITY) +#define BKP_NR_DATA_REGS 42 +#endif + +/** Backup peripheral register map type. */ +typedef struct bkp_reg_map { + const uint32 RESERVED1; ///< Reserved + __io uint32 DR1; ///< Data register 1 + __io uint32 DR2; ///< Data register 2 + __io uint32 DR3; ///< Data register 3 + __io uint32 DR4; ///< Data register 4 + __io uint32 DR5; ///< Data register 5 + __io uint32 DR6; ///< Data register 6 + __io uint32 DR7; ///< Data register 7 + __io uint32 DR8; ///< Data register 8 + __io uint32 DR9; ///< Data register 9 + __io uint32 DR10; ///< Data register 10 + __io uint32 RTCCR; ///< RTC control register + __io uint32 CR; ///< Control register + __io uint32 CSR; ///< Control and status register +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + const uint32 RESERVED2; ///< Reserved + const uint32 RESERVED3; ///< Reserved + __io uint32 DR11; ///< Data register 11 + __io uint32 DR12; ///< Data register 12 + __io uint32 DR13; ///< Data register 13 + __io uint32 DR14; ///< Data register 14 + __io uint32 DR15; ///< Data register 15 + __io uint32 DR16; ///< Data register 16 + __io uint32 DR17; ///< Data register 17 + __io uint32 DR18; ///< Data register 18 + __io uint32 DR19; ///< Data register 19 + __io uint32 DR20; ///< Data register 20 + __io uint32 DR21; ///< Data register 21 + __io uint32 DR22; ///< Data register 22 + __io uint32 DR23; ///< Data register 23 + __io uint32 DR24; ///< Data register 24 + __io uint32 DR25; ///< Data register 25 + __io uint32 DR26; ///< Data register 26 + __io uint32 DR27; ///< Data register 27 + __io uint32 DR28; ///< Data register 28 + __io uint32 DR29; ///< Data register 29 + __io uint32 DR30; ///< Data register 30 + __io uint32 DR31; ///< Data register 31 + __io uint32 DR32; ///< Data register 32 + __io uint32 DR33; ///< Data register 33 + __io uint32 DR34; ///< Data register 34 + __io uint32 DR35; ///< Data register 35 + __io uint32 DR36; ///< Data register 36 + __io uint32 DR37; ///< Data register 37 + __io uint32 DR38; ///< Data register 38 + __io uint32 DR39; ///< Data register 39 + __io uint32 DR40; ///< Data register 40 + __io uint32 DR41; ///< Data register 41 + __io uint32 DR42; ///< Data register 42 +#endif +} bkp_reg_map; + +/** Backup peripheral register map base pointer. */ +#define BKP_BASE ((struct bkp_reg_map*)0x40006C00) + +/** Backup peripheral device type. */ +typedef struct bkp_dev { + bkp_reg_map *regs; /**< Register map */ +} bkp_dev; + +extern const bkp_dev *BKP; + +/* + * Register bit definitions + */ + +/* Data Registers */ + +#define BKP_DR_D 0xFFFF + +/* RTC Clock Calibration Register */ + +#define BKP_RTCCR_ASOS_BIT 9 +#define BKP_RTCCR_ASOE_BIT 8 +#define BKP_RTCCR_CCO_BIT 7 + +#define BKP_RTCCR_ASOS BIT(BKP_RTCCR_ASOS_BIT) +#define BKP_RTCCR_ASOE BIT(BKP_RTCCR_ASOE_BIT) +#define BKP_RTCCR_CCO BIT(BKP_RTCCR_CCO_BIT) +#define BKP_RTCCR_CAL 0x7F + +/* Backup control register */ + +#define BKP_CR_TPAL_BIT 1 +#define BKP_CR_TPE_BIT 0 + +#define BKP_CR_TPAL BIT(BKP_CR_TPAL_BIT) +#define BKP_CR_TPE BIT(BKP_CR_TPE_BIT) + +/* Backup control/status register */ + +#define BKP_CSR_TIF_BIT 9 +#define BKP_CSR_TEF_BIT 8 +#define BKP_CSR_TPIE_BIT 2 +#define BKP_CSR_CTI_BIT 1 +#define BKP_CSR_CTE_BIT 0 + +#define BKP_CSR_TIF BIT(BKP_CSR_TIF_BIT) +#define BKP_CSR_TEF BIT(BKP_CSR_TEF_BIT) +#define BKP_CSR_TPIE BIT(BKP_CSR_TPIE_BIT) +#define BKP_CSR_CTI BIT(BKP_CSR_CTI_BIT) +#define BKP_CSR_CTE BIT(BKP_CSR_CTE_BIT) + +/* + * Convenience functions + */ + +void bkp_init(void); +void bkp_enable_writes(void); +void bkp_disable_writes(void); +uint16 bkp_read(uint8 reg); +void bkp_write(uint8 reg, uint16 val); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/libmaple/include/libmaple/dac.h b/libmaple/include/libmaple/dac.h new file mode 100644 index 0000000..56bfdc4 --- /dev/null +++ b/libmaple/include/libmaple/dac.h @@ -0,0 +1,158 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * Copyright (c) 2010 Bryan Newbold. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/dac.h + * @brief Digital to analog converter support. + */ + +/* See notes/dac.txt for more info */ + +#ifndef _LIBMAPLE_DAC_H_ +#define _LIBMAPLE_DAC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <series/dac.h> +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> +#include <libmaple/stm32.h> + +/* + * Register map base and device pointers. + * + * The DACs are the same on all supported targets, so it's not worth + * repeating these in the series headers. + */ + +#define DAC_BASE ((struct dac_reg_map*)0x40007400) + +/** DAC device type. */ +typedef struct dac_dev { + dac_reg_map *regs; /**< Register map */ +} dac_dev; + +#if STM32_HAVE_DAC +extern const dac_dev *DAC; +#endif + +/* + * Register bit definitions + */ + +/* Control register */ + +/* Channel 1 control */ +#define DAC_CR_EN1 (1U << 0) /* Enable */ +#define DAC_CR_BOFF1 (1U << 1) /* Output buffer disable */ +#define DAC_CR_TEN1 (1U << 2) /* Trigger enable */ +#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */ +#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave */ +#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */ +#define DAC_CR_DMAEN1 (1U << 12) /* DMA enable */ +/* Channel 2 control */ +#define DAC_CR_EN2 (1U << 16) /* Enable */ +#define DAC_CR_BOFF2 (1U << 17) /* Output buffer disable */ +#define DAC_CR_TEN2 (1U << 18) /* Trigger enable */ +#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */ +#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave */ +#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */ +#define DAC_CR_DMAEN2 (1U << 28) /* DMA enable */ + +/* Software trigger register */ + +#define DAC_SWTRIGR_SWTRIG1 (1U << 0) /* Channel 1 software trigger */ +#define DAC_SWTRIGR_SWTRIG2 (1U << 1) /* Channel 2 software trigger */ + +/* Channel 1 12-bit right-aligned data holding register */ + +#define DAC_DHR12R1_DACC1DHR 0x00000FFF + +/* Channel 1 12-bit left-aligned data holding register */ + +#define DAC_DHR12L1_DACC1DHR 0x0000FFF0 + +/* Channel 1 8-bit left-aligned data holding register */ + +#define DAC_DHR8R1_DACC1DHR 0x000000FF + +/* Channel 2 12-bit right-aligned data holding register */ + +#define DAC_DHR12R2_DACC2DHR 0x00000FFF + +/* Channel 2 12-bit left-aligned data holding register */ + +#define DAC_DHR12L2_DACC2DHR 0x0000FFF0 + +/* Channel 2 8-bit left-aligned data holding register */ + +#define DAC_DHR8R2_DACC2DHR 0x000000FF + +/* Dual DAC 12-bit right-aligned data holding register */ + +#define DAC_DHR12RD_DACC1DHR 0x00000FFF +#define DAC_DHR12RD_DACC2DHR 0x0FFF0000 + +/* Dual DAC 12-bit left-aligned data holding register */ + +#define DAC_DHR12LD_DACC1DHR 0x0000FFF0 +#define DAC_DHR12LD_DACC2DHR 0xFFF00000 + +/* Dual DAC 8-bit left-aligned data holding register */ + +#define DAC_DHR8RD_DACC1DHR 0x000000FF +#define DAC_DHR8RD_DACC2DHR 0x0000FF00 + +/* Channel 1 data output register */ + +#define DAC_DOR1_DACC1DOR 0x00000FFF + +/* Channel 1 data output register */ + +#define DAC_DOR2_DACC2DOR 0x00000FFF + +/* + * Routines + */ + +/* We take the dev argument in these for future-proofing */ + +#define DAC_CH1 0x1 +#define DAC_CH2 0x2 +void dac_init(const dac_dev *dev, uint32 flags); + +void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val); +void dac_enable_channel(const dac_dev *dev, uint8 channel); +void dac_disable_channel(const dac_dev *dev, uint8 channel); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/delay.h b/libmaple/include/libmaple/delay.h new file mode 100644 index 0000000..472a208 --- /dev/null +++ b/libmaple/include/libmaple/delay.h @@ -0,0 +1,65 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/delay.h + * @brief Delay implementation + */ + +#ifndef _LIBMAPLE_DELAY_H_ +#define _LIBMAPLE_DELAY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/stm32.h> + +/** + * @brief Delay the given number of microseconds. + * + * @param us Number of microseconds to delay. + */ +static inline void delay_us(uint32 us) { + us *= STM32_DELAY_US_MULT; + + /* fudge for function call overhead */ + us--; + asm volatile(" mov r0, %[us] \n\t" + "1: subs r0, #1 \n\t" + " bhi 1b \n\t" + : + : [us] "r" (us) + : "r0"); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/dma.h b/libmaple/include/libmaple/dma.h new file mode 100644 index 0000000..0b1ec4c --- /dev/null +++ b/libmaple/include/libmaple/dma.h @@ -0,0 +1,444 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Michael Hope. + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/dma.h + * + * @author Marti Bolivar <mbolivar@leaflabs.com>; + * Original implementation by Michael Hope + * + * @brief Direct Memory Access peripheral support + */ + +#ifndef _LIBMAPLE_DMA_H_ +#define _LIBMAPLE_DMA_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/* <series/dma.h> provides: + * + * - An opaque dma_tube type, and predefined rvalues for each tube + * supported by the series. + * + * A "DMA tube" is a series-specific (hopefully integer) datatype + * that abstracts the conduit through which DMA-ed data flow. + * + * Examples: On STM32F1, dma_tube is just an alias for dma_channel, + * and the tube values are just DMA_CH1 (=1), DMA_CH2 (=2), etc. + * + * Note that a dma_tube doesn't have to be an enum, and its values + * don't have to be integral. They _do_ need to be cheap to pass as + * arguments, though. + * + * - struct dma_tube_reg_map (and typedef to dma_tube_reg_map). DMA + * register maps tend to be split into global registers and per-tube + * registers. It's convenient to pass around pointers to a tube's + * registers, since that makes it possible to configure or otherwise + * mess with a tube without knowing which one you're dealing with. + * + * - Base pointers to the various dma_tube_reg_maps. + * + * Examples: On STM32F1, these are DMAxCHy_BASE. You can access + * registers like DMAxCHy_BASE->CPAR, etc. + * + * - enum dma_request_src (and typedef to dma_request_src). This + * specifies the peripheral DMA request sources (e.g. USART TX DMA + * requests, etc.). + * + * - enum dma_mode_flags (and typedef to dma_mode_flags). Used in + * dma_tube_config. If two series both support the same mode flags, + * they must use the same enumerator names for those flags (the + * values of those enumerators are of course allowed to differ). + * + * - Normal stuff: dma_reg_map and base pointers, register bit + * definitions, dma_dev pointer declarations, and any other + * convenience functions useful for the series. */ +#include <series/dma.h> +/* <libmaple/dma_common.h> buys us dma_dev and other necessities. */ +#include <libmaple/dma_common.h> +#include <libmaple/libmaple_types.h> + +/* + * Declarations/documentation for some of the series-provided types. + */ + +/** + * @brief (Series-dependent) DMA request sources. + * + * These specify the various pieces of peripheral functionality which + * may make DMA requests. Use them to set up a DMA transfer (see + * struct dma_tube_config, dma_tube_cfg()). + */ +enum dma_request_src; + +/** + * @brief (Series-dependent) DMA tube configuration flags. + * These specify miscellaneous bits of configuration for a DMA tube. + * @see struct dma_mode_config + */ +enum dma_cfg_flags; + +/** + * @brief (Series-dependent) DMA tube register map type. + * This allows you to access a tube's registers as a group. + * @see dma_tube_regs() + */ +struct dma_tube_reg_map; + +/* + * Convenience functions + */ + +/* Initialization */ + +void dma_init(dma_dev *dev); + +/* dma_tube configuration + * + * Use these types and functions to set up DMA transfers, handle + * interrupts, etc. The main function of interest is dma_tube_cfg(), + * which the various series implement separately. */ + +/** + * @brief Specifies a DMA tube configuration. + * + * Use one of these to set up a DMA transfer by passing it to + * dma_tube_cfg(). + * + * @see dma_tube_cfg() + * @see dma_xfer_size + */ +typedef struct dma_tube_config { + /** Source of data */ + __io void *tube_src; + /** Source transfer size */ + dma_xfer_size tube_src_size; + + /** Destination of data */ + __io void *tube_dst; + /** Destination transfer size */ + dma_xfer_size tube_dst_size; + + /** + * Number of data to transfer (0 to 65,535). + * + * Note that this is NOT measured in bytes; it's measured in + * number of data, which occur in multiples of tube_src_size. For + * example, if tube_src_size is DMA_SIZE_32BITS and tube_nr_xfers + * is 2, then 8 total bytes will be transferred. + */ + unsigned tube_nr_xfers; + + /** + * Target-specific configuration flags. + * + * These are an OR of series-specific enum dma_mode_flags values. + * Consult the documentation for your target for what flags you + * can use here. + * + * Typical flag examples: DMA_CFG_SRC_INC, DMA_CFG_DST_INC, + * DMA_CFG_CIRC, DMA_CFG_CMPLT_IE, etc. + */ + unsigned tube_flags; + + /** + * Currently unused. You must set this to 0 or something valid for + * your target. */ + void *target_data; + + /** + * Hardware DMA request source. + * + * This is ignored for memory-to-memory transfers. + */ + enum dma_request_src tube_req_src; +} dma_tube_config; + +#define DMA_TUBE_CFG_SUCCESS 0 +#define DMA_TUBE_CFG_EREQ 1 +#define DMA_TUBE_CFG_ENDATA 2 +#define DMA_TUBE_CFG_EDEV 3 +#define DMA_TUBE_CFG_ESRC 4 +#define DMA_TUBE_CFG_EDST 5 +#define DMA_TUBE_CFG_EDIR 6 +#define DMA_TUBE_CFG_ESIZE 7 +#define DMA_TUBE_CFG_ECFG 0xFF +/** + * @brief Configure a DMA tube. + * + * Use this function to set up a DMA transfer. The tube will be + * disabled before being reconfigured. The transfer will have low + * priority by default. You can choose another priority before the + * transfer begins using dma_set_priority(). You can manage your + * interrupt handlers for the tube using dma_attach_interrupt() and + * dma_detach_interrupt(). + * + * After calling dma_tube_cfg() and performing any other desired + * configuration, start the transfer using dma_enable(). + * + * @param dev DMA device. + * @param tube DMA tube to configure. + * @param cfg Configuration to apply to tube. + * + * @return DMA_TUBE_CFG_SUCCESS (0) on success, <0 on failure. On + * failure, returned value will be the opposite (-) of one of: + * + * - DMA_TUBE_CFG_EREQ: tube doesn't work with cfg->tube_req_src + * - DMA_TUBE_CFG_ENDATA: cfg->tube_[src,dst]_size are + * incompatible with cfg->tube_nr_xfers, or cfg->tube_nr_xfers + * is out of bounds. + * - DMA_TUBE_CFG_EDEV: dev does not support cfg + * - DMA_TUBE_CFG_ESRC: bad cfg->tube_src + * - DMA_TUBE_CFG_EDST: bad cfg->tube_dst + * - DMA_TUBE_CFG_EDIR: dev can't transfer from cfg->tube_src to + * cfg->tube_dst + * - DMA_TUBE_CFG_ESIZE: something ended up wrong due to MSIZE/PSIZE + * - DMA_TUBE_CFG_ECFG: generic "something's wrong" + * + * @sideeffect Disables tube. May alter tube's registers even when an + * error occurs. + * @see struct dma_tube_config + * @see dma_attach_interrupt() + * @see dma_detach_interrupt() + * @see dma_enable() + */ +extern int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg); + +/* Other tube configuration functions. You can use these if + * dma_tube_cfg() isn't enough, or to adjust parts of an existing tube + * configuration. */ + +/** DMA transfer priority. */ +typedef enum dma_priority { + DMA_PRIORITY_LOW = 0, /**< Low priority */ + DMA_PRIORITY_MEDIUM = 1, /**< Medium priority */ + DMA_PRIORITY_HIGH = 2, /**< High priority */ + DMA_PRIORITY_VERY_HIGH = 3, /**< Very high priority */ +} dma_priority; + +/** + * @brief Set the priority of a DMA transfer. + * + * You may not call this function while the tube is enabled. + * + * @param dev DMA device + * @param tube DMA tube + * @param priority priority to set. + */ +extern void dma_set_priority(dma_dev *dev, dma_tube tube, + dma_priority priority); + +/** + * @brief Set the number of data transfers on a DMA tube. + * + * You may not call this function while the tube is enabled. + * + * @param dev DMA device + * @param tube Tube through which the transfer will occur. + * @param num_transfers Number of DMA transactions to set. + */ +extern void dma_set_num_transfers(dma_dev *dev, dma_tube tube, + uint16 num_transfers); + +/** + * @brief Set the base memory address where data will be read from or + * written to. + * + * You must not call this function while the tube is enabled. + * + * If the DMA memory size is 16 bits, the address is automatically + * aligned to a half-word. If the DMA memory size is 32 bits, the + * address is aligned to a word. + * + * @param dev DMA Device + * @param tube Tube whose base memory address to set. + * @param address Memory base address to use. + */ +extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address); + +/** + * @brief Set the base peripheral address where data will be read from + * or written to. + * + * You must not call this function while the channel is enabled. + * + * If the DMA peripheral size is 16 bits, the address is automatically + * aligned to a half-word. If the DMA peripheral size is 32 bits, the + * address is aligned to a word. + * + * @param dev DMA Device + * @param tube Tube whose peripheral data register base address to set. + * @param addr Peripheral memory base address to use. + */ +extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address); + +/* Interrupt handling */ + +/** + * @brief Attach an interrupt to a DMA transfer. + * + * Interrupts are enabled using series-specific mode flags in + * dma_tube_cfg(). + * + * @param dev DMA device + * @param tube Tube to attach handler to + * @param handler Interrupt handler to call when tube interrupt fires. + * @see dma_tube_cfg() + * @see dma_get_irq_cause() + * @see dma_detach_interrupt() + */ +extern void dma_attach_interrupt(dma_dev *dev, dma_tube tube, + void (*handler)(void)); + + +/** + * @brief Detach a DMA transfer interrupt handler. + * + * After calling this function, the given tube's interrupts will be + * disabled. + * + * @param dev DMA device + * @param tube Tube whose handler to detach + * @sideeffect Clears the tube's interrupt enable bits. + * @see dma_attach_interrupt() + */ +extern void dma_detach_interrupt(dma_dev *dev, dma_tube tube); + +/* Tube enable/disable */ + +/** + * @brief Enable a DMA tube. + * + * If the tube has been properly configured, calling this function + * allows it to start serving DMA requests. + * + * @param dev DMA device + * @param tube Tube to enable + * @see dma_tube_cfg() + */ +extern void dma_enable(dma_dev *dev, dma_tube tube); + +/** + * @brief Disable a DMA channel. + * + * Calling this function makes the tube stop serving DMA requests. + * + * @param dev DMA device + * @param tube Tube to disable + */ +extern void dma_disable(dma_dev *dev, dma_tube tube); + +/** + * @brief Check if a DMA tube is enabled. + * @param dev DMA device. + * @param tube Tube to check. + * @return 0 if the tube is disabled, >0 if it is enabled. + */ +static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube); + +/* Other conveniences */ + +/** + * @brief Obtain a pointer to an individual DMA tube's registers. + * + * Examples: + * + * - On STM32F1, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1. + * + * @param dev DMA device. + * @param tube DMA tube whose register map to obtain. + * @return (Series-specific) tube register map. + */ +static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube); + +/** + * Encodes the reason why a DMA interrupt was called. + * @see dma_get_irq_cause() + */ +typedef enum dma_irq_cause { + DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */ + DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */ + DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */ + DMA_TRANSFER_DME_ERROR, /**< + * @brief Direct mode error occurred during + * transfer. */ + DMA_TRANSFER_FIFO_ERROR, /**< FIFO error occurred during transfer. */ +} dma_irq_cause; + +/** + * @brief Discover the reason why a DMA interrupt was called. + * + * You may only call this function within an attached interrupt + * handler for the given channel. + * + * This function resets the internal DMA register state which encodes + * the cause of the interrupt; consequently, it can only be called + * once per interrupt handler invocation. + * + * @param dev DMA device + * @param tube Tube whose interrupt is being handled. + * @return Reason why the interrupt fired. + * @sideeffect Clears flags in dev's interrupt status registers. + * @see dma_attach_interrupt() + * @see dma_irq_cause + */ +extern dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube); + +/** + * @brief Get the ISR status bits for a DMA channel. + * + * The bits are returned right-aligned, in the order they appear in + * the corresponding ISR register. + * + * If you're trying to figure out why a DMA interrupt fired, you may + * find dma_get_irq_cause() more convenient. + * + * @param dev DMA device + * @param tube Tube whose ISR bits to return. + * @see dma_get_irq_cause(). + */ +static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube); + +/** + * @brief Clear the ISR status bits for a given DMA tube. + * + * If you're trying to clean up after yourself in a DMA interrupt, you + * may find dma_get_irq_cause() more convenient. + * + * @param dev DMA device + * @param tube Tube whose ISR bits to clear. + * @see dma_get_irq_cause() + */ +static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/dma_common.h b/libmaple/include/libmaple/dma_common.h new file mode 100644 index 0000000..67475f7 --- /dev/null +++ b/libmaple/include/libmaple/dma_common.h @@ -0,0 +1,114 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/dma_common.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief Common DMA sub-header for <series/dma.h> and <libmaple/dma.h>. + * + * WARNING: CONTENTS UNSTABLE + * + * The existence of this file is an implementation detail. Its + * contents are not stable, so never include it directly. If you need + * something from here, #include <libmaple/dma.h> instead. + */ + +/* + * There's a fair amount of common DMA functionality needed by each + * <series/dma.h> and <libmaple/dma.h>. This header exists in order + * to provide it to both, avoiding some hacks and circular + * dependencies. + */ + +#ifndef _LIBMAPLE_DMA_COMMON_H_ +#define _LIBMAPLE_DMA_COMMON_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/nvic.h> +#include <libmaple/rcc.h> + +/* + * Devices + */ + +struct dma_reg_map; + +/* Encapsulates state related to user interrupt handlers. You + * shouldn't touch these directly; use dma_attach_interrupt() and + * dma_detach_interupt() instead. */ +typedef struct dma_handler_config { + void (*handler)(void); /* User handler */ + nvic_irq_num irq_line; /* IRQ line for interrupt */ +} dma_handler_config; + +/** DMA device type */ +typedef struct dma_dev { + struct dma_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< Clock ID */ + struct dma_handler_config handlers[]; /**< For internal use */ +} dma_dev; + +/** + * @brief DMA channels + * + * Notes: + * - This is also the dma_tube type for STM32F1. + * - Channel 0 is not available on all STM32 series. + * + * @see dma_tube + */ +typedef enum dma_channel { + DMA_CH0 = 0, /**< Channel 0 */ + DMA_CH1 = 1, /**< Channel 1 */ + DMA_CH2 = 2, /**< Channel 2 */ + DMA_CH3 = 3, /**< Channel 3 */ + DMA_CH4 = 4, /**< Channel 4 */ + DMA_CH5 = 5, /**< Channel 5 */ + DMA_CH6 = 6, /**< Channel 6 */ + DMA_CH7 = 7, /**< Channel 7 */ +} dma_channel; + +/** + * @brief Source and destination transfer sizes. + * Use these when initializing a struct dma_tube_config. + * @see struct dma_tube_config + * @see dma_tube_cfg + */ +typedef enum dma_xfer_size { + DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ + DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ + DMA_SIZE_32BITS = 2, /**< 32-bit transfers */ +} dma_xfer_size; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/exti.h b/libmaple/include/libmaple/exti.h new file mode 100644 index 0000000..3800b4a --- /dev/null +++ b/libmaple/include/libmaple/exti.h @@ -0,0 +1,138 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/exti.h + * @brief External interrupt control + */ + +/* See notes/exti.txt for more info */ + +#ifndef _LIBMAPLE_EXTI_H_ +#define _LIBMAPLE_EXTI_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <series/exti.h> /* provides EXTI_BASE */ +#include <libmaple/libmaple_types.h> + +/* + * Register map and base pointer. + */ + +/** EXTI register map type */ +typedef struct exti_reg_map { + __io uint32 IMR; /**< Interrupt mask register */ + __io uint32 EMR; /**< Event mask register */ + __io uint32 RTSR; /**< Rising trigger selection register */ + __io uint32 FTSR; /**< Falling trigger selection register */ + __io uint32 SWIER; /**< Software interrupt event register */ + __io uint32 PR; /**< Pending register */ +} exti_reg_map; + +/* + * Types: exti_num, exti_cfg, exti_trigger_mode. + * + * A combination of these three specifies an external interrupt + * configuration (see exti_attach_interrupt()). + */ + +/** EXTI line. */ +typedef enum exti_num { + EXTI0, /**< EXTI line 0 */ + EXTI1, /**< EXTI line 1 */ + EXTI2, /**< EXTI line 2 */ + EXTI3, /**< EXTI line 3 */ + EXTI4, /**< EXTI line 4 */ + EXTI5, /**< EXTI line 5 */ + EXTI6, /**< EXTI line 6 */ + EXTI7, /**< EXTI line 7 */ + EXTI8, /**< EXTI line 8 */ + EXTI9, /**< EXTI line 9 */ + EXTI10, /**< EXTI line 10 */ + EXTI11, /**< EXTI line 11 */ + EXTI12, /**< EXTI line 12 */ + EXTI13, /**< EXTI line 13 */ + EXTI14, /**< EXTI line 14 */ + EXTI15, /**< EXTI line 15 */ +} exti_num; + +/** + * @brief EXTI port configuration + * + * These specify which GPIO port an external interrupt line should be + * connected to. + */ +typedef enum exti_cfg { + EXTI_PA, /**< Use PAx pin */ + EXTI_PB, /**< Use PBx pin */ + EXTI_PC, /**< Use PCx pin */ + EXTI_PD, /**< Use PDx pin */ + EXTI_PE, /**< Use PEx pin */ + EXTI_PF, /**< Use PFx pin */ + EXTI_PG, /**< Use PGx pin */ + EXTI_PH, /**< Use PHx pin */ + EXTI_PI, /**< Use PIx pin */ +} exti_cfg; + +/** External interrupt trigger mode */ +typedef enum exti_trigger_mode { + EXTI_RISING, /**< Trigger on the rising edge */ + EXTI_FALLING, /**< Trigger on the falling edge */ + EXTI_RISING_FALLING /**< Trigger on both the rising and falling edges */ +} exti_trigger_mode; + +/* + * Routines + */ + +void exti_attach_interrupt(exti_num num, + exti_cfg port, + voidFuncPtr handler, + exti_trigger_mode mode); +void exti_detach_interrupt(exti_num num); + +/** + * @brief Set the GPIO port for an EXTI line. + * + * This is a low-level routine that most users will not + * need. exti_attach_interrupt() handles calling this function + * appropriately. + * + * @param num EXTI line + * @param port EXTI configuration for GPIO port to connect to num. + * @see exti_num + * @see exti_cfg + */ +extern void exti_select(exti_num num, exti_cfg port); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/flash.h b/libmaple/include/libmaple/flash.h new file mode 100644 index 0000000..943e466 --- /dev/null +++ b/libmaple/include/libmaple/flash.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/flash.h + * @brief Flash support. + */ + +#ifndef _LIBMAPLE_FLASH_H_ +#define _LIBMAPLE_FLASH_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +#define FLASH_WAIT_STATE_0 0x0 +#define FLASH_WAIT_STATE_1 0x1 +#define FLASH_WAIT_STATE_2 0x2 +#define FLASH_WAIT_STATE_3 0x3 +#define FLASH_WAIT_STATE_4 0x4 +#define FLASH_WAIT_STATE_5 0x5 +#define FLASH_WAIT_STATE_6 0x6 +#define FLASH_WAIT_STATE_7 0x7 + +/* The series header must define: + * + * - FLASH_SAFE_WAIT_STATES, the smallest number of wait states that + * it is safe to use when SYSCLK is at its fastest documented rate + * and the MCU is powered at 3.3V (i.e. this doesn't consider + * overclocking or low voltage operation). + * + * - The following bit flags, for flash_enable_features(): + * + * -- FLASH_PREFETCH: prefetcher + * -- FLASH_ICACHE: instruction cache + * -- FLASH_DCACHE: data cache + * + * See that function's Doxygen for more restrictions. + */ +#include <series/flash.h> + +#ifdef __DOXYGEN__ +/** Flash register map base pointer. */ +#define FLASH_BASE +#endif + +/* + * Flash routines + */ + +void flash_set_latency(uint32 wait_states); + +/** + * @brief Enable Flash memory features + * + * If the target MCU doesn't provide a feature (e.g. instruction and + * data caches on the STM32F1), the flag will be ignored. This allows + * using these flags unconditionally, with the desired effect taking + * place on targets that support them. + * + * @param feature_flags Bitwise OR of the following: + * FLASH_PREFETCH (turns on prefetcher), + * FLASH_ICACHE (turns on instruction cache), + * FLASH_DCACHE (turns on data cache). + */ +static inline void flash_enable_features(uint32 feature_flags) { + FLASH_BASE->ACR |= feature_flags; +} + +/** + * @brief Deprecated. Use flash_enable_features(FLASH_PREFETCH) instead. + */ +static inline void flash_enable_prefetch(void) { + flash_enable_features(FLASH_PREFETCH); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/fsmc.h b/libmaple/include/libmaple/fsmc.h new file mode 100644 index 0000000..6225fee --- /dev/null +++ b/libmaple/include/libmaple/fsmc.h @@ -0,0 +1,340 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Bryan Newbold. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/fsmc.h + * @brief Flexible static memory controller support. + */ + +/* + * See ../notes/fsmc.txt for more info + */ + +#ifndef _LIBMAPLE_FSMC_H_ +#define _LIBMAPLE_FSMC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/stm32.h> + +#if !STM32_HAVE_FSMC +#error "FSMC is unavailable on your MCU" +#endif + +/* + * Register maps and devices + */ + +/** FSMC register map type */ +typedef struct fsmc_reg_map { + __io uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ + __io uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ + __io uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ + __io uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ + __io uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ + __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ + __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ + __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ + const uint8 RESERVED1[64]; /**< Reserved */ + __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ + __io uint32 SR2; /**< FIFO status and interrupt register 2 */ + __io uint32 PMEM2; /**< Common memory space timing register 2 */ + __io uint32 PATT2; /**< Attribute memory space timing register 2 */ + const uint8 RESERVED2[4]; /**< Reserved */ + __io uint32 ECCR2; /**< ECC result register 2 */ + const uint8 RESERVED3[2]; + __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ + __io uint32 SR3; /**< FIFO status and interrupt register 3 */ + __io uint32 PMEM3; /**< Common memory space timing register 3 */ + __io uint32 PATT3; /**< Attribute memory space timing register 3 */ + const uint32 RESERVED4; /**< Reserved */ + __io uint32 ECCR3; /**< ECC result register 3 */ + const uint8 RESERVED5[8]; /**< Reserved */ + __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ + __io uint32 SR4; /**< FIFO status and interrupt register 4 */ + __io uint32 PMEM4; /**< Common memory space timing register 4 */ + __io uint32 PATT4; /**< Attribute memory space timing register 4 */ + __io uint32 PIO4; /**< I/O space timing register 4 */ + const uint8 RESERVED6[80]; /**< Reserved */ + __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ + const uint32 RESERVED7; /**< Reserved */ + __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ + const uint32 RESERVED8; /**< Reserved */ + __io uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ + const uint32 RESERVED9; /**< Reserved */ + __io uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ +} __attribute__((packed)) fsmc_reg_map; + +#define __FSMCB 0xA0000000 + +/** FSMC register map base pointer */ +#define FSMC_BASE ((struct fsmc_reg_map*)__FSMCB) + +/** FSMC NOR/PSRAM register map type */ +typedef struct fsmc_nor_psram_reg_map { + __io uint32 BCR; /**< Chip-select control register */ + __io uint32 BTR; /**< Chip-select timing register */ + const uint8 RESERVED[252]; /**< Reserved */ + __io uint32 BWTR; /**< Write timing register */ +} fsmc_nor_psram_reg_map; + +/** FSMC NOR/PSRAM base pointer 1 */ +#define FSMC_NOR_PSRAM1_BASE ((struct fsmc_nor_psram_reg_map*)__FSMCB) + +/** FSMC NOR/PSRAM base pointer 2 */ +#define FSMC_NOR_PSRAM2_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x8)) + +/** FSMC NOR/PSRAM base pointer 3 */ +#define FSMC_NOR_PSRAM3_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x10)) + +/** FSMC NOR/PSRAM base pointer 4 */ +#define FSMC_NOR_PSRAM4_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x18)) + +/* + * Register bit definitions + */ + +/* NOR/PSRAM chip-select control registers */ + +#define FSMC_BCR_CBURSTRW_BIT 19 +#define FSMC_BCR_ASYNCWAIT_BIT 15 +#define FSMC_BCR_EXTMOD_BIT 14 +#define FSMC_BCR_WAITEN_BIT 13 +#define FSMC_BCR_WREN_BIT 12 +#define FSMC_BCR_WAITCFG_BIT 11 +#define FSMC_BCR_WRAPMOD_BIT 10 +#define FSMC_BCR_WAITPOL_BIT 9 +#define FSMC_BCR_BURSTEN_BIT 8 +#define FSMC_BCR_FACCEN_BIT 6 +#define FSMC_BCR_MUXEN_BIT 1 +#define FSMC_BCR_MBKEN_BIT 0 + +#define FSMC_BCR_CBURSTRW (1U << FSMC_BCR_CBURSTRW_BIT) +#define FSMC_BCR_ASYNCWAIT (1U << FSMC_BCR_ASYNCWAIT_BIT) +#define FSMC_BCR_EXTMOD (1U << FSMC_BCR_EXTMOD_BIT) +#define FSMC_BCR_WAITEN (1U << FSMC_BCR_WAITEN_BIT) +#define FSMC_BCR_WREN (1U << FSMC_BCR_WREN_BIT) +#define FSMC_BCR_WAITCFG (1U << FSMC_BCR_WAITCFG_BIT) +#define FSMC_BCR_WRAPMOD (1U << FSMC_BCR_WRAPMOD_BIT) +#define FSMC_BCR_WAITPOL (1U << FSMC_BCR_WAITPOL_BIT) +#define FSMC_BCR_BURSTEN (1U << FSMC_BCR_BURSTEN_BIT) +#define FSMC_BCR_FACCEN (1U << FSMC_BCR_FACCEN_BIT) +#define FSMC_BCR_MWID (0x3 << 4) +#define FSMC_BCR_MWID_8BITS (0x0 << 4) +#define FSMC_BCR_MWID_16BITS (0x1 << 4) +#define FSMC_BCR_MTYP (0x3 << 2) +#define FSMC_BCR_MTYP_SRAM (0x0 << 2) +#define FSMC_BCR_MTYP_PSRAM (0x1 << 2) +#define FSMC_BCR_MTYP_NOR_FLASH (0x2 << 2) +#define FSMC_BCR_MUXEN (1U << FSMC_BCR_MUXEN_BIT) +#define FSMC_BCR_MBKEN (1U << FSMC_BCR_MBKEN_BIT) + +/* SRAM/NOR-Flash chip-select timing registers */ + +#define FSMC_BTR_ACCMOD (0x3 << 28) +#define FSMC_BTR_ACCMOD_A (0x0 << 28) +#define FSMC_BTR_ACCMOD_B (0x1 << 28) +#define FSMC_BTR_ACCMOD_C (0x2 << 28) +#define FSMC_BTR_ACCMOD_D (0x3 << 28) +#define FSMC_BTR_DATLAT (0xF << 24) +#define FSMC_BTR_CLKDIV (0xF << 20) +#define FSMC_BTR_BUSTURN (0xF << 16) +#define FSMC_BTR_DATAST (0xFF << 8) +#define FSMC_BTR_ADDHLD (0xF << 4) +#define FSMC_BTR_ADDSET 0xF + +/* SRAM/NOR-Flash write timing registers */ + +#define FSMC_BWTR_ACCMOD (0x3 << 28) +#define FSMC_BWTR_ACCMOD_A (0x0 << 28) +#define FSMC_BWTR_ACCMOD_B (0x1 << 28) +#define FSMC_BWTR_ACCMOD_C (0x2 << 28) +#define FSMC_BWTR_ACCMOD_D (0x3 << 28) +#define FSMC_BWTR_DATLAT (0xF << 24) +#define FSMC_BWTR_CLKDIV (0xF << 20) +#define FSMC_BWTR_DATAST (0xFF << 8) +#define FSMC_BWTR_ADDHLD (0xF << 4) +#define FSMC_BWTR_ADDSET 0xF + +/* NAND Flash/PC Card controller registers */ + +#define FSMC_PCR_ECCEN_BIT 6 +#define FSMC_PCR_PTYP_BIT 3 +#define FSMC_PCR_PBKEN_BIT 2 +#define FSMC_PCR_PWAITEN_BIT 1 + +#define FSMC_PCR_ECCPS (0x7 << 17) +#define FSMC_PCR_ECCPS_256B (0x0 << 17) +#define FSMC_PCR_ECCPS_512B (0x1 << 17) +#define FSMC_PCR_ECCPS_1024B (0x2 << 17) +#define FSMC_PCR_ECCPS_2048B (0x3 << 17) +#define FSMC_PCR_ECCPS_4096B (0x4 << 17) +#define FSMC_PCR_ECCPS_8192B (0x5 << 17) +#define FSMC_PCR_TAR (0xF << 13) +#define FSMC_PCR_TCLR (0xF << 9) +#define FSMC_PCR_ECCEN (1U << FSMC_PCR_ECCEN_BIT) +#define FSMC_PCR_PWID (0x3 << 4) +#define FSMC_PCR_PWID_8BITS (0x0 << 4) +#define FSMC_PCR_PWID_16BITS (0x1 << 4) +#define FSMC_PCR_PTYP (1U << FSMC_PCR_PTYP_BIT) +#define FSMC_PCR_PTYP_PC_CF_PCMCIA (0x0 << FSMC_PCR_PTYP_BIT) +#define FSMC_PCR_PTYP_NAND (0x1 << FSMC_PCR_PTYP_BIT) +#define FSMC_PCR_PBKEN (1U << FSMC_PCR_PBKEN_BIT) +#define FSMC_PCR_PWAITEN (1U << FSMC_PCR_PWAITEN_BIT) + +/* FIFO status and interrupt registers */ + +#define FSMC_SR_FEMPT_BIT 6 +#define FSMC_SR_IFEN_BIT 5 +#define FSMC_SR_ILEN_BIT 4 +#define FSMC_SR_IREN_BIT 3 +#define FSMC_SR_IFS_BIT 2 +#define FSMC_SR_ILS_BIT 1 +#define FSMC_SR_IRS_BIT 0 + +#define FSMC_SR_FEMPT (1U << FSMC_SR_FEMPT_BIT) +#define FSMC_SR_IFEN (1U << FSMC_SR_IFEN_BIT) +#define FSMC_SR_ILEN (1U << FSMC_SR_ILEN_BIT) +#define FSMC_SR_IREN (1U << FSMC_SR_IREN_BIT) +#define FSMC_SR_IFS (1U << FSMC_SR_IFS_BIT) +#define FSMC_SR_ILS (1U << FSMC_SR_ILS_BIT) +#define FSMC_SR_IRS (1U << FSMC_SR_IRS_BIT) + +/* Common memory space timing registers */ + +#define FSMC_PMEM_MEMHIZ (0xFF << 24) +#define FSMC_PMEM_MEMHOLD (0xFF << 16) +#define FSMC_PMEM_MEMWAIT (0xFF << 8) +#define FSMC_PMEM_MEMSET 0xFF + +/* Attribute memory space timing registers */ + +#define FSMC_PATT_ATTHIZ (0xFF << 24) +#define FSMC_PATT_ATTHOLD (0xFF << 16) +#define FSMC_PATT_ATTWAIT (0xFF << 8) +#define FSMC_PATT_ATTSET 0xFF + +/* I/O space timing register 4 */ + +#define FSMC_PIO_IOHIZ (0xFF << 24) +#define FSMC_PIO_IOHOLD (0xFF << 16) +#define FSMC_PIO_IOWAIT (0xFF << 8) +#define FSMC_PIO_IOSET 0xFF + +/* + * Memory bank boundary addresses + */ + +/** + * @brief Void pointer to base address of FSMC memory bank 1 (NOR/PSRAM). + * + * This bank is split into 4 regions. Each region supports interfacing + * with 1 NOR Flash, SRAM, or PSRAM chip. The base addresses of these + * regions are FSMC_NOR_PSRAM_REGIONx, for x = 1, 2, 3, 4. + */ +#define FSMC_BANK1 ((void*)0x60000000) + +/** + * @brief Void pointer to base address of FSMC memory bank 1, region 1 + * (NOR/PSRAM). + */ +#define FSMC_NOR_PSRAM_REGION1 FSMC_BANK1 + +/** + * @brief Void pointer to base address of FSMC memory bank 1, region 2 + * (NOR/PSRAM). + */ +#define FSMC_NOR_PSRAM_REGION2 ((void*)0x64000000) + +/** + * @brief Void pointer to base address of FSMC memory bank 1, region 3 + * (NOR/PSRAM). + */ +#define FSMC_NOR_PSRAM_REGION3 ((void*)0x68000000) + +/** + * @brief Void pointer to base address of FSMC memory bank 1, region 4 + * (NOR/PSRAM). + */ +#define FSMC_NOR_PSRAM_REGION4 ((void*)0x6C000000) + +/** Void pointer to base address of FSMC memory bank 2 (NAND Flash). */ +#define FSMC_BANK2 ((void*)0x70000000) + +/** Void pointer to base address of FSMC memory bank 3 (NAND Flash). */ +#define FSMC_BANK3 ((void*)0x80000000) + +/** + * @brief Void pointer to base address of FSMC memory bank 4 (PC card + * devices). + */ +#define FSMC_BANK4 ((void*)0x90000000) + +/* + * SRAM/NOR Flash routines + */ + +/** + * @brief Configure FSMC GPIOs for use with SRAM. + */ +void fsmc_sram_init_gpios(void); + +/** + * Set the DATAST bits in the given NOR/PSRAM register map's + * chip-select timing register (FSMC_BTR). + * + * @param regs NOR Flash/PSRAM register map whose chip-select timing + * register to set. + * @param datast Value to use for DATAST bits. + */ +static inline void fsmc_nor_psram_set_datast(fsmc_nor_psram_reg_map *regs, + uint8 datast) { + regs->BTR &= ~FSMC_BTR_DATAST; + regs->BTR |= datast << 8; +} + +/** + * Set the ADDHLD bits in the given NOR/PSRAM register map's chip + * select timing register (FSMC_BTRx). + * + * @param regs NOR Flash/PSRAM register map whose chip-select timing + * register to set. + * @param addset Value to use for ADDSET bits. + */ +static inline void fsmc_nor_psram_set_addset(fsmc_nor_psram_reg_map *regs, + uint8 addset) { + regs->BTR &= ~FSMC_BTR_ADDSET; + regs->BTR |= addset & 0xF; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/libmaple/include/libmaple/gpio.h b/libmaple/include/libmaple/gpio.h new file mode 100644 index 0000000..0cc3746 --- /dev/null +++ b/libmaple/include/libmaple/gpio.h @@ -0,0 +1,121 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +/** + * @file libmaple/include/libmaple/gpio.h + * @brief General Purpose I/O (GPIO) interace. + */ + +#ifndef _LIBMAPLE_GPIO_H_ +#define _LIBMAPLE_GPIO_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + * Note: Series header must define: + * - enum gpio_pin_mode (TODO think harder about portability here) + */ +#include <series/gpio.h> +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> +#include <libmaple/exti.h> + +/* + * Device type + */ + +/** GPIO device type */ +typedef struct gpio_dev { + gpio_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ + /** + * @brief (Deprecated) External interrupt port. + * Instead of dev->exti_port, use gpio_exti_port(dev). + */ + exti_cfg exti_port; +} gpio_dev; + +/* + * Portable routines + */ + +void gpio_init(gpio_dev *dev); +void gpio_init_all(void); +/* TODO flags argument version? */ +void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); + +/** + * @brief Get a GPIO port's corresponding EXTI port configuration. + * @param dev GPIO port whose exti_cfg to return. + */ +static inline exti_cfg gpio_exti_port(gpio_dev *dev) { + return (exti_cfg)(EXTI_PA + (dev->clk_id - RCC_GPIOA)); +} + +/** + * Set or reset a GPIO pin. + * + * Pin must have previously been configured to output mode. + * + * @param dev GPIO device whose pin to set. + * @param pin Pin on to set or reset + * @param val If true, set the pin. If false, reset the pin. + */ +static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { + val = !val; /* "set" bits are lower than "reset" bits */ + dev->regs->BSRR = (1U << pin) << (16 * val); +} + +/** + * Determine whether or not a GPIO pin is set. + * + * Pin must have previously been configured to input mode. + * + * @param dev GPIO device whose pin to test. + * @param pin Pin on dev to test. + * @return True if the pin is set, false otherwise. + */ +static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { + return dev->regs->IDR & (1U << pin); +} + +/** + * Toggle a pin configured as output push-pull. + * @param dev GPIO device. + * @param pin Pin on dev to toggle. + */ +static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { + dev->regs->ODR = dev->regs->ODR ^ (1U << pin); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/i2c.h b/libmaple/include/libmaple/i2c.h new file mode 100644 index 0000000..ff1c313 --- /dev/null +++ b/libmaple/include/libmaple/i2c.h @@ -0,0 +1,413 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/i2c.h + * @brief Inter-Integrated Circuit (I2C) peripheral support + * + * Currently master-only. Usage notes: + * + * - Enable an I2C device with i2c_master_enable(). + * - Initialize an array of struct i2c_msg to suit the bus + * transactions (reads/writes) you wish to perform. + * - Call i2c_master_xfer() to do the work. + */ + +#ifndef _LIBMAPLE_I2C_H_ +#define _LIBMAPLE_I2C_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Series header must provide: + * + * - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in + * MHz. (This is for internal use only). + * + * - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1. + * This is for internal use only. It's a hack to work around a + * silicon bug related to I2C IRQ pre-emption on some targets. If 1, + * the series header must also declare and implement a routine with + * this signature (it may also be provided as a macro): + * + * void _i2c_irq_priority_fixup(i2c_dev*) + * + * This will be called by i2c_enable_irq() before actually enabling + * I2C interrupts. + * + * - Reg. map base pointers, device pointer declarations. + */ + +#include <series/i2c.h> +#include <libmaple/i2c_common.h> + +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> +#include <libmaple/nvic.h> +#include <libmaple/gpio.h> + +/** I2C register map type */ +typedef struct i2c_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 OAR1; /**< Own address register 1 */ + __io uint32 OAR2; /**< Own address register 2 */ + __io uint32 DR; /**< Data register */ + __io uint32 SR1; /**< Status register 1 */ + __io uint32 SR2; /**< Status register 2 */ + __io uint32 CCR; /**< Clock control register */ + __io uint32 TRISE; /**< TRISE (rise time) register */ +} i2c_reg_map; + +/** + * @brief I2C message type + */ +typedef struct i2c_msg { + uint16 addr; /**< Address */ + +#define I2C_MSG_READ 0x1 +#define I2C_MSG_10BIT_ADDR 0x2 + /** + * Bitwise OR of: + * - I2C_MSG_READ (write is default) + * - I2C_MSG_10BIT_ADDR (7-bit is default) */ + uint16 flags; + + uint16 length; /**< Message length */ + uint16 xferred; /**< Messages transferred */ + uint8 *data; /**< Data */ +} i2c_msg; + +/* + * Register bit definitions + */ + +/* Control register 1 */ + +#define I2C_CR1_SWRST (1U << 15) // Software reset +#define I2C_CR1_ALERT (1U << 13) // SMBus alert +#define I2C_CR1_PEC (1U << 12) // Packet error checking +#define I2C_CR1_POS (1U << 11) // Acknowledge/PEC position +#define I2C_CR1_ACK (1U << 10) // Acknowledge enable +#define I2C_CR1_STOP (1U << 9) // Stop generation +#define I2C_CR1_START (1U << 8) // Start generation +#define I2C_CR1_NOSTRETCH (1U << 7) // Clock stretching disable +#define I2C_CR1_ENGC (1U << 6) // General call enable +#define I2C_CR1_ENPEC (1U << 5) // PEC enable +#define I2C_CR1_ENARP (1U << 4) // ARP enable +#define I2C_CR1_SMBTYPE (1U << 3) // SMBus type +#define I2C_CR1_SMBTYPE_DEVICE (0U << 3) // SMBus type: device +#define I2C_CR1_SMBTYPE_HOST (1U << 3) // SMBus type: host +#define I2C_CR1_SMBUS (1U << 1) // SMBus mode +#define I2C_CR1_SMBUS_I2C (0U << 1) // SMBus mode: I2C +#define I2C_CR1_SMBUS_SMBUS (1U << 1) // SMBus mode: SMBus +#define I2C_CR1_PE (1U << 0) // Peripheral Enable + +/* Control register 2 */ + +#define I2C_CR2_LAST (1U << 12) // DMA last transfer +#define I2C_CR2_DMAEN (1U << 11) // DMA requests enable +#define I2C_CR2_ITBUFEN (1U << 10) // Buffer interrupt enable +#define I2C_CR2_ITEVTEN (1U << 9) // Event interupt enable +#define I2C_CR2_ITERREN (1U << 8) // Error interupt enable +#define I2C_CR2_FREQ 0x3F // Peripheral input frequency + +/* Own address register 1 */ + +#define I2C_OAR1_ADDMODE (1U << 15) // Addressing mode +#define I2C_OAR1_ADDMODE_7_BIT (0U << 15) // Addressing mode: 7-bit +#define I2C_OAR1_ADDMODE_10_BIT (1U << 15) // Addressing mode: 10-bit +#define I2C_OAR1_ADD 0x3FF // Interface address + +/* Own address register 2 */ + +#define I2C_OAR2_ADD2 0xFE // Interface address +#define I2C_OAR2_ENDUAL 1U // Dual addressing mode enable + +/* Status register 1 */ + +#define I2C_SR1_SMBALERT (1U << 15) // SMBus alert +#define I2C_SR1_TIMEOUT (1U << 14) // Timeout or Tlow error +#define I2C_SR1_PECERR (1U << 12) // PEC Error in reception +#define I2C_SR1_OVR (1U << 11) // Overrun/underrun +#define I2C_SR1_AF (1U << 10) // Acknowledge failure +#define I2C_SR1_ARLO (1U << 9) // Arbitration lost +#define I2C_SR1_BERR (1U << 8) // Bus error +#define I2C_SR1_TXE (1U << 7) // Data register empty +#define I2C_SR1_RXNE (1U << 6) // Data register not empty +#define I2C_SR1_STOPF (1U << 4) // Stop detection +#define I2C_SR1_ADD10 (1U << 3) // 10-bit header sent +#define I2C_SR1_BTF (1U << 2) // Byte transfer finished +#define I2C_SR1_ADDR (1U << 1) // Address sent/matched +#define I2C_SR1_SB (1U << 0) // Start bit + +/* Status register 2 */ + +#define I2C_SR2_PEC 0xFF00 // Packet error checking register +#define I2C_SR2_DUALF (1U << 7) // Dual flag +#define I2C_SR2_SMBHOST (1U << 6) // SMBus host header +#define I2C_SR2_SMBDEFAULT (1U << 5) // SMBus device default address +#define I2C_SR2_GENCALL (1U << 4) // General call address +#define I2C_SR2_TRA (1U << 2) // Transmitter/receiver +#define I2C_SR2_BUSY (1U << 1) // Bus busy +#define I2C_SR2_MSL (1U << 0) // Master/slave + +/* Clock control register */ + +#define I2C_CCR_FS (1U << 15) // Fast mode selection +#define I2C_CCR_DUTY (1U << 14) // Fast mode duty cycle +#define I2C_CCR_DUTY_2_1 (0U << 14) // Fast mode duty: 2/1 +#define I2C_CCR_DUTY_16_9 (1U << 14) // Fast mode duty: 16/9 +#define I2C_CCR_CCR 0xFFF // Clock control bits + +/* + * Convenience routines + */ + +/* Main I2C API */ + +/* I2C enable options */ +#define I2C_FAST_MODE 0x1 // 400 khz +#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio +/* Flag 0x4 is reserved; DO NOT USE. */ +#define I2C_BUS_RESET 0x8 // Perform a bus reset +void i2c_master_enable(i2c_dev *dev, uint32 flags); + +#define I2C_ERROR_PROTOCOL (-1) +#define I2C_ERROR_TIMEOUT (-2) +int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout); + +void i2c_bus_reset(const i2c_dev *dev); + +/** + * @brief Disable an I2C device + * + * This function disables the corresponding peripheral and marks dev's + * state as I2C_STATE_DISABLED. + * + * @param dev Device to disable. + */ +static inline void i2c_disable(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_PE; + dev->state = I2C_STATE_DISABLED; +} + +/* Start/stop conditions */ + +/** + * @brief Generate a start condition on the bus. + * @param dev I2C device + */ +static inline void i2c_start_condition(i2c_dev *dev) { + uint32 cr1; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } + dev->regs->CR1 |= I2C_CR1_START; +} + +/** + * @brief Generate a stop condition on the bus + * @param dev I2C device + */ +static inline void i2c_stop_condition(i2c_dev *dev) { + uint32 cr1; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } + dev->regs->CR1 |= I2C_CR1_STOP; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } + +} + +/* IRQ enable/disable */ + +#ifndef _I2C_HAVE_IRQ_FIXUP +/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined, + * but we need it either way. */ +#define _i2c_irq_priority_fixup(dev) ((void)0) +#endif + +#define I2C_IRQ_ERROR I2C_CR2_ITERREN +#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN +#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN +/** + * @brief Enable one or more I2C interrupts + * @param dev I2C device + * @param irqs Bitwise or of: + * I2C_IRQ_ERROR (error interrupt), + * I2C_IRQ_EVENT (event interrupt), and + * I2C_IRQ_BUFFER (buffer interrupt). + */ +static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) { + _i2c_irq_priority_fixup(dev); + dev->regs->CR2 |= irqs; +} + +/** + * @brief Disable one or more I2C interrupts + * @param dev I2C device + * @param irqs Bitwise or of: + * I2C_IRQ_ERROR (error interrupt), + * I2C_IRQ_EVENT (event interrupt), and + * I2C_IRQ_BUFFER (buffer interrupt). + */ +static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) { + dev->regs->CR2 &= ~irqs; +} + +/* ACK/NACK */ + +/** + * @brief Enable I2C acknowledgment + * @param dev I2C device + */ +static inline void i2c_enable_ack(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_ACK; +} + +/** + * @brief Disable I2C acknowledgment + * @param dev I2C device + */ +static inline void i2c_disable_ack(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_ACK; +} + +/* GPIO control */ + +/** + * @brief Configure device GPIOs. + * + * Configure GPIO bits dev->sda_pin and dev->scl_pin on GPIO device + * dev->gpio_port for use with I2C device dev. + * + * @param dev I2C Device + * @see i2c_release_gpios() + */ +extern void i2c_config_gpios(const i2c_dev *dev); + +/** + * @brief Release GPIOs controlling an I2C bus + * + * Releases the I2C bus controlled by dev as master, and disconnects + * GPIO bits dev->sda_pin and dev->scl_pin on GPIO device + * dev->gpio_port from I2C device dev. + * + * @param dev I2C device + * @see i2c_config_gpios() + */ +extern void i2c_master_release_bus(const i2c_dev *dev); + +/* Miscellaneous low-level routines */ + +void i2c_init(i2c_dev *dev); + +/** + * @brief Turn on an I2C peripheral + * @param dev Device to enable + */ +static inline void i2c_peripheral_enable(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_PE; +} + +/** + * @brief Turn off an I2C peripheral + * @param dev Device to turn off + */ +static inline void i2c_peripheral_disable(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_PE; +} + +/** + * @brief Fill transmit register + * @param dev I2C device + * @param byte Byte to write + */ +static inline void i2c_write(i2c_dev *dev, uint8 byte) { + dev->regs->DR = byte; +} + +/** + * @brief Set input clock frequency, in MHz + * @param dev I2C device + * @param freq Frequency, in MHz. This must be at least 2, and at most + * the APB frequency of dev's bus. (For example, if + * rcc_dev_clk(dev) == RCC_APB1, freq must be at most + * PCLK1, in MHz). There is an additional limit of 46 MHz. + */ +static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { +#define I2C_MAX_FREQ_MHZ 46 + ASSERT(2 <= freq && freq <= _i2c_bus_clk(dev) && freq <= I2C_MAX_FREQ_MHZ); + uint32 cr2 = dev->regs->CR2; + cr2 &= ~I2C_CR2_FREQ; + cr2 |= freq; + dev->regs->CR2 = freq; +#undef I2C_MAX_FREQ_MHZ +} + +/** + * @brief Set I2C clock control register. + * + * See the chip reference manual for the details. + * + * @param dev I2C device + * @param val Value to use for clock control register (in + * Fast/Standard mode) + */ +static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) { + uint32 ccr = dev->regs->CCR; + ccr &= ~I2C_CCR_CCR; + ccr |= val; + dev->regs->CCR = ccr; +} + +/** + * @brief Set SCL rise time + * @param dev I2C device + * @param trise Maximum rise time in fast/standard mode (see chip + * reference manual for the relevant formulas). + */ +static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) { + dev->regs->TRISE = trise; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/i2c_common.h b/libmaple/include/libmaple/i2c_common.h new file mode 100644 index 0000000..5d99530 --- /dev/null +++ b/libmaple/include/libmaple/i2c_common.h @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung (from <libmaple/i2c.h>). + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/i2c_common.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief This file is an implementation detail + * + * WARNING: CONTENTS UNSTABLE + * + * The existence of this file is an implementation detail. Its + * contents are not stable, so never include it directly. If you need + * something from here, #include <libmaple/i2c.h> instead. + */ + +#ifndef _LIBMAPLE_I2C_COMMON_H_ +#define _LIBMAPLE_I2C_COMMON_H_ + +#include <libmaple/libmaple_types.h> +#include <libmaple/nvic.h> +#include <libmaple/rcc.h> + +struct gpio_dev; +struct i2c_reg_map; +struct i2c_msg; + +/** I2C device states */ +typedef enum i2c_state { + I2C_STATE_DISABLED = 0, /**< Disabled */ + I2C_STATE_IDLE = 1, /**< Idle */ + I2C_STATE_XFER_DONE = 2, /**< Done with transfer */ + I2C_STATE_BUSY = 3, /**< Busy */ + I2C_STATE_ERROR = -1 /**< Error occurred */ +} i2c_state; + +/** + * @brief I2C device type. + */ +typedef struct i2c_dev { + struct i2c_reg_map *regs; /**< Register map */ + struct i2c_msg *msg; /**< Messages */ + uint32 error_flags; /**< Error flags, set on I2C error condition */ + volatile uint32 timestamp; /**< For internal use */ + + /** + * @brief Deprecated. Use .scl_port or .sda_port instead. + * If non-null, this will be used as SDA, SCL pins' GPIO port. If + * null, then .sda_port will be used for SDA, and .sda_port for + * SDA. */ + struct gpio_dev *gpio_port; + + /** + * @brief SDA GPIO device (but see .gpio_port). + */ + struct gpio_dev *sda_port; + + /** + * @brief SCL GPIO device (but see .gpio_port). + */ + struct gpio_dev *scl_port; + + uint16 msgs_left; /**< Messages left */ + uint8 sda_pin; /**< SDA bit on gpio_port */ + uint8 scl_pin; /**< SCL bit on gpio_port */ + rcc_clk_id clk_id; /**< RCC clock information */ + nvic_irq_num ev_nvic_line; /**< Event IRQ number */ + nvic_irq_num er_nvic_line; /**< Error IRQ number */ + volatile i2c_state state; /**< Device state */ +} i2c_dev; + +#endif diff --git a/libmaple/include/libmaple/iwdg.h b/libmaple/include/libmaple/iwdg.h new file mode 100644 index 0000000..3a16c55 --- /dev/null +++ b/libmaple/include/libmaple/iwdg.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Michael Hope. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/iwdg.h + * @author Michael Hope, Marti Bolivar <mbolivar@leaflabs.com> + * @brief Independent watchdog support. + * + * To use the independent watchdog, first call iwdg_init() with the + * appropriate prescaler and IWDG counter reload values for your + * application. Afterwards, you must periodically call iwdg_feed() + * before the IWDG counter reaches 0 to reset the counter to its + * reload value. If you do not, the chip will reset. + * + * Once started, the independent watchdog cannot be turned off. + */ + +#ifndef _LIBMAPLE_IWDG_H_ +#define _LIBMAPLE_IWDG_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/* + * Register map + */ + +/** Independent watchdog register map type. */ +typedef struct iwdg_reg_map { + __io uint32 KR; /**< Key register. */ + __io uint32 PR; /**< Prescaler register. */ + __io uint32 RLR; /**< Reload register. */ + __io uint32 SR; /**< Status register */ +} iwdg_reg_map; + +/** Independent watchdog base pointer */ +#define IWDG_BASE ((struct iwdg_reg_map*)0x40003000) + +/* + * Register bit definitions + */ + +/* Key register */ + +#define IWDG_KR_UNLOCK 0x5555 +#define IWDG_KR_FEED 0xAAAA +#define IWDG_KR_START 0xCCCC + +/* Prescaler register */ + +#define IWDG_PR_DIV_4 0x0 +#define IWDG_PR_DIV_8 0x1 +#define IWDG_PR_DIV_16 0x2 +#define IWDG_PR_DIV_32 0x3 +#define IWDG_PR_DIV_64 0x4 +#define IWDG_PR_DIV_128 0x5 +#define IWDG_PR_DIV_256 0x6 + +/* Status register */ + +#define IWDG_SR_RVU_BIT 1 +#define IWDG_SR_PVU_BIT 0 + +#define IWDG_SR_RVU (1U << IWDG_SR_RVU_BIT) +#define IWDG_SR_PVU (1U << IWDG_SR_PVU_BIT) + +/** + * @brief Independent watchdog prescalers. + * + * These divide the 40 kHz IWDG clock. + */ +typedef enum iwdg_prescaler { + IWDG_PRE_4 = IWDG_PR_DIV_4, /**< Divide by 4 */ + IWDG_PRE_8 = IWDG_PR_DIV_8, /**< Divide by 8 */ + IWDG_PRE_16 = IWDG_PR_DIV_16, /**< Divide by 16 */ + IWDG_PRE_32 = IWDG_PR_DIV_32, /**< Divide by 32 */ + IWDG_PRE_64 = IWDG_PR_DIV_64, /**< Divide by 64 */ + IWDG_PRE_128 = IWDG_PR_DIV_128, /**< Divide by 128 */ + IWDG_PRE_256 = IWDG_PR_DIV_256 /**< Divide by 256 */ +} iwdg_prescaler; + +void iwdg_init(iwdg_prescaler prescaler, uint16 reload); +void iwdg_feed(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/libmaple.h b/libmaple/include/libmaple/libmaple.h new file mode 100644 index 0000000..f1a595e --- /dev/null +++ b/libmaple/include/libmaple/libmaple.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/libmaple.h + * @brief General include file for libmaple + */ + +#ifndef _LIBMAPLE_LIBMAPLE_H_ +#define _LIBMAPLE_LIBMAPLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/stm32.h> +#include <libmaple/util.h> +#include <libmaple/delay.h> + +/* + * Where to put usercode, based on space reserved for bootloader. + * + * FIXME this has no business being here + */ +#define USER_ADDR_ROM 0x08005000 +#define USER_ADDR_RAM 0x20000C00 +#define STACK_TOP 0x20000800 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/libmaple_types.h b/libmaple/include/libmaple/libmaple_types.h new file mode 100644 index 0000000..9e1fbb3 --- /dev/null +++ b/libmaple/include/libmaple/libmaple_types.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/libmaple_types.h + * + * @brief libmaple's types, and operations on types. + */ + +#ifndef _LIBMAPLE_LIBMAPLE_TYPES_H_ +#define _LIBMAPLE_LIBMAPLE_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned long long uint64; + +typedef signed char int8; +typedef short int16; +typedef int int32; +typedef long long int64; + +typedef void (*voidFuncPtr)(void); + +#define __io volatile +#define __attr_flash __attribute__((section (".USER_FLASH"))) +#define __packed __attribute__((__packed__)) +#define __deprecated __attribute__((__deprecated__)) +#define __weak __attribute__((weak)) +#define __always_inline inline __attribute__((always_inline)) +#define __unused __attribute__((unused)) + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef offsetof +#define offsetof(type, member) __builtin_offsetof(type, member) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/nvic.h b/libmaple/include/libmaple/nvic.h new file mode 100644 index 0000000..ac102d9 --- /dev/null +++ b/libmaple/include/libmaple/nvic.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/nvic.h + * @brief Nested vectored interrupt controller support. + * + * Basic usage: + * + * @code + * // Initialise the interrupt controller and point to the vector + * // table at the start of flash. + * nvic_init(0x08000000, 0); + * // Bind in a timer interrupt handler + * timer_attach_interrupt(TIMER_CC1_INTERRUPT, handler); + * // Optionally set the priority + * nvic_irq_set_priority(NVIC_TIMER1_CC, 5); + * // All done, enable all interrupts + * nvic_globalirq_enable(); + * @endcode + */ + +#ifndef _LIBMAPLE_NVIC_H_ +#define _LIBMAPLE_NVIC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/util.h> + +/** NVIC register map type. */ +typedef struct nvic_reg_map { + __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */ + /** Reserved */ + uint32 RESERVED0[24]; + + __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ + /** Reserved */ + uint32 RESERVED1[24]; + + __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ + /** Reserved */ + uint32 RESERVED2[24]; + + __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ + /** Reserved */ + uint32 RESERVED3[24]; + + __io uint32 IABR[8]; /**< Interrupt Active bit Registers */ + /** Reserved */ + uint32 RESERVED4[56]; + + __io uint8 IP[240]; /**< Interrupt Priority Registers */ + /** Reserved */ + uint32 RESERVED5[644]; + + __io uint32 STIR; /**< Software Trigger Interrupt Registers */ +} nvic_reg_map; + +/** NVIC register map base pointer. */ +#define NVIC_BASE ((struct nvic_reg_map*)0xE000E100) + +/* + * Note: The series header must define enum nvic_irq_num, which gives + * descriptive names to the interrupts and exceptions from NMI (-14) + * to the largest interrupt available in the series, where the value + * for nonnegative enumerators corresponds to its position in the + * vector table. + * + * It also must define a static inline nvic_irq_disable_all(), which + * writes 0xFFFFFFFF to all ICE registers available in the series. (We + * place the include here to give the series header access to + * NVIC_BASE, in order to let it do so). + */ +#include <series/nvic.h> + +void nvic_init(uint32 address, uint32 offset); +void nvic_set_vector_table(uint32 address, uint32 offset); +void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority); +void nvic_sys_reset(); + +/** + * Enables interrupts and configurable fault handlers (clear PRIMASK). + */ +static inline void nvic_globalirq_enable() { + asm volatile("cpsie i"); +} + +/** + * Disable interrupts and configurable fault handlers (set PRIMASK). + */ +static inline void nvic_globalirq_disable() { + asm volatile("cpsid i"); +} + +/** + * @brief Enable interrupt irq_num + * @param irq_num Interrupt to enable + */ +static inline void nvic_irq_enable(nvic_irq_num irq_num) { + if (irq_num < 0) { + return; + } + NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32); +} + +/** + * @brief Disable interrupt irq_num + * @param irq_num Interrupt to disable + */ +static inline void nvic_irq_disable(nvic_irq_num irq_num) { + if (irq_num < 0) { + return; + } + NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32); +} + +/** + * @brief Quickly disable all interrupts. + * + * Calling this function is significantly faster than calling + * nvic_irq_disable() in a loop. + */ +static inline void nvic_irq_disable_all(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/pwr.h b/libmaple/include/libmaple/pwr.h new file mode 100644 index 0000000..e4b5b0d --- /dev/null +++ b/libmaple/include/libmaple/pwr.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/pwr.h + * @brief Power control (PWR). + */ + +#ifndef _LIBMAPLE_PWR_H_ +#define _LIBMAPLE_PWR_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple.h> +#include <series/pwr.h> + +/** Power interface register map. */ +typedef struct pwr_reg_map { + __io uint32 CR; /**< Control register */ + __io uint32 CSR; /**< Control and status register */ +} pwr_reg_map; + +/** Power peripheral register map base pointer. */ +#define PWR_BASE ((struct pwr_reg_map*)0x40007000) + +/* + * Register bit definitions + */ + +/* Control register */ + +/** Disable backup domain write protection bit */ +#define PWR_CR_DBP_BIT 8 +/** Power voltage detector enable bit */ +#define PWR_CR_PVDE_BIT 4 +/** Clear standby flag bit */ +#define PWR_CR_CSBF_BIT 3 +/** Clear wakeup flag bit */ +#define PWR_CR_CWUF_BIT 2 +/** Power down deepsleep bit */ +#define PWR_CR_PDDS_BIT 1 +/** Low-power deepsleep bit */ +#define PWR_CR_LPDS_BIT 0 + +/** Disable backup domain write protection */ +#define PWR_CR_DBP (1U << PWR_CR_DBP_BIT) +/** Power voltage detector (PVD) level selection */ +#define PWR_CR_PLS (0x7 << 5) +/** Power voltage detector enable */ +#define PWR_CR_PVDE (1U << PWR_CR_PVDE_BIT) +/** Clear standby flag */ +#define PWR_CR_CSBF (1U << PWR_CR_CSBF_BIT) +/** Clear wakeup flag */ +#define PWR_CR_CWUF (1U << PWR_CR_CWUF_BIT) +/** Power down deepsleep */ +#define PWR_CR_PDDS (1U << PWR_CR_PDDS_BIT) +/** Low-power deepsleep */ +#define PWR_CR_LPDS (1U << PWR_CR_LPDS_BIT) + +/* Control and status register */ + +/** Enable wakeup pin bit */ +#define PWR_CSR_EWUP_BIT 8 +/** PVD output bit */ +#define PWR_CSR_PVDO_BIT 2 +/** Standby flag bit */ +#define PWR_CSR_SBF_BIT 1 +/** Wakeup flag bit */ +#define PWR_CSR_WUF_BIT 0 + +/** Enable wakeup pin */ +#define PWR_CSR_EWUP (1U << PWR_CSR_EWUP_BIT) +/** PVD output */ +#define PWR_CSR_PVDO (1U << PWR_CSR_PVDO_BIT) +/** Standby flag */ +#define PWR_CSR_SBF (1U << PWR_CSR_SBF_BIT) +/** Wakeup flag */ +#define PWR_CSR_WUF (1U << PWR_CSR_WUF_BIT) + +/* + * Convenience functions + */ + +void pwr_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/rcc.h b/libmaple/include/libmaple/rcc.h new file mode 100644 index 0000000..ea16803 --- /dev/null +++ b/libmaple/include/libmaple/rcc.h @@ -0,0 +1,175 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/rcc.h + * @brief Reset and Clock Control (RCC) interface. + */ + +#ifndef _LIBMAPLE_RCC_H_ +#define _LIBMAPLE_RCC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/* Put the SYSCLK sources before the series header is included, as it + * might need them. */ +/** + * @brief SYSCLK sources + * @see rcc_switch_sysclk() + */ +typedef enum rcc_sysclk_src { + RCC_CLKSRC_HSI = 0x0, + RCC_CLKSRC_HSE = 0x1, + RCC_CLKSRC_PLL = 0x2, +} rcc_sysclk_src; + +#include <series/rcc.h> + +/* Note: Beyond the usual (registers, etc.), it's up to the series + * header to define the following types: + * + * - enum rcc_clk: Available system and secondary clock sources, + * e.g. RCC_CLK_HSE, RCC_CLK_PLL, RCC_CLK_LSE. + * + * Note that the inclusion of secondary clock sources (like LSI and + * LSE) makes enum rcc_clk different from the SYSCLK sources, which + * are defined in this header as enum rcc_sysclk_src. + * + * IMPORTANT NOTE TO IMPLEMENTORS: If you are adding support for a + * new STM32 series, see the comment near rcc_clk_reg() in + * libmaple/rcc.c for information on how to choose these values so + * that rcc_turn_on_clk() etc. will work on your series. + * + * - enum rcc_clk_id: For each available peripheral. These are widely used + * as unique IDs (TODO extricate from RCC?). Peripherals which are + * common across STM32 series should use the same token for their + * rcc_clk_id in each series header. + * + * - enum rcc_clk_domain: For each clock domain. This is returned by + * rcc_dev_clk(). For instance, each AHB and APB is a clock domain. + * + * - enum rcc_prescaler: And a suitable set of dividers for + * rcc_set_prescaler(). + * + * - enum rcc_pllsrc: For each PLL source. Same source, same token. + * + * - A target-dependent type to be pointed to by the data field in a + * struct rcc_pll_cfg. + */ + +#ifdef __DOXYGEN__ +/** RCC register map base pointer */ +#define RCC_BASE +#endif + +/* Clock prescaler management. */ + +/** + * @brief Set the divider on a peripheral prescaler + * @param prescaler prescaler to set + * @param divider prescaler divider + */ +extern void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); + +/* SYSCLK. */ + +void rcc_switch_sysclk(rcc_sysclk_src sysclk_src); + +/* PLL configuration */ + +/** + * @brief Specifies a configuration for the main PLL. + */ +typedef struct rcc_pll_cfg { + rcc_pllsrc pllsrc; /**< PLL source */ + + /** Series-specific configuration data. */ + void *data; +} rcc_pll_cfg; + +/** + * @brief Configure the main PLL. + * + * You may only call this function while the PLL is disabled. + * + * @param pll_cfg Desired PLL configuration. The contents of this + * struct depend entirely on the target. + */ +extern void rcc_configure_pll(rcc_pll_cfg *pll_cfg); + +/* System and secondary clock sources. */ + +void rcc_turn_on_clk(rcc_clk clock); +void rcc_turn_off_clk(rcc_clk clock); +int rcc_is_clk_on(rcc_clk clock); +int rcc_is_clk_ready(rcc_clk clock); + +/* Peripheral clock lines and clock domains. */ + +/** + * @brief Turn on the clock line on a peripheral + * @param id Clock ID of the peripheral to turn on. + */ +extern void rcc_clk_enable(rcc_clk_id id); + +/** + * @brief Reset a peripheral. + * + * Caution: not all rcc_clk_id values refer to a peripheral which can + * be reset. (Only rcc_clk_ids for peripherals with bits in an RCC + * reset register can be used here.) + * + * @param id Clock ID of the peripheral to reset. + */ +extern void rcc_reset_dev(rcc_clk_id id); + +rcc_clk_domain rcc_dev_clk(rcc_clk_id id); + +/* Clock security system */ + +/** + * @brief Enable the clock security system (CSS). + */ +static inline void rcc_enable_css() { + RCC_BASE->CR |= RCC_CR_CSSON; +} + +/** + * @brief Disable the clock security system (CSS). + */ +static inline void rcc_disable_css() { + RCC_BASE->CR &= ~RCC_CR_CSSON; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/ring_buffer.h b/libmaple/include/libmaple/ring_buffer.h new file mode 100644 index 0000000..e02e6e7 --- /dev/null +++ b/libmaple/include/libmaple/ring_buffer.h @@ -0,0 +1,188 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/ring_buffer.h + * @brief Simple circular buffer + * + * This implementation is not thread-safe. In particular, none of + * these functions is guaranteed re-entrant. + */ + +#ifndef _LIBMAPLE_RING_BUFFER_H_ +#define _LIBMAPLE_RING_BUFFER_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/** + * Ring buffer type. + * + * The buffer is empty when head == tail. + * + * The buffer is full when the head is one byte in front of the tail, + * modulo buffer length. + * + * One byte is left free to distinguish empty from full. */ +typedef struct ring_buffer { + volatile uint8 *buf; /**< Buffer items are stored into */ + uint16 head; /**< Index of the next item to remove */ + uint16 tail; /**< Index where the next item will get inserted */ + uint16 size; /**< Buffer capacity minus one */ +} ring_buffer; + +/** + * Initialise a ring buffer. + * + * @param rb Instance to initialise + * + * @param size Number of items in buf. The ring buffer will always + * leave one element unoccupied, so the maximum number of + * elements it can store will be size - 1. Thus, size + * must be at least 2. + * + * @param buf Buffer to store items into + */ +static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) { + rb->head = 0; + rb->tail = 0; + rb->size = size - 1; + rb->buf = buf; +} + +/** + * @brief Return the number of elements stored in the ring buffer. + * @param rb Buffer whose elements to count. + */ +static inline uint16 rb_full_count(ring_buffer *rb) { + __io ring_buffer *arb = rb; + int32 size = arb->tail - arb->head; + if (arb->tail < arb->head) { + size += arb->size + 1; + } + return (uint16)size; +} + +/** + * @brief Returns true if and only if the ring buffer is full. + * @param rb Buffer to test. + */ +static inline int rb_is_full(ring_buffer *rb) { + return (rb->tail + 1 == rb->head) || + (rb->tail == rb->size && rb->head == 0); +} + +/** + * @brief Returns true if and only if the ring buffer is empty. + * @param rb Buffer to test. + */ +static inline int rb_is_empty(ring_buffer *rb) { + return rb->head == rb->tail; +} + +/** + * Append element onto the end of a ring buffer. + * @param rb Buffer to append onto. + * @param element Value to append. + */ +static inline void rb_insert(ring_buffer *rb, uint8 element) { + rb->buf[rb->tail] = element; + rb->tail = (rb->tail == rb->size) ? 0 : rb->tail + 1; +} + +/** + * @brief Remove and return the first item from a ring buffer. + * @param rb Buffer to remove from, must contain at least one element. + */ +static inline uint8 rb_remove(ring_buffer *rb) { + uint8 ch = rb->buf[rb->head]; + rb->head = (rb->head == rb->size) ? 0 : rb->head + 1; + return ch; +} + +/** + * @brief Attempt to remove the first item from a ring buffer. + * + * If the ring buffer is nonempty, removes and returns its first item. + * If it is empty, does nothing and returns a negative value. + * + * @param rb Buffer to attempt to remove from. + */ +static inline int16 rb_safe_remove(ring_buffer *rb) { + return rb_is_empty(rb) ? -1 : rb_remove(rb); +} + +/** + * @brief Attempt to insert an element into a ring buffer. + * + * @param rb Buffer to insert into. + * @param element Value to insert into rb. + * @sideeffect If rb is not full, appends element onto buffer. + * @return If element was appended, then true; otherwise, false. */ +static inline int rb_safe_insert(ring_buffer *rb, uint8 element) { + if (rb_is_full(rb)) { + return 0; + } + rb_insert(rb, element); + return 1; +} + +/** + * @brief Append an item onto the end of a non-full ring buffer. + * + * If the buffer is full, removes its first item, then inserts the new + * element at the end. + * + * @param rb Ring buffer to insert into. + * @param element Value to insert into ring buffer. + * @return On success, returns -1. If an element was popped, returns + * the popped value. + */ +static inline int rb_push_insert(ring_buffer *rb, uint8 element) { + int ret = -1; + if (rb_is_full(rb)) { + ret = rb_remove(rb); + } + rb_insert(rb, element); + return ret; +} + +/** + * @brief Discard all items from a ring buffer. + * @param rb Ring buffer to discard all items from. + */ +static inline void rb_reset(ring_buffer *rb) { + rb->tail = rb->head; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/scb.h b/libmaple/include/libmaple/scb.h new file mode 100644 index 0000000..1c7c5d7 --- /dev/null +++ b/libmaple/include/libmaple/scb.h @@ -0,0 +1,209 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/scb.h + * @brief System control block header + */ + +#ifndef _LIBMAPLE_SCB_H_ +#define _LIBMAPLE_SCB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> + +/* + * Register map and base pointer + */ + +/** System control block register map type */ +typedef struct scb_reg_map { + __io uint32 CPUID; /**< CPU ID Base Register */ + __io uint32 ICSR; /**< Interrupt Control State Register */ + __io uint32 VTOR; /**< Vector Table Offset Register */ + __io uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ + __io uint32 SCR; /**< System Control Register */ + __io uint32 CCR; /**< Configuration and Control Register */ + __io uint8 SHP[12]; /**< System Handler Priority Registers + (4-7, 8-11, 12-15) */ + __io uint32 SHCSR; /**< System Handler Control and State Register */ + __io uint32 CFSR; /**< Configurable Fault Status Register */ + __io uint32 HFSR; /**< Hard Fault Status Register */ + /* DFSR is not documented by ST in PM0056 (as of Revision 4), but + * there's a 4 byte hole in the SCB register map docs right where + * it belongs. Since it's specified as "always implemented" in + * the ARM v7-M ARM, I'm assuming its absence is a bug in the ST + * doc, but I haven't proven it. [mbolivar] */ + __io uint32 DFSR; /**< Debug Fault Status Register */ + __io uint32 MMFAR; /**< Mem Manage Address Register */ + __io uint32 BFAR; /**< Bus Fault Address Register */ +#if 0 + /* The following registers are implementation-defined according to + * ARM v7-M, and I can't find evidence of their existence in ST's + * docs. I'm removing them. Feel free to yell at me if they do + * exist. [mbolivar] + */ + __io uint32 AFSR; /**< Auxiliary Fault Status Register */ + __io uint32 PFR[2]; /**< Processor Feature Register */ + __io uint32 DFR; /**< Debug Feature Register */ + __io uint32 AFR; /**< Auxiliary Feature Register */ + __io uint32 MMFR[4]; /**< Memory Model Feature Register */ + __io uint32 ISAR[5]; /**< ISA Feature Register */ +#endif +} scb_reg_map; + +/** System control block register map base pointer */ +#define SCB_BASE ((struct scb_reg_map*)0xE000ED00) + +/* + * Register bit definitions + */ + +/* No SCB_REG_FIELD_BIT macros as the relevant addresses are not in a + * bit-band region. */ + +/* CPUID base register (SCB_CPUID) */ + +#define SCB_CPUID_IMPLEMENTER (0xFF << 24) +#define SCB_CPUID_VARIANT (0xF << 20) +#define SCB_CPUID_CONSTANT (0xF << 16) +#define SCB_CPUID_PARTNO (0xFFF << 4) +#define SCB_CPUID_REVISION 0xF + +/* Interrupt control state register (SCB_ICSR) */ + +#define SCB_ICSR_NMIPENDSET BIT(31) +#define SCB_ICSR_PENDSVSET BIT(28) +#define SCB_ICSR_PENDSVCLR BIT(27) +#define SCB_ICSR_PENDSTSET BIT(26) +#define SCB_ICSR_PENDSTCLR BIT(25) +#define SCB_ICSR_ISRPENDING BIT(22) +#define SCB_ICSR_VECTPENDING (0x3FF << 12) +#define SCB_ICSR_RETOBASE BIT(11) +#define SCB_ICSR_VECTACTIVE 0xFF + +/* Vector table offset register (SCB_VTOR) */ + +#define SCB_VTOR_TBLOFF (0x1FFFFF << 9) + +/* Application interrupt and reset control register (SCB_AIRCR) */ + +#define SCB_AIRCR_VECTKEYSTAT (0x5FA << 16) +#define SCB_AIRCR_VECTKEY (0x5FA << 16) +#define SCB_AIRCR_ENDIANNESS BIT(15) +#define SCB_AIRCR_PRIGROUP (0x3 << 8) +#define SCB_AIRCR_SYSRESETREQ BIT(2) +#define SCB_AIRCR_VECTCLRACTIVE BIT(1) +#define SCB_AIRCR_VECTRESET BIT(0) + +/* System control register (SCB_SCR) */ + +#define SCB_SCR_SEVONPEND BIT(4) +#define SCB_SCR_SLEEPDEEP BIT(2) +#define SCB_SCR_SLEEPONEXIT BIT(1) + +/* Configuration and Control Register (SCB_CCR) */ + +#define SCB_CCR_STKALIGN BIT(9) +#define SCB_CCR_BFHFNMIGN BIT(8) +#define SCB_CCR_DIV_0_TRP BIT(4) +#define SCB_CCR_UNALIGN_TRP BIT(3) +#define SCB_CCR_USERSETMPEND BIT(1) +#define SCB_CCR_NONBASETHRDENA BIT(0) + +/* System handler priority registers (SCB_SHPRx) */ + +#define SCB_SHPR1_PRI6 (0xFF << 16) +#define SCB_SHPR1_PRI5 (0xFF << 8) +#define SCB_SHPR1_PRI4 0xFF + +#define SCB_SHPR2_PRI11 (0xFF << 24) + +#define SCB_SHPR3_PRI15 (0xFF << 24) +#define SCB_SHPR3_PRI14 (0xFF << 16) + +/* System Handler Control and state register (SCB_SHCSR) */ + +#define SCB_SHCSR_USGFAULTENA BIT(18) +#define SCB_SHCSR_BUSFAULTENA BIT(17) +#define SCB_SHCSR_MEMFAULTENA BIT(16) +#define SCB_SHCSR_SVCALLPENDED BIT(15) +#define SCB_SHCSR_BUSFAULTPENDED BIT(14) +#define SCB_SHCSR_MEMFAULTPENDED BIT(13) +#define SCB_SHCSR_USGFAULTPENDED BIT(12) +#define SCB_SHCSR_SYSTICKACT BIT(11) +#define SCB_SHCSR_PENDSVACT BIT(10) +#define SCB_SHCSR_MONITORACT BIT(8) +#define SCB_SHCSR_SVCALLACT BIT(7) +#define SCB_SHCSR_USGFAULTACT BIT(3) +#define SCB_SHCSR_BUSFAULTACT BIT(1) +#define SCB_SHCSR_MEMFAULTACT BIT(0) + +/* Configurable fault status register (SCB_CFSR) */ + +#define SCB_CFSR_DIVBYZERO BIT(25) +#define SCB_CFSR_UNALIGNED BIT(24) +#define SCB_CFSR_NOCP BIT(19) +#define SCB_CFSR_INVPC BIT(18) +#define SCB_CFSR_INVSTATE BIT(17) +#define SCB_CFSR_UNDEFINSTR BIT(16) +#define SCB_CFSR_BFARVALID BIT(15) +#define SCB_CFSR_STKERR BIT(12) +#define SCB_CFSR_UNSTKERR BIT(11) +#define SCB_CFSR_IMPRECISERR BIT(10) +#define SCB_CFSR_PRECISERR BIT(9) +#define SCB_CFSR_IBUSERR BIT(8) +#define SCB_CFSR_MMARVALID BIT(7) +#define SCB_CFSR_MSTKERR BIT(4) +#define SCB_CFSR_MUNSTKERR BIT(3) +#define SCB_CFSR_DACCVIOL BIT(1) +#define SCB_CFSR_IACCVIOL BIT(0) + +/* Hard Fault Status Register (SCB_HFSR) */ + +#define SCB_HFSR_DEBUG_VT BIT(31) +#define SCB_CFSR_FORCED BIT(30) +#define SCB_CFSR_VECTTBL BIT(1) + +/* Debug Fault Status Register */ + +/* Not specified by PM0056, but required by ARM. The bit definitions + * here are based on the names given in the ARM v7-M ARM. */ + +#define SCB_DFSR_EXTERNAL BIT(4) +#define SCB_DFSR_VCATCH BIT(3) +#define SCB_DFSR_DWTTRAP BIT(2) +#define SCB_DFSR_BKPT BIT(1) +#define SCB_DFSR_HALTED BIT(0) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/spi.h b/libmaple/include/libmaple/spi.h new file mode 100644 index 0000000..fab643f --- /dev/null +++ b/libmaple/include/libmaple/spi.h @@ -0,0 +1,469 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/spi.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief Serial Peripheral Interface (SPI) and Integrated + * Interchip Sound (I2S) peripheral support. + * + * I2S support is currently limited to register maps and bit definitions. + */ + +#ifndef _LIBMAPLE_SPI_H_ +#define _LIBMAPLE_SPI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> +#include <libmaple/nvic.h> +#include <series/spi.h> + +/* + * Register maps + */ + +/** SPI register map type. */ +typedef struct spi_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 SR; /**< Status register */ + __io uint32 DR; /**< Data register */ + __io uint32 CRCPR; /**< CRC polynomial register */ + __io uint32 RXCRCR; /**< RX CRC register */ + __io uint32 TXCRCR; /**< TX CRC register */ + __io uint32 I2SCFGR; /**< I2S configuration register */ + __io uint32 I2SPR; /**< I2S prescaler register */ +} spi_reg_map; + +/* + * Register bit definitions + */ + +/* Control register 1 */ + +#define SPI_CR1_BIDIMODE_BIT 15 +#define SPI_CR1_BIDIOE_BIT 14 +#define SPI_CR1_CRCEN_BIT 13 +#define SPI_CR1_CRCNEXT_BIT 12 +#define SPI_CR1_DFF_BIT 11 +#define SPI_CR1_RXONLY_BIT 10 +#define SPI_CR1_SSM_BIT 9 +#define SPI_CR1_SSI_BIT 8 +#define SPI_CR1_LSBFIRST_BIT 7 +#define SPI_CR1_SPE_BIT 6 +#define SPI_CR1_MSTR_BIT 2 +#define SPI_CR1_CPOL_BIT 1 +#define SPI_CR1_CPHA_BIT 0 + +#define SPI_CR1_BIDIMODE (1U << SPI_CR1_BIDIMODE_BIT) +#define SPI_CR1_BIDIMODE_2_LINE (0x0 << SPI_CR1_BIDIMODE_BIT) +#define SPI_CR1_BIDIMODE_1_LINE (0x1 << SPI_CR1_BIDIMODE_BIT) +#define SPI_CR1_BIDIOE (1U << SPI_CR1_BIDIOE_BIT) +#define SPI_CR1_CRCEN (1U << SPI_CR1_CRCEN_BIT) +#define SPI_CR1_CRCNEXT (1U << SPI_CR1_CRCNEXT_BIT) +#define SPI_CR1_DFF (1U << SPI_CR1_DFF_BIT) +#define SPI_CR1_DFF_8_BIT (0x0 << SPI_CR1_DFF_BIT) +#define SPI_CR1_DFF_16_BIT (0x1 << SPI_CR1_DFF_BIT) +#define SPI_CR1_RXONLY (1U << SPI_CR1_RXONLY_BIT) +#define SPI_CR1_SSM (1U << SPI_CR1_SSM_BIT) +#define SPI_CR1_SSI (1U << SPI_CR1_SSI_BIT) +#define SPI_CR1_LSBFIRST (1U << SPI_CR1_LSBFIRST_BIT) +#define SPI_CR1_SPE (1U << SPI_CR1_SPE_BIT) +#define SPI_CR1_BR (0x7 << 3) +#define SPI_CR1_BR_PCLK_DIV_2 (0x0 << 3) +#define SPI_CR1_BR_PCLK_DIV_4 (0x1 << 3) +#define SPI_CR1_BR_PCLK_DIV_8 (0x2 << 3) +#define SPI_CR1_BR_PCLK_DIV_16 (0x3 << 3) +#define SPI_CR1_BR_PCLK_DIV_32 (0x4 << 3) +#define SPI_CR1_BR_PCLK_DIV_64 (0x5 << 3) +#define SPI_CR1_BR_PCLK_DIV_128 (0x6 << 3) +#define SPI_CR1_BR_PCLK_DIV_256 (0x7 << 3) +#define SPI_CR1_MSTR (1U << SPI_CR1_MSTR_BIT) +#define SPI_CR1_CPOL (1U << SPI_CR1_CPOL_BIT) +#define SPI_CR1_CPOL_LOW (0x0 << SPI_CR1_CPOL_BIT) +#define SPI_CR1_CPOL_HIGH (0x1 << SPI_CR1_CPOL_BIT) +#define SPI_CR1_CPHA (1U << SPI_CR1_CPHA_BIT) + +/* Control register 2 */ + +#define SPI_CR2_TXEIE_BIT 7 +#define SPI_CR2_RXNEIE_BIT 6 +#define SPI_CR2_ERRIE_BIT 5 +#define SPI_CR2_SSOE_BIT 2 +#define SPI_CR2_TXDMAEN_BIT 1 +#define SPI_CR2_RXDMAEN_BIT 0 + +#define SPI_CR2_TXEIE (1U << SPI_CR2_TXEIE_BIT) +#define SPI_CR2_RXNEIE (1U << SPI_CR2_RXNEIE_BIT) +#define SPI_CR2_ERRIE (1U << SPI_CR2_ERRIE_BIT) +#define SPI_CR2_SSOE (1U << SPI_CR2_SSOE_BIT) +#define SPI_CR2_TXDMAEN (1U << SPI_CR2_TXDMAEN_BIT) +#define SPI_CR2_RXDMAEN (1U << SPI_CR2_RXDMAEN_BIT) + +/* Status register */ + +#define SPI_SR_BSY_BIT 7 +#define SPI_SR_OVR_BIT 6 +#define SPI_SR_MODF_BIT 5 +#define SPI_SR_CRCERR_BIT 4 +#define SPI_SR_UDR_BIT 3 +#define SPI_SR_CHSIDE_BIT 2 +#define SPI_SR_TXE_BIT 1 +#define SPI_SR_RXNE_BIT 0 + +#define SPI_SR_BSY (1U << SPI_SR_BSY_BIT) +#define SPI_SR_OVR (1U << SPI_SR_OVR_BIT) +#define SPI_SR_MODF (1U << SPI_SR_MODF_BIT) +#define SPI_SR_CRCERR (1U << SPI_SR_CRCERR_BIT) +#define SPI_SR_UDR (1U << SPI_SR_UDR_BIT) +#define SPI_SR_CHSIDE (1U << SPI_SR_CHSIDE_BIT) +#define SPI_SR_CHSIDE_LEFT (0x0 << SPI_SR_CHSIDE_BIT) +#define SPI_SR_CHSIDE_RIGHT (0x1 << SPI_SR_CHSIDE_BIT) +#define SPI_SR_TXE (1U << SPI_SR_TXE_BIT) +#define SPI_SR_RXNE (1U << SPI_SR_RXNE_BIT) + +/* I2S configuration register */ + +#define SPI_I2SCFGR_I2SMOD_BIT 11 +#define SPI_I2SCFGR_I2SE_BIT 10 +#define SPI_I2SCFGR_PCMSYNC_BIT 7 +#define SPI_I2SCFGR_CKPOL_BIT 3 +#define SPI_I2SCFGR_CHLEN_BIT 0 + +#define SPI_I2SCFGR_I2SMOD (1U << SPI_I2SCFGR_I2SMOD_BIT) +#define SPI_I2SCFGR_I2SMOD_SPI (0x0 << SPI_I2SCFGR_I2SMOD_BIT) +#define SPI_I2SCFGR_I2SMOD_I2S (0x1 << SPI_I2SCFGR_I2SMOD_BIT) +#define SPI_I2SCFGR_I2SE (1U << SPI_I2SCFGR_I2SE_BIT) +#define SPI_I2SCFGR_I2SCFG (0x3 << 8) +#define SPI_I2SCFGR_I2SCFG_SLAVE_TX (0x0 << 8) +#define SPI_I2SCFGR_I2SCFG_SLAVE_RX (0x1 << 8) +#define SPI_I2SCFGR_I2SCFG_MASTER_TX (0x2 << 8) +#define SPI_I2SCFGR_I2SCFG_MASTER_RX (0x3 << 8) +#define SPI_I2SCFGR_PCMSYNC (1U << SPI_I2SCFGR_PCMSYNC_BIT) +#define SPI_I2SCFGR_PCMSYNC_SHORT (0x0 << SPI_I2SCFGR_PCMSYNC_BIT) +#define SPI_I2SCFGR_PCMSYNC_LONG (0x1 << SPI_I2SCFGR_PCMSYNC_BIT) +#define SPI_I2SCFGR_I2SSTD (0x3 << 4) +#define SPI_I2SCFGR_I2SSTD_PHILLIPS (0x0 << 4) +#define SPI_I2SCFGR_I2SSTD_MSB (0x1 << 4) +#define SPI_I2SCFGR_I2SSTD_LSB (0x2 << 4) +#define SPI_I2SCFGR_I2SSTD_PCM (0x3 << 4) +#define SPI_I2SCFGR_CKPOL (1U << SPI_I2SCFGR_CKPOL_BIT) +#define SPI_I2SCFGR_CKPOL_LOW (0x0 << SPI_I2SCFGR_CKPOL_BIT) +#define SPI_I2SCFGR_CKPOL_HIGH (0x1 << SPI_I2SCFGR_CKPOL_BIT) +#define SPI_I2SCFGR_DATLEN (0x3 << 1) +#define SPI_I2SCFGR_DATLEN_16_BIT (0x0 << 1) +#define SPI_I2SCFGR_DATLEN_24_BIT (0x1 << 1) +#define SPI_I2SCFGR_DATLEN_32_BIT (0x2 << 1) +#define SPI_I2SCFGR_CHLEN (1U << SPI_I2SCFGR_CHLEN_BIT) +#define SPI_I2SCFGR_CHLEN_16_BIT (0x0 << SPI_I2SCFGR_CHLEN_BIT) +#define SPI_I2SCFGR_CHLEN_32_BIT (0x1 << SPI_I2SCFGR_CHLEN_BIT) + +/* I2S prescaler register */ + +#define SPI_I2SPR_MCKOE_BIT 9 +#define SPI_I2SPR_ODD_BIT 8 + +#define SPI_I2SPR_MCKOE (1U << SPI_I2SPR_MCKOE_BIT) +#define SPI_I2SPR_ODD (1U << SPI_I2SPR_ODD_BIT) +#define SPI_I2SPR_I2SDIV 0xFF + +/* + * Devices + */ + +/** SPI device type */ +typedef struct spi_dev { + spi_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ + nvic_irq_num irq_num; /**< NVIC interrupt number */ +} spi_dev; + +/* + * SPI Convenience functions + */ + +void spi_init(spi_dev *dev); + +struct gpio_dev; +/** + * @brief Configure GPIO bit modes for use as a SPI port's pins. + * @param as_master If true, configure bits for use as a bus master. + * Otherwise, configure bits for use as slave. + * @param nss_dev NSS pin's GPIO device + * @param comm_dev SCK, MISO, MOSI pins' GPIO device + * @param nss_bit NSS pin's GPIO bit on nss_dev + * @param sck_bit SCK pin's GPIO bit on comm_dev + * @param miso_bit MISO pin's GPIO bit on comm_dev + * @param mosi_bit MOSI pin's GPIO bit on comm_dev + */ +extern void spi_config_gpios(spi_dev *dev, + uint8 as_master, + struct gpio_dev *nss_dev, + uint8 nss_bit, + struct gpio_dev *comm_dev, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit); + +/** + * @brief SPI mode configuration. + * + * A SPI mode determines a combination of the idle state of the clock + * line (the clock polarity, or "CPOL"), and which clock edge triggers + * data capture (the clock phase, or "CPHA"). + */ +typedef enum spi_mode { + /** Clock idles low, data captured on rising edge (first transition) */ + SPI_MODE_LOW_RISING = 0, + /** Clock idles low, data captured on falling edge (second transition) */ + SPI_MODE_LOW_FALLING = 1, + /** Clock idles high, data captured on falling edge (first transition) */ + SPI_MODE_HIGH_FALLING = 2, + /** Clock idles high, data captured on rising edge (second transition) */ + SPI_MODE_HIGH_RISING = 3, + + SPI_MODE_0 = SPI_MODE_LOW_RISING, /**< Same as SPI_MODE_LOW_RISING */ + SPI_MODE_1 = SPI_MODE_LOW_FALLING, /**< Same as SPI_MODE_LOW_FALLING */ + SPI_MODE_2 = SPI_MODE_HIGH_FALLING, /**< Same as SPI_MODE_HIGH_FALLING */ + SPI_MODE_3 = SPI_MODE_HIGH_RISING, /**< Same as SPI_MODE_HIGH_RISING */ +} spi_mode; + +/** + * @brief SPI baud rate configuration, as a divisor of f_PCLK, the + * PCLK clock frequency. + */ +typedef enum spi_baud_rate { + SPI_BAUD_PCLK_DIV_2 = SPI_CR1_BR_PCLK_DIV_2, /**< f_PCLK/2 */ + SPI_BAUD_PCLK_DIV_4 = SPI_CR1_BR_PCLK_DIV_4, /**< f_PCLK/4 */ + SPI_BAUD_PCLK_DIV_8 = SPI_CR1_BR_PCLK_DIV_8, /**< f_PCLK/8 */ + SPI_BAUD_PCLK_DIV_16 = SPI_CR1_BR_PCLK_DIV_16, /**< f_PCLK/16 */ + SPI_BAUD_PCLK_DIV_32 = SPI_CR1_BR_PCLK_DIV_32, /**< f_PCLK/32 */ + SPI_BAUD_PCLK_DIV_64 = SPI_CR1_BR_PCLK_DIV_64, /**< f_PCLK/64 */ + SPI_BAUD_PCLK_DIV_128 = SPI_CR1_BR_PCLK_DIV_128, /**< f_PCLK/128 */ + SPI_BAUD_PCLK_DIV_256 = SPI_CR1_BR_PCLK_DIV_256, /**< f_PCLK/256 */ +} spi_baud_rate; + +/** + * @brief SPI initialization flags. + * @see spi_master_enable() + * @see spi_slave_enable() + */ +typedef enum spi_cfg_flag { + SPI_BIDIMODE = SPI_CR1_BIDIMODE, /**< Bidirectional mode enable */ + SPI_BIDIOE = SPI_CR1_BIDIOE, /**< Output enable in bidirectional + mode */ + SPI_CRCEN = SPI_CR1_CRCEN, /**< Cyclic redundancy check (CRC) + enable */ + SPI_DFF_8_BIT = SPI_CR1_DFF_8_BIT, /**< 8-bit data frame format (this is + the default) */ + SPI_DFF_16_BIT = SPI_CR1_DFF_16_BIT, /**< 16-bit data frame format */ + SPI_RX_ONLY = SPI_CR1_RXONLY, /**< Receive only */ + SPI_SW_SLAVE = SPI_CR1_SSM, /**< Software slave management */ + SPI_SOFT_SS = SPI_CR1_SSI, /**< Software (internal) slave + select. This flag only has an + effect when used in combination + with SPI_SW_SLAVE. */ + SPI_FRAME_LSB = SPI_CR1_LSBFIRST, /**< LSB-first (little-endian) frame + format */ + SPI_FRAME_MSB = 0, /**< MSB-first (big-endian) frame + format (this is the default) */ +} spi_cfg_flag; + +void spi_master_enable(spi_dev *dev, + spi_baud_rate baud, + spi_mode mode, + uint32 flags); + +void spi_slave_enable(spi_dev *dev, + spi_mode mode, + uint32 flags); + +uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len); + +/** + * @brief Call a function on each SPI port + * @param fn Function to call. + */ +extern void spi_foreach(void (*fn)(spi_dev*)); + +void spi_peripheral_enable(spi_dev *dev); +void spi_peripheral_disable(spi_dev *dev); + +void spi_tx_dma_enable(spi_dev *dev); +void spi_tx_dma_disable(spi_dev *dev); + +void spi_rx_dma_enable(spi_dev *dev); +void spi_rx_dma_disable(spi_dev *dev); + +/** + * @brief Determine if a SPI peripheral is enabled. + * @param dev SPI device + * @return True, if and only if dev's peripheral is enabled. + */ +static inline uint8 spi_is_enabled(spi_dev *dev) { + return dev->regs->CR1 & SPI_CR1_SPE_BIT; +} + +/** + * @brief Disable all SPI peripherals + */ +static inline void spi_peripheral_disable_all(void) { + spi_foreach(spi_peripheral_disable); +} + +/** Available SPI interrupts */ +typedef enum spi_interrupt { + SPI_TXE_INTERRUPT = SPI_CR2_TXEIE, /**< TX buffer empty interrupt */ + SPI_RXNE_INTERRUPT = SPI_CR2_RXNEIE, /**< RX buffer not empty interrupt */ + SPI_ERR_INTERRUPT = SPI_CR2_ERRIE /**< + * Error interrupt (CRC, overrun, + * and mode fault errors for SPI; + * underrun, overrun errors for I2S) + */ +} spi_interrupt; + +/** + * @brief Mask for all spi_interrupt values + * @see spi_interrupt + */ +#define SPI_INTERRUPTS_ALL (SPI_TXE_INTERRUPT | \ + SPI_RXNE_INTERRUPT | \ + SPI_ERR_INTERRUPT) + +/** + * @brief Enable SPI interrupt requests + * @param dev SPI device + * @param interrupt_flags Bitwise OR of spi_interrupt values to enable + * @see spi_interrupt + */ +static inline void spi_irq_enable(spi_dev *dev, uint32 interrupt_flags) { + dev->regs->CR2 |= interrupt_flags; + nvic_irq_enable(dev->irq_num); +} + +/** + * @brief Disable SPI interrupt requests + * @param dev SPI device + * @param interrupt_flags Bitwise OR of spi_interrupt values to disable + * @see spi_interrupt + */ +static inline void spi_irq_disable(spi_dev *dev, uint32 interrupt_flags) { + dev->regs->CR2 &= ~interrupt_flags; +} + +/** + * @brief Get the data frame format flags with which a SPI port is + * configured. + * @param dev SPI device whose data frame format to get. + * @return SPI_DFF_8_BIT, if dev has an 8-bit data frame format. + * Otherwise, SPI_DFF_16_BIT. + */ +static inline spi_cfg_flag spi_dff(spi_dev *dev) { + return ((dev->regs->CR1 & SPI_CR1_DFF) == SPI_CR1_DFF_8_BIT ? + SPI_DFF_8_BIT : + SPI_DFF_16_BIT); +} + +/** + * @brief Determine whether the device's peripheral receive (RX) + * register is empty. + * @param dev SPI device + * @return true, iff dev's RX register is empty. + */ +static inline uint8 spi_is_rx_nonempty(spi_dev *dev) { + return dev->regs->SR & SPI_SR_RXNE; +} + +/** + * @brief Retrieve the contents of the device's peripheral receive + * (RX) register. + * + * You may only call this function when the RX register is nonempty. + * Calling this function clears the contents of the RX register. + * + * @param dev SPI device + * @return Contents of dev's peripheral RX register + * @see spi_is_rx_reg_nonempty() + */ +static inline uint16 spi_rx_reg(spi_dev *dev) { + return (uint16)dev->regs->DR; +} + +/** + * @brief Determine whether the device's peripheral transmit (TX) + * register is empty. + * @param dev SPI device + * @return true, iff dev's TX register is empty. + */ +static inline uint8 spi_is_tx_empty(spi_dev *dev) { + return dev->regs->SR & SPI_SR_TXE; +} + +/** + * @brief Load a value into the device's peripheral transmit (TX) register. + * + * You may only call this function when the TX register is empty. + * Calling this function loads val into the peripheral's TX register. + * If the device is properly configured, this will initiate a + * transmission, the completion of which will cause the TX register to + * be empty again. + * + * @param dev SPI device + * @param val Value to load into the TX register. If the SPI data + * frame format is 8 bit, the value must be right-aligned. + * @see spi_is_tx_reg_empty() + * @see spi_init() + * @see spi_master_enable() + * @see spi_slave_enable() + */ +static inline void spi_tx_reg(spi_dev *dev, uint16 val) { + dev->regs->DR = val; +} + +/** + * @brief Determine whether the device's peripheral busy (SPI_SR_BSY) + * flag is set. + * @param dev SPI device + * @return true, iff dev's BSY flag is set. + */ +static inline uint8 spi_is_busy(spi_dev *dev) { + return dev->regs->SR & SPI_SR_BSY; +} + +/* + * I2S convenience functions (TODO) + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/stm32.h b/libmaple/include/libmaple/stm32.h new file mode 100644 index 0000000..3845cab --- /dev/null +++ b/libmaple/include/libmaple/stm32.h @@ -0,0 +1,237 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010, 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/stm32.h + * @brief STM32 chip header + * + * This header supplies various chip-specific values for the current + * build target. It's useful both to abstract away hardware details + * (e.g. through use of STM32_NR_INTERRUPTS) and to decide what to do + * when you want something nonportable (e.g. by checking + * STM32_MCU_SERIES). + */ + +#ifndef _LIBMAPLE_STM32_H_ +#define _LIBMAPLE_STM32_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * STM32 series identifiers. + * + * Don't make these into an enum; the preprocessor needs them. + */ + +/** STM32F1 series. */ +#define STM32_SERIES_F1 0 +/** STM32F2 series. */ +#define STM32_SERIES_F2 1 +/** STM32L1 series. */ +#define STM32_SERIES_L1 2 +/** STM32F4 series. */ +#define STM32_SERIES_F4 3 + +/* The series header is responsible for defining: + * + * - Everything in the following __DOXYGEN__ conditional block. + * + * - STM32_HAVE_FSMC: 1 if the MCU has the FSMC peripheral, and 0 + * otherwise. + * + * - STM32_HAVE_USB: 1 if the MCU has a USB peripheral, and 0 + * otherwise. + */ +#include <series/stm32.h> + +/* Ensure the series header isn't broken. */ +#if (!defined(STM32_PCLK1) || \ + !defined(STM32_PCLK2) || \ + !defined(STM32_MCU_SERIES) || \ + !defined(STM32_NR_INTERRUPTS) || \ + !defined(STM32_NR_GPIO_PORTS) || \ + !defined(STM32_TIMER_MASK) || \ + !defined(STM32_DELAY_US_MULT) || \ + !defined(STM32_SRAM_END) || \ + !defined(STM32_HAVE_DAC) || \ + !defined(STM32_HAVE_FSMC) || \ + !defined(STM32_HAVE_USB)) +#error "Bad STM32F1 configuration. Check <series/stm32.h> header for your MCU." +#endif + +/* + * Derived macros + */ + +/* FIXME [0.0.13] add this to ReST API page */ +/** + * @brief Statically determine whether a timer is present. + * + * Given a constant timer number n (starting from 1), this macro has a + * nonzero value exactly when TIMERn is available. + */ +#define STM32_HAVE_TIMER(n) (STM32_TIMER_MASK & (1 << (n))) + +/* + * Doxygen for functionality provided by series header. + */ + +#ifdef __DOXYGEN__ + +/* + * Clock configuration. + * + * These defines depend upon how the MCU is configured. Because of + * the potential for a mismatch between them and the actual clock + * configuration, keep their number to a minimum. + */ + +/** + * @brief APB1 clock speed, in Hz. + */ +#define STM32_PCLK1 + +/** + * @brief APB2 clock speed, in Hz. + */ +#define STM32_PCLK2 + +/** @brief Deprecated. Use STM32_PCLK1 instead. */ +#define PCLK1 +/** @brief Deprecated. Use STM32_PCLK2 instead. */ +#define PCLK2 + +/* + * Series- and MCU-specific values. + */ + +/** + * @brief STM32 series value for the MCU being targeted. + * + * At time of writing, allowed values are: STM32_SERIES_F1, + * STM32_SERIES_F2. This set of values will expand as libmaple adds + * support for more STM32 series MCUs. + */ +#define STM32_MCU_SERIES + +/** + * @brief Number of interrupts in the vector table. + * + * This does not include Cortex-M interrupts (NMI, HardFault, etc.). + */ +#define STM32_NR_INTERRUPTS + +/** + * Number of GPIO ports. + */ +#define STM32_NR_GPIO_PORTS + +/* FIXME [0.0.13] add this to ReST API page */ +/** + * @brief Bitmask of timers available on the MCU. + * + * That is, if TIMERn is available, then STM32_TIMER_MASK & (1 << n) + * will be nonzero. For example, a nonzero value of "STM32_TIMER_MASK + * & 0x2" means TIMER1 is available. + * + * A bitmask is necessary as some STM32 MCUs have "holes" in the range + * of available timers. + */ +#define STM32_TIMER_MASK + +/** + * @brief Multiplier to convert microseconds into loop iterations + * in delay_us(). + * + * @see delay_us() + */ +#define STM32_DELAY_US_MULT + +/** + * @brief Pointer to end of built-in SRAM. + * + * Points to the address which is 1 byte past the last valid + * SRAM address. + */ +#define STM32_SRAM_END + +/** + * @brief 1 if the target MCU has a DAC, and 0 otherwise. + */ +#define STM32_HAVE_DAC + +/** + * @brief 1 if the target MCU has the FSMC peripheral, and 0 otherwise. + * + * Note that the feature set of the FSMC peripheral is restricted on + * some MCUs. + */ +#define STM32_HAVE_FSMC + +/** + * @brief 1 if the target MCU has a USB peripheral, and 0 otherwise. + * + * Note that a variety of USB peripherals are available across the + * different series, with widely varying feature sets and programming + * interfaces. This macro will be 1 if any such peripheral is present. + */ +#define STM32_HAVE_USB + +#endif /* __DOXYGEN__ */ + +/* + * The following are for backwards compatibility only. + */ + +/* PCLK1 and PCLK2 are for backwards compatibility only; don't use in + * new code. */ +#ifndef PCLK1 +#define PCLK1 STM32_PCLK1 +#endif +#if PCLK1 != STM32_PCLK1 +#error "PCLK1 (which is deprecated) differs from STM32_PCLK1." +#endif +#ifndef PCLK2 +#define PCLK2 STM32_PCLK2 +#endif +#if PCLK2 != STM32_PCLK2 +#error "PCLK2 (which is deprecated) differs from STM32_PCLK2." +#endif + +/** @brief Deprecated. Use STM32_NR_INTERRUPTS instead. */ +#define NR_INTERRUPTS STM32_NR_INTERRUPTS +/** @brief Deprecated. Use STM32_NR_GPIO_PORTS instead. */ +#define NR_GPIO_PORTS STM32_NR_GPIO_PORTS +/** @brief Deprecated. Use STM32_DELAY_US_MULT instead. */ +#define DELAY_US_MULT STM32_DELAY_US_MULT + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/syscfg.h b/libmaple/include/libmaple/syscfg.h new file mode 100644 index 0000000..6b375d3 --- /dev/null +++ b/libmaple/include/libmaple/syscfg.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/syscfg.h + * @brief System configuration controller (SYSCFG) + * + * Availability: STM32F2, STM32F4. + */ + +#ifndef _LIBMAPLE_SYSCFG_H_ +#define _LIBMAPLE_SYSCFG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> + +/* + * Register map and base pointer + */ + +/** + * @brief SYSCFG register map type. + */ +typedef struct syscfg_reg_map { + __io uint32 MEMRMP; /**< Memory remap register */ + __io uint32 PMC; /**< Peripheral mode configuration */ + __io uint32 EXTICR[4]; /**< External interrupt configuration registers */ + const uint32 RESERVED1; + const uint32 RESERVED2; + __io uint32 CMPCR; /**< Compensation cell control register */ +} syscfg_reg_map; + +/** SYSCFG register map base pointer */ +#define SYSCFG_BASE ((struct syscfg_reg_map*)0x40013800) + +/* + * Register bit definitions + */ + +/* Memory remap register */ + +#define SYSCFG_MEMRMP_MEM_MODE 0x3 +#define SYSCFG_MEMRMP_MEM_MODE_FLASH 0x0 +#define SYSCFG_MEMRMP_MEM_MODE_SYS_FLASH 0x1 +#define SYSCFG_MEMRMP_MEM_MODE_FSMC_1 0x2 +#define SYSCFG_MEMRMP_MEM_MODE_EMB_SRAM 0x3 + +/* Peripheral mode configuration register */ + +#define SYSCFG_PMC_MII_RMII_SEL_BIT 23 + +#define SYSCFG_PMC_MII_RMII_SEL (1U << SYSCFG_PMC_MII_RMII_SEL_BIT) +#define SYSCFG_PMC_MII_RMII_SEL_MII (0U << SYSCFG_PMC_MII_RMII_SEL_BIT) +#define SYSCFG_PMC_MII_RMII_SEL_RMII (1U << SYSCFG_PMC_MII_RMII_SEL_BIT) + +/* External interrupt configuration register 1 */ + +#define SYSCFG_EXTICR1_EXTI0 0xF +#define SYSCFG_EXTICR1_EXTI1 0xF0 +#define SYSCFG_EXTICR1_EXTI2 0xF00 +#define SYSCFG_EXTICR1_EXTI3 0xF000 + +/* External interrupt configuration register 2 */ + +#define SYSCFG_EXTICR2_EXTI4 0xF +#define SYSCFG_EXTICR2_EXTI5 0xF0 +#define SYSCFG_EXTICR2_EXTI6 0xF00 +#define SYSCFG_EXTICR2_EXTI7 0xF000 + +/* External interrupt configuration register 3 */ + +#define SYSCFG_EXTICR3_EXTI8 0xF +#define SYSCFG_EXTICR3_EXTI9 0xF0 +#define SYSCFG_EXTICR3_EXTI10 0xF00 +#define SYSCFG_EXTICR3_EXTI11 0xF000 + +/* External interrupt configuration register 4 */ + +#define SYSCFG_EXTICR4_EXTI12 0xF +#define SYSCFG_EXTICR4_EXTI13 0xF0 +#define SYSCFG_EXTICR4_EXTI14 0xF00 +#define SYSCFG_EXTICR4_EXTI15 0xF000 + +/* Compensation cell control register */ + +#define SYSCFG_CMPCR_READY_BIT 8 +#define SYSCFG_CMPCR_CMP_PD_BIT 0 + +#define SYSCFG_CMPCR_READY (1U << SYSCFG_CMPCR_READY_BIT) +#define SYSCFG_CMPCR_CMP_PD (1U << SYSCFG_CMPCR_CMP_PD_BIT) +#define SYSCFG_CMPCR_CMP_PD_PDWN (0U << SYSCFG_CMPCR_CMP_PD_BIT) +#define SYSCFG_CMPCR_CMP_PD_ENABLE (1U << SYSCFG_CMPCR_CMP_PD_BIT) + +/* + * Routines + */ + +void syscfg_init(void); + +void syscfg_enable_io_compensation(void); +void syscfg_disable_io_compensation(void); + +/** + * @brief System memory mode + * These values specify what memory to map to address 0x00000000. + * @see syscfg_set_mem_mode + */ +typedef enum syscfg_mem_mode { + /** Main flash memory is mapped at 0x0. */ + SYCFG_MEM_MODE_FLASH = SYSCFG_MEMRMP_MEM_MODE_FLASH, + /** System flash (i.e. ST's baked-in bootloader) is mapped at 0x0. */ + SYCFG_MEM_MODE_SYSTEM_FLASH = SYSCFG_MEMRMP_MEM_MODE_SYS_FLASH, + /** FSMC bank 1 (NOR/PSRAM 1 and 2) is mapped at 0x0. */ + SYCFG_MEM_MODE_FSMC_BANK_1 = SYSCFG_MEMRMP_MEM_MODE_FSMC_1, + /** Embedded SRAM (i.e., not backup SRAM) is mapped at 0x0. */ + SYCFG_MEM_MODE_SRAM = SYSCFG_MEMRMP_MEM_MODE_EMB_SRAM, +} syscfg_mem_mode; + +void syscfg_set_mem_mode(syscfg_mem_mode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/systick.h b/libmaple/include/libmaple/systick.h new file mode 100644 index 0000000..551f800 --- /dev/null +++ b/libmaple/include/libmaple/systick.h @@ -0,0 +1,115 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/systick.h + * @brief System timer definitions + */ + +#ifndef _LIBMAPLE_SYSTICK_H_ +#define _LIBMAPLE_SYSTICK_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/util.h> + +/** SysTick register map type */ +typedef struct systick_reg_map { + __io uint32 CSR; /**< Control and status register */ + __io uint32 RVR; /**< Reload value register */ + __io uint32 CNT; /**< Current value register ("count") */ + __io uint32 CVR; /**< Calibration value register */ +} systick_reg_map; + +/** SysTick register map base pointer */ +#define SYSTICK_BASE ((struct systick_reg_map*)0xE000E010) + +/* + * Register bit definitions. + */ + +/* Control and status register */ + +#define SYSTICK_CSR_COUNTFLAG BIT(16) +#define SYSTICK_CSR_CLKSOURCE BIT(2) +#define SYSTICK_CSR_CLKSOURCE_EXTERNAL 0 +#define SYSTICK_CSR_CLKSOURCE_CORE BIT(2) +#define SYSTICK_CSR_TICKINT BIT(1) +#define SYSTICK_CSR_TICKINT_PEND BIT(1) +#define SYSTICK_CSR_TICKINT_NO_PEND 0 +#define SYSTICK_CSR_ENABLE BIT(0) +#define SYSTICK_CSR_ENABLE_MULTISHOT BIT(0) +#define SYSTICK_CSR_ENABLE_DISABLED 0 + +/* Calibration value register */ + +#define SYSTICK_CVR_NOREF BIT(31) +#define SYSTICK_CVR_SKEW BIT(30) +#define SYSTICK_CVR_TENMS 0xFFFFFF + +/** System elapsed time, in milliseconds */ +extern volatile uint32 systick_uptime_millis; + +/** + * @brief Returns the system uptime, in milliseconds. + */ +static inline uint32 systick_uptime(void) { + return systick_uptime_millis; +} + + +void systick_init(uint32 reload_val); +void systick_disable(); +void systick_enable(); + +/** + * @brief Returns the current value of the SysTick counter. + */ +static inline uint32 systick_get_count(void) { + return SYSTICK_BASE->CNT; +} + +/** + * @brief Check for underflow. + * + * This function returns 1 if the SysTick timer has counted to 0 since + * the last time it was called. However, any reads of any part of the + * SysTick Control and Status Register SYSTICK_BASE->CSR will + * interfere with this functionality. See the ARM Cortex M3 Technical + * Reference Manual for more details (e.g. Table 8-3 in revision r1p1). + */ +static inline uint32 systick_check_underflow(void) { + return SYSTICK_BASE->CSR & SYSTICK_CSR_COUNTFLAG; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/timer.h b/libmaple/include/libmaple/timer.h new file mode 100644 index 0000000..995f868 --- /dev/null +++ b/libmaple/include/libmaple/timer.h @@ -0,0 +1,1110 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/timer.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief Timer interface. + */ + +#ifndef _LIBMAPLE_TIMER_H_ +#define _LIBMAPLE_TIMER_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <series/timer.h> +#include <libmaple/libmaple.h> +#include <libmaple/rcc.h> +#include <libmaple/nvic.h> +#include <libmaple/bitband.h> + +/* + * Register maps + */ + +/** Advanced control timer register map type */ +typedef struct timer_adv_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 SMCR; /**< Slave mode control register */ + __io uint32 DIER; /**< DMA/interrupt enable register */ + __io uint32 SR; /**< Status register */ + __io uint32 EGR; /**< Event generation register */ + __io uint32 CCMR1; /**< Capture/compare mode register 1 */ + __io uint32 CCMR2; /**< Capture/compare mode register 2 */ + __io uint32 CCER; /**< Capture/compare enable register */ + __io uint32 CNT; /**< Counter */ + __io uint32 PSC; /**< Prescaler */ + __io uint32 ARR; /**< Auto-reload register */ + __io uint32 RCR; /**< Repetition counter register */ + __io uint32 CCR1; /**< Capture/compare register 1 */ + __io uint32 CCR2; /**< Capture/compare register 2 */ + __io uint32 CCR3; /**< Capture/compare register 3 */ + __io uint32 CCR4; /**< Capture/compare register 4 */ + __io uint32 BDTR; /**< Break and dead-time register */ + __io uint32 DCR; /**< DMA control register */ + __io uint32 DMAR; /**< DMA address for full transfer */ +} timer_adv_reg_map; + +/* General purpose timer register map type: intentionally omitted. + * + * General purpose timers differ slightly across series, so leave it + * up to the series header to define struct timer_gen_reg_map. */ + +/** Basic timer register map type */ +typedef struct timer_bas_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + const uint32 RESERVED1; /**< Reserved */ + __io uint32 DIER; /**< DMA/interrupt enable register */ + __io uint32 SR; /**< Status register */ + __io uint32 EGR; /**< Event generation register */ + const uint32 RESERVED2; /**< Reserved */ + const uint32 RESERVED3; /**< Reserved */ + const uint32 RESERVED4; /**< Reserved */ + __io uint32 CNT; /**< Counter */ + __io uint32 PSC; /**< Prescaler */ + __io uint32 ARR; /**< Auto-reload register */ +} timer_bas_reg_map; + +/* + * Timer devices + */ + +/** + * @brief Timer register map type. + * + * Just holds a pointer to the correct type of register map, based on + * the timer's type. + */ +typedef union timer_reg_map { + timer_adv_reg_map *adv; /**< Advanced register map */ + timer_gen_reg_map *gen; /**< General purpose register map */ + timer_bas_reg_map *bas; /**< Basic register map */ +} timer_reg_map; + +/** + * @brief Timer type + * + * Type marker for timer_dev. + * + * @see timer_dev + */ +typedef enum timer_type { + TIMER_ADVANCED, /**< Advanced type */ + TIMER_GENERAL, /**< General purpose type */ + TIMER_BASIC, /**< Basic type */ +} timer_type; + +/** Timer device type */ +typedef struct timer_dev { + timer_reg_map regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ + timer_type type; /**< Timer's type */ + voidFuncPtr handlers[]; /**< + * Don't touch these. Use these instead: + * @see timer_attach_interrupt() + * @see timer_detach_interrupt() */ +} timer_dev; + +#if STM32_HAVE_TIMER(1) +extern timer_dev *TIMER1; +#endif +#if STM32_HAVE_TIMER(2) +extern timer_dev *TIMER2; +#endif +#if STM32_HAVE_TIMER(3) +extern timer_dev *TIMER3; +#endif +#if STM32_HAVE_TIMER(4) +extern timer_dev *TIMER4; +#endif +#if STM32_HAVE_TIMER(5) +extern timer_dev *TIMER5; +#endif +#if STM32_HAVE_TIMER(6) +extern timer_dev *TIMER6; +#endif +#if STM32_HAVE_TIMER(7) +extern timer_dev *TIMER7; +#endif +#if STM32_HAVE_TIMER(8) +extern timer_dev *TIMER8; +#endif +#if STM32_HAVE_TIMER(9) +extern timer_dev *TIMER9; +#endif +#if STM32_HAVE_TIMER(10) +extern timer_dev *TIMER10; +#endif +#if STM32_HAVE_TIMER(11) +extern timer_dev *TIMER11; +#endif +#if STM32_HAVE_TIMER(12) +extern timer_dev *TIMER12; +#endif +#if STM32_HAVE_TIMER(13) +extern timer_dev *TIMER13; +#endif +#if STM32_HAVE_TIMER(14) +extern timer_dev *TIMER14; +#endif + +/* + * Register bit definitions + */ + +/* Control register 1 (CR1) */ + +#define TIMER_CR1_ARPE_BIT 7 +#define TIMER_CR1_DIR_BIT 4 +#define TIMER_CR1_OPM_BIT 3 +#define TIMER_CR1_URS_BIT 2 +#define TIMER_CR1_UDIS_BIT 1 +#define TIMER_CR1_CEN_BIT 0 + +#define TIMER_CR1_CKD (0x3 << 8) +#define TIMER_CR1_CKD_1TCKINT (0x0 << 8) +#define TIMER_CR1_CKD_2TCKINT (0x1 << 8) +#define TIMER_CR1_CKD_4TICKINT (0x2 << 8) +#define TIMER_CR1_ARPE (1U << TIMER_CR1_ARPE_BIT) +#define TIMER_CR1_CKD_CMS (0x3 << 5) +#define TIMER_CR1_CKD_CMS_EDGE (0x0 << 5) +#define TIMER_CR1_CKD_CMS_CENTER1 (0x1 << 5) +#define TIMER_CR1_CKD_CMS_CENTER2 (0x2 << 5) +#define TIMER_CR1_CKD_CMS_CENTER3 (0x3 << 5) +#define TIMER_CR1_DIR (1U << TIMER_CR1_DIR_BIT) +#define TIMER_CR1_OPM (1U << TIMER_CR1_OPM_BIT) +#define TIMER_CR1_URS (1U << TIMER_CR1_URS_BIT) +#define TIMER_CR1_UDIS (1U << TIMER_CR1_UDIS_BIT) +#define TIMER_CR1_CEN (1U << TIMER_CR1_CEN_BIT) + +/* Control register 2 (CR2) */ + +#define TIMER_CR2_OIS4_BIT 14 +#define TIMER_CR2_OIS3N_BIT 13 +#define TIMER_CR2_OIS3_BIT 12 +#define TIMER_CR2_OIS2N_BIT 11 +#define TIMER_CR2_OIS2_BIT 10 +#define TIMER_CR2_OIS1N_BIT 9 +#define TIMER_CR2_OIS1_BIT 8 +#define TIMER_CR2_TI1S_BIT 7 +#define TIMER_CR2_CCDS_BIT 3 +#define TIMER_CR2_CCUS_BIT 2 +#define TIMER_CR2_CCPC_BIT 0 + +#define TIMER_CR2_OIS4 (1U << TIMER_CR2_OIS4_BIT) +#define TIMER_CR2_OIS3N (1U << TIMER_CR2_OIS3N_BIT) +#define TIMER_CR2_OIS3 (1U << TIMER_CR2_OIS3_BIT) +#define TIMER_CR2_OIS2N (1U << TIMER_CR2_OIS2N_BIT) +#define TIMER_CR2_OIS2 (1U << TIMER_CR2_OIS2_BIT) +#define TIMER_CR2_OIS1N (1U << TIMER_CR2_OIS1N_BIT) +#define TIMER_CR2_OIS1 (1U << TIMER_CR2_OIS1_BIT) +#define TIMER_CR2_TI1S (1U << TIMER_CR2_TI1S_BIT) +#define TIMER_CR2_MMS (0x7 << 4) +#define TIMER_CR2_MMS_RESET (0x0 << 4) +#define TIMER_CR2_MMS_ENABLE (0x1 << 4) +#define TIMER_CR2_MMS_UPDATE (0x2 << 4) +#define TIMER_CR2_MMS_COMPARE_PULSE (0x3 << 4) +#define TIMER_CR2_MMS_COMPARE_OC1REF (0x4 << 4) +#define TIMER_CR2_MMS_COMPARE_OC2REF (0x5 << 4) +#define TIMER_CR2_MMS_COMPARE_OC3REF (0x6 << 4) +#define TIMER_CR2_MMS_COMPARE_OC4REF (0x7 << 4) +#define TIMER_CR2_CCDS (1U << TIMER_CR2_CCDS_BIT) +#define TIMER_CR2_CCUS (1U << TIMER_CR2_CCUS_BIT) +#define TIMER_CR2_CCPC (1U << TIMER_CR2_CCPC_BIT) + +/* Slave mode control register (SMCR) */ + +#define TIMER_SMCR_ETP_BIT 15 +#define TIMER_SMCR_ECE_BIT 14 +#define TIMER_SMCR_MSM_BIT 7 + +#define TIMER_SMCR_ETP (1U << TIMER_SMCR_ETP_BIT) +#define TIMER_SMCR_ECE (1U << TIMER_SMCR_ECE_BIT) +#define TIMER_SMCR_ETPS (0x3 << 12) +#define TIMER_SMCR_ETPS_OFF (0x0 << 12) +#define TIMER_SMCR_ETPS_DIV2 (0x1 << 12) +#define TIMER_SMCR_ETPS_DIV4 (0x2 << 12) +#define TIMER_SMCR_ETPS_DIV8 (0x3 << 12) +#define TIMER_SMCR_ETF (0xF << 12) +#define TIMER_SMCR_MSM (1U << TIMER_SMCR_MSM_BIT) +#define TIMER_SMCR_TS (0x3 << 4) +#define TIMER_SMCR_TS_ITR0 (0x0 << 4) +#define TIMER_SMCR_TS_ITR1 (0x1 << 4) +#define TIMER_SMCR_TS_ITR2 (0x2 << 4) +#define TIMER_SMCR_TS_ITR3 (0x3 << 4) +#define TIMER_SMCR_TS_TI1F_ED (0x4 << 4) +#define TIMER_SMCR_TS_TI1FP1 (0x5 << 4) +#define TIMER_SMCR_TS_TI2FP2 (0x6 << 4) +#define TIMER_SMCR_TS_ETRF (0x7 << 4) +#define TIMER_SMCR_SMS 0x3 +#define TIMER_SMCR_SMS_DISABLED 0x0 +#define TIMER_SMCR_SMS_ENCODER1 0x1 +#define TIMER_SMCR_SMS_ENCODER2 0x2 +#define TIMER_SMCR_SMS_ENCODER3 0x3 +#define TIMER_SMCR_SMS_RESET 0x4 +#define TIMER_SMCR_SMS_GATED 0x5 +#define TIMER_SMCR_SMS_TRIGGER 0x6 +#define TIMER_SMCR_SMS_EXTERNAL 0x7 + +/* DMA/Interrupt enable register (DIER) */ + +#define TIMER_DIER_TDE_BIT 14 +#define TIMER_DIER_COMDE_BIT 13 +#define TIMER_DIER_CC4DE_BIT 12 +#define TIMER_DIER_CC3DE_BIT 11 +#define TIMER_DIER_CC2DE_BIT 10 +#define TIMER_DIER_CC1DE_BIT 9 +#define TIMER_DIER_UDE_BIT 8 +#define TIMER_DIER_BIE_BIT 7 +#define TIMER_DIER_TIE_BIT 6 +#define TIMER_DIER_COMIE_BIT 5 +#define TIMER_DIER_CC4IE_BIT 4 +#define TIMER_DIER_CC3IE_BIT 3 +#define TIMER_DIER_CC2IE_BIT 2 +#define TIMER_DIER_CC1IE_BIT 1 +#define TIMER_DIER_UIE_BIT 0 + +#define TIMER_DIER_TDE (1U << TIMER_DIER_TDE_BIT) +#define TIMER_DIER_COMDE (1U << TIMER_DIER_COMDE_BIT) +#define TIMER_DIER_CC4DE (1U << TIMER_DIER_CC4DE_BIT) +#define TIMER_DIER_CC3DE (1U << TIMER_DIER_CC3DE_BIT) +#define TIMER_DIER_CC2DE (1U << TIMER_DIER_CC2DE_BIT) +#define TIMER_DIER_CC1DE (1U << TIMER_DIER_CC1DE_BIT) +#define TIMER_DIER_UDE (1U << TIMER_DIER_UDE_BIT) +#define TIMER_DIER_BIE (1U << TIMER_DIER_BIE_BIT) +#define TIMER_DIER_TIE (1U << TIMER_DIER_TIE_BIT) +#define TIMER_DIER_COMIE (1U << TIMER_DIER_COMIE_BIT) +#define TIMER_DIER_CC4IE (1U << TIMER_DIER_CC4IE_BIT) +#define TIMER_DIER_CC3IE (1U << TIMER_DIER_CC3IE_BIT) +#define TIMER_DIER_CC2IE (1U << TIMER_DIER_CC2IE_BIT) +#define TIMER_DIER_CC1IE (1U << TIMER_DIER_CC1IE_BIT) +#define TIMER_DIER_UIE (1U << TIMER_DIER_UIE_BIT) + +/* Status register (SR) */ + +#define TIMER_SR_CC4OF_BIT 12 +#define TIMER_SR_CC3OF_BIT 11 +#define TIMER_SR_CC2OF_BIT 10 +#define TIMER_SR_CC1OF_BIT 9 +#define TIMER_SR_BIF_BIT 7 +#define TIMER_SR_TIF_BIT 6 +#define TIMER_SR_COMIF_BIT 5 +#define TIMER_SR_CC4IF_BIT 4 +#define TIMER_SR_CC3IF_BIT 3 +#define TIMER_SR_CC2IF_BIT 2 +#define TIMER_SR_CC1IF_BIT 1 +#define TIMER_SR_UIF_BIT 0 + +#define TIMER_SR_CC4OF (1U << TIMER_SR_CC4OF_BIT) +#define TIMER_SR_CC3OF (1U << TIMER_SR_CC3OF_BIT) +#define TIMER_SR_CC2OF (1U << TIMER_SR_CC2OF_BIT) +#define TIMER_SR_CC1OF (1U << TIMER_SR_CC1OF_BIT) +#define TIMER_SR_BIF (1U << TIMER_SR_BIF_BIT) +#define TIMER_SR_TIF (1U << TIMER_SR_TIF_BIT) +#define TIMER_SR_COMIF (1U << TIMER_SR_COMIF_BIT) +#define TIMER_SR_CC4IF (1U << TIMER_SR_CC4IF_BIT) +#define TIMER_SR_CC3IF (1U << TIMER_SR_CC3IF_BIT) +#define TIMER_SR_CC2IF (1U << TIMER_SR_CC2IF_BIT) +#define TIMER_SR_CC1IF (1U << TIMER_SR_CC1IF_BIT) +#define TIMER_SR_UIF (1U << TIMER_SR_UIF_BIT) + +/* Event generation register (EGR) */ + +#define TIMER_EGR_BG_BIT 7 +#define TIMER_EGR_TG_BIT 6 +#define TIMER_EGR_COMG_BIT 5 +#define TIMER_EGR_CC4G_BIT 4 +#define TIMER_EGR_CC3G_BIT 3 +#define TIMER_EGR_CC2G_BIT 2 +#define TIMER_EGR_CC1G_BIT 1 +#define TIMER_EGR_UG_BIT 0 + +#define TIMER_EGR_BG (1U << TIMER_EGR_BG_BIT) +#define TIMER_EGR_TG (1U << TIMER_EGR_TG_BIT) +#define TIMER_EGR_COMG (1U << TIMER_EGR_COMG_BIT) +#define TIMER_EGR_CC4G (1U << TIMER_EGR_CC4G_BIT) +#define TIMER_EGR_CC3G (1U << TIMER_EGR_CC3G_BIT) +#define TIMER_EGR_CC2G (1U << TIMER_EGR_CC2G_BIT) +#define TIMER_EGR_CC1G (1U << TIMER_EGR_CC1G_BIT) +#define TIMER_EGR_UG (1U << TIMER_EGR_UG_BIT) + +/* Capture/compare mode registers, common values */ + +#define TIMER_CCMR_CCS_OUTPUT 0x0 +#define TIMER_CCMR_CCS_INPUT_TI1 0x1 +#define TIMER_CCMR_CCS_INPUT_TI2 0x2 +#define TIMER_CCMR_CCS_INPUT_TRC 0x3 + +/* Capture/compare mode register 1 (CCMR1) */ + +#define TIMER_CCMR1_OC2CE_BIT 15 +#define TIMER_CCMR1_OC2PE_BIT 11 +#define TIMER_CCMR1_OC2FE_BIT 10 +#define TIMER_CCMR1_OC1CE_BIT 7 +#define TIMER_CCMR1_OC1PE_BIT 3 +#define TIMER_CCMR1_OC1FE_BIT 2 + +#define TIMER_CCMR1_OC2CE (1U << TIMER_CCMR1_OC2CE_BIT) +#define TIMER_CCMR1_OC2M (0x3 << 12) +#define TIMER_CCMR1_IC2F (0xF << 12) +#define TIMER_CCMR1_OC2PE (1U << TIMER_CCMR1_OC2PE_BIT) +#define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT) +#define TIMER_CCMR1_IC2PSC (0x3 << 10) +#define TIMER_CCMR1_CC2S (0x3 << 8) +#define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) +#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) +#define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT) +#define TIMER_CCMR1_OC1M (0x3 << 4) +#define TIMER_CCMR1_IC1F (0xF << 4) +#define TIMER_CCMR1_OC1PE (1U << TIMER_CCMR1_OC1PE_BIT) +#define TIMER_CCMR1_OC1FE (1U << TIMER_CCMR1_OC1FE_BIT) +#define TIMER_CCMR1_IC1PSC (0x3 << 2) +#define TIMER_CCMR1_CC1S 0x3 +#define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT +#define TIMER_CCMR1_CC1S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 +#define TIMER_CCMR1_CC1S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 +#define TIMER_CCMR1_CC1S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC + +/* Capture/compare mode register 2 (CCMR2) */ + +#define TIMER_CCMR2_OC4CE_BIT 15 +#define TIMER_CCMR2_OC4PE_BIT 11 +#define TIMER_CCMR2_OC4FE_BIT 10 +#define TIMER_CCMR2_OC3CE_BIT 7 +#define TIMER_CCMR2_OC3PE_BIT 3 +#define TIMER_CCMR2_OC3FE_BIT 2 + +#define TIMER_CCMR2_OC4CE (1U << TIMER_CCMR2_OC4CE_BIT) +#define TIMER_CCMR2_OC4M (0x3 << 12) +#define TIMER_CCMR2_IC4F (0xF << 12) +#define TIMER_CCMR2_OC4PE (1U << TIMER_CCMR2_OC4PE_BIT) +#define TIMER_CCMR2_OC4FE (1U << TIMER_CCMR2_OC4FE_BIT) +#define TIMER_CCMR2_IC4PSC (0x3 << 10) +#define TIMER_CCMR2_CC4S (0x3 << 8) +#define TIMER_CCMR2_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) +#define TIMER_CCMR2_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) +#define TIMER_CCMR2_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) +#define TIMER_CCMR2_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) +#define TIMER_CCMR2_OC3CE (1U << TIMER_CCMR2_OC3CE_BIT) +#define TIMER_CCMR2_OC3M (0x3 << 4) +#define TIMER_CCMR2_IC3F (0xF << 4) +#define TIMER_CCMR2_OC3PE (1U << TIMER_CCMR2_OC3PE_BIT) +#define TIMER_CCMR2_OC3FE (1U << TIMER_CCMR2_OC3FE_BIT) +#define TIMER_CCMR2_IC3PSC (0x3 << 2) +#define TIMER_CCMR2_CC3S 0x3 +#define TIMER_CCMR2_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT +#define TIMER_CCMR2_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 +#define TIMER_CCMR2_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 +#define TIMER_CCMR2_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC + +/* Capture/compare enable register (CCER) */ + +#define TIMER_CCER_CC4P_BIT 13 +#define TIMER_CCER_CC4E_BIT 12 +#define TIMER_CCER_CC3NP_BIT 11 +#define TIMER_CCER_CC3NE_BIT 10 +#define TIMER_CCER_CC3P_BIT 9 +#define TIMER_CCER_CC3E_BIT 8 +#define TIMER_CCER_CC2NP_BIT 7 +#define TIMER_CCER_CC2NE_BIT 6 +#define TIMER_CCER_CC2P_BIT 5 +#define TIMER_CCER_CC2E_BIT 4 +#define TIMER_CCER_CC1NP_BIT 3 +#define TIMER_CCER_CC1NE_BIT 2 +#define TIMER_CCER_CC1P_BIT 1 +#define TIMER_CCER_CC1E_BIT 0 + +#define TIMER_CCER_CC4P (1U << TIMER_CCER_CC4P_BIT) +#define TIMER_CCER_CC4E (1U << TIMER_CCER_CC4E_BIT) +#define TIMER_CCER_CC3NP (1U << TIMER_CCER_CC3NP_BIT) +#define TIMER_CCER_CC3NE (1U << TIMER_CCER_CC3NE_BIT) +#define TIMER_CCER_CC3P (1U << TIMER_CCER_CC3P_BIT) +#define TIMER_CCER_CC3E (1U << TIMER_CCER_CC3E_BIT) +#define TIMER_CCER_CC2NP (1U << TIMER_CCER_CC2NP_BIT) +#define TIMER_CCER_CC2NE (1U << TIMER_CCER_CC2NE_BIT) +#define TIMER_CCER_CC2P (1U << TIMER_CCER_CC2P_BIT) +#define TIMER_CCER_CC2E (1U << TIMER_CCER_CC2E_BIT) +#define TIMER_CCER_CC1NP (1U << TIMER_CCER_CC1NP_BIT) +#define TIMER_CCER_CC1NE (1U << TIMER_CCER_CC1NE_BIT) +#define TIMER_CCER_CC1P (1U << TIMER_CCER_CC1P_BIT) +#define TIMER_CCER_CC1E (1U << TIMER_CCER_CC1E_BIT) + +/* Break and dead-time register (BDTR) */ + +#define TIMER_BDTR_MOE_BIT 15 +#define TIMER_BDTR_AOE_BIT 14 +#define TIMER_BDTR_BKP_BIT 13 +#define TIMER_BDTR_BKE_BIT 12 +#define TIMER_BDTR_OSSR_BIT 11 +#define TIMER_BDTR_OSSI_BIT 10 + +#define TIMER_BDTR_MOE (1U << TIMER_BDTR_MOE_BIT) +#define TIMER_BDTR_AOE (1U << TIMER_BDTR_AOE_BIT) +#define TIMER_BDTR_BKP (1U << TIMER_BDTR_BKP_BIT) +#define TIMER_BDTR_BKE (1U << TIMER_BDTR_BKE_BIT) +#define TIMER_BDTR_OSSR (1U << TIMER_BDTR_OSSR_BIT) +#define TIMER_BDTR_OSSI (1U << TIMER_BDTR_OSSI_BIT) +#define TIMER_BDTR_LOCK (0x3 << 8) +#define TIMER_BDTR_LOCK_OFF (0x0 << 8) +#define TIMER_BDTR_LOCK_LEVEL1 (0x1 << 8) +#define TIMER_BDTR_LOCK_LEVEL2 (0x2 << 8) +#define TIMER_BDTR_LOCK_LEVEL3 (0x3 << 8) +#define TIMER_BDTR_DTG 0xFF + +/* DMA control register (DCR) */ + +#define TIMER_DCR_DBL (0x1F << 8) +#define TIMER_DCR_DBL_1_XFER (0x0 << 8) +#define TIMER_DCR_DBL_2_XFER (0x1 << 8) +#define TIMER_DCR_DBL_3_XFER (0x2 << 8) +#define TIMER_DCR_DBL_4_XFER (0x3 << 8) +#define TIMER_DCR_DBL_5_XFER (0x4 << 8) +#define TIMER_DCR_DBL_6_XFER (0x5 << 8) +#define TIMER_DCR_DBL_7_XFER (0x6 << 8) +#define TIMER_DCR_DBL_8_XFER (0x7 << 8) +#define TIMER_DCR_DBL_9_XFER (0x8 << 8) +#define TIMER_DCR_DBL_10_XFER (0x9 << 8) +#define TIMER_DCR_DBL_11_XFER (0xA << 8) +#define TIMER_DCR_DBL_12_XFER (0xB << 8) +#define TIMER_DCR_DBL_13_XFER (0xC << 8) +#define TIMER_DCR_DBL_14_XFER (0xD << 8) +#define TIMER_DCR_DBL_15_XFER (0xE << 8) +#define TIMER_DCR_DBL_16_XFER (0xF << 8) +#define TIMER_DCR_DBL_17_XFER (0x10 << 8) +#define TIMER_DCR_DBL_18_XFER (0x11 << 8) +#define TIMER_DCR_DBA 0x1F +#define TIMER_DCR_DBA_CR1 0x0 +#define TIMER_DCR_DBA_CR2 0x1 +#define TIMER_DCR_DBA_SMCR 0x2 +#define TIMER_DCR_DBA_DIER 0x3 +#define TIMER_DCR_DBA_SR 0x4 +#define TIMER_DCR_DBA_EGR 0x5 +#define TIMER_DCR_DBA_CCMR1 0x6 +#define TIMER_DCR_DBA_CCMR2 0x7 +#define TIMER_DCR_DBA_CCER 0x8 +#define TIMER_DCR_DBA_CNT 0x9 +#define TIMER_DCR_DBA_PSC 0xA +#define TIMER_DCR_DBA_ARR 0xB +#define TIMER_DCR_DBA_RCR 0xC +#define TIMER_DCR_DBA_CCR1 0xD +#define TIMER_DCR_DBA_CCR2 0xE +#define TIMER_DCR_DBA_CCR3 0xF +#define TIMER_DCR_DBA_CCR4 0x10 +#define TIMER_DCR_DBA_BDTR 0x11 +#define TIMER_DCR_DBA_DCR 0x12 +#define TIMER_DCR_DBA_DMAR 0x13 + +/* + * Convenience routines + */ + +/** + * @brief Used to configure the behavior of a timer channel. + * + * Be careful: not all timers can be configured in every mode. + */ +typedef enum timer_mode { + /** + * The timer stops counting, channel interrupts are detached, and + * no state changes are output. */ + TIMER_DISABLED, + + /** PWM output. */ + TIMER_PWM, + + /* TIMER_PWM_CENTER_ALIGNED, TODO: Center-aligned PWM output mode. */ + + /** + * The timer counts from 0 to its reload value repeatedly; every + * time the counter value reaches one of the channel compare + * values, the corresponding interrupt is fired. */ + TIMER_OUTPUT_COMPARE, + + /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the + * pulse lengths of input signals */ + /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single + * pulse on a GPIO pin for a specified amount of + * time. */ +} timer_mode; + +/** Timer channel numbers */ +typedef enum timer_channel { + TIMER_CH1 = 1, /**< Channel 1 */ + TIMER_CH2 = 2, /**< Channel 2 */ + TIMER_CH3 = 3, /**< Channel 3 */ + TIMER_CH4 = 4 /**< Channel 4 */ +} timer_channel; + +/* + * Note: Don't require timer_channel arguments! We want to be able to say + * + * for (int channel = 1; channel <= 4; channel++) { + * ... + * } + * + * without the compiler yelling at us. + */ + +void timer_init(timer_dev *dev); +void timer_disable(timer_dev *dev); +void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode); +void timer_foreach(void (*fn)(timer_dev*)); +int timer_has_cc_channel(timer_dev *dev, uint8 channel); + +/** + * @brief Timer interrupt number. + * + * Not all timers support all of these values. All timers support + * TIMER_UPDATE_INTERRUPT. "General purpose" timers can be a special + * nuisance in this regard, as they individually support different + * subsets of the available interupts. Consult your target's reference + * manual for the details. + */ +typedef enum timer_interrupt_id { + TIMER_UPDATE_INTERRUPT, /**< Update interrupt. */ + TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt. */ + TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt. */ + TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt. */ + TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt. */ + TIMER_COM_INTERRUPT, /**< COM interrupt. */ + TIMER_TRG_INTERRUPT, /**< Trigger interrupt. */ + TIMER_BREAK_INTERRUPT, /**< Break interrupt. */ +} timer_interrupt_id; + +void timer_attach_interrupt(timer_dev *dev, + uint8 interrupt, + voidFuncPtr handler); +void timer_detach_interrupt(timer_dev *dev, uint8 interrupt); + +/** + * Initialize all timer devices on the chip. + */ +static inline void timer_init_all(void) { + timer_foreach(timer_init); +} + +/** + * Disables all timers on the device. + */ +static inline void timer_disable_all(void) { + timer_foreach(timer_disable); +} + +/** + * @brief Stop a timer's counter from changing. + * + * Does not affect the timer's mode or other settings. + * + * @param dev Device whose counter to pause. + */ +static inline void timer_pause(timer_dev *dev) { + *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 0; +} + +/** + * @brief Start a timer's counter. + * + * Does not affect the timer's mode or other settings. + * + * @param dev Device whose counter to resume + */ +static inline void timer_resume(timer_dev *dev) { + *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1; +} + +/** + * @brief Returns the timer's counter value. + * + * This value is likely to be inaccurate if the counter is running + * with a low prescaler. + * + * @param dev Timer whose counter to return + */ +static inline uint16 timer_get_count(timer_dev *dev) { + return (uint16)(dev->regs).bas->CNT; +} + +/** + * @brief Sets the counter value for the given timer. + * @param dev Timer whose counter to set + * @param value New counter value + */ +static inline void timer_set_count(timer_dev *dev, uint16 value) { + (dev->regs).bas->CNT = value; +} + +/** + * @brief Returns the given timer's prescaler. + * + * Note that if the timer's prescaler is set (e.g. via + * timer_set_prescaler() or accessing a TIMx_PSC register), the value + * returned by this function will reflect the new setting, but the + * timer's counter will only reflect the new prescaler at the next + * update event. + * + * @param dev Timer whose prescaler to return + * @see timer_generate_update() + */ +static inline uint16 timer_get_prescaler(timer_dev *dev) { + return (uint16)(dev->regs).bas->PSC; +} + +/** + * @brief Set a timer's prescale value. + * + * Divides the input clock by (PSC+1). The new value will not take + * effect until the next update event. + * + * @param dev Timer whose prescaler to set + * @param psc New prescaler value + * @see timer_generate_update() + */ +static inline void timer_set_prescaler(timer_dev *dev, uint16 psc) { + (dev->regs).bas->PSC = psc; +} + +/** + * @brief Returns a timer's reload value. + * @param dev Timer whose reload value to return + */ +static inline uint16 timer_get_reload(timer_dev *dev) { + return (uint16)(dev->regs).bas->ARR; +} + +/** + * @brief Set a timer's reload value. + * @param dev Timer whose reload value to set + * @param arr New reload value to use. Takes effect at next update event. + * @see timer_generate_update() + */ +static inline void timer_set_reload(timer_dev *dev, uint16 arr) { + (dev->regs).bas->ARR = arr; +} + +/** + * @brief Get the compare value for the given timer channel. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose compare value to get. + */ +static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { + __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + return *ccr; +} + +/** + * @brief Set the compare value for the given timer channel. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose compare value to set. + * @param value New compare value. + */ +static inline void timer_set_compare(timer_dev *dev, + uint8 channel, + uint16 value) { + __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + *ccr = value; +} + +/** + * @brief Generate an update event for the given timer. + * + * Normally, this will cause the prescaler and auto-reload values in + * the PSC and ARR registers to take immediate effect. However, this + * function will do nothing if the UDIS bit is set in the timer's CR1 + * register (UDIS is cleared by default). + * + * @param dev Timer device to generate an update for. + */ +static inline void timer_generate_update(timer_dev *dev) { + *bb_perip(&(dev->regs).bas->EGR, TIMER_EGR_UG_BIT) = 1; +} + +/** + * @brief Enable a timer's trigger DMA request + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL + */ +static inline void timer_dma_enable_trg_req(timer_dev *dev) { + *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 1; +} + +/** + * @brief Disable a timer's trigger DMA request + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL + */ +static inline void timer_dma_disable_trg_req(timer_dev *dev) { + *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 0; +} + +/** + * @brief Enable a timer channel's DMA request. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL + * @param channel Channel whose DMA request to enable. + */ +static inline void timer_dma_enable_req(timer_dev *dev, uint8 channel) { + *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 1; +} + +/** + * @brief Disable a timer channel's DMA request. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose DMA request to disable. + */ +static inline void timer_dma_disable_req(timer_dev *dev, uint8 channel) { + *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 0; +} + +/** + * @brief Enable a timer interrupt. + * @param dev Timer device. + * @param interrupt Interrupt number to enable; this may be any + * timer_interrupt_id value appropriate for the timer. + * @see timer_interrupt_id + * @see timer_channel + */ +static inline void timer_enable_irq(timer_dev *dev, uint8 interrupt) { + *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1; +} + +/** + * @brief Disable a timer interrupt. + * @param dev Timer device. + * @param interrupt Interrupt number to disable; this may be any + * timer_interrupt_id value appropriate for the timer. + * @see timer_interrupt_id + * @see timer_channel + */ +static inline void timer_disable_irq(timer_dev *dev, uint8 interrupt) { + *bb_perip(&(dev->regs).adv->DIER, interrupt) = 0; +} + +/** + * @brief Enable a timer channel's capture/compare signal. + * + * If the channel is configured as output, the corresponding output + * compare signal will be output on the corresponding output pin. If + * the channel is configured as input, enables capture of the counter + * value into the input capture/compare register. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel to enable, from 1 to 4. + */ +static inline void timer_cc_enable(timer_dev *dev, uint8 channel) { + *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 1; +} + +/** + * @brief Disable a timer channel's output compare or input capture signal. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel to disable, from 1 to 4. + * @see timer_cc_enable() + */ +static inline void timer_cc_disable(timer_dev *dev, uint8 channel) { + *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 0; +} + +/** + * @brief Get a channel's capture/compare output polarity + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose capture/compare output polarity to get. + * @return Polarity, either 0 or 1. + * @see timer_cc_set_polarity() + */ +static inline uint8 timer_cc_get_pol(timer_dev *dev, uint8 channel) { + return *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1); +} + +/** + * @brief Set a timer channel's capture/compare output polarity. + * + * If the timer channel is configured as output: polarity == 0 means + * the output channel will be active high; polarity == 1 means active + * low. + * + * If the timer channel is configured as input: polarity == 0 means + * capture is done on the rising edge of ICn; when used as an external + * trigger, ICn is non-inverted. polarity == 1 means capture is done + * on the falling edge of ICn; when used as an external trigger, ICn + * is inverted. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose capture/compare output polarity to set. + * @param pol New polarity, 0 or 1. + */ +static inline void timer_cc_set_pol(timer_dev *dev, uint8 channel, uint8 pol) { + *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1) = pol; +} + +/** + * @brief Get a timer's DMA burst length. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @return Number of transfers per read or write to timer DMA register, + * from 1 to 18. + */ +static inline uint8 timer_dma_get_burst_len(timer_dev *dev) { + uint32 dbl = ((dev->regs).gen->DCR & TIMER_DCR_DBL) >> 8; + return dbl + 1; /* 0 means 1 transfer, etc. */ +} + +/** + * @brief Set a timer's DMA burst length. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param length DMA burst length; i.e., number of DMA transfers per + * read/write to timer DMA register, from 1 to 18. + */ +static inline void timer_dma_set_burst_len(timer_dev *dev, uint8 length) { + uint32 tmp = (dev->regs).gen->DCR; + tmp &= ~TIMER_DCR_DBL; + tmp |= (length - 1) << 8; + (dev->regs).gen->DCR = tmp; +} + +/** + * @brief Timer DMA base address. + * + * Defines the base address for DMA transfers. + */ +typedef enum timer_dma_base_addr { + /** Base is control register 1 */ + TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1, + /** Base is control register 2 */ + TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2, + /** Base is slave mode control register */ + TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR, + /** Base is DMA interrupt enable register */ + TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER, + /** Base is status register */ + TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR, + /** Base is event generation register */ + TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR, + /** Base is capture/compare mode register 1 */ + TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1, + /** Base is capture/compare mode register 2 */ + TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2, + /** Base is capture/compare enable register */ + TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER, + /** Base is counter */ + TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT, + /** Base is prescaler */ + TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC, + /** Base is auto-reload register */ + TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR, + /** Base is repetition counter register */ + TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR, + /** Base is capture/compare register 1 */ + TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1, + /** Base is capture/compare register 2 */ + TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2, + /** Base is capture/compare register 3 */ + TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3, + /** Base is capture/compare register 4 */ + TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4, + /** Base is break and dead-time register */ + TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR, + /** Base is DMA control register */ + TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR, + /** Base is DMA address for full transfer */ + TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR, +} timer_dma_base_addr; + +/** + * @brief Get the timer's DMA base address. + * + * Some restrictions apply; see the reference manual for your chip. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @return DMA base address + */ +static inline timer_dma_base_addr timer_dma_get_base_addr(timer_dev *dev) { + uint32 dcr = (dev->regs).gen->DCR; + return (timer_dma_base_addr)(dcr & TIMER_DCR_DBA); +} + +/** + * @brief Set the timer's DMA base address. + * + * Some restrictions apply; see the reference manual for your chip. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param dma_base DMA base address. + */ +static inline void timer_dma_set_base_addr(timer_dev *dev, + timer_dma_base_addr dma_base) { + uint32 tmp = (dev->regs).gen->DCR; + tmp &= ~TIMER_DCR_DBA; + tmp |= dma_base; + (dev->regs).gen->DCR = tmp; +} + +/** + * Timer output compare modes. + */ +typedef enum timer_oc_mode { + /** + * Frozen: comparison between output compare register and counter + * has no effect on the outputs. */ + TIMER_OC_MODE_FROZEN = 0 << 4, + /** + * OCxREF signal is forced high when the count matches the channel + * capture/compare register. */ + TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4, + /** + * OCxREF signal is forced low when the counter matches the + * channel capture/compare register. */ + TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4, + /** + * OCxREF toggles when counter matches the channel capture/compare + * register. */ + TIMER_OC_MODE_TOGGLE = 3 << 4, + /** OCxREF is forced low. */ + TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4, + /** OCxREF is forced high. */ + TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4, + /** + * PWM mode 1. In upcounting, channel is active as long as count + * is less than channel capture/compare register, else inactive. + * In downcounting, channel is inactive as long as count exceeds + * capture/compare register, else active. */ + TIMER_OC_MODE_PWM_1 = 6 << 4, + /** + * PWM mode 2. In upcounting, channel is inactive as long as count + * is less than capture/compare register, else active. In + * downcounting, channel is active as long as count exceeds + * capture/compare register, else inactive. */ + TIMER_OC_MODE_PWM_2 = 7 << 4, +} timer_oc_mode; + +/** + * Timer output compare mode flags. + * @see timer_oc_set_mode() + */ +typedef enum timer_oc_mode_flags { + TIMER_OC_CE = 1U << 7, /**< Output compare clear enable. */ + TIMER_OC_PE = 1U << 3, /**< Output compare preload enable. */ + TIMER_OC_FE = 1U << 2, /**< Output compare fast enable. */ +} timer_oc_mode_flags; + +/** + * @brief Configure a channel's output compare mode. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel to configure in output compare mode. + * @param mode Timer mode to set. + * @param flags OR of timer_oc_mode_flags. + * @see timer_oc_mode + * @see timer_oc_mode_flags + */ +static inline void timer_oc_set_mode(timer_dev *dev, + uint8 channel, + timer_oc_mode mode, + uint8 flags) { + /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */ + __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + (((channel - 1) >> 1) & 1); + /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */ + uint8 shift = 8 * (1 - (channel & 1)); + + uint32 tmp = *ccmr; + tmp &= ~(0xFF << shift); + tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift; + *ccmr = tmp; +} + +/* + * Old, erroneous bit definitions from previous releases, kept for + * backwards compatibility: + */ + +/** Deprecated. Use TIMER_CCMR1_CC4S_OUTPUT instead. */ +#define TIMER_CCMR1_CC4S_OUTPUT TIMER_CCMR2_CC4S_OUTPUT +/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI1 instead. */ +#define TIMER_CCMR1_CC4S_INPUT_TI1 TIMER_CCMR2_CC4S_INPUT_TI1 +/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI2 instead. */ +#define TIMER_CCMR1_CC4S_INPUT_TI2 TIMER_CCMR2_CC4S_INPUT_TI2 +/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TRC instead. */ +#define TIMER_CCMR1_CC4S_INPUT_TRC TIMER_CCMR2_CC4S_INPUT_TRC +/** Deprecated. Use TIMER_CCMR2_IC4F instead. */ +#define TIMER_CCMR2_IC2F TIMER_CCMR2_IC4F +/** Deprecated. Use TIMER_CCMR2_IC4PSC instead. */ +#define TIMER_CCMR2_IC2PSC TIMER_CCMR2_IC4PSC +/** Deprecated. Use TIMER_CCMR2_IC3F instead. */ +#define TIMER_CCMR2_IC1F TIMER_CCMR2_IC3F +/** Deprecated. Use TIMER_CCMR2_IC3PSC instead. */ +#define TIMER_CCMR2_IC1PSC TIMER_CCMR2_IC3PSC +/** Deprecated. Use TIMER_CCMR1_CC3S_OUTPUT instead. */ +#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR2_CC3S_OUTPUT +/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI1 instead. */ +#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR2_CC3S_INPUT_TI1 +/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI2 instead. */ +#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR2_CC3S_INPUT_TI2 +/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TRC instead. */ +#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR2_CC3S_INPUT_TRC + +/** Deprecated. Use TIMER_DCR_DBL_1_XFER instead. */ +#define TIMER_DCR_DBL_1BYTE TIMER_DCR_DBL_1_XFER +/** Deprecated. Use TIMER_DCR_DBL_2_XFER instead. */ +#define TIMER_DCR_DBL_2BYTE TIMER_DCR_DBL_2_XFER +/** Deprecated. Use TIMER_DCR_DBL_3_XFER instead. */ +#define TIMER_DCR_DBL_3BYTE TIMER_DCR_DBL_3_XFER +/** Deprecated. Use TIMER_DCR_DBL_4_XFER instead. */ +#define TIMER_DCR_DBL_4BYTE TIMER_DCR_DBL_4_XFER +/** Deprecated. Use TIMER_DCR_DBL_5_XFER instead. */ +#define TIMER_DCR_DBL_5BYTE TIMER_DCR_DBL_5_XFER +/** Deprecated. Use TIMER_DCR_DBL_6_XFER instead. */ +#define TIMER_DCR_DBL_6BYTE TIMER_DCR_DBL_6_XFER +/** Deprecated. Use TIMER_DCR_DBL_7_XFER instead. */ +#define TIMER_DCR_DBL_7BYTE TIMER_DCR_DBL_7_XFER +/** Deprecated. Use TIMER_DCR_DBL_8_XFER instead. */ +#define TIMER_DCR_DBL_8BYTE TIMER_DCR_DBL_8_XFER +/** Deprecated. Use TIMER_DCR_DBL_9_XFER instead. */ +#define TIMER_DCR_DBL_9BYTE TIMER_DCR_DBL_9_XFER +/** Deprecated. Use TIMER_DCR_DBL_10_XFER instead. */ +#define TIMER_DCR_DBL_10BYTE TIMER_DCR_DBL_10_XFER +/** Deprecated. Use TIMER_DCR_DBL_11_XFER instead. */ +#define TIMER_DCR_DBL_11BYTE TIMER_DCR_DBL_11_XFER +/** Deprecated. Use TIMER_DCR_DBL_12_XFER instead. */ +#define TIMER_DCR_DBL_12BYTE TIMER_DCR_DBL_12_XFER +/** Deprecated. Use TIMER_DCR_DBL_13_XFER instead. */ +#define TIMER_DCR_DBL_13BYTE TIMER_DCR_DBL_13_XFER +/** Deprecated. Use TIMER_DCR_DBL_14_XFER instead. */ +#define TIMER_DCR_DBL_14BYTE TIMER_DCR_DBL_14_XFER +/** Deprecated. Use TIMER_DCR_DBL_15_XFER instead. */ +#define TIMER_DCR_DBL_15BYTE TIMER_DCR_DBL_15_XFER +/** Deprecated. Use TIMER_DCR_DBL_16_XFER instead. */ +#define TIMER_DCR_DBL_16BYTE TIMER_DCR_DBL_16_XFER +/** Deprecated. Use TIMER_DCR_DBL_17_XFER instead. */ +#define TIMER_DCR_DBL_17BYTE TIMER_DCR_DBL_17_XFER +/** Deprecated. Use TIMER_DCR_DBL_18_XFER instead. */ +#define TIMER_DCR_DBL_18BYTE TIMER_DCR_DBL_18_XFER + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/usart.h b/libmaple/include/libmaple/usart.h new file mode 100644 index 0000000..26a64d3 --- /dev/null +++ b/libmaple/include/libmaple/usart.h @@ -0,0 +1,495 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/usart.h + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> + * @brief USART definitions and prototypes + */ + +#ifndef _LIBMAPLE_USART_H_ +#define _LIBMAPLE_USART_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/util.h> +#include <libmaple/rcc.h> +#include <libmaple/nvic.h> +#include <libmaple/ring_buffer.h> +#include <series/usart.h> + +/* + * Register map (common across supported STM32 series). + */ + +/** USART register map type */ +typedef struct usart_reg_map { + __io uint32 SR; /**< Status register */ + __io uint32 DR; /**< Data register */ + __io uint32 BRR; /**< Baud rate register */ + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 CR3; /**< Control register 3 */ + __io uint32 GTPR; /**< Guard time and prescaler register */ +} usart_reg_map; + +/* + * Register bit definitions + */ + +/* Status register */ + +/** Clear to send bit */ +#define USART_SR_CTS_BIT 9 +/** Line break detection bit */ +#define USART_SR_LBD_BIT 8 +/** Transmit data register empty bit */ +#define USART_SR_TXE_BIT 7 +/** Transmission complete bit */ +#define USART_SR_TC_BIT 6 +/** Read data register not empty bit */ +#define USART_SR_RXNE_BIT 5 +/** IDLE line detected bit */ +#define USART_SR_IDLE_BIT 4 +/** Overrun error bit */ +#define USART_SR_ORE_BIT 3 +/** Noise error bit */ +#define USART_SR_NE_BIT 2 +/** + * @brief Synonym for USART_SR_NE_BIT. + * + * Some series (e.g. STM32F2) use "NF" for "noise flag" instead of the + * original "NE" for "noise error". The meaning of the bit is + * unchanged, but the NF flag can be disabled when the line is + * noise-free. + * + * @see USART_SR_NE_BIT + */ +#define USART_SR_NF_BIT USART_SR_NE_BIT +/** Framing error bit */ +#define USART_SR_FE_BIT 1 +/** Parity error bit */ +#define USART_SR_PE_BIT 0 + +/** Clear to send mask */ +#define USART_SR_CTS BIT(USART_SR_CTS_BIT) +/** Line break detected mask */ +#define USART_SR_LBD BIT(USART_SR_LBD_BIT) +/** Transmit data register empty mask */ +#define USART_SR_TXE BIT(USART_SR_TXE_BIT) +/** Transmission complete mask */ +#define USART_SR_TC BIT(USART_SR_TC_BIT) +/** Read data register not empty mask */ +#define USART_SR_RXNE BIT(USART_SR_RXNE_BIT) +/** IDLE line detected mask */ +#define USART_SR_IDLE BIT(USART_SR_IDLE_BIT) +/** Overrun error mask */ +#define USART_SR_ORE BIT(USART_SR_ORE_BIT) +/** Noise error mask */ +#define USART_SR_NE BIT(USART_SR_NE_BIT) +/** + * @brief Synonym for USART_SR_NE. + * @see USART_SR_NF_BIT + */ +#define USART_SR_NF USART_SR_NE +/** Framing error mask */ +#define USART_SR_FE BIT(USART_SR_FE_BIT) +/** Parity error mask */ +#define USART_SR_PE BIT(USART_SR_PE_BIT) + +/* Data register */ + +/** Data register data value mask */ +#define USART_DR_DR 0xFF + +/* Baud rate register */ + +/** Mantissa of USARTDIV mask */ +#define USART_BRR_DIV_MANTISSA (0xFFF << 4) +/** Fraction of USARTDIV mask */ +#define USART_BRR_DIV_FRACTION 0xF + +/* Control register 1 */ + +/** USART enable bit */ +#define USART_CR1_UE_BIT 13 +/** Word length bit */ +#define USART_CR1_M_BIT 12 +/** Wakeup method bit */ +#define USART_CR1_WAKE_BIT 11 +/** Parity control enable bit */ +#define USART_CR1_PCE_BIT 10 +/** Parity selection bit */ +#define USART_CR1_PS_BIT 9 +/** Parity error interrupt enable bit */ +#define USART_CR1_PEIE_BIT 8 +/** Transmit data regsiter not empty interrupt enable bit */ +#define USART_CR1_TXEIE_BIT 7 +/** Transmission complete interrupt enable bit */ +#define USART_CR1_TCIE_BIT 6 +/** RXNE interrupt enable bit */ +#define USART_CR1_RXNEIE_BIT 5 +/** IDLE interrupt enable bit */ +#define USART_CR1_IDLEIE_BIT 4 +/** Transmitter enable bit */ +#define USART_CR1_TE_BIT 3 +/** Receiver enable bit */ +#define USART_CR1_RE_BIT 2 +/** Receiver wakeup bit */ +#define USART_CR1_RWU_BIT 1 +/** Send break bit */ +#define USART_CR1_SBK_BIT 0 + +/** USART enable mask */ +#define USART_CR1_UE BIT(USART_CR1_UE_BIT) +/** Word length mask */ +#define USART_CR1_M BIT(USART_CR1_M_BIT) +/** Word length: 1 start bit, 8 data bits, n stop bit */ +#define USART_CR1_M_8N1 (0 << USART_CR1_M_BIT) +/** Word length: 1 start bit, 9 data bits, n stop bit */ +#define USART_CR1_M_9N1 (1 << USART_CR1_M_BIT) +/** Wakeup method mask */ +#define USART_CR1_WAKE BIT(USART_CR1_WAKE_BIT) +/** Wakeup on idle line */ +#define USART_CR1_WAKE_IDLE (0 << USART_CR1_WAKE_BIT) +/** Wakeup on address mark */ +#define USART_CR1_WAKE_ADDR (1 << USART_CR1_WAKE_BIT) +/** Parity control enable mask */ +#define USART_CR1_PCE BIT(USART_CR1_PCE_BIT) +/** Parity selection mask */ +#define USART_CR1_PS BIT(USART_CR1_PS_BIT) +/** Parity selection: even parity */ +#define USART_CR1_PS_EVEN (0 << USART_CR1_PS_BIT) +/** Parity selection: odd parity */ +#define USART_CR1_PS_ODD (1 << USART_CR1_PS_BIT) +/** Parity error interrupt enable mask */ +#define USART_CR1_PEIE BIT(USART_CR1_PEIE_BIT) +/** Transmit data register empty interrupt enable mask */ +#define USART_CR1_TXEIE BIT(USART_CR1_TXEIE_BIT) +/** Transmission complete interrupt enable mask */ +#define USART_CR1_TCIE BIT(USART_CR1_TCIE_BIT) +/** RXNE interrupt enable mask */ +#define USART_CR1_RXNEIE BIT(USART_CR1_RXNEIE_BIT) +/** IDLE line interrupt enable mask */ +#define USART_CR1_IDLEIE BIT(USART_CR1_IDLEIE_BIT) +/** Transmitter enable mask */ +#define USART_CR1_TE BIT(USART_CR1_TE_BIT) +/** Receiver enable mask */ +#define USART_CR1_RE BIT(USART_CR1_RE_BIT) +/** Receiver wakeup mask */ +#define USART_CR1_RWU BIT(USART_CR1_RWU_BIT) +/** Receiver wakeup: receiver in active mode */ +#define USART_CR1_RWU_ACTIVE (0 << USART_CR1_RWU_BIT) +/** Receiver wakeup: receiver in mute mode */ +#define USART_CR1_RWU_MUTE (1 << USART_CR1_RWU_BIT) +/** Send break */ +#define USART_CR1_SBK BIT(USART_CR1_SBK_BIT) + +/* Control register 2 */ + +/** LIN mode enable bit */ +#define USART_CR2_LINEN_BIT 14 +/** Clock enable bit */ +#define USART_CR2_CLKEN_BIT 11 +/** Clock polarity bit */ +#define USART_CR2_CPOL_BIT 10 +/** Clock phase bit */ +#define USART_CR2_CPHA_BIT 9 +/** Last bit clock pulse bit */ +#define USART_CR2_LBCL_BIT 8 +/** LIN break detection interrupt enable bit */ +#define USART_CR2_LBDIE_BIT 6 +/** LIN break detection length bit */ +#define USART_CR2_LBDL_BIT 5 + +/** LIN mode enable mask */ +#define USART_CR2_LINEN BIT(USART_CR2_LINEN_BIT) +/** STOP bits mask */ +#define USART_CR2_STOP (0x3 << 12) +/** STOP bits: 1 stop bit */ +#define USART_CR2_STOP_BITS_1 (0x0 << 12) +/** + * @brief STOP bits: 0.5 stop bits + * Not available on UART4, UART5. */ +#define USART_CR2_STOP_BITS_POINT_5 (0x1 << 12) +/** STOP bits: 2 stop bits */ +#define USART_CR2_STOP_BITS_2 (0x2 << 12) +/** + * @brief STOP bits: 1.5 stop bits + * Not available on UART4, UART5. */ +#define USART_CR2_STOP_BITS_1_POINT_5 (0x3 << 12) +/** + * @brief Clock enable. + * Not available on UART4, UART5 */ +#define USART_CR2_CLKEN BIT(USART_CR2_CLKEN_BIT) +/** + * @brief Clock polarity mask. + * Not available on UART4, UART5 */ +#define USART_CR2_CPOL BIT(USART_CR2_CPOL_BIT) +/** Clock polarity: low */ +#define USART_CR2_CPOL_LOW (0x0 << USART_CR2_CLKEN_BIT) +/** Clock polarity: high */ +#define USART_CR2_CPOL_HIGH (0x1 << USART_CR2_CLKEN_BIT) +/** + * @brief Clock phase mask. + * Not available on UART4, UART5 */ +#define USART_CR2_CPHA BIT(USART_CR2_CPHA_BIT) +/** + * @brief Clock phase: first + * First clock transition is the first data capture edge. */ +#define USART_CR2_CPHA_FIRST (0x0 << USART_CR2_CPHA_BIT) +/** + * @brief Clock phase: second + * Second clock transition is the first data capture edge. */ +#define USART_CR2_CPHA_SECOND (0x1 << USART_CR2_CPHA_BIT) +/** + * @brief Last bit clock pulse mask. + * + * When set, the last bit transmitted causes a clock pulse in + * synchronous mode. + * + * Not available on UART4, UART5 */ +#define USART_CR2_LBCL BIT(USART_CR2_LBCL_BIT) +/** LIN break detection interrupt enable mask. */ +#define USART_CR2_LBDIE BIT(USART_CR2_LBDIE_BIT) +/** LIN break detection length. */ +#define USART_CR2_LBDL BIT(USART_CR2_LBDL_BIT) +/** LIN break detection length: 10 bits */ +#define USART_CR2_LBDL_10_BIT (0 << USART_CR2_LBDL_BIT) +/** LIN break detection length: 11 bits */ +#define USART_CR2_LBDL_11_BIT (1 << USART_CR2_LBDL_BIT) +/** + * @brief Address of the USART node + * This is useful during multiprocessor communication. */ +#define USART_CR2_ADD 0xF + +/* Control register 3 */ + +/** Clear to send interrupt enable bit */ +#define USART_CR3_CTSIE_BIT 10 +/** Clear to send enable bit */ +#define USART_CR3_CTSE_BIT 9 +/** Ready to send enable bit */ +#define USART_CR3_RTSE_BIT 8 +/** DMA enable transmitter bit */ +#define USART_CR3_DMAT_BIT 7 +/** DMA enable receiver bit */ +#define USART_CR3_DMAR_BIT 6 +/** Smartcard mode enable bit */ +#define USART_CR3_SCEN_BIT 5 +/** Smartcard NACK enable bit */ +#define USART_CR3_NACK_BIT 4 +/** Half-duplex selection bit */ +#define USART_CR3_HDSEL_BIT 3 +/** IrDA low power bit */ +#define USART_CR3_IRLP_BIT 2 +/** IrDA mode enable bit */ +#define USART_CR3_IREN_BIT 1 +/** Error interrupt enable bit */ +#define USART_CR3_EIE_BIT 0 + +/** + * @brief Clear to send interrupt enable + * Not available on UART4, UART5. */ +#define USART_CR3_CTSIE BIT(USART_CR3_CTSIE_BIT) +/** + * @brief Clear to send enable + * Not available on UART4, UART5. */ +#define USART_CR3_CTSE BIT(USART_CR3_CTSE_BIT) +/** + * @brief Ready to send enable + * Not available on UART4, UART5. */ +#define USART_CR3_RTSE BIT(USART_CR3_RTSE_BIT) +/** + * @brief DMA enable transmitter + * Not available on UART5. */ +#define USART_CR3_DMAT BIT(USART_CR3_DMAT_BIT) +/** + * @brief DMA enable receiver + * Not available on UART5. */ +#define USART_CR3_DMAR BIT(USART_CR3_DMAR_BIT) +/** + * @brief Smartcard mode enable + * Not available on UART4, UART5. */ +#define USART_CR3_SCEN BIT(USART_CR3_SCEN_BIT) +/** + * @brief Smartcard NACK enable + * Not available on UART4, UART5. */ +#define USART_CR3_NACK BIT(USART_CR3_NACK_BIT) +/** + * @brief Half-duplex selection + * When set, single-wire half duplex mode is selected. + */ +#define USART_CR3_HDSEL BIT(USART_CR3_HDSEL_BIT) +/** IrDA low power mode */ +#define USART_CR3_IRLP BIT(USART_CR3_IRLP_BIT) +/** IrDA mode: normal */ +#define USART_CR3_IRLP_NORMAL (0U << USART_CR3_IRLP_BIT) +/** IrDA mode: low power */ +#define USART_CR3_IRLP_LOW_POWER (1U << USART_CR3_IRLP_BIT) +/** IrDA mode enable */ +#define USART_CR3_IREN BIT(USART_CR3_IREN_BIT) +/** Error interrupt enable */ +#define USART_CR3_EIE BIT(USART_CR3_EIE_BIT) + +/* Guard time and prescaler register */ + +/** + * @brief Guard time value mask + * Used in Smartcard mode. Not available on UART4, UART5. */ +#define USART_GTPR_GT (0xFF << 8) +/** + * @brief Prescaler value mask + * Restrictions on this value apply, depending on the USART mode. Not + * available on UART4, UART5. */ +#define USART_GTPR_PSC 0xFF + +/* + * Devices + */ + +#ifndef USART_RX_BUF_SIZE +#define USART_RX_BUF_SIZE 64 +#endif + +/** USART device type */ +typedef struct usart_dev { + usart_reg_map *regs; /**< Register map */ + ring_buffer *rb; /**< RX ring buffer */ + uint32 max_baud; /**< @brief Deprecated. + * Maximum baud rate. */ + uint8 rx_buf[USART_RX_BUF_SIZE]; /**< @brief Deprecated. + * Actual RX buffer used by rb. + * This field will be removed in + * a future release. */ + rcc_clk_id clk_id; /**< RCC clock information */ + nvic_irq_num irq_num; /**< USART NVIC interrupt */ +} usart_dev; + +void usart_init(usart_dev *dev); + +struct gpio_dev; /* forward declaration */ +/* FIXME [PRE 0.0.13] decide if flags are necessary */ +/** + * @brief Configure GPIOs for use as USART TX/RX. + * @param udev USART device to use + * @param rx_dev RX pin gpio_dev + * @param rx RX pin bit on rx_dev + * @param tx_dev TX pin gpio_dev + * @param tx TX pin bit on tx_dev + * @param flags Currently ignored + */ +extern void usart_config_gpios_async(usart_dev *udev, + struct gpio_dev *rx_dev, uint8 rx, + struct gpio_dev *tx_dev, uint8 tx, + unsigned flags); + +#define USART_USE_PCLK 0 +void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud); + +void usart_enable(usart_dev *dev); +void usart_disable(usart_dev *dev); +void usart_foreach(void (*fn)(usart_dev *dev)); +uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len); +uint32 usart_rx(usart_dev *dev, uint8 *buf, uint32 len); +void usart_putudec(usart_dev *dev, uint32 val); + +/** + * @brief Disable all serial ports. + */ +static inline void usart_disable_all(void) { + usart_foreach(usart_disable); +} + +/** + * @brief Transmit one character on a serial port. + * + * This function blocks until the character has been successfully + * transmitted. + * + * @param dev Serial port to send on. + * @param byte Byte to transmit. + */ +static inline void usart_putc(usart_dev* dev, uint8 byte) { + while (!usart_tx(dev, &byte, 1)) + ; +} + +/** + * @brief Transmit a character string on a serial port. + * + * This function blocks until str is completely transmitted. + * + * @param dev Serial port to send on + * @param str String to send + */ +static inline void usart_putstr(usart_dev *dev, const char* str) { + uint32 i = 0; + while (str[i] != '\0') { + usart_putc(dev, str[i++]); + } +} + +/** + * @brief Read one character from a serial port. + * + * It's not safe to call this function if the serial port has no data + * available. + * + * @param dev Serial port to read from + * @return byte read + * @see usart_data_available() + */ +static inline uint8 usart_getc(usart_dev *dev) { + return rb_remove(dev->rb); +} + +/** + * @brief Return the amount of data available in a serial port's RX buffer. + * @param dev Serial port to check + * @return Number of bytes in dev's RX buffer. + */ +static inline uint32 usart_data_available(usart_dev *dev) { + return rb_full_count(dev->rb); +} + +/** + * @brief Discard the contents of a serial port's RX buffer. + * @param dev Serial port whose buffer to empty. + */ +static inline void usart_reset_rx(usart_dev *dev) { + rb_reset(dev->rb); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/usb.h b/libmaple/include/libmaple/usb.h new file mode 100644 index 0000000..8555aca --- /dev/null +++ b/libmaple/include/libmaple/usb.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010, 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* + * NOTE: This API is _unstable_ and will change drastically over time. + */ + +#ifndef _LIBMAPLE_USB_H_ +#define _LIBMAPLE_USB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> + +#ifndef USB_ISR_MSK +/* Handle CTRM, WKUPM, SUSPM, ERRM, SOFM, ESOFM, RESETM */ +#define USB_ISR_MSK 0xBF00 +#endif + +typedef enum usb_dev_state { + USB_UNCONNECTED, + USB_ATTACHED, + USB_POWERED, + USB_SUSPENDED, + USB_ADDRESSED, + USB_CONFIGURED +} usb_dev_state; + +/* Encapsulates global state formerly handled by usb_lib/ */ +typedef struct usblib_dev { + uint32 irq_mask; + void (**ep_int_in)(void); + void (**ep_int_out)(void); + usb_dev_state state; + rcc_clk_id clk_id; +} usblib_dev; + +extern usblib_dev *USBLIB; + +void usb_init_usblib(usblib_dev *dev, + void (**ep_int_in)(void), + void (**ep_int_out)(void)); + +static inline uint8 usb_is_connected(usblib_dev *dev) { + return dev->state != USB_UNCONNECTED; +} + +static inline uint8 usb_is_configured(usblib_dev *dev) { + return dev->state == USB_CONFIGURED; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/usb_cdcacm.h b/libmaple/include/libmaple/usb_cdcacm.h new file mode 100644 index 0000000..9d70758 --- /dev/null +++ b/libmaple/include/libmaple/usb_cdcacm.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/usb_cdcacm.h + * @brief USB CDC ACM (virtual serial terminal) support + */ + +#ifndef _LIBMAPLE_USB_CDCACM_H_ +#define _LIBMAPLE_USB_CDCACM_H_ + +#include <libmaple/libmaple_types.h> +#include <libmaple/gpio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +void usb_cdcacm_enable(gpio_dev*, uint8); +void usb_cdcacm_disable(gpio_dev*, uint8); + +void usb_cdcacm_putc(char ch); +uint32 usb_cdcacm_tx(const uint8* buf, uint32 len); +uint32 usb_cdcacm_rx(uint8* buf, uint32 len); + +uint32 usb_cdcacm_data_available(void); /* in RX buffer */ +uint16 usb_cdcacm_get_pending(void); + +uint8 usb_cdcacm_get_dtr(void); +uint8 usb_cdcacm_get_rts(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/util.h b/libmaple/include/libmaple/util.h new file mode 100644 index 0000000..5a70348 --- /dev/null +++ b/libmaple/include/libmaple/util.h @@ -0,0 +1,111 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/util.h + * @brief Miscellaneous utility macros and procedures. + */ + +#ifndef _LIBMAPLE_UTIL_H_ +#define _LIBMAPLE_UTIL_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/* + * Bit manipulation + */ + +/** 1UL shifted left by 'shift' */ +#define BIT(shift) (1UL << (shift)) +/** 'Mask' shifted left by 'shift' */ +#define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift)) +/** Bits m to n of x */ +#define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m))) +/** True iff v is a power of two (1, 2, 4, 8, ...) */ +#define IS_POWER_OF_TWO(v) ((v) && !((v) & ((v) - 1))) + +/* + * Failure routines + */ + +void __error(void); +void _fail(const char*, int, const char*); +void throb(void); + +/* + * Asserts and debug levels + */ + +#define DEBUG_NONE 0 +#define DEBUG_FAULT 1 +#define DEBUG_ALL 2 + +/** + * \def DEBUG_LEVEL + * + * Controls the level of assertion checking. + * + * The higher the debug level, the more assertions will be compiled + * in. This increases the amount of debugging information, but slows + * down (and increases the size of) the binary. + * + * The debug levels, from lowest to highest, are DEBUG_NONE, + * DEBUG_FAULT, and DEBUG_ALL. The default level is DEBUG_ALL. + */ + +#ifndef DEBUG_LEVEL +#define DEBUG_LEVEL DEBUG_ALL +#endif + +#if DEBUG_LEVEL >= DEBUG_ALL +#define ASSERT(exp) \ + if (exp) { \ + } else { \ + _fail(__FILE__, __LINE__, #exp); \ + } +#else +#define ASSERT(exp) (void)((0)) +#endif + +#if DEBUG_LEVEL >= DEBUG_FAULT +#define ASSERT_FAULT(exp) \ + if (exp) { \ + } else { \ + _fail(__FILE__, __LINE__, #exp); \ + } +#else +#define ASSERT_FAULT(exp) (void)((0)) +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif |