diff options
Diffstat (limited to 'libmaple')
125 files changed, 14124 insertions, 4220 deletions
diff --git a/libmaple/adc.c b/libmaple/adc.c index 2bd2ad1..acce923 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -25,44 +25,15 @@ *****************************************************************************/ /** - * @file adc.c - * + * @file libmaple/adc.c + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> * @brief Analog to digital converter routines - * - * IMPORTANT: maximum external impedance must be below 0.4kOhms for 1.5 - * sample conversion time. - * - * At 55.5 cycles/sample, the external input impedance < 50kOhms. - * - * See STM32 manual RM0008 for how to calculate this. */ -#include "libmaple.h" -#include "rcc.h" -#include "adc.h" - -static adc_dev adc1 = { - .regs = ADC1_BASE, - .clk_id = RCC_ADC1 -}; -/** ADC1 device. */ -const adc_dev *ADC1 = &adc1; - -static adc_dev adc2 = { - .regs = ADC2_BASE, - .clk_id = RCC_ADC2 -}; -/** ADC2 device. */ -const adc_dev *ADC2 = &adc2; - -#ifdef STM32_HIGH_DENSITY -adc_dev adc3 = { - .regs = ADC3_BASE, - .clk_id = RCC_ADC3 -}; -/** ADC3 device. */ -const adc_dev *ADC3 = &adc3; -#endif +#include <libmaple/adc.h> +#include <libmaple/libmaple.h> +#include <libmaple/rcc.h> /** * @brief Initialize an ADC peripheral. @@ -91,20 +62,10 @@ void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) { } /** - * @brief Call a function on all ADC devices. - * @param fn Function to call on each ADC device. - */ -void adc_foreach(void (*fn)(const adc_dev*)) { - fn(ADC1); - fn(ADC2); -#ifdef STM32_HIGH_DENSITY - fn(ADC3); -#endif -} - -/** - * @brief Turn the given sample rate into values for ADC_SMPRx. Don't - * call this during conversion. + * @brief Set the sample rate for all channels on an ADC device. + * + * Don't call this during conversion. + * * @param dev adc device * @param smp_rate sample rate to set * @see adc_smp_rate @@ -127,25 +88,8 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { } /** - * @brief Calibrate an ADC peripheral - * @param dev adc device - */ -void adc_calibrate(const adc_dev *dev) { - __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); - __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); - - *rstcal_bit = 1; - while (*rstcal_bit) - ; - - *cal_bit = 1; - while (*cal_bit) - ; -} - -/** * @brief Perform a single synchronous software triggered conversion on a - * channel. + * channel. * @param dev ADC device to use for reading. * @param channel channel to convert * @return conversion result diff --git a/libmaple/dac.c b/libmaple/dac.c index 15e944f..d802d2b 100644 --- a/libmaple/dac.c +++ b/libmaple/dac.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Bryan Newbold. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,25 +26,20 @@ *****************************************************************************/ /** - * @file dac.c + * @file libmaple/dac.c * @brief Digital to analog converter support. */ -#include "libmaple.h" -#include "gpio.h" -#include "dac.h" - -#ifdef STM32_HIGH_DENSITY - -/** - * @brief DAC peripheral routines. - */ +#include <libmaple/dac.h> +#include <libmaple/libmaple.h> +#include <libmaple/gpio.h> +#if STM32_HAVE_DAC dac_dev dac = { .regs = DAC_BASE, }; -/** DAC device. */ const dac_dev *DAC = &dac; +#endif /** * @brief Initialize the digital to analog converter @@ -92,16 +88,16 @@ void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val) { */ void dac_enable_channel(const dac_dev *dev, uint8 channel) { /* - * Setup ANALOG mode on PA4 and PA5. This mapping is consistent across - * all STM32 chips with a DAC. See RM0008 12.2. + * Setup ANALOG mode on PA4 and PA5. This mapping is consistent + * across all supported STM32s with a DAC. */ switch (channel) { case 1: - gpio_set_mode(GPIOA, 4, GPIO_INPUT_ANALOG); + gpio_set_mode(GPIOA, 4, GPIO_MODE_ANALOG); dev->regs->CR |= DAC_CR_EN1; break; case 2: - gpio_set_mode(GPIOA, 5, GPIO_INPUT_ANALOG); + gpio_set_mode(GPIOA, 5, GPIO_MODE_ANALOG); dev->regs->CR |= DAC_CR_EN2; break; } @@ -122,5 +118,3 @@ void dac_disable_channel(const dac_dev *dev, uint8 channel) { break; } } - -#endif /* STM32_HIGH_DENSITY */ diff --git a/libmaple/dac.h b/libmaple/dac.h deleted file mode 100644 index aa04981..0000000 --- a/libmaple/dac.h +++ /dev/null @@ -1,168 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Bryan Newbold. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file dac.h - * @brief Digital to analog converter support. - */ - -/* See notes/dac.txt for more info */ - -#ifndef _DAC_H_ -#define _DAC_H_ - -#include "rcc.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * Register maps - */ - -/** DAC register map. */ -typedef struct dac_reg_map { - __io uint32 CR; /**< Control register */ - __io uint32 SWTRIGR; /**< Software trigger register */ - __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data - holding register */ - __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data - holding register */ - __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data - holding register */ - __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data - holding register */ - __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data - holding register */ - __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data - holding register */ - __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data - holding register */ - __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data - holding register */ - __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding - register */ - __io uint32 DOR1; /**< Channel 1 data output register */ - __io uint32 DOR2; /**< Channel 2 data output register */ -} dac_reg_map; - -/** DAC register map base address */ -#define DAC_BASE ((struct dac_reg_map*)0x40007400) - -/* - * Devices - */ - -/** DAC device type. */ -typedef struct dac_dev { - dac_reg_map *regs; /**< Register map */ -} dac_dev; - -extern const dac_dev *DAC; - -/* - * Register bit definitions - */ - -/* Control register */ -/* Channel 1 control */ -#define DAC_CR_EN1 BIT(0) /* Enable */ -#define DAC_CR_BOFF1 BIT(1) /* Output buffer disable */ -#define DAC_CR_TEN1 BIT(2) /* Trigger enable */ -#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */ -#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave enable */ -#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */ -#define DAC_CR_DMAEN1 BIT(12) /* DMA enable */ -/* Channel 2 control */ -#define DAC_CR_EN2 BIT(16) /* Enable */ -#define DAC_CR_BOFF2 BIT(17) /* Output buffer disable */ -#define DAC_CR_TEN2 BIT(18) /* Trigger enable */ -#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */ -#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave generation*/ -#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */ -#define DAC_CR_DMAEN2 BIT(28) /* DMA enable */ - -/* Software trigger register */ -#define DAC_SWTRIGR_SWTRIG1 BIT(0) /* Channel 1 software trigger */ -#define DAC_SWTRIGR_SWTRIG2 BIT(1) /* Channel 2 software trigger */ - -/* Channel 1 12-bit right-aligned data holding register */ -#define DAC_DHR12R1_DACC1DHR 0x00000FFF - -/* Channel 1 12-bit left-aligned data holding register */ -#define DAC_DHR12L1_DACC1DHR 0x0000FFF0 - -/* Channel 1 8-bit left-aligned data holding register */ -#define DAC_DHR8R1_DACC1DHR 0x000000FF - -/* Channel 2 12-bit right-aligned data holding register */ -#define DAC_DHR12R2_DACC2DHR 0x00000FFF - -/* Channel 2 12-bit left-aligned data holding register */ -#define DAC_DHR12L2_DACC2DHR 0x0000FFF0 - -/* Channel 2 8-bit left-aligned data holding register */ -#define DAC_DHR8R2_DACC2DHR 0x000000FF - -/* Dual DAC 12-bit right-aligned data holding register */ -#define DAC_DHR12RD_DACC1DHR 0x00000FFF -#define DAC_DHR12RD_DACC2DHR 0x0FFF0000 - -/* Dual DAC 12-bit left-aligned data holding register */ -#define DAC_DHR12LD_DACC1DHR 0x0000FFF0 -#define DAC_DHR12LD_DACC2DHR 0xFFF00000 - -/* Dual DAC 8-bit left-aligned data holding register */ -#define DAC_DHR8RD_DACC1DHR 0x000000FF -#define DAC_DHR8RD_DACC2DHR 0x0000FF00 - -/* Channel 1 data output register */ -#define DAC_DOR1_DACC1DOR 0x00000FFF - -/* Channel 1 data output register */ -#define DAC_DOR2_DACC2DOR 0x00000FFF - -/* - * Convenience functions - */ - -/* We take the dev argument in these convenience functions for - * future-proofing */ - -#define DAC_CH1 0x1 -#define DAC_CH2 0x2 -void dac_init(const dac_dev *dev, uint32 flags); - -void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val); -void dac_enable_channel(const dac_dev *dev, uint8 channel); -void dac_disable_channel(const dac_dev *dev, uint8 channel); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/libmaple/delay.h b/libmaple/delay.h deleted file mode 100644 index 6f8b8ba..0000000 --- a/libmaple/delay.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file delay.h - * @brief Delay implementation - */ - -#include "libmaple_types.h" -#include "stm32.h" - -#ifndef _DELAY_H_ -#define _DELAY_H_ - -/** - * @brief Delay the given number of microseconds. - * - * @param us Number of microseconds to delay. - */ -static inline void delay_us(uint32 us) { - us *= STM32_DELAY_US_MULT; - - /* fudge for function call overhead */ - us--; - asm volatile(" mov r0, %[us] \n\t" - "1: subs r0, #1 \n\t" - " bhi 1b \n\t" - : - : [us] "r" (us) - : "r0"); -} -#endif - diff --git a/libmaple/dma.c b/libmaple/dma.c index 60f4d47..d13de10 100644 --- a/libmaple/dma.c +++ b/libmaple/dma.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Michael Hope. + * Copyright (c) 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,47 +26,15 @@ *****************************************************************************/ /** - * @file dma.c + * @file libmaple/dma.c * @author Marti Bolivar <mbolivar@leaflabs.com>; * Original implementation by Michael Hope - * @brief Direct Memory Access peripheral support + * @brief Portable DMA routines. */ -#include "dma.h" -#include "bitband.h" -#include "util.h" - -/* - * Devices - */ - -static dma_dev dma1 = { - .regs = DMA1_BASE, - .clk_id = RCC_DMA1, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH4 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH5 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH6 }, - { .handler = NULL, .irq_line = NVIC_DMA_CH7 }} -}; -/** DMA1 device */ -dma_dev *DMA1 = &dma1; - -#ifdef STM32_HIGH_DENSITY -static dma_dev dma2 = { - .regs = DMA2_BASE, - .clk_id = RCC_DMA2, - .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH2 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH3 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }, - { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }} /* !@#$ */ -}; -/** DMA2 device */ -dma_dev *DMA2 = &dma2; -#endif +#include <libmaple/dma.h> +#include "dma_private.h" +#include "stm32_private.h" /* * Convenience routines @@ -79,301 +48,35 @@ void dma_init(dma_dev *dev) { rcc_clk_enable(dev->clk_id); } -/** - * @brief Set up a DMA transfer. - * - * The channel will be disabled before being reconfigured. The - * transfer will have low priority by default. You may choose another - * priority before the transfer begins using dma_set_priority(), as - * well as performing any other configuration you desire. When the - * channel is configured to your liking, enable it using dma_enable(). - * - * @param dev DMA device. - * @param channel DMA channel. - * @param peripheral_address Base address of peripheral data register - * involved in the transfer. - * @param peripheral_size Peripheral data transfer size. - * @param memory_address Base memory address involved in the transfer. - * @param memory_size Memory data transfer size. - * @param mode Logical OR of dma_mode_flags - * @sideeffect Disables the given DMA channel. - * @see dma_xfer_size - * @see dma_mode_flags - * @see dma_set_num_transfers() - * @see dma_set_priority() - * @see dma_attach_interrupt() - * @see dma_enable() - */ -void dma_setup_transfer(dma_dev *dev, - dma_channel channel, - __io void *peripheral_address, - dma_xfer_size peripheral_size, - __io void *memory_address, - dma_xfer_size memory_size, - uint32 mode) { - dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel); - - dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */ - channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode; - channel_regs->CMAR = (uint32)memory_address; - channel_regs->CPAR = (uint32)peripheral_address; -} - -/** - * @brief Set the number of data to be transferred on a DMA channel. - * - * You may not call this function while the channel is enabled. - * - * @param dev DMA device - * @param channel Channel through which the transfer occurs. - * @param num_transfers - */ -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers) { - dma_channel_reg_map *channel_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - channel_regs->CNDTR = num_transfers; -} - -/** - * @brief Set the priority of a DMA transfer. - * - * You may not call this function while the channel is enabled. - * - * @param dev DMA device - * @param channel DMA channel - * @param priority priority to set. - */ -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority) { - dma_channel_reg_map *channel_regs; - uint32 ccr; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - channel_regs = dma_channel_regs(dev, channel); - ccr = channel_regs->CCR; - ccr &= ~DMA_CCR_PL; - ccr |= priority; - channel_regs->CCR = ccr; -} - -/** - * @brief Attach an interrupt to a DMA transfer. - * - * Interrupts are enabled using appropriate mode flags in - * dma_setup_transfer(). - * - * @param dev DMA device - * @param channel Channel to attach handler to - * @param handler Interrupt handler to call when channel interrupt fires. - * @see dma_setup_transfer() - * @see dma_get_irq_cause() - * @see dma_detach_interrupt() - */ -void dma_attach_interrupt(dma_dev *dev, - dma_channel channel, - void (*handler)(void)) { - dev->handlers[channel - 1].handler = handler; - nvic_irq_enable(dev->handlers[channel - 1].irq_line); -} - -/** - * @brief Detach a DMA transfer interrupt handler. - * - * After calling this function, the given channel's interrupts will be - * disabled. - * - * @param dev DMA device - * @param channel Channel whose handler to detach - * @sideeffect Clears interrupt enable bits in the channel's CCR register. - * @see dma_attach_interrupt() - */ -void dma_detach_interrupt(dma_dev *dev, dma_channel channel) { - /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */ - dma_channel_regs(dev, channel)->CCR &= ~0xF; - dev->handlers[channel - 1].handler = NULL; -} - -/** - * @brief Discover the reason why a DMA interrupt was called. - * - * You may only call this function within an attached interrupt - * handler for the given channel. - * - * This function resets the internal DMA register state which encodes - * the cause of the interrupt; consequently, it can only be called - * once per interrupt handler invocation. - * - * @param dev DMA device - * @param channel Channel whose interrupt is being handled. - * @return Reason why the interrupt fired. - * @sideeffect Clears channel status flags in dev->regs->ISR. - * @see dma_attach_interrupt() - * @see dma_irq_cause - */ -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { - uint8 status_bits = dma_get_isr_bits(dev, channel); - - /* If the channel global interrupt flag is cleared, then - * something's very wrong. */ - ASSERT(status_bits & BIT(0)); - - dma_clear_isr_bits(dev, channel); - - /* ISR flags get set even if the corresponding interrupt enable - * bits in the channel's configuration register are cleared, so we - * can't use a switch here. - * - * Don't change the order of these if statements. */ - if (status_bits & BIT(3)) { - return DMA_TRANSFER_ERROR; - } else if (status_bits & BIT(1)) { - return DMA_TRANSFER_COMPLETE; - } else if (status_bits & BIT(2)) { - return DMA_TRANSFER_HALF_COMPLETE; - } else if (status_bits & BIT(0)) { - /* Shouldn't happen (unless someone messed up an IFCR write). */ - throb(); - } -#if DEBUG_LEVEL < DEBUG_ALL - else { - /* We shouldn't have been called, but the debug level is too - * low for the above ASSERT() to have had any effect. In - * order to fail fast, mimic the DMA controller's behavior - * when an error occurs. */ - dma_disable(dev, channel); - } -#endif - return DMA_TRANSFER_ERROR; -} - -/** - * @brief Enable a DMA channel. - * @param dev DMA device - * @param channel Channel to enable - */ -void dma_enable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1); -} - -/** - * @brief Disable a DMA channel. - * @param dev DMA device - * @param channel Channel to disable - */ -void dma_disable(dma_dev *dev, dma_channel channel) { - dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); - bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); -} - -/** - * @brief Set the base memory address where data will be read from or - * written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA memory size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA memory size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param channel Channel whose base memory address to set. - * @param addr Memory base address to use. - */ -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CMAR = (uint32)addr; -} - -/** - * @brief Set the base peripheral address where data will be read from - * or written to. - * - * You must not call this function while the channel is enabled. - * - * If the DMA peripheral size is 16 bits, the address is automatically - * aligned to a half-word. If the DMA peripheral size is 32 bits, the - * address is aligned to a word. - * - * @param dev DMA Device - * @param channel Channel whose peripheral data register base address to set. - * @param addr Peripheral memory base address to use. - */ -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { - dma_channel_reg_map *chan_regs; - - ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - - chan_regs = dma_channel_regs(dev, channel); - chan_regs->CPAR = (uint32)addr; -} - /* - * IRQ handlers + * Private API */ -static inline void dispatch_handler(dma_dev *dev, dma_channel channel) { - void (*handler)(void) = dev->handlers[channel - 1].handler; - if (handler) { - handler(); - dma_clear_isr_bits(dev, channel); /* in case handler doesn't */ +enum dma_atype _dma_addr_type(__io void *addr) { + switch (stm32_block_purpose((void*)addr)) { + /* Notice we're treating the code block as memory here. That's + * correct for addresses in Flash and in [0x0, 0x7FFFFFF] + * (provided that those addresses are aliased to Flash, SRAM, or + * FSMC, depending on BOOT[01] and possibly SYSCFG_MEMRMP). It's + * not correct for other addresses in the code block, but those + * will (hopefully) just fail-fast with transfer or bus errors. If + * lots of people get confused, it might be worth being more + * careful here. */ + case STM32_BLOCK_CODE: /* Fall through */ + case STM32_BLOCK_SRAM: /* ... */ + case STM32_BLOCK_FSMC_1_2: /* ... */ + case STM32_BLOCK_FSMC_3_4: + return DMA_ATYPE_MEM; + case STM32_BLOCK_PERIPH: + return DMA_ATYPE_PER; + case STM32_BLOCK_FSMC_REG: /* Fall through */ + /* Is this right? I can't think of a reason to DMA into or out + * of the FSMC registers. [mbolivar] */ + case STM32_BLOCK_UNUSED: /* ... */ + case STM32_BLOCK_CORTEX_INTERNAL: /* ... */ + return DMA_ATYPE_OTHER; + default: + ASSERT(0); /* Can't happen */ + return DMA_ATYPE_OTHER; } } - -void __irq_dma1_channel1(void) { - dispatch_handler(DMA1, DMA_CH1); -} - -void __irq_dma1_channel2(void) { - dispatch_handler(DMA1, DMA_CH2); -} - -void __irq_dma1_channel3(void) { - dispatch_handler(DMA1, DMA_CH3); -} - -void __irq_dma1_channel4(void) { - dispatch_handler(DMA1, DMA_CH4); -} - -void __irq_dma1_channel5(void) { - dispatch_handler(DMA1, DMA_CH5); -} - -void __irq_dma1_channel6(void) { - dispatch_handler(DMA1, DMA_CH6); -} - -void __irq_dma1_channel7(void) { - dispatch_handler(DMA1, DMA_CH7); -} - -#ifdef STM32_HIGH_DENSITY -void __irq_dma2_channel1(void) { - dispatch_handler(DMA2, DMA_CH1); -} - -void __irq_dma2_channel2(void) { - dispatch_handler(DMA2, DMA_CH2); -} - -void __irq_dma2_channel3(void) { - dispatch_handler(DMA2, DMA_CH3); -} - -void __irq_dma2_channel4_5(void) { - dispatch_handler(DMA2, DMA_CH4); - dispatch_handler(DMA2, DMA_CH5); -} -#endif diff --git a/libmaple/dma.h b/libmaple/dma.h deleted file mode 100644 index 6e8087f..0000000 --- a/libmaple/dma.h +++ /dev/null @@ -1,453 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Michael Hope. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file dma.h - * - * @author Marti Bolivar <mbolivar@leaflabs.com>; - * Original implementation by Michael Hope - * - * @brief Direct Memory Access peripheral support - */ - -/* - * See /notes/dma.txt for more information. - */ - -#ifndef _DMA_H_ -#define _DMA_H_ - -#include "libmaple_types.h" -#include "rcc.h" -#include "nvic.h" - -#ifdef __cplusplus -extern "C"{ -#endif - -/* - * Register maps - */ - -/** - * @brief DMA register map type. - * - * Note that DMA controller 2 (register map base pointer DMA2_BASE) - * only supports channels 1--5. - */ -typedef struct dma_reg_map { - __io uint32 ISR; /**< Interrupt status register */ - __io uint32 IFCR; /**< Interrupt flag clear register */ - __io uint32 CCR1; /**< Channel 1 configuration register */ - __io uint32 CNDTR1; /**< Channel 1 number of data register */ - __io uint32 CPAR1; /**< Channel 1 peripheral address register */ - __io uint32 CMAR1; /**< Channel 1 memory address register */ - const uint32 RESERVED1; /**< Reserved. */ - __io uint32 CCR2; /**< Channel 2 configuration register */ - __io uint32 CNDTR2; /**< Channel 2 number of data register */ - __io uint32 CPAR2; /**< Channel 2 peripheral address register */ - __io uint32 CMAR2; /**< Channel 2 memory address register */ - const uint32 RESERVED2; /**< Reserved. */ - __io uint32 CCR3; /**< Channel 3 configuration register */ - __io uint32 CNDTR3; /**< Channel 3 number of data register */ - __io uint32 CPAR3; /**< Channel 3 peripheral address register */ - __io uint32 CMAR3; /**< Channel 3 memory address register */ - const uint32 RESERVED3; /**< Reserved. */ - __io uint32 CCR4; /**< Channel 4 configuration register */ - __io uint32 CNDTR4; /**< Channel 4 number of data register */ - __io uint32 CPAR4; /**< Channel 4 peripheral address register */ - __io uint32 CMAR4; /**< Channel 4 memory address register */ - const uint32 RESERVED4; /**< Reserved. */ - __io uint32 CCR5; /**< Channel 5 configuration register */ - __io uint32 CNDTR5; /**< Channel 5 number of data register */ - __io uint32 CPAR5; /**< Channel 5 peripheral address register */ - __io uint32 CMAR5; /**< Channel 5 memory address register */ - const uint32 RESERVED5; /**< Reserved. */ - __io uint32 CCR6; /**< Channel 6 configuration register */ - __io uint32 CNDTR6; /**< Channel 6 number of data register */ - __io uint32 CPAR6; /**< Channel 6 peripheral address register */ - __io uint32 CMAR6; /**< Channel 6 memory address register */ - const uint32 RESERVED6; /**< Reserved. */ - __io uint32 CCR7; /**< Channel 7 configuration register */ - __io uint32 CNDTR7; /**< Channel 7 number of data register */ - __io uint32 CPAR7; /**< Channel 7 peripheral address register */ - __io uint32 CMAR7; /**< Channel 7 memory address register */ - const uint32 RESERVED7; /**< Reserved. */ -} dma_reg_map; - -/** DMA controller 1 register map base pointer */ -#define DMA1_BASE ((struct dma_reg_map*)0x40020000) - -#ifdef STM32_HIGH_DENSITY -/** DMA controller 2 register map base pointer */ -#define DMA2_BASE ((struct dma_reg_map*)0x40020400) -#endif - -/* - * Register bit definitions - */ - -/* Interrupt status register */ - -#define DMA_ISR_TEIF7_BIT 27 -#define DMA_ISR_HTIF7_BIT 26 -#define DMA_ISR_TCIF7_BIT 25 -#define DMA_ISR_GIF7_BIT 24 -#define DMA_ISR_TEIF6_BIT 23 -#define DMA_ISR_HTIF6_BIT 22 -#define DMA_ISR_TCIF6_BIT 21 -#define DMA_ISR_GIF6_BIT 20 -#define DMA_ISR_TEIF5_BIT 19 -#define DMA_ISR_HTIF5_BIT 18 -#define DMA_ISR_TCIF5_BIT 17 -#define DMA_ISR_GIF5_BIT 16 -#define DMA_ISR_TEIF4_BIT 15 -#define DMA_ISR_HTIF4_BIT 14 -#define DMA_ISR_TCIF4_BIT 13 -#define DMA_ISR_GIF4_BIT 12 -#define DMA_ISR_TEIF3_BIT 11 -#define DMA_ISR_HTIF3_BIT 10 -#define DMA_ISR_TCIF3_BIT 9 -#define DMA_ISR_GIF3_BIT 8 -#define DMA_ISR_TEIF2_BIT 7 -#define DMA_ISR_HTIF2_BIT 6 -#define DMA_ISR_TCIF2_BIT 5 -#define DMA_ISR_GIF2_BIT 4 -#define DMA_ISR_TEIF1_BIT 3 -#define DMA_ISR_HTIF1_BIT 2 -#define DMA_ISR_TCIF1_BIT 1 -#define DMA_ISR_GIF1_BIT 0 - -#define DMA_ISR_TEIF7 BIT(DMA_ISR_TEIF7_BIT) -#define DMA_ISR_HTIF7 BIT(DMA_ISR_HTIF7_BIT) -#define DMA_ISR_TCIF7 BIT(DMA_ISR_TCIF7_BIT) -#define DMA_ISR_GIF7 BIT(DMA_ISR_GIF7_BIT) -#define DMA_ISR_TEIF6 BIT(DMA_ISR_TEIF6_BIT) -#define DMA_ISR_HTIF6 BIT(DMA_ISR_HTIF6_BIT) -#define DMA_ISR_TCIF6 BIT(DMA_ISR_TCIF6_BIT) -#define DMA_ISR_GIF6 BIT(DMA_ISR_GIF6_BIT) -#define DMA_ISR_TEIF5 BIT(DMA_ISR_TEIF5_BIT) -#define DMA_ISR_HTIF5 BIT(DMA_ISR_HTIF5_BIT) -#define DMA_ISR_TCIF5 BIT(DMA_ISR_TCIF5_BIT) -#define DMA_ISR_GIF5 BIT(DMA_ISR_GIF5_BIT) -#define DMA_ISR_TEIF4 BIT(DMA_ISR_TEIF4_BIT) -#define DMA_ISR_HTIF4 BIT(DMA_ISR_HTIF4_BIT) -#define DMA_ISR_TCIF4 BIT(DMA_ISR_TCIF4_BIT) -#define DMA_ISR_GIF4 BIT(DMA_ISR_GIF4_BIT) -#define DMA_ISR_TEIF3 BIT(DMA_ISR_TEIF3_BIT) -#define DMA_ISR_HTIF3 BIT(DMA_ISR_HTIF3_BIT) -#define DMA_ISR_TCIF3 BIT(DMA_ISR_TCIF3_BIT) -#define DMA_ISR_GIF3 BIT(DMA_ISR_GIF3_BIT) -#define DMA_ISR_TEIF2 BIT(DMA_ISR_TEIF2_BIT) -#define DMA_ISR_HTIF2 BIT(DMA_ISR_HTIF2_BIT) -#define DMA_ISR_TCIF2 BIT(DMA_ISR_TCIF2_BIT) -#define DMA_ISR_GIF2 BIT(DMA_ISR_GIF2_BIT) -#define DMA_ISR_TEIF1 BIT(DMA_ISR_TEIF1_BIT) -#define DMA_ISR_HTIF1 BIT(DMA_ISR_HTIF1_BIT) -#define DMA_ISR_TCIF1 BIT(DMA_ISR_TCIF1_BIT) -#define DMA_ISR_GIF1 BIT(DMA_ISR_GIF1_BIT) - -/* Interrupt flag clear register */ - -#define DMA_IFCR_CTEIF7_BIT 27 -#define DMA_IFCR_CHTIF7_BIT 26 -#define DMA_IFCR_CTCIF7_BIT 25 -#define DMA_IFCR_CGIF7_BIT 24 -#define DMA_IFCR_CTEIF6_BIT 23 -#define DMA_IFCR_CHTIF6_BIT 22 -#define DMA_IFCR_CTCIF6_BIT 21 -#define DMA_IFCR_CGIF6_BIT 20 -#define DMA_IFCR_CTEIF5_BIT 19 -#define DMA_IFCR_CHTIF5_BIT 18 -#define DMA_IFCR_CTCIF5_BIT 17 -#define DMA_IFCR_CGIF5_BIT 16 -#define DMA_IFCR_CTEIF4_BIT 15 -#define DMA_IFCR_CHTIF4_BIT 14 -#define DMA_IFCR_CTCIF4_BIT 13 -#define DMA_IFCR_CGIF4_BIT 12 -#define DMA_IFCR_CTEIF3_BIT 11 -#define DMA_IFCR_CHTIF3_BIT 10 -#define DMA_IFCR_CTCIF3_BIT 9 -#define DMA_IFCR_CGIF3_BIT 8 -#define DMA_IFCR_CTEIF2_BIT 7 -#define DMA_IFCR_CHTIF2_BIT 6 -#define DMA_IFCR_CTCIF2_BIT 5 -#define DMA_IFCR_CGIF2_BIT 4 -#define DMA_IFCR_CTEIF1_BIT 3 -#define DMA_IFCR_CHTIF1_BIT 2 -#define DMA_IFCR_CTCIF1_BIT 1 -#define DMA_IFCR_CGIF1_BIT 0 - -#define DMA_IFCR_CTEIF7 BIT(DMA_IFCR_CTEIF7_BIT) -#define DMA_IFCR_CHTIF7 BIT(DMA_IFCR_CHTIF7_BIT) -#define DMA_IFCR_CTCIF7 BIT(DMA_IFCR_CTCIF7_BIT) -#define DMA_IFCR_CGIF7 BIT(DMA_IFCR_CGIF7_BIT) -#define DMA_IFCR_CTEIF6 BIT(DMA_IFCR_CTEIF6_BIT) -#define DMA_IFCR_CHTIF6 BIT(DMA_IFCR_CHTIF6_BIT) -#define DMA_IFCR_CTCIF6 BIT(DMA_IFCR_CTCIF6_BIT) -#define DMA_IFCR_CGIF6 BIT(DMA_IFCR_CGIF6_BIT) -#define DMA_IFCR_CTEIF5 BIT(DMA_IFCR_CTEIF5_BIT) -#define DMA_IFCR_CHTIF5 BIT(DMA_IFCR_CHTIF5_BIT) -#define DMA_IFCR_CTCIF5 BIT(DMA_IFCR_CTCIF5_BIT) -#define DMA_IFCR_CGIF5 BIT(DMA_IFCR_CGIF5_BIT) -#define DMA_IFCR_CTEIF4 BIT(DMA_IFCR_CTEIF4_BIT) -#define DMA_IFCR_CHTIF4 BIT(DMA_IFCR_CHTIF4_BIT) -#define DMA_IFCR_CTCIF4 BIT(DMA_IFCR_CTCIF4_BIT) -#define DMA_IFCR_CGIF4 BIT(DMA_IFCR_CGIF4_BIT) -#define DMA_IFCR_CTEIF3 BIT(DMA_IFCR_CTEIF3_BIT) -#define DMA_IFCR_CHTIF3 BIT(DMA_IFCR_CHTIF3_BIT) -#define DMA_IFCR_CTCIF3 BIT(DMA_IFCR_CTCIF3_BIT) -#define DMA_IFCR_CGIF3 BIT(DMA_IFCR_CGIF3_BIT) -#define DMA_IFCR_CTEIF2 BIT(DMA_IFCR_CTEIF2_BIT) -#define DMA_IFCR_CHTIF2 BIT(DMA_IFCR_CHTIF2_BIT) -#define DMA_IFCR_CTCIF2 BIT(DMA_IFCR_CTCIF2_BIT) -#define DMA_IFCR_CGIF2 BIT(DMA_IFCR_CGIF2_BIT) -#define DMA_IFCR_CTEIF1 BIT(DMA_IFCR_CTEIF1_BIT) -#define DMA_IFCR_CHTIF1 BIT(DMA_IFCR_CHTIF1_BIT) -#define DMA_IFCR_CTCIF1 BIT(DMA_IFCR_CTCIF1_BIT) -#define DMA_IFCR_CGIF1 BIT(DMA_IFCR_CGIF1_BIT) - -/* Channel configuration register */ - -#define DMA_CCR_MEM2MEM_BIT 14 -#define DMA_CCR_MINC_BIT 7 -#define DMA_CCR_PINC_BIT 6 -#define DMA_CCR_CIRC_BIT 5 -#define DMA_CCR_DIR_BIT 4 -#define DMA_CCR_TEIE_BIT 3 -#define DMA_CCR_HTIE_BIT 2 -#define DMA_CCR_TCIE_BIT 1 -#define DMA_CCR_EN_BIT 0 - -#define DMA_CCR_MEM2MEM BIT(DMA_CCR_MEM2MEM_BIT) -#define DMA_CCR_PL (0x3 << 12) -#define DMA_CCR_PL_LOW (0x0 << 12) -#define DMA_CCR_PL_MEDIUM (0x1 << 12) -#define DMA_CCR_PL_HIGH (0x2 << 12) -#define DMA_CCR_PL_VERY_HIGH (0x3 << 12) -#define DMA_CCR_MSIZE (0x3 << 10) -#define DMA_CCR_MSIZE_8BITS (0x0 << 10) -#define DMA_CCR_MSIZE_16BITS (0x1 << 10) -#define DMA_CCR_MSIZE_32BITS (0x2 << 10) -#define DMA_CCR_PSIZE (0x3 << 8) -#define DMA_CCR_PSIZE_8BITS (0x0 << 8) -#define DMA_CCR_PSIZE_16BITS (0x1 << 8) -#define DMA_CCR_PSIZE_32BITS (0x2 << 8) -#define DMA_CCR_MINC BIT(DMA_CCR_MINC_BIT) -#define DMA_CCR_PINC BIT(DMA_CCR_PINC_BIT) -#define DMA_CCR_CIRC BIT(DMA_CCR_CIRC_BIT) -#define DMA_CCR_DIR BIT(DMA_CCR_DIR_BIT) -#define DMA_CCR_TEIE BIT(DMA_CCR_TEIE_BIT) -#define DMA_CCR_HTIE BIT(DMA_CCR_HTIE_BIT) -#define DMA_CCR_TCIE BIT(DMA_CCR_TCIE_BIT) -#define DMA_CCR_EN BIT(DMA_CCR_EN_BIT) - -/* - * Devices - */ - -/** Encapsulates state related to a DMA channel interrupt. */ -typedef struct dma_handler_config { - void (*handler)(void); /**< User-specified channel interrupt - handler */ - nvic_irq_num irq_line; /**< Channel's NVIC interrupt number */ -} dma_handler_config; - -/** DMA device type */ -typedef struct dma_dev { - dma_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< Clock ID */ - dma_handler_config handlers[]; /**< - * @brief IRQ handlers and NVIC numbers. - * - * @see dma_attach_interrupt() - * @see dma_detach_interrupt() - */ -} dma_dev; - -extern dma_dev *DMA1; -#ifdef STM32_HIGH_DENSITY -extern dma_dev *DMA2; -#endif - -/* - * Convenience functions - */ - -void dma_init(dma_dev *dev); - -/** Flags for DMA transfer configuration. */ -typedef enum dma_mode_flags { - DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ - DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ - DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ - DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ - DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ - DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ - DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ - DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ -} dma_mode_flags; - -/** Source and destination transfer sizes. */ -typedef enum dma_xfer_size { - DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ - DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ - DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ -} dma_xfer_size; - -/** DMA channel */ -typedef enum dma_channel { - DMA_CH1 = 1, /**< Channel 1 */ - DMA_CH2 = 2, /**< Channel 2 */ - DMA_CH3 = 3, /**< Channel 3 */ - DMA_CH4 = 4, /**< Channel 4 */ - DMA_CH5 = 5, /**< Channel 5 */ - DMA_CH6 = 6, /**< Channel 6 */ - DMA_CH7 = 7, /**< Channel 7 */ -} dma_channel; - -void dma_setup_transfer(dma_dev *dev, - dma_channel channel, - __io void *peripheral_address, - dma_xfer_size peripheral_size, - __io void *memory_address, - dma_xfer_size memory_size, - uint32 mode); - -void dma_set_num_transfers(dma_dev *dev, - dma_channel channel, - uint16 num_transfers); - -/** DMA transfer priority. */ -typedef enum dma_priority { - DMA_PRIORITY_LOW = DMA_CCR_PL_LOW, /**< Low priority */ - DMA_PRIORITY_MEDIUM = DMA_CCR_PL_MEDIUM, /**< Medium priority */ - DMA_PRIORITY_HIGH = DMA_CCR_PL_HIGH, /**< High priority */ - DMA_PRIORITY_VERY_HIGH = DMA_CCR_PL_VERY_HIGH /**< Very high priority */ -} dma_priority; - -void dma_set_priority(dma_dev *dev, - dma_channel channel, - dma_priority priority); - -void dma_attach_interrupt(dma_dev *dev, - dma_channel channel, - void (*handler)(void)); -void dma_detach_interrupt(dma_dev *dev, dma_channel channel); - -/** - * Encodes the reason why a DMA interrupt was called. - * @see dma_get_irq_cause() - */ -typedef enum dma_irq_cause { - DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */ - DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */ - DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */ -} dma_irq_cause; - -dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel); - -void dma_enable(dma_dev *dev, dma_channel channel); -void dma_disable(dma_dev *dev, dma_channel channel); - -void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *address); -void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *address); - -/** - * @brief DMA channel register map type. - * - * Provides access to an individual channel's registers. - */ -typedef struct dma_channel_reg_map { - __io uint32 CCR; /**< Channel configuration register */ - __io uint32 CNDTR; /**< Channel number of data register */ - __io uint32 CPAR; /**< Channel peripheral address register */ - __io uint32 CMAR; /**< Channel memory address register */ -} dma_channel_reg_map; - -#define DMA_CHANNEL_NREGS 5 - -/** - * @brief Obtain a pointer to an individual DMA channel's registers. - * - * For example, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1. - * - * @param dev DMA device - * @param channel DMA channel whose channel register map to obtain. - */ -static inline dma_channel_reg_map* dma_channel_regs(dma_dev *dev, - dma_channel channel) { - __io uint32 *ccr1 = &dev->regs->CCR1; - return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (channel - 1)); -} - -/** - * @brief Check if a DMA channel is enabled - * @param dev DMA device - * @param channel Channel whose enabled bit to check. - */ -static inline uint8 dma_is_channel_enabled(dma_dev *dev, dma_channel channel) { - return (uint8)(dma_channel_regs(dev, channel)->CCR & DMA_CCR_EN); -} - -/** - * @brief Get the ISR status bits for a DMA channel. - * - * The bits are returned right-aligned, in the following order: - * transfer error flag, half-transfer flag, transfer complete flag, - * global interrupt flag. - * - * If you're attempting to figure out why a DMA interrupt fired; you - * may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param channel Channel whose ISR bits to return. - * @see dma_get_irq_cause(). - */ -static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_channel channel) { - uint8 shift = (channel - 1) * 4; - return (dev->regs->ISR >> shift) & 0xF; -} - -/** - * @brief Clear the ISR status bits for a given DMA channel. - * - * If you're attempting to clean up after yourself in a DMA interrupt, - * you may find dma_get_irq_cause() more convenient. - * - * @param dev DMA device - * @param channel Channel whose ISR bits to clear. - * @see dma_get_irq_cause() - */ -static inline void dma_clear_isr_bits(dma_dev *dev, dma_channel channel) { - dev->regs->IFCR = BIT(4 * (channel - 1)); -} - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/libmaple/dma_private.h b/libmaple/dma_private.h new file mode 100644 index 0000000..b25ded2 --- /dev/null +++ b/libmaple/dma_private.h @@ -0,0 +1,61 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +#ifndef _LIBMAPLE_DMA_PRIVATE_H_ +#define _LIBMAPLE_DMA_PRIVATE_H_ + +#include <libmaple/dma.h> +#include <libmaple/libmaple_types.h> + +/* + * IRQ handling + */ + +/* Wrap this in an ifdef to shut up GCC. (We provide DMA_GET_HANDLER + * in the series support files, which need dma_irq_handler().) */ +#ifdef DMA_GET_HANDLER +static __always_inline void dma_irq_handler(dma_dev *dev, dma_tube tube) { + void (*handler)(void) = DMA_GET_HANDLER(dev, tube); + if (handler) { + handler(); + dma_clear_isr_bits(dev, tube); /* in case handler doesn't */ + } +} +#endif + +/* + * Conveniences for dealing with tube sources/destinations + */ + +enum dma_atype { + DMA_ATYPE_MEM, + DMA_ATYPE_PER, + DMA_ATYPE_OTHER, +}; + +enum dma_atype _dma_addr_type(__io void *addr); + +#endif diff --git a/libmaple/exti.c b/libmaple/exti.c index 1fcc35b..9023782 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,14 +26,14 @@ *****************************************************************************/ /** - * @file exti.c + * @file libmaple/exti.c * @brief External interrupt control routines */ -#include "exti.h" -#include "libmaple.h" -#include "nvic.h" -#include "bitband.h" +#include <libmaple/exti.h> +#include <libmaple/libmaple.h> +#include <libmaple/nvic.h> +#include <libmaple/bitband.h> static inline void dispatch_single_exti(uint32 exti_num); static inline void dispatch_extis(uint32 start, uint32 stop); @@ -66,7 +67,7 @@ static exti_channel exti_channels[] = { }; /* - * Convenience routines + * Portable routines */ /** @@ -80,13 +81,13 @@ static exti_channel exti_channels[] = { * @param handler Function handler to execute when interrupt is triggered. * @param mode Type of transition to trigger on, one of: * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING. - * @see afio_exti_num - * @see afio_exti_port + * @see exti_num + * @see exti_cfg * @see voidFuncPtr * @see exti_trigger_mode */ -void exti_attach_interrupt(afio_exti_num num, - afio_exti_port port, +void exti_attach_interrupt(exti_num num, + exti_cfg port, voidFuncPtr handler, exti_trigger_mode mode) { ASSERT(handler); @@ -108,8 +109,8 @@ void exti_attach_interrupt(afio_exti_num num, break; } - /* Map num to port */ - afio_exti_select(num, port); + /* Use the chip-specific exti_select() to map num to port */ + exti_select(num, port); /* Unmask external interrupt request */ bb_peri_set_bit(&EXTI_BASE->IMR, num, 1); @@ -120,10 +121,10 @@ void exti_attach_interrupt(afio_exti_num num, /** * @brief Unregister an external interrupt handler - * @param num Number of the external interrupt line to disable. - * @see afio_exti_num + * @param num External interrupt line to disable. + * @see exti_num */ -void exti_detach_interrupt(afio_exti_num num) { +void exti_detach_interrupt(exti_num num) { /* First, mask the interrupt request */ bb_peri_set_bit(&EXTI_BASE->IMR, num, 0); @@ -136,27 +137,39 @@ void exti_detach_interrupt(afio_exti_num num) { } /* + * Private routines + */ + +void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port) { + uint32 shift = 4 * (num % 4); + uint32 cr = *exti_cr; + cr &= ~(0xF << shift); + cr |= port << shift; + *exti_cr = cr; +} + +/* * Interrupt handlers */ void __irq_exti0(void) { - dispatch_single_exti(AFIO_EXTI_0); + dispatch_single_exti(EXTI0); } void __irq_exti1(void) { - dispatch_single_exti(AFIO_EXTI_1); + dispatch_single_exti(EXTI1); } void __irq_exti2(void) { - dispatch_single_exti(AFIO_EXTI_2); + dispatch_single_exti(EXTI2); } void __irq_exti3(void) { - dispatch_single_exti(AFIO_EXTI_3); + dispatch_single_exti(EXTI3); } void __irq_exti4(void) { - dispatch_single_exti(AFIO_EXTI_4); + dispatch_single_exti(EXTI4); } void __irq_exti9_5(void) { @@ -177,7 +190,7 @@ void __irq_exti15_10(void) { * won't actually be cleared in time and the ISR will fire again. To * compensate, this function NOPs for 2 cycles after clearing the * pending bits to ensure it takes effect. */ -static inline void clear_pending_msk(uint32 exti_msk) { +static __always_inline void clear_pending_msk(uint32 exti_msk) { EXTI_BASE->PR = exti_msk; asm volatile("nop"); asm volatile("nop"); @@ -185,7 +198,7 @@ static inline void clear_pending_msk(uint32 exti_msk) { /* This dispatch routine is for non-multiplexed EXTI lines only; i.e., * it doesn't check EXTI_PR. */ -static inline void dispatch_single_exti(uint32 exti) { +static __always_inline void dispatch_single_exti(uint32 exti) { voidFuncPtr handler = exti_channels[exti].handler; if (!handler) { @@ -193,18 +206,18 @@ static inline void dispatch_single_exti(uint32 exti) { } handler(); - clear_pending_msk(BIT(exti)); + clear_pending_msk(1U << exti); } /* Dispatch routine for EXTIs which share an IRQ. */ -static inline void dispatch_extis(uint32 start, uint32 stop) { +static __always_inline void dispatch_extis(uint32 start, uint32 stop) { uint32 pr = EXTI_BASE->PR; uint32 handled_msk = 0; uint32 exti; /* Dispatch user handlers for pending EXTIs. */ for (exti = start; exti <= stop; exti++) { - uint32 eb = BIT(exti); + uint32 eb = (1U << exti); if (pr & eb) { voidFuncPtr handler = exti_channels[exti].handler; if (handler) { diff --git a/libmaple/exti_private.h b/libmaple/exti_private.h new file mode 100644 index 0000000..4f0a4cf --- /dev/null +++ b/libmaple/exti_private.h @@ -0,0 +1,34 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +#ifndef _LIBMAPLE_EXTI_PRIVATE_H_ +#define _LIBMAPLE_EXTI_PRIVATE_H_ + +#include <libmaple/exti.h> + +void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port); + +#endif diff --git a/libmaple/flash.c b/libmaple/flash.c index a22fbd3..0cdff59 100644 --- a/libmaple/flash.c +++ b/libmaple/flash.c @@ -25,30 +25,24 @@ *****************************************************************************/ /** - * @file flash.c + * @file libmaple/flash.c * @brief Flash management functions */ -#include "libmaple.h" -#include "flash.h" -#include "bitband.h" - -/** - * @brief Turn on the hardware prefetcher. - */ -void flash_enable_prefetch(void) { - *bb_perip(&FLASH_BASE->ACR, FLASH_ACR_PRFTBE_BIT) = 1; -} +#include <libmaple/libmaple_types.h> +#include <libmaple/flash.h> /** * @brief Set flash wait states * - * See ST PM0042, section 3.1 for restrictions on the acceptable value - * of wait_states for a given SYSCLK configuration. + * Note that not all wait states are available on every MCU. See the + * Flash programming manual for your MCU for restrictions on the + * allowed value of wait_states for a given system clock (SYSCLK) + * frequency. * * @param wait_states number of wait states (one of * FLASH_WAIT_STATE_0, FLASH_WAIT_STATE_1, - * FLASH_WAIT_STATE_2). + * ..., FLASH_WAIT_STATE_7). */ void flash_set_latency(uint32 wait_states) { uint32 val = FLASH_BASE->ACR; diff --git a/libmaple/gpio.c b/libmaple/gpio.c index e643873..898007a 100644 --- a/libmaple/gpio.c +++ b/libmaple/gpio.c @@ -25,77 +25,15 @@ *****************************************************************************/ /** - * @file gpio.c - * @brief GPIO initialization routine + * @file libmaple/gpio.c + * @brief Generic STM32 GPIO support. */ -#include "gpio.h" -#include "rcc.h" +#include <libmaple/gpio.h> +#include <libmaple/rcc.h> /* - * GPIO devices - */ - -gpio_dev gpioa = { - .regs = GPIOA_BASE, - .clk_id = RCC_GPIOA, - .exti_port = AFIO_EXTI_PA, -}; -/** GPIO port A device. */ -gpio_dev* const GPIOA = &gpioa; - -gpio_dev gpiob = { - .regs = GPIOB_BASE, - .clk_id = RCC_GPIOB, - .exti_port = AFIO_EXTI_PB, -}; -/** GPIO port B device. */ -gpio_dev* const GPIOB = &gpiob; - -gpio_dev gpioc = { - .regs = GPIOC_BASE, - .clk_id = RCC_GPIOC, - .exti_port = AFIO_EXTI_PC, -}; -/** GPIO port C device. */ -gpio_dev* const GPIOC = &gpioc; - -gpio_dev gpiod = { - .regs = GPIOD_BASE, - .clk_id = RCC_GPIOD, - .exti_port = AFIO_EXTI_PD, -}; -/** GPIO port D device. */ -gpio_dev* const GPIOD = &gpiod; - -#ifdef STM32_HIGH_DENSITY -gpio_dev gpioe = { - .regs = GPIOE_BASE, - .clk_id = RCC_GPIOE, - .exti_port = AFIO_EXTI_PE, -}; -/** GPIO port E device. */ -gpio_dev* const GPIOE = &gpioe; - -gpio_dev gpiof = { - .regs = GPIOF_BASE, - .clk_id = RCC_GPIOF, - .exti_port = AFIO_EXTI_PF, -}; -/** GPIO port F device. */ -gpio_dev* const GPIOF = &gpiof; - -gpio_dev gpiog = { - .regs = GPIOG_BASE, - .clk_id = RCC_GPIOG, - .exti_port = AFIO_EXTI_PG, -}; -/** GPIO port G device. */ -gpio_dev* const GPIOG = &gpiog; -#endif - -/* - * GPIO convenience routines + * GPIO routines */ /** @@ -109,88 +47,3 @@ void gpio_init(gpio_dev *dev) { rcc_clk_enable(dev->clk_id); rcc_reset_dev(dev->clk_id); } - -/** - * Initialize and reset all available GPIO devices. - */ -void gpio_init_all(void) { - gpio_init(GPIOA); - gpio_init(GPIOB); - gpio_init(GPIOC); - gpio_init(GPIOD); -#ifdef STM32_HIGH_DENSITY - gpio_init(GPIOE); - gpio_init(GPIOF); - gpio_init(GPIOG); -#endif -} - -/** - * Set the mode of a GPIO pin. - * - * @param dev GPIO device. - * @param pin Pin on the device whose mode to set, 0--15. - * @param mode General purpose or alternate function mode to set the pin to. - * @see gpio_pin_mode - */ -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { - gpio_reg_map *regs = dev->regs; - __io uint32 *cr = ®s->CRL + (pin >> 3); - uint32 shift = (pin & 0x7) * 4; - uint32 tmp = *cr; - - tmp &= ~(0xF << shift); - tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; - *cr = tmp; - - if (mode == GPIO_INPUT_PD) { - regs->ODR &= ~BIT(pin); - } else if (mode == GPIO_INPUT_PU) { - regs->ODR |= BIT(pin); - } -} - -/* - * AFIO - */ - -/** - * @brief Initialize the AFIO clock, and reset the AFIO registers. - */ -void afio_init(void) { - rcc_clk_enable(RCC_AFIO); - rcc_reset_dev(RCC_AFIO); -} - -#define AFIO_EXTI_SEL_MASK 0xF - -/** - * @brief Select a source input for an external interrupt. - * - * @param exti External interrupt. - * @param gpio_port Port which contains pin to use as source input. - * @see afio_exti_num - * @see afio_exti_port - */ -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) { - __io uint32 *exti_cr = &AFIO_BASE->EXTICR1 + exti / 4; - uint32 shift = 4 * (exti % 4); - uint32 cr = *exti_cr; - - cr &= ~(AFIO_EXTI_SEL_MASK << shift); - cr |= gpio_port << shift; - *exti_cr = cr; -} - -/** - * @brief Perform an alternate function remap. - * @param remapping Remapping to perform. - */ -void afio_remap(afio_remap_peripheral remapping) { - if (remapping & AFIO_REMAP_USE_MAPR2) { - remapping &= ~AFIO_REMAP_USE_MAPR2; - AFIO_BASE->MAPR2 |= remapping; - } else { - AFIO_BASE->MAPR |= remapping; - } -} diff --git a/libmaple/i2c.c b/libmaple/i2c.c index e3f3199..9c93d3f 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,49 +26,28 @@ *****************************************************************************/ /** - * @file i2c.c + * @file libmaple/i2c.c + * @author Perry Hung <perry@leaflabs.com> * @brief Inter-Integrated Circuit (I2C) support. * * Currently, only master mode is supported. */ -#include "libmaple.h" -#include "rcc.h" -#include "gpio.h" -#include "nvic.h" -#include "i2c.h" -#include "string.h" -#include "systick.h" - -static i2c_dev i2c_dev1 = { - .regs = I2C1_BASE, - .gpio_port = &gpiob, - .sda_pin = 7, - .scl_pin = 6, - .clk_id = RCC_I2C1, - .ev_nvic_line = NVIC_I2C1_EV, - .er_nvic_line = NVIC_I2C1_ER, - .state = I2C_STATE_DISABLED -}; -/** I2C1 device */ -i2c_dev* const I2C1 = &i2c_dev1; - -static i2c_dev i2c_dev2 = { - .regs = I2C2_BASE, - .gpio_port = &gpiob, - .sda_pin = 11, - .scl_pin = 10, - .clk_id = RCC_I2C2, - .ev_nvic_line = NVIC_I2C2_EV, - .er_nvic_line = NVIC_I2C2_ER, - .state = I2C_STATE_DISABLED -}; -/** I2C2 device */ -i2c_dev* const I2C2 = &i2c_dev2; +#include "i2c_private.h" + +#include <libmaple/libmaple.h> +#include <libmaple/rcc.h> +#include <libmaple/gpio.h> +#include <libmaple/nvic.h> +#include <libmaple/i2c.h> +#include <libmaple/systick.h> + +#include <string.h> static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state, uint32 timeout); +static void set_ccr_trise(i2c_dev *dev, uint32 flags); /** * @brief Fill data register with slave address @@ -125,10 +105,191 @@ enum { }; /** - * @brief IRQ handler for I2C master. Handles transmission/reception. + * @brief Reset an I2C bus. + * + * Reset is accomplished by clocking out pulses until any hung slaves + * release SDA and SCL, then generating a START condition, then a STOP + * condition. + * + * @param dev I2C device + */ +void i2c_bus_reset(const i2c_dev *dev) { + /* Release both lines */ + i2c_master_release_bus(dev); + + /* + * Make sure the bus is free by clocking it until any slaves release the + * bus. + */ + while (!gpio_read_bit(sda_port(dev), dev->sda_pin)) { + /* Wait for any clock stretching to finish */ + while (!gpio_read_bit(scl_port(dev), dev->scl_pin)) + ; + delay_us(10); + + /* Pull low */ + gpio_write_bit(scl_port(dev), dev->scl_pin, 0); + delay_us(10); + + /* Release high again */ + gpio_write_bit(scl_port(dev), dev->scl_pin, 1); + delay_us(10); + } + + /* Generate start then stop condition */ + gpio_write_bit(sda_port(dev), dev->sda_pin, 0); + delay_us(10); + gpio_write_bit(scl_port(dev), dev->scl_pin, 0); + delay_us(10); + gpio_write_bit(scl_port(dev), dev->scl_pin, 1); + delay_us(10); + gpio_write_bit(sda_port(dev), dev->sda_pin, 1); +} + +/** + * @brief Initialize an I2C device and reset its registers to their + * default values. + * @param dev Device to initialize. + */ +void i2c_init(i2c_dev *dev) { + rcc_reset_dev(dev->clk_id); + rcc_clk_enable(dev->clk_id); +} + +/* Hack for deprecated bit of STM32F1 functionality */ +#ifndef _I2C_HAVE_DEPRECATED_I2C_REMAP +#define _i2c_handle_remap(dev, flags) ((void)0) +#endif + +/** + * @brief Initialize an I2C device as bus master + * @param dev Device to enable + * @param flags Bitwise or of the following I2C options: + * I2C_FAST_MODE: 400 khz operation, + * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for + * fast mode), + * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on + * initialization, + * I2C_10BIT_ADDRESSING: Enable 10-bit addressing, + * I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8 + * SDA/PB9. + */ +void i2c_master_enable(i2c_dev *dev, uint32 flags) { + /* PE must be disabled to configure the device */ + ASSERT(!(dev->regs->CR1 & I2C_CR1_PE)); + + /* Ugh */ + _i2c_handle_remap(dev, flags); + + /* Reset the bus. Clock out any hung slaves. */ + if (flags & I2C_BUS_RESET) { + i2c_bus_reset(dev); + } + + /* Turn on clock and set GPIO modes */ + i2c_init(dev); + i2c_config_gpios(dev); + + /* Configure clock and rise time */ + set_ccr_trise(dev, flags); + + /* Enable event and buffer interrupts */ + nvic_irq_enable(dev->ev_nvic_line); + nvic_irq_enable(dev->er_nvic_line); + i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR); + + /* Make it go! */ + i2c_peripheral_enable(dev); + + dev->state = I2C_STATE_IDLE; +} + +/** + * @brief Process an i2c transaction. + * + * Transactions are composed of one or more i2c_msg's, and may be read + * or write tranfers. Multiple i2c_msg's will generate a repeated + * start in between messages. + * * @param dev I2C device + * @param msgs Messages to send/receive + * @param num Number of messages to send/receive + * @param timeout Bus idle timeout in milliseconds before aborting the + * transfer. 0 denotes no timeout. + * @return 0 on success, + * I2C_ERROR_PROTOCOL if there was a protocol error, + * I2C_ERROR_TIMEOUT if the transfer timed out. */ -static void i2c_irq_handler(i2c_dev *dev) { +int32 i2c_master_xfer(i2c_dev *dev, + i2c_msg *msgs, + uint16 num, + uint32 timeout) { + int32 rc; + + ASSERT(dev->state == I2C_STATE_IDLE); + + dev->msg = msgs; + dev->msgs_left = num; + dev->timestamp = systick_uptime(); + dev->state = I2C_STATE_BUSY; + + i2c_enable_irq(dev, I2C_IRQ_EVENT); + i2c_start_condition(dev); + + rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE, timeout); + if (rc < 0) { + goto out; + } + + dev->state = I2C_STATE_IDLE; +out: + return rc; +} + +/** + * @brief Wait for an I2C event, or time out in case of error. + * @param dev I2C device + * @param state I2C_state state to wait for + * @param timeout Timeout, in milliseconds + * @return 0 if target state is reached, a negative value on error. + */ +static inline int32 wait_for_state_change(i2c_dev *dev, + i2c_state state, + uint32 timeout) { + i2c_state tmp; + + while (1) { + tmp = dev->state; + + if (tmp == I2C_STATE_ERROR) { + return I2C_STATE_ERROR; + } + + if (tmp == state) { + return 0; + } + + if (timeout) { + if (systick_uptime() > (dev->timestamp + timeout)) { + /* TODO: overflow? */ + /* TODO: racy? */ + return I2C_ERROR_TIMEOUT; + } + } + } +} + +/* + * Private API + */ + +/* + * IRQ handler for I2C master. Handles transmission/reception. + */ +void _i2c_irq_handler(i2c_dev *dev) { + /* WTFs: + * - Where is I2C_MSG_10BIT_ADDR handled? + */ i2c_msg *msg = dev->msg; uint8 read = msg->flags & I2C_MSG_READ; @@ -214,7 +375,7 @@ static void i2c_irq_handler(i2c_dev *dev) { /* * This should be impossible... */ - throb(); + ASSERT(0); } sr1 = sr2 = 0; } @@ -288,20 +449,11 @@ static void i2c_irq_handler(i2c_dev *dev) { } } -void __irq_i2c1_ev(void) { - i2c_irq_handler(&i2c_dev1); -} - -void __irq_i2c2_ev(void) { - i2c_irq_handler(&i2c_dev2); -} - -/** - * @brief Interrupt handler for I2C error conditions - * @param dev I2C device - * @sideeffect Aborts any pending I2C transactions +/* + * Interrupt handler for I2C error conditions. Aborts any pending I2C + * transactions. */ -static void i2c_irq_error_handler(i2c_dev *dev) { +void _i2c_irq_error_handler(i2c_dev *dev) { I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2); dev->error_flags = dev->regs->SR2 & (I2C_SR1_BERR | @@ -317,125 +469,34 @@ static void i2c_irq_error_handler(i2c_dev *dev) { dev->state = I2C_STATE_ERROR; } -void __irq_i2c1_er(void) { - i2c_irq_error_handler(&i2c_dev1); -} - -void __irq_i2c2_er(void) { - i2c_irq_error_handler(&i2c_dev2); -} - -/** - * @brief Reset an I2C bus. - * - * Reset is accomplished by clocking out pulses until any hung slaves - * release SDA and SCL, then generating a START condition, then a STOP - * condition. - * - * @param dev I2C device - */ -void i2c_bus_reset(const i2c_dev *dev) { - /* Release both lines */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_OUTPUT_OD); - - /* - * Make sure the bus is free by clocking it until any slaves release the - * bus. - */ - while (!gpio_read_bit(dev->gpio_port, dev->sda_pin)) { - /* Wait for any clock stretching to finish */ - while (!gpio_read_bit(dev->gpio_port, dev->scl_pin)) - ; - delay_us(10); - - /* Pull low */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); - delay_us(10); - - /* Release high again */ - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); - delay_us(10); - } - - /* Generate start then stop condition */ - gpio_write_bit(dev->gpio_port, dev->sda_pin, 0); - delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); - delay_us(10); - gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); - delay_us(10); - gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); -} - -/** - * @brief Initialize an I2C device and reset its registers to their - * default values. - * @param dev Device to initialize. +/* + * CCR/TRISE configuration helper */ -void i2c_init(i2c_dev *dev) { - rcc_reset_dev(dev->clk_id); - rcc_clk_enable(dev->clk_id); -} +static void set_ccr_trise(i2c_dev *dev, uint32 flags) { + uint32 ccr = 0; + uint32 trise = 0; + uint32 clk_mhz = _i2c_bus_clk(dev); + uint32 clk_hz = clk_mhz * (1000 * 1000); -/** - * @brief Initialize an I2C device as bus master - * @param dev Device to enable - * @param flags Bitwise or of the following I2C options: - * I2C_FAST_MODE: 400 khz operation, - * I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for - * fast mode), - * I2C_BUS_RESET: Reset the bus and clock out any hung slaves on - * initialization, - * I2C_10BIT_ADDRESSING: Enable 10-bit addressing, - * I2C_REMAP: Remap I2C1 to SCL/PB8 SDA/PB9. - */ -void i2c_master_enable(i2c_dev *dev, uint32 flags) { -#define I2C_CLK (STM32_PCLK1/1000000) - uint32 ccr = 0; - uint32 trise = 0; - - /* PE must be disabled to configure the device */ - ASSERT(!(dev->regs->CR1 & I2C_CR1_PE)); - - if ((dev == I2C1) && (flags & I2C_REMAP)) { - afio_remap(AFIO_REMAP_I2C1); - I2C1->sda_pin = 9; - I2C1->scl_pin = 8; - } - - /* Reset the bus. Clock out any hung slaves. */ - if (flags & I2C_BUS_RESET) { - i2c_bus_reset(dev); - } - - /* Turn on clock and set GPIO modes */ - i2c_init(dev); - gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_AF_OUTPUT_OD); - gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); - - /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ - i2c_set_input_clk(dev, I2C_CLK); + i2c_set_input_clk(dev, clk_mhz); if (flags & I2C_FAST_MODE) { ccr |= I2C_CCR_FS; if (flags & I2C_DUTY_16_9) { /* Tlow/Thigh = 16/9 */ - ccr |= I2C_CCR_DUTY; - ccr |= STM32_PCLK1/(400000 * 25); + ccr |= I2C_CCR_DUTY_16_9; + ccr |= clk_hz / (400000 * 25); } else { /* Tlow/Thigh = 2 */ - ccr |= STM32_PCLK1/(400000 * 3); + ccr |= clk_hz / (400000 * 3); } - trise = (300 * (I2C_CLK)/1000) + 1; + trise = (300 * clk_mhz / 1000) + 1; } else { /* Tlow/Thigh = 1 */ - ccr = STM32_PCLK1/(100000 * 2); - trise = I2C_CLK + 1; + ccr = clk_hz / (100000 * 2); + trise = clk_mhz + 1; } /* Set minimum required value if CCR < 1*/ @@ -445,121 +506,4 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { i2c_set_clk_control(dev, ccr); i2c_set_trise(dev, trise); - - /* Enable event and buffer interrupts */ - nvic_irq_enable(dev->ev_nvic_line); - nvic_irq_enable(dev->er_nvic_line); - i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR); - - /* - * Important STM32 Errata: - * - * See STM32F10xx8 and STM32F10xxB Errata sheet (Doc ID 14574 Rev 8), - * Section 2.11.1, 2.11.2. - * - * 2.11.1: - * When the EV7, EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events are not - * managed before the current byte is being transferred, problems may be - * encountered such as receiving an extra byte, reading the same data twice - * or missing data. - * - * 2.11.2: - * In Master Receiver mode, when closing the communication using - * method 2, the content of the last read data can be corrupted. - * - * If the user software is not able to read the data N-1 before the STOP - * condition is generated on the bus, the content of the shift register - * (data N) will be corrupted. (data N is shifted 1-bit to the left). - * - * ---------------------------------------------------------------------- - * - * In order to ensure that events are not missed, the i2c interrupt must - * not be preempted. We set the i2c interrupt priority to be the highest - * interrupt in the system (priority level 0). All other interrupts have - * been initialized to priority level 16. See nvic_init(). - */ - nvic_irq_set_priority(dev->ev_nvic_line, 0); - nvic_irq_set_priority(dev->er_nvic_line, 0); - - /* Make it go! */ - i2c_peripheral_enable(dev); - - dev->state = I2C_STATE_IDLE; -} - - -/** - * @brief Process an i2c transaction. - * - * Transactions are composed of one or more i2c_msg's, and may be read - * or write tranfers. Multiple i2c_msg's will generate a repeated - * start in between messages. - * - * @param dev I2C device - * @param msgs Messages to send/receive - * @param num Number of messages to send/receive - * @param timeout Bus idle timeout in milliseconds before aborting the - * transfer. 0 denotes no timeout. - * @return 0 on success, - * I2C_ERROR_PROTOCOL if there was a protocol error, - * I2C_ERROR_TIMEOUT if the transfer timed out. - */ -int32 i2c_master_xfer(i2c_dev *dev, - i2c_msg *msgs, - uint16 num, - uint32 timeout) { - int32 rc; - - ASSERT(dev->state == I2C_STATE_IDLE); - - dev->msg = msgs; - dev->msgs_left = num; - dev->timestamp = systick_uptime(); - dev->state = I2C_STATE_BUSY; - - i2c_enable_irq(dev, I2C_IRQ_EVENT); - i2c_start_condition(dev); - - rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE, timeout); - if (rc < 0) { - goto out; - } - - dev->state = I2C_STATE_IDLE; -out: - return rc; -} - - -/** - * @brief Wait for an I2C event, or time out in case of error. - * @param dev I2C device - * @param state I2C_state state to wait for - * @param timeout Timeout, in milliseconds - * @return 0 if target state is reached, a negative value on error. - */ -static inline int32 wait_for_state_change(i2c_dev *dev, - i2c_state state, - uint32 timeout) { - i2c_state tmp; - - while (1) { - tmp = dev->state; - - if (tmp == I2C_STATE_ERROR) { - return I2C_STATE_ERROR; - } - - if (tmp == state) { - return 0; - } - - if (timeout) { - if (systick_uptime() > (dev->timestamp + timeout)) { - /* TODO: overflow? */ - /* TODO: racy? */ - return I2C_ERROR_TIMEOUT; - } - } - } } diff --git a/libmaple/i2c_private.h b/libmaple/i2c_private.h new file mode 100644 index 0000000..5b79516 --- /dev/null +++ b/libmaple/i2c_private.h @@ -0,0 +1,79 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifndef _LIBMAPLE_I2C_PRIVATE_H_ +#define _LIBMAPLE_I2C_PRIVATE_H_ + +#include <libmaple/i2c_common.h> + +/* For old-style definitions (SDA/SCL on same GPIO device) */ +#define I2C_DEV_OLD(num, port, sda, scl) \ + { \ + .regs = I2C##num##_BASE, \ + .gpio_port = port, \ + .scl_port = NULL, \ + .sda_port = NULL, \ + .sda_pin = sda, \ + .scl_pin = scl, \ + .clk_id = RCC_I2C##num, \ + .ev_nvic_line = NVIC_I2C##num##_EV, \ + .er_nvic_line = NVIC_I2C##num##_ER, \ + .state = I2C_STATE_DISABLED, \ + } + +/* For new-style definitions (SDA/SCL may be on different GPIO devices) */ +#define I2C_DEV_NEW(num, sdaport, sdabit, sclport, sclbit) \ + { \ + .regs = I2C##num##_BASE, \ + .gpio_port = NULL, \ + .scl_port = sclport, \ + .scl_pin = sclbit, \ + .sda_port = sdaport, \ + .sda_pin = sdabit, \ + .clk_id = RCC_I2C##num, \ + .ev_nvic_line = NVIC_I2C##num##_EV, \ + .er_nvic_line = NVIC_I2C##num##_ER, \ + .state = I2C_STATE_DISABLED, \ + } + +void _i2c_irq_handler(i2c_dev *dev); +void _i2c_irq_error_handler(i2c_dev *dev); + +struct gpio_dev; + +static inline struct gpio_dev* scl_port(const i2c_dev *dev) { + return (dev->gpio_port == NULL) ? dev->scl_port : dev->gpio_port; +} + +static inline struct gpio_dev* sda_port(const i2c_dev *dev) { + return (dev->gpio_port == NULL) ? dev->sda_port : dev->gpio_port; +} + +/* Auxiliary procedure for enabling an I2C peripheral; `flags' as for + * i2c_master_enable(). */ +void _i2c_set_ccr_trise(i2c_dev *dev, uint32 flags); + +#endif /* _LIBMAPLE_I2C_PRIVATE_H_ */ diff --git a/libmaple/adc.h b/libmaple/include/libmaple/adc.h index d0b85fa..a500af7 100644 --- a/libmaple/adc.h +++ b/libmaple/include/libmaple/adc.h @@ -1,6 +1,7 @@ /****************************************************************************** * The MIT License * + * Copyright (c) 2012 LeafLabs, LLC. * Copyright (c) 2010 Perry Hung. * * Permission is hereby granted, free of charge, to any person @@ -25,22 +26,29 @@ *****************************************************************************/ /** - * @file adc.h - * - * @brief Analog-to-Digital Conversion (ADC) header. + * @file libmaple/include/libmaple/adc.h + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> + * @brief Analog-to-Digital Conversion (ADC) header. */ -#ifndef _ADC_H_ -#define _ADC_H_ - -#include "libmaple.h" -#include "bitband.h" -#include "rcc.h" +#ifndef _LIBMAPLE_ADC_H_ +#define _LIBMAPLE_ADC_H_ #ifdef __cplusplus extern "C"{ #endif +#include <libmaple/libmaple.h> +#include <libmaple/bitband.h> +#include <libmaple/rcc.h> +/* We include the series header below, after defining the register map + * and device structs. */ + +/* + * Register map + */ + /** ADC register map type. */ typedef struct adc_reg_map { __io uint32 SR; ///< Status register @@ -71,24 +79,30 @@ typedef struct adc_dev { rcc_clk_id clk_id; /**< RCC clock information */ } adc_dev; -extern const adc_dev *ADC1; -extern const adc_dev *ADC2; -#ifdef STM32_HIGH_DENSITY -extern const adc_dev *ADC3; -#endif - -/* - * Register map base pointers +/* Pull in the series header (which may need the above struct + * definitions). + * + * IMPORTANT: The series header must define the following: + * + * - enum adc_extsel_event (and typedef to adc_extsel_event): One per + * external event used to trigger start of conversion of a regular + * group. If two different series support the same event as a + * trigger, they must use the same token for the enumerator for that + * event. (The value of the enumerator is of course allowed to be + * different). + * + * - enum adc_smp_rate (and typedef to adc_smp_rate): One per + * available sampling time. These must be in the form ADC_SMPR_X_Y + * for X.Y cycles (e.g. ADC_SMPR_1_5 means 1.5 cycles), or + * ADC_SMPR_X for X cycles (e.g. ADC_SMPR_3 means 3 cycles). + * + * - enum adc_prescaler (and typedef): One per available prescaler, + * suitable for adc_set_prescaler. Series which have the same + * prescaler dividers (e.g. STM32F1 and STM32F2 both divide PCLK2 by + * 2, 4, 6, or 8) must provide the same tokens as enumerators, for + * portability. */ - -/** ADC1 register map base pointer. */ -#define ADC1_BASE ((struct adc_reg_map*)0x40012400) -/** ADC2 register map base pointer. */ -#define ADC2_BASE ((struct adc_reg_map*)0x40012800) -#ifdef STM32_HIGH_DENSITY -/** ADC3 register map base pointer. */ -#define ADC3_BASE ((struct adc_reg_map*)0x40013C00) -#endif +#include <series/adc.h> /* * Register bit definitions @@ -136,31 +150,9 @@ extern const adc_dev *ADC3; /* Control register 2 */ -#define ADC_CR2_ADON_BIT 0 -#define ADC_CR2_CONT_BIT 1 -#define ADC_CR2_CAL_BIT 2 -#define ADC_CR2_RSTCAL_BIT 3 -#define ADC_CR2_DMA_BIT 8 -#define ADC_CR2_ALIGN_BIT 11 -#define ADC_CR2_JEXTTRIG_BIT 15 -#define ADC_CR2_EXTTRIG_BIT 20 -#define ADC_CR2_JSWSTART_BIT 21 -#define ADC_CR2_SWSTART_BIT 22 -#define ADC_CR2_TSEREFE_BIT 23 - -#define ADC_CR2_ADON BIT(ADC_CR2_ADON_BIT) -#define ADC_CR2_CONT BIT(ADC_CR2_CONT_BIT) -#define ADC_CR2_CAL BIT(ADC_CR2_CAL_BIT) -#define ADC_CR2_RSTCAL BIT(ADC_CR2_RSTCAL_BIT) -#define ADC_CR2_DMA BIT(ADC_CR2_DMA_BIT) -#define ADC_CR2_ALIGN BIT(ADC_CR2_ALIGN_BIT) -#define ADC_CR2_JEXTSEL (0x7000) -#define ADC_CR2_JEXTTRIG BIT(ADC_CR2_JEXTTRIG_BIT) -#define ADC_CR2_EXTSEL (0xE0000) -#define ADC_CR2_EXTTRIG BIT(ADC_CR2_EXTTRIG_BIT) -#define ADC_CR2_JSWSTART BIT(ADC_CR2_JSWSTART_BIT) -#define ADC_CR2_SWSTART BIT(ADC_CR2_SWSTART_BIT) -#define ADC_CR2_TSEREFE BIT(ADC_CR2_TSEREFE_BIT) +/* Because this register varies significantly by series (e.g. some + * bits moved and others disappeared in the F1->F2 transition), its + * definitions are in the series headers. */ /* Sample time register 1 */ @@ -245,68 +237,51 @@ extern const adc_dev *ADC3; #define ADC_DR_ADC2DATA (0xFFFF << 16) #define ADC_DR_DATA 0xFFFF +/* + * Routines + */ + void adc_init(const adc_dev *dev); +void adc_set_extsel(const adc_dev *dev, adc_extsel_event event); +void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); +uint16 adc_read(const adc_dev *dev, uint8 channel); /** - * @brief External event selector for regular group conversion. - * @see adc_set_extsel + * @brief Set the ADC prescaler. + * + * This determines the ADC clock for all devices. */ -typedef enum adc_extsel_event { - ADC_ADC12_TIM1_CC1 = (0 << 17), /**< ADC1 and ADC2: Timer 1 CC1 event */ - ADC_ADC12_TIM1_CC2 = (1 << 17), /**< ADC1 and ADC2: Timer 1 CC2 event */ - ADC_ADC12_TIM1_CC3 = (2 << 17), /**< ADC1 and ADC2: Timer 1 CC3 event */ - ADC_ADC12_TIM2_CC2 = (3 << 17), /**< ADC1 and ADC2: Timer 2 CC2 event */ - ADC_ADC12_TIM3_TRGO = (4 << 17), /**< ADC1 and ADC2: Timer 3 TRGO event */ - ADC_ADC12_TIM4_CC4 = (5 << 17), /**< ADC1 and ADC2: Timer 4 CC4 event */ - ADC_ADC12_EXTI11 = (6 << 17), /**< ADC1 and ADC2: EXTI11 event */ -#ifdef STM32_HIGH_DENSITY - ADC_ADC12_TIM8_TRGO = (6 << 17), /**< ADC1 and ADC2: Timer 8 TRGO - event (high density only) */ -#endif - ADC_ADC12_SWSTART = (7 << 17), /**< ADC1 and ADC2: Software start */ -#ifdef STM32_HIGH_DENSITY - ADC_ADC3_TIM3_CC1 = (0 << 17), /**< ADC3: Timer 3 CC1 event - (high density only) */ - ADC_ADC3_TIM2_CC3 = (1 << 17), /**< ADC3: Timer 2 CC3 event - (high density only) */ - ADC_ADC3_TIM1_CC3 = (2 << 17), /**< ADC3: Timer 1 CC3 event - (high density only) */ - ADC_ADC3_TIM8_CC1 = (3 << 17), /**< ADC3: Timer 8 CC1 event - (high density only) */ - ADC_ADC3_TIM8_TRGO = (4 << 17), /**< ADC3: Timer 8 TRGO event - (high density only) */ - ADC_ADC3_TIM5_CC1 = (5 << 17), /**< ADC3: Timer 5 CC1 event - (high density only) */ - ADC_ADC3_TIM5_CC3 = (6 << 17), /**< ADC3: Timer 5 CC3 event - (high density only) */ - ADC_ADC3_SWSTART = (7 << 17), /**< ADC3: Software start (high - density only) */ -#endif - ADC_SWSTART = (7 << 17) /**< ADC1, ADC2, ADC3: Software start */ -} adc_extsel_event; +extern void adc_set_prescaler(adc_prescaler pre); -void adc_set_extsel(const adc_dev *dev, adc_extsel_event event); -void adc_foreach(void (*fn)(const adc_dev*)); +/** + * @brief Call a function on all ADC devices. + * @param fn Function to call on each ADC device. + */ +extern void adc_foreach(void (*fn)(const adc_dev*)); +struct gpio_dev; /** - * @brief ADC sample times, in ADC clock cycles - * - * These control the amount of time spent sampling the input voltage. + * @brief Configure a GPIO pin for ADC conversion. + * @param dev ADC device to use for conversion (currently ignored on + * all targets). + * @param gdev GPIO device to configure. + * @param bit Bit on gdev to configure for ADC conversion. */ -typedef enum { - ADC_SMPR_1_5, /**< 1.5 ADC cycles */ - ADC_SMPR_7_5, /**< 7.5 ADC cycles */ - ADC_SMPR_13_5, /**< 13.5 ADC cycles */ - ADC_SMPR_28_5, /**< 28.5 ADC cycles */ - ADC_SMPR_41_5, /**< 41.5 ADC cycles */ - ADC_SMPR_55_5, /**< 55.5 ADC cycles */ - ADC_SMPR_71_5, /**< 71.5 ADC cycles */ - ADC_SMPR_239_5 /**< 239.5 ADC cycles */ -} adc_smp_rate; +extern void adc_config_gpio(const struct adc_dev *dev, + struct gpio_dev *gdev, + uint8 bit); -void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); -void adc_calibrate(const adc_dev *dev); -uint16 adc_read(const adc_dev *dev, uint8 channel); +/** + * @brief Enable an ADC and configure it for single conversion mode. + * + * This function performs any initialization necessary to allow the + * ADC device to perform a single synchronous regular software + * triggered conversion, using adc_read(). + * + * @param dev Device to enable. + * @see adc_read() + */ +extern void adc_enable_single_swstart(const adc_dev* dev); /** * @brief Set the regular channel sequence length. @@ -325,16 +300,6 @@ static inline void adc_set_reg_seqlen(const adc_dev *dev, uint8 length) { } /** - * @brief Set external trigger conversion mode event for regular channels - * @param dev ADC device - * @param enable If 1, conversion on external events is enabled; if 0, - * disabled. - */ -static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { - *bb_perip(&dev->regs->CR2, ADC_CR2_EXTTRIG_BIT) = !!enable; -} - -/** * @brief Enable an adc peripheral * @param dev ADC device to enable */ diff --git a/libmaple/bitband.h b/libmaple/include/libmaple/bitband.h index 73941b0..6e77991 100644 --- a/libmaple/bitband.h +++ b/libmaple/include/libmaple/bitband.h @@ -25,15 +25,19 @@ *****************************************************************************/ /** - * @file bitband.h + * @file libmaple/include/libmaple/bitband.h * * @brief Bit-banding utility functions */ -#include "libmaple_types.h" +#ifndef _LIBMAPLE_BITBAND_H_ +#define _LIBMAPLE_BITBAND_H_ -#ifndef _BITBAND_H_ -#define _BITBAND_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> #define BB_SRAM_REF 0x20000000 #define BB_SRAM_BASE 0x22000000 @@ -47,7 +51,7 @@ static inline volatile uint32* __bb_addr(volatile void*, /** * @brief Obtain a pointer to the bit-band address corresponding to a - * bit in a volatile SRAM address. + * bit in a volatile SRAM address. * @param address Address in the bit-banded SRAM region * @param bit Bit in address to bit-band */ @@ -79,7 +83,7 @@ static inline void bb_sram_set_bit(volatile void *address, /** * @brief Obtain a pointer to the bit-band address corresponding to a - * bit in a peripheral address. + * bit in a peripheral address. * @param address Address in the bit-banded peripheral region * @param bit Bit in address to bit-band */ @@ -117,4 +121,8 @@ static inline volatile uint32* __bb_addr(volatile void *address, bit * 4); } -#endif /* _BITBAND_H_ */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/bkp.h b/libmaple/include/libmaple/bkp.h index a81267d..bb63a2f 100644 --- a/libmaple/bkp.h +++ b/libmaple/include/libmaple/bkp.h @@ -25,19 +25,19 @@ *****************************************************************************/ /** - * @file bkp.h - * @brief Backup register support. + * @file libmaple/include/libmaple/bkp.h + * @brief Backup register support (STM32F1 only). */ -#ifndef _BKP_H_ -#define _BKP_H_ - -#include "libmaple.h" +#ifndef _LIBMAPLE_BKP_H_ +#define _LIBMAPLE_BKP_H_ #ifdef __cplusplus extern "C" { #endif +#include <libmaple/libmaple.h> + #if defined(STM32_MEDIUM_DENSITY) #define BKP_NR_DATA_REGS 10 #elif defined(STM32_HIGH_DENSITY) @@ -60,7 +60,7 @@ typedef struct bkp_reg_map { __io uint32 RTCCR; ///< RTC control register __io uint32 CR; ///< Control register __io uint32 CSR; ///< Control and status register -#ifdef STM32_HIGH_DENSITY +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) const uint32 RESERVED2; ///< Reserved const uint32 RESERVED3; ///< Reserved __io uint32 DR11; ///< Data register 11 diff --git a/libmaple/include/libmaple/dac.h b/libmaple/include/libmaple/dac.h new file mode 100644 index 0000000..56bfdc4 --- /dev/null +++ b/libmaple/include/libmaple/dac.h @@ -0,0 +1,158 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * Copyright (c) 2010 Bryan Newbold. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/dac.h + * @brief Digital to analog converter support. + */ + +/* See notes/dac.txt for more info */ + +#ifndef _LIBMAPLE_DAC_H_ +#define _LIBMAPLE_DAC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <series/dac.h> +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> +#include <libmaple/stm32.h> + +/* + * Register map base and device pointers. + * + * The DACs are the same on all supported targets, so it's not worth + * repeating these in the series headers. + */ + +#define DAC_BASE ((struct dac_reg_map*)0x40007400) + +/** DAC device type. */ +typedef struct dac_dev { + dac_reg_map *regs; /**< Register map */ +} dac_dev; + +#if STM32_HAVE_DAC +extern const dac_dev *DAC; +#endif + +/* + * Register bit definitions + */ + +/* Control register */ + +/* Channel 1 control */ +#define DAC_CR_EN1 (1U << 0) /* Enable */ +#define DAC_CR_BOFF1 (1U << 1) /* Output buffer disable */ +#define DAC_CR_TEN1 (1U << 2) /* Trigger enable */ +#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */ +#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave */ +#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */ +#define DAC_CR_DMAEN1 (1U << 12) /* DMA enable */ +/* Channel 2 control */ +#define DAC_CR_EN2 (1U << 16) /* Enable */ +#define DAC_CR_BOFF2 (1U << 17) /* Output buffer disable */ +#define DAC_CR_TEN2 (1U << 18) /* Trigger enable */ +#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */ +#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave */ +#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */ +#define DAC_CR_DMAEN2 (1U << 28) /* DMA enable */ + +/* Software trigger register */ + +#define DAC_SWTRIGR_SWTRIG1 (1U << 0) /* Channel 1 software trigger */ +#define DAC_SWTRIGR_SWTRIG2 (1U << 1) /* Channel 2 software trigger */ + +/* Channel 1 12-bit right-aligned data holding register */ + +#define DAC_DHR12R1_DACC1DHR 0x00000FFF + +/* Channel 1 12-bit left-aligned data holding register */ + +#define DAC_DHR12L1_DACC1DHR 0x0000FFF0 + +/* Channel 1 8-bit left-aligned data holding register */ + +#define DAC_DHR8R1_DACC1DHR 0x000000FF + +/* Channel 2 12-bit right-aligned data holding register */ + +#define DAC_DHR12R2_DACC2DHR 0x00000FFF + +/* Channel 2 12-bit left-aligned data holding register */ + +#define DAC_DHR12L2_DACC2DHR 0x0000FFF0 + +/* Channel 2 8-bit left-aligned data holding register */ + +#define DAC_DHR8R2_DACC2DHR 0x000000FF + +/* Dual DAC 12-bit right-aligned data holding register */ + +#define DAC_DHR12RD_DACC1DHR 0x00000FFF +#define DAC_DHR12RD_DACC2DHR 0x0FFF0000 + +/* Dual DAC 12-bit left-aligned data holding register */ + +#define DAC_DHR12LD_DACC1DHR 0x0000FFF0 +#define DAC_DHR12LD_DACC2DHR 0xFFF00000 + +/* Dual DAC 8-bit left-aligned data holding register */ + +#define DAC_DHR8RD_DACC1DHR 0x000000FF +#define DAC_DHR8RD_DACC2DHR 0x0000FF00 + +/* Channel 1 data output register */ + +#define DAC_DOR1_DACC1DOR 0x00000FFF + +/* Channel 1 data output register */ + +#define DAC_DOR2_DACC2DOR 0x00000FFF + +/* + * Routines + */ + +/* We take the dev argument in these for future-proofing */ + +#define DAC_CH1 0x1 +#define DAC_CH2 0x2 +void dac_init(const dac_dev *dev, uint32 flags); + +void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val); +void dac_enable_channel(const dac_dev *dev, uint8 channel); +void dac_disable_channel(const dac_dev *dev, uint8 channel); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/exti.h b/libmaple/include/libmaple/delay.h index f225844..472a208 100644 --- a/libmaple/exti.h +++ b/libmaple/include/libmaple/delay.h @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,50 +26,40 @@ *****************************************************************************/ /** - * @file exti.h - * @brief External interrupt control prototypes and defines + * @file libmaple/include/libmaple/delay.h + * @brief Delay implementation */ -/* See notes/exti.txt for more info */ - -#include "libmaple.h" -#include "gpio.h" - -#ifndef _EXTI_H_ -#define _EXTI_H_ +#ifndef _LIBMAPLE_DELAY_H_ +#define _LIBMAPLE_DELAY_H_ #ifdef __cplusplus -extern "C"{ +extern "C" { #endif -/** EXTI register map type */ -typedef struct exti_reg_map { - __io uint32 IMR; /**< Interrupt mask register */ - __io uint32 EMR; /**< Event mask register */ - __io uint32 RTSR; /**< Rising trigger selection register */ - __io uint32 FTSR; /**< Falling trigger selection register */ - __io uint32 SWIER; /**< Software interrupt event register */ - __io uint32 PR; /**< Pending register */ -} exti_reg_map; - -/** EXTI register map base pointer */ -#define EXTI_BASE ((struct exti_reg_map*)0x40010400) +#include <libmaple/libmaple_types.h> +#include <libmaple/stm32.h> -/** External interrupt trigger mode */ -typedef enum exti_trigger_mode { - EXTI_RISING, /**< Trigger on the rising edge */ - EXTI_FALLING, /**< Trigger on the falling edge */ - EXTI_RISING_FALLING /**< Trigger on both the rising and falling edges */ -} exti_trigger_mode; +/** + * @brief Delay the given number of microseconds. + * + * @param us Number of microseconds to delay. + */ +static inline void delay_us(uint32 us) { + us *= STM32_DELAY_US_MULT; -void exti_attach_interrupt(afio_exti_num num, - afio_exti_port port, - voidFuncPtr handler, - exti_trigger_mode mode); -void exti_detach_interrupt(afio_exti_num num); + /* fudge for function call overhead */ + us--; + asm volatile(" mov r0, %[us] \n\t" + "1: subs r0, #1 \n\t" + " bhi 1b \n\t" + : + : [us] "r" (us) + : "r0"); +} #ifdef __cplusplus -} // extern "C" +} #endif #endif diff --git a/libmaple/include/libmaple/dma.h b/libmaple/include/libmaple/dma.h new file mode 100644 index 0000000..0b1ec4c --- /dev/null +++ b/libmaple/include/libmaple/dma.h @@ -0,0 +1,444 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Michael Hope. + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/dma.h + * + * @author Marti Bolivar <mbolivar@leaflabs.com>; + * Original implementation by Michael Hope + * + * @brief Direct Memory Access peripheral support + */ + +#ifndef _LIBMAPLE_DMA_H_ +#define _LIBMAPLE_DMA_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/* <series/dma.h> provides: + * + * - An opaque dma_tube type, and predefined rvalues for each tube + * supported by the series. + * + * A "DMA tube" is a series-specific (hopefully integer) datatype + * that abstracts the conduit through which DMA-ed data flow. + * + * Examples: On STM32F1, dma_tube is just an alias for dma_channel, + * and the tube values are just DMA_CH1 (=1), DMA_CH2 (=2), etc. + * + * Note that a dma_tube doesn't have to be an enum, and its values + * don't have to be integral. They _do_ need to be cheap to pass as + * arguments, though. + * + * - struct dma_tube_reg_map (and typedef to dma_tube_reg_map). DMA + * register maps tend to be split into global registers and per-tube + * registers. It's convenient to pass around pointers to a tube's + * registers, since that makes it possible to configure or otherwise + * mess with a tube without knowing which one you're dealing with. + * + * - Base pointers to the various dma_tube_reg_maps. + * + * Examples: On STM32F1, these are DMAxCHy_BASE. You can access + * registers like DMAxCHy_BASE->CPAR, etc. + * + * - enum dma_request_src (and typedef to dma_request_src). This + * specifies the peripheral DMA request sources (e.g. USART TX DMA + * requests, etc.). + * + * - enum dma_mode_flags (and typedef to dma_mode_flags). Used in + * dma_tube_config. If two series both support the same mode flags, + * they must use the same enumerator names for those flags (the + * values of those enumerators are of course allowed to differ). + * + * - Normal stuff: dma_reg_map and base pointers, register bit + * definitions, dma_dev pointer declarations, and any other + * convenience functions useful for the series. */ +#include <series/dma.h> +/* <libmaple/dma_common.h> buys us dma_dev and other necessities. */ +#include <libmaple/dma_common.h> +#include <libmaple/libmaple_types.h> + +/* + * Declarations/documentation for some of the series-provided types. + */ + +/** + * @brief (Series-dependent) DMA request sources. + * + * These specify the various pieces of peripheral functionality which + * may make DMA requests. Use them to set up a DMA transfer (see + * struct dma_tube_config, dma_tube_cfg()). + */ +enum dma_request_src; + +/** + * @brief (Series-dependent) DMA tube configuration flags. + * These specify miscellaneous bits of configuration for a DMA tube. + * @see struct dma_mode_config + */ +enum dma_cfg_flags; + +/** + * @brief (Series-dependent) DMA tube register map type. + * This allows you to access a tube's registers as a group. + * @see dma_tube_regs() + */ +struct dma_tube_reg_map; + +/* + * Convenience functions + */ + +/* Initialization */ + +void dma_init(dma_dev *dev); + +/* dma_tube configuration + * + * Use these types and functions to set up DMA transfers, handle + * interrupts, etc. The main function of interest is dma_tube_cfg(), + * which the various series implement separately. */ + +/** + * @brief Specifies a DMA tube configuration. + * + * Use one of these to set up a DMA transfer by passing it to + * dma_tube_cfg(). + * + * @see dma_tube_cfg() + * @see dma_xfer_size + */ +typedef struct dma_tube_config { + /** Source of data */ + __io void *tube_src; + /** Source transfer size */ + dma_xfer_size tube_src_size; + + /** Destination of data */ + __io void *tube_dst; + /** Destination transfer size */ + dma_xfer_size tube_dst_size; + + /** + * Number of data to transfer (0 to 65,535). + * + * Note that this is NOT measured in bytes; it's measured in + * number of data, which occur in multiples of tube_src_size. For + * example, if tube_src_size is DMA_SIZE_32BITS and tube_nr_xfers + * is 2, then 8 total bytes will be transferred. + */ + unsigned tube_nr_xfers; + + /** + * Target-specific configuration flags. + * + * These are an OR of series-specific enum dma_mode_flags values. + * Consult the documentation for your target for what flags you + * can use here. + * + * Typical flag examples: DMA_CFG_SRC_INC, DMA_CFG_DST_INC, + * DMA_CFG_CIRC, DMA_CFG_CMPLT_IE, etc. + */ + unsigned tube_flags; + + /** + * Currently unused. You must set this to 0 or something valid for + * your target. */ + void *target_data; + + /** + * Hardware DMA request source. + * + * This is ignored for memory-to-memory transfers. + */ + enum dma_request_src tube_req_src; +} dma_tube_config; + +#define DMA_TUBE_CFG_SUCCESS 0 +#define DMA_TUBE_CFG_EREQ 1 +#define DMA_TUBE_CFG_ENDATA 2 +#define DMA_TUBE_CFG_EDEV 3 +#define DMA_TUBE_CFG_ESRC 4 +#define DMA_TUBE_CFG_EDST 5 +#define DMA_TUBE_CFG_EDIR 6 +#define DMA_TUBE_CFG_ESIZE 7 +#define DMA_TUBE_CFG_ECFG 0xFF +/** + * @brief Configure a DMA tube. + * + * Use this function to set up a DMA transfer. The tube will be + * disabled before being reconfigured. The transfer will have low + * priority by default. You can choose another priority before the + * transfer begins using dma_set_priority(). You can manage your + * interrupt handlers for the tube using dma_attach_interrupt() and + * dma_detach_interrupt(). + * + * After calling dma_tube_cfg() and performing any other desired + * configuration, start the transfer using dma_enable(). + * + * @param dev DMA device. + * @param tube DMA tube to configure. + * @param cfg Configuration to apply to tube. + * + * @return DMA_TUBE_CFG_SUCCESS (0) on success, <0 on failure. On + * failure, returned value will be the opposite (-) of one of: + * + * - DMA_TUBE_CFG_EREQ: tube doesn't work with cfg->tube_req_src + * - DMA_TUBE_CFG_ENDATA: cfg->tube_[src,dst]_size are + * incompatible with cfg->tube_nr_xfers, or cfg->tube_nr_xfers + * is out of bounds. + * - DMA_TUBE_CFG_EDEV: dev does not support cfg + * - DMA_TUBE_CFG_ESRC: bad cfg->tube_src + * - DMA_TUBE_CFG_EDST: bad cfg->tube_dst + * - DMA_TUBE_CFG_EDIR: dev can't transfer from cfg->tube_src to + * cfg->tube_dst + * - DMA_TUBE_CFG_ESIZE: something ended up wrong due to MSIZE/PSIZE + * - DMA_TUBE_CFG_ECFG: generic "something's wrong" + * + * @sideeffect Disables tube. May alter tube's registers even when an + * error occurs. + * @see struct dma_tube_config + * @see dma_attach_interrupt() + * @see dma_detach_interrupt() + * @see dma_enable() + */ +extern int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg); + +/* Other tube configuration functions. You can use these if + * dma_tube_cfg() isn't enough, or to adjust parts of an existing tube + * configuration. */ + +/** DMA transfer priority. */ +typedef enum dma_priority { + DMA_PRIORITY_LOW = 0, /**< Low priority */ + DMA_PRIORITY_MEDIUM = 1, /**< Medium priority */ + DMA_PRIORITY_HIGH = 2, /**< High priority */ + DMA_PRIORITY_VERY_HIGH = 3, /**< Very high priority */ +} dma_priority; + +/** + * @brief Set the priority of a DMA transfer. + * + * You may not call this function while the tube is enabled. + * + * @param dev DMA device + * @param tube DMA tube + * @param priority priority to set. + */ +extern void dma_set_priority(dma_dev *dev, dma_tube tube, + dma_priority priority); + +/** + * @brief Set the number of data transfers on a DMA tube. + * + * You may not call this function while the tube is enabled. + * + * @param dev DMA device + * @param tube Tube through which the transfer will occur. + * @param num_transfers Number of DMA transactions to set. + */ +extern void dma_set_num_transfers(dma_dev *dev, dma_tube tube, + uint16 num_transfers); + +/** + * @brief Set the base memory address where data will be read from or + * written to. + * + * You must not call this function while the tube is enabled. + * + * If the DMA memory size is 16 bits, the address is automatically + * aligned to a half-word. If the DMA memory size is 32 bits, the + * address is aligned to a word. + * + * @param dev DMA Device + * @param tube Tube whose base memory address to set. + * @param address Memory base address to use. + */ +extern void dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *address); + +/** + * @brief Set the base peripheral address where data will be read from + * or written to. + * + * You must not call this function while the channel is enabled. + * + * If the DMA peripheral size is 16 bits, the address is automatically + * aligned to a half-word. If the DMA peripheral size is 32 bits, the + * address is aligned to a word. + * + * @param dev DMA Device + * @param tube Tube whose peripheral data register base address to set. + * @param addr Peripheral memory base address to use. + */ +extern void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address); + +/* Interrupt handling */ + +/** + * @brief Attach an interrupt to a DMA transfer. + * + * Interrupts are enabled using series-specific mode flags in + * dma_tube_cfg(). + * + * @param dev DMA device + * @param tube Tube to attach handler to + * @param handler Interrupt handler to call when tube interrupt fires. + * @see dma_tube_cfg() + * @see dma_get_irq_cause() + * @see dma_detach_interrupt() + */ +extern void dma_attach_interrupt(dma_dev *dev, dma_tube tube, + void (*handler)(void)); + + +/** + * @brief Detach a DMA transfer interrupt handler. + * + * After calling this function, the given tube's interrupts will be + * disabled. + * + * @param dev DMA device + * @param tube Tube whose handler to detach + * @sideeffect Clears the tube's interrupt enable bits. + * @see dma_attach_interrupt() + */ +extern void dma_detach_interrupt(dma_dev *dev, dma_tube tube); + +/* Tube enable/disable */ + +/** + * @brief Enable a DMA tube. + * + * If the tube has been properly configured, calling this function + * allows it to start serving DMA requests. + * + * @param dev DMA device + * @param tube Tube to enable + * @see dma_tube_cfg() + */ +extern void dma_enable(dma_dev *dev, dma_tube tube); + +/** + * @brief Disable a DMA channel. + * + * Calling this function makes the tube stop serving DMA requests. + * + * @param dev DMA device + * @param tube Tube to disable + */ +extern void dma_disable(dma_dev *dev, dma_tube tube); + +/** + * @brief Check if a DMA tube is enabled. + * @param dev DMA device. + * @param tube Tube to check. + * @return 0 if the tube is disabled, >0 if it is enabled. + */ +static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube); + +/* Other conveniences */ + +/** + * @brief Obtain a pointer to an individual DMA tube's registers. + * + * Examples: + * + * - On STM32F1, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1. + * + * @param dev DMA device. + * @param tube DMA tube whose register map to obtain. + * @return (Series-specific) tube register map. + */ +static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube); + +/** + * Encodes the reason why a DMA interrupt was called. + * @see dma_get_irq_cause() + */ +typedef enum dma_irq_cause { + DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */ + DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */ + DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */ + DMA_TRANSFER_DME_ERROR, /**< + * @brief Direct mode error occurred during + * transfer. */ + DMA_TRANSFER_FIFO_ERROR, /**< FIFO error occurred during transfer. */ +} dma_irq_cause; + +/** + * @brief Discover the reason why a DMA interrupt was called. + * + * You may only call this function within an attached interrupt + * handler for the given channel. + * + * This function resets the internal DMA register state which encodes + * the cause of the interrupt; consequently, it can only be called + * once per interrupt handler invocation. + * + * @param dev DMA device + * @param tube Tube whose interrupt is being handled. + * @return Reason why the interrupt fired. + * @sideeffect Clears flags in dev's interrupt status registers. + * @see dma_attach_interrupt() + * @see dma_irq_cause + */ +extern dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube); + +/** + * @brief Get the ISR status bits for a DMA channel. + * + * The bits are returned right-aligned, in the order they appear in + * the corresponding ISR register. + * + * If you're trying to figure out why a DMA interrupt fired, you may + * find dma_get_irq_cause() more convenient. + * + * @param dev DMA device + * @param tube Tube whose ISR bits to return. + * @see dma_get_irq_cause(). + */ +static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube); + +/** + * @brief Clear the ISR status bits for a given DMA tube. + * + * If you're trying to clean up after yourself in a DMA interrupt, you + * may find dma_get_irq_cause() more convenient. + * + * @param dev DMA device + * @param tube Tube whose ISR bits to clear. + * @see dma_get_irq_cause() + */ +static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/dma_common.h b/libmaple/include/libmaple/dma_common.h new file mode 100644 index 0000000..67475f7 --- /dev/null +++ b/libmaple/include/libmaple/dma_common.h @@ -0,0 +1,114 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/dma_common.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief Common DMA sub-header for <series/dma.h> and <libmaple/dma.h>. + * + * WARNING: CONTENTS UNSTABLE + * + * The existence of this file is an implementation detail. Its + * contents are not stable, so never include it directly. If you need + * something from here, #include <libmaple/dma.h> instead. + */ + +/* + * There's a fair amount of common DMA functionality needed by each + * <series/dma.h> and <libmaple/dma.h>. This header exists in order + * to provide it to both, avoiding some hacks and circular + * dependencies. + */ + +#ifndef _LIBMAPLE_DMA_COMMON_H_ +#define _LIBMAPLE_DMA_COMMON_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/nvic.h> +#include <libmaple/rcc.h> + +/* + * Devices + */ + +struct dma_reg_map; + +/* Encapsulates state related to user interrupt handlers. You + * shouldn't touch these directly; use dma_attach_interrupt() and + * dma_detach_interupt() instead. */ +typedef struct dma_handler_config { + void (*handler)(void); /* User handler */ + nvic_irq_num irq_line; /* IRQ line for interrupt */ +} dma_handler_config; + +/** DMA device type */ +typedef struct dma_dev { + struct dma_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< Clock ID */ + struct dma_handler_config handlers[]; /**< For internal use */ +} dma_dev; + +/** + * @brief DMA channels + * + * Notes: + * - This is also the dma_tube type for STM32F1. + * - Channel 0 is not available on all STM32 series. + * + * @see dma_tube + */ +typedef enum dma_channel { + DMA_CH0 = 0, /**< Channel 0 */ + DMA_CH1 = 1, /**< Channel 1 */ + DMA_CH2 = 2, /**< Channel 2 */ + DMA_CH3 = 3, /**< Channel 3 */ + DMA_CH4 = 4, /**< Channel 4 */ + DMA_CH5 = 5, /**< Channel 5 */ + DMA_CH6 = 6, /**< Channel 6 */ + DMA_CH7 = 7, /**< Channel 7 */ +} dma_channel; + +/** + * @brief Source and destination transfer sizes. + * Use these when initializing a struct dma_tube_config. + * @see struct dma_tube_config + * @see dma_tube_cfg + */ +typedef enum dma_xfer_size { + DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ + DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ + DMA_SIZE_32BITS = 2, /**< 32-bit transfers */ +} dma_xfer_size; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/exti.h b/libmaple/include/libmaple/exti.h new file mode 100644 index 0000000..3800b4a --- /dev/null +++ b/libmaple/include/libmaple/exti.h @@ -0,0 +1,138 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/exti.h + * @brief External interrupt control + */ + +/* See notes/exti.txt for more info */ + +#ifndef _LIBMAPLE_EXTI_H_ +#define _LIBMAPLE_EXTI_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <series/exti.h> /* provides EXTI_BASE */ +#include <libmaple/libmaple_types.h> + +/* + * Register map and base pointer. + */ + +/** EXTI register map type */ +typedef struct exti_reg_map { + __io uint32 IMR; /**< Interrupt mask register */ + __io uint32 EMR; /**< Event mask register */ + __io uint32 RTSR; /**< Rising trigger selection register */ + __io uint32 FTSR; /**< Falling trigger selection register */ + __io uint32 SWIER; /**< Software interrupt event register */ + __io uint32 PR; /**< Pending register */ +} exti_reg_map; + +/* + * Types: exti_num, exti_cfg, exti_trigger_mode. + * + * A combination of these three specifies an external interrupt + * configuration (see exti_attach_interrupt()). + */ + +/** EXTI line. */ +typedef enum exti_num { + EXTI0, /**< EXTI line 0 */ + EXTI1, /**< EXTI line 1 */ + EXTI2, /**< EXTI line 2 */ + EXTI3, /**< EXTI line 3 */ + EXTI4, /**< EXTI line 4 */ + EXTI5, /**< EXTI line 5 */ + EXTI6, /**< EXTI line 6 */ + EXTI7, /**< EXTI line 7 */ + EXTI8, /**< EXTI line 8 */ + EXTI9, /**< EXTI line 9 */ + EXTI10, /**< EXTI line 10 */ + EXTI11, /**< EXTI line 11 */ + EXTI12, /**< EXTI line 12 */ + EXTI13, /**< EXTI line 13 */ + EXTI14, /**< EXTI line 14 */ + EXTI15, /**< EXTI line 15 */ +} exti_num; + +/** + * @brief EXTI port configuration + * + * These specify which GPIO port an external interrupt line should be + * connected to. + */ +typedef enum exti_cfg { + EXTI_PA, /**< Use PAx pin */ + EXTI_PB, /**< Use PBx pin */ + EXTI_PC, /**< Use PCx pin */ + EXTI_PD, /**< Use PDx pin */ + EXTI_PE, /**< Use PEx pin */ + EXTI_PF, /**< Use PFx pin */ + EXTI_PG, /**< Use PGx pin */ + EXTI_PH, /**< Use PHx pin */ + EXTI_PI, /**< Use PIx pin */ +} exti_cfg; + +/** External interrupt trigger mode */ +typedef enum exti_trigger_mode { + EXTI_RISING, /**< Trigger on the rising edge */ + EXTI_FALLING, /**< Trigger on the falling edge */ + EXTI_RISING_FALLING /**< Trigger on both the rising and falling edges */ +} exti_trigger_mode; + +/* + * Routines + */ + +void exti_attach_interrupt(exti_num num, + exti_cfg port, + voidFuncPtr handler, + exti_trigger_mode mode); +void exti_detach_interrupt(exti_num num); + +/** + * @brief Set the GPIO port for an EXTI line. + * + * This is a low-level routine that most users will not + * need. exti_attach_interrupt() handles calling this function + * appropriately. + * + * @param num EXTI line + * @param port EXTI configuration for GPIO port to connect to num. + * @see exti_num + * @see exti_cfg + */ +extern void exti_select(exti_num num, exti_cfg port); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/include/libmaple/flash.h b/libmaple/include/libmaple/flash.h new file mode 100644 index 0000000..943e466 --- /dev/null +++ b/libmaple/include/libmaple/flash.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/flash.h + * @brief Flash support. + */ + +#ifndef _LIBMAPLE_FLASH_H_ +#define _LIBMAPLE_FLASH_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +#define FLASH_WAIT_STATE_0 0x0 +#define FLASH_WAIT_STATE_1 0x1 +#define FLASH_WAIT_STATE_2 0x2 +#define FLASH_WAIT_STATE_3 0x3 +#define FLASH_WAIT_STATE_4 0x4 +#define FLASH_WAIT_STATE_5 0x5 +#define FLASH_WAIT_STATE_6 0x6 +#define FLASH_WAIT_STATE_7 0x7 + +/* The series header must define: + * + * - FLASH_SAFE_WAIT_STATES, the smallest number of wait states that + * it is safe to use when SYSCLK is at its fastest documented rate + * and the MCU is powered at 3.3V (i.e. this doesn't consider + * overclocking or low voltage operation). + * + * - The following bit flags, for flash_enable_features(): + * + * -- FLASH_PREFETCH: prefetcher + * -- FLASH_ICACHE: instruction cache + * -- FLASH_DCACHE: data cache + * + * See that function's Doxygen for more restrictions. + */ +#include <series/flash.h> + +#ifdef __DOXYGEN__ +/** Flash register map base pointer. */ +#define FLASH_BASE +#endif + +/* + * Flash routines + */ + +void flash_set_latency(uint32 wait_states); + +/** + * @brief Enable Flash memory features + * + * If the target MCU doesn't provide a feature (e.g. instruction and + * data caches on the STM32F1), the flag will be ignored. This allows + * using these flags unconditionally, with the desired effect taking + * place on targets that support them. + * + * @param feature_flags Bitwise OR of the following: + * FLASH_PREFETCH (turns on prefetcher), + * FLASH_ICACHE (turns on instruction cache), + * FLASH_DCACHE (turns on data cache). + */ +static inline void flash_enable_features(uint32 feature_flags) { + FLASH_BASE->ACR |= feature_flags; +} + +/** + * @brief Deprecated. Use flash_enable_features(FLASH_PREFETCH) instead. + */ +static inline void flash_enable_prefetch(void) { + flash_enable_features(FLASH_PREFETCH); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/fsmc.h b/libmaple/include/libmaple/fsmc.h index ef82b08..6225fee 100644 --- a/libmaple/fsmc.h +++ b/libmaple/include/libmaple/fsmc.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file fsmc.h + * @file libmaple/include/libmaple/fsmc.h * @brief Flexible static memory controller support. */ @@ -33,20 +33,19 @@ * See ../notes/fsmc.txt for more info */ -#include "libmaple_types.h" - -/** - * @file fsmc.h - */ - -#ifndef _FSMC_H_ -#define _FSMC_H_ +#ifndef _LIBMAPLE_FSMC_H_ +#define _LIBMAPLE_FSMC_H_ #ifdef __cplusplus extern "C"{ #endif -#ifdef STM32_HIGH_DENSITY +#include <libmaple/libmaple_types.h> +#include <libmaple/stm32.h> + +#if !STM32_HAVE_FSMC +#error "FSMC is unavailable on your MCU" +#endif /* * Register maps and devices @@ -136,16 +135,16 @@ typedef struct fsmc_nor_psram_reg_map { #define FSMC_BCR_MUXEN_BIT 1 #define FSMC_BCR_MBKEN_BIT 0 -#define FSMC_BCR_CBURSTRW BIT(FSMC_BCR_CBURSTRW_BIT) -#define FSMC_BCR_ASYNCWAIT BIT(FSMC_BCR_ASYNCWAIT_BIT) -#define FSMC_BCR_EXTMOD BIT(FSMC_BCR_EXTMOD_BIT) -#define FSMC_BCR_WAITEN BIT(FSMC_BCR_WAITEN_BIT) -#define FSMC_BCR_WREN BIT(FSMC_BCR_WREN_BIT) -#define FSMC_BCR_WAITCFG BIT(FSMC_BCR_WAITCFG_BIT) -#define FSMC_BCR_WRAPMOD BIT(FSMC_BCR_WRAPMOD_BIT) -#define FSMC_BCR_WAITPOL BIT(FSMC_BCR_WAITPOL_BIT) -#define FSMC_BCR_BURSTEN BIT(FSMC_BCR_BURSTEN_BIT) -#define FSMC_BCR_FACCEN BIT(FSMC_BCR_FACCEN_BIT) +#define FSMC_BCR_CBURSTRW (1U << FSMC_BCR_CBURSTRW_BIT) +#define FSMC_BCR_ASYNCWAIT (1U << FSMC_BCR_ASYNCWAIT_BIT) +#define FSMC_BCR_EXTMOD (1U << FSMC_BCR_EXTMOD_BIT) +#define FSMC_BCR_WAITEN (1U << FSMC_BCR_WAITEN_BIT) +#define FSMC_BCR_WREN (1U << FSMC_BCR_WREN_BIT) +#define FSMC_BCR_WAITCFG (1U << FSMC_BCR_WAITCFG_BIT) +#define FSMC_BCR_WRAPMOD (1U << FSMC_BCR_WRAPMOD_BIT) +#define FSMC_BCR_WAITPOL (1U << FSMC_BCR_WAITPOL_BIT) +#define FSMC_BCR_BURSTEN (1U << FSMC_BCR_BURSTEN_BIT) +#define FSMC_BCR_FACCEN (1U << FSMC_BCR_FACCEN_BIT) #define FSMC_BCR_MWID (0x3 << 4) #define FSMC_BCR_MWID_8BITS (0x0 << 4) #define FSMC_BCR_MWID_16BITS (0x1 << 4) @@ -153,8 +152,8 @@ typedef struct fsmc_nor_psram_reg_map { #define FSMC_BCR_MTYP_SRAM (0x0 << 2) #define FSMC_BCR_MTYP_PSRAM (0x1 << 2) #define FSMC_BCR_MTYP_NOR_FLASH (0x2 << 2) -#define FSMC_BCR_MUXEN BIT(FSMC_BCR_MUXEN_BIT) -#define FSMC_BCR_MBKEN BIT(FSMC_BCR_MBKEN_BIT) +#define FSMC_BCR_MUXEN (1U << FSMC_BCR_MUXEN_BIT) +#define FSMC_BCR_MBKEN (1U << FSMC_BCR_MBKEN_BIT) /* SRAM/NOR-Flash chip-select timing registers */ @@ -199,15 +198,15 @@ typedef struct fsmc_nor_psram_reg_map { #define FSMC_PCR_ECCPS_8192B (0x5 << 17) #define FSMC_PCR_TAR (0xF << 13) #define FSMC_PCR_TCLR (0xF << 9) -#define FSMC_PCR_ECCEN BIT(FSMC_PCR_ECCEN_BIT) +#define FSMC_PCR_ECCEN (1U << FSMC_PCR_ECCEN_BIT) #define FSMC_PCR_PWID (0x3 << 4) #define FSMC_PCR_PWID_8BITS (0x0 << 4) #define FSMC_PCR_PWID_16BITS (0x1 << 4) -#define FSMC_PCR_PTYP BIT(FSMC_PCR_PTYP_BIT) +#define FSMC_PCR_PTYP (1U << FSMC_PCR_PTYP_BIT) #define FSMC_PCR_PTYP_PC_CF_PCMCIA (0x0 << FSMC_PCR_PTYP_BIT) #define FSMC_PCR_PTYP_NAND (0x1 << FSMC_PCR_PTYP_BIT) -#define FSMC_PCR_PBKEN BIT(FSMC_PCR_PBKEN_BIT) -#define FSMC_PCR_PWAITEN BIT(FSMC_PCR_PWAITEN_BIT) +#define FSMC_PCR_PBKEN (1U << FSMC_PCR_PBKEN_BIT) +#define FSMC_PCR_PWAITEN (1U << FSMC_PCR_PWAITEN_BIT) /* FIFO status and interrupt registers */ @@ -219,13 +218,13 @@ typedef struct fsmc_nor_psram_reg_map { #define FSMC_SR_ILS_BIT 1 #define FSMC_SR_IRS_BIT 0 -#define FSMC_SR_FEMPT BIT(FSMC_SR_FEMPT_BIT) -#define FSMC_SR_IFEN BIT(FSMC_SR_IFEN_BIT) -#define FSMC_SR_ILEN BIT(FSMC_SR_ILEN_BIT) -#define FSMC_SR_IREN BIT(FSMC_SR_IREN_BIT) -#define FSMC_SR_IFS BIT(FSMC_SR_IFS_BIT) -#define FSMC_SR_ILS BIT(FSMC_SR_ILS_BIT) -#define FSMC_SR_IRS BIT(FSMC_SR_IRS_BIT) +#define FSMC_SR_FEMPT (1U << FSMC_SR_FEMPT_BIT) +#define FSMC_SR_IFEN (1U << FSMC_SR_IFEN_BIT) +#define FSMC_SR_ILEN (1U << FSMC_SR_ILEN_BIT) +#define FSMC_SR_IREN (1U << FSMC_SR_IREN_BIT) +#define FSMC_SR_IFS (1U << FSMC_SR_IFS_BIT) +#define FSMC_SR_ILS (1U << FSMC_SR_ILS_BIT) +#define FSMC_SR_IRS (1U << FSMC_SR_IRS_BIT) /* Common memory space timing registers */ @@ -252,35 +251,58 @@ typedef struct fsmc_nor_psram_reg_map { * Memory bank boundary addresses */ -/** Pointer to base address of FSMC memory bank 1 (split into 4 - * regions, each supporting 1 NOR Flash, SRAM, or PSRAM chip) */ +/** + * @brief Void pointer to base address of FSMC memory bank 1 (NOR/PSRAM). + * + * This bank is split into 4 regions. Each region supports interfacing + * with 1 NOR Flash, SRAM, or PSRAM chip. The base addresses of these + * regions are FSMC_NOR_PSRAM_REGIONx, for x = 1, 2, 3, 4. + */ #define FSMC_BANK1 ((void*)0x60000000) -/** Pointer to base address of FSMC memory bank 1, region 1 (for NOR/PSRAM) */ +/** + * @brief Void pointer to base address of FSMC memory bank 1, region 1 + * (NOR/PSRAM). + */ #define FSMC_NOR_PSRAM_REGION1 FSMC_BANK1 -/** Pointer to base address of FSMC memory bank 1, region 2 (for NOR/PSRAM) */ +/** + * @brief Void pointer to base address of FSMC memory bank 1, region 2 + * (NOR/PSRAM). + */ #define FSMC_NOR_PSRAM_REGION2 ((void*)0x64000000) -/** Pointer to base address of FSMC memory bank 1, region 3 (for NOR/PSRAM) */ +/** + * @brief Void pointer to base address of FSMC memory bank 1, region 3 + * (NOR/PSRAM). + */ #define FSMC_NOR_PSRAM_REGION3 ((void*)0x68000000) -/** Pointer to base address of FSMC memory bank 1, region 4 (for NOR/PSRAM) */ +/** + * @brief Void pointer to base address of FSMC memory bank 1, region 4 + * (NOR/PSRAM). + */ #define FSMC_NOR_PSRAM_REGION4 ((void*)0x6C000000) -/** Pointer to base address of FSMC memory bank 2 (for NAND Flash) */ +/** Void pointer to base address of FSMC memory bank 2 (NAND Flash). */ #define FSMC_BANK2 ((void*)0x70000000) -/** Pointer to base address of FSMC memory bank 3 (for NAND Flash) */ +/** Void pointer to base address of FSMC memory bank 3 (NAND Flash). */ #define FSMC_BANK3 ((void*)0x80000000) -/** Pointer to base address of FSMC memory bank 4 (for PC card devices */ +/** + * @brief Void pointer to base address of FSMC memory bank 4 (PC card + * devices). + */ #define FSMC_BANK4 ((void*)0x90000000) /* * SRAM/NOR Flash routines */ +/** + * @brief Configure FSMC GPIOs for use with SRAM. + */ void fsmc_sram_init_gpios(void); /** @@ -311,8 +333,6 @@ static inline void fsmc_nor_psram_set_addset(fsmc_nor_psram_reg_map *regs, regs->BTR |= addset & 0xF; } -#endif /* STM32_HIGH_DENSITY */ - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/libmaple/include/libmaple/gpio.h b/libmaple/include/libmaple/gpio.h new file mode 100644 index 0000000..0cc3746 --- /dev/null +++ b/libmaple/include/libmaple/gpio.h @@ -0,0 +1,121 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +/** + * @file libmaple/include/libmaple/gpio.h + * @brief General Purpose I/O (GPIO) interace. + */ + +#ifndef _LIBMAPLE_GPIO_H_ +#define _LIBMAPLE_GPIO_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + * Note: Series header must define: + * - enum gpio_pin_mode (TODO think harder about portability here) + */ +#include <series/gpio.h> +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> +#include <libmaple/exti.h> + +/* + * Device type + */ + +/** GPIO device type */ +typedef struct gpio_dev { + gpio_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ + /** + * @brief (Deprecated) External interrupt port. + * Instead of dev->exti_port, use gpio_exti_port(dev). + */ + exti_cfg exti_port; +} gpio_dev; + +/* + * Portable routines + */ + +void gpio_init(gpio_dev *dev); +void gpio_init_all(void); +/* TODO flags argument version? */ +void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); + +/** + * @brief Get a GPIO port's corresponding EXTI port configuration. + * @param dev GPIO port whose exti_cfg to return. + */ +static inline exti_cfg gpio_exti_port(gpio_dev *dev) { + return (exti_cfg)(EXTI_PA + (dev->clk_id - RCC_GPIOA)); +} + +/** + * Set or reset a GPIO pin. + * + * Pin must have previously been configured to output mode. + * + * @param dev GPIO device whose pin to set. + * @param pin Pin on to set or reset + * @param val If true, set the pin. If false, reset the pin. + */ +static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { + val = !val; /* "set" bits are lower than "reset" bits */ + dev->regs->BSRR = (1U << pin) << (16 * val); +} + +/** + * Determine whether or not a GPIO pin is set. + * + * Pin must have previously been configured to input mode. + * + * @param dev GPIO device whose pin to test. + * @param pin Pin on dev to test. + * @return True if the pin is set, false otherwise. + */ +static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { + return dev->regs->IDR & (1U << pin); +} + +/** + * Toggle a pin configured as output push-pull. + * @param dev GPIO device. + * @param pin Pin on dev to toggle. + */ +static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { + dev->regs->ODR = dev->regs->ODR ^ (1U << pin); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/i2c.h b/libmaple/include/libmaple/i2c.h index 4c60ad7..ff1c313 100644 --- a/libmaple/i2c.h +++ b/libmaple/include/libmaple/i2c.h @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,17 +26,51 @@ *****************************************************************************/ /** - * @file i2c.h + * @file libmaple/include/libmaple/i2c.h * @brief Inter-Integrated Circuit (I2C) peripheral support + * + * Currently master-only. Usage notes: + * + * - Enable an I2C device with i2c_master_enable(). + * - Initialize an array of struct i2c_msg to suit the bus + * transactions (reads/writes) you wish to perform. + * - Call i2c_master_xfer() to do the work. */ -#include "libmaple_types.h" -#include "rcc.h" -#include "nvic.h" -#include "gpio.h" +#ifndef _LIBMAPLE_I2C_H_ +#define _LIBMAPLE_I2C_H_ -#ifndef _I2C_H_ -#define _I2C_H_ +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Series header must provide: + * + * - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in + * MHz. (This is for internal use only). + * + * - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1. + * This is for internal use only. It's a hack to work around a + * silicon bug related to I2C IRQ pre-emption on some targets. If 1, + * the series header must also declare and implement a routine with + * this signature (it may also be provided as a macro): + * + * void _i2c_irq_priority_fixup(i2c_dev*) + * + * This will be called by i2c_enable_irq() before actually enabling + * I2C interrupts. + * + * - Reg. map base pointers, device pointer declarations. + */ + +#include <series/i2c.h> +#include <libmaple/i2c_common.h> + +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> +#include <libmaple/nvic.h> +#include <libmaple/gpio.h> /** I2C register map type */ typedef struct i2c_reg_map { @@ -50,136 +85,118 @@ typedef struct i2c_reg_map { __io uint32 TRISE; /**< TRISE (rise time) register */ } i2c_reg_map; -/** I2C device states */ -typedef enum i2c_state { - I2C_STATE_DISABLED = 0, /**< Disabled */ - I2C_STATE_IDLE = 1, /**< Idle */ - I2C_STATE_XFER_DONE = 2, /**< Done with transfer */ - I2C_STATE_BUSY = 3, /**< Busy */ - I2C_STATE_ERROR = -1 /**< Error occurred */ -} i2c_state; - /** * @brief I2C message type */ typedef struct i2c_msg { uint16 addr; /**< Address */ + #define I2C_MSG_READ 0x1 #define I2C_MSG_10BIT_ADDR 0x2 - uint16 flags; /**< Bitwise OR of I2C_MSG_READ and - I2C_MSG_10BIT_ADDR */ + /** + * Bitwise OR of: + * - I2C_MSG_READ (write is default) + * - I2C_MSG_10BIT_ADDR (7-bit is default) */ + uint16 flags; + uint16 length; /**< Message length */ uint16 xferred; /**< Messages transferred */ uint8 *data; /**< Data */ } i2c_msg; -/** - * @brief I2C device type. - */ -typedef struct i2c_dev { - i2c_reg_map *regs; /**< Register map */ - gpio_dev *gpio_port; /**< SDA, SCL pins' GPIO port */ - uint8 sda_pin; /**< SDA bit on gpio_port */ - uint8 scl_pin; /**< SCL bit on gpio_port */ - rcc_clk_id clk_id; /**< RCC clock information */ - nvic_irq_num ev_nvic_line; /**< Event IRQ number */ - nvic_irq_num er_nvic_line; /**< Error IRQ number */ - volatile i2c_state state; /**< Device state */ - uint16 msgs_left; /**< Messages left */ - i2c_msg *msg; /**< Messages */ - volatile uint32 timestamp; /**< For internal use */ - uint32 error_flags; /**< Error flags, set on I2C error condition */ -} i2c_dev; - -/* - * Devices - */ - -extern i2c_dev* const I2C1; -extern i2c_dev* const I2C2; - -/* - * Register map base pointers - */ - -/** I2C1 register map base pointer */ -#define I2C1_BASE ((struct i2c_reg_map*)0x40005400) -/** I2C2 register map base pointer */ -#define I2C2_BASE ((struct i2c_reg_map*)0x40005800) - /* * Register bit definitions */ /* Control register 1 */ -#define I2C_CR1_SWRST BIT(15) // Software reset -#define I2C_CR1_ALERT BIT(13) // SMBus alert -#define I2C_CR1_PEC BIT(12) // Packet error checking -#define I2C_CR1_POS BIT(11) // Acknowledge/PEC position -#define I2C_CR1_ACK BIT(10) // Acknowledge enable -#define I2C_CR1_START BIT(8) // Start generation -#define I2C_CR1_STOP BIT(9) // Stop generation -#define I2C_CR1_PE BIT(0) // Peripheral Enable +#define I2C_CR1_SWRST (1U << 15) // Software reset +#define I2C_CR1_ALERT (1U << 13) // SMBus alert +#define I2C_CR1_PEC (1U << 12) // Packet error checking +#define I2C_CR1_POS (1U << 11) // Acknowledge/PEC position +#define I2C_CR1_ACK (1U << 10) // Acknowledge enable +#define I2C_CR1_STOP (1U << 9) // Stop generation +#define I2C_CR1_START (1U << 8) // Start generation +#define I2C_CR1_NOSTRETCH (1U << 7) // Clock stretching disable +#define I2C_CR1_ENGC (1U << 6) // General call enable +#define I2C_CR1_ENPEC (1U << 5) // PEC enable +#define I2C_CR1_ENARP (1U << 4) // ARP enable +#define I2C_CR1_SMBTYPE (1U << 3) // SMBus type +#define I2C_CR1_SMBTYPE_DEVICE (0U << 3) // SMBus type: device +#define I2C_CR1_SMBTYPE_HOST (1U << 3) // SMBus type: host +#define I2C_CR1_SMBUS (1U << 1) // SMBus mode +#define I2C_CR1_SMBUS_I2C (0U << 1) // SMBus mode: I2C +#define I2C_CR1_SMBUS_SMBUS (1U << 1) // SMBus mode: SMBus +#define I2C_CR1_PE (1U << 0) // Peripheral Enable /* Control register 2 */ -#define I2C_CR2_LAST BIT(12) // DMA last transfer -#define I2C_CR2_DMAEN BIT(11) // DMA requests enable -#define I2C_CR2_ITBUFEN BIT(10) // Buffer interrupt enable -#define I2C_CR2_ITEVTEN BIT(9) // Event interupt enable -#define I2C_CR2_ITERREN BIT(8) // Error interupt enable -#define I2C_CR2_FREQ 0xFFF // Peripheral input frequency +#define I2C_CR2_LAST (1U << 12) // DMA last transfer +#define I2C_CR2_DMAEN (1U << 11) // DMA requests enable +#define I2C_CR2_ITBUFEN (1U << 10) // Buffer interrupt enable +#define I2C_CR2_ITEVTEN (1U << 9) // Event interupt enable +#define I2C_CR2_ITERREN (1U << 8) // Error interupt enable +#define I2C_CR2_FREQ 0x3F // Peripheral input frequency -/* Clock control register */ +/* Own address register 1 */ -#define I2C_CCR_FS BIT(15) // Fast mode selection -#define I2C_CCR_DUTY BIT(14) // 16/9 duty ratio -#define I2C_CCR_CCR 0xFFF // Clock control bits +#define I2C_OAR1_ADDMODE (1U << 15) // Addressing mode +#define I2C_OAR1_ADDMODE_7_BIT (0U << 15) // Addressing mode: 7-bit +#define I2C_OAR1_ADDMODE_10_BIT (1U << 15) // Addressing mode: 10-bit +#define I2C_OAR1_ADD 0x3FF // Interface address + +/* Own address register 2 */ + +#define I2C_OAR2_ADD2 0xFE // Interface address +#define I2C_OAR2_ENDUAL 1U // Dual addressing mode enable /* Status register 1 */ -#define I2C_SR1_SB BIT(0) // Start bit -#define I2C_SR1_ADDR BIT(1) // Address sent/matched -#define I2C_SR1_BTF BIT(2) // Byte transfer finished -#define I2C_SR1_ADD10 BIT(3) // 10-bit header sent -#define I2C_SR1_STOPF BIT(4) // Stop detection -#define I2C_SR1_RXNE BIT(6) // Data register not empty -#define I2C_SR1_TXE BIT(7) // Data register empty -#define I2C_SR1_BERR BIT(8) // Bus error -#define I2C_SR1_ARLO BIT(9) // Arbitration lost -#define I2C_SR1_AF BIT(10) // Acknowledge failure -#define I2C_SR1_OVR BIT(11) // Overrun/underrun -#define I2C_SR1_PECERR BIT(12) // PEC Error in reception -#define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error -#define I2C_SR1_SMBALERT BIT(15) // SMBus alert +#define I2C_SR1_SMBALERT (1U << 15) // SMBus alert +#define I2C_SR1_TIMEOUT (1U << 14) // Timeout or Tlow error +#define I2C_SR1_PECERR (1U << 12) // PEC Error in reception +#define I2C_SR1_OVR (1U << 11) // Overrun/underrun +#define I2C_SR1_AF (1U << 10) // Acknowledge failure +#define I2C_SR1_ARLO (1U << 9) // Arbitration lost +#define I2C_SR1_BERR (1U << 8) // Bus error +#define I2C_SR1_TXE (1U << 7) // Data register empty +#define I2C_SR1_RXNE (1U << 6) // Data register not empty +#define I2C_SR1_STOPF (1U << 4) // Stop detection +#define I2C_SR1_ADD10 (1U << 3) // 10-bit header sent +#define I2C_SR1_BTF (1U << 2) // Byte transfer finished +#define I2C_SR1_ADDR (1U << 1) // Address sent/matched +#define I2C_SR1_SB (1U << 0) // Start bit /* Status register 2 */ -#define I2C_SR2_MSL BIT(0) // Master/slave -#define I2C_SR2_BUSY BIT(1) // Bus busy -#define I2C_SR2_TRA BIT(2) // Transmitter/receiver -#define I2C_SR2_GENCALL BIT(4) // General call address -#define I2C_SR2_SMBDEFAULT BIT(5) // SMBus device default address -#define I2C_SR2_SMBHOST BIT(6) // SMBus host header -#define I2C_SR2_DUALF BIT(7) // Dual flag #define I2C_SR2_PEC 0xFF00 // Packet error checking register +#define I2C_SR2_DUALF (1U << 7) // Dual flag +#define I2C_SR2_SMBHOST (1U << 6) // SMBus host header +#define I2C_SR2_SMBDEFAULT (1U << 5) // SMBus device default address +#define I2C_SR2_GENCALL (1U << 4) // General call address +#define I2C_SR2_TRA (1U << 2) // Transmitter/receiver +#define I2C_SR2_BUSY (1U << 1) // Bus busy +#define I2C_SR2_MSL (1U << 0) // Master/slave + +/* Clock control register */ + +#define I2C_CCR_FS (1U << 15) // Fast mode selection +#define I2C_CCR_DUTY (1U << 14) // Fast mode duty cycle +#define I2C_CCR_DUTY_2_1 (0U << 14) // Fast mode duty: 2/1 +#define I2C_CCR_DUTY_16_9 (1U << 14) // Fast mode duty: 16/9 +#define I2C_CCR_CCR 0xFFF // Clock control bits /* * Convenience routines */ -#ifdef __cplusplus -extern "C" { -#endif - -void i2c_init(i2c_dev *dev); +/* Main I2C API */ /* I2C enable options */ -#define I2C_FAST_MODE BIT(0) // 400 khz -#define I2C_DUTY_16_9 BIT(1) // 16/9 duty ratio -#define I2C_REMAP BIT(2) // Use alternate pin mapping -#define I2C_BUS_RESET BIT(3) // Perform a bus reset +#define I2C_FAST_MODE 0x1 // 400 khz +#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio +/* Flag 0x4 is reserved; DO NOT USE. */ +#define I2C_BUS_RESET 0x8 // Perform a bus reset void i2c_master_enable(i2c_dev *dev, uint32 flags); #define I2C_ERROR_PROTOCOL (-1) @@ -201,67 +218,7 @@ static inline void i2c_disable(i2c_dev *dev) { dev->state = I2C_STATE_DISABLED; } -/** - * @brief Turn on an I2C peripheral - * @param dev Device to enable - */ -static inline void i2c_peripheral_enable(i2c_dev *dev) { - dev->regs->CR1 |= I2C_CR1_PE; -} - -/** - * @brief Turn off an I2C peripheral - * @param dev Device to turn off - */ -static inline void i2c_peripheral_disable(i2c_dev *dev) { - dev->regs->CR1 &= ~I2C_CR1_PE; -} - -/** - * @brief Fill transmit register - * @param dev I2C device - * @param byte Byte to write - */ -static inline void i2c_write(i2c_dev *dev, uint8 byte) { - dev->regs->DR = byte; -} - -/** - * @brief Set input clock frequency, in MHz - * @param dev I2C device - * @param freq Frequency in megahertz (2-36) - */ -static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { - uint32 cr2 = dev->regs->CR2; - cr2 &= ~I2C_CR2_FREQ; - cr2 |= freq; - dev->regs->CR2 = freq; -} - -/** - * @brief Set I2C clock control register. See RM008 - * @param dev I2C device - * @param val Value to use for clock control register (in - * Fast/Standard mode) - */ -static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) { - uint32 ccr = dev->regs->CCR; - ccr &= ~I2C_CCR_CCR; - ccr |= val; - dev->regs->CCR = ccr; -} - - -/** - * @brief Set SCL rise time - * @param dev I2C device - * @param trise Maximum rise time in fast/standard mode (see RM0008 - * for relevant formula). - */ -static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) { - dev->regs->TRISE = trise; -} - +/* Start/stop conditions */ /** * @brief Generate a start condition on the bus. @@ -297,6 +254,17 @@ static inline void i2c_stop_condition(i2c_dev *dev) { } +/* IRQ enable/disable */ + +#ifndef _I2C_HAVE_IRQ_FIXUP +/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined, + * but we need it either way. */ +#define _i2c_irq_priority_fixup(dev) ((void)0) +#endif + +#define I2C_IRQ_ERROR I2C_CR2_ITERREN +#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN +#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN /** * @brief Enable one or more I2C interrupts * @param dev I2C device @@ -305,10 +273,8 @@ static inline void i2c_stop_condition(i2c_dev *dev) { * I2C_IRQ_EVENT (event interrupt), and * I2C_IRQ_BUFFER (buffer interrupt). */ -#define I2C_IRQ_ERROR I2C_CR2_ITERREN -#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN -#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) { + _i2c_irq_priority_fixup(dev); dev->regs->CR2 |= irqs; } @@ -324,6 +290,7 @@ static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) { dev->regs->CR2 &= ~irqs; } +/* ACK/NACK */ /** * @brief Enable I2C acknowledgment @@ -341,6 +308,104 @@ static inline void i2c_disable_ack(i2c_dev *dev) { dev->regs->CR1 &= ~I2C_CR1_ACK; } +/* GPIO control */ + +/** + * @brief Configure device GPIOs. + * + * Configure GPIO bits dev->sda_pin and dev->scl_pin on GPIO device + * dev->gpio_port for use with I2C device dev. + * + * @param dev I2C Device + * @see i2c_release_gpios() + */ +extern void i2c_config_gpios(const i2c_dev *dev); + +/** + * @brief Release GPIOs controlling an I2C bus + * + * Releases the I2C bus controlled by dev as master, and disconnects + * GPIO bits dev->sda_pin and dev->scl_pin on GPIO device + * dev->gpio_port from I2C device dev. + * + * @param dev I2C device + * @see i2c_config_gpios() + */ +extern void i2c_master_release_bus(const i2c_dev *dev); + +/* Miscellaneous low-level routines */ + +void i2c_init(i2c_dev *dev); + +/** + * @brief Turn on an I2C peripheral + * @param dev Device to enable + */ +static inline void i2c_peripheral_enable(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_PE; +} + +/** + * @brief Turn off an I2C peripheral + * @param dev Device to turn off + */ +static inline void i2c_peripheral_disable(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_PE; +} + +/** + * @brief Fill transmit register + * @param dev I2C device + * @param byte Byte to write + */ +static inline void i2c_write(i2c_dev *dev, uint8 byte) { + dev->regs->DR = byte; +} + +/** + * @brief Set input clock frequency, in MHz + * @param dev I2C device + * @param freq Frequency, in MHz. This must be at least 2, and at most + * the APB frequency of dev's bus. (For example, if + * rcc_dev_clk(dev) == RCC_APB1, freq must be at most + * PCLK1, in MHz). There is an additional limit of 46 MHz. + */ +static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { +#define I2C_MAX_FREQ_MHZ 46 + ASSERT(2 <= freq && freq <= _i2c_bus_clk(dev) && freq <= I2C_MAX_FREQ_MHZ); + uint32 cr2 = dev->regs->CR2; + cr2 &= ~I2C_CR2_FREQ; + cr2 |= freq; + dev->regs->CR2 = freq; +#undef I2C_MAX_FREQ_MHZ +} + +/** + * @brief Set I2C clock control register. + * + * See the chip reference manual for the details. + * + * @param dev I2C device + * @param val Value to use for clock control register (in + * Fast/Standard mode) + */ +static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) { + uint32 ccr = dev->regs->CCR; + ccr &= ~I2C_CCR_CCR; + ccr |= val; + dev->regs->CCR = ccr; +} + +/** + * @brief Set SCL rise time + * @param dev I2C device + * @param trise Maximum rise time in fast/standard mode (see chip + * reference manual for the relevant formulas). + */ +static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) { + dev->regs->TRISE = trise; +} + #ifdef __cplusplus } #endif diff --git a/libmaple/include/libmaple/i2c_common.h b/libmaple/include/libmaple/i2c_common.h new file mode 100644 index 0000000..5d99530 --- /dev/null +++ b/libmaple/include/libmaple/i2c_common.h @@ -0,0 +1,95 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung (from <libmaple/i2c.h>). + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/i2c_common.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief This file is an implementation detail + * + * WARNING: CONTENTS UNSTABLE + * + * The existence of this file is an implementation detail. Its + * contents are not stable, so never include it directly. If you need + * something from here, #include <libmaple/i2c.h> instead. + */ + +#ifndef _LIBMAPLE_I2C_COMMON_H_ +#define _LIBMAPLE_I2C_COMMON_H_ + +#include <libmaple/libmaple_types.h> +#include <libmaple/nvic.h> +#include <libmaple/rcc.h> + +struct gpio_dev; +struct i2c_reg_map; +struct i2c_msg; + +/** I2C device states */ +typedef enum i2c_state { + I2C_STATE_DISABLED = 0, /**< Disabled */ + I2C_STATE_IDLE = 1, /**< Idle */ + I2C_STATE_XFER_DONE = 2, /**< Done with transfer */ + I2C_STATE_BUSY = 3, /**< Busy */ + I2C_STATE_ERROR = -1 /**< Error occurred */ +} i2c_state; + +/** + * @brief I2C device type. + */ +typedef struct i2c_dev { + struct i2c_reg_map *regs; /**< Register map */ + struct i2c_msg *msg; /**< Messages */ + uint32 error_flags; /**< Error flags, set on I2C error condition */ + volatile uint32 timestamp; /**< For internal use */ + + /** + * @brief Deprecated. Use .scl_port or .sda_port instead. + * If non-null, this will be used as SDA, SCL pins' GPIO port. If + * null, then .sda_port will be used for SDA, and .sda_port for + * SDA. */ + struct gpio_dev *gpio_port; + + /** + * @brief SDA GPIO device (but see .gpio_port). + */ + struct gpio_dev *sda_port; + + /** + * @brief SCL GPIO device (but see .gpio_port). + */ + struct gpio_dev *scl_port; + + uint16 msgs_left; /**< Messages left */ + uint8 sda_pin; /**< SDA bit on gpio_port */ + uint8 scl_pin; /**< SCL bit on gpio_port */ + rcc_clk_id clk_id; /**< RCC clock information */ + nvic_irq_num ev_nvic_line; /**< Event IRQ number */ + nvic_irq_num er_nvic_line; /**< Error IRQ number */ + volatile i2c_state state; /**< Device state */ +} i2c_dev; + +#endif diff --git a/libmaple/iwdg.h b/libmaple/include/libmaple/iwdg.h index 59e8e18..3a16c55 100644 --- a/libmaple/iwdg.h +++ b/libmaple/include/libmaple/iwdg.h @@ -25,7 +25,7 @@ *****************************************************************************/ /** - * @file iwdg.h + * @file libmaple/include/libmaple/iwdg.h * @author Michael Hope, Marti Bolivar <mbolivar@leaflabs.com> * @brief Independent watchdog support. * @@ -38,16 +38,15 @@ * Once started, the independent watchdog cannot be turned off. */ -#ifndef _IWDG_H_ -#define _IWDG_H_ - -#include "libmaple_types.h" -#include "util.h" +#ifndef _LIBMAPLE_IWDG_H_ +#define _LIBMAPLE_IWDG_H_ #ifdef __cplusplus extern "C"{ #endif +#include <libmaple/libmaple_types.h> + /* * Register map */ @@ -88,8 +87,8 @@ typedef struct iwdg_reg_map { #define IWDG_SR_RVU_BIT 1 #define IWDG_SR_PVU_BIT 0 -#define IWDG_SR_RVU BIT(IWDG_SR_RVU_BIT) -#define IWDG_SR_PVU BIT(IWDG_SR_PVU_BIT) +#define IWDG_SR_RVU (1U << IWDG_SR_RVU_BIT) +#define IWDG_SR_PVU (1U << IWDG_SR_PVU_BIT) /** * @brief Independent watchdog prescalers. diff --git a/libmaple/libmaple.h b/libmaple/include/libmaple/libmaple.h index c509f5d..f1a595e 100644 --- a/libmaple/libmaple.h +++ b/libmaple/include/libmaple/libmaple.h @@ -25,17 +25,21 @@ *****************************************************************************/ /** - * @file libmaple.h + * @file libmaple/include/libmaple/libmaple.h * @brief General include file for libmaple */ -#ifndef _LIBMAPLE_H_ -#define _LIBMAPLE_H_ +#ifndef _LIBMAPLE_LIBMAPLE_H_ +#define _LIBMAPLE_LIBMAPLE_H_ -#include "libmaple_types.h" -#include "stm32.h" -#include "util.h" -#include "delay.h" +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/stm32.h> +#include <libmaple/util.h> +#include <libmaple/delay.h> /* * Where to put usercode, based on space reserved for bootloader. @@ -46,5 +50,8 @@ #define USER_ADDR_RAM 0x20000C00 #define STACK_TOP 0x20000800 +#ifdef __cplusplus +} #endif +#endif diff --git a/libmaple/libmaple_types.h b/libmaple/include/libmaple/libmaple_types.h index 08adaff..9e1fbb3 100644 --- a/libmaple/libmaple_types.h +++ b/libmaple/include/libmaple/libmaple_types.h @@ -25,13 +25,17 @@ *****************************************************************************/ /** - * @file libmaple_types.h + * @file libmaple/include/libmaple/libmaple_types.h * - * @brief libmaple types + * @brief libmaple's types, and operations on types. */ -#ifndef _LIBMAPLE_TYPES_H_ -#define _LIBMAPLE_TYPES_H_ +#ifndef _LIBMAPLE_LIBMAPLE_TYPES_H_ +#define _LIBMAPLE_LIBMAPLE_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif typedef unsigned char uint8; typedef unsigned short uint16; @@ -48,10 +52,21 @@ typedef void (*voidFuncPtr)(void); #define __io volatile #define __attr_flash __attribute__((section (".USER_FLASH"))) #define __packed __attribute__((__packed__)) +#define __deprecated __attribute__((__deprecated__)) +#define __weak __attribute__((weak)) +#define __always_inline inline __attribute__((always_inline)) +#define __unused __attribute__((unused)) #ifndef NULL #define NULL 0 #endif +#ifndef offsetof +#define offsetof(type, member) __builtin_offsetof(type, member) #endif +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/nvic.h b/libmaple/include/libmaple/nvic.h new file mode 100644 index 0000000..ac102d9 --- /dev/null +++ b/libmaple/include/libmaple/nvic.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/nvic.h + * @brief Nested vectored interrupt controller support. + * + * Basic usage: + * + * @code + * // Initialise the interrupt controller and point to the vector + * // table at the start of flash. + * nvic_init(0x08000000, 0); + * // Bind in a timer interrupt handler + * timer_attach_interrupt(TIMER_CC1_INTERRUPT, handler); + * // Optionally set the priority + * nvic_irq_set_priority(NVIC_TIMER1_CC, 5); + * // All done, enable all interrupts + * nvic_globalirq_enable(); + * @endcode + */ + +#ifndef _LIBMAPLE_NVIC_H_ +#define _LIBMAPLE_NVIC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/util.h> + +/** NVIC register map type. */ +typedef struct nvic_reg_map { + __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */ + /** Reserved */ + uint32 RESERVED0[24]; + + __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ + /** Reserved */ + uint32 RESERVED1[24]; + + __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ + /** Reserved */ + uint32 RESERVED2[24]; + + __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ + /** Reserved */ + uint32 RESERVED3[24]; + + __io uint32 IABR[8]; /**< Interrupt Active bit Registers */ + /** Reserved */ + uint32 RESERVED4[56]; + + __io uint8 IP[240]; /**< Interrupt Priority Registers */ + /** Reserved */ + uint32 RESERVED5[644]; + + __io uint32 STIR; /**< Software Trigger Interrupt Registers */ +} nvic_reg_map; + +/** NVIC register map base pointer. */ +#define NVIC_BASE ((struct nvic_reg_map*)0xE000E100) + +/* + * Note: The series header must define enum nvic_irq_num, which gives + * descriptive names to the interrupts and exceptions from NMI (-14) + * to the largest interrupt available in the series, where the value + * for nonnegative enumerators corresponds to its position in the + * vector table. + * + * It also must define a static inline nvic_irq_disable_all(), which + * writes 0xFFFFFFFF to all ICE registers available in the series. (We + * place the include here to give the series header access to + * NVIC_BASE, in order to let it do so). + */ +#include <series/nvic.h> + +void nvic_init(uint32 address, uint32 offset); +void nvic_set_vector_table(uint32 address, uint32 offset); +void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority); +void nvic_sys_reset(); + +/** + * Enables interrupts and configurable fault handlers (clear PRIMASK). + */ +static inline void nvic_globalirq_enable() { + asm volatile("cpsie i"); +} + +/** + * Disable interrupts and configurable fault handlers (set PRIMASK). + */ +static inline void nvic_globalirq_disable() { + asm volatile("cpsid i"); +} + +/** + * @brief Enable interrupt irq_num + * @param irq_num Interrupt to enable + */ +static inline void nvic_irq_enable(nvic_irq_num irq_num) { + if (irq_num < 0) { + return; + } + NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32); +} + +/** + * @brief Disable interrupt irq_num + * @param irq_num Interrupt to disable + */ +static inline void nvic_irq_disable(nvic_irq_num irq_num) { + if (irq_num < 0) { + return; + } + NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32); +} + +/** + * @brief Quickly disable all interrupts. + * + * Calling this function is significantly faster than calling + * nvic_irq_disable() in a loop. + */ +static inline void nvic_irq_disable_all(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/pwr.h b/libmaple/include/libmaple/pwr.h index 88b49c0..e4b5b0d 100644 --- a/libmaple/pwr.h +++ b/libmaple/include/libmaple/pwr.h @@ -25,16 +25,20 @@ *****************************************************************************/ /** - * @file pwr.h - * @brief Power control (PWR) defines. + * @file libmaple/include/libmaple/pwr.h + * @brief Power control (PWR). */ -#include "libmaple.h" +#ifndef _LIBMAPLE_PWR_H_ +#define _LIBMAPLE_PWR_H_ #ifdef __cplusplus extern "C" { #endif +#include <libmaple/libmaple.h> +#include <series/pwr.h> + /** Power interface register map. */ typedef struct pwr_reg_map { __io uint32 CR; /**< Control register */ @@ -51,28 +55,52 @@ typedef struct pwr_reg_map { /* Control register */ /** Disable backup domain write protection bit */ -#define PWR_CR_DBP 8 +#define PWR_CR_DBP_BIT 8 /** Power voltage detector enable bit */ -#define PWR_CR_PVDE 4 +#define PWR_CR_PVDE_BIT 4 /** Clear standby flag bit */ -#define PWR_CR_CSBF 3 +#define PWR_CR_CSBF_BIT 3 /** Clear wakeup flag bit */ -#define PWR_CR_CWUF 2 +#define PWR_CR_CWUF_BIT 2 /** Power down deepsleep bit */ -#define PWR_CR_PDDS 1 +#define PWR_CR_PDDS_BIT 1 /** Low-power deepsleep bit */ -#define PWR_CR_LPDS 0 +#define PWR_CR_LPDS_BIT 0 + +/** Disable backup domain write protection */ +#define PWR_CR_DBP (1U << PWR_CR_DBP_BIT) +/** Power voltage detector (PVD) level selection */ +#define PWR_CR_PLS (0x7 << 5) +/** Power voltage detector enable */ +#define PWR_CR_PVDE (1U << PWR_CR_PVDE_BIT) +/** Clear standby flag */ +#define PWR_CR_CSBF (1U << PWR_CR_CSBF_BIT) +/** Clear wakeup flag */ +#define PWR_CR_CWUF (1U << PWR_CR_CWUF_BIT) +/** Power down deepsleep */ +#define PWR_CR_PDDS (1U << PWR_CR_PDDS_BIT) +/** Low-power deepsleep */ +#define PWR_CR_LPDS (1U << PWR_CR_LPDS_BIT) /* Control and status register */ /** Enable wakeup pin bit */ -#define PWR_CSR_EWUP 8 +#define PWR_CSR_EWUP_BIT 8 /** PVD output bit */ -#define PWR_CSR_PVDO 2 +#define PWR_CSR_PVDO_BIT 2 /** Standby flag bit */ -#define PWR_CSR_SBF 1 +#define PWR_CSR_SBF_BIT 1 /** Wakeup flag bit */ -#define PWR_CSR_WUF 0 +#define PWR_CSR_WUF_BIT 0 + +/** Enable wakeup pin */ +#define PWR_CSR_EWUP (1U << PWR_CSR_EWUP_BIT) +/** PVD output */ +#define PWR_CSR_PVDO (1U << PWR_CSR_PVDO_BIT) +/** Standby flag */ +#define PWR_CSR_SBF (1U << PWR_CSR_SBF_BIT) +/** Wakeup flag */ +#define PWR_CSR_WUF (1U << PWR_CSR_WUF_BIT) /* * Convenience functions @@ -83,3 +111,5 @@ void pwr_init(void); #ifdef __cplusplus } #endif + +#endif diff --git a/libmaple/include/libmaple/rcc.h b/libmaple/include/libmaple/rcc.h new file mode 100644 index 0000000..ea16803 --- /dev/null +++ b/libmaple/include/libmaple/rcc.h @@ -0,0 +1,175 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/rcc.h + * @brief Reset and Clock Control (RCC) interface. + */ + +#ifndef _LIBMAPLE_RCC_H_ +#define _LIBMAPLE_RCC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/* Put the SYSCLK sources before the series header is included, as it + * might need them. */ +/** + * @brief SYSCLK sources + * @see rcc_switch_sysclk() + */ +typedef enum rcc_sysclk_src { + RCC_CLKSRC_HSI = 0x0, + RCC_CLKSRC_HSE = 0x1, + RCC_CLKSRC_PLL = 0x2, +} rcc_sysclk_src; + +#include <series/rcc.h> + +/* Note: Beyond the usual (registers, etc.), it's up to the series + * header to define the following types: + * + * - enum rcc_clk: Available system and secondary clock sources, + * e.g. RCC_CLK_HSE, RCC_CLK_PLL, RCC_CLK_LSE. + * + * Note that the inclusion of secondary clock sources (like LSI and + * LSE) makes enum rcc_clk different from the SYSCLK sources, which + * are defined in this header as enum rcc_sysclk_src. + * + * IMPORTANT NOTE TO IMPLEMENTORS: If you are adding support for a + * new STM32 series, see the comment near rcc_clk_reg() in + * libmaple/rcc.c for information on how to choose these values so + * that rcc_turn_on_clk() etc. will work on your series. + * + * - enum rcc_clk_id: For each available peripheral. These are widely used + * as unique IDs (TODO extricate from RCC?). Peripherals which are + * common across STM32 series should use the same token for their + * rcc_clk_id in each series header. + * + * - enum rcc_clk_domain: For each clock domain. This is returned by + * rcc_dev_clk(). For instance, each AHB and APB is a clock domain. + * + * - enum rcc_prescaler: And a suitable set of dividers for + * rcc_set_prescaler(). + * + * - enum rcc_pllsrc: For each PLL source. Same source, same token. + * + * - A target-dependent type to be pointed to by the data field in a + * struct rcc_pll_cfg. + */ + +#ifdef __DOXYGEN__ +/** RCC register map base pointer */ +#define RCC_BASE +#endif + +/* Clock prescaler management. */ + +/** + * @brief Set the divider on a peripheral prescaler + * @param prescaler prescaler to set + * @param divider prescaler divider + */ +extern void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); + +/* SYSCLK. */ + +void rcc_switch_sysclk(rcc_sysclk_src sysclk_src); + +/* PLL configuration */ + +/** + * @brief Specifies a configuration for the main PLL. + */ +typedef struct rcc_pll_cfg { + rcc_pllsrc pllsrc; /**< PLL source */ + + /** Series-specific configuration data. */ + void *data; +} rcc_pll_cfg; + +/** + * @brief Configure the main PLL. + * + * You may only call this function while the PLL is disabled. + * + * @param pll_cfg Desired PLL configuration. The contents of this + * struct depend entirely on the target. + */ +extern void rcc_configure_pll(rcc_pll_cfg *pll_cfg); + +/* System and secondary clock sources. */ + +void rcc_turn_on_clk(rcc_clk clock); +void rcc_turn_off_clk(rcc_clk clock); +int rcc_is_clk_on(rcc_clk clock); +int rcc_is_clk_ready(rcc_clk clock); + +/* Peripheral clock lines and clock domains. */ + +/** + * @brief Turn on the clock line on a peripheral + * @param id Clock ID of the peripheral to turn on. + */ +extern void rcc_clk_enable(rcc_clk_id id); + +/** + * @brief Reset a peripheral. + * + * Caution: not all rcc_clk_id values refer to a peripheral which can + * be reset. (Only rcc_clk_ids for peripherals with bits in an RCC + * reset register can be used here.) + * + * @param id Clock ID of the peripheral to reset. + */ +extern void rcc_reset_dev(rcc_clk_id id); + +rcc_clk_domain rcc_dev_clk(rcc_clk_id id); + +/* Clock security system */ + +/** + * @brief Enable the clock security system (CSS). + */ +static inline void rcc_enable_css() { + RCC_BASE->CR |= RCC_CR_CSSON; +} + +/** + * @brief Disable the clock security system (CSS). + */ +static inline void rcc_disable_css() { + RCC_BASE->CR &= ~RCC_CR_CSSON; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/ring_buffer.h b/libmaple/include/libmaple/ring_buffer.h index c443bc3..e02e6e7 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/include/libmaple/ring_buffer.h @@ -25,22 +25,22 @@ *****************************************************************************/ /** - * @file ring_buffer.h + * @file libmaple/include/libmaple/ring_buffer.h * @brief Simple circular buffer * * This implementation is not thread-safe. In particular, none of * these functions is guaranteed re-entrant. */ -#ifndef _RING_BUFFER_H_ -#define _RING_BUFFER_H_ - -#include "libmaple_types.h" +#ifndef _LIBMAPLE_RING_BUFFER_H_ +#define _LIBMAPLE_RING_BUFFER_H_ #ifdef __cplusplus extern "C"{ #endif +#include <libmaple/libmaple_types.h> + /** * Ring buffer type. * @@ -186,4 +186,3 @@ static inline void rb_reset(ring_buffer *rb) { #endif #endif - diff --git a/libmaple/scb.h b/libmaple/include/libmaple/scb.h index feacaa5..1c7c5d7 100644 --- a/libmaple/scb.h +++ b/libmaple/include/libmaple/scb.h @@ -25,14 +25,18 @@ *****************************************************************************/ /** - * @file scb.h + * @file libmaple/include/libmaple/scb.h * @brief System control block header */ -#include "libmaple_types.h" +#ifndef _LIBMAPLE_SCB_H_ +#define _LIBMAPLE_SCB_H_ -#ifndef _SCB_H_ -#define _SCB_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> /* * Register map and base pointer @@ -198,4 +202,8 @@ typedef struct scb_reg_map { #define SCB_DFSR_BKPT BIT(1) #define SCB_DFSR_HALTED BIT(0) +#ifdef __cplusplus +} +#endif + #endif diff --git a/libmaple/spi.h b/libmaple/include/libmaple/spi.h index f4fa4b7..fab643f 100644 --- a/libmaple/spi.h +++ b/libmaple/include/libmaple/spi.h @@ -1,6 +1,7 @@ /****************************************************************************** * The MIT License * + * Copyright (c) 2011, 2012 LeafLabs, LLC. * Copyright (c) 2010 Perry Hung. * * Permission is hereby granted, free of charge, to any person @@ -25,7 +26,7 @@ *****************************************************************************/ /** - * @file spi.h + * @file libmaple/include/libmaple/spi.h * @author Marti Bolivar <mbolivar@leaflabs.com> * @brief Serial Peripheral Interface (SPI) and Integrated * Interchip Sound (I2S) peripheral support. @@ -33,19 +34,18 @@ * I2S support is currently limited to register maps and bit definitions. */ -#ifndef _SPI_H_ -#define _SPI_H_ - -#include "libmaple_types.h" -#include "rcc.h" -#include "nvic.h" -#include "gpio.h" -#include "util.h" +#ifndef _LIBMAPLE_SPI_H_ +#define _LIBMAPLE_SPI_H_ #ifdef __cplusplus extern "C" { #endif +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> +#include <libmaple/nvic.h> +#include <series/spi.h> + /* * Register maps */ @@ -63,13 +63,6 @@ typedef struct spi_reg_map { __io uint32 I2SPR; /**< I2S prescaler register */ } spi_reg_map; -/** SPI1 register map base pointer */ -#define SPI1_BASE ((struct spi_reg_map*)0x40013000) -/** SPI2 register map base pointer */ -#define SPI2_BASE ((struct spi_reg_map*)0x40003800) -/** SPI3 register map base pointer */ -#define SPI3_BASE ((struct spi_reg_map*)0x40003C00) - /* * Register bit definitions */ @@ -90,20 +83,20 @@ typedef struct spi_reg_map { #define SPI_CR1_CPOL_BIT 1 #define SPI_CR1_CPHA_BIT 0 -#define SPI_CR1_BIDIMODE BIT(SPI_CR1_BIDIMODE_BIT) +#define SPI_CR1_BIDIMODE (1U << SPI_CR1_BIDIMODE_BIT) #define SPI_CR1_BIDIMODE_2_LINE (0x0 << SPI_CR1_BIDIMODE_BIT) #define SPI_CR1_BIDIMODE_1_LINE (0x1 << SPI_CR1_BIDIMODE_BIT) -#define SPI_CR1_BIDIOE BIT(SPI_CR1_BIDIOE_BIT) -#define SPI_CR1_CRCEN BIT(SPI_CR1_CRCEN_BIT) -#define SPI_CR1_CRCNEXT BIT(SPI_CR1_CRCNEXT_BIT) -#define SPI_CR1_DFF BIT(SPI_CR1_DFF_BIT) +#define SPI_CR1_BIDIOE (1U << SPI_CR1_BIDIOE_BIT) +#define SPI_CR1_CRCEN (1U << SPI_CR1_CRCEN_BIT) +#define SPI_CR1_CRCNEXT (1U << SPI_CR1_CRCNEXT_BIT) +#define SPI_CR1_DFF (1U << SPI_CR1_DFF_BIT) #define SPI_CR1_DFF_8_BIT (0x0 << SPI_CR1_DFF_BIT) #define SPI_CR1_DFF_16_BIT (0x1 << SPI_CR1_DFF_BIT) -#define SPI_CR1_RXONLY BIT(SPI_CR1_RXONLY_BIT) -#define SPI_CR1_SSM BIT(SPI_CR1_SSM_BIT) -#define SPI_CR1_SSI BIT(SPI_CR1_SSI_BIT) -#define SPI_CR1_LSBFIRST BIT(SPI_CR1_LSBFIRST_BIT) -#define SPI_CR1_SPE BIT(SPI_CR1_SPE_BIT) +#define SPI_CR1_RXONLY (1U << SPI_CR1_RXONLY_BIT) +#define SPI_CR1_SSM (1U << SPI_CR1_SSM_BIT) +#define SPI_CR1_SSI (1U << SPI_CR1_SSI_BIT) +#define SPI_CR1_LSBFIRST (1U << SPI_CR1_LSBFIRST_BIT) +#define SPI_CR1_SPE (1U << SPI_CR1_SPE_BIT) #define SPI_CR1_BR (0x7 << 3) #define SPI_CR1_BR_PCLK_DIV_2 (0x0 << 3) #define SPI_CR1_BR_PCLK_DIV_4 (0x1 << 3) @@ -113,17 +106,14 @@ typedef struct spi_reg_map { #define SPI_CR1_BR_PCLK_DIV_64 (0x5 << 3) #define SPI_CR1_BR_PCLK_DIV_128 (0x6 << 3) #define SPI_CR1_BR_PCLK_DIV_256 (0x7 << 3) -#define SPI_CR1_MSTR BIT(SPI_CR1_MSTR_BIT) -#define SPI_CR1_CPOL BIT(SPI_CR1_CPOL_BIT) +#define SPI_CR1_MSTR (1U << SPI_CR1_MSTR_BIT) +#define SPI_CR1_CPOL (1U << SPI_CR1_CPOL_BIT) #define SPI_CR1_CPOL_LOW (0x0 << SPI_CR1_CPOL_BIT) #define SPI_CR1_CPOL_HIGH (0x1 << SPI_CR1_CPOL_BIT) -#define SPI_CR1_CPHA BIT(SPI_CR1_CPHA_BIT) +#define SPI_CR1_CPHA (1U << SPI_CR1_CPHA_BIT) /* Control register 2 */ -/* RM0008-ism: SPI CR2 has "TXDMAEN" and "RXDMAEN" bits, while the - * USARTs have CR3 "DMAR" and "DMAT" bits. */ - #define SPI_CR2_TXEIE_BIT 7 #define SPI_CR2_RXNEIE_BIT 6 #define SPI_CR2_ERRIE_BIT 5 @@ -131,12 +121,12 @@ typedef struct spi_reg_map { #define SPI_CR2_TXDMAEN_BIT 1 #define SPI_CR2_RXDMAEN_BIT 0 -#define SPI_CR2_TXEIE BIT(SPI_CR2_TXEIE_BIT) -#define SPI_CR2_RXNEIE BIT(SPI_CR2_RXNEIE_BIT) -#define SPI_CR2_ERRIE BIT(SPI_CR2_ERRIE_BIT) -#define SPI_CR2_SSOE BIT(SPI_CR2_SSOE_BIT) -#define SPI_CR2_TXDMAEN BIT(SPI_CR2_TXDMAEN_BIT) -#define SPI_CR2_RXDMAEN BIT(SPI_CR2_RXDMAEN_BIT) +#define SPI_CR2_TXEIE (1U << SPI_CR2_TXEIE_BIT) +#define SPI_CR2_RXNEIE (1U << SPI_CR2_RXNEIE_BIT) +#define SPI_CR2_ERRIE (1U << SPI_CR2_ERRIE_BIT) +#define SPI_CR2_SSOE (1U << SPI_CR2_SSOE_BIT) +#define SPI_CR2_TXDMAEN (1U << SPI_CR2_TXDMAEN_BIT) +#define SPI_CR2_RXDMAEN (1U << SPI_CR2_RXDMAEN_BIT) /* Status register */ @@ -149,37 +139,35 @@ typedef struct spi_reg_map { #define SPI_SR_TXE_BIT 1 #define SPI_SR_RXNE_BIT 0 -#define SPI_SR_BSY BIT(SPI_SR_BSY_BIT) -#define SPI_SR_OVR BIT(SPI_SR_OVR_BIT) -#define SPI_SR_MODF BIT(SPI_SR_MODF_BIT) -#define SPI_SR_CRCERR BIT(SPI_SR_CRCERR_BIT) -#define SPI_SR_UDR BIT(SPI_SR_UDR_BIT) -#define SPI_SR_CHSIDE BIT(SPI_SR_CHSIDE_BIT) +#define SPI_SR_BSY (1U << SPI_SR_BSY_BIT) +#define SPI_SR_OVR (1U << SPI_SR_OVR_BIT) +#define SPI_SR_MODF (1U << SPI_SR_MODF_BIT) +#define SPI_SR_CRCERR (1U << SPI_SR_CRCERR_BIT) +#define SPI_SR_UDR (1U << SPI_SR_UDR_BIT) +#define SPI_SR_CHSIDE (1U << SPI_SR_CHSIDE_BIT) #define SPI_SR_CHSIDE_LEFT (0x0 << SPI_SR_CHSIDE_BIT) #define SPI_SR_CHSIDE_RIGHT (0x1 << SPI_SR_CHSIDE_BIT) -#define SPI_SR_TXE BIT(SPI_SR_TXE_BIT) -#define SPI_SR_RXNE BIT(SPI_SR_RXNE_BIT) +#define SPI_SR_TXE (1U << SPI_SR_TXE_BIT) +#define SPI_SR_RXNE (1U << SPI_SR_RXNE_BIT) /* I2S configuration register */ -/* RM0008-ism: CR1 has "CPOL", I2SCFGR has "CKPOL". */ - #define SPI_I2SCFGR_I2SMOD_BIT 11 #define SPI_I2SCFGR_I2SE_BIT 10 #define SPI_I2SCFGR_PCMSYNC_BIT 7 #define SPI_I2SCFGR_CKPOL_BIT 3 #define SPI_I2SCFGR_CHLEN_BIT 0 -#define SPI_I2SCFGR_I2SMOD BIT(SPI_I2SCFGR_I2SMOD_BIT) +#define SPI_I2SCFGR_I2SMOD (1U << SPI_I2SCFGR_I2SMOD_BIT) #define SPI_I2SCFGR_I2SMOD_SPI (0x0 << SPI_I2SCFGR_I2SMOD_BIT) #define SPI_I2SCFGR_I2SMOD_I2S (0x1 << SPI_I2SCFGR_I2SMOD_BIT) -#define SPI_I2SCFGR_I2SE BIT(SPI_I2SCFGR_I2SE_BIT) +#define SPI_I2SCFGR_I2SE (1U << SPI_I2SCFGR_I2SE_BIT) #define SPI_I2SCFGR_I2SCFG (0x3 << 8) #define SPI_I2SCFGR_I2SCFG_SLAVE_TX (0x0 << 8) #define SPI_I2SCFGR_I2SCFG_SLAVE_RX (0x1 << 8) #define SPI_I2SCFGR_I2SCFG_MASTER_TX (0x2 << 8) #define SPI_I2SCFGR_I2SCFG_MASTER_RX (0x3 << 8) -#define SPI_I2SCFGR_PCMSYNC BIT(SPI_I2SCFGR_PCMSYNC_BIT) +#define SPI_I2SCFGR_PCMSYNC (1U << SPI_I2SCFGR_PCMSYNC_BIT) #define SPI_I2SCFGR_PCMSYNC_SHORT (0x0 << SPI_I2SCFGR_PCMSYNC_BIT) #define SPI_I2SCFGR_PCMSYNC_LONG (0x1 << SPI_I2SCFGR_PCMSYNC_BIT) #define SPI_I2SCFGR_I2SSTD (0x3 << 4) @@ -187,17 +175,26 @@ typedef struct spi_reg_map { #define SPI_I2SCFGR_I2SSTD_MSB (0x1 << 4) #define SPI_I2SCFGR_I2SSTD_LSB (0x2 << 4) #define SPI_I2SCFGR_I2SSTD_PCM (0x3 << 4) -#define SPI_I2SCFGR_CKPOL BIT(SPI_I2SCFGR_CKPOL_BIT) +#define SPI_I2SCFGR_CKPOL (1U << SPI_I2SCFGR_CKPOL_BIT) #define SPI_I2SCFGR_CKPOL_LOW (0x0 << SPI_I2SCFGR_CKPOL_BIT) #define SPI_I2SCFGR_CKPOL_HIGH (0x1 << SPI_I2SCFGR_CKPOL_BIT) #define SPI_I2SCFGR_DATLEN (0x3 << 1) #define SPI_I2SCFGR_DATLEN_16_BIT (0x0 << 1) #define SPI_I2SCFGR_DATLEN_24_BIT (0x1 << 1) #define SPI_I2SCFGR_DATLEN_32_BIT (0x2 << 1) -#define SPI_I2SCFGR_CHLEN BIT(SPI_I2SCFGR_CHLEN_BIT) +#define SPI_I2SCFGR_CHLEN (1U << SPI_I2SCFGR_CHLEN_BIT) #define SPI_I2SCFGR_CHLEN_16_BIT (0x0 << SPI_I2SCFGR_CHLEN_BIT) #define SPI_I2SCFGR_CHLEN_32_BIT (0x1 << SPI_I2SCFGR_CHLEN_BIT) +/* I2S prescaler register */ + +#define SPI_I2SPR_MCKOE_BIT 9 +#define SPI_I2SPR_ODD_BIT 8 + +#define SPI_I2SPR_MCKOE (1U << SPI_I2SPR_MCKOE_BIT) +#define SPI_I2SPR_ODD (1U << SPI_I2SPR_ODD_BIT) +#define SPI_I2SPR_I2SDIV 0xFF + /* * Devices */ @@ -209,42 +206,54 @@ typedef struct spi_dev { nvic_irq_num irq_num; /**< NVIC interrupt number */ } spi_dev; -extern spi_dev *SPI1; -extern spi_dev *SPI2; -#ifdef STM32_HIGH_DENSITY -extern spi_dev *SPI3; -#endif - /* * SPI Convenience functions */ void spi_init(spi_dev *dev); -void spi_gpio_cfg(uint8 as_master, - gpio_dev *nss_dev, - uint8 nss_bit, - gpio_dev *comm_dev, - uint8 sck_bit, - uint8 miso_bit, - uint8 mosi_bit); +struct gpio_dev; +/** + * @brief Configure GPIO bit modes for use as a SPI port's pins. + * @param as_master If true, configure bits for use as a bus master. + * Otherwise, configure bits for use as slave. + * @param nss_dev NSS pin's GPIO device + * @param comm_dev SCK, MISO, MOSI pins' GPIO device + * @param nss_bit NSS pin's GPIO bit on nss_dev + * @param sck_bit SCK pin's GPIO bit on comm_dev + * @param miso_bit MISO pin's GPIO bit on comm_dev + * @param mosi_bit MOSI pin's GPIO bit on comm_dev + */ +extern void spi_config_gpios(spi_dev *dev, + uint8 as_master, + struct gpio_dev *nss_dev, + uint8 nss_bit, + struct gpio_dev *comm_dev, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit); /** * @brief SPI mode configuration. * - * Determines a combination of clock polarity (CPOL), which determines - * idle state of the clock line, and clock phase (CPHA), which - * determines which clock edge triggers data capture. + * A SPI mode determines a combination of the idle state of the clock + * line (the clock polarity, or "CPOL"), and which clock edge triggers + * data capture (the clock phase, or "CPHA"). */ typedef enum spi_mode { - SPI_MODE_0, /**< Clock line idles low (0), data capture on first - clock transition. */ - SPI_MODE_1, /**< Clock line idles low (0), data capture on second - clock transition */ - SPI_MODE_2, /**< Clock line idles high (1), data capture on first - clock transition. */ - SPI_MODE_3 /**< Clock line idles high (1), data capture on - second clock transition. */ + /** Clock idles low, data captured on rising edge (first transition) */ + SPI_MODE_LOW_RISING = 0, + /** Clock idles low, data captured on falling edge (second transition) */ + SPI_MODE_LOW_FALLING = 1, + /** Clock idles high, data captured on falling edge (first transition) */ + SPI_MODE_HIGH_FALLING = 2, + /** Clock idles high, data captured on rising edge (second transition) */ + SPI_MODE_HIGH_RISING = 3, + + SPI_MODE_0 = SPI_MODE_LOW_RISING, /**< Same as SPI_MODE_LOW_RISING */ + SPI_MODE_1 = SPI_MODE_LOW_FALLING, /**< Same as SPI_MODE_LOW_FALLING */ + SPI_MODE_2 = SPI_MODE_HIGH_FALLING, /**< Same as SPI_MODE_HIGH_FALLING */ + SPI_MODE_3 = SPI_MODE_HIGH_RISING, /**< Same as SPI_MODE_HIGH_RISING */ } spi_mode; /** @@ -299,7 +308,11 @@ void spi_slave_enable(spi_dev *dev, uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len); -void spi_foreach(void (*fn)(spi_dev (*dev))); +/** + * @brief Call a function on each SPI port + * @param fn Function to call. + */ +extern void spi_foreach(void (*fn)(spi_dev*)); void spi_peripheral_enable(spi_dev *dev); void spi_peripheral_disable(spi_dev *dev); diff --git a/libmaple/include/libmaple/stm32.h b/libmaple/include/libmaple/stm32.h new file mode 100644 index 0000000..3845cab --- /dev/null +++ b/libmaple/include/libmaple/stm32.h @@ -0,0 +1,237 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010, 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/stm32.h + * @brief STM32 chip header + * + * This header supplies various chip-specific values for the current + * build target. It's useful both to abstract away hardware details + * (e.g. through use of STM32_NR_INTERRUPTS) and to decide what to do + * when you want something nonportable (e.g. by checking + * STM32_MCU_SERIES). + */ + +#ifndef _LIBMAPLE_STM32_H_ +#define _LIBMAPLE_STM32_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * STM32 series identifiers. + * + * Don't make these into an enum; the preprocessor needs them. + */ + +/** STM32F1 series. */ +#define STM32_SERIES_F1 0 +/** STM32F2 series. */ +#define STM32_SERIES_F2 1 +/** STM32L1 series. */ +#define STM32_SERIES_L1 2 +/** STM32F4 series. */ +#define STM32_SERIES_F4 3 + +/* The series header is responsible for defining: + * + * - Everything in the following __DOXYGEN__ conditional block. + * + * - STM32_HAVE_FSMC: 1 if the MCU has the FSMC peripheral, and 0 + * otherwise. + * + * - STM32_HAVE_USB: 1 if the MCU has a USB peripheral, and 0 + * otherwise. + */ +#include <series/stm32.h> + +/* Ensure the series header isn't broken. */ +#if (!defined(STM32_PCLK1) || \ + !defined(STM32_PCLK2) || \ + !defined(STM32_MCU_SERIES) || \ + !defined(STM32_NR_INTERRUPTS) || \ + !defined(STM32_NR_GPIO_PORTS) || \ + !defined(STM32_TIMER_MASK) || \ + !defined(STM32_DELAY_US_MULT) || \ + !defined(STM32_SRAM_END) || \ + !defined(STM32_HAVE_DAC) || \ + !defined(STM32_HAVE_FSMC) || \ + !defined(STM32_HAVE_USB)) +#error "Bad STM32F1 configuration. Check <series/stm32.h> header for your MCU." +#endif + +/* + * Derived macros + */ + +/* FIXME [0.0.13] add this to ReST API page */ +/** + * @brief Statically determine whether a timer is present. + * + * Given a constant timer number n (starting from 1), this macro has a + * nonzero value exactly when TIMERn is available. + */ +#define STM32_HAVE_TIMER(n) (STM32_TIMER_MASK & (1 << (n))) + +/* + * Doxygen for functionality provided by series header. + */ + +#ifdef __DOXYGEN__ + +/* + * Clock configuration. + * + * These defines depend upon how the MCU is configured. Because of + * the potential for a mismatch between them and the actual clock + * configuration, keep their number to a minimum. + */ + +/** + * @brief APB1 clock speed, in Hz. + */ +#define STM32_PCLK1 + +/** + * @brief APB2 clock speed, in Hz. + */ +#define STM32_PCLK2 + +/** @brief Deprecated. Use STM32_PCLK1 instead. */ +#define PCLK1 +/** @brief Deprecated. Use STM32_PCLK2 instead. */ +#define PCLK2 + +/* + * Series- and MCU-specific values. + */ + +/** + * @brief STM32 series value for the MCU being targeted. + * + * At time of writing, allowed values are: STM32_SERIES_F1, + * STM32_SERIES_F2. This set of values will expand as libmaple adds + * support for more STM32 series MCUs. + */ +#define STM32_MCU_SERIES + +/** + * @brief Number of interrupts in the vector table. + * + * This does not include Cortex-M interrupts (NMI, HardFault, etc.). + */ +#define STM32_NR_INTERRUPTS + +/** + * Number of GPIO ports. + */ +#define STM32_NR_GPIO_PORTS + +/* FIXME [0.0.13] add this to ReST API page */ +/** + * @brief Bitmask of timers available on the MCU. + * + * That is, if TIMERn is available, then STM32_TIMER_MASK & (1 << n) + * will be nonzero. For example, a nonzero value of "STM32_TIMER_MASK + * & 0x2" means TIMER1 is available. + * + * A bitmask is necessary as some STM32 MCUs have "holes" in the range + * of available timers. + */ +#define STM32_TIMER_MASK + +/** + * @brief Multiplier to convert microseconds into loop iterations + * in delay_us(). + * + * @see delay_us() + */ +#define STM32_DELAY_US_MULT + +/** + * @brief Pointer to end of built-in SRAM. + * + * Points to the address which is 1 byte past the last valid + * SRAM address. + */ +#define STM32_SRAM_END + +/** + * @brief 1 if the target MCU has a DAC, and 0 otherwise. + */ +#define STM32_HAVE_DAC + +/** + * @brief 1 if the target MCU has the FSMC peripheral, and 0 otherwise. + * + * Note that the feature set of the FSMC peripheral is restricted on + * some MCUs. + */ +#define STM32_HAVE_FSMC + +/** + * @brief 1 if the target MCU has a USB peripheral, and 0 otherwise. + * + * Note that a variety of USB peripherals are available across the + * different series, with widely varying feature sets and programming + * interfaces. This macro will be 1 if any such peripheral is present. + */ +#define STM32_HAVE_USB + +#endif /* __DOXYGEN__ */ + +/* + * The following are for backwards compatibility only. + */ + +/* PCLK1 and PCLK2 are for backwards compatibility only; don't use in + * new code. */ +#ifndef PCLK1 +#define PCLK1 STM32_PCLK1 +#endif +#if PCLK1 != STM32_PCLK1 +#error "PCLK1 (which is deprecated) differs from STM32_PCLK1." +#endif +#ifndef PCLK2 +#define PCLK2 STM32_PCLK2 +#endif +#if PCLK2 != STM32_PCLK2 +#error "PCLK2 (which is deprecated) differs from STM32_PCLK2." +#endif + +/** @brief Deprecated. Use STM32_NR_INTERRUPTS instead. */ +#define NR_INTERRUPTS STM32_NR_INTERRUPTS +/** @brief Deprecated. Use STM32_NR_GPIO_PORTS instead. */ +#define NR_GPIO_PORTS STM32_NR_GPIO_PORTS +/** @brief Deprecated. Use STM32_DELAY_US_MULT instead. */ +#define DELAY_US_MULT STM32_DELAY_US_MULT + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/include/libmaple/syscfg.h b/libmaple/include/libmaple/syscfg.h new file mode 100644 index 0000000..6b375d3 --- /dev/null +++ b/libmaple/include/libmaple/syscfg.h @@ -0,0 +1,151 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/libmaple/syscfg.h + * @brief System configuration controller (SYSCFG) + * + * Availability: STM32F2, STM32F4. + */ + +#ifndef _LIBMAPLE_SYSCFG_H_ +#define _LIBMAPLE_SYSCFG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libmaple/libmaple_types.h> + +/* + * Register map and base pointer + */ + +/** + * @brief SYSCFG register map type. + */ +typedef struct syscfg_reg_map { + __io uint32 MEMRMP; /**< Memory remap register */ + __io uint32 PMC; /**< Peripheral mode configuration */ + __io uint32 EXTICR[4]; /**< External interrupt configuration registers */ + const uint32 RESERVED1; + const uint32 RESERVED2; + __io uint32 CMPCR; /**< Compensation cell control register */ +} syscfg_reg_map; + +/** SYSCFG register map base pointer */ +#define SYSCFG_BASE ((struct syscfg_reg_map*)0x40013800) + +/* + * Register bit definitions + */ + +/* Memory remap register */ + +#define SYSCFG_MEMRMP_MEM_MODE 0x3 +#define SYSCFG_MEMRMP_MEM_MODE_FLASH 0x0 +#define SYSCFG_MEMRMP_MEM_MODE_SYS_FLASH 0x1 +#define SYSCFG_MEMRMP_MEM_MODE_FSMC_1 0x2 +#define SYSCFG_MEMRMP_MEM_MODE_EMB_SRAM 0x3 + +/* Peripheral mode configuration register */ + +#define SYSCFG_PMC_MII_RMII_SEL_BIT 23 + +#define SYSCFG_PMC_MII_RMII_SEL (1U << SYSCFG_PMC_MII_RMII_SEL_BIT) +#define SYSCFG_PMC_MII_RMII_SEL_MII (0U << SYSCFG_PMC_MII_RMII_SEL_BIT) +#define SYSCFG_PMC_MII_RMII_SEL_RMII (1U << SYSCFG_PMC_MII_RMII_SEL_BIT) + +/* External interrupt configuration register 1 */ + +#define SYSCFG_EXTICR1_EXTI0 0xF +#define SYSCFG_EXTICR1_EXTI1 0xF0 +#define SYSCFG_EXTICR1_EXTI2 0xF00 +#define SYSCFG_EXTICR1_EXTI3 0xF000 + +/* External interrupt configuration register 2 */ + +#define SYSCFG_EXTICR2_EXTI4 0xF +#define SYSCFG_EXTICR2_EXTI5 0xF0 +#define SYSCFG_EXTICR2_EXTI6 0xF00 +#define SYSCFG_EXTICR2_EXTI7 0xF000 + +/* External interrupt configuration register 3 */ + +#define SYSCFG_EXTICR3_EXTI8 0xF +#define SYSCFG_EXTICR3_EXTI9 0xF0 +#define SYSCFG_EXTICR3_EXTI10 0xF00 +#define SYSCFG_EXTICR3_EXTI11 0xF000 + +/* External interrupt configuration register 4 */ + +#define SYSCFG_EXTICR4_EXTI12 0xF +#define SYSCFG_EXTICR4_EXTI13 0xF0 +#define SYSCFG_EXTICR4_EXTI14 0xF00 +#define SYSCFG_EXTICR4_EXTI15 0xF000 + +/* Compensation cell control register */ + +#define SYSCFG_CMPCR_READY_BIT 8 +#define SYSCFG_CMPCR_CMP_PD_BIT 0 + +#define SYSCFG_CMPCR_READY (1U << SYSCFG_CMPCR_READY_BIT) +#define SYSCFG_CMPCR_CMP_PD (1U << SYSCFG_CMPCR_CMP_PD_BIT) +#define SYSCFG_CMPCR_CMP_PD_PDWN (0U << SYSCFG_CMPCR_CMP_PD_BIT) +#define SYSCFG_CMPCR_CMP_PD_ENABLE (1U << SYSCFG_CMPCR_CMP_PD_BIT) + +/* + * Routines + */ + +void syscfg_init(void); + +void syscfg_enable_io_compensation(void); +void syscfg_disable_io_compensation(void); + +/** + * @brief System memory mode + * These values specify what memory to map to address 0x00000000. + * @see syscfg_set_mem_mode + */ +typedef enum syscfg_mem_mode { + /** Main flash memory is mapped at 0x0. */ + SYCFG_MEM_MODE_FLASH = SYSCFG_MEMRMP_MEM_MODE_FLASH, + /** System flash (i.e. ST's baked-in bootloader) is mapped at 0x0. */ + SYCFG_MEM_MODE_SYSTEM_FLASH = SYSCFG_MEMRMP_MEM_MODE_SYS_FLASH, + /** FSMC bank 1 (NOR/PSRAM 1 and 2) is mapped at 0x0. */ + SYCFG_MEM_MODE_FSMC_BANK_1 = SYSCFG_MEMRMP_MEM_MODE_FSMC_1, + /** Embedded SRAM (i.e., not backup SRAM) is mapped at 0x0. */ + SYCFG_MEM_MODE_SRAM = SYSCFG_MEMRMP_MEM_MODE_EMB_SRAM, +} syscfg_mem_mode; + +void syscfg_set_mem_mode(syscfg_mem_mode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/systick.h b/libmaple/include/libmaple/systick.h index 6ec3364..551f800 100644 --- a/libmaple/systick.h +++ b/libmaple/include/libmaple/systick.h @@ -25,21 +25,20 @@ *****************************************************************************/ /** - * @file systick.h - * - * @brief Various system timer definitions + * @file libmaple/include/libmaple/systick.h + * @brief System timer definitions */ -#ifndef _SYSTICK_H_ -#define _SYSTICK_H_ - -#include "libmaple_types.h" -#include "util.h" +#ifndef _LIBMAPLE_SYSTICK_H_ +#define _LIBMAPLE_SYSTICK_H_ #ifdef __cplusplus extern "C"{ #endif +#include <libmaple/libmaple_types.h> +#include <libmaple/util.h> + /** SysTick register map type */ typedef struct systick_reg_map { __io uint32 CSR; /**< Control and status register */ @@ -114,4 +113,3 @@ static inline uint32 systick_check_underflow(void) { #endif #endif - diff --git a/libmaple/timer.h b/libmaple/include/libmaple/timer.h index 53e2547..995f868 100644 --- a/libmaple/timer.h +++ b/libmaple/include/libmaple/timer.h @@ -1,7 +1,7 @@ /****************************************************************************** * The MIT License * - * Copyright (c) 2011 LeafLabs, LLC. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,27 +25,26 @@ *****************************************************************************/ /** - * @file timer.h + * @file libmaple/include/libmaple/timer.h * @author Marti Bolivar <mbolivar@leaflabs.com> - * @brief New-style timer interface. - * - * Replaces old timers.h implementation. + * @brief Timer interface. */ -#ifndef _TIMERS_H_ -#define _TIMERS_H_ - -#include "libmaple.h" -#include "rcc.h" -#include "nvic.h" -#include "bitband.h" +#ifndef _LIBMAPLE_TIMER_H_ +#define _LIBMAPLE_TIMER_H_ #ifdef __cplusplus extern "C"{ #endif +#include <series/timer.h> +#include <libmaple/libmaple.h> +#include <libmaple/rcc.h> +#include <libmaple/nvic.h> +#include <libmaple/bitband.h> + /* - * Register maps and devices + * Register maps */ /** Advanced control timer register map type */ @@ -53,7 +52,7 @@ typedef struct timer_adv_reg_map { __io uint32 CR1; /**< Control register 1 */ __io uint32 CR2; /**< Control register 2 */ __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ + __io uint32 DIER; /**< DMA/interrupt enable register */ __io uint32 SR; /**< Status register */ __io uint32 EGR; /**< Event generation register */ __io uint32 CCMR1; /**< Capture/compare mode register 1 */ @@ -72,36 +71,17 @@ typedef struct timer_adv_reg_map { __io uint32 DMAR; /**< DMA address for full transfer */ } timer_adv_reg_map; -/** General purpose timer register map type */ -typedef struct timer_gen_reg_map { - __io uint32 CR1; /**< Control register 1 */ - __io uint32 CR2; /**< Control register 2 */ - __io uint32 SMCR; /**< Slave mode control register */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ - __io uint32 SR; /**< Status register */ - __io uint32 EGR; /**< Event generation register */ - __io uint32 CCMR1; /**< Capture/compare mode register 1 */ - __io uint32 CCMR2; /**< Capture/compare mode register 2 */ - __io uint32 CCER; /**< Capture/compare enable register */ - __io uint32 CNT; /**< Counter */ - __io uint32 PSC; /**< Prescaler */ - __io uint32 ARR; /**< Auto-reload register */ - const uint32 RESERVED1; /**< Reserved */ - __io uint32 CCR1; /**< Capture/compare register 1 */ - __io uint32 CCR2; /**< Capture/compare register 2 */ - __io uint32 CCR3; /**< Capture/compare register 3 */ - __io uint32 CCR4; /**< Capture/compare register 4 */ - const uint32 RESERVED2; /**< Reserved */ - __io uint32 DCR; /**< DMA control register */ - __io uint32 DMAR; /**< DMA address for full transfer */ -} timer_gen_reg_map; +/* General purpose timer register map type: intentionally omitted. + * + * General purpose timers differ slightly across series, so leave it + * up to the series header to define struct timer_gen_reg_map. */ /** Basic timer register map type */ typedef struct timer_bas_reg_map { __io uint32 CR1; /**< Control register 1 */ __io uint32 CR2; /**< Control register 2 */ const uint32 RESERVED1; /**< Reserved */ - __io uint32 DIER; /**< DMA/Interrupt enable register */ + __io uint32 DIER; /**< DMA/interrupt enable register */ __io uint32 SR; /**< Status register */ __io uint32 EGR; /**< Event generation register */ const uint32 RESERVED2; /**< Reserved */ @@ -112,25 +92,6 @@ typedef struct timer_bas_reg_map { __io uint32 ARR; /**< Auto-reload register */ } timer_bas_reg_map; -/** Timer 1 register map base pointer */ -#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00) -/** Timer 2 register map base pointer */ -#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000) -/** Timer 3 register map base pointer */ -#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400) -/** Timer 4 register map base pointer */ -#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800) -#ifdef STM32_HIGH_DENSITY -/** Timer 5 register map base pointer */ -#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00) -/** Timer 6 register map base pointer */ -#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000) -/** Timer 7 register map base pointer */ -#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400) -/** Timer 8 register map base pointer */ -#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400) -#endif - /* * Timer devices */ @@ -157,7 +118,7 @@ typedef union timer_reg_map { typedef enum timer_type { TIMER_ADVANCED, /**< Advanced type */ TIMER_GENERAL, /**< General purpose type */ - TIMER_BASIC /**< Basic type */ + TIMER_BASIC, /**< Basic type */ } timer_type; /** Timer device type */ @@ -165,19 +126,54 @@ typedef struct timer_dev { timer_reg_map regs; /**< Register map */ rcc_clk_id clk_id; /**< RCC clock information */ timer_type type; /**< Timer's type */ - voidFuncPtr handlers[]; /**< User IRQ handlers */ + voidFuncPtr handlers[]; /**< + * Don't touch these. Use these instead: + * @see timer_attach_interrupt() + * @see timer_detach_interrupt() */ } timer_dev; +#if STM32_HAVE_TIMER(1) extern timer_dev *TIMER1; +#endif +#if STM32_HAVE_TIMER(2) extern timer_dev *TIMER2; +#endif +#if STM32_HAVE_TIMER(3) extern timer_dev *TIMER3; +#endif +#if STM32_HAVE_TIMER(4) extern timer_dev *TIMER4; -#ifdef STM32_HIGH_DENSITY +#endif +#if STM32_HAVE_TIMER(5) extern timer_dev *TIMER5; +#endif +#if STM32_HAVE_TIMER(6) extern timer_dev *TIMER6; +#endif +#if STM32_HAVE_TIMER(7) extern timer_dev *TIMER7; +#endif +#if STM32_HAVE_TIMER(8) extern timer_dev *TIMER8; #endif +#if STM32_HAVE_TIMER(9) +extern timer_dev *TIMER9; +#endif +#if STM32_HAVE_TIMER(10) +extern timer_dev *TIMER10; +#endif +#if STM32_HAVE_TIMER(11) +extern timer_dev *TIMER11; +#endif +#if STM32_HAVE_TIMER(12) +extern timer_dev *TIMER12; +#endif +#if STM32_HAVE_TIMER(13) +extern timer_dev *TIMER13; +#endif +#if STM32_HAVE_TIMER(14) +extern timer_dev *TIMER14; +#endif /* * Register bit definitions @@ -196,17 +192,17 @@ extern timer_dev *TIMER8; #define TIMER_CR1_CKD_1TCKINT (0x0 << 8) #define TIMER_CR1_CKD_2TCKINT (0x1 << 8) #define TIMER_CR1_CKD_4TICKINT (0x2 << 8) -#define TIMER_CR1_ARPE BIT(TIMER_CR1_ARPE_BIT) +#define TIMER_CR1_ARPE (1U << TIMER_CR1_ARPE_BIT) #define TIMER_CR1_CKD_CMS (0x3 << 5) #define TIMER_CR1_CKD_CMS_EDGE (0x0 << 5) #define TIMER_CR1_CKD_CMS_CENTER1 (0x1 << 5) #define TIMER_CR1_CKD_CMS_CENTER2 (0x2 << 5) #define TIMER_CR1_CKD_CMS_CENTER3 (0x3 << 5) -#define TIMER_CR1_DIR BIT(TIMER_CR1_DIR_BIT) -#define TIMER_CR1_OPM BIT(TIMER_CR1_OPM_BIT) -#define TIMER_CR1_URS BIT(TIMER_CR1_URS_BIT) -#define TIMER_CR1_UDIS BIT(TIMER_CR1_UDIS_BIT) -#define TIMER_CR1_CEN BIT(TIMER_CR1_CEN_BIT) +#define TIMER_CR1_DIR (1U << TIMER_CR1_DIR_BIT) +#define TIMER_CR1_OPM (1U << TIMER_CR1_OPM_BIT) +#define TIMER_CR1_URS (1U << TIMER_CR1_URS_BIT) +#define TIMER_CR1_UDIS (1U << TIMER_CR1_UDIS_BIT) +#define TIMER_CR1_CEN (1U << TIMER_CR1_CEN_BIT) /* Control register 2 (CR2) */ @@ -217,19 +213,19 @@ extern timer_dev *TIMER8; #define TIMER_CR2_OIS2_BIT 10 #define TIMER_CR2_OIS1N_BIT 9 #define TIMER_CR2_OIS1_BIT 8 -#define TIMER_CR2_TI1S_BIT 7 /* tills? yikes */ +#define TIMER_CR2_TI1S_BIT 7 #define TIMER_CR2_CCDS_BIT 3 #define TIMER_CR2_CCUS_BIT 2 #define TIMER_CR2_CCPC_BIT 0 -#define TIMER_CR2_OIS4 BIT(TIMER_CR2_OIS4_BIT) -#define TIMER_CR2_OIS3N BIT(TIMER_CR2_OIS3N_BIT) -#define TIMER_CR2_OIS3 BIT(TIMER_CR2_OIS3_BIT) -#define TIMER_CR2_OIS2N BIT(TIMER_CR2_OIS2N_BIT) -#define TIMER_CR2_OIS2 BIT(TIMER_CR2_OIS2_BIT) -#define TIMER_CR2_OIS1N BIT(TIMER_CR2_OIS1N_BIT) -#define TIMER_CR2_OIS1 BIT(TIMER_CR2_OIS1_BIT) -#define TIMER_CR2_TI1S BIT(TIMER_CR2_TI1S_BIT) +#define TIMER_CR2_OIS4 (1U << TIMER_CR2_OIS4_BIT) +#define TIMER_CR2_OIS3N (1U << TIMER_CR2_OIS3N_BIT) +#define TIMER_CR2_OIS3 (1U << TIMER_CR2_OIS3_BIT) +#define TIMER_CR2_OIS2N (1U << TIMER_CR2_OIS2N_BIT) +#define TIMER_CR2_OIS2 (1U << TIMER_CR2_OIS2_BIT) +#define TIMER_CR2_OIS1N (1U << TIMER_CR2_OIS1N_BIT) +#define TIMER_CR2_OIS1 (1U << TIMER_CR2_OIS1_BIT) +#define TIMER_CR2_TI1S (1U << TIMER_CR2_TI1S_BIT) #define TIMER_CR2_MMS (0x7 << 4) #define TIMER_CR2_MMS_RESET (0x0 << 4) #define TIMER_CR2_MMS_ENABLE (0x1 << 4) @@ -239,9 +235,9 @@ extern timer_dev *TIMER8; #define TIMER_CR2_MMS_COMPARE_OC2REF (0x5 << 4) #define TIMER_CR2_MMS_COMPARE_OC3REF (0x6 << 4) #define TIMER_CR2_MMS_COMPARE_OC4REF (0x7 << 4) -#define TIMER_CR2_CCDS BIT(TIMER_CR2_CCDS_BIT) -#define TIMER_CR2_CCUS BIT(TIMER_CR2_CCUS_BIT) -#define TIMER_CR2_CCPC BIT(TIMER_CR2_CCPC_BIT) +#define TIMER_CR2_CCDS (1U << TIMER_CR2_CCDS_BIT) +#define TIMER_CR2_CCUS (1U << TIMER_CR2_CCUS_BIT) +#define TIMER_CR2_CCPC (1U << TIMER_CR2_CCPC_BIT) /* Slave mode control register (SMCR) */ @@ -249,15 +245,15 @@ extern timer_dev *TIMER8; #define TIMER_SMCR_ECE_BIT 14 #define TIMER_SMCR_MSM_BIT 7 -#define TIMER_SMCR_ETP BIT(TIMER_SMCR_ETP_BIT) -#define TIMER_SMCR_ECE BIT(TIMER_SMCR_ECE_BIT) +#define TIMER_SMCR_ETP (1U << TIMER_SMCR_ETP_BIT) +#define TIMER_SMCR_ECE (1U << TIMER_SMCR_ECE_BIT) #define TIMER_SMCR_ETPS (0x3 << 12) #define TIMER_SMCR_ETPS_OFF (0x0 << 12) #define TIMER_SMCR_ETPS_DIV2 (0x1 << 12) #define TIMER_SMCR_ETPS_DIV4 (0x2 << 12) #define TIMER_SMCR_ETPS_DIV8 (0x3 << 12) #define TIMER_SMCR_ETF (0xF << 12) -#define TIMER_SMCR_MSM BIT(TIMER_SMCR_MSM_BIT) +#define TIMER_SMCR_MSM (1U << TIMER_SMCR_MSM_BIT) #define TIMER_SMCR_TS (0x3 << 4) #define TIMER_SMCR_TS_ITR0 (0x0 << 4) #define TIMER_SMCR_TS_ITR1 (0x1 << 4) @@ -280,30 +276,36 @@ extern timer_dev *TIMER8; /* DMA/Interrupt enable register (DIER) */ #define TIMER_DIER_TDE_BIT 14 +#define TIMER_DIER_COMDE_BIT 13 #define TIMER_DIER_CC4DE_BIT 12 #define TIMER_DIER_CC3DE_BIT 11 #define TIMER_DIER_CC2DE_BIT 10 #define TIMER_DIER_CC1DE_BIT 9 #define TIMER_DIER_UDE_BIT 8 +#define TIMER_DIER_BIE_BIT 7 #define TIMER_DIER_TIE_BIT 6 +#define TIMER_DIER_COMIE_BIT 5 #define TIMER_DIER_CC4IE_BIT 4 #define TIMER_DIER_CC3IE_BIT 3 #define TIMER_DIER_CC2IE_BIT 2 #define TIMER_DIER_CC1IE_BIT 1 #define TIMER_DIER_UIE_BIT 0 -#define TIMER_DIER_TDE BIT(TIMER_DIER_TDE_BIT) -#define TIMER_DIER_CC4DE BIT(TIMER_DIER_CC4DE_BIT) -#define TIMER_DIER_CC3DE BIT(TIMER_DIER_CC3DE_BIT) -#define TIMER_DIER_CC2DE BIT(TIMER_DIER_CC2DE_BIT) -#define TIMER_DIER_CC1DE BIT(TIMER_DIER_CC1DE_BIT) -#define TIMER_DIER_UDE BIT(TIMER_DIER_UDE_BIT) -#define TIMER_DIER_TIE BIT(TIMER_DIER_TIE_BIT) -#define TIMER_DIER_CC4IE BIT(TIMER_DIER_CC4IE_BIT) -#define TIMER_DIER_CC3IE BIT(TIMER_DIER_CC3IE_BIT) -#define TIMER_DIER_CC2IE BIT(TIMER_DIER_CC2IE_BIT) -#define TIMER_DIER_CC1IE BIT(TIMER_DIER_CC1IE_BIT) -#define TIMER_DIER_UIE BIT(TIMER_DIER_UIE_BIT) +#define TIMER_DIER_TDE (1U << TIMER_DIER_TDE_BIT) +#define TIMER_DIER_COMDE (1U << TIMER_DIER_COMDE_BIT) +#define TIMER_DIER_CC4DE (1U << TIMER_DIER_CC4DE_BIT) +#define TIMER_DIER_CC3DE (1U << TIMER_DIER_CC3DE_BIT) +#define TIMER_DIER_CC2DE (1U << TIMER_DIER_CC2DE_BIT) +#define TIMER_DIER_CC1DE (1U << TIMER_DIER_CC1DE_BIT) +#define TIMER_DIER_UDE (1U << TIMER_DIER_UDE_BIT) +#define TIMER_DIER_BIE (1U << TIMER_DIER_BIE_BIT) +#define TIMER_DIER_TIE (1U << TIMER_DIER_TIE_BIT) +#define TIMER_DIER_COMIE (1U << TIMER_DIER_COMIE_BIT) +#define TIMER_DIER_CC4IE (1U << TIMER_DIER_CC4IE_BIT) +#define TIMER_DIER_CC3IE (1U << TIMER_DIER_CC3IE_BIT) +#define TIMER_DIER_CC2IE (1U << TIMER_DIER_CC2IE_BIT) +#define TIMER_DIER_CC1IE (1U << TIMER_DIER_CC1IE_BIT) +#define TIMER_DIER_UIE (1U << TIMER_DIER_UIE_BIT) /* Status register (SR) */ @@ -320,34 +322,38 @@ extern timer_dev *TIMER8; #define TIMER_SR_CC1IF_BIT 1 #define TIMER_SR_UIF_BIT 0 -#define TIMER_SR_CC4OF BIT(TIMER_SR_CC4OF_BIT) -#define TIMER_SR_CC3OF BIT(TIMER_SR_CC3OF_BIT) -#define TIMER_SR_CC2OF BIT(TIMER_SR_CC2OF_BIT) -#define TIMER_SR_CC1OF BIT(TIMER_SR_CC1OF_BIT) -#define TIMER_SR_BIF BIT(TIMER_SR_BIF_BIT) -#define TIMER_SR_TIF BIT(TIMER_SR_TIF_BIT) -#define TIMER_SR_COMIF BIT(TIMER_SR_COMIF_BIT) -#define TIMER_SR_CC4IF BIT(TIMER_SR_CC4IF_BIT) -#define TIMER_SR_CC3IF BIT(TIMER_SR_CC3IF_BIT) -#define TIMER_SR_CC2IF BIT(TIMER_SR_CC2IF_BIT) -#define TIMER_SR_CC1IF BIT(TIMER_SR_CC1IF_BIT) -#define TIMER_SR_UIF BIT(TIMER_SR_UIF_BIT) +#define TIMER_SR_CC4OF (1U << TIMER_SR_CC4OF_BIT) +#define TIMER_SR_CC3OF (1U << TIMER_SR_CC3OF_BIT) +#define TIMER_SR_CC2OF (1U << TIMER_SR_CC2OF_BIT) +#define TIMER_SR_CC1OF (1U << TIMER_SR_CC1OF_BIT) +#define TIMER_SR_BIF (1U << TIMER_SR_BIF_BIT) +#define TIMER_SR_TIF (1U << TIMER_SR_TIF_BIT) +#define TIMER_SR_COMIF (1U << TIMER_SR_COMIF_BIT) +#define TIMER_SR_CC4IF (1U << TIMER_SR_CC4IF_BIT) +#define TIMER_SR_CC3IF (1U << TIMER_SR_CC3IF_BIT) +#define TIMER_SR_CC2IF (1U << TIMER_SR_CC2IF_BIT) +#define TIMER_SR_CC1IF (1U << TIMER_SR_CC1IF_BIT) +#define TIMER_SR_UIF (1U << TIMER_SR_UIF_BIT) /* Event generation register (EGR) */ +#define TIMER_EGR_BG_BIT 7 #define TIMER_EGR_TG_BIT 6 +#define TIMER_EGR_COMG_BIT 5 #define TIMER_EGR_CC4G_BIT 4 #define TIMER_EGR_CC3G_BIT 3 #define TIMER_EGR_CC2G_BIT 2 #define TIMER_EGR_CC1G_BIT 1 #define TIMER_EGR_UG_BIT 0 -#define TIMER_EGR_TG BIT(TIMER_EGR_TG_BIT) -#define TIMER_EGR_CC4G BIT(TIMER_EGR_CC4G_BIT) -#define TIMER_EGR_CC3G BIT(TIMER_EGR_CC3G_BIT) -#define TIMER_EGR_CC2G BIT(TIMER_EGR_CC2G_BIT) -#define TIMER_EGR_CC1G BIT(TIMER_EGR_CC1G_BIT) -#define TIMER_EGR_UG BIT(TIMER_EGR_UG_BIT) +#define TIMER_EGR_BG (1U << TIMER_EGR_BG_BIT) +#define TIMER_EGR_TG (1U << TIMER_EGR_TG_BIT) +#define TIMER_EGR_COMG (1U << TIMER_EGR_COMG_BIT) +#define TIMER_EGR_CC4G (1U << TIMER_EGR_CC4G_BIT) +#define TIMER_EGR_CC3G (1U << TIMER_EGR_CC3G_BIT) +#define TIMER_EGR_CC2G (1U << TIMER_EGR_CC2G_BIT) +#define TIMER_EGR_CC1G (1U << TIMER_EGR_CC1G_BIT) +#define TIMER_EGR_UG (1U << TIMER_EGR_UG_BIT) /* Capture/compare mode registers, common values */ @@ -365,22 +371,22 @@ extern timer_dev *TIMER8; #define TIMER_CCMR1_OC1PE_BIT 3 #define TIMER_CCMR1_OC1FE_BIT 2 -#define TIMER_CCMR1_OC2CE BIT(TIMER_CCMR1_OC2CE_BIT) +#define TIMER_CCMR1_OC2CE (1U << TIMER_CCMR1_OC2CE_BIT) #define TIMER_CCMR1_OC2M (0x3 << 12) #define TIMER_CCMR1_IC2F (0xF << 12) -#define TIMER_CCMR1_OC2PE BIT(TIMER_CCMR1_OC2PE_BIT) -#define TIMER_CCMR1_OC2FE BIT(TIMER_CCMR1_OC2FE_BIT) +#define TIMER_CCMR1_OC2PE (1U << TIMER_CCMR1_OC2PE_BIT) +#define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT) #define TIMER_CCMR1_IC2PSC (0x3 << 10) #define TIMER_CCMR1_CC2S (0x3 << 8) #define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) #define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) #define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) #define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) -#define TIMER_CCMR1_OC1CE BIT(TIMER_CCMR1_OC1CE_BIT) +#define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT) #define TIMER_CCMR1_OC1M (0x3 << 4) #define TIMER_CCMR1_IC1F (0xF << 4) -#define TIMER_CCMR1_OC1PE BIT(TIMER_CCMR1_OC1PE_BIT) -#define TIMER_CCMR1_OC1FE BIT(TIMER_CCMR1_OC1FE_BIT) +#define TIMER_CCMR1_OC1PE (1U << TIMER_CCMR1_OC1PE_BIT) +#define TIMER_CCMR1_OC1FE (1U << TIMER_CCMR1_OC1FE_BIT) #define TIMER_CCMR1_IC1PSC (0x3 << 2) #define TIMER_CCMR1_CC1S 0x3 #define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT @@ -397,48 +403,60 @@ extern timer_dev *TIMER8; #define TIMER_CCMR2_OC3PE_BIT 3 #define TIMER_CCMR2_OC3FE_BIT 2 -#define TIMER_CCMR2_OC4CE BIT(TIMER_CCMR2_OC4CE_BIT) +#define TIMER_CCMR2_OC4CE (1U << TIMER_CCMR2_OC4CE_BIT) #define TIMER_CCMR2_OC4M (0x3 << 12) -#define TIMER_CCMR2_IC2F (0xF << 12) -#define TIMER_CCMR2_OC4PE BIT(TIMER_CCMR2_OC4PE_BIT) -#define TIMER_CCMR2_OC4FE BIT(TIMER_CCMR2_OC4FE_BIT) -#define TIMER_CCMR2_IC2PSC (0x3 << 10) +#define TIMER_CCMR2_IC4F (0xF << 12) +#define TIMER_CCMR2_OC4PE (1U << TIMER_CCMR2_OC4PE_BIT) +#define TIMER_CCMR2_OC4FE (1U << TIMER_CCMR2_OC4FE_BIT) +#define TIMER_CCMR2_IC4PSC (0x3 << 10) #define TIMER_CCMR2_CC4S (0x3 << 8) -#define TIMER_CCMR1_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) -#define TIMER_CCMR1_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) -#define TIMER_CCMR1_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) -#define TIMER_CCMR1_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) -#define TIMER_CCMR2_OC3CE BIT(TIMER_CCMR2_OC3CE_BIT) +#define TIMER_CCMR2_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) +#define TIMER_CCMR2_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) +#define TIMER_CCMR2_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) +#define TIMER_CCMR2_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) +#define TIMER_CCMR2_OC3CE (1U << TIMER_CCMR2_OC3CE_BIT) #define TIMER_CCMR2_OC3M (0x3 << 4) -#define TIMER_CCMR2_IC1F (0xF << 4) -#define TIMER_CCMR2_OC3PE BIT(TIMER_CCMR2_OC3PE_BIT) -#define TIMER_CCMR2_OC3FE BIT(TIMER_CCMR2_OC3FE_BIT) -#define TIMER_CCMR2_IC1PSC (0x3 << 2) +#define TIMER_CCMR2_IC3F (0xF << 4) +#define TIMER_CCMR2_OC3PE (1U << TIMER_CCMR2_OC3PE_BIT) +#define TIMER_CCMR2_OC3FE (1U << TIMER_CCMR2_OC3FE_BIT) +#define TIMER_CCMR2_IC3PSC (0x3 << 2) #define TIMER_CCMR2_CC3S 0x3 -#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT -#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 -#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 -#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC +#define TIMER_CCMR2_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT +#define TIMER_CCMR2_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 +#define TIMER_CCMR2_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 +#define TIMER_CCMR2_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC /* Capture/compare enable register (CCER) */ #define TIMER_CCER_CC4P_BIT 13 #define TIMER_CCER_CC4E_BIT 12 +#define TIMER_CCER_CC3NP_BIT 11 +#define TIMER_CCER_CC3NE_BIT 10 #define TIMER_CCER_CC3P_BIT 9 #define TIMER_CCER_CC3E_BIT 8 +#define TIMER_CCER_CC2NP_BIT 7 +#define TIMER_CCER_CC2NE_BIT 6 #define TIMER_CCER_CC2P_BIT 5 #define TIMER_CCER_CC2E_BIT 4 +#define TIMER_CCER_CC1NP_BIT 3 +#define TIMER_CCER_CC1NE_BIT 2 #define TIMER_CCER_CC1P_BIT 1 #define TIMER_CCER_CC1E_BIT 0 -#define TIMER_CCER_CC4P BIT(TIMER_CCER_CC4P_BIT) -#define TIMER_CCER_CC4E BIT(TIMER_CCER_CC4E_BIT) -#define TIMER_CCER_CC3P BIT(TIMER_CCER_CC3P_BIT) -#define TIMER_CCER_CC3E BIT(TIMER_CCER_CC3E_BIT) -#define TIMER_CCER_CC2P BIT(TIMER_CCER_CC2P_BIT) -#define TIMER_CCER_CC2E BIT(TIMER_CCER_CC2E_BIT) -#define TIMER_CCER_CC1P BIT(TIMER_CCER_CC1P_BIT) -#define TIMER_CCER_CC1E BIT(TIMER_CCER_CC1E_BIT) +#define TIMER_CCER_CC4P (1U << TIMER_CCER_CC4P_BIT) +#define TIMER_CCER_CC4E (1U << TIMER_CCER_CC4E_BIT) +#define TIMER_CCER_CC3NP (1U << TIMER_CCER_CC3NP_BIT) +#define TIMER_CCER_CC3NE (1U << TIMER_CCER_CC3NE_BIT) +#define TIMER_CCER_CC3P (1U << TIMER_CCER_CC3P_BIT) +#define TIMER_CCER_CC3E (1U << TIMER_CCER_CC3E_BIT) +#define TIMER_CCER_CC2NP (1U << TIMER_CCER_CC2NP_BIT) +#define TIMER_CCER_CC2NE (1U << TIMER_CCER_CC2NE_BIT) +#define TIMER_CCER_CC2P (1U << TIMER_CCER_CC2P_BIT) +#define TIMER_CCER_CC2E (1U << TIMER_CCER_CC2E_BIT) +#define TIMER_CCER_CC1NP (1U << TIMER_CCER_CC1NP_BIT) +#define TIMER_CCER_CC1NE (1U << TIMER_CCER_CC1NE_BIT) +#define TIMER_CCER_CC1P (1U << TIMER_CCER_CC1P_BIT) +#define TIMER_CCER_CC1E (1U << TIMER_CCER_CC1E_BIT) /* Break and dead-time register (BDTR) */ @@ -449,12 +467,12 @@ extern timer_dev *TIMER8; #define TIMER_BDTR_OSSR_BIT 11 #define TIMER_BDTR_OSSI_BIT 10 -#define TIMER_BDTR_MOE BIT(TIMER_BDTR_MOE_BIT) -#define TIMER_BDTR_AOE BIT(TIMER_BDTR_AOE_BIT) -#define TIMER_BDTR_BKP BIT(TIMER_BDTR_BKP_BIT) -#define TIMER_BDTR_BKE BIT(TIMER_BDTR_BKE_BIT) -#define TIMER_BDTR_OSSR BIT(TIMER_BDTR_OSSR_BIT) -#define TIMER_BDTR_OSSI BIT(TIMER_BDTR_OSSI_BIT) +#define TIMER_BDTR_MOE (1U << TIMER_BDTR_MOE_BIT) +#define TIMER_BDTR_AOE (1U << TIMER_BDTR_AOE_BIT) +#define TIMER_BDTR_BKP (1U << TIMER_BDTR_BKP_BIT) +#define TIMER_BDTR_BKE (1U << TIMER_BDTR_BKE_BIT) +#define TIMER_BDTR_OSSR (1U << TIMER_BDTR_OSSR_BIT) +#define TIMER_BDTR_OSSI (1U << TIMER_BDTR_OSSI_BIT) #define TIMER_BDTR_LOCK (0x3 << 8) #define TIMER_BDTR_LOCK_OFF (0x0 << 8) #define TIMER_BDTR_LOCK_LEVEL1 (0x1 << 8) @@ -465,24 +483,24 @@ extern timer_dev *TIMER8; /* DMA control register (DCR) */ #define TIMER_DCR_DBL (0x1F << 8) -#define TIMER_DCR_DBL_1BYTE (0x0 << 8) -#define TIMER_DCR_DBL_2BYTE (0x1 << 8) -#define TIMER_DCR_DBL_3BYTE (0x2 << 8) -#define TIMER_DCR_DBL_4BYTE (0x3 << 8) -#define TIMER_DCR_DBL_5BYTE (0x4 << 8) -#define TIMER_DCR_DBL_6BYTE (0x5 << 8) -#define TIMER_DCR_DBL_7BYTE (0x6 << 8) -#define TIMER_DCR_DBL_8BYTE (0x7 << 8) -#define TIMER_DCR_DBL_9BYTE (0x8 << 8) -#define TIMER_DCR_DBL_10BYTE (0x9 << 8) -#define TIMER_DCR_DBL_11BYTE (0xA << 8) -#define TIMER_DCR_DBL_12BYTE (0xB << 8) -#define TIMER_DCR_DBL_13BYTE (0xC << 8) -#define TIMER_DCR_DBL_14BYTE (0xD << 8) -#define TIMER_DCR_DBL_15BYTE (0xE << 8) -#define TIMER_DCR_DBL_16BYTE (0xF << 8) -#define TIMER_DCR_DBL_17BYTE (0x10 << 8) -#define TIMER_DCR_DBL_18BYTE (0x11 << 8) +#define TIMER_DCR_DBL_1_XFER (0x0 << 8) +#define TIMER_DCR_DBL_2_XFER (0x1 << 8) +#define TIMER_DCR_DBL_3_XFER (0x2 << 8) +#define TIMER_DCR_DBL_4_XFER (0x3 << 8) +#define TIMER_DCR_DBL_5_XFER (0x4 << 8) +#define TIMER_DCR_DBL_6_XFER (0x5 << 8) +#define TIMER_DCR_DBL_7_XFER (0x6 << 8) +#define TIMER_DCR_DBL_8_XFER (0x7 << 8) +#define TIMER_DCR_DBL_9_XFER (0x8 << 8) +#define TIMER_DCR_DBL_10_XFER (0x9 << 8) +#define TIMER_DCR_DBL_11_XFER (0xA << 8) +#define TIMER_DCR_DBL_12_XFER (0xB << 8) +#define TIMER_DCR_DBL_13_XFER (0xC << 8) +#define TIMER_DCR_DBL_14_XFER (0xD << 8) +#define TIMER_DCR_DBL_15_XFER (0xE << 8) +#define TIMER_DCR_DBL_16_XFER (0xF << 8) +#define TIMER_DCR_DBL_17_XFER (0x10 << 8) +#define TIMER_DCR_DBL_18_XFER (0x11 << 8) #define TIMER_DCR_DBA 0x1F #define TIMER_DCR_DBA_CR1 0x0 #define TIMER_DCR_DBA_CR2 0x1 @@ -510,27 +528,32 @@ extern timer_dev *TIMER8; */ /** - * Used to configure the behavior of a timer channel. Note that not - * all timers can be configured in every mode. + * @brief Used to configure the behavior of a timer channel. + * + * Be careful: not all timers can be configured in every mode. */ -/* TODO TIMER_PWM_CENTER_ALIGNED, TIMER_INPUT_CAPTURE, TIMER_ONE_PULSE */ typedef enum timer_mode { - TIMER_DISABLED, /**< In this mode, the timer stops counting, - channel interrupts are detached, and no state - changes are output. */ - TIMER_PWM, /**< PWM output mode. This is the default mode for pins - after initialization. */ - /* TIMER_PWM_CENTER_ALIGNED, /\**< Center-aligned PWM output mode. *\/ */ - TIMER_OUTPUT_COMPARE, /**< In this mode, the timer counts from 0 - to its reload value repeatedly; every - time the counter value reaches one of - the channel compare values, the - corresponding interrupt is fired. */ - /* TIMER_INPUT_CAPTURE, /\**< In this mode, the timer can measure the */ - /* pulse lengths of input signals. *\/ */ - /* TIMER_ONE_PULSE /\**< In this mode, the timer can generate a single */ - /* pulse on a GPIO pin for a specified amount of */ - /* time. *\/ */ + /** + * The timer stops counting, channel interrupts are detached, and + * no state changes are output. */ + TIMER_DISABLED, + + /** PWM output. */ + TIMER_PWM, + + /* TIMER_PWM_CENTER_ALIGNED, TODO: Center-aligned PWM output mode. */ + + /** + * The timer counts from 0 to its reload value repeatedly; every + * time the counter value reaches one of the channel compare + * values, the corresponding interrupt is fired. */ + TIMER_OUTPUT_COMPARE, + + /* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the + * pulse lengths of input signals */ + /* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single + * pulse on a GPIO pin for a specified amount of + * time. */ } timer_mode; /** Timer channel numbers */ @@ -555,27 +578,26 @@ void timer_init(timer_dev *dev); void timer_disable(timer_dev *dev); void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode); void timer_foreach(void (*fn)(timer_dev*)); +int timer_has_cc_channel(timer_dev *dev, uint8 channel); /** * @brief Timer interrupt number. * - * Not all timers support all of these values; see the descriptions - * for each value. + * Not all timers support all of these values. All timers support + * TIMER_UPDATE_INTERRUPT. "General purpose" timers can be a special + * nuisance in this regard, as they individually support different + * subsets of the available interupts. Consult your target's reference + * manual for the details. */ typedef enum timer_interrupt_id { - TIMER_UPDATE_INTERRUPT, /**< Update interrupt, available on all timers. */ - TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt, available - on general and advanced timers only. */ - TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt, general and - advanced timers only. */ - TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt, general and - advanced timers only. */ - TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt, general and - advanced timers only. */ - TIMER_COM_INTERRUPT, /**< COM interrupt, advanced timers only */ - TIMER_TRG_INTERRUPT, /**< Trigger interrupt, general and advanced - timers only */ - TIMER_BREAK_INTERRUPT /**< Break interrupt, advanced timers only. */ + TIMER_UPDATE_INTERRUPT, /**< Update interrupt. */ + TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt. */ + TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt. */ + TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt. */ + TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt. */ + TIMER_COM_INTERRUPT, /**< COM interrupt. */ + TIMER_TRG_INTERRUPT, /**< Trigger interrupt. */ + TIMER_BREAK_INTERRUPT, /**< Break interrupt. */ } timer_interrupt_id; void timer_attach_interrupt(timer_dev *dev, @@ -843,18 +865,19 @@ static inline void timer_cc_set_pol(timer_dev *dev, uint8 channel, uint8 pol) { /** * @brief Get a timer's DMA burst length. * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @return Number of bytes to be transferred per DMA request, from 1 to 18. + * @return Number of transfers per read or write to timer DMA register, + * from 1 to 18. */ static inline uint8 timer_dma_get_burst_len(timer_dev *dev) { uint32 dbl = ((dev->regs).gen->DCR & TIMER_DCR_DBL) >> 8; - return dbl + 1; /* 0 means 1 byte, etc. */ + return dbl + 1; /* 0 means 1 transfer, etc. */ } /** * @brief Set a timer's DMA burst length. * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @param length DMA burst length; i.e., number of bytes to transfer - * per DMA request, from 1 to 18. + * @param length DMA burst length; i.e., number of DMA transfers per + * read/write to timer DMA register, from 1 to 18. */ static inline void timer_dma_set_burst_len(timer_dev *dev, uint8 length) { uint32 tmp = (dev->regs).gen->DCR; @@ -869,47 +892,52 @@ static inline void timer_dma_set_burst_len(timer_dev *dev, uint8 length) { * Defines the base address for DMA transfers. */ typedef enum timer_dma_base_addr { - TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1, /**< Base is control register 1 */ - TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2, /**< Base is control register 2 */ - TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR, /**< Base is slave mode - control register */ - TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER, /**< Base is DMA interrupt enable - register */ - TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR, /**< Base is status register */ - TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR, /**< Base is event generation - register */ - TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1, /**< Base is capture/compare - mode register 1 */ - TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2, /**< Base is capture/compare - mode register 2 */ - TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER, /**< Base is capture/compare - enable register */ - TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT, /**< Base is counter */ - TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC, /**< Base is prescaler */ - TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR, /**< Base is auto-reload - register */ - TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR, /**< Base is repetition - counter register */ - TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1, /**< Base is capture/compare - register 1 */ - TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2, /**< Base is capture/compare - register 2 */ - TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3, /**< Base is capture/compare - register 3 */ - TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4, /**< Base is capture/compare - register 4 */ - TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR, /**< Base is break and - dead-time register */ - TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR, /**< Base is DMA control - register */ - TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR /**< Base is DMA address for - full transfer */ + /** Base is control register 1 */ + TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1, + /** Base is control register 2 */ + TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2, + /** Base is slave mode control register */ + TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR, + /** Base is DMA interrupt enable register */ + TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER, + /** Base is status register */ + TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR, + /** Base is event generation register */ + TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR, + /** Base is capture/compare mode register 1 */ + TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1, + /** Base is capture/compare mode register 2 */ + TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2, + /** Base is capture/compare enable register */ + TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER, + /** Base is counter */ + TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT, + /** Base is prescaler */ + TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC, + /** Base is auto-reload register */ + TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR, + /** Base is repetition counter register */ + TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR, + /** Base is capture/compare register 1 */ + TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1, + /** Base is capture/compare register 2 */ + TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2, + /** Base is capture/compare register 3 */ + TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3, + /** Base is capture/compare register 4 */ + TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4, + /** Base is break and dead-time register */ + TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR, + /** Base is DMA control register */ + TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR, + /** Base is DMA address for full transfer */ + TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR, } timer_dma_base_addr; /** * @brief Get the timer's DMA base address. * - * Some restrictions apply; see ST RM0008. + * Some restrictions apply; see the reference manual for your chip. * * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. * @return DMA base address @@ -922,7 +950,7 @@ static inline timer_dma_base_addr timer_dma_get_base_addr(timer_dev *dev) { /** * @brief Set the timer's DMA base address. * - * Some restrictions apply; see ST RM0008. + * Some restrictions apply; see the reference manual for your chip. * * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. * @param dma_base DMA base address. @@ -939,35 +967,38 @@ static inline void timer_dma_set_base_addr(timer_dev *dev, * Timer output compare modes. */ typedef enum timer_oc_mode { - TIMER_OC_MODE_FROZEN = 0 << 4, /**< Frozen: comparison between output - compare register and counter has no - effect on the outputs. */ - TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4, /**< OCxREF signal is forced - high when the count matches - the channel capture/compare - register. */ - TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4, /**< OCxREF signal is forced - low when the counter matches - the channel capture/compare - register. */ - TIMER_OC_MODE_TOGGLE = 3 << 4, /**< OCxREF toggles when counter - matches the cannel capture/compare - register. */ - TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4, /**< OCxREF is forced low. */ - TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4, /**< OCxREF is forced high. */ - TIMER_OC_MODE_PWM_1 = 6 << 4, /**< PWM mode 1. In upcounting, channel is - active as long as count is less than - channel capture/compare register, else - inactive. In downcounting, channel is - inactive as long as count exceeds - capture/compare register, else - active. */ - TIMER_OC_MODE_PWM_2 = 7 << 4 /**< PWM mode 2. In upcounting, channel is - inactive as long as count is less than - capture/compare register, else active. - In downcounting, channel is active as - long as count exceeds capture/compare - register, else inactive. */ + /** + * Frozen: comparison between output compare register and counter + * has no effect on the outputs. */ + TIMER_OC_MODE_FROZEN = 0 << 4, + /** + * OCxREF signal is forced high when the count matches the channel + * capture/compare register. */ + TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4, + /** + * OCxREF signal is forced low when the counter matches the + * channel capture/compare register. */ + TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4, + /** + * OCxREF toggles when counter matches the channel capture/compare + * register. */ + TIMER_OC_MODE_TOGGLE = 3 << 4, + /** OCxREF is forced low. */ + TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4, + /** OCxREF is forced high. */ + TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4, + /** + * PWM mode 1. In upcounting, channel is active as long as count + * is less than channel capture/compare register, else inactive. + * In downcounting, channel is inactive as long as count exceeds + * capture/compare register, else active. */ + TIMER_OC_MODE_PWM_1 = 6 << 4, + /** + * PWM mode 2. In upcounting, channel is inactive as long as count + * is less than capture/compare register, else active. In + * downcounting, channel is active as long as count exceeds + * capture/compare register, else inactive. */ + TIMER_OC_MODE_PWM_2 = 7 << 4, } timer_oc_mode; /** @@ -975,9 +1006,9 @@ typedef enum timer_oc_mode { * @see timer_oc_set_mode() */ typedef enum timer_oc_mode_flags { - TIMER_OC_CE = BIT(7), /**< Output compare clear enable. */ - TIMER_OC_PE = BIT(3), /**< Output compare preload enable. */ - TIMER_OC_FE = BIT(2) /**< Output compare fast enable. */ + TIMER_OC_CE = 1U << 7, /**< Output compare clear enable. */ + TIMER_OC_PE = 1U << 3, /**< Output compare preload enable. */ + TIMER_OC_FE = 1U << 2, /**< Output compare fast enable. */ } timer_oc_mode_flags; /** @@ -1005,6 +1036,73 @@ static inline void timer_oc_set_mode(timer_dev *dev, *ccmr = tmp; } +/* + * Old, erroneous bit definitions from previous releases, kept for + * backwards compatibility: + */ + +/** Deprecated. Use TIMER_CCMR1_CC4S_OUTPUT instead. */ +#define TIMER_CCMR1_CC4S_OUTPUT TIMER_CCMR2_CC4S_OUTPUT +/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI1 instead. */ +#define TIMER_CCMR1_CC4S_INPUT_TI1 TIMER_CCMR2_CC4S_INPUT_TI1 +/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI2 instead. */ +#define TIMER_CCMR1_CC4S_INPUT_TI2 TIMER_CCMR2_CC4S_INPUT_TI2 +/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TRC instead. */ +#define TIMER_CCMR1_CC4S_INPUT_TRC TIMER_CCMR2_CC4S_INPUT_TRC +/** Deprecated. Use TIMER_CCMR2_IC4F instead. */ +#define TIMER_CCMR2_IC2F TIMER_CCMR2_IC4F +/** Deprecated. Use TIMER_CCMR2_IC4PSC instead. */ +#define TIMER_CCMR2_IC2PSC TIMER_CCMR2_IC4PSC +/** Deprecated. Use TIMER_CCMR2_IC3F instead. */ +#define TIMER_CCMR2_IC1F TIMER_CCMR2_IC3F +/** Deprecated. Use TIMER_CCMR2_IC3PSC instead. */ +#define TIMER_CCMR2_IC1PSC TIMER_CCMR2_IC3PSC +/** Deprecated. Use TIMER_CCMR1_CC3S_OUTPUT instead. */ +#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR2_CC3S_OUTPUT +/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI1 instead. */ +#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR2_CC3S_INPUT_TI1 +/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI2 instead. */ +#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR2_CC3S_INPUT_TI2 +/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TRC instead. */ +#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR2_CC3S_INPUT_TRC + +/** Deprecated. Use TIMER_DCR_DBL_1_XFER instead. */ +#define TIMER_DCR_DBL_1BYTE TIMER_DCR_DBL_1_XFER +/** Deprecated. Use TIMER_DCR_DBL_2_XFER instead. */ +#define TIMER_DCR_DBL_2BYTE TIMER_DCR_DBL_2_XFER +/** Deprecated. Use TIMER_DCR_DBL_3_XFER instead. */ +#define TIMER_DCR_DBL_3BYTE TIMER_DCR_DBL_3_XFER +/** Deprecated. Use TIMER_DCR_DBL_4_XFER instead. */ +#define TIMER_DCR_DBL_4BYTE TIMER_DCR_DBL_4_XFER +/** Deprecated. Use TIMER_DCR_DBL_5_XFER instead. */ +#define TIMER_DCR_DBL_5BYTE TIMER_DCR_DBL_5_XFER +/** Deprecated. Use TIMER_DCR_DBL_6_XFER instead. */ +#define TIMER_DCR_DBL_6BYTE TIMER_DCR_DBL_6_XFER +/** Deprecated. Use TIMER_DCR_DBL_7_XFER instead. */ +#define TIMER_DCR_DBL_7BYTE TIMER_DCR_DBL_7_XFER +/** Deprecated. Use TIMER_DCR_DBL_8_XFER instead. */ +#define TIMER_DCR_DBL_8BYTE TIMER_DCR_DBL_8_XFER +/** Deprecated. Use TIMER_DCR_DBL_9_XFER instead. */ +#define TIMER_DCR_DBL_9BYTE TIMER_DCR_DBL_9_XFER +/** Deprecated. Use TIMER_DCR_DBL_10_XFER instead. */ +#define TIMER_DCR_DBL_10BYTE TIMER_DCR_DBL_10_XFER +/** Deprecated. Use TIMER_DCR_DBL_11_XFER instead. */ +#define TIMER_DCR_DBL_11BYTE TIMER_DCR_DBL_11_XFER +/** Deprecated. Use TIMER_DCR_DBL_12_XFER instead. */ +#define TIMER_DCR_DBL_12BYTE TIMER_DCR_DBL_12_XFER +/** Deprecated. Use TIMER_DCR_DBL_13_XFER instead. */ +#define TIMER_DCR_DBL_13BYTE TIMER_DCR_DBL_13_XFER +/** Deprecated. Use TIMER_DCR_DBL_14_XFER instead. */ +#define TIMER_DCR_DBL_14BYTE TIMER_DCR_DBL_14_XFER +/** Deprecated. Use TIMER_DCR_DBL_15_XFER instead. */ +#define TIMER_DCR_DBL_15BYTE TIMER_DCR_DBL_15_XFER +/** Deprecated. Use TIMER_DCR_DBL_16_XFER instead. */ +#define TIMER_DCR_DBL_16BYTE TIMER_DCR_DBL_16_XFER +/** Deprecated. Use TIMER_DCR_DBL_17_XFER instead. */ +#define TIMER_DCR_DBL_17BYTE TIMER_DCR_DBL_17_XFER +/** Deprecated. Use TIMER_DCR_DBL_18_XFER instead. */ +#define TIMER_DCR_DBL_18BYTE TIMER_DCR_DBL_18_XFER + #ifdef __cplusplus } // extern "C" #endif diff --git a/libmaple/usart.h b/libmaple/include/libmaple/usart.h index ed00e16..26a64d3 100644 --- a/libmaple/usart.h +++ b/libmaple/include/libmaple/usart.h @@ -25,27 +25,28 @@ *****************************************************************************/ /** - * @file usart.h + * @file libmaple/include/libmaple/usart.h * @author Marti Bolivar <mbolivar@leaflabs.com>, * Perry Hung <perry@leaflabs.com> * @brief USART definitions and prototypes */ -#ifndef _USART_H_ -#define _USART_H_ - -#include "libmaple_types.h" -#include "util.h" -#include "rcc.h" -#include "nvic.h" -#include "ring_buffer.h" +#ifndef _LIBMAPLE_USART_H_ +#define _LIBMAPLE_USART_H_ #ifdef __cplusplus extern "C"{ #endif +#include <libmaple/libmaple_types.h> +#include <libmaple/util.h> +#include <libmaple/rcc.h> +#include <libmaple/nvic.h> +#include <libmaple/ring_buffer.h> +#include <series/usart.h> + /* - * Register maps and devices + * Register map (common across supported STM32 series). */ /** USART register map type */ @@ -59,169 +60,315 @@ typedef struct usart_reg_map { __io uint32 GTPR; /**< Guard time and prescaler register */ } usart_reg_map; -/** USART1 register map base pointer */ -#define USART1_BASE ((struct usart_reg_map*)0x40013800) -/** USART2 register map base pointer */ -#define USART2_BASE ((struct usart_reg_map*)0x40004400) -/** USART3 register map base pointer */ -#define USART3_BASE ((struct usart_reg_map*)0x40004800) -#ifdef STM32_HIGH_DENSITY -/** UART4 register map base pointer */ -#define UART4_BASE ((struct usart_reg_map*)0x40004C00) -/** UART5 register map base pointer */ -#define UART5_BASE ((struct usart_reg_map*)0x40005000) -#endif - /* * Register bit definitions */ /* Status register */ +/** Clear to send bit */ #define USART_SR_CTS_BIT 9 +/** Line break detection bit */ #define USART_SR_LBD_BIT 8 +/** Transmit data register empty bit */ #define USART_SR_TXE_BIT 7 +/** Transmission complete bit */ #define USART_SR_TC_BIT 6 +/** Read data register not empty bit */ #define USART_SR_RXNE_BIT 5 +/** IDLE line detected bit */ #define USART_SR_IDLE_BIT 4 +/** Overrun error bit */ #define USART_SR_ORE_BIT 3 +/** Noise error bit */ #define USART_SR_NE_BIT 2 +/** + * @brief Synonym for USART_SR_NE_BIT. + * + * Some series (e.g. STM32F2) use "NF" for "noise flag" instead of the + * original "NE" for "noise error". The meaning of the bit is + * unchanged, but the NF flag can be disabled when the line is + * noise-free. + * + * @see USART_SR_NE_BIT + */ +#define USART_SR_NF_BIT USART_SR_NE_BIT +/** Framing error bit */ #define USART_SR_FE_BIT 1 +/** Parity error bit */ #define USART_SR_PE_BIT 0 +/** Clear to send mask */ #define USART_SR_CTS BIT(USART_SR_CTS_BIT) +/** Line break detected mask */ #define USART_SR_LBD BIT(USART_SR_LBD_BIT) +/** Transmit data register empty mask */ #define USART_SR_TXE BIT(USART_SR_TXE_BIT) +/** Transmission complete mask */ #define USART_SR_TC BIT(USART_SR_TC_BIT) +/** Read data register not empty mask */ #define USART_SR_RXNE BIT(USART_SR_RXNE_BIT) +/** IDLE line detected mask */ #define USART_SR_IDLE BIT(USART_SR_IDLE_BIT) +/** Overrun error mask */ #define USART_SR_ORE BIT(USART_SR_ORE_BIT) +/** Noise error mask */ #define USART_SR_NE BIT(USART_SR_NE_BIT) +/** + * @brief Synonym for USART_SR_NE. + * @see USART_SR_NF_BIT + */ +#define USART_SR_NF USART_SR_NE +/** Framing error mask */ #define USART_SR_FE BIT(USART_SR_FE_BIT) +/** Parity error mask */ #define USART_SR_PE BIT(USART_SR_PE_BIT) /* Data register */ +/** Data register data value mask */ #define USART_DR_DR 0xFF /* Baud rate register */ +/** Mantissa of USARTDIV mask */ #define USART_BRR_DIV_MANTISSA (0xFFF << 4) +/** Fraction of USARTDIV mask */ #define USART_BRR_DIV_FRACTION 0xF /* Control register 1 */ +/** USART enable bit */ #define USART_CR1_UE_BIT 13 +/** Word length bit */ #define USART_CR1_M_BIT 12 +/** Wakeup method bit */ #define USART_CR1_WAKE_BIT 11 +/** Parity control enable bit */ #define USART_CR1_PCE_BIT 10 +/** Parity selection bit */ #define USART_CR1_PS_BIT 9 +/** Parity error interrupt enable bit */ #define USART_CR1_PEIE_BIT 8 +/** Transmit data regsiter not empty interrupt enable bit */ #define USART_CR1_TXEIE_BIT 7 +/** Transmission complete interrupt enable bit */ #define USART_CR1_TCIE_BIT 6 +/** RXNE interrupt enable bit */ #define USART_CR1_RXNEIE_BIT 5 +/** IDLE interrupt enable bit */ #define USART_CR1_IDLEIE_BIT 4 +/** Transmitter enable bit */ #define USART_CR1_TE_BIT 3 +/** Receiver enable bit */ #define USART_CR1_RE_BIT 2 +/** Receiver wakeup bit */ #define USART_CR1_RWU_BIT 1 +/** Send break bit */ #define USART_CR1_SBK_BIT 0 +/** USART enable mask */ #define USART_CR1_UE BIT(USART_CR1_UE_BIT) +/** Word length mask */ #define USART_CR1_M BIT(USART_CR1_M_BIT) +/** Word length: 1 start bit, 8 data bits, n stop bit */ +#define USART_CR1_M_8N1 (0 << USART_CR1_M_BIT) +/** Word length: 1 start bit, 9 data bits, n stop bit */ +#define USART_CR1_M_9N1 (1 << USART_CR1_M_BIT) +/** Wakeup method mask */ #define USART_CR1_WAKE BIT(USART_CR1_WAKE_BIT) +/** Wakeup on idle line */ #define USART_CR1_WAKE_IDLE (0 << USART_CR1_WAKE_BIT) +/** Wakeup on address mark */ #define USART_CR1_WAKE_ADDR (1 << USART_CR1_WAKE_BIT) +/** Parity control enable mask */ #define USART_CR1_PCE BIT(USART_CR1_PCE_BIT) +/** Parity selection mask */ #define USART_CR1_PS BIT(USART_CR1_PS_BIT) +/** Parity selection: even parity */ #define USART_CR1_PS_EVEN (0 << USART_CR1_PS_BIT) +/** Parity selection: odd parity */ #define USART_CR1_PS_ODD (1 << USART_CR1_PS_BIT) +/** Parity error interrupt enable mask */ #define USART_CR1_PEIE BIT(USART_CR1_PEIE_BIT) +/** Transmit data register empty interrupt enable mask */ #define USART_CR1_TXEIE BIT(USART_CR1_TXEIE_BIT) +/** Transmission complete interrupt enable mask */ #define USART_CR1_TCIE BIT(USART_CR1_TCIE_BIT) +/** RXNE interrupt enable mask */ #define USART_CR1_RXNEIE BIT(USART_CR1_RXNEIE_BIT) +/** IDLE line interrupt enable mask */ #define USART_CR1_IDLEIE BIT(USART_CR1_IDLEIE_BIT) +/** Transmitter enable mask */ #define USART_CR1_TE BIT(USART_CR1_TE_BIT) +/** Receiver enable mask */ #define USART_CR1_RE BIT(USART_CR1_RE_BIT) +/** Receiver wakeup mask */ #define USART_CR1_RWU BIT(USART_CR1_RWU_BIT) +/** Receiver wakeup: receiver in active mode */ #define USART_CR1_RWU_ACTIVE (0 << USART_CR1_RWU_BIT) +/** Receiver wakeup: receiver in mute mode */ #define USART_CR1_RWU_MUTE (1 << USART_CR1_RWU_BIT) +/** Send break */ #define USART_CR1_SBK BIT(USART_CR1_SBK_BIT) /* Control register 2 */ +/** LIN mode enable bit */ #define USART_CR2_LINEN_BIT 14 +/** Clock enable bit */ #define USART_CR2_CLKEN_BIT 11 +/** Clock polarity bit */ #define USART_CR2_CPOL_BIT 10 +/** Clock phase bit */ #define USART_CR2_CPHA_BIT 9 +/** Last bit clock pulse bit */ #define USART_CR2_LBCL_BIT 8 +/** LIN break detection interrupt enable bit */ #define USART_CR2_LBDIE_BIT 6 +/** LIN break detection length bit */ #define USART_CR2_LBDL_BIT 5 +/** LIN mode enable mask */ #define USART_CR2_LINEN BIT(USART_CR2_LINEN_BIT) +/** STOP bits mask */ #define USART_CR2_STOP (0x3 << 12) +/** STOP bits: 1 stop bit */ #define USART_CR2_STOP_BITS_1 (0x0 << 12) -/* Not on UART4, UART5 */ +/** + * @brief STOP bits: 0.5 stop bits + * Not available on UART4, UART5. */ #define USART_CR2_STOP_BITS_POINT_5 (0x1 << 12) -/* Not on UART4, UART5 */ -#define USART_CR2_STOP_BITS_1_POINT_5 (0x3 << 12) +/** STOP bits: 2 stop bits */ #define USART_CR2_STOP_BITS_2 (0x2 << 12) +/** + * @brief STOP bits: 1.5 stop bits + * Not available on UART4, UART5. */ +#define USART_CR2_STOP_BITS_1_POINT_5 (0x3 << 12) +/** + * @brief Clock enable. + * Not available on UART4, UART5 */ #define USART_CR2_CLKEN BIT(USART_CR2_CLKEN_BIT) -/* Not on UART4, UART5 */ +/** + * @brief Clock polarity mask. + * Not available on UART4, UART5 */ #define USART_CR2_CPOL BIT(USART_CR2_CPOL_BIT) +/** Clock polarity: low */ #define USART_CR2_CPOL_LOW (0x0 << USART_CR2_CLKEN_BIT) +/** Clock polarity: high */ #define USART_CR2_CPOL_HIGH (0x1 << USART_CR2_CLKEN_BIT) -/* Not on UART4, UART5 */ +/** + * @brief Clock phase mask. + * Not available on UART4, UART5 */ #define USART_CR2_CPHA BIT(USART_CR2_CPHA_BIT) +/** + * @brief Clock phase: first + * First clock transition is the first data capture edge. */ #define USART_CR2_CPHA_FIRST (0x0 << USART_CR2_CPHA_BIT) +/** + * @brief Clock phase: second + * Second clock transition is the first data capture edge. */ #define USART_CR2_CPHA_SECOND (0x1 << USART_CR2_CPHA_BIT) -/* Not on UART4, UART5 */ +/** + * @brief Last bit clock pulse mask. + * + * When set, the last bit transmitted causes a clock pulse in + * synchronous mode. + * + * Not available on UART4, UART5 */ #define USART_CR2_LBCL BIT(USART_CR2_LBCL_BIT) +/** LIN break detection interrupt enable mask. */ #define USART_CR2_LBDIE BIT(USART_CR2_LBDIE_BIT) +/** LIN break detection length. */ #define USART_CR2_LBDL BIT(USART_CR2_LBDL_BIT) +/** LIN break detection length: 10 bits */ #define USART_CR2_LBDL_10_BIT (0 << USART_CR2_LBDL_BIT) +/** LIN break detection length: 11 bits */ #define USART_CR2_LBDL_11_BIT (1 << USART_CR2_LBDL_BIT) +/** + * @brief Address of the USART node + * This is useful during multiprocessor communication. */ #define USART_CR2_ADD 0xF /* Control register 3 */ +/** Clear to send interrupt enable bit */ #define USART_CR3_CTSIE_BIT 10 +/** Clear to send enable bit */ #define USART_CR3_CTSE_BIT 9 +/** Ready to send enable bit */ #define USART_CR3_RTSE_BIT 8 +/** DMA enable transmitter bit */ #define USART_CR3_DMAT_BIT 7 +/** DMA enable receiver bit */ #define USART_CR3_DMAR_BIT 6 +/** Smartcard mode enable bit */ #define USART_CR3_SCEN_BIT 5 +/** Smartcard NACK enable bit */ #define USART_CR3_NACK_BIT 4 +/** Half-duplex selection bit */ #define USART_CR3_HDSEL_BIT 3 +/** IrDA low power bit */ #define USART_CR3_IRLP_BIT 2 +/** IrDA mode enable bit */ #define USART_CR3_IREN_BIT 1 +/** Error interrupt enable bit */ #define USART_CR3_EIE_BIT 0 -/* Not on UART4, UART5 */ +/** + * @brief Clear to send interrupt enable + * Not available on UART4, UART5. */ #define USART_CR3_CTSIE BIT(USART_CR3_CTSIE_BIT) -/* Not on UART4, UART5 */ +/** + * @brief Clear to send enable + * Not available on UART4, UART5. */ #define USART_CR3_CTSE BIT(USART_CR3_CTSE_BIT) -/* Not on UART4, UART5 */ +/** + * @brief Ready to send enable + * Not available on UART4, UART5. */ #define USART_CR3_RTSE BIT(USART_CR3_RTSE_BIT) -/* Not on UART5 */ +/** + * @brief DMA enable transmitter + * Not available on UART5. */ #define USART_CR3_DMAT BIT(USART_CR3_DMAT_BIT) -/* Not on UART5 */ +/** + * @brief DMA enable receiver + * Not available on UART5. */ #define USART_CR3_DMAR BIT(USART_CR3_DMAR_BIT) -/* Not on UART4, UART5 */ +/** + * @brief Smartcard mode enable + * Not available on UART4, UART5. */ #define USART_CR3_SCEN BIT(USART_CR3_SCEN_BIT) -/* Not on UART4, UART5 */ +/** + * @brief Smartcard NACK enable + * Not available on UART4, UART5. */ #define USART_CR3_NACK BIT(USART_CR3_NACK_BIT) +/** + * @brief Half-duplex selection + * When set, single-wire half duplex mode is selected. + */ #define USART_CR3_HDSEL BIT(USART_CR3_HDSEL_BIT) +/** IrDA low power mode */ #define USART_CR3_IRLP BIT(USART_CR3_IRLP_BIT) -#define USART_CR3_IRLP_NORMAL (0 << USART_CR3_IRLP_BIT) -#define USART_CR3_IRLP_LOW_POWER (1 << USART_CR3_IRLP_BIT) +/** IrDA mode: normal */ +#define USART_CR3_IRLP_NORMAL (0U << USART_CR3_IRLP_BIT) +/** IrDA mode: low power */ +#define USART_CR3_IRLP_LOW_POWER (1U << USART_CR3_IRLP_BIT) +/** IrDA mode enable */ #define USART_CR3_IREN BIT(USART_CR3_IREN_BIT) +/** Error interrupt enable */ #define USART_CR3_EIE BIT(USART_CR3_EIE_BIT) /* Guard time and prescaler register */ -/* Not on UART4, UART5 */ +/** + * @brief Guard time value mask + * Used in Smartcard mode. Not available on UART4, UART5. */ #define USART_GTPR_GT (0xFF << 8) -/* Not on UART4, UART5 */ +/** + * @brief Prescaler value mask + * Restrictions on this value apply, depending on the USART mode. Not + * available on UART4, UART5. */ #define USART_GTPR_PSC 0xFF /* @@ -236,7 +383,8 @@ typedef struct usart_reg_map { typedef struct usart_dev { usart_reg_map *regs; /**< Register map */ ring_buffer *rb; /**< RX ring buffer */ - uint32 max_baud; /**< Maximum baud */ + uint32 max_baud; /**< @brief Deprecated. + * Maximum baud rate. */ uint8 rx_buf[USART_RX_BUF_SIZE]; /**< @brief Deprecated. * Actual RX buffer used by rb. * This field will be removed in @@ -245,16 +393,27 @@ typedef struct usart_dev { nvic_irq_num irq_num; /**< USART NVIC interrupt */ } usart_dev; -extern usart_dev *USART1; -extern usart_dev *USART2; -extern usart_dev *USART3; -#ifdef STM32_HIGH_DENSITY -extern usart_dev *UART4; -extern usart_dev *UART5; -#endif - void usart_init(usart_dev *dev); + +struct gpio_dev; /* forward declaration */ +/* FIXME [PRE 0.0.13] decide if flags are necessary */ +/** + * @brief Configure GPIOs for use as USART TX/RX. + * @param udev USART device to use + * @param rx_dev RX pin gpio_dev + * @param rx RX pin bit on rx_dev + * @param tx_dev TX pin gpio_dev + * @param tx TX pin bit on tx_dev + * @param flags Currently ignored + */ +extern void usart_config_gpios_async(usart_dev *udev, + struct gpio_dev *rx_dev, uint8 rx, + struct gpio_dev *tx_dev, uint8 tx, + unsigned flags); + +#define USART_USE_PCLK 0 void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud); + void usart_enable(usart_dev *dev); void usart_disable(usart_dev *dev); void usart_foreach(void (*fn)(usart_dev *dev)); @@ -333,4 +492,4 @@ static inline void usart_reset_rx(usart_dev *dev) { } // extern "C" #endif -#endif // _USART_H_ +#endif diff --git a/libmaple/usb.h b/libmaple/include/libmaple/usb.h index 94579ea..8555aca 100644 --- a/libmaple/usb.h +++ b/libmaple/include/libmaple/usb.h @@ -1,7 +1,7 @@ /****************************************************************************** * The MIT License * - * Copyright (c) 2010 LeafLabs LLC. + * Copyright (c) 2010, 2011 LeafLabs LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -28,16 +28,16 @@ * NOTE: This API is _unstable_ and will change drastically over time. */ -#ifndef _USB_H_ -#define _USB_H_ - -#include "libmaple_types.h" -#include "rcc.h" +#ifndef _LIBMAPLE_USB_H_ +#define _LIBMAPLE_USB_H_ #ifdef __cplusplus extern "C" { #endif +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> + #ifndef USB_ISR_MSK /* Handle CTRM, WKUPM, SUSPM, ERRM, SOFM, ESOFM, RESETM */ #define USB_ISR_MSK 0xBF00 diff --git a/libmaple/usb/usb_cdcacm.h b/libmaple/include/libmaple/usb_cdcacm.h index 8ca1c68..9d70758 100644 --- a/libmaple/usb/usb_cdcacm.h +++ b/libmaple/include/libmaple/usb_cdcacm.h @@ -25,15 +25,15 @@ *****************************************************************************/ /** - * @file usb_cdcacm.h + * @file libmaple/include/libmaple/usb_cdcacm.h * @brief USB CDC ACM (virtual serial terminal) support */ -#ifndef _USB_CDCACM_H_ -#define _USB_CDCACM_H_ +#ifndef _LIBMAPLE_USB_CDCACM_H_ +#define _LIBMAPLE_USB_CDCACM_H_ -#include "libmaple_types.h" -#include "gpio.h" +#include <libmaple/libmaple_types.h> +#include <libmaple/gpio.h> #ifdef __cplusplus extern "C" { diff --git a/libmaple/util.h b/libmaple/include/libmaple/util.h index 7b41769..5a70348 100644 --- a/libmaple/util.h +++ b/libmaple/include/libmaple/util.h @@ -25,30 +25,30 @@ *****************************************************************************/ /** - * @file util.h + * @file libmaple/include/libmaple/util.h * @brief Miscellaneous utility macros and procedures. */ -#include "libmaple_types.h" - -#ifndef _UTIL_H_ -#define _UTIL_H_ +#ifndef _LIBMAPLE_UTIL_H_ +#define _LIBMAPLE_UTIL_H_ #ifdef __cplusplus extern "C"{ #endif +#include <libmaple/libmaple_types.h> + /* * Bit manipulation */ -/** 1 << the bit number */ +/** 1UL shifted left by 'shift' */ #define BIT(shift) (1UL << (shift)) -/** Mask shifted left by 'shift' */ +/** 'Mask' shifted left by 'shift' */ #define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift)) /** Bits m to n of x */ #define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m))) -/** True if v is a power of two (1, 2, 4, 8, ...) */ +/** True iff v is a power of two (1, 2, 4, 8, ...) */ #define IS_POWER_OF_TWO(v) ((v) && !((v) & ((v) - 1))) /* diff --git a/libmaple/iwdg.c b/libmaple/iwdg.c index 63c1b2b..2456235 100644 --- a/libmaple/iwdg.c +++ b/libmaple/iwdg.c @@ -25,11 +25,11 @@ *****************************************************************************/ /** - * @file iwdg.c + * @file libmaple/iwdg.c * @brief Independent watchdog (IWDG) support */ -#include "iwdg.h" +#include <libmaple/iwdg.h> /** * @brief Initialise and start the watchdog diff --git a/libmaple/nvic.c b/libmaple/nvic.c index 345c850..fe7c7bc 100644 --- a/libmaple/nvic.c +++ b/libmaple/nvic.c @@ -25,13 +25,13 @@ *****************************************************************************/ /** - * @file nvic.c + * @file libmaple/nvic.c * @brief Nested vector interrupt controller support. */ -#include "nvic.h" -#include "scb.h" -#include "stm32.h" +#include <libmaple/nvic.h> +#include <libmaple/scb.h> +#include <libmaple/stm32.h> /** * @brief Set interrupt priority for an interrupt line @@ -46,7 +46,7 @@ */ void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) { if (irqn < 0) { - /* This interrupt is in the system handler block */ + /* This interrupt is in the system handler block */ SCB_BASE->SHP[((uint32)irqn & 0xF) - 4] = (priority & 0xF) << 4; } else { NVIC_BASE->IP[irqn] = (priority & 0xF) << 4; @@ -54,16 +54,12 @@ void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) { } /** - * @brief Initialize the NVIC - * @param vector_table_address Vector table base address. - * @param offset Offset from vector_table_address. Some restrictions - * apply to the use of nonzero offsets; see ST RM0008 - * and the ARM Cortex M3 Technical Reference Manual. + * @brief Initialize the NVIC, setting interrupts to a default priority. */ -void nvic_init(uint32 vector_table_address, uint32 offset) { +void nvic_init(uint32 address, uint32 offset) { uint32 i; - nvic_set_vector_table(vector_table_address, offset); + nvic_set_vector_table(address, offset); /* * Lower priority level for all peripheral interrupts to lowest @@ -78,10 +74,18 @@ void nvic_init(uint32 vector_table_address, uint32 offset) { } /** - * Reset the vector table address. + * @brief Set the vector table base address. + * + * For stand-alone products, the vector table base address is normally + * the start of Flash (0x08000000). + * + * @param address Vector table base address. + * @param offset Offset from address. Some restrictions apply to the + * use of nonzero offsets; see the ARM Cortex M3 + * Technical Reference Manual. */ -void nvic_set_vector_table(uint32 addr, uint32 offset) { - SCB_BASE->VTOR = addr | (offset & 0x1FFFFF80); +void nvic_set_vector_table(uint32 address, uint32 offset) { + SCB_BASE->VTOR = address | (offset & 0x1FFFFF80); } /** diff --git a/libmaple/pwr.c b/libmaple/pwr.c index ead8b64..3cf170f 100644 --- a/libmaple/pwr.c +++ b/libmaple/pwr.c @@ -25,12 +25,12 @@ *****************************************************************************/ /** - * @file pwr.c + * @file libmaple/pwr.c * @brief Power control (PWR) support. */ -#include "pwr.h" -#include "rcc.h" +#include <libmaple/pwr.h> +#include <libmaple/rcc.h> /** * Enables the power interface clock, and resets the power device. diff --git a/libmaple/rcc.c b/libmaple/rcc.c index 65abfb6..8e7d1ea 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,182 +26,144 @@ *****************************************************************************/ /** - * @file rcc.c - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. + * @file libmaple/rcc.c + * @brief Portable RCC routines. */ -#include "libmaple.h" -#include "flash.h" -#include "rcc.h" -#include "bitband.h" - -#define APB1 RCC_APB1 -#define APB2 RCC_APB2 -#define AHB RCC_AHB - -struct rcc_dev_info { - const rcc_clk_domain clk_domain; - const uint8 line_num; -}; - -/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset - * register bit numbers. */ -static const struct rcc_dev_info rcc_dev_table[] = { - [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, - [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, - [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, - [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, - [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, - [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, - [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, - [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, - [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, - [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, - [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, - [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 }, - [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, - [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, - [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, - [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, - [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, - [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, - [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, - [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, - [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, - [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, - [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, - [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, - [RCC_USB] = { .clk_domain = APB1, .line_num = 23}, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, - [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, - [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, - [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, - [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, - [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, - [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, - [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, - [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, - [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, - [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, -#endif -#ifdef STM32_XL_DENSITY - [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, - [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, - [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, - [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, - [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, - [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, -#endif -}; +#include <libmaple/rcc.h> + +#include "rcc_private.h" /** - * @brief Initialize the clock control system. Initializes the system - * clock source to use the PLL driven by an external oscillator - * @param sysclk_src system clock source, must be PLL - * @param pll_src pll clock source, must be HSE - * @param pll_mul pll multiplier + * @brief Get a peripheral's clock domain + * @param id Clock ID of the peripheral whose clock domain to return + * @return Clock source for the given clock ID */ -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul) { - uint32 cfgr = 0; - uint32 cr; - - /* Assume that we're going to clock the chip off the PLL, fed by - * the HSE */ - ASSERT(sysclk_src == RCC_CLKSRC_PLL && - pll_src == RCC_PLLSRC_HSE); - - RCC_BASE->CFGR = pll_src | pll_mul; - - /* Turn on the HSE */ - cr = RCC_BASE->CR; - cr |= RCC_CR_HSEON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_HSERDY)) - ; - - /* Now the PLL */ - cr |= RCC_CR_PLLON; - RCC_BASE->CR = cr; - while (!(RCC_BASE->CR & RCC_CR_PLLRDY)) - ; +rcc_clk_domain rcc_dev_clk(rcc_clk_id id) { + return rcc_dev_table[id].clk_domain; +} - /* Finally, let's switch over to the PLL */ +/** + * @brief Switch the clock used as the source of the system clock. + * + * After switching the source, this function blocks until the new + * clock source is in use. + * + * @param sysclk_src New system clock source. + * @see rcc_sysclk_src + */ +void rcc_switch_sysclk(rcc_sysclk_src sysclk_src) { + uint32 cfgr = RCC_BASE->CFGR; cfgr &= ~RCC_CFGR_SW; - cfgr |= RCC_CFGR_SW_PLL; + cfgr |= sysclk_src; + + /* Switch SYSCLK source. */ RCC_BASE->CFGR = cfgr; - while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) + + /* Wait for new source to come into use. */ + while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != (sysclk_src << 2)) ; } -/** - * @brief Turn on the clock line on a peripheral - * @param id Clock ID of the peripheral to turn on. +/* + * Turning clocks off and on, querying their status. */ -void rcc_clk_enable(rcc_clk_id id) { - static const __io uint32* enable_regs[] = { - [APB1] = &RCC_BASE->APB1ENR, - [APB2] = &RCC_BASE->APB2ENR, - [AHB] = &RCC_BASE->AHBENR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(enr, lnum, 1); + +/* IMPORTANT NOTE FOR IMPLEMENTORS: + * + * libmaple assumes that enum rcc_clk enumerators are two-byte + * values, stored in a uint16, in the following way: + * + * - The high-order byte is the byte offset (from RCC_BASE) of the register + * to touch when turning on or off the given clock. + * + * - The low-order byte is the bit in that register that turns the + * clock on or off. + * + * Example for STM32F1: Turning on the high-speed external clock (HSE) + * involves setting HSEON, bit 16, of RCC_CR. The high-order byte is + * then offsetof(struct rcc_reg_map, CR) = 0, and the low-order byte + * is 16. + * + * The corresponding value of RCC_CLK_HSE is thus (0 << 8) | 16 = 16. + * + * On all known STM32 series, this encoding has the property that + * adding one to the low byte also gives the bit to check to determine + * if the clock is ready. For example, on STM32F1, RCC_CR_HSERDY is + * bit 17. If that's not the case on your series, rcc_is_clk_ready() + * won't work for you. */ + +/* Returns the RCC register which controls the clock source. */ +static inline __io uint32* rcc_clk_reg(rcc_clk clock) { + return (__io uint32*)((__io uint8*)RCC_BASE + (clock >> 8)); +} + +/* Returns a mask in rcc_clk_reg(clock) to be used for turning the + * clock on and off */ +static inline uint32 rcc_clk_on_mask(rcc_clk clock) { + return 1 << (clock & 0xFF); +} + +/* Returns a mask in rcc_clk_reg(clock) to be used when checking the + * readiness of the clock. */ +static inline uint32 rcc_clk_ready_mask(rcc_clk clock) { + return rcc_clk_on_mask(clock) << 1; } /** - * @brief Reset a peripheral. - * @param id Clock ID of the peripheral to reset. + * @brief Turn on a clock source. + * + * After this routine exits, callers should ensure that the clock + * source is ready by waiting until rcc_is_clk_ready(clock) returns + * true. + * + * @param clock Clock to turn on. + * @see rcc_turn_off_clk() + * @see rcc_is_clk_ready() */ -void rcc_reset_dev(rcc_clk_id id) { - static const __io uint32* reset_regs[] = { - [APB1] = &RCC_BASE->APB1RSTR, - [APB2] = &RCC_BASE->APB2RSTR, - }; - - rcc_clk_domain clk_domain = rcc_dev_clk(id); - __io void* addr = (__io void*)reset_regs[clk_domain]; - uint8 lnum = rcc_dev_table[id].line_num; - - bb_peri_set_bit(addr, lnum, 1); - bb_peri_set_bit(addr, lnum, 0); +void rcc_turn_on_clk(rcc_clk clock) { + *rcc_clk_reg(clock) |= rcc_clk_on_mask(clock); } /** - * @brief Get a peripheral's clock domain - * @param id Clock ID of the peripheral whose clock domain to return - * @return Clock source for the given clock ID + * @brief Turn off a clock source. + * + * In certain configurations, certain clock sources cannot be safely + * turned off. (For example, the main PLL on STM32F1 devices cannot be + * turned off if it has been selected as the SYSCLK source). Consult + * the reference material for your MCU to ensure it is safe to call + * this function. + * + * @param clock Clock to turn off. + * @see rcc_turn_on_clk() + * @see rcc_is_clk_ready() */ -rcc_clk_domain rcc_dev_clk(rcc_clk_id id) { - return rcc_dev_table[id].clk_domain; +void rcc_turn_off_clk(rcc_clk clock) { + *rcc_clk_reg(clock) &= ~rcc_clk_on_mask(clock); } /** - * @brief Set the divider on a peripheral prescaler - * @param prescaler prescaler to set - * @param divider prescaler divider + * @brief Check if a clock is on. + * @param clock Clock to check. + * @return 1 if the clock is on, 0 if the clock is off. */ -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { - static const uint32 masks[] = { - [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, - [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, - [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, - [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, - [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, - }; +int rcc_is_clk_on(rcc_clk clock) { + return !!(*rcc_clk_reg(clock) & rcc_clk_on_mask(clock)); +} - uint32 cfgr = RCC_BASE->CFGR; - cfgr &= ~masks[prescaler]; - cfgr |= divider; - RCC_BASE->CFGR = cfgr; +/** + * @brief Check if a clock source is ready. + * + * In general, it is not safe to rely on a clock source unless this + * function returns nonzero. Also note that this function may return + * nonzero for a short period of time after a clock has been turned + * off. Consult the reference material for your MCU for more details. + * + * @param clock Clock whose readiness to check for. + * @return Nonzero if the clock is ready, zero otherwise. + * @see rcc_turn_on_clk() + * @see rcc_turn_off_clk() + */ +int rcc_is_clk_ready(rcc_clk clock) { + return (int)(*rcc_clk_reg(clock) & rcc_clk_ready_mask(clock)); } diff --git a/libmaple/rcc_private.h b/libmaple/rcc_private.h new file mode 100644 index 0000000..66eaf00 --- /dev/null +++ b/libmaple/rcc_private.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* + * RCC private header. + */ + +#ifndef _LIBMAPLE_PRIVATE_RCC_H_ +#define _LIBMAPLE_PRIVATE_RCC_H_ + +#include <libmaple/bitband.h> + +struct rcc_dev_info { + const rcc_clk_domain clk_domain; + const uint8 line_num; +}; + +extern const struct rcc_dev_info rcc_dev_table[]; + +static inline void rcc_do_clk_enable(__io uint32** enable_regs, + rcc_clk_id id) { + __io uint32 *enable_reg = enable_regs[rcc_dev_clk(id)]; + uint8 line_num = rcc_dev_table[id].line_num; + bb_peri_set_bit(enable_reg, line_num, 1); +} + +static inline void rcc_do_reset_dev(__io uint32** reset_regs, + rcc_clk_id id) { + __io uint32 *reset_reg = reset_regs[rcc_dev_clk(id)]; + uint8 line_num = rcc_dev_table[id].line_num; + bb_peri_set_bit(reset_reg, line_num, 1); + bb_peri_set_bit(reset_reg, line_num, 0); +} + +static inline void rcc_do_set_prescaler(const uint32 *masks, + rcc_prescaler prescaler, + uint32 divider) { + uint32 cfgr = RCC_BASE->CFGR; + cfgr &= ~masks[prescaler]; + cfgr |= divider; + RCC_BASE->CFGR = cfgr; +} + +#endif diff --git a/libmaple/rules.mk b/libmaple/rules.mk index 1ee611d..71979f0 100644 --- a/libmaple/rules.mk +++ b/libmaple/rules.mk @@ -3,43 +3,35 @@ sp := $(sp).x dirstack_$(sp) := $(d) d := $(dir) BUILDDIRS += $(BUILD_PATH)/$(d) -BUILDDIRS += $(BUILD_PATH)/$(d)/usb -BUILDDIRS += $(BUILD_PATH)/$(d)/usb/usb_lib -LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usb -I$(LIBMAPLE_PATH)/usb/usb_lib +LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH)/include -I$(LIBMAPLE_MODULE_SERIES)/include +LIBMAPLE_PRIVATE_INCLUDES := -I$(LIBMAPLE_PATH) # Local flags -CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) -Wall -Werror +CFLAGS_$(d) = $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror # Local rules and targets -cSRCS_$(d) := adc.c \ - bkp.c \ - dac.c \ - dma.c \ - exti.c \ - flash.c \ - fsmc.c \ - gpio.c \ - iwdg.c \ - nvic.c \ - pwr.c \ - i2c.c \ - rcc.c \ - spi.c \ - syscalls.c \ - systick.c \ - timer.c \ - usart.c \ - util.c \ - usb/usb.c \ - usb/usb_reg_map.c \ - usb/usb_cdcacm.c \ - usb/usb_lib/usb_core.c \ - usb/usb_lib/usb_init.c \ - usb/usb_lib/usb_mem.c \ - usb/usb_lib/usb_regs.c - +cSRCS_$(d) := adc.c +cSRCS_$(d) += dac.c +cSRCS_$(d) += dma.c +cSRCS_$(d) += exti.c +cSRCS_$(d) += flash.c +cSRCS_$(d) += gpio.c +cSRCS_$(d) += iwdg.c +cSRCS_$(d) += nvic.c +cSRCS_$(d) += pwr.c +cSRCS_$(d) += rcc.c +cSRCS_$(d) += spi.c +cSRCS_$(d) += systick.c +cSRCS_$(d) += timer.c +cSRCS_$(d) += usart.c +cSRCS_$(d) += usart_private.c +cSRCS_$(d) += util.c sSRCS_$(d) := exc.S +# I2C support must be ported to F2: +ifeq ($(MCU_SERIES),stm32f1) +cSRCS_$(d) += i2c.c +endif cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%) diff --git a/libmaple/spi.c b/libmaple/spi.c index 1c68529..194a82e 100644 --- a/libmaple/spi.c +++ b/libmaple/spi.c @@ -1,6 +1,7 @@ /****************************************************************************** * The MIT License * + * Copyright (c) 2011, 2012 LeafLabs, LLC. * Copyright (c) 2010 Perry Hung. * * Permission is hereby granted, free of charge, to any person @@ -25,48 +26,18 @@ *****************************************************************************/ /** - * @file spi.c + * @file libmaple/spi.c * @author Marti Bolivar <mbolivar@leaflabs.com> * @brief Serial Peripheral Interface (SPI) support. * Currently, there is no Integrated Interchip Sound (I2S) support. */ -#include "spi.h" -#include "bitband.h" +#include <libmaple/spi.h> +#include <libmaple/bitband.h> static void spi_reconfigure(spi_dev *dev, uint32 cr1_config); /* - * SPI devices - */ - -static spi_dev spi1 = { - .regs = SPI1_BASE, - .clk_id = RCC_SPI1, - .irq_num = NVIC_SPI1, -}; -/** SPI device 1 */ -spi_dev *SPI1 = &spi1; - -static spi_dev spi2 = { - .regs = SPI2_BASE, - .clk_id = RCC_SPI2, - .irq_num = NVIC_SPI2, -}; -/** SPI device 2 */ -spi_dev *SPI2 = &spi2; - -#ifdef STM32_HIGH_DENSITY -static spi_dev spi3 = { - .regs = SPI3_BASE, - .clk_id = RCC_SPI3, - .irq_num = NVIC_SPI3, -}; -/** SPI device 3 */ -spi_dev *SPI3 = &spi3; -#endif - -/* * SPI convenience routines */ @@ -80,37 +51,6 @@ void spi_init(spi_dev *dev) { } /** - * @brief Configure GPIO bit modes for use as a SPI port's pins. - * @param as_master If true, configure bits for use as a bus master. - * Otherwise, configure bits for use as slave. - * @param nss_dev NSS pin's GPIO device - * @param comm_dev SCK, MISO, MOSI pins' GPIO device - * @param nss_bit NSS pin's GPIO bit on nss_dev - * @param sck_bit SCK pin's GPIO bit on comm_dev - * @param miso_bit MISO pin's GPIO bit on comm_dev - * @param mosi_bit MOSI pin's GPIO bit on comm_dev - */ -void spi_gpio_cfg(uint8 as_master, - gpio_dev *nss_dev, - uint8 nss_bit, - gpio_dev *comm_dev, - uint8 sck_bit, - uint8 miso_bit, - uint8 mosi_bit) { - if (as_master) { - gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP); - } else { - gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING); - } -} - -/** * @brief Configure and enable a SPI device as bus master. * * The device's peripheral will be disabled before being reconfigured. @@ -165,18 +105,6 @@ uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { } /** - * @brief Call a function on each SPI port - * @param fn Function to call. - */ -void spi_foreach(void (*fn)(spi_dev*)) { - fn(SPI1); - fn(SPI2); -#ifdef STM32_HIGH_DENSITY - fn(SPI3); -#endif -} - -/** * @brief Enable a SPI peripheral * @param dev Device to enable */ @@ -234,7 +162,3 @@ static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { dev->regs->CR1 = cr1_config; spi_peripheral_enable(dev); } - -/* - * IRQ handlers (TODO) - */ diff --git a/libmaple/spi_private.h b/libmaple/spi_private.h new file mode 100644 index 0000000..f0e0bd1 --- /dev/null +++ b/libmaple/spi_private.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifndef _LIBMAPLE_SPI_PRIVATE_H_ +#define _LIBMAPLE_SPI_PRIVATE_H_ + +#define SPI_DEV(num) \ + { \ + .regs = SPI##num##_BASE, \ + .clk_id = RCC_SPI##num, \ + .irq_num = NVIC_SPI##num, \ + } + +#endif diff --git a/libmaple/stm32.h b/libmaple/stm32.h deleted file mode 100644 index 3b54dbc..0000000 --- a/libmaple/stm32.h +++ /dev/null @@ -1,191 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file stm32.h - * @brief STM32 chip-specific definitions - */ - -#ifndef _STM32_H_ -#define _STM32_H_ - -/* - * User-specific configuration. - * - * The #defines here depend upon how libmaple is used. Because of the - * potential for a mismatch between them and the actual libmaple - * usage, you should try to keep their number to an absolute minimum. - */ - -#ifdef __DOXYGEN_PREDEFINED_HACK - - /** @brief APB1 clock speed, in Hz. */ - #define STM32_PCLK1 - /** @brief APB2 clock speed, in Hz. */ - #define STM32_PCLK2 - - /** Deprecated. Use STM32_PCLK1 instead. */ - #define PCLK1 - /** Deprecated. Use STM32_PCLK2 instead. */ - #define PCLK2 - -#endif - -#ifndef STM32_PCLK1 -#define STM32_PCLK1 36000000U -#endif -#ifndef PCLK1 -#define PCLK1 STM32_PCLK1 -#endif -#if PCLK1 != STM32_PCLK1 -#error "(Deprecated) PCLK1 differs from STM32_PCLK1" -#endif - -#ifndef STM32_PCLK2 -#define STM32_PCLK2 72000000U -#endif -#ifndef PCLK2 -#define PCLK2 STM32_PCLK2 -#endif -#if PCLK2 != STM32_PCLK2 -#error "(Deprecated) PCLK2 differs from STM32_PCLK2" -#endif - -/* - * Density-specific configuration. - */ - -#ifdef __DOXYGEN_PREDEFINED_HACK - - /** - * @brief Number of interrupts in the NVIC. - * - * This define is automatically generated whenever the proper - * density is defined (currently, this is restricted to defining - * one of STM32_MEDIUM_DENSITY and STM32_HIGH_DENSITY). - */ - #define STM32_NR_INTERRUPTS - - /** Deprecated. Use STM32_NR_INTERRUPTS instead. */ - #define NR_INTERRUPTS - -#endif - -#ifdef STM32_MEDIUM_DENSITY - #define STM32_NR_INTERRUPTS 43 -#elif defined(STM32_HIGH_DENSITY) - #define STM32_NR_INTERRUPTS 60 -#else -#error "No STM32 board type defined!" -#endif - -#define NR_INTERRUPTS STM32_NR_INTERRUPTS - -/* - * MCU-specific configuration. - */ - -#ifdef __DOXYGEN_PREDEFINED_HACK - - /** - * Number of GPIO ports. - */ - #define STM32_NR_GPIO_PORTS - - /** - * @brief Multiplier to convert microseconds into loop iterations - * in delay_us(). - * - * @see delay_us() - */ - #define STM32_DELAY_US_MULT - - /** - * @brief Pointer to end of built-in SRAM. - * - * Points to the address which is 1 byte past the last valid - * SRAM address. - */ - #define STM32_SRAM_END - - /** Deprecated. Use STM32_NR_GPIO_PORTS instead. */ - #define NR_GPIO_PORTS - /** Deprecated. Use STM32_DELAY_US_MULT instead. */ - #define DELAY_US_MULT - -#endif - -#if defined(MCU_STM32F103RB) - /* e.g., LeafLabs Maple */ - - #define STM32_NR_GPIO_PORTS 4 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20005000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103ZE) - /* e.g., LeafLabs Maple Native */ - - #define STM32_NR_GPIO_PORTS 7 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103CB) - /* e.g., LeafLabs Maple Mini */ - - /* This STM32_NR_GPIO_PORTS value is not, strictly speaking, true. - * But only pins 0 and 1 exist, and they're used for OSC on the - * Mini, so we'll live with this for now. */ - #define STM32_NR_GPIO_PORTS 3 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20005000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#elif defined(MCU_STM32F103RE) - /* e.g., LeafLabs Maple RET6 edition */ - - #define STM32_NR_GPIO_PORTS 4 - #define STM32_DELAY_US_MULT 12 - #define STM32_SRAM_END ((void*)0x20010000) - - #define NR_GPIO_PORTS STM32_NR_GPIO_PORTS - #define DELAY_US_MULT STM32_DELAY_US_MULT - -#else - -#error "No MCU type specified. Add something like -DMCU_STM32F103RB " \ - "to your compiler arguments (probably in a Makefile)." - -#endif - -#endif /* _STM32_H_ */ diff --git a/libmaple/stm32_private.h b/libmaple/stm32_private.h new file mode 100644 index 0000000..427417a --- /dev/null +++ b/libmaple/stm32_private.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +#ifndef _LIBMAPLE_STM32_PRIVATE_H_ +#define _LIBMAPLE_STM32_PRIVATE_H_ + +typedef enum stm32_mem_block_purpose { + STM32_BLOCK_CODE, + STM32_BLOCK_SRAM, + STM32_BLOCK_PERIPH, + STM32_BLOCK_FSMC_1_2, + STM32_BLOCK_FSMC_3_4, + STM32_BLOCK_FSMC_REG, + STM32_BLOCK_UNUSED, + STM32_BLOCK_CORTEX_INTERNAL, +} stm32_mem_block_purpose; + +static inline stm32_mem_block_purpose stm32_block_purpose(void *addr) { + return (stm32_mem_block_purpose)((unsigned)addr >> 29); +} + +#endif diff --git a/libmaple/stm32f1/adc.c b/libmaple/stm32f1/adc.c new file mode 100644 index 0000000..ecfbc1c --- /dev/null +++ b/libmaple/stm32f1/adc.c @@ -0,0 +1,112 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/adc.c + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> + * @brief STM32F1 ADC support. + */ + +#include <libmaple/adc.h> +#include <libmaple/gpio.h> + +/* + * Devices + */ + +static adc_dev adc1 = { + .regs = ADC1_BASE, + .clk_id = RCC_ADC1, +}; +/** ADC1 device. */ +const adc_dev *ADC1 = &adc1; + +static adc_dev adc2 = { + .regs = ADC2_BASE, + .clk_id = RCC_ADC2, +}; +/** ADC2 device. */ +const adc_dev *ADC2 = &adc2; + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +static adc_dev adc3 = { + .regs = ADC3_BASE, + .clk_id = RCC_ADC3, +}; +/** ADC3 device. */ +const adc_dev *ADC3 = &adc3; +#endif + +/* + * STM32F1 routines + */ + +/** + * @brief Calibrate an ADC peripheral + * @param dev adc device + */ +void adc_calibrate(const adc_dev *dev) { + __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); + __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); + + *rstcal_bit = 1; + while (*rstcal_bit) + ; + + *cal_bit = 1; + while (*cal_bit) + ; +} + +/* + * Common routines + */ + +void adc_set_prescaler(adc_prescaler pre) { + rcc_set_prescaler(RCC_PRESCALER_ADC, (uint32)pre); +} + +void adc_foreach(void (*fn)(const adc_dev*)) { + fn(ADC1); + fn(ADC2); +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + fn(ADC3); +#endif +} + +void adc_config_gpio(const adc_dev *ignored, gpio_dev *gdev, uint8 bit) { + gpio_set_mode(gdev, bit, GPIO_INPUT_ANALOG); +} + +void adc_enable_single_swstart(const adc_dev *dev) { + adc_init(dev); + adc_set_extsel(dev, ADC_SWSTART); + adc_set_exttrig(dev, 1); + adc_enable(dev); + adc_calibrate(dev); +} diff --git a/libmaple/bkp.c b/libmaple/stm32f1/bkp.c index 7d1ad7f..f435ff1 100644 --- a/libmaple/bkp.c +++ b/libmaple/stm32f1/bkp.c @@ -25,14 +25,14 @@ *****************************************************************************/ /** - * @file bkp.c - * @brief Backup register support. + * @file libmaple/stm32f1/bkp.c + * @brief STM32F1 Backup register support. */ -#include "bkp.h" -#include "pwr.h" -#include "rcc.h" -#include "bitband.h" +#include <libmaple/bkp.h> +#include <libmaple/pwr.h> +#include <libmaple/rcc.h> +#include <libmaple/bitband.h> static inline __io uint32* data_register(uint8 reg); diff --git a/libmaple/stm32f1/dma.c b/libmaple/stm32f1/dma.c new file mode 100644 index 0000000..5364a04 --- /dev/null +++ b/libmaple/stm32f1/dma.c @@ -0,0 +1,412 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Michael Hope. + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/dma.c + * @author Marti Bolivar <mbolivar@leaflabs.com>; + * Original implementation by Michael Hope + * @brief STM32F1 DMA support. + */ + +#include <libmaple/dma.h> +#include <libmaple/bitband.h> + +/* Hack to ensure inlining in dma_irq_handler() */ +#define DMA_GET_HANDLER(dev, tube) (dev->handlers[tube - 1].handler) +#include "dma_private.h" + +/* + * Devices + */ + +static dma_dev dma1 = { + .regs = DMA1_BASE, + .clk_id = RCC_DMA1, + .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA_CH1 }, + { .handler = NULL, .irq_line = NVIC_DMA_CH2 }, + { .handler = NULL, .irq_line = NVIC_DMA_CH3 }, + { .handler = NULL, .irq_line = NVIC_DMA_CH4 }, + { .handler = NULL, .irq_line = NVIC_DMA_CH5 }, + { .handler = NULL, .irq_line = NVIC_DMA_CH6 }, + { .handler = NULL, .irq_line = NVIC_DMA_CH7 }}, +}; +/** STM32F1 DMA1 device */ +dma_dev *DMA1 = &dma1; + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +static dma_dev dma2 = { + .regs = DMA2_BASE, + .clk_id = RCC_DMA2, + .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 }, + { .handler = NULL, .irq_line = NVIC_DMA2_CH2 }, + { .handler = NULL, .irq_line = NVIC_DMA2_CH3 }, + { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }, + { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }}, /* !@#$ */ +}; +/** STM32F1 DMA2 device */ +dma_dev *DMA2 = &dma2; +#endif + +/* + * Auxiliary routines + */ + +/* Can channel serve cfg->tube_req_src? */ +static int cfg_req_ok(dma_channel channel, dma_tube_config *cfg) { + return (cfg->tube_req_src & 0x7) == channel; +} + +/* Can dev serve cfg->tube_req_src? */ +static int cfg_dev_ok(dma_dev *dev, dma_tube_config *cfg) { + return (rcc_clk_id)(cfg->tube_req_src >> 3) == dev->clk_id; +} + +/* Is addr acceptable for use as DMA src/dst? */ +static int cfg_mem_ok(__io void *addr) { + enum dma_atype atype = _dma_addr_type(addr); + return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER; +} + +/* Is the direction implied by src->dst supported? */ +static int cfg_dir_ok(dma_tube_config *cfg) { + /* We can't do peripheral->peripheral transfers. */ + return ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) || + (_dma_addr_type(cfg->tube_dst) == DMA_ATYPE_MEM)); +} + +static int preconfig_check(dma_dev *dev, dma_channel channel, + dma_tube_config *cfg) { + if (!cfg_req_ok(channel, cfg)) { + return -DMA_TUBE_CFG_EREQ; + } + if (cfg->tube_nr_xfers > 65535) { + return -DMA_TUBE_CFG_ENDATA; + } + if (!cfg_dev_ok(dev, cfg)) { + return -DMA_TUBE_CFG_EDEV; + } + if (!cfg_mem_ok(cfg->tube_src)) { + return -DMA_TUBE_CFG_ESRC; + } + if (!cfg_mem_ok(cfg->tube_dst)) { + return -DMA_TUBE_CFG_EDST; + } + if (!cfg_dir_ok(cfg)) { + return -DMA_TUBE_CFG_EDIR; + } + return DMA_TUBE_CFG_SUCCESS; +} + +static inline void set_ccr(dma_tube_reg_map *chregs, + dma_xfer_size msize, int minc, + dma_xfer_size psize, int pinc, + uint32 other_flags) { + chregs->CCR = ((msize << 10) | (psize << 8) | + (minc ? DMA_CCR_MINC : 0) | (pinc ? DMA_CCR_PINC : 0) | + other_flags); +} + +static inline uint32 cfg_ccr_flags(unsigned tube_flags) { + /* DMA_CFG_SRC_INC and DMA_CFG_DST_INC are special */ + return tube_flags & ~(DMA_CFG_SRC_INC | DMA_CFG_DST_INC); +} + +/* Configure chregs according to cfg, where cfg->tube_dst is peripheral. */ +static int config_to_per(dma_tube_reg_map *chregs, dma_tube_config *cfg) { + /* Check that ->tube_src is memory (if it's anything else, we + * shouldn't have been called). */ + ASSERT(_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM); + + set_ccr(chregs, + cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC, + cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC, + (cfg_ccr_flags(cfg->tube_flags) | DMA_CCR_DIR_FROM_MEM)); + chregs->CMAR = (uint32)cfg->tube_src; + chregs->CPAR = (uint32)cfg->tube_dst; + return DMA_TUBE_CFG_SUCCESS; +} + +/* Configure chregs according to cfg, where cfg->tube_dst is memory. */ +static int config_to_mem(dma_tube_reg_map *chregs, dma_tube_config *cfg) { + uint32 mem2mem; + + if ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) && + (cfg->tube_flags & DMA_CFG_CIRC)) { + /* Can't do mem-to-mem and circular mode */ + return -DMA_TUBE_CFG_ECFG; + } + + mem2mem = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ? + DMA_CCR_MEM2MEM : 0); + set_ccr(chregs, + cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC, + cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC, + (cfg_ccr_flags(cfg->tube_flags) | + DMA_CCR_DIR_FROM_PER | + mem2mem)); + chregs->CNDTR = cfg->tube_nr_xfers; + chregs->CMAR = (uint32)cfg->tube_dst; + chregs->CPAR = (uint32)cfg->tube_src; + return DMA_TUBE_CFG_SUCCESS; +} + +/* + * Routines + */ + +int dma_tube_cfg(dma_dev *dev, dma_channel channel, dma_tube_config *cfg) { + dma_tube_reg_map *chregs; + int ret = preconfig_check(dev, channel, cfg); + + if (ret < 0) { + return ret; + } + + dma_disable(dev, channel); /* Must disable before reconfiguring */ + dma_clear_isr_bits(dev, channel); /* For sanity and consistency + * with STM32F2. */ + + chregs = dma_tube_regs(dev, channel); + switch (_dma_addr_type(cfg->tube_dst)) { + case DMA_ATYPE_PER: + ret = config_to_per(chregs, cfg); + break; + case DMA_ATYPE_MEM: + ret = config_to_mem(chregs, cfg); + break; + default: + /* Can't happen */ + ASSERT(0); + return -DMA_TUBE_CFG_ECFG; + } + if (ret < 0) { + return ret; + } + chregs->CNDTR = cfg->tube_nr_xfers; + return DMA_TUBE_CFG_SUCCESS; +} + +void dma_set_priority(dma_dev *dev, + dma_channel channel, + dma_priority priority) { + dma_channel_reg_map *channel_regs; + uint32 ccr; + + ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); + + channel_regs = dma_channel_regs(dev, channel); + ccr = channel_regs->CCR; + ccr &= ~DMA_CCR_PL; + ccr |= (priority << 12); + channel_regs->CCR = ccr; +} + +void dma_set_num_transfers(dma_dev *dev, + dma_channel channel, + uint16 num_transfers) { + dma_channel_reg_map *channel_regs; + + ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); + + channel_regs = dma_channel_regs(dev, channel); + channel_regs->CNDTR = num_transfers; +} + +void dma_attach_interrupt(dma_dev *dev, dma_channel channel, + void (*handler)(void)) { + DMA_GET_HANDLER(dev, channel) = handler; + nvic_irq_enable(dev->handlers[channel - 1].irq_line); +} + +void dma_detach_interrupt(dma_dev *dev, dma_channel channel) { + /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */ + dma_channel_regs(dev, channel)->CCR &= ~0xF; + DMA_GET_HANDLER(dev, channel) = NULL; +} + +void dma_enable(dma_dev *dev, dma_channel channel) { + dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); + bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1); +} + +void dma_disable(dma_dev *dev, dma_channel channel) { + dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); + bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); +} + +dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { + /* Grab and clear the ISR bits. */ + uint8 status_bits = dma_get_isr_bits(dev, channel); + dma_clear_isr_bits(dev, channel); + + /* If the channel global interrupt flag is cleared, then + * something's very wrong. */ + ASSERT(status_bits & 0x1); + /* If GIF is set, then some other flag should be set, barring + * something unexpected (e.g. the user making an unforeseen IFCR + * write). */ + ASSERT(status_bits != 0x1); + + /* ISR flags get set even if the corresponding interrupt enable + * bits in the channel's configuration register are cleared, so we + * can't use a switch here. + * + * Don't change the order of these if statements. */ + if (status_bits & 0x8) { + return DMA_TRANSFER_ERROR; + } else if (status_bits & 0x2) { + return DMA_TRANSFER_COMPLETE; + } else if (status_bits & 0x4) { + return DMA_TRANSFER_HALF_COMPLETE; + } + + /* If we get here, one of our assumptions has been violated, but + * the debug level is too low for the above ASSERTs() to have had + * any effect. In order to fail fast, mimic the DMA controller's + * behavior when an error occurs. */ + dma_disable(dev, channel); + return DMA_TRANSFER_ERROR; +} + +void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { + dma_channel_reg_map *chan_regs; + + ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); + + chan_regs = dma_channel_regs(dev, channel); + chan_regs->CMAR = (uint32)addr; +} + +void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { + dma_channel_reg_map *chan_regs; + + ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); + + chan_regs = dma_channel_regs(dev, channel); + chan_regs->CPAR = (uint32)addr; +} + +/** + * @brief Deprecated. Use dma_tube_cfg() instead. + * + * Set up a DMA transfer. + * + * The channel will be disabled before being reconfigured. The + * transfer will have low priority by default. You may choose another + * priority before the transfer begins using dma_set_priority(), as + * well as performing any other configuration you desire. When the + * channel is configured to your liking, enable it using dma_enable(). + * + * @param dev DMA device. + * @param channel DMA channel. + * @param peripheral_address Base address of peripheral data register + * involved in the transfer. + * @param peripheral_size Peripheral data transfer size. + * @param memory_address Base memory address involved in the transfer. + * @param memory_size Memory data transfer size. + * @param mode Logical OR of dma_mode_flags + * + * @see dma_tube_cfg() + * + * @sideeffect Disables the given DMA channel. + * @see dma_xfer_size + * @see dma_mode_flags + * @see dma_set_num_transfers() + * @see dma_set_priority() + * @see dma_attach_interrupt() + * @see dma_enable() + */ +__deprecated +void dma_setup_transfer(dma_dev *dev, + dma_channel channel, + __io void *peripheral_address, + dma_xfer_size peripheral_size, + __io void *memory_address, + dma_xfer_size memory_size, + uint32 mode) { + dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel); + + dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */ + channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode; + channel_regs->CMAR = (uint32)memory_address; + channel_regs->CPAR = (uint32)peripheral_address; +} + +/* + * IRQ handlers + */ + +void __irq_dma1_channel1(void) { + dma_irq_handler(DMA1, DMA_CH1); +} + +void __irq_dma1_channel2(void) { + dma_irq_handler(DMA1, DMA_CH2); +} + +void __irq_dma1_channel3(void) { + dma_irq_handler(DMA1, DMA_CH3); +} + +void __irq_dma1_channel4(void) { + dma_irq_handler(DMA1, DMA_CH4); +} + +void __irq_dma1_channel5(void) { + dma_irq_handler(DMA1, DMA_CH5); +} + +void __irq_dma1_channel6(void) { + dma_irq_handler(DMA1, DMA_CH6); +} + +void __irq_dma1_channel7(void) { + dma_irq_handler(DMA1, DMA_CH7); +} + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +void __irq_dma2_channel1(void) { + dma_irq_handler(DMA2, DMA_CH1); +} + +void __irq_dma2_channel2(void) { + dma_irq_handler(DMA2, DMA_CH2); +} + +void __irq_dma2_channel3(void) { + dma_irq_handler(DMA2, DMA_CH3); +} + +void __irq_dma2_channel4_5(void) { + if ((DMA2_BASE->CCR4 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF4)) { + dma_irq_handler(DMA2, DMA_CH4); + } + if ((DMA2_BASE->CCR5 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF5)) { + dma_irq_handler(DMA2, DMA_CH5); + } +} +#endif diff --git a/libmaple/stm32f1/exti.c b/libmaple/stm32f1/exti.c new file mode 100644 index 0000000..b9ff401 --- /dev/null +++ b/libmaple/stm32f1/exti.c @@ -0,0 +1,32 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +#include <libmaple/gpio.h> +#include "exti_private.h" + +void exti_select(exti_num num, exti_cfg port) { + exti_do_select(&AFIO_BASE->EXTICR1 + num / 4, num, port); +} diff --git a/libmaple/fsmc.c b/libmaple/stm32f1/fsmc.c index 06ca7df..210f0be 100644 --- a/libmaple/fsmc.c +++ b/libmaple/stm32f1/fsmc.c @@ -1,6 +1,7 @@ /****************************************************************************** * The MIT License * + * Copyright (c) 2012 LeafLabs, LLC. * Copyright (c) 2010 Bryan Newbold. * * Permission is hereby granted, free of charge, to any person @@ -25,18 +26,19 @@ *****************************************************************************/ /** - * @file fsmc.c - * @brief Flexible static memory controller support. + * @file libmaple/stm32f1/fsmc.c + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Bryan Newbold <bnewbold@robocracy.org> + * @brief STM32F1 FSMC support. */ -#include "fsmc.h" -#include "gpio.h" +#include <libmaple/stm32.h> -#ifdef STM32_HIGH_DENSITY +#if STM32_HAVE_FSMC /* Don't try building the rest for MCUs without FSMC */ + +#include <libmaple/fsmc.h> +#include <libmaple/gpio.h> -/** - * Configure FSMC GPIOs for use with SRAM. - */ void fsmc_sram_init_gpios(void) { /* Data lines... */ gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP); @@ -90,4 +92,4 @@ void fsmc_sram_init_gpios(void) { gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1 } -#endif /* STM32_HIGH_DENSITY */ +#endif /* STM32_HAVE_FSMC */ diff --git a/libmaple/stm32f1/gpio.c b/libmaple/stm32f1/gpio.c new file mode 100644 index 0000000..4b596e9 --- /dev/null +++ b/libmaple/stm32f1/gpio.c @@ -0,0 +1,166 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/gpio.c + * @brief STM32F1 GPIO support. + */ + +#include <libmaple/gpio.h> +#include <libmaple/rcc.h> + +/* + * GPIO devices + */ + +gpio_dev gpioa = { + .regs = GPIOA_BASE, + .clk_id = RCC_GPIOA, + .exti_port = EXTI_PA, +}; +/** GPIO port A device. */ +gpio_dev* const GPIOA = &gpioa; + +gpio_dev gpiob = { + .regs = GPIOB_BASE, + .clk_id = RCC_GPIOB, + .exti_port = EXTI_PB, +}; +/** GPIO port B device. */ +gpio_dev* const GPIOB = &gpiob; + +gpio_dev gpioc = { + .regs = GPIOC_BASE, + .clk_id = RCC_GPIOC, + .exti_port = EXTI_PC, +}; +/** GPIO port C device. */ +gpio_dev* const GPIOC = &gpioc; + +gpio_dev gpiod = { + .regs = GPIOD_BASE, + .clk_id = RCC_GPIOD, + .exti_port = EXTI_PD, +}; +/** GPIO port D device. */ +gpio_dev* const GPIOD = &gpiod; + +#ifdef STM32_HIGH_DENSITY +gpio_dev gpioe = { + .regs = GPIOE_BASE, + .clk_id = RCC_GPIOE, + .exti_port = EXTI_PE, +}; +/** GPIO port E device. */ +gpio_dev* const GPIOE = &gpioe; + +gpio_dev gpiof = { + .regs = GPIOF_BASE, + .clk_id = RCC_GPIOF, + .exti_port = EXTI_PF, +}; +/** GPIO port F device. */ +gpio_dev* const GPIOF = &gpiof; + +gpio_dev gpiog = { + .regs = GPIOG_BASE, + .clk_id = RCC_GPIOG, + .exti_port = EXTI_PG, +}; +/** GPIO port G device. */ +gpio_dev* const GPIOG = &gpiog; +#endif + +/* + * GPIO routines + */ + +/** + * Initialize and reset all available GPIO devices. + */ +void gpio_init_all(void) { + gpio_init(GPIOA); + gpio_init(GPIOB); + gpio_init(GPIOC); + gpio_init(GPIOD); +#ifdef STM32_HIGH_DENSITY + gpio_init(GPIOE); + gpio_init(GPIOF); + gpio_init(GPIOG); +#endif +} + +/** + * Set the mode of a GPIO pin. + * + * @param dev GPIO device. + * @param pin Pin on the device whose mode to set, 0--15. + * @param mode General purpose or alternate function mode to set the pin to. + * @see gpio_pin_mode + */ +void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { + gpio_reg_map *regs = dev->regs; + __io uint32 *cr = ®s->CRL + (pin >> 3); + uint32 shift = (pin & 0x7) * 4; + uint32 tmp = *cr; + + tmp &= ~(0xF << shift); + tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; + *cr = tmp; + + if (mode == GPIO_INPUT_PD) { + regs->ODR &= ~(1U << pin); + } else if (mode == GPIO_INPUT_PU) { + regs->ODR |= (1U << pin); + } +} + +/* + * AFIO + */ + +/** + * @brief Initialize the AFIO clock, and reset the AFIO registers. + */ +void afio_init(void) { + rcc_clk_enable(RCC_AFIO); + rcc_reset_dev(RCC_AFIO); +} + +#define AFIO_EXTI_SEL_MASK 0xF + +/** + * @brief Perform an alternate function remap. + * @param remapping Remapping to perform. + */ +void afio_remap(afio_remap_peripheral remapping) { + if (remapping & AFIO_REMAP_USE_MAPR2) { + remapping &= ~AFIO_REMAP_USE_MAPR2; + AFIO_BASE->MAPR2 |= remapping; + } else { + AFIO_BASE->MAPR |= remapping; + } +} diff --git a/libmaple/stm32f1/i2c.c b/libmaple/stm32f1/i2c.c new file mode 100644 index 0000000..8439793 --- /dev/null +++ b/libmaple/stm32f1/i2c.c @@ -0,0 +1,129 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/i2c.c + * @brief STM32F1 I2C support + */ + +#include "i2c_private.h" +#include <libmaple/i2c.h> + +/* + * Devices + */ + +static i2c_dev i2c1 = I2C_DEV_OLD(1, &gpiob, 7, 6); +static i2c_dev i2c2 = I2C_DEV_OLD(2, &gpiob, 11, 10); + +/** STM32F1 I2C device 1 */ +i2c_dev* const I2C1 = &i2c1; +/** STM32F1 I2C device 2 */ +i2c_dev* const I2C2 = &i2c2; + +/* + * Routines + */ + +static int i2c1_wants_remap(const i2c_dev *dev) { + /* Check if we've got I2C1 configured for SDA/SCL remap on PB9/PB8 */ + return (dev->clk_id == RCC_I2C1) && + (scl_port(dev)->clk_id == RCC_GPIOB) && + (sda_port(dev)->clk_id == RCC_GPIOB) && + (dev->sda_pin == 9) && + (dev->scl_pin == 8); +} + +void i2c_config_gpios(const i2c_dev *dev) { + if (i2c1_wants_remap(dev)) { + afio_remap(AFIO_REMAP_I2C1); + } + gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_AF_OUTPUT_OD); + gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_AF_OUTPUT_OD); +} + +void i2c_master_release_bus(const i2c_dev *dev) { + gpio_write_bit(scl_port(dev), dev->scl_pin, 1); + gpio_write_bit(sda_port(dev), dev->sda_pin, 1); + gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_OUTPUT_OD); + gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_OUTPUT_OD); +} + +/* + * IRQ handlers + */ + +void __irq_i2c1_ev(void) { + _i2c_irq_handler(I2C1); +} + +void __irq_i2c2_ev(void) { + _i2c_irq_handler(I2C2); +} + +void __irq_i2c1_er(void) { + _i2c_irq_error_handler(I2C1); +} + +void __irq_i2c2_er(void) { + _i2c_irq_error_handler(I2C2); +} + +/* + * Internal APIs + */ + +void _i2c_irq_priority_fixup(i2c_dev *dev) { + /* + * Important STM32 Errata: + * + * See STM32F10xx8 and STM32F10xxB Errata sheet (Doc ID 14574 Rev 8), + * Section 2.11.1, 2.11.2. + * + * 2.11.1: + * When the EV7, EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events are not + * managed before the current byte is being transferred, problems may be + * encountered such as receiving an extra byte, reading the same data twice + * or missing data. + * + * 2.11.2: + * In Master Receiver mode, when closing the communication using + * method 2, the content of the last read data can be corrupted. + * + * If the user software is not able to read the data N-1 before the STOP + * condition is generated on the bus, the content of the shift register + * (data N) will be corrupted. (data N is shifted 1-bit to the left). + * + * ---------------------------------------------------------------------- + * + * In order to ensure that events are not missed, the i2c interrupt must + * not be preempted. We set the i2c interrupt priority to be the highest + * interrupt in the system (priority level 0). All other interrupts have + * been initialized to priority level 16. See nvic_init(). + */ + nvic_irq_set_priority(dev->ev_nvic_line, 0); + nvic_irq_set_priority(dev->er_nvic_line, 0); +} diff --git a/libmaple/stm32f1/include/series/adc.h b/libmaple/stm32f1/include/series/adc.h new file mode 100644 index 0000000..774c97c --- /dev/null +++ b/libmaple/stm32f1/include/series/adc.h @@ -0,0 +1,254 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/adc.h + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> + * @brief STM32F1 ADC header. + */ + +#ifndef _LIBMAPLE_STM32F1_ADC_H_ +#define _LIBMAPLE_STM32F1_ADC_H_ + +#include <libmaple/bitband.h> +#include <libmaple/libmaple_types.h> +#include <libmaple/rcc.h> /* For the prescalers */ + +/* + * Devices + */ + +extern const struct adc_dev *ADC1; +extern const struct adc_dev *ADC2; +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +extern const struct adc_dev *ADC3; +#endif + +/* + * Register map base pointers + */ + +/** ADC1 register map base pointer. */ +#define ADC1_BASE ((struct adc_reg_map*)0x40012400) +/** ADC2 register map base pointer. */ +#define ADC2_BASE ((struct adc_reg_map*)0x40012800) +/** ADC3 register map base pointer. */ +#define ADC3_BASE ((struct adc_reg_map*)0x40013C00) + +/* + * Register bit definitions + */ + +/* Control register 2 */ + +#define ADC_CR2_ADON_BIT 0 +#define ADC_CR2_CONT_BIT 1 +#define ADC_CR2_CAL_BIT 2 +#define ADC_CR2_RSTCAL_BIT 3 +#define ADC_CR2_DMA_BIT 8 +#define ADC_CR2_ALIGN_BIT 11 +#define ADC_CR2_JEXTTRIG_BIT 15 +#define ADC_CR2_EXTTRIG_BIT 20 +#define ADC_CR2_JSWSTART_BIT 21 +#define ADC_CR2_SWSTART_BIT 22 +#define ADC_CR2_TSEREFE_BIT 23 + +#define ADC_CR2_ADON (1U << ADC_CR2_ADON_BIT) +#define ADC_CR2_CONT (1U << ADC_CR2_CONT_BIT) +#define ADC_CR2_CAL (1U << ADC_CR2_CAL_BIT) +#define ADC_CR2_RSTCAL (1U << ADC_CR2_RSTCAL_BIT) +#define ADC_CR2_DMA (1U << ADC_CR2_DMA_BIT) +#define ADC_CR2_ALIGN (1U << ADC_CR2_ALIGN_BIT) +#define ADC_CR2_JEXTSEL 0x7000 +#define ADC_CR2_JEXTTRIG (1U << ADC_CR2_JEXTTRIG_BIT) +#define ADC_CR2_EXTSEL 0xE0000 +#define ADC_CR2_EXTTRIG (1U << ADC_CR2_EXTTRIG_BIT) +#define ADC_CR2_JSWSTART (1U << ADC_CR2_JSWSTART_BIT) +#define ADC_CR2_SWSTART (1U << ADC_CR2_SWSTART_BIT) +#define ADC_CR2_TSEREFE (1U << ADC_CR2_TSEREFE_BIT) + +/* + * Other types + */ + +/** + * @brief STM32F1 external event selectors for regular group + * conversion. + * + * Some external events are only available on ADCs 1 and 2, others + * only on ADC3, while others are available on all three ADCs. + * Additionally, some events are only available on high- and + * XL-density STM32F1 MCUs, as they use peripherals only available on + * those MCU densities. + * + * For ease of use, each event selector is given along with the ADCs + * it's available on, along with any other availability restrictions. + * + * @see adc_set_extsel() + */ +typedef enum adc_extsel_event { + /* TODO: Smarten this up a bit, as follows. + * + * The EXTSEL bits on F1 are a little brain-damaged in that the + * TIM8 TRGO event has different bits depending on whether you're + * using ADC1/2 or ADC3. We route around this by declaring two + * enumerators, ADC_EXT_EV_ADC12_TIM8_TRGO and + * ADC_EXT_EV_ADC3_TIM8_TRGO. + * + * The right thing to do is to provide a single + * ADC_EXT_EV_TIM8_TRGO enumerator and override adc_set_extsel on + * STM32F1 to handle this situation correctly. We can do that + * later, though, and change the per-ADC enumerator values to + * ADC_EXT_EV_TIM8_TRGO to preserve compatibility. */ + + /* ADC1 and ADC2 only: */ + ADC_EXT_EV_TIM1_CC1 = 0x00000, /**< ADC1, ADC2: Timer 1 CC1 event */ + ADC_EXT_EV_TIM1_CC2 = 0x20000, /**< ADC1, ADC2: Timer 1 CC2 event */ + ADC_EXT_EV_TIM2_CC2 = 0x60000, /**< ADC1, ADC2: Timer 2 CC2 event */ + ADC_EXT_EV_TIM3_TRGO = 0x80000, /**< ADC1, ADC2: Timer 3 TRGO event */ + ADC_EXT_EV_TIM4_CC4 = 0xA0000, /**< ADC1, ADC2: Timer 4 CC4 event */ + ADC_EXT_EV_EXTI11 = 0xC0000, /**< ADC1, ADC2: EXTI11 event */ + + /* Common: */ + ADC_EXT_EV_TIM1_CC3 = 0x40000, /**< ADC1, ADC2, ADC3: Timer 1 CC3 event */ + ADC_EXT_EV_SWSTART = 0xE0000, /**< ADC1, ADC2, ADC3: Software start */ + + /* HD only: */ + ADC_EXT_EV_TIM3_CC1 = 0x00000, /**< + * ADC3: Timer 3 CC1 event + * Availability: high- and XL-density. */ + ADC_EXT_EV_TIM2_CC3 = 0x20000, /**< + * ADC3: Timer 2 CC3 event + * Availability: high- and XL-density. */ + ADC_EXT_EV_TIM8_CC1 = 0x60000, /**< + * ADC3: Timer 8 CC1 event + * Availability: high- and XL-density. */ + ADC_EXT_EV_ADC3_TIM8_TRGO = 0x80000, /**< + * ADC3: Timer 8 TRGO event + * Availability: high- and XL-density. */ + ADC_EXT_EV_TIM5_CC1 = 0xA0000, /**< + * ADC3: Timer 5 CC1 event + * Availability: high- and XL-density. */ + ADC_EXT_EV_ADC12_TIM8_TRGO = 0xC0000, /**< + * ADC1, ADC2: Timer 8 TRGO event + * Availability: high- and XL-density. */ + ADC_EXT_EV_TIM5_CC3 = 0xC0000, /**< + * ADC3: Timer 5 CC3 event + * Availability: high- and XL-density. */ +} adc_extsel_event; + +/* We'll keep these old adc_extsel_event enumerators around for a + * while, for backwards compatibility: */ +/** Deprecated. Use ADC_EXT_EV_TIM1_CC1 instead. */ +#define ADC_ADC12_TIM1_CC1 ADC_EXT_EV_TIM1_CC1 +/** Deprecated. Use ADC_EXT_EV_TIM1_CC2 instead. */ +#define ADC_ADC12_TIM1_CC2 ADC_EXT_EV_TIM1_CC2 +/** Deprecated. Use ADC_EXT_EV_TIM1_CC3 instead. */ +#define ADC_ADC12_TIM1_CC3 ADC_EXT_EV_TIM1_CC3 +/** Deprecated. Use ADC_EXT_EV_TIM2_CC2 instead. */ +#define ADC_ADC12_TIM2_CC2 ADC_EXT_EV_TIM2_CC2 +/** Deprecated. Use ADC_EXT_EV_TIM3_TRGO instead. */ +#define ADC_ADC12_TIM3_TRGO ADC_EXT_EV_TIM3_TRGO +/** Deprecated. Use ADC_EXT_EV_TIM4_CC4 instead. */ +#define ADC_ADC12_TIM4_CC4 ADC_EXT_EV_TIM4_CC4 +/** Deprecated. Use ADC_EXT_EV_EXTI11 instead. */ +#define ADC_ADC12_EXTI11 ADC_EXT_EV_EXTI11 +/** Deprecated. Use ADC_EXT_EV_ADC12_TIM8_TRGO instead. */ +#define ADC_ADC12_TIM8_TRGO ADC_EXT_EV_ADC12_TIM8_TRGO +/** Deprecated. Use ADC_EXT_EV_SWSTART instead. */ +#define ADC_ADC12_SWSTART ADC_EXT_EV_SWSTART +/** Deprecated. Use ADC_EXT_EV_TIM1_CC1 instead. */ +#define ADC_ADC3_TIM3_CC1 ADC_EXT_EV_TIM1_CC1 +/** Deprecated. Use ADC_EXT_EV_TIM1_CC2 instead. */ +#define ADC_ADC3_TIM2_CC3 ADC_EXT_EV_TIM1_CC2 +/** Deprecated. Use ADC_EXT_EV_TIM1_CC3 instead. */ +#define ADC_ADC3_TIM1_CC3 ADC_EXT_EV_TIM1_CC3 +/** Deprecated. Use ADC_EXT_EV_TIM2_CC2 instead. */ +#define ADC_ADC3_TIM8_CC1 ADC_EXT_EV_TIM2_CC2 +/** Deprecated. Use ADC_EXT_EV_TIM3_TRGO instead. */ +#define ADC_ADC3_TIM8_TRGO ADC_EXT_EV_TIM3_TRGO +/** Deprecated. Use ADC_EXT_EV_TIM4_CC4 instead. */ +#define ADC_ADC3_TIM5_CC1 ADC_EXT_EV_TIM4_CC4 +/** Deprecated. Use ADC_EXT_EV_EXTI11 instead. */ +#define ADC_ADC3_TIM5_CC3 ADC_EXT_EV_EXTI11 +/** Deprecated. Use ADC_EXT_EV_TIM8_TRGO instead. */ +#define ADC_ADC3_SWSTART ADC_EXT_EV_TIM8_TRGO +/** Deprecated. Use ADC_EXT_EV_SWSTART instead. */ +#define ADC_SWSTART ADC_EXT_EV_SWSTART + +/** + * @brief STM32F1 sample times, in ADC clock cycles. + * + * These control the amount of time spent sampling the input voltage. + * + * IMPORTANT: maximum external impedance must be below 0.4kOhms for + * 1.5 cycle sampling time. At 55.5 cycles/sample, the external input + * impedance must be at most 50kOhms. See your device's datasheet for + * more information. + */ +typedef enum adc_smp_rate { + ADC_SMPR_1_5, /**< 1.5 ADC cycles */ + ADC_SMPR_7_5, /**< 7.5 ADC cycles */ + ADC_SMPR_13_5, /**< 13.5 ADC cycles */ + ADC_SMPR_28_5, /**< 28.5 ADC cycles */ + ADC_SMPR_41_5, /**< 41.5 ADC cycles */ + ADC_SMPR_55_5, /**< 55.5 ADC cycles */ + ADC_SMPR_71_5, /**< 71.5 ADC cycles */ + ADC_SMPR_239_5, /**< 239.5 ADC cycles */ +} adc_smp_rate; + +/** + * @brief STM32F1 ADC prescalers, as divisors of PCLK2. + */ +typedef enum adc_prescaler { + ADC_PRE_PCLK2_DIV_2 = RCC_ADCPRE_PCLK_DIV_2, /** PCLK2 divided by 2 */ + ADC_PRE_PCLK2_DIV_4 = RCC_ADCPRE_PCLK_DIV_4, /** PCLK2 divided by 4 */ + ADC_PRE_PCLK2_DIV_6 = RCC_ADCPRE_PCLK_DIV_6, /** PCLK2 divided by 6 */ + ADC_PRE_PCLK2_DIV_8 = RCC_ADCPRE_PCLK_DIV_8, /** PCLK2 divided by 8 */ +} adc_prescaler; + +/* + * Routines + */ + +void adc_calibrate(const adc_dev *dev); + +/** + * @brief Set external trigger conversion mode event for regular channels + * + * Availability: STM32F1. + * + * @param dev ADC device + * @param enable If 1, conversion on external events is enabled; if 0, + * disabled. + */ +static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { + *bb_perip(&dev->regs->CR2, ADC_CR2_EXTTRIG_BIT) = !!enable; +} + +#endif diff --git a/libmaple/stm32f1/include/series/dac.h b/libmaple/stm32f1/include/series/dac.h new file mode 100644 index 0000000..c0d026b --- /dev/null +++ b/libmaple/stm32f1/include/series/dac.h @@ -0,0 +1,71 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/dac.h + * @brief STM32F1 DAC support + */ + +#ifndef _LIBMAPLE_STM32F1_DAC_H_ +#define _LIBMAPLE_STM32F1_DAC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/** STM32F1 DAC register map type. */ +typedef struct dac_reg_map { + __io uint32 CR; /**< Control register */ + __io uint32 SWTRIGR; /**< Software trigger register */ + __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + holding register */ + __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + holding register */ + __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + holding register */ + __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + holding register */ + __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + holding register */ + __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + holding register */ + __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + holding register */ + __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + holding register */ + __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding + register */ + __io uint32 DOR1; /**< Channel 1 data output register */ + __io uint32 DOR2; /**< Channel 2 data output register */ +} dac_reg_map; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f1/include/series/dma.h b/libmaple/stm32f1/include/series/dma.h new file mode 100644 index 0000000..3b19e2b --- /dev/null +++ b/libmaple/stm32f1/include/series/dma.h @@ -0,0 +1,565 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Michael Hope. + * Copyright (c) 2012 LeafLabs, LLC + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/dma.h + * @author Marti Bolivar <mbolivar@leaflabs.com>; + * Original implementation by Michael Hope + * @brief STM32F1 DMA series header. + */ + +/* + * See /notes/dma-stm32f1.txt for more information. + */ + +#ifndef _LIBMAPLE_STM32F1_DMA_H_ +#define _LIBMAPLE_STM32F1_DMA_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> +#include <libmaple/dma_common.h> + +/* + * Register maps and base pointers + */ + +/** + * @brief STM32F1 DMA register map type. + * + * Note that DMA controller 2 (register map base pointer DMA2_BASE) + * only supports channels 1--5. + */ +typedef struct dma_reg_map { + __io uint32 ISR; /**< Interrupt status register */ + __io uint32 IFCR; /**< Interrupt flag clear register */ + __io uint32 CCR1; /**< Channel 1 configuration register */ + __io uint32 CNDTR1; /**< Channel 1 number of data register */ + __io uint32 CPAR1; /**< Channel 1 peripheral address register */ + __io uint32 CMAR1; /**< Channel 1 memory address register */ + const uint32 RESERVED1; /**< Reserved. */ + __io uint32 CCR2; /**< Channel 2 configuration register */ + __io uint32 CNDTR2; /**< Channel 2 number of data register */ + __io uint32 CPAR2; /**< Channel 2 peripheral address register */ + __io uint32 CMAR2; /**< Channel 2 memory address register */ + const uint32 RESERVED2; /**< Reserved. */ + __io uint32 CCR3; /**< Channel 3 configuration register */ + __io uint32 CNDTR3; /**< Channel 3 number of data register */ + __io uint32 CPAR3; /**< Channel 3 peripheral address register */ + __io uint32 CMAR3; /**< Channel 3 memory address register */ + const uint32 RESERVED3; /**< Reserved. */ + __io uint32 CCR4; /**< Channel 4 configuration register */ + __io uint32 CNDTR4; /**< Channel 4 number of data register */ + __io uint32 CPAR4; /**< Channel 4 peripheral address register */ + __io uint32 CMAR4; /**< Channel 4 memory address register */ + const uint32 RESERVED4; /**< Reserved. */ + __io uint32 CCR5; /**< Channel 5 configuration register */ + __io uint32 CNDTR5; /**< Channel 5 number of data register */ + __io uint32 CPAR5; /**< Channel 5 peripheral address register */ + __io uint32 CMAR5; /**< Channel 5 memory address register */ + const uint32 RESERVED5; /**< Reserved. */ + __io uint32 CCR6; /**< Channel 6 configuration register */ + __io uint32 CNDTR6; /**< Channel 6 number of data register */ + __io uint32 CPAR6; /**< Channel 6 peripheral address register */ + __io uint32 CMAR6; /**< Channel 6 memory address register */ + const uint32 RESERVED6; /**< Reserved. */ + __io uint32 CCR7; /**< Channel 7 configuration register */ + __io uint32 CNDTR7; /**< Channel 7 number of data register */ + __io uint32 CPAR7; /**< Channel 7 peripheral address register */ + __io uint32 CMAR7; /**< Channel 7 memory address register */ + const uint32 RESERVED7; /**< Reserved. */ +} dma_reg_map; + +/** DMA controller 1 register map base pointer */ +#define DMA1_BASE ((struct dma_reg_map*)0x40020000) +/** DMA controller 2 register map base pointer */ +#define DMA2_BASE ((struct dma_reg_map*)0x40020400) + +/** + * @brief STM32F1 DMA channel (i.e. tube) register map type. + * Provides access to an individual channel's registers. + * @see dma_tube_regs() + */ +typedef struct dma_tube_reg_map { + __io uint32 CCR; /**< Channel configuration register */ + __io uint32 CNDTR; /**< Channel number of data register */ + __io uint32 CPAR; /**< Channel peripheral address register */ + __io uint32 CMAR; /**< Channel memory address register */ +} dma_tube_reg_map; + +/** DMA1 channel 1 register map base pointer */ +#define DMA1CH1_BASE ((struct dma_tube_reg_map*)0x40020008) +/** DMA1 channel 2 register map base pointer */ +#define DMA1CH2_BASE ((struct dma_tube_reg_map*)0x4002001C) +/** DMA1 channel 3 register map base pointer */ +#define DMA1CH3_BASE ((struct dma_tube_reg_map*)0x40020030) +/** DMA1 channel 4 register map base pointer */ +#define DMA1CH4_BASE ((struct dma_tube_reg_map*)0x40020044) +/** DMA1 channel 5 register map base pointer */ +#define DMA1CH5_BASE ((struct dma_tube_reg_map*)0x40020058) +/** DMA1 channel 6 register map base pointer */ +#define DMA1CH6_BASE ((struct dma_tube_reg_map*)0x4002006C) +/** DMA1 channel 7 register map base pointer */ +#define DMA1CH7_BASE ((struct dma_tube_reg_map*)0x40020080) + +/** DMA2 channel 1 register map base pointer */ +#define DMA2CH1_BASE ((struct dma_tube_reg_map*)0x40020408) +/** DMA2 channel 2 register map base pointer */ +#define DMA2CH2_BASE ((struct dma_tube_reg_map*)0x4002041C) +/** DMA2 channel 3 register map base pointer */ +#define DMA2CH3_BASE ((struct dma_tube_reg_map*)0x40020430) +/** DMA2 channel 4 register map base pointer */ +#define DMA2CH4_BASE ((struct dma_tube_reg_map*)0x40020444) +/** DMA2 channel 5 register map base pointer */ +#define DMA2CH5_BASE ((struct dma_tube_reg_map*)0x40020458) + +/* + * Register bit definitions + */ + +/* Interrupt status register */ + +#define DMA_ISR_TEIF7_BIT 27 +#define DMA_ISR_HTIF7_BIT 26 +#define DMA_ISR_TCIF7_BIT 25 +#define DMA_ISR_GIF7_BIT 24 +#define DMA_ISR_TEIF6_BIT 23 +#define DMA_ISR_HTIF6_BIT 22 +#define DMA_ISR_TCIF6_BIT 21 +#define DMA_ISR_GIF6_BIT 20 +#define DMA_ISR_TEIF5_BIT 19 +#define DMA_ISR_HTIF5_BIT 18 +#define DMA_ISR_TCIF5_BIT 17 +#define DMA_ISR_GIF5_BIT 16 +#define DMA_ISR_TEIF4_BIT 15 +#define DMA_ISR_HTIF4_BIT 14 +#define DMA_ISR_TCIF4_BIT 13 +#define DMA_ISR_GIF4_BIT 12 +#define DMA_ISR_TEIF3_BIT 11 +#define DMA_ISR_HTIF3_BIT 10 +#define DMA_ISR_TCIF3_BIT 9 +#define DMA_ISR_GIF3_BIT 8 +#define DMA_ISR_TEIF2_BIT 7 +#define DMA_ISR_HTIF2_BIT 6 +#define DMA_ISR_TCIF2_BIT 5 +#define DMA_ISR_GIF2_BIT 4 +#define DMA_ISR_TEIF1_BIT 3 +#define DMA_ISR_HTIF1_BIT 2 +#define DMA_ISR_TCIF1_BIT 1 +#define DMA_ISR_GIF1_BIT 0 + +#define DMA_ISR_TEIF7 (1U << DMA_ISR_TEIF7_BIT) +#define DMA_ISR_HTIF7 (1U << DMA_ISR_HTIF7_BIT) +#define DMA_ISR_TCIF7 (1U << DMA_ISR_TCIF7_BIT) +#define DMA_ISR_GIF7 (1U << DMA_ISR_GIF7_BIT) +#define DMA_ISR_TEIF6 (1U << DMA_ISR_TEIF6_BIT) +#define DMA_ISR_HTIF6 (1U << DMA_ISR_HTIF6_BIT) +#define DMA_ISR_TCIF6 (1U << DMA_ISR_TCIF6_BIT) +#define DMA_ISR_GIF6 (1U << DMA_ISR_GIF6_BIT) +#define DMA_ISR_TEIF5 (1U << DMA_ISR_TEIF5_BIT) +#define DMA_ISR_HTIF5 (1U << DMA_ISR_HTIF5_BIT) +#define DMA_ISR_TCIF5 (1U << DMA_ISR_TCIF5_BIT) +#define DMA_ISR_GIF5 (1U << DMA_ISR_GIF5_BIT) +#define DMA_ISR_TEIF4 (1U << DMA_ISR_TEIF4_BIT) +#define DMA_ISR_HTIF4 (1U << DMA_ISR_HTIF4_BIT) +#define DMA_ISR_TCIF4 (1U << DMA_ISR_TCIF4_BIT) +#define DMA_ISR_GIF4 (1U << DMA_ISR_GIF4_BIT) +#define DMA_ISR_TEIF3 (1U << DMA_ISR_TEIF3_BIT) +#define DMA_ISR_HTIF3 (1U << DMA_ISR_HTIF3_BIT) +#define DMA_ISR_TCIF3 (1U << DMA_ISR_TCIF3_BIT) +#define DMA_ISR_GIF3 (1U << DMA_ISR_GIF3_BIT) +#define DMA_ISR_TEIF2 (1U << DMA_ISR_TEIF2_BIT) +#define DMA_ISR_HTIF2 (1U << DMA_ISR_HTIF2_BIT) +#define DMA_ISR_TCIF2 (1U << DMA_ISR_TCIF2_BIT) +#define DMA_ISR_GIF2 (1U << DMA_ISR_GIF2_BIT) +#define DMA_ISR_TEIF1 (1U << DMA_ISR_TEIF1_BIT) +#define DMA_ISR_HTIF1 (1U << DMA_ISR_HTIF1_BIT) +#define DMA_ISR_TCIF1 (1U << DMA_ISR_TCIF1_BIT) +#define DMA_ISR_GIF1 (1U << DMA_ISR_GIF1_BIT) + +/* Interrupt flag clear register */ + +#define DMA_IFCR_CTEIF7_BIT 27 +#define DMA_IFCR_CHTIF7_BIT 26 +#define DMA_IFCR_CTCIF7_BIT 25 +#define DMA_IFCR_CGIF7_BIT 24 +#define DMA_IFCR_CTEIF6_BIT 23 +#define DMA_IFCR_CHTIF6_BIT 22 +#define DMA_IFCR_CTCIF6_BIT 21 +#define DMA_IFCR_CGIF6_BIT 20 +#define DMA_IFCR_CTEIF5_BIT 19 +#define DMA_IFCR_CHTIF5_BIT 18 +#define DMA_IFCR_CTCIF5_BIT 17 +#define DMA_IFCR_CGIF5_BIT 16 +#define DMA_IFCR_CTEIF4_BIT 15 +#define DMA_IFCR_CHTIF4_BIT 14 +#define DMA_IFCR_CTCIF4_BIT 13 +#define DMA_IFCR_CGIF4_BIT 12 +#define DMA_IFCR_CTEIF3_BIT 11 +#define DMA_IFCR_CHTIF3_BIT 10 +#define DMA_IFCR_CTCIF3_BIT 9 +#define DMA_IFCR_CGIF3_BIT 8 +#define DMA_IFCR_CTEIF2_BIT 7 +#define DMA_IFCR_CHTIF2_BIT 6 +#define DMA_IFCR_CTCIF2_BIT 5 +#define DMA_IFCR_CGIF2_BIT 4 +#define DMA_IFCR_CTEIF1_BIT 3 +#define DMA_IFCR_CHTIF1_BIT 2 +#define DMA_IFCR_CTCIF1_BIT 1 +#define DMA_IFCR_CGIF1_BIT 0 + +#define DMA_IFCR_CTEIF7 (1U << DMA_IFCR_CTEIF7_BIT) +#define DMA_IFCR_CHTIF7 (1U << DMA_IFCR_CHTIF7_BIT) +#define DMA_IFCR_CTCIF7 (1U << DMA_IFCR_CTCIF7_BIT) +#define DMA_IFCR_CGIF7 (1U << DMA_IFCR_CGIF7_BIT) +#define DMA_IFCR_CTEIF6 (1U << DMA_IFCR_CTEIF6_BIT) +#define DMA_IFCR_CHTIF6 (1U << DMA_IFCR_CHTIF6_BIT) +#define DMA_IFCR_CTCIF6 (1U << DMA_IFCR_CTCIF6_BIT) +#define DMA_IFCR_CGIF6 (1U << DMA_IFCR_CGIF6_BIT) +#define DMA_IFCR_CTEIF5 (1U << DMA_IFCR_CTEIF5_BIT) +#define DMA_IFCR_CHTIF5 (1U << DMA_IFCR_CHTIF5_BIT) +#define DMA_IFCR_CTCIF5 (1U << DMA_IFCR_CTCIF5_BIT) +#define DMA_IFCR_CGIF5 (1U << DMA_IFCR_CGIF5_BIT) +#define DMA_IFCR_CTEIF4 (1U << DMA_IFCR_CTEIF4_BIT) +#define DMA_IFCR_CHTIF4 (1U << DMA_IFCR_CHTIF4_BIT) +#define DMA_IFCR_CTCIF4 (1U << DMA_IFCR_CTCIF4_BIT) +#define DMA_IFCR_CGIF4 (1U << DMA_IFCR_CGIF4_BIT) +#define DMA_IFCR_CTEIF3 (1U << DMA_IFCR_CTEIF3_BIT) +#define DMA_IFCR_CHTIF3 (1U << DMA_IFCR_CHTIF3_BIT) +#define DMA_IFCR_CTCIF3 (1U << DMA_IFCR_CTCIF3_BIT) +#define DMA_IFCR_CGIF3 (1U << DMA_IFCR_CGIF3_BIT) +#define DMA_IFCR_CTEIF2 (1U << DMA_IFCR_CTEIF2_BIT) +#define DMA_IFCR_CHTIF2 (1U << DMA_IFCR_CHTIF2_BIT) +#define DMA_IFCR_CTCIF2 (1U << DMA_IFCR_CTCIF2_BIT) +#define DMA_IFCR_CGIF2 (1U << DMA_IFCR_CGIF2_BIT) +#define DMA_IFCR_CTEIF1 (1U << DMA_IFCR_CTEIF1_BIT) +#define DMA_IFCR_CHTIF1 (1U << DMA_IFCR_CHTIF1_BIT) +#define DMA_IFCR_CTCIF1 (1U << DMA_IFCR_CTCIF1_BIT) +#define DMA_IFCR_CGIF1 (1U << DMA_IFCR_CGIF1_BIT) + +/* Channel configuration register */ + +#define DMA_CCR_MEM2MEM_BIT 14 +#define DMA_CCR_MINC_BIT 7 +#define DMA_CCR_PINC_BIT 6 +#define DMA_CCR_CIRC_BIT 5 +#define DMA_CCR_DIR_BIT 4 +#define DMA_CCR_TEIE_BIT 3 +#define DMA_CCR_HTIE_BIT 2 +#define DMA_CCR_TCIE_BIT 1 +#define DMA_CCR_EN_BIT 0 + +#define DMA_CCR_MEM2MEM (1U << DMA_CCR_MEM2MEM_BIT) +#define DMA_CCR_PL (0x3 << 12) +#define DMA_CCR_PL_LOW (0x0 << 12) +#define DMA_CCR_PL_MEDIUM (0x1 << 12) +#define DMA_CCR_PL_HIGH (0x2 << 12) +#define DMA_CCR_PL_VERY_HIGH (0x3 << 12) +#define DMA_CCR_MSIZE (0x3 << 10) +#define DMA_CCR_MSIZE_8BITS (0x0 << 10) +#define DMA_CCR_MSIZE_16BITS (0x1 << 10) +#define DMA_CCR_MSIZE_32BITS (0x2 << 10) +#define DMA_CCR_PSIZE (0x3 << 8) +#define DMA_CCR_PSIZE_8BITS (0x0 << 8) +#define DMA_CCR_PSIZE_16BITS (0x1 << 8) +#define DMA_CCR_PSIZE_32BITS (0x2 << 8) +#define DMA_CCR_MINC (1U << DMA_CCR_MINC_BIT) +#define DMA_CCR_PINC (1U << DMA_CCR_PINC_BIT) +#define DMA_CCR_CIRC (1U << DMA_CCR_CIRC_BIT) +#define DMA_CCR_DIR (1U << DMA_CCR_DIR_BIT) +#define DMA_CCR_DIR_FROM_PER (0U << DMA_CCR_DIR_BIT) +#define DMA_CCR_DIR_FROM_MEM (1U << DMA_CCR_DIR_BIT) +#define DMA_CCR_TEIE (1U << DMA_CCR_TEIE_BIT) +#define DMA_CCR_HTIE (1U << DMA_CCR_HTIE_BIT) +#define DMA_CCR_TCIE (1U << DMA_CCR_TCIE_BIT) +#define DMA_CCR_EN (1U << DMA_CCR_EN_BIT) + +/* + * Devices + */ + +extern dma_dev *DMA1; +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +extern dma_dev *DMA2; +#endif + +/* + * Other types needed by, or useful for, <libmaple/dma.h>. + */ + +/** + * @brief STM32F1 dma_tube. + * On STM32F1, DMA tubes are just channels. + */ +#define dma_tube dma_channel + +/** + * @brief On STM32F1, dma_channel_reg_map is an alias for dma_tube_reg_map. + * This is for backwards compatibility. */ +#define dma_channel_reg_map dma_tube_reg_map + +/** + * @brief STM32F1 configuration flags for dma_tube_config + * @see struct dma_tube_config + */ +typedef enum dma_cfg_flags { + /** + * Source address increment mode + * + * If this flag is set, the source address is incremented (by the + * source size) after each DMA transfer. + */ + DMA_CFG_SRC_INC = 1U << 31, + + /** + * Destination address increment mode + * + * If this flag is set, the destination address is incremented (by + * the destination size) after each DMA transfer. + */ + DMA_CFG_DST_INC = 1U << 30, + + /** + * Circular mode + * + * This mode is not available for memory-to-memory transfers. + */ + DMA_CFG_CIRC = DMA_CCR_CIRC, + + /** Transfer complete interrupt enable */ + DMA_CFG_CMPLT_IE = DMA_CCR_TCIE, + /** Transfer half-complete interrupt enable */ + DMA_CFG_HALF_CMPLT_IE = DMA_CCR_HTIE, + /** Transfer error interrupt enable */ + DMA_CFG_ERR_IE = DMA_CCR_TEIE, +} dma_cfg_flags; + +/** + * @brief STM32F1 DMA request sources. + * + * IMPORTANT: + * + * 1. On STM32F1, each dma_request_src can only be used by a + * particular tube on a particular DMA controller. For example, + * DMA_REQ_SRC_ADC1 belongs to DMA1, tube 1. DMA2 cannot serve + * requests from ADC1, nor can DMA1 tube 2, etc. If you try to use a + * request source with the wrong DMA controller or tube on STM32F1, + * dma_tube_cfg() will fail. + * + * 2. In general, a DMA tube can only serve a single request source at + * a time, and on STM32F1, Terrible Super-Bad Things will happen if + * two request sources are active for a single tube. + * + * To make all this easier to sort out, these dma_request_src + * enumerators are grouped by DMA controller and tube. + * + * @see struct dma_tube_config + * @see dma_tube_cfg() + */ +typedef enum dma_request_src { + /* Each request source encodes the DMA controller and channel it + * belongs to, for error checking in dma_tube_cfg(). */ + + /* DMA1 request sources */ + + /**@{*/ + /** (DMA1, tube 1) */ + DMA_REQ_SRC_ADC1 = (RCC_DMA1 << 3) | 1, + DMA_REQ_SRC_TIM2_CH3 = (RCC_DMA1 << 3) | 1, + DMA_REQ_SRC_TIM4_CH1 = (RCC_DMA1 << 3) | 1, + /**@}*/ + + /**@{*/ + /** (DMA1, tube 2)*/ + DMA_REQ_SRC_SPI1_RX = (RCC_DMA1 << 3) | 2, + DMA_REQ_SRC_USART3_TX = (RCC_DMA1 << 3) | 2, + DMA_REQ_SRC_TIM1_CH1 = (RCC_DMA1 << 3) | 2, + DMA_REQ_SRC_TIM2_UP = (RCC_DMA1 << 3) | 2, + DMA_REQ_SRC_TIM3_CH3 = (RCC_DMA1 << 3) | 2, + /**@}*/ + + /**@{*/ + /** (DMA1, tube 3)*/ + DMA_REQ_SRC_SPI1_TX = (RCC_DMA1 << 3) | 3, + DMA_REQ_SRC_USART3_RX = (RCC_DMA1 << 3) | 3, + DMA_REQ_SRC_TIM1_CH2 = (RCC_DMA1 << 3) | 3, + DMA_REQ_SRC_TIM3_CH4 = (RCC_DMA1 << 3) | 3, + DMA_REQ_SRC_TIM3_UP = (RCC_DMA1 << 3) | 3, + /**@}*/ + + /**@{*/ + /** (DMA1, tube 4)*/ + DMA_REQ_SRC_SPI2_RX = (RCC_DMA1 << 3) | 4, + DMA_REQ_SRC_I2S2_RX = (RCC_DMA1 << 3) | 4, + DMA_REQ_SRC_USART1_TX = (RCC_DMA1 << 3) | 4, + DMA_REQ_SRC_I2C2_TX = (RCC_DMA1 << 3) | 4, + DMA_REQ_SRC_TIM1_CH4 = (RCC_DMA1 << 3) | 4, + DMA_REQ_SRC_TIM1_TRIG = (RCC_DMA1 << 3) | 4, + DMA_REQ_SRC_TIM1_COM = (RCC_DMA1 << 3) | 4, + DMA_REQ_SRC_TIM4_CH2 = (RCC_DMA1 << 3) | 4, + /**@}*/ + + /**@{*/ + /** (DMA1, tube 5)*/ + DMA_REQ_SRC_SPI2_TX = (RCC_DMA1 << 3) | 5, + DMA_REQ_SRC_I2S2_TX = (RCC_DMA1 << 3) | 5, + DMA_REQ_SRC_USART1_RX = (RCC_DMA1 << 3) | 5, + DMA_REQ_SRC_I2C2_RX = (RCC_DMA1 << 3) | 5, + DMA_REQ_SRC_TIM1_UP = (RCC_DMA1 << 3) | 5, + DMA_REQ_SRC_TIM2_CH1 = (RCC_DMA1 << 3) | 5, + DMA_REQ_SRC_TIM4_CH3 = (RCC_DMA1 << 3) | 5, + /**@}*/ + + /**@{*/ + /** (DMA1, tube 6)*/ + DMA_REQ_SRC_USART2_RX = (RCC_DMA1 << 3) | 6, + DMA_REQ_SRC_I2C1_TX = (RCC_DMA1 << 3) | 6, + DMA_REQ_SRC_TIM1_CH3 = (RCC_DMA1 << 3) | 6, + DMA_REQ_SRC_TIM3_CH1 = (RCC_DMA1 << 3) | 6, + DMA_REQ_SRC_TIM3_TRIG = (RCC_DMA1 << 3) | 6, + /**@}*/ + + /**@{*/ + /* Tube 7 */ + DMA_REQ_SRC_USART2_TX = (RCC_DMA1 << 3) | 7, + DMA_REQ_SRC_I2C1_RX = (RCC_DMA1 << 3) | 7, + DMA_REQ_SRC_TIM2_CH2 = (RCC_DMA1 << 3) | 7, + DMA_REQ_SRC_TIM2_CH4 = (RCC_DMA1 << 3) | 7, + DMA_REQ_SRC_TIM4_UP = (RCC_DMA1 << 3) | 7, + /**@}*/ + + /* DMA2 request sources */ + + /**@{*/ + /** (DMA2, tube 1)*/ + DMA_REQ_SRC_SPI3_RX = (RCC_DMA2 << 3) | 1, + DMA_REQ_SRC_I2S3_RX = (RCC_DMA2 << 3) | 1, + DMA_REQ_SRC_TIM5_CH4 = (RCC_DMA2 << 3) | 1, + DMA_REQ_SRC_TIM5_TRIG = (RCC_DMA2 << 3) | 1, + /**@}*/ + + /**@{*/ + /** (DMA2, tube 2)*/ + DMA_REQ_SRC_SPI3_TX = (RCC_DMA2 << 3) | 2, + DMA_REQ_SRC_I2S3_TX = (RCC_DMA2 << 3) | 2, + DMA_REQ_SRC_TIM5_CH3 = (RCC_DMA2 << 3) | 2, + DMA_REQ_SRC_TIM5_UP = (RCC_DMA2 << 3) | 2, + /**@}*/ + + /**@{*/ + /** (DMA2, tube 3)*/ + DMA_REQ_SRC_UART4_RX = (RCC_DMA2 << 3) | 3, + DMA_REQ_SRC_TIM6_UP = (RCC_DMA2 << 3) | 3, + DMA_REQ_SRC_DAC_CH1 = (RCC_DMA2 << 3) | 3, + /**@}*/ + + /**@{*/ + /** (DMA2, tube 4)*/ + DMA_REQ_SRC_SDIO = (RCC_DMA2 << 3) | 4, + DMA_REQ_SRC_TIM5_CH2 = (RCC_DMA2 << 3) | 4, + /**@}*/ + + /**@{*/ + /** (DMA2, tube 5)*/ + DMA_REQ_SRC_ADC3 = (RCC_DMA2 << 3) | 5, + DMA_REQ_SRC_UART4_TX = (RCC_DMA2 << 3) | 5, + DMA_REQ_SRC_TIM5_CH1 = (RCC_DMA2 << 3) | 5, + /**@}*/ +} dma_request_src; + +/* + * Convenience routines. + */ + +/** + * @brief On STM32F1, dma_is_channel_enabled() is an alias for + * dma_is_enabled(). + * This is for backwards compatibility. + */ +#define dma_is_channel_enabled dma_is_enabled + +#define DMA_CHANNEL_NREGS 5 /* accounts for reserved word */ +static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, dma_tube tube) { + __io uint32 *ccr1 = &dev->regs->CCR1; + return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (tube - 1)); +} + +/** + * @brief On STM32F1, dma_channel_regs() is an alias for dma_tube_regs(). + * This is for backwards compatibility. */ +#define dma_channel_regs(dev, ch) dma_tube_regs(dev, ch) + +static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube) { + return (uint8)(dma_tube_regs(dev, tube)->CCR & DMA_CCR_EN); +} + +static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube) { + uint8 shift = (tube - 1) * 4; + return (dev->regs->ISR >> shift) & 0xF; +} + +static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) { + dev->regs->IFCR = (1U << (4 * (tube - 1))); +} + +/** + * @brief Deprecated + * STM32F1 mode flags for dma_setup_xfer(). Use dma_tube_cfg() instead. + * @see dma_tube_cfg() + */ +typedef enum dma_mode_flags { + DMA_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ + DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */ + DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */ + DMA_CIRC_MODE = 1 << 5, /**< Circular mode */ + DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */ + DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */ + DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */ + DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */ +} dma_mode_flags; + +/* Keep this around for backwards compatibility, but it's deprecated. + * New code should use dma_tube_cfg() instead. + * + * (It's not possible to fully configure a DMA stream on F2 with just + * this information, so this interface is too tied to the F1.) */ +__deprecated +void dma_setup_transfer(dma_dev *dev, + dma_channel channel, + __io void *peripheral_address, + dma_xfer_size peripheral_size, + __io void *memory_address, + dma_xfer_size memory_size, + uint32 mode); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/stm32f1/include/series/exti.h b/libmaple/stm32f1/include/series/exti.h new file mode 100644 index 0000000..1ece664 --- /dev/null +++ b/libmaple/stm32f1/include/series/exti.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/exti.h + * @brief STM32F1 external interrupts + */ + +#ifndef _LIBMAPLE_STM32F1_EXTI_H_ +#define _LIBMAPLE_STM32F1_EXTI_H_ + +#ifdef __cpluspus +extern "C" { +#endif + +struct exti_reg_map; +#define EXTI_BASE ((struct exti_reg_map*)0x40010400) + +#ifdef __cpluspus +} +#endif + +#endif diff --git a/libmaple/flash.h b/libmaple/stm32f1/include/series/flash.h index 0b4e49b..24efb0b 100644 --- a/libmaple/flash.h +++ b/libmaple/stm32f1/include/series/flash.h @@ -25,21 +25,28 @@ *****************************************************************************/ /** - * @file flash.h - * @brief STM32 Medium and high density Flash register map and setup - * routines + * @file libmaple/stm32f1/include/series/flash.h + * @brief STM32F1 Flash header. + * + * Provides register map, base pointer, and register bit definitions + * for the Flash controller on the STM32F1 line, along with + * series-specific configuration values. */ -#include "libmaple_types.h" - -#ifndef _FLASH_H_ -#define _FLASH_H_ +#ifndef _LIBMAPLE_STM32F1_FLASH_H_ +#define _LIBMAPLE_STM32F1_FLASH_H_ #ifdef __cplusplus extern "C"{ #endif -/** Flash register map type */ +#include <libmaple/libmaple_types.h> + +/* + * Register map + */ + +/** @brief STM32F1 Flash register map type */ typedef struct flash_reg_map { __io uint32 ACR; /**< Access control register */ __io uint32 KEYR; /**< Key register */ @@ -51,7 +58,6 @@ typedef struct flash_reg_map { __io uint32 WRPR; /**< Write protection register */ } flash_reg_map; -/** Flash register map base pointer */ #define FLASH_BASE ((struct flash_reg_map*)0x40022000) /* @@ -64,9 +70,9 @@ typedef struct flash_reg_map { #define FLASH_ACR_PRFTBE_BIT 4 #define FLASH_ACR_HLFCYA_BIT 3 -#define FLASH_ACR_PRFTBS BIT(FLASH_ACR_PRFTBS_BIT) -#define FLASH_ACR_PRFTBE BIT(FLASH_ACR_PRFTBE_BIT) -#define FLASH_ACR_HLFCYA BIT(FLASH_ACR_HLFCYA_BIT) +#define FLASH_ACR_PRFTBS (1U << FLASH_ACR_PRFTBS_BIT) +#define FLASH_ACR_PRFTBE (1U << FLASH_ACR_PRFTBE_BIT) +#define FLASH_ACR_HLFCYA (1U << FLASH_ACR_HLFCYA_BIT) #define FLASH_ACR_LATENCY 0x7 /* Status register */ @@ -76,10 +82,10 @@ typedef struct flash_reg_map { #define FLASH_SR_PGERR_BIT 2 #define FLASH_SR_BSY_BIT 0 -#define FLASH_SR_EOP BIT(FLASH_SR_EOP_BIT) -#define FLASH_SR_WRPRTERR BIT(FLASH_SR_WRPRTERR_BIT) -#define FLASH_SR_PGERR BIT(FLASH_SR_PGERR_BIT) -#define FLASH_SR_BSY BIT(FLASH_SR_BSY_BIT) +#define FLASH_SR_EOP (1U << FLASH_SR_EOP_BIT) +#define FLASH_SR_WRPRTERR (1U << FLASH_SR_WRPRTERR_BIT) +#define FLASH_SR_PGERR (1U << FLASH_SR_PGERR_BIT) +#define FLASH_SR_BSY (1U << FLASH_SR_BSY_BIT) /* Control register */ @@ -94,16 +100,16 @@ typedef struct flash_reg_map { #define FLASH_CR_PER_BIT 1 #define FLASH_CR_PG_BIT 0 -#define FLASH_CR_EOPIE BIT(FLASH_CR_EOPIE_BIT) -#define FLASH_CR_ERRIE BIT(FLASH_CR_ERRIE_BIT) -#define FLASH_CR_OPTWRE BIT(FLASH_CR_OPTWRE_BIT) -#define FLASH_CR_LOCK BIT(FLASH_CR_LOCK_BIT) -#define FLASH_CR_STRT BIT(FLASH_CR_STRT_BIT) -#define FLASH_CR_OPTER BIT(FLASH_CR_OPTER_BIT) -#define FLASH_CR_OPTPG BIT(FLASH_CR_OPTPG_BIT) -#define FLASH_CR_MER BIT(FLASH_CR_MER_BIT) -#define FLASH_CR_PER BIT(FLASH_CR_PER_BIT) -#define FLASH_CR_PG BIT(FLASH_CR_PG_BIT) +#define FLASH_CR_EOPIE (1U << FLASH_CR_EOPIE_BIT) +#define FLASH_CR_ERRIE (1U << FLASH_CR_ERRIE_BIT) +#define FLASH_CR_OPTWRE (1U << FLASH_CR_OPTWRE_BIT) +#define FLASH_CR_LOCK (1U << FLASH_CR_LOCK_BIT) +#define FLASH_CR_STRT (1U << FLASH_CR_STRT_BIT) +#define FLASH_CR_OPTER (1U << FLASH_CR_OPTER_BIT) +#define FLASH_CR_OPTPG (1U << FLASH_CR_OPTPG_BIT) +#define FLASH_CR_MER (1U << FLASH_CR_MER_BIT) +#define FLASH_CR_PER (1U << FLASH_CR_PER_BIT) +#define FLASH_CR_PG (1U << FLASH_CR_PG_BIT) /* Option byte register */ @@ -116,27 +122,28 @@ typedef struct flash_reg_map { #define FLASH_OBR_DATA1 (0xFF << 18) #define FLASH_OBR_DATA0 (0xFF << 10) #define FLASH_OBR_USER 0x3FF -#define FLASH_OBR_nRST_STDBY BIT(FLASH_OBR_nRST_STDBY_BIT) -#define FLASH_OBR_nRST_STOP BIT(FLASH_OBR_nRST_STOP_BIT) -#define FLASH_OBR_WDG_SW BIT(FLASH_OBR_WDG_SW_BIT) -#define FLASH_OBR_RDPRT BIT(FLASH_OBR_RDPRT_BIT) -#define FLASH_OBR_OPTERR BIT(FLASH_OBR_OPTERR_BIT) +#define FLASH_OBR_nRST_STDBY (1U << FLASH_OBR_nRST_STDBY_BIT) +#define FLASH_OBR_nRST_STOP (1U << FLASH_OBR_nRST_STOP_BIT) +#define FLASH_OBR_WDG_SW (1U << FLASH_OBR_WDG_SW_BIT) +#define FLASH_OBR_RDPRT (1U << FLASH_OBR_RDPRT_BIT) +#define FLASH_OBR_OPTERR (1U << FLASH_OBR_OPTERR_BIT) /* - * Setup routines + * Series-specific configuration values. */ -#define FLASH_WAIT_STATE_0 0x0 -#define FLASH_WAIT_STATE_1 0x1 -#define FLASH_WAIT_STATE_2 0x2 +#define FLASH_SAFE_WAIT_STATES FLASH_WAIT_STATE_2 -void flash_enable_prefetch(void); -void flash_set_latency(uint32 wait_states); +/* Flash memory features available via ACR */ +enum { + FLASH_PREFETCH = 0x10, + FLASH_HALF_CYCLE = 0x8, + FLASH_ICACHE = 0x0, /* Not available on STM32F1 */ + FLASH_DCACHE = 0x0, /* Not available on STM32F1 */ +}; #ifdef __cplusplus } #endif #endif - - diff --git a/libmaple/gpio.h b/libmaple/stm32f1/include/series/gpio.h index a7859a7..aecf911 100644 --- a/libmaple/gpio.h +++ b/libmaple/stm32f1/include/series/gpio.h @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,22 +26,22 @@ *****************************************************************************/ /** - * @file gpio.h - * - * @brief General purpose I/O (GPIO) and Alternate Function I/O - * (AFIO) prototypes, defines, and inlined access functions. + * @file libmaple/stm32f1/include/series/gpio.h + * @brief STM32F1 GPIO and AFIO support. + * General purpose I/O (GPIO) and Alternate Function I/O (AFIO). */ -#ifndef _GPIO_H_ -#define _GPIO_H_ - -#include "libmaple.h" -#include "rcc.h" +#ifndef _LIBMAPLE_STM32F1_GPIO_H_ +#define _LIBMAPLE_STM32F1_GPIO_H_ #ifdef __cplusplus extern "C"{ #endif +#include <libmaple/stm32.h> +#include <libmaple/libmaple_types.h> +#include <libmaple/exti.h> + /* * GPIO register maps and devices */ @@ -56,46 +57,22 @@ typedef struct gpio_reg_map { __io uint32 LCKR; /**< Port configuration lock register */ } gpio_reg_map; -/** - * @brief External interrupt line port selector. - * - * Used to determine which GPIO port to map an external interrupt line - * onto. */ -/* (See AFIO sections, below) */ -typedef enum afio_exti_port { - AFIO_EXTI_PA, /**< Use port A (PAx) pin. */ - AFIO_EXTI_PB, /**< Use port B (PBx) pin. */ - AFIO_EXTI_PC, /**< Use port C (PCx) pin. */ - AFIO_EXTI_PD, /**< Use port D (PDx) pin. */ -#ifdef STM32_HIGH_DENSITY - AFIO_EXTI_PE, /**< Use port E (PEx) pin. */ - AFIO_EXTI_PF, /**< Use port F (PFx) pin. */ - AFIO_EXTI_PG, /**< Use port G (PGx) pin. */ -#endif -} afio_exti_port; - -/** GPIO device type */ -typedef struct gpio_dev { - gpio_reg_map *regs; /**< Register map */ - rcc_clk_id clk_id; /**< RCC clock information */ - afio_exti_port exti_port; /**< AFIO external interrupt port value */ -} gpio_dev; - -extern gpio_dev gpioa; -extern gpio_dev* const GPIOA; -extern gpio_dev gpiob; -extern gpio_dev* const GPIOB; -extern gpio_dev gpioc; -extern gpio_dev* const GPIOC; -extern gpio_dev gpiod; -extern gpio_dev* const GPIOD; +struct gpio_dev; +extern struct gpio_dev gpioa; +extern struct gpio_dev* const GPIOA; +extern struct gpio_dev gpiob; +extern struct gpio_dev* const GPIOB; +extern struct gpio_dev gpioc; +extern struct gpio_dev* const GPIOC; +extern struct gpio_dev gpiod; +extern struct gpio_dev* const GPIOD; #ifdef STM32_HIGH_DENSITY -extern gpio_dev gpioe; -extern gpio_dev* const GPIOE; -extern gpio_dev gpiof; -extern gpio_dev* const GPIOF; -extern gpio_dev gpiog; -extern gpio_dev* const GPIOG; +extern struct gpio_dev gpioe; +extern struct gpio_dev* const GPIOE; +extern struct gpio_dev gpiof; +extern struct gpio_dev* const GPIOF; +extern struct gpio_dev gpiog; +extern struct gpio_dev* const GPIOG; #endif /** GPIO port A register map base pointer */ @@ -106,14 +83,12 @@ extern gpio_dev* const GPIOG; #define GPIOC_BASE ((struct gpio_reg_map*)0x40011000) /** GPIO port D register map base pointer */ #define GPIOD_BASE ((struct gpio_reg_map*)0x40011400) -#ifdef STM32_HIGH_DENSITY /** GPIO port E register map base pointer */ #define GPIOE_BASE ((struct gpio_reg_map*)0x40011800) /** GPIO port F register map base pointer */ #define GPIOF_BASE ((struct gpio_reg_map*)0x40011C00) /** GPIO port G register map base pointer */ #define GPIOG_BASE ((struct gpio_reg_map*)0x40012000) -#endif /* * GPIO register bit definitions @@ -136,86 +111,33 @@ extern gpio_dev* const GPIOG; #define GPIO_CR_MODE_OUTPUT_50MHZ 0x3 /** - * @brief GPIO Pin modes. + * @brief GPIO pin modes. * * These only allow for 50MHZ max output speeds; if you want slower, * use direct register access. */ typedef enum gpio_pin_mode { - GPIO_OUTPUT_PP = (GPIO_CR_CNF_OUTPUT_PP | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output push-pull. */ - GPIO_OUTPUT_OD = (GPIO_CR_CNF_OUTPUT_OD | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output open-drain. */ - GPIO_AF_OUTPUT_PP = (GPIO_CR_CNF_AF_OUTPUT_PP | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function - output push-pull. */ - GPIO_AF_OUTPUT_OD = (GPIO_CR_CNF_AF_OUTPUT_OD | - GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function - output open drain. */ - GPIO_INPUT_ANALOG = (GPIO_CR_CNF_INPUT_ANALOG | - GPIO_CR_MODE_INPUT), /**< Analog input. */ - GPIO_INPUT_FLOATING = (GPIO_CR_CNF_INPUT_FLOATING | - GPIO_CR_MODE_INPUT), /**< Input floating. */ - GPIO_INPUT_PD = (GPIO_CR_CNF_INPUT_PU_PD | - GPIO_CR_MODE_INPUT), /**< Input pull-down. */ - GPIO_INPUT_PU /**< Input pull-up. */ - /* GPIO_INPUT_PU treated as a special case, for ODR twiddling */ + /** Output push-pull. */ + GPIO_OUTPUT_PP = GPIO_CR_CNF_OUTPUT_PP | GPIO_CR_MODE_OUTPUT_50MHZ, + /** Output open-drain. */ + GPIO_OUTPUT_OD = GPIO_CR_CNF_OUTPUT_OD | GPIO_CR_MODE_OUTPUT_50MHZ, + /** Alternate function output push-pull. */ + GPIO_AF_OUTPUT_PP = GPIO_CR_CNF_AF_OUTPUT_PP | GPIO_CR_MODE_OUTPUT_50MHZ, + /** Alternate function output open drain. */ + GPIO_AF_OUTPUT_OD = GPIO_CR_CNF_AF_OUTPUT_OD | GPIO_CR_MODE_OUTPUT_50MHZ, + /** Analog input. */ + GPIO_INPUT_ANALOG = GPIO_CR_CNF_INPUT_ANALOG | GPIO_CR_MODE_INPUT, + /** Input floating. */ + GPIO_INPUT_FLOATING = GPIO_CR_CNF_INPUT_FLOATING | GPIO_CR_MODE_INPUT, + /** Input pull-down. */ + GPIO_INPUT_PD = GPIO_CR_CNF_INPUT_PU_PD | GPIO_CR_MODE_INPUT, + /** Input pull-up. */ + GPIO_INPUT_PU, /* (treated a special case, for ODR twiddling) */ } gpio_pin_mode; -/* - * GPIO Convenience routines - */ - -void gpio_init(gpio_dev *dev); -void gpio_init_all(void); -void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); - -/** - * @brief Get a GPIO port's corresponding afio_exti_port. - * @param dev GPIO device whose afio_exti_port to return. - */ -static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { - return dev->exti_port; -} - -/** - * Set or reset a GPIO pin. - * - * Pin must have previously been configured to output mode. - * - * @param dev GPIO device whose pin to set. - * @param pin Pin on to set or reset - * @param val If true, set the pin. If false, reset the pin. - */ -static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { - if (val) { - dev->regs->BSRR = BIT(pin); - } else { - dev->regs->BRR = BIT(pin); - } -} - -/** - * Determine whether or not a GPIO pin is set. - * - * Pin must have previously been configured to input mode. - * - * @param dev GPIO device whose pin to test. - * @param pin Pin on dev to test. - * @return True if the pin is set, false otherwise. - */ -static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { - return dev->regs->IDR & BIT(pin); -} - -/** - * Toggle a pin configured as output push-pull. - * @param dev GPIO device. - * @param pin Pin on dev to toggle. - */ -static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { - dev->regs->ODR = dev->regs->ODR ^ BIT(pin); -} +/* Hacks for F2: */ +#define GPIO_MODE_ANALOG GPIO_INPUT_ANALOG +#define GPIO_MODE_OUTPUT GPIO_OUTPUT_PP /* * AFIO register map @@ -223,19 +145,14 @@ static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { /** AFIO register map */ typedef struct afio_reg_map { - __io uint32 EVCR; /**< Event control register. */ - __io uint32 MAPR; /**< AF remap and debug I/O configuration - register. */ - __io uint32 EXTICR1; /**< External interrupt configuration - register 1. */ - __io uint32 EXTICR2; /**< External interrupt configuration - register 2. */ - __io uint32 EXTICR3; /**< External interrupt configuration - register 3. */ - __io uint32 EXTICR4; /**< External interrupt configuration - register 4. */ - __io uint32 MAPR2; /**< AF remap and debug I/O configuration - register 2. */ + __io uint32 EVCR; /**< Event control register. */ + __io uint32 MAPR; /**< AF remap and debug I/O configuration register. */ + __io uint32 EXTICR1; /**< External interrupt configuration register 1. */ + __io uint32 EXTICR2; /**< External interrupt configuration register 2. */ + __io uint32 EXTICR3; /**< External interrupt configuration register 3. */ + __io uint32 EXTICR4; /**< External interrupt configuration register 4. */ + __io uint32 MAPR2; /**< + * AF remap and debug I/O configuration register 2. */ } afio_reg_map; /** AFIO register map base pointer. */ @@ -277,17 +194,17 @@ typedef struct afio_reg_map { #define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24) #define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24) #define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24) -#define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20) -#define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19) -#define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18) -#define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17) -#define AFIO_MAPR_TIM5CH4_IREMAP BIT(16) -#define AFIO_MAPR_PD01_REMAP BIT(15) +#define AFIO_MAPR_ADC2_ETRGREG_REMAP (1U << 20) +#define AFIO_MAPR_ADC2_ETRGINJ_REMAP (1U << 19) +#define AFIO_MAPR_ADC1_ETRGREG_REMAP (1U << 18) +#define AFIO_MAPR_ADC1_ETRGINJ_REMAP (1U << 17) +#define AFIO_MAPR_TIM5CH4_IREMAP (1U << 16) +#define AFIO_MAPR_PD01_REMAP (1U << 15) #define AFIO_MAPR_CAN_REMAP (0x3 << 13) #define AFIO_MAPR_CAN_REMAP_NONE (0x0 << 13) #define AFIO_MAPR_CAN_REMAP_PB8_PB9 (0x2 << 13) #define AFIO_MAPR_CAN_REMAP_PD0_PD1 (0x3 << 13) -#define AFIO_MAPR_TIM4_REMAP BIT(12) +#define AFIO_MAPR_TIM4_REMAP (1U << 12) #define AFIO_MAPR_TIM3_REMAP (0x3 << 10) #define AFIO_MAPR_TIM3_REMAP_NONE (0x0 << 10) #define AFIO_MAPR_TIM3_REMAP_PARTIAL (0x2 << 10) @@ -305,10 +222,10 @@ typedef struct afio_reg_map { #define AFIO_MAPR_USART3_REMAP_NONE (0x0 << 4) #define AFIO_MAPR_USART3_REMAP_PARTIAL (0x1 << 4) #define AFIO_MAPR_USART3_REMAP_FULL (0x3 << 4) -#define AFIO_MAPR_USART2_REMAP BIT(3) -#define AFIO_MAPR_USART1_REMAP BIT(2) -#define AFIO_MAPR_I2C1_REMAP BIT(1) -#define AFIO_MAPR_SPI1_REMAP BIT(0) +#define AFIO_MAPR_USART2_REMAP (1U << 3) +#define AFIO_MAPR_USART1_REMAP (1U << 2) +#define AFIO_MAPR_I2C1_REMAP (1U << 1) +#define AFIO_MAPR_SPI1_REMAP (1U << 0) /* External interrupt configuration register 1 */ @@ -382,12 +299,12 @@ typedef struct afio_reg_map { /* AF remap and debug I/O configuration register 2 */ -#define AFIO_MAPR2_FSMC_NADV BIT(10) -#define AFIO_MAPR2_TIM14_REMAP BIT(9) -#define AFIO_MAPR2_TIM13_REMAP BIT(8) -#define AFIO_MAPR2_TIM11_REMAP BIT(7) -#define AFIO_MAPR2_TIM10_REMAP BIT(6) -#define AFIO_MAPR2_TIM9_REMAP BIT(5) +#define AFIO_MAPR2_FSMC_NADV (1U << 10) +#define AFIO_MAPR2_TIM14_REMAP (1U << 9) +#define AFIO_MAPR2_TIM13_REMAP (1U << 8) +#define AFIO_MAPR2_TIM11_REMAP (1U << 7) +#define AFIO_MAPR2_TIM10_REMAP (1U << 6) +#define AFIO_MAPR2_TIM9_REMAP (1U << 5) /* * AFIO convenience routines @@ -395,95 +312,67 @@ typedef struct afio_reg_map { void afio_init(void); -/** - * External interrupt line numbers. - */ -typedef enum afio_exti_num { - AFIO_EXTI_0, /**< External interrupt line 0. */ - AFIO_EXTI_1, /**< External interrupt line 1. */ - AFIO_EXTI_2, /**< External interrupt line 2. */ - AFIO_EXTI_3, /**< External interrupt line 3. */ - AFIO_EXTI_4, /**< External interrupt line 4. */ - AFIO_EXTI_5, /**< External interrupt line 5. */ - AFIO_EXTI_6, /**< External interrupt line 6. */ - AFIO_EXTI_7, /**< External interrupt line 7. */ - AFIO_EXTI_8, /**< External interrupt line 8. */ - AFIO_EXTI_9, /**< External interrupt line 9. */ - AFIO_EXTI_10, /**< External interrupt line 10. */ - AFIO_EXTI_11, /**< External interrupt line 11. */ - AFIO_EXTI_12, /**< External interrupt line 12. */ - AFIO_EXTI_13, /**< External interrupt line 13. */ - AFIO_EXTI_14, /**< External interrupt line 14. */ - AFIO_EXTI_15, /**< External interrupt line 15. */ -} afio_exti_num; - -void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); - /* HACK: Use upper bit to denote MAPR2, Bit 31 is reserved and * not used in either MAPR or MAPR2 */ -#define AFIO_REMAP_USE_MAPR2 (1 << 31) +#define AFIO_REMAP_USE_MAPR2 (1U << 31) /** * @brief Available peripheral remaps. * @see afio_remap() */ typedef enum afio_remap_peripheral { - AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP, /**< - ADC 2 external trigger regular conversion remapping */ - AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP, /**< - ADC 2 external trigger injected conversion remapping */ - AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP, /**< - ADC 1 external trigger regular conversion remapping */ - AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP, /**< - ADC 1 external trigger injected conversion remapping */ - AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP, /**< - Timer 5 channel 4 internal remapping */ - AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP, /**< - Port D0/Port D1 mapping on OSC_IN/OSC_OUT */ - AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9, /**< - CAN alternate function remapping 1 (RX on PB8, TX on PB9) */ - AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1, /**< - CAN alternate function remapping 2 (RX on PD0, TX on PD1) */ - AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP, /**< - Timer 4 remapping */ - AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL, /**< - Timer 3 partial remapping */ - AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL, /**< - Timer 3 full remapping */ - AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3, /**< - Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3, CH3 - on PA2, CH4 on PA3) */ - AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, /**< - Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, CH3 - on PB10, CH4 on PB11) */ - AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, /**< - Timer 2 full remapping */ - AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP, /**< - USART 2 remapping */ - AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP, /**< - USART 1 remapping */ - AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP, /**< - I2C 1 remapping */ - AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP, /**< - SPI 1 remapping */ - AFIO_REMAP_FSMC_NADV = (AFIO_MAPR2_FSMC_NADV | - AFIO_REMAP_USE_MAPR2), /**< - NADV signal not connected */ - AFIO_REMAP_TIM14 = (AFIO_MAPR2_TIM14_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 14 remapping */ - AFIO_REMAP_TIM13 = (AFIO_MAPR2_TIM13_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 13 remapping */ - AFIO_REMAP_TIM11 = (AFIO_MAPR2_TIM11_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 11 remapping */ - AFIO_REMAP_TIM10 = (AFIO_MAPR2_TIM10_REMAP | - AFIO_REMAP_USE_MAPR2), /**< - Timer 10 remapping */ - AFIO_REMAP_TIM9 = (AFIO_MAPR2_TIM9_REMAP | - AFIO_REMAP_USE_MAPR2) /**< - Timer 9 */ + /** ADC 2 external trigger regular conversion remapping */ + AFIO_REMAP_ADC2_ETRGREG = AFIO_MAPR_ADC2_ETRGREG_REMAP, + /** ADC 2 external trigger injected conversion remapping */ + AFIO_REMAP_ADC2_ETRGINJ = AFIO_MAPR_ADC2_ETRGINJ_REMAP, + /** ADC 1 external trigger regular conversion remapping */ + AFIO_REMAP_ADC1_ETRGREG = AFIO_MAPR_ADC1_ETRGREG_REMAP, + /** ADC 1 external trigger injected conversion remapping */ + AFIO_REMAP_ADC1_ETRGINJ = AFIO_MAPR_ADC1_ETRGINJ_REMAP, + /** Timer 5 channel 4 internal remapping */ + AFIO_REMAP_TIM5CH4_I = AFIO_MAPR_TIM5CH4_IREMAP, + /** Port D0/Port D1 mapping on OSC_IN/OSC_OUT */ + AFIO_REMAP_PD01 = AFIO_MAPR_PD01_REMAP, + /** CAN alternate function remapping 1 (RX on PB8, TX on PB9) */ + AFIO_REMAP_CAN_1 = AFIO_MAPR_CAN_REMAP_PB8_PB9, + /** CAN alternate function remapping 2 (RX on PD0, TX on PD1) */ + AFIO_REMAP_CAN_2 = AFIO_MAPR_CAN_REMAP_PD0_PD1, + /** Timer 4 remapping */ + AFIO_REMAP_TIM4 = AFIO_MAPR_TIM4_REMAP, + /** Timer 3 partial remapping */ + AFIO_REMAP_TIM3_PARTIAL = AFIO_MAPR_TIM3_REMAP_PARTIAL, + /** Timer 3 full remapping */ + AFIO_REMAP_TIM3_FULL = AFIO_MAPR_TIM3_REMAP_FULL, + /** + * Timer 2 partial remapping 1 (CH1 and ETR on PA15, CH2 on PB3, + * CH3 on PA2, CH4 on PA3) */ + AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3, + /** + * Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1, + * CH3 on PB10, CH4 on PB11) */ + AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11, + /** Timer 2 full remapping */ + AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL, + /** USART 2 remapping */ + AFIO_REMAP_USART2 = AFIO_MAPR_USART2_REMAP, + /** USART 1 remapping */ + AFIO_REMAP_USART1 = AFIO_MAPR_USART1_REMAP, + /** I2C 1 remapping */ + AFIO_REMAP_I2C1 = AFIO_MAPR_I2C1_REMAP, + /** SPI 1 remapping */ + AFIO_REMAP_SPI1 = AFIO_MAPR_SPI1_REMAP, + /** NADV signal not connected */ + AFIO_REMAP_FSMC_NADV = AFIO_MAPR2_FSMC_NADV | AFIO_REMAP_USE_MAPR2, + /** Timer 14 remapping */ + AFIO_REMAP_TIM14 = AFIO_MAPR2_TIM14_REMAP | AFIO_REMAP_USE_MAPR2, + /** Timer 13 remapping */ + AFIO_REMAP_TIM13 = AFIO_MAPR2_TIM13_REMAP | AFIO_REMAP_USE_MAPR2, + /** Timer 11 remapping */ + AFIO_REMAP_TIM11 = AFIO_MAPR2_TIM11_REMAP | AFIO_REMAP_USE_MAPR2, + /** Timer 10 remapping */ + AFIO_REMAP_TIM10 = AFIO_MAPR2_TIM10_REMAP | AFIO_REMAP_USE_MAPR2, + /** Timer 9 remapping */ + AFIO_REMAP_TIM9 = AFIO_MAPR2_TIM9_REMAP | AFIO_REMAP_USE_MAPR2, } afio_remap_peripheral; void afio_remap(afio_remap_peripheral p); @@ -497,16 +386,14 @@ void afio_remap(afio_remap_peripheral p); * @see afio_cfg_debug_ports() */ typedef enum afio_debug_cfg { - AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, /**< - Full Serial Wire and JTAG debug */ - AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, /**< - Full Serial Wire and JTAG, but no NJTRST. */ - AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, /**< - Serial Wire debug only (JTAG-DP disabled, - SW-DP enabled) */ - AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW /**< - No debug; all JTAG and SW pins are free - for use as GPIOs. */ + /** Full Serial Wire and JTAG debug */ + AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, + /** Full Serial Wire and JTAG, but no NJTRST. */ + AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, + /** Serial Wire debug only (JTAG-DP disabled, SW-DP enabled) */ + AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, + /** No debug; all JTAG and SW pins are free for use as GPIOs. */ + AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW, } afio_debug_cfg; /** @@ -519,9 +406,88 @@ static inline void afio_cfg_debug_ports(afio_debug_cfg config) { *mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; } +/* + * Deprecated bits + */ + +/** + * @brief Deprecated. Use exti_cfg instead. + * + * In previous versions of libmaple, exti_attach_interrupt() took an + * afio_exti_port argument; afio_exti_port was also a member of struct + * gpio_dev. This isn't portable, so we now use exti_cfg + * instead. This typedef (and the macros AFIO_EXTI_PA, ..., + * AFIO_EXTI_PG) exist to preserve backwards compatibility. + */ +typedef exti_cfg afio_exti_port; + +/** Deprecated. Use EXTI_PA instead. */ +#define AFIO_EXTI_PA EXTI_PA +/** Deprecated. Use EXTI_PB instead. */ +#define AFIO_EXTI_PB EXTI_PB +/** Deprecated. Use EXTI_PC instead. */ +#define AFIO_EXTI_PC EXTI_PC +/** Deprecated. Use EXTI_PD instead. */ +#define AFIO_EXTI_PD EXTI_PD +/** Deprecated. Use EXTI_PE instead. */ +#define AFIO_EXTI_PE EXTI_PE +/** Deprecated. Use EXTI_PF instead. */ +#define AFIO_EXTI_PF EXTI_PF +/** Deprecated. Use EXTI_PG instead. */ +#define AFIO_EXTI_PG EXTI_PG + +/** + * @brief Deprecated. Use exti_num instead. + * + * In previous versions of libmaple, exti_attach_interrupt() took an + * afio_exti_num argument. This isn't portable, so we use exti_num + * instead. This typedef (and the macros AFIO_EXTI_0, ..., + * AFIO_EXTI_15) exist to preserve backwards compatibility. + */ +typedef exti_num afio_exti_num; + +/** Deprecated. Use EXTI0 instead. */ +#define AFIO_EXTI_0 EXTI0 +/** Deprecated. Use EXTI1 instead. */ +#define AFIO_EXTI_1 EXTI1 +/** Deprecated. Use EXTI2 instead. */ +#define AFIO_EXTI_2 EXTI2 +/** Deprecated. Use EXTI3 instead. */ +#define AFIO_EXTI_3 EXTI3 +/** Deprecated. Use EXTI4 instead. */ +#define AFIO_EXTI_4 EXTI4 +/** Deprecated. Use EXTI5 instead. */ +#define AFIO_EXTI_5 EXTI5 +/** Deprecated. Use EXTI6 instead. */ +#define AFIO_EXTI_6 EXTI6 +/** Deprecated. Use EXTI7 instead. */ +#define AFIO_EXTI_7 EXTI7 +/** Deprecated. Use EXTI8 instead. */ +#define AFIO_EXTI_8 EXTI8 +/** Deprecated. Use EXTI9 instead. */ +#define AFIO_EXTI_9 EXTI9 +/** Deprecated. Use EXTI10 instead. */ +#define AFIO_EXTI_10 EXTI10 +/** Deprecated. Use EXTI11 instead. */ +#define AFIO_EXTI_11 EXTI11 +/** Deprecated. Use EXTI12 instead. */ +#define AFIO_EXTI_12 EXTI12 +/** Deprecated. Use EXTI13 instead. */ +#define AFIO_EXTI_13 EXTI13 +/** Deprecated. Use EXTI14 instead. */ +#define AFIO_EXTI_14 EXTI14 +/** Deprecated. Use EXTI15 instead. */ +#define AFIO_EXTI_15 EXTI15 + +/** + * @brief Deprecated. Use exti_select(exti, port) instead. + */ +static __always_inline void afio_exti_select(exti_num exti, exti_cfg port) { + exti_select(exti, port); +} + #ifdef __cplusplus } #endif #endif - diff --git a/libmaple/stm32f1/include/series/i2c.h b/libmaple/stm32f1/include/series/i2c.h new file mode 100644 index 0000000..a0822e8 --- /dev/null +++ b/libmaple/stm32f1/include/series/i2c.h @@ -0,0 +1,85 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung (from <libmaple/i2c.h>). + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/include/stm32f1/include/series/i2c.h + * @brief STM32F1 I2C + */ + +#ifndef _LIBMAPLE_STM32F1_I2C_H_ +#define _LIBMAPLE_STM32F1_I2C_H_ + +#include <libmaple/i2c_common.h> +#include <libmaple/gpio.h> +#include <libmaple/stm32.h> + +/* + * Register maps + */ + +struct i2c_reg_map; + +/** STM32F1 I2C1 register map base pointer */ +#define I2C1_BASE ((struct i2c_reg_map*)0x40005400) +/** STM32F1 I2C2 register map base pointer */ +#define I2C2_BASE ((struct i2c_reg_map*)0x40005800) + +/* + * Devices + */ + +extern i2c_dev* const I2C1; +extern i2c_dev* const I2C2; + +/* + * For internal use + */ + +static inline uint32 _i2c_bus_clk(i2c_dev *dev) { + /* Both I2C peripherals are on APB1 */ + return STM32_PCLK1 / (1000 * 1000); +} + +#define _I2C_HAVE_IRQ_FIXUP 1 +void _i2c_irq_priority_fixup(i2c_dev *dev); + +/* + * Deprecated functionality + */ + +/* Flag to use alternate pin mapping in i2c_master_enable(). */ +#define _I2C_HAVE_DEPRECATED_I2C_REMAP 1 +#define I2C_REMAP 0x4 +static inline void _i2c_handle_remap(i2c_dev *dev, uint32 flags) { + if ((dev == I2C1) && (flags & I2C_REMAP)) { + afio_remap(AFIO_REMAP_I2C1); + I2C1->sda_pin = 9; + I2C1->scl_pin = 8; + } +} + +#endif /* _LIBMAPLE_STM32F1_I2C_H_ */ diff --git a/libmaple/nvic.h b/libmaple/stm32f1/include/series/nvic.h index feb7335..cdac737 100644 --- a/libmaple/nvic.h +++ b/libmaple/stm32f1/include/series/nvic.h @@ -25,63 +25,23 @@ *****************************************************************************/ /** - * @file nvic.h - * @brief Nested vector interrupt controller support. - * - * Basic usage: - * - * @code - * // Initialise the interrupt controller and point to the vector - * // table at the start of flash. - * nvic_init(0x08000000, 0); - * // Bind in a timer interrupt handler - * timer_attach_interrupt(TIMER_CC1_INTERRUPT, handler); - * // Optionally set the priority - * nvic_irq_set_priority(NVIC_TIMER1_CC, 5); - * // All done, enable all interrupts - * nvic_globalirq_enable(); - * @endcode + * @file libmaple/stm32f1/include/series/nvic.h + * @brief STM32F1 Nested Vectored Interrupt Controller (NVIC) support. */ -#ifndef _NVIC_H_ -#define _NVIC_H_ - -#include "libmaple_types.h" -#include "util.h" +#ifndef _LIBMAPLE_STM32F1_NVIC_H_ +#define _LIBMAPLE_STM32F1_NVIC_H_ #ifdef __cplusplus extern "C"{ #endif -/** NVIC register map type. */ -typedef struct nvic_reg_map { - __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */ - uint32 RESERVED0[24]; /**< Reserved */ - __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ - uint32 RSERVED1[24]; /**< Reserved */ - __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ - uint32 RESERVED2[24]; /**< Reserved */ - __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ - uint32 RESERVED3[24]; /**< Reserved */ - __io uint32 IABR[8]; /**< Interrupt Active bit Registers */ - uint32 RESERVED4[56]; /**< Reserved */ - __io uint8 IP[240]; /**< Interrupt Priority Registers */ - uint32 RESERVED5[644]; /**< Reserved */ - __io uint32 STIR; /**< Software Trigger Interrupt Registers */ -} nvic_reg_map; - -/** NVIC register map base pointer. */ -#define NVIC_BASE ((struct nvic_reg_map*)0xE000E100) +#include <libmaple/libmaple_types.h> +#include <libmaple/stm32.h> /** - * @brief Interrupt vector table interrupt numbers. - * - * Each positive-valued enumerator is the position of the - * corresponding interrupt in the vector table. Negative-valued - * enumerators correspond to interrupts controlled by the system - * handler block. - * - * @see scb.h + * @brief STM32F1 interrupt vector table interrupt numbers. + * @see <libmaple/scb.h> */ typedef enum nvic_irq_num { NVIC_NMI = -14, /**< Non-maskable interrupt */ @@ -119,9 +79,11 @@ typedef enum nvic_irq_num { NVIC_CAN_RX1 = 21, /**< CAN RX1 */ NVIC_CAN_SCE = 22, /**< CAN SCE */ NVIC_EXTI_9_5 = 23, /**< EXTI line [9:5] */ - NVIC_TIMER1_BRK = 24, /**< Timer 1 break */ - NVIC_TIMER1_UP = 25, /**< Timer 1 update */ - NVIC_TIMER1_TRG_COM = 26, /**< Timer 1 trigger and commutation */ + NVIC_TIMER1_BRK_TIMER9 = 24, /**< Timer 1 break, Timer 9. */ + NVIC_TIMER1_UP_TIMER10 = 25, /**< Timer 1 update, Timer 10. */ + NVIC_TIMER1_TRG_COM_TIMER11 = 26, /**< + * Timer 1 trigger and commutation, + * Timer 11. */ NVIC_TIMER1_CC = 27, /**< Timer 1 capture/compare */ NVIC_TIMER2 = 28, /**< Timer 2 */ NVIC_TIMER3 = 29, /**< Timer 3 */ @@ -139,11 +101,12 @@ typedef enum nvic_irq_num { NVIC_RTCALARM = 41, /**< RTC alarm through EXTI line */ NVIC_USBWAKEUP = 42, /**< USB wakeup from suspend through EXTI line */ - NVIC_TIMER8_BRK = 43, /**< Timer 8 break */ - NVIC_TIMER8_UP = 44, /**< Timer 8 update */ - NVIC_TIMER8_TRG_COM = 45, /**< Timer 8 trigger and commutation */ + NVIC_TIMER8_BRK_TIMER12 = 43, /**< Timer 8 break, timer 12 */ + NVIC_TIMER8_UP_TIMER13 = 44, /**< Timer 8 update, timer 13 */ + NVIC_TIMER8_TRG_COM_TIMER14 = 45, /**< + * Timer 8 trigger and commutation, + * Timer 14. */ NVIC_TIMER8_CC = 46, /**< Timer 8 capture/compare */ -#ifdef STM32_HIGH_DENSITY NVIC_ADC3 = 47, /**< ADC3 */ NVIC_FSMC = 48, /**< FSMC */ NVIC_SDIO = 49, /**< SDIO */ @@ -157,81 +120,50 @@ typedef enum nvic_irq_num { NVIC_DMA2_CH2 = 57, /**< DMA2 channel 2 */ NVIC_DMA2_CH3 = 58, /**< DMA2 channel 3 */ NVIC_DMA2_CH_4_5 = 59, /**< DMA2 channels 4 and 5 */ -#endif -} nvic_irq_num; - -/* - * Initialises the interrupt controller and sets all interrupts to the - * lowest priority. - * - * For stand-alone products, the base address is normally the start of - * flash (0x08000000). - * - * @param vector_table_address base address of the vector table - */ -void nvic_init(uint32 vector_table_address, uint32 offset); - -/** - * Sets the base address of the vector table. - */ -void nvic_set_vector_table(uint32 address, uint32 offset); - -void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority); -void nvic_sys_reset(); - -/** - * Enables interrupts and configurable fault handlers (clear PRIMASK). - */ -static inline void nvic_globalirq_enable() { - asm volatile("cpsie i"); -} - -/** - * Disable interrupts and configurable fault handlers (set PRIMASK). - */ -static inline void nvic_globalirq_disable() { - asm volatile("cpsid i"); -} - -/** - * @brief Enable interrupt irq_num - * @param irq_num Interrupt to enable - */ -static inline void nvic_irq_enable(nvic_irq_num irq_num) { - if (irq_num < 0) { - return; - } - NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32); -} -/** - * @brief Disable interrupt irq_num - * @param irq_num Interrupt to disable - */ -static inline void nvic_irq_disable(nvic_irq_num irq_num) { - if (irq_num < 0) { - return; - } - NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32); -} + /* Old enumerators kept around for backwards compatibility: */ + NVIC_TIMER1_BRK = + NVIC_TIMER1_BRK_TIMER9, /**< @brief (Deprecated) Timer 1 break + * + * For backwards compatibility only. + * Use NVIC_TIMER1_BRK_TIMER9 instead. */ + NVIC_TIMER1_UP = + NVIC_TIMER1_UP_TIMER10, /**< @brief (Deprecated) Timer 1 update. + * + * For backwards compatibility only. + * Use NVIC_TIMER1_UP_TIMER10 instead. */ + NVIC_TIMER1_TRG_COM = + NVIC_TIMER1_TRG_COM_TIMER11, /**< @brief (deprecated) Timer 1 trigger + * and commutation. + * + * For backwards compatibility only. + * Use NVIC_TIMER1_TRG_COM_TIMER11 + * instead. */ + NVIC_TIMER8_BRK = + NVIC_TIMER8_BRK_TIMER12, /**< @brief (deprecated) Timer 8 break + * + * For backwards compatibility only. + * Use NVIC_TIMER8_BRK_TIMER12 instead. */ + NVIC_TIMER8_UP = + NVIC_TIMER8_UP_TIMER13, /**< @brief (deprecated) Timer 8 update + * For backwards compatibility only. + * Use NVIC_TIMER8_UP_TIMER13 instead. */ + NVIC_TIMER8_TRG_COM = + NVIC_TIMER8_TRG_COM_TIMER14, /**< @brief (deprecated) Timer 8 trigger + * and commutation. + * For backwards compatibility only. + * Use NVIC_TIMER8_TRG_COM_TIMER14 + * instead. */ +} nvic_irq_num; -/** - * @brief Quickly disable all interrupts. - * - * Calling this function is significantly faster than calling - * nvic_irq_disable() in a loop. - */ static inline void nvic_irq_disable_all(void) { - /* Note: This only works up to XL density. The fix for - * connectivity line is: - * - * NVIC_BASE->ICER[2] = 0xF; - * - * We don't support connectivity line devices (yet), so leave it - * alone for now. - */ + /* Even low-density devices have over 32 interrupt lines. */ NVIC_BASE->ICER[0] = 0xFFFFFFFF; NVIC_BASE->ICER[1] = 0xFFFFFFFF; +#if STM32_NR_INTERRUPTS > 64 + /* Only some have over 64; e.g. connectivity line MCUs. */ + NVIC_BASE->ICER[2] = 0xFFFFFFFF; +#endif } #ifdef __cplusplus diff --git a/libmaple/stm32f1/include/series/pwr.h b/libmaple/stm32f1/include/series/pwr.h new file mode 100644 index 0000000..e143a8c --- /dev/null +++ b/libmaple/stm32f1/include/series/pwr.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/pwr.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F1 Power control (PWR) support. + */ + +#ifndef _LIBMAPLE_STM32F1_PWR_H_ +#define _LIBMAPLE_STM32F1_PWR_H_ + +/* + * Register bit definitions + */ + +/* Control register */ + +/* PVD level selection */ +#define PWR_CR_PLS_2_2V (0x0 << 5) +#define PWR_CR_PLS_2_3V (0x1 << 5) +#define PWR_CR_PLS_2_4V (0x2 << 5) +#define PWR_CR_PLS_2_5V (0x3 << 5) +#define PWR_CR_PLS_2_6V (0x4 << 5) +#define PWR_CR_PLS_2_7V (0x5 << 5) +#define PWR_CR_PLS_2_8V (0x6 << 5) +#define PWR_CR_PLS_2_9V (0x7 << 5) + +#endif diff --git a/libmaple/rcc.h b/libmaple/stm32f1/include/series/rcc.h index c50686c..225ca49 100644 --- a/libmaple/rcc.h +++ b/libmaple/stm32f1/include/series/rcc.h @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,20 +26,24 @@ *****************************************************************************/ /** - * @file rcc.h - * @brief reset and clock control definitions and prototypes + * @file libmaple/stm32f1/include/series/rcc.h + * @brief STM32F1 reset and clock control (RCC) support. */ -#include "libmaple_types.h" - -#ifndef _RCC_H_ -#define _RCC_H_ +#ifndef _LIBMAPLE_STM32F1_RCC_H_ +#define _LIBMAPLE_STM32F1_RCC_H_ #ifdef __cplusplus extern "C"{ #endif -/** RCC register map type */ +#include <libmaple/libmaple_types.h> + +/* + * Register map + */ + +/** STM32F1 RCC register map type */ typedef struct rcc_reg_map { __io uint32 CR; /**< Clock control register */ __io uint32 CFGR; /**< Clock configuration register */ @@ -52,7 +57,6 @@ typedef struct rcc_reg_map { __io uint32 CSR; /**< Control/status register */ } rcc_reg_map; -/** RCC register map base pointer */ #define RCC_BASE ((struct rcc_reg_map*)0x40021000) /* @@ -70,16 +74,16 @@ typedef struct rcc_reg_map { #define RCC_CR_HSIRDY_BIT 1 #define RCC_CR_HSION_BIT 0 -#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) -#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) -#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) -#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) -#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) -#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) +#define RCC_CR_PLLRDY (1U << RCC_CR_PLLRDY_BIT) +#define RCC_CR_PLLON (1U << RCC_CR_PLLON_BIT) +#define RCC_CR_CSSON (1U << RCC_CR_CSSON_BIT) +#define RCC_CR_HSEBYP (1U << RCC_CR_HSEBYP_BIT) +#define RCC_CR_HSERDY (1U << RCC_CR_HSERDY_BIT) +#define RCC_CR_HSEON (1U << RCC_CR_HSEON_BIT) #define RCC_CR_HSICAL (0xFF << 8) #define RCC_CR_HSITRIM (0x1F << 3) -#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) -#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) +#define RCC_CR_HSIRDY (1U << RCC_CR_HSIRDY_BIT) +#define RCC_CR_HSION (1U << RCC_CR_HSION_BIT) /* Clock configuration register */ @@ -88,10 +92,10 @@ typedef struct rcc_reg_map { #define RCC_CFGR_PLLSRC_BIT 16 #define RCC_CFGR_MCO (0x3 << 24) -#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) +#define RCC_CFGR_USBPRE (1U << RCC_CFGR_USBPRE_BIT) #define RCC_CFGR_PLLMUL (0xF << 18) -#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) -#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) +#define RCC_CFGR_PLLXTPRE (1U << RCC_CFGR_PLLXTPRE_BIT) +#define RCC_CFGR_PLLSRC (1U << RCC_CFGR_PLLSRC_BIT) #define RCC_CFGR_ADCPRE (0x3 << 14) #define RCC_CFGR_PPRE2 (0x7 << 11) #define RCC_CFGR_PPRE1 (0x7 << 8) @@ -123,23 +127,23 @@ typedef struct rcc_reg_map { #define RCC_CIR_LSERDYF_BIT 1 #define RCC_CIR_LSIRDYF_BIT 0 -#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) -#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) -#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) -#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) -#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) -#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) -#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) -#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) -#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) -#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) -#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) -#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) -#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) -#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) -#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) -#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) -#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) +#define RCC_CIR_CSSC (1U << RCC_CIR_CSSC_BIT) +#define RCC_CIR_PLLRDYC (1U << RCC_CIR_PLLRDYC_BIT) +#define RCC_CIR_HSERDYC (1U << RCC_CIR_HSERDYC_BIT) +#define RCC_CIR_HSIRDYC (1U << RCC_CIR_HSIRDYC_BIT) +#define RCC_CIR_LSERDYC (1U << RCC_CIR_LSERDYC_BIT) +#define RCC_CIR_LSIRDYC (1U << RCC_CIR_LSIRDYC_BIT) +#define RCC_CIR_PLLRDYIE (1U << RCC_CIR_PLLRDYIE_BIT) +#define RCC_CIR_HSERDYIE (1U << RCC_CIR_HSERDYIE_BIT) +#define RCC_CIR_HSIRDYIE (1U << RCC_CIR_HSIRDYIE_BIT) +#define RCC_CIR_LSERDYIE (1U << RCC_CIR_LSERDYIE_BIT) +#define RCC_CIR_LSIRDYIE (1U << RCC_CIR_LSIRDYIE_BIT) +#define RCC_CIR_CSSF (1U << RCC_CIR_CSSF_BIT) +#define RCC_CIR_PLLRDYF (1U << RCC_CIR_PLLRDYF_BIT) +#define RCC_CIR_HSERDYF (1U << RCC_CIR_HSERDYF_BIT) +#define RCC_CIR_HSIRDYF (1U << RCC_CIR_HSIRDYF_BIT) +#define RCC_CIR_LSERDYF (1U << RCC_CIR_LSERDYF_BIT) +#define RCC_CIR_LSIRDYF (1U << RCC_CIR_LSIRDYF_BIT) /* APB2 peripheral reset register */ @@ -162,24 +166,24 @@ typedef struct rcc_reg_map { #define RCC_APB2RSTR_IOPARST_BIT 2 #define RCC_APB2RSTR_AFIORST_BIT 0 -#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) -#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) -#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) -#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) -#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) -#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) -#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) -#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) -#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) -#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) -#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) -#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) -#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) -#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) -#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) -#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) -#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) -#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) +#define RCC_APB2RSTR_TIM11RST (1U << RCC_APB2RSTR_TIM11RST_BIT) +#define RCC_APB2RSTR_TIM10RST (1U << RCC_APB2RSTR_TIM10RST_BIT) +#define RCC_APB2RSTR_TIM9RST (1U << RCC_APB2RSTR_TIM9RST_BIT) +#define RCC_APB2RSTR_ADC3RST (1U << RCC_APB2RSTR_ADC3RST_BIT) +#define RCC_APB2RSTR_USART1RST (1U << RCC_APB2RSTR_USART1RST_BIT) +#define RCC_APB2RSTR_TIM8RST (1U << RCC_APB2RSTR_TIM8RST_BIT) +#define RCC_APB2RSTR_SPI1RST (1U << RCC_APB2RSTR_SPI1RST_BIT) +#define RCC_APB2RSTR_TIM1RST (1U << RCC_APB2RSTR_TIM1RST_BIT) +#define RCC_APB2RSTR_ADC2RST (1U << RCC_APB2RSTR_ADC2RST_BIT) +#define RCC_APB2RSTR_ADC1RST (1U << RCC_APB2RSTR_ADC1RST_BIT) +#define RCC_APB2RSTR_IOPGRST (1U << RCC_APB2RSTR_IOPGRST_BIT) +#define RCC_APB2RSTR_IOPFRST (1U << RCC_APB2RSTR_IOPFRST_BIT) +#define RCC_APB2RSTR_IOPERST (1U << RCC_APB2RSTR_IOPERST_BIT) +#define RCC_APB2RSTR_IOPDRST (1U << RCC_APB2RSTR_IOPDRST_BIT) +#define RCC_APB2RSTR_IOPCRST (1U << RCC_APB2RSTR_IOPCRST_BIT) +#define RCC_APB2RSTR_IOPBRST (1U << RCC_APB2RSTR_IOPBRST_BIT) +#define RCC_APB2RSTR_IOPARST (1U << RCC_APB2RSTR_IOPARST_BIT) +#define RCC_APB2RSTR_AFIORST (1U << RCC_APB2RSTR_AFIORST_BIT) /* APB1 peripheral reset register */ @@ -207,29 +211,29 @@ typedef struct rcc_reg_map { #define RCC_APB1RSTR_TIM3RST_BIT 1 #define RCC_APB1RSTR_TIM2RST_BIT 0 -#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) -#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) -#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) -#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) -#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) -#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) -#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) -#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) -#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) -#define RCC_APB1RSTR_USART3RST BIT(RCC_APB1RSTR_USART3RST_BIT) -#define RCC_APB1RSTR_USART2RST BIT(RCC_APB1RSTR_USART2RST_BIT) -#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) -#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) -#define RCC_APB1RSTR_WWDRST BIT(RCC_APB1RSTR_WWDRST_BIT) -#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) -#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) -#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) -#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) -#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) -#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) -#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) -#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) -#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) +#define RCC_APB1RSTR_DACRST (1U << RCC_APB1RSTR_DACRST_BIT) +#define RCC_APB1RSTR_PWRRST (1U << RCC_APB1RSTR_PWRRST_BIT) +#define RCC_APB1RSTR_BKPRST (1U << RCC_APB1RSTR_BKPRST_BIT) +#define RCC_APB1RSTR_CANRST (1U << RCC_APB1RSTR_CANRST_BIT) +#define RCC_APB1RSTR_USBRST (1U << RCC_APB1RSTR_USBRST_BIT) +#define RCC_APB1RSTR_I2C2RST (1U << RCC_APB1RSTR_I2C2RST_BIT) +#define RCC_APB1RSTR_I2C1RST (1U << RCC_APB1RSTR_I2C1RST_BIT) +#define RCC_APB1RSTR_UART5RST (1U << RCC_APB1RSTR_UART5RST_BIT) +#define RCC_APB1RSTR_UART4RST (1U << RCC_APB1RSTR_UART4RST_BIT) +#define RCC_APB1RSTR_USART3RST (1U << RCC_APB1RSTR_USART3RST_BIT) +#define RCC_APB1RSTR_USART2RST (1U << RCC_APB1RSTR_USART2RST_BIT) +#define RCC_APB1RSTR_SPI3RST (1U << RCC_APB1RSTR_SPI3RST_BIT) +#define RCC_APB1RSTR_SPI2RST (1U << RCC_APB1RSTR_SPI2RST_BIT) +#define RCC_APB1RSTR_WWDRST (1U << RCC_APB1RSTR_WWDRST_BIT) +#define RCC_APB1RSTR_TIM14RST (1U << RCC_APB1RSTR_TIM14RST_BIT) +#define RCC_APB1RSTR_TIM13RST (1U << RCC_APB1RSTR_TIM13RST_BIT) +#define RCC_APB1RSTR_TIM12RST (1U << RCC_APB1RSTR_TIM12RST_BIT) +#define RCC_APB1RSTR_TIM7RST (1U << RCC_APB1RSTR_TIM7RST_BIT) +#define RCC_APB1RSTR_TIM6RST (1U << RCC_APB1RSTR_TIM6RST_BIT) +#define RCC_APB1RSTR_TIM5RST (1U << RCC_APB1RSTR_TIM5RST_BIT) +#define RCC_APB1RSTR_TIM4RST (1U << RCC_APB1RSTR_TIM4RST_BIT) +#define RCC_APB1RSTR_TIM3RST (1U << RCC_APB1RSTR_TIM3RST_BIT) +#define RCC_APB1RSTR_TIM2RST (1U << RCC_APB1RSTR_TIM2RST_BIT) /* AHB peripheral clock enable register */ @@ -241,13 +245,13 @@ typedef struct rcc_reg_map { #define RCC_AHBENR_DMA2EN_BIT 1 #define RCC_AHBENR_DMA1EN_BIT 0 -#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) -#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) -#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) -#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) -#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) -#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) -#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) +#define RCC_AHBENR_SDIOEN (1U << RCC_AHBENR_SDIOEN_BIT) +#define RCC_AHBENR_FSMCEN (1U << RCC_AHBENR_FSMCEN_BIT) +#define RCC_AHBENR_CRCEN (1U << RCC_AHBENR_CRCEN_BIT) +#define RCC_AHBENR_FLITFEN (1U << RCC_AHBENR_FLITFEN_BIT) +#define RCC_AHBENR_SRAMEN (1U << RCC_AHBENR_SRAMEN_BIT) +#define RCC_AHBENR_DMA2EN (1U << RCC_AHBENR_DMA2EN_BIT) +#define RCC_AHBENR_DMA1EN (1U << RCC_AHBENR_DMA1EN_BIT) /* APB2 peripheral clock enable register */ @@ -270,24 +274,24 @@ typedef struct rcc_reg_map { #define RCC_APB2ENR_IOPAEN_BIT 2 #define RCC_APB2ENR_AFIOEN_BIT 0 -#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) -#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) -#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) -#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) -#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) -#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) -#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) -#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) -#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) -#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) -#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) -#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) -#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) -#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) -#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) -#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) -#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) -#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) +#define RCC_APB2ENR_TIM11EN (1U << RCC_APB2ENR_TIM11EN_BIT) +#define RCC_APB2ENR_TIM10EN (1U << RCC_APB2ENR_TIM10EN_BIT) +#define RCC_APB2ENR_TIM9EN (1U << RCC_APB2ENR_TIM9EN_BIT) +#define RCC_APB2ENR_ADC3EN (1U << RCC_APB2ENR_ADC3EN_BIT) +#define RCC_APB2ENR_USART1EN (1U << RCC_APB2ENR_USART1EN_BIT) +#define RCC_APB2ENR_TIM8EN (1U << RCC_APB2ENR_TIM8EN_BIT) +#define RCC_APB2ENR_SPI1EN (1U << RCC_APB2ENR_SPI1EN_BIT) +#define RCC_APB2ENR_TIM1EN (1U << RCC_APB2ENR_TIM1EN_BIT) +#define RCC_APB2ENR_ADC2EN (1U << RCC_APB2ENR_ADC2EN_BIT) +#define RCC_APB2ENR_ADC1EN (1U << RCC_APB2ENR_ADC1EN_BIT) +#define RCC_APB2ENR_IOPGEN (1U << RCC_APB2ENR_IOPGEN_BIT) +#define RCC_APB2ENR_IOPFEN (1U << RCC_APB2ENR_IOPFEN_BIT) +#define RCC_APB2ENR_IOPEEN (1U << RCC_APB2ENR_IOPEEN_BIT) +#define RCC_APB2ENR_IOPDEN (1U << RCC_APB2ENR_IOPDEN_BIT) +#define RCC_APB2ENR_IOPCEN (1U << RCC_APB2ENR_IOPCEN_BIT) +#define RCC_APB2ENR_IOPBEN (1U << RCC_APB2ENR_IOPBEN_BIT) +#define RCC_APB2ENR_IOPAEN (1U << RCC_APB2ENR_IOPAEN_BIT) +#define RCC_APB2ENR_AFIOEN (1U << RCC_APB2ENR_AFIOEN_BIT) /* APB1 peripheral clock enable register */ @@ -315,29 +319,29 @@ typedef struct rcc_reg_map { #define RCC_APB1ENR_TIM3EN_BIT 1 #define RCC_APB1ENR_TIM2EN_BIT 0 -#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) -#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) -#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) -#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) -#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) -#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) -#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) -#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) -#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) -#define RCC_APB1ENR_USART3EN BIT(RCC_APB1ENR_USART3EN_BIT) -#define RCC_APB1ENR_USART2EN BIT(RCC_APB1ENR_USART2EN_BIT) -#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) -#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) -#define RCC_APB1ENR_WWDEN BIT(RCC_APB1ENR_WWDEN_BIT) -#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) -#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) -#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) -#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) -#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) -#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) -#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) -#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) -#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) +#define RCC_APB1ENR_DACEN (1U << RCC_APB1ENR_DACEN_BIT) +#define RCC_APB1ENR_PWREN (1U << RCC_APB1ENR_PWREN_BIT) +#define RCC_APB1ENR_BKPEN (1U << RCC_APB1ENR_BKPEN_BIT) +#define RCC_APB1ENR_CANEN (1U << RCC_APB1ENR_CANEN_BIT) +#define RCC_APB1ENR_USBEN (1U << RCC_APB1ENR_USBEN_BIT) +#define RCC_APB1ENR_I2C2EN (1U << RCC_APB1ENR_I2C2EN_BIT) +#define RCC_APB1ENR_I2C1EN (1U << RCC_APB1ENR_I2C1EN_BIT) +#define RCC_APB1ENR_UART5EN (1U << RCC_APB1ENR_UART5EN_BIT) +#define RCC_APB1ENR_UART4EN (1U << RCC_APB1ENR_UART4EN_BIT) +#define RCC_APB1ENR_USART3EN (1U << RCC_APB1ENR_USART3EN_BIT) +#define RCC_APB1ENR_USART2EN (1U << RCC_APB1ENR_USART2EN_BIT) +#define RCC_APB1ENR_SPI3EN (1U << RCC_APB1ENR_SPI3EN_BIT) +#define RCC_APB1ENR_SPI2EN (1U << RCC_APB1ENR_SPI2EN_BIT) +#define RCC_APB1ENR_WWDEN (1U << RCC_APB1ENR_WWDEN_BIT) +#define RCC_APB1ENR_TIM14EN (1U << RCC_APB1ENR_TIM14EN_BIT) +#define RCC_APB1ENR_TIM13EN (1U << RCC_APB1ENR_TIM13EN_BIT) +#define RCC_APB1ENR_TIM12EN (1U << RCC_APB1ENR_TIM12EN_BIT) +#define RCC_APB1ENR_TIM7EN (1U << RCC_APB1ENR_TIM7EN_BIT) +#define RCC_APB1ENR_TIM6EN (1U << RCC_APB1ENR_TIM6EN_BIT) +#define RCC_APB1ENR_TIM5EN (1U << RCC_APB1ENR_TIM5EN_BIT) +#define RCC_APB1ENR_TIM4EN (1U << RCC_APB1ENR_TIM4EN_BIT) +#define RCC_APB1ENR_TIM3EN (1U << RCC_APB1ENR_TIM3EN_BIT) +#define RCC_APB1ENR_TIM2EN (1U << RCC_APB1ENR_TIM2EN_BIT) /* Backup domain control register */ @@ -347,15 +351,15 @@ typedef struct rcc_reg_map { #define RCC_BDCR_LSERDY_BIT 1 #define RCC_BDCR_LSEON_BIT 0 -#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) -#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTC_BIT) +#define RCC_BDCR_BDRST (1U << RCC_BDCR_BDRST_BIT) +#define RCC_BDCR_RTCEN (1U << RCC_BDCR_RTC_BIT) #define RCC_BDCR_RTCSEL (0x3 << 8) #define RCC_BDCR_RTCSEL_NONE (0x0 << 8) #define RCC_BDCR_RTCSEL_LSE (0x1 << 8) #define RCC_BDCR_RTCSEL_HSE (0x3 << 8) -#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) -#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) -#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) +#define RCC_BDCR_LSEBYP (1U << RCC_BDCR_LSEBYP_BIT) +#define RCC_BDCR_LSERDY (1U << RCC_BDCR_LSERDY_BIT) +#define RCC_BDCR_LSEON (1U << RCC_BDCR_LSEON_BIT) /* Control/status register */ @@ -369,136 +373,93 @@ typedef struct rcc_reg_map { #define RCC_CSR_LSIRDY_BIT 1 #define RCC_CSR_LSION_BIT 0 -#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) -#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) -#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) -#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) -#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) -#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) -#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) -#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) -#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) +#define RCC_CSR_LPWRRSTF (1U << RCC_CSR_LPWRRSTF_BIT) +#define RCC_CSR_WWDGRSTF (1U << RCC_CSR_WWDGRSTF_BIT) +#define RCC_CSR_IWDGRSTF (1U << RCC_CSR_IWDGRSTF_BIT) +#define RCC_CSR_SFTRSTF (1U << RCC_CSR_SFTRSTF_BIT) +#define RCC_CSR_PORRSTF (1U << RCC_CSR_PORRSTF_BIT) +#define RCC_CSR_PINRSTF (1U << RCC_CSR_PINRSTF_BIT) +#define RCC_CSR_RMVF (1U << RCC_CSR_RMVF_BIT) +#define RCC_CSR_LSIRDY (1U << RCC_CSR_LSIRDY_BIT) +#define RCC_CSR_LSION (1U << RCC_CSR_LSION_BIT) /* - * Convenience routines - */ - -/** - * SYSCLK sources - * @see rcc_clk_init() - */ -typedef enum rcc_sysclk_src { - RCC_CLKSRC_HSI = 0x0, - RCC_CLKSRC_HSE = 0x1, - RCC_CLKSRC_PLL = 0x2, -} rcc_sysclk_src; - -/** - * PLL entry clock source - * @see rcc_clk_init() - */ -typedef enum rcc_pllsrc { - RCC_PLLSRC_HSE = (0x1 << 16), - RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) -} rcc_pllsrc; - -/** - * PLL multipliers - * @see rcc_clk_init() + * libmaple-mandated enumeration types. */ -typedef enum rcc_pll_multiplier { - RCC_PLLMUL_2 = (0x0 << 18), - RCC_PLLMUL_3 = (0x1 << 18), - RCC_PLLMUL_4 = (0x2 << 18), - RCC_PLLMUL_5 = (0x3 << 18), - RCC_PLLMUL_6 = (0x4 << 18), - RCC_PLLMUL_7 = (0x5 << 18), - RCC_PLLMUL_8 = (0x6 << 18), - RCC_PLLMUL_9 = (0x7 << 18), - RCC_PLLMUL_10 = (0x8 << 18), - RCC_PLLMUL_11 = (0x9 << 18), - RCC_PLLMUL_12 = (0xA << 18), - RCC_PLLMUL_13 = (0xB << 18), - RCC_PLLMUL_14 = (0xC << 18), - RCC_PLLMUL_15 = (0xD << 18), - RCC_PLLMUL_16 = (0xE << 18), -} rcc_pll_multiplier; /** - * @brief Identifies bus and clock line for a peripheral. - * - * Also generally useful as a unique identifier for that peripheral - * (or its corresponding device struct). + * @brief STM32F1 rcc_clk_id. */ typedef enum rcc_clk_id { - RCC_GPIOA, - RCC_GPIOB, - RCC_GPIOC, - RCC_GPIOD, - RCC_AFIO, RCC_ADC1, RCC_ADC2, RCC_ADC3, - RCC_USART1, - RCC_USART2, - RCC_USART3, - RCC_TIMER1, - RCC_TIMER2, - RCC_TIMER3, - RCC_TIMER4, - RCC_SPI1, - RCC_SPI2, - RCC_DMA1, - RCC_PWR, + RCC_AFIO, RCC_BKP, - RCC_I2C1, - RCC_I2C2, RCC_CRC, + RCC_DAC, + RCC_DMA1, + RCC_DMA2, RCC_FLITF, - RCC_SRAM, - RCC_USB, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + RCC_FSMC, + RCC_GPIOA, + RCC_GPIOB, + RCC_GPIOC, + RCC_GPIOD, RCC_GPIOE, RCC_GPIOF, RCC_GPIOG, - RCC_UART4, - RCC_UART5, + RCC_I2C1, + RCC_I2C2, + RCC_PWR, + RCC_SDIO, + RCC_SPI1, + RCC_SPI2, + RCC_SPI3, + RCC_SRAM, + RCC_TIMER1, + RCC_TIMER2, + RCC_TIMER3, + RCC_TIMER4, RCC_TIMER5, RCC_TIMER6, RCC_TIMER7, RCC_TIMER8, - RCC_FSMC, - RCC_DAC, - RCC_DMA2, - RCC_SDIO, - RCC_SPI3, -#endif -#ifdef STM32_XL_DENSITY RCC_TIMER9, RCC_TIMER10, RCC_TIMER11, RCC_TIMER12, RCC_TIMER13, RCC_TIMER14, -#endif + RCC_USART1, + RCC_USART2, + RCC_USART3, + RCC_UART4, + RCC_UART5, + RCC_USB, } rcc_clk_id; -void rcc_clk_init(rcc_sysclk_src sysclk_src, - rcc_pllsrc pll_src, - rcc_pll_multiplier pll_mul); -void rcc_clk_enable(rcc_clk_id device); -void rcc_reset_dev(rcc_clk_id device); +/** + * @brief STM32F1 PLL clock sources. + * @see rcc_configure_pll() + */ +typedef enum rcc_pllsrc { + RCC_PLLSRC_HSE = (0x1 << 16), + RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) +} rcc_pllsrc; +/** + * @brief STM32F1 clock domains. + * @see rcc_dev_clk() + */ typedef enum rcc_clk_domain { RCC_APB1, RCC_APB2, RCC_AHB } rcc_clk_domain; -rcc_clk_domain rcc_dev_clk(rcc_clk_id device); - /** - * Prescaler identifiers + * @brief STM32F1 Prescaler identifiers * @see rcc_set_prescaler() */ typedef enum rcc_prescaler { @@ -510,7 +471,7 @@ typedef enum rcc_prescaler { } rcc_prescaler; /** - * ADC prescaler dividers + * @brief STM32F1 ADC prescaler dividers * @see rcc_set_prescaler() */ typedef enum rcc_adc_divider { @@ -521,7 +482,7 @@ typedef enum rcc_adc_divider { } rcc_adc_divider; /** - * APB1 prescaler dividers + * @brief STM32F1 APB1 prescaler dividers * @see rcc_set_prescaler() */ typedef enum rcc_apb1_divider { @@ -533,7 +494,7 @@ typedef enum rcc_apb1_divider { } rcc_apb1_divider; /** - * APB2 prescaler dividers + * @brief STM32F1 APB2 prescaler dividers * @see rcc_set_prescaler() */ typedef enum rcc_apb2_divider { @@ -545,7 +506,7 @@ typedef enum rcc_apb2_divider { } rcc_apb2_divider; /** - * AHB prescaler dividers + * @brief STM32F1 AHB prescaler dividers * @see rcc_set_prescaler() */ typedef enum rcc_ahb_divider { @@ -561,10 +522,78 @@ typedef enum rcc_ahb_divider { RCC_AHB_SYSCLK_DIV_512 = 0xF << 4, } rcc_ahb_divider; -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); +/** + * @brief STM32F1 clock sources. + */ +typedef enum rcc_clk { + RCC_CLK_PLL = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_PLLON_BIT), /**< Main PLL, clocked by + HSI or HSE. */ + RCC_CLK_HSE = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_HSEON_BIT), /**< High speed external. */ + RCC_CLK_HSI = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_HSION_BIT), /**< High speed internal. */ + RCC_CLK_LSE = (uint16)((offsetof(struct rcc_reg_map, BDCR) << 8) | + RCC_BDCR_LSEON_BIT), /**< Low-speed external + * (32.768 KHz). */ + RCC_CLK_LSI = (uint16)((offsetof(struct rcc_reg_map, CSR) << 8) | + RCC_CSR_LSION_BIT), /**< Low-speed internal + * (approximately 32 KHz). */ +} rcc_clk; + +/** + * @brief STM32F1 PLL multipliers. + */ +typedef enum rcc_pll_multiplier { + RCC_PLLMUL_2 = (0x0 << 18), + RCC_PLLMUL_3 = (0x1 << 18), + RCC_PLLMUL_4 = (0x2 << 18), + RCC_PLLMUL_5 = (0x3 << 18), + RCC_PLLMUL_6 = (0x4 << 18), + RCC_PLLMUL_7 = (0x5 << 18), + RCC_PLLMUL_8 = (0x6 << 18), + RCC_PLLMUL_9 = (0x7 << 18), + RCC_PLLMUL_10 = (0x8 << 18), + RCC_PLLMUL_11 = (0x9 << 18), + RCC_PLLMUL_12 = (0xA << 18), + RCC_PLLMUL_13 = (0xB << 18), + RCC_PLLMUL_14 = (0xC << 18), + RCC_PLLMUL_15 = (0xD << 18), + RCC_PLLMUL_16 = (0xE << 18), +} rcc_pll_multiplier; + +/* FIXME [0.0.13] Just have data point to an rcc_pll_multiplier! */ + +/** + * @brief STM32F1 PLL configuration values. + * Point to one of these with the "data" field in a struct rcc_pll_cfg. + * @see struct rcc_pll_cfg. + */ +typedef struct stm32f1_rcc_pll_data { + rcc_pll_multiplier pll_mul; /**< PLL multiplication factor. */ +} stm32f1_rcc_pll_data; + +/* + * Deprecated bits. + */ + +/** + * @brief Deprecated; STM32F1 only. + * + * Initialize the clock control system. Initializes the system + * clock source to use the PLL driven by an external oscillator. + * + * @param sysclk_src system clock source, must be PLL + * @param pll_src pll clock source, must be HSE + * @param pll_mul pll multiplier + */ +__deprecated +void rcc_clk_init(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul); #ifdef __cplusplus -} // extern "C" +} #endif #endif diff --git a/libmaple/stm32f1/include/series/spi.h b/libmaple/stm32f1/include/series/spi.h new file mode 100644 index 0000000..d288a0c --- /dev/null +++ b/libmaple/stm32f1/include/series/spi.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/spi.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F1 SPI/I2S series header. + */ + +#ifndef _LIBMAPLE_STM32F1_SPI_H_ +#define _LIBMAPLE_STM32F1_SPI_H_ + +#include <libmaple/libmaple_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Register map base pointers + */ + +struct spi_reg_map; + +#define SPI1_BASE ((struct spi_reg_map*)0x40013000) +#define SPI2_BASE ((struct spi_reg_map*)0x40003800) +#define SPI3_BASE ((struct spi_reg_map*)0x40003C00) + +/* + * Device pointers + */ + +struct spi_dev; + +extern struct spi_dev *SPI1; +extern struct spi_dev *SPI2; +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +extern struct spi_dev *SPI3; +#endif + +/* + * Routines + */ + +/* spi_gpio_cfg(): Backwards compatibility shim to spi_config_gpios() */ +struct gpio_dev; +extern void spi_config_gpios(struct spi_dev*, uint8, + struct gpio_dev*, uint8, + struct gpio_dev*, uint8, uint8, uint8); +/** + * @brief Deprecated. Use spi_config_gpios() instead. + * @see spi_config_gpios() + */ +static __always_inline void spi_gpio_cfg(uint8 as_master, + struct gpio_dev *nss_dev, + uint8 nss_bit, + struct gpio_dev *comm_dev, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit) { + /* We switched style globally to foo_config_gpios() and always + * taking a foo_dev* argument (that last bit is the important + * part) after this function was written. + * + * However, spi_config_gpios() just ignores the spi_dev* on F1, so + * we can still keep this around for older code. */ + spi_config_gpios(NULL, as_master, nss_dev, nss_bit, + comm_dev, sck_bit, miso_bit, mosi_bit); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f1/include/series/stm32.h b/libmaple/stm32f1/include/series/stm32.h new file mode 100644 index 0000000..f6e96f8 --- /dev/null +++ b/libmaple/stm32f1/include/series/stm32.h @@ -0,0 +1,212 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010, 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/stm32.h + * @brief STM32F1 chip- and series-specific definitions. + */ + +#ifndef _LIBMAPLE_STM32F1_H_ +#define _LIBMAPLE_STM32F1_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define STM32_MCU_SERIES STM32_SERIES_F1 + +/* The STM32F1 series is subdivided into "lines". libmaple currently + * officially supports STM32F103 performance line MCUs (see the + * MCU-specific value section below). + * + * You can use these F1 line defines if porting libmaple to support + * MCUs on other lines. */ +/** STM32F1 value line (STM32F100 MCUs). */ +#define STM32_F1_LINE_VALUE 0 +/** STM32F1 access line (STM32F101 MCUs). */ +#define STM32_F1_LINE_ACCESS 1 +/** STM32F1 USB access line (STM32F102 MCUs). */ +#define STM32_F1_LINE_USB_ACCESS 2 +/** STM32F1 performance line (STM32F103 MCUs). */ +#define STM32_F1_LINE_PERFORMANCE 3 +/** STM32F1 connectivity line (STM32F105/F107 MCUs). */ +#define STM32_F1_LINE_CONNECTIVITY 5 + +/* + * MCU-specific values. + * + * You can use this section to override any of the below settings on a + * per-MCU basis. For example, if your MCU has different STM32_PCLK1 + * or STM32_PCLK2 values, you can set them here and the values for + * STM32F103 microcontrollers set below won't take effect. + */ + +#if defined(MCU_STM32F103RB) +# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE +# define STM32_NR_GPIO_PORTS 4 +# define STM32_SRAM_END ((void*)0x20005000) +# define STM32_MEDIUM_DENSITY + +#elif defined(MCU_STM32F103ZE) +# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE +# define STM32_NR_GPIO_PORTS 7 +# define STM32_SRAM_END ((void*)0x20010000) +# define STM32_HIGH_DENSITY + +#elif defined(MCU_STM32F103CB) +# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE + /* This STM32_NR_GPIO_PORTS is not true, but only pins 0 and + * exist, and they're used for OSC (e.g. on LeafLabs' Maple Mini), + * so we'll live with this for now. */ +# define STM32_NR_GPIO_PORTS 3 +# define STM32_SRAM_END ((void*)0x20005000) +# define STM32_MEDIUM_DENSITY + +#elif defined(MCU_STM32F103RE) +# define STM32_F1_LINE STM32_F1_LINE_PERFORMANCE +# define STM32_NR_GPIO_PORTS 4 +# define STM32_SRAM_END ((void*)0x20010000) +# define STM32_HIGH_DENSITY + +#elif defined(MCU_STM32F100RB) +# define STM32_F1_LINE STM32_F1_LINE_VALUE +# define STM32_NR_GPIO_PORTS 4 +# define STM32_TIMER_MASK 0x380DE /* Timers: 1-4, 6, 7, 15-17. */ +# define STM32_SRAM_END ((void*)0x20002000) +# define STM32_MEDIUM_DENSITY + +#else +#warning "Unsupported or unspecified STM32F1 MCU." +#endif + +/* + * Derived values. + */ + +#if STM32_F1_LINE == STM32_F1_LINE_PERFORMANCE + /* All supported performance line MCUs have a USB peripheral */ +# define STM32_HAVE_USB 1 + +# ifdef STM32_MEDIUM_DENSITY +# define STM32_NR_INTERRUPTS 43 +# define STM32_TIMER_MASK 0x1E /* TIMER1--TIMER4 */ +# define STM32_HAVE_FSMC 0 +# define STM32_HAVE_DAC 0 +# elif defined(STM32_HIGH_DENSITY) +# define STM32_NR_INTERRUPTS 60 +# define STM32_TIMER_MASK 0x1FE /* TIMER1--TIMER8 */ +# define STM32_HAVE_FSMC 1 +# define STM32_HAVE_DAC 1 +# elif defined(STM32_XL_DENSITY) +# define STM32_NR_INTERRUPTS 60 +# define STM32_TIMER_MASK 0x7FFE /* TIMER1--TIMER14 */ +# define STM32_HAVE_FSMC 1 +# define STM32_HAVE_DAC 1 +# endif + +#elif STM32_F1_LINE == STM32_F1_LINE_VALUE + /* Value line MCUs don't have USB peripherals. */ +# define STM32_HAVE_USB 0 + +# ifdef STM32_MEDIUM_DENSITY +# define STM32_NR_INTERRUPTS 56 +# define STM32_HAVE_FSMC 0 +# define STM32_HAVE_DAC 1 +# elif defined(STM32_HIGH_DENSITY) + /* 61 interrupts here counts the possibility for a remapped + * DMA2 channel 5 IRQ occurring at NVIC index 60. */ +# define STM32_NR_INTERRUPTS 61 +# define STM32_HAVE_FSMC 1 +# define STM32_HAVE_DAC 1 +# endif + +#endif + +/* + * Clock configuration. + * + * You can patch these for your line, MCU, clock configuration, + * etc. here or by setting cflags when compiling libmaple. + */ + +#if STM32_F1_LINE == STM32_F1_LINE_PERFORMANCE +# ifndef STM32_PCLK1 +# define STM32_PCLK1 36000000U +# endif +# ifndef STM32_PCLK2 +# define STM32_PCLK2 72000000U +# endif +# ifndef STM32_DELAY_US_MULT +# define STM32_DELAY_US_MULT 12 /* FIXME: value is incorrect. */ +# endif +#elif STM32_F1_LINE == STM32_F1_LINE_VALUE /* TODO */ +# ifndef STM32_PCLK1 +# define STM32_PCLK1 12000000U +# endif +# ifndef STM32_PCLK2 +# define STM32_PCLK2 24000000U +# endif +# ifndef STM32_DELAY_US_MULT +# define STM32_DELAY_US_MULT 8 /* FIXME: value is incorrect. */ +# endif +#elif STM32_F1_LINE == STM32_F1_LINE_ACCESS /* TODO */ +#elif STM32_F1_LINE == STM32_F1_LINE_USB_ACCESS /* TODO */ +#elif STM32_F1_LINE == STM32_F1_LINE_CONNECTIVITY /* TODO */ +#endif + +/* + * Sanity checks. + * + * Make sure we have the F1-specific defines we need. + * <libmaple/stm32.h> will check that we've defined everything it needs. + */ + +#if !defined(STM32_F1_LINE) +#error "Bad STM32F1 configuration. Check STM32F1 <series/stm32.h> header." +#endif + +/* + * Doxygen + */ + +#ifdef __DOXYGEN__ + +/** + * @brief STM32 line value for the STM32F1 MCU being targeted. + * + * At time of writing, allowed values are: STM32_F1_LINE_PERFORMANCE, + * STM32_F1_LINE_VALUE. This set of values may expand as libmaple adds + * support for more STM32F1 lines. + */ +#define STM32_F1_LINE + +#endif /* __DOXYGEN__ */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f1/include/series/timer.h b/libmaple/stm32f1/include/series/timer.h new file mode 100644 index 0000000..cfeb770 --- /dev/null +++ b/libmaple/stm32f1/include/series/timer.h @@ -0,0 +1,128 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/timer.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F1 timer support. + */ + +#ifndef _LIBMAPLE_STM32F1_TIMER_H_ +#define _LIBMAPLE_STM32F1_TIMER_H_ + +#include <libmaple/libmaple_types.h> + +/* + * Register maps and base pointers + */ + +/** STM32F1 general purpose timer register map type */ +typedef struct timer_gen_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 SMCR; /**< Slave mode control register */ + __io uint32 DIER; /**< DMA/Interrupt enable register */ + __io uint32 SR; /**< Status register */ + __io uint32 EGR; /**< Event generation register */ + __io uint32 CCMR1; /**< Capture/compare mode register 1 */ + __io uint32 CCMR2; /**< Capture/compare mode register 2 */ + __io uint32 CCER; /**< Capture/compare enable register */ + __io uint32 CNT; /**< Counter */ + __io uint32 PSC; /**< Prescaler */ + __io uint32 ARR; /**< Auto-reload register */ + const uint32 RESERVED1; /**< Reserved */ + __io uint32 CCR1; /**< Capture/compare register 1 */ + __io uint32 CCR2; /**< Capture/compare register 2 */ + __io uint32 CCR3; /**< Capture/compare register 3 */ + __io uint32 CCR4; /**< Capture/compare register 4 */ + const uint32 RESERVED2; /**< Reserved */ + __io uint32 DCR; /**< DMA control register */ + __io uint32 DMAR; /**< DMA address for full transfer */ +} timer_gen_reg_map; + +struct timer_adv_reg_map; +struct timer_bas_reg_map; + +/** Timer 1 register map base pointer */ +#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00) +/** Timer 2 register map base pointer */ +#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000) +/** Timer 3 register map base pointer */ +#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400) +/** Timer 4 register map base pointer */ +#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800) +/** Timer 5 register map base pointer */ +#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00) +/** Timer 6 register map base pointer */ +#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000) +/** Timer 7 register map base pointer */ +#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400) +/** Timer 8 register map base pointer */ +#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400) +/** Timer 9 register map base pointer */ +#define TIMER9_BASE ((struct timer_gen_reg_map*)0x40014C00) +/** Timer 10 register map base pointer */ +#define TIMER10_BASE ((struct timer_gen_reg_map*)0x40015000) +/** Timer 11 register map base pointer */ +#define TIMER11_BASE ((struct timer_gen_reg_map*)0x40015400) +/** Timer 12 register map base pointer */ +#define TIMER12_BASE ((struct timer_gen_reg_map*)0x40001800) +/** Timer 13 register map base pointer */ +#define TIMER13_BASE ((struct timer_gen_reg_map*)0x40001C00) +/** Timer 14 register map base pointer */ +#define TIMER14_BASE ((struct timer_gen_reg_map*)0x40002000) + +/* + * Device pointers + * + * We only declare device pointers to timers which actually exist on + * the target MCU. This helps when porting programs to STM32F1 (or + * within F1 to a lower density MCU), as attempts to use nonexistent + * timers cause build errors instead of undefined behavior. + */ + +struct timer_dev; + +extern struct timer_dev *TIMER1; +extern struct timer_dev *TIMER2; +extern struct timer_dev *TIMER3; +extern struct timer_dev *TIMER4; +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +extern struct timer_dev *TIMER5; +extern struct timer_dev *TIMER6; +extern struct timer_dev *TIMER7; +extern struct timer_dev *TIMER8; +#endif +#ifdef STM32_XL_DENSITY +extern struct timer_dev *TIMER9; +extern struct timer_dev *TIMER10; +extern struct timer_dev *TIMER11; +extern struct timer_dev *TIMER12; +extern struct timer_dev *TIMER13; +extern struct timer_dev *TIMER14; +#endif + +#endif diff --git a/libmaple/stm32f1/include/series/usart.h b/libmaple/stm32f1/include/series/usart.h new file mode 100644 index 0000000..d12a3e2 --- /dev/null +++ b/libmaple/stm32f1/include/series/usart.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/usart.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F1 USART support. + */ + +#ifndef _LIBMAPLE_STM32F1_USART_H_ +#define _LIBMAPLE_STM32F1_USART_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + * Register map base pointers + */ + +struct usart_reg_map; + +/** USART1 register map base pointer */ +#define USART1_BASE ((struct usart_reg_map*)0x40013800) +/** USART2 register map base pointer */ +#define USART2_BASE ((struct usart_reg_map*)0x40004400) +/** USART3 register map base pointer */ +#define USART3_BASE ((struct usart_reg_map*)0x40004800) +#ifdef STM32_HIGH_DENSITY +/** UART4 register map base pointer */ +#define UART4_BASE ((struct usart_reg_map*)0x40004C00) +/** UART5 register map base pointer */ +#define UART5_BASE ((struct usart_reg_map*)0x40005000) +#endif + +/* + * Devices + */ + +struct usart_dev; +extern struct usart_dev *USART1; +extern struct usart_dev *USART2; +extern struct usart_dev *USART3; +#ifdef STM32_HIGH_DENSITY +extern struct usart_dev *UART4; +extern struct usart_dev *UART5; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f1/isrs_performance.S b/libmaple/stm32f1/performance/isrs.S index be102e7..a8f0709 100644 --- a/libmaple/stm32f1/isrs_performance.S +++ b/libmaple/stm32f1/performance/isrs.S @@ -1,4 +1,30 @@ -/* STM32 ISR weak declarations */ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* STM32F1 performance line ISR weak declarations */ .thumb diff --git a/libmaple/stm32f1/vector_table_performance.S b/libmaple/stm32f1/performance/vector_table.S index 0392a02..b489b94 100644 --- a/libmaple/stm32f1/vector_table_performance.S +++ b/libmaple/stm32f1/performance/vector_table.S @@ -1,4 +1,30 @@ -/* STM32 vector table */ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* STM32F1 performance line vector table */ .section ".stm32.interrupt_vector" diff --git a/libmaple/stm32f1/rcc.c b/libmaple/stm32f1/rcc.c new file mode 100644 index 0000000..8d71a41 --- /dev/null +++ b/libmaple/stm32f1/rcc.c @@ -0,0 +1,164 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/rcc.c + * @brief STM32F1 RCC. + */ + +#include <libmaple/rcc.h> +#include <libmaple/libmaple.h> +#include <libmaple/bitband.h> + +#include "rcc_private.h" + +#define APB1 RCC_APB1 +#define APB2 RCC_APB2 +#define AHB RCC_AHB + +/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset + * register bit numbers. */ +const struct rcc_dev_info rcc_dev_table[] = { + [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, + [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, + [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, + [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, + [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, + [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, + [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, + [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, + [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, + [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, + [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, + [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 }, + [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, + [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, + [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, + [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, + [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, + [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, + [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, + [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, + [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, + [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, + [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, + [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, + [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, + [RCC_USB] = { .clk_domain = APB1, .line_num = 23}, +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, + [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, + [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, + [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, + [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, + [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, + [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, + [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, + [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, + [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, + [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, + [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, + [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, + [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, +#endif +#ifdef STM32_XL_DENSITY + [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, + [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, + [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, + [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, + [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, + [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, +#endif +}; + +__deprecated +void rcc_clk_init(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul) { + /* Assume that we're going to clock the chip off the PLL, fed by + * the HSE */ + ASSERT(sysclk_src == RCC_CLKSRC_PLL && + pll_src == RCC_PLLSRC_HSE); + + RCC_BASE->CFGR = pll_src | pll_mul; + + /* Turn on, and wait for, HSE. */ + rcc_turn_on_clk(RCC_CLK_HSE); + while (!rcc_is_clk_ready(RCC_CLK_HSE)) + ; + + /* Do the same for the main PLL. */ + rcc_turn_on_clk(RCC_CLK_PLL); + while(!rcc_is_clk_ready(RCC_CLK_PLL)) + ; + + /* Finally, switch over to the PLL. */ + rcc_switch_sysclk(RCC_CLKSRC_PLL); +} + +/* pll_cfg->data must point to a valid struct stm32f1_rcc_pll_data. */ +void rcc_configure_pll(rcc_pll_cfg *pll_cfg) { + stm32f1_rcc_pll_data *data = pll_cfg->data; + rcc_pll_multiplier pll_mul = data->pll_mul; + uint32 cfgr; + + /* Check that the PLL is disabled. */ + ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL)); + + cfgr = RCC_BASE->CFGR; + cfgr &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL); + cfgr |= pll_cfg->pllsrc | pll_mul; + RCC_BASE->CFGR = cfgr; +} + +void rcc_clk_enable(rcc_clk_id id) { + static __io uint32* enable_regs[] = { + [APB1] = &RCC_BASE->APB1ENR, + [APB2] = &RCC_BASE->APB2ENR, + [AHB] = &RCC_BASE->AHBENR, + }; + rcc_do_clk_enable(enable_regs, id); +} + +void rcc_reset_dev(rcc_clk_id id) { + static __io uint32* reset_regs[] = { + [APB1] = &RCC_BASE->APB1RSTR, + [APB2] = &RCC_BASE->APB2RSTR, + }; + rcc_do_reset_dev(reset_regs, id); +} + +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { + static const uint32 masks[] = { + [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, + [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, + [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, + [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, + [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, + }; + rcc_do_set_prescaler(masks, prescaler, divider); +} diff --git a/libmaple/stm32f1/rules.mk b/libmaple/stm32f1/rules.mk index 5cadefd..3ca0813 100644 --- a/libmaple/stm32f1/rules.mk +++ b/libmaple/stm32f1/rules.mk @@ -4,16 +4,37 @@ dirstack_$(sp) := $(d) d := $(dir) BUILDDIRS += $(BUILD_PATH)/$(d) +# Local flags +CFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror + +# Extra BUILDDIRS +BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_F1_LINE) + # Local rules and targets -sSRCS_$(d) := isrs_performance.S \ - vector_table_performance.S +sSRCS_$(d) := $(MCU_F1_LINE)/isrs.S +sSRCS_$(d) += $(MCU_F1_LINE)/vector_table.S + +cSRCS_$(d) := adc.c +cSRCS_$(d) += bkp.c +cSRCS_$(d) += dma.c +cSRCS_$(d) += exti.c +cSRCS_$(d) += fsmc.c +cSRCS_$(d) += gpio.c +cSRCS_$(d) += i2c.c +cSRCS_$(d) += rcc.c +cSRCS_$(d) += spi.c +cSRCS_$(d) += timer.c +cSRCS_$(d) += usart.c sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%) +cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) -OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) +OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \ + $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) DEPS_$(d) := $(OBJS_$(d):%.o=%.d) $(OBJS_$(d)): TGT_ASFLAGS := +$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d)) TGT_BIN += $(OBJS_$(d)) diff --git a/libmaple/stm32f1/spi.c b/libmaple/stm32f1/spi.c new file mode 100644 index 0000000..1c78cc3 --- /dev/null +++ b/libmaple/stm32f1/spi.c @@ -0,0 +1,84 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/spi.c + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F1 SPI/I2S. + */ + +#include <libmaple/spi.h> +#include <libmaple/gpio.h> +#include "spi_private.h" + +/* + * Devices + */ + +static spi_dev spi1 = SPI_DEV(1); +static spi_dev spi2 = SPI_DEV(2); + +spi_dev *SPI1 = &spi1; +spi_dev *SPI2 = &spi2; + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +static spi_dev spi3 = SPI_DEV(3); +spi_dev *SPI3 = &spi3; +#endif + +/* + * Routines + */ + +void spi_config_gpios(spi_dev *ignored, + uint8 as_master, + gpio_dev *nss_dev, + uint8 nss_bit, + gpio_dev *comm_dev, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit) { + if (as_master) { + gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP); + } else { + gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING); + } +} + +void spi_foreach(void (*fn)(spi_dev*)) { + fn(SPI1); + fn(SPI2); +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + fn(SPI3); +#endif +} diff --git a/libmaple/stm32f1/timer.c b/libmaple/stm32f1/timer.c new file mode 100644 index 0000000..8b9e976 --- /dev/null +++ b/libmaple/stm32f1/timer.c @@ -0,0 +1,124 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/timer.c + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F1 timer. + */ + +#include <libmaple/timer.h> +#include <libmaple/stm32.h> +#include "timer_private.h" + +/* + * IRQ handlers + * + * Defer to the timer_private dispatch API. + * + * FIXME: The names of these handlers are inaccurate since XL-density + * devices came out. Update these to match the STM32F2 names, maybe + * using some weak symbol magic to preserve backwards compatibility if + * possible. Once that's done, we can just move the IRQ handlers into + * the top-level libmaple/timer.c, and there will be no need for this + * file. + */ + +void __irq_tim1_brk(void) { + dispatch_adv_brk(TIMER1); +#if STM32_HAVE_TIMER(9) + dispatch_tim_9_12(TIMER9); +#endif +} + +void __irq_tim1_up(void) { + dispatch_adv_up(TIMER1); +#if STM32_HAVE_TIMER(10) + dispatch_tim_10_11_13_14(TIMER10); +#endif +} + +void __irq_tim1_trg_com(void) { + dispatch_adv_trg_com(TIMER1); +#if STM32_HAVE_TIMER(11) + dispatch_tim_10_11_13_14(TIMER11); +#endif +} + +void __irq_tim1_cc(void) { + dispatch_adv_cc(TIMER1); +} + +void __irq_tim2(void) { + dispatch_general(TIMER2); +} + +void __irq_tim3(void) { + dispatch_general(TIMER3); +} + +void __irq_tim4(void) { + dispatch_general(TIMER4); +} + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +void __irq_tim5(void) { + dispatch_general(TIMER5); +} + +void __irq_tim6(void) { + dispatch_basic(TIMER6); +} + +void __irq_tim7(void) { + dispatch_basic(TIMER7); +} + +void __irq_tim8_brk(void) { + dispatch_adv_brk(TIMER8); +#if STM32_HAVE_TIMER(12) + dispatch_tim_9_12(TIMER12); +#endif +} + +void __irq_tim8_up(void) { + dispatch_adv_up(TIMER8); +#if STM32_HAVE_TIMER(13) + dispatch_tim_10_11_13_14(TIMER13); +#endif +} + +void __irq_tim8_trg_com(void) { + dispatch_adv_trg_com(TIMER8); +#if STM32_HAVE_TIMER(14) + dispatch_tim_10_11_13_14(TIMER14); +#endif +} + +void __irq_tim8_cc(void) { + dispatch_adv_cc(TIMER8); +} +#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */ diff --git a/libmaple/stm32f1/usart.c b/libmaple/stm32f1/usart.c new file mode 100644 index 0000000..b3b849f --- /dev/null +++ b/libmaple/stm32f1/usart.c @@ -0,0 +1,170 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/usart.c + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * Perry Hung <perry@leaflabs.com> + * @brief STM32F1 USART. + */ + +#include <libmaple/usart.h> +#include <libmaple/gpio.h> +#include "usart_private.h" + +/* + * Devices + */ + +static ring_buffer usart1_rb; +static usart_dev usart1 = { + .regs = USART1_BASE, + .rb = &usart1_rb, + .max_baud = 4500000UL, + .clk_id = RCC_USART1, + .irq_num = NVIC_USART1, +}; +/** USART1 device */ +usart_dev *USART1 = &usart1; + +static ring_buffer usart2_rb; +static usart_dev usart2 = { + .regs = USART2_BASE, + .rb = &usart2_rb, + .max_baud = 2250000UL, + .clk_id = RCC_USART2, + .irq_num = NVIC_USART2, +}; +/** USART2 device */ +usart_dev *USART2 = &usart2; + +static ring_buffer usart3_rb; +static usart_dev usart3 = { + .regs = USART3_BASE, + .rb = &usart3_rb, + .max_baud = 2250000UL, + .clk_id = RCC_USART3, + .irq_num = NVIC_USART3, +}; +/** USART3 device */ +usart_dev *USART3 = &usart3; + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +static ring_buffer uart4_rb; +static usart_dev uart4 = { + .regs = UART4_BASE, + .rb = &uart4_rb, + .max_baud = 2250000UL, + .clk_id = RCC_UART4, + .irq_num = NVIC_UART4, +}; +/** UART4 device */ +usart_dev *UART4 = &uart4; + +static ring_buffer uart5_rb; +static usart_dev uart5 = { + .regs = UART5_BASE, + .rb = &uart5_rb, + .max_baud = 2250000UL, + .clk_id = RCC_UART5, + .irq_num = NVIC_UART5, +}; +/** UART5 device */ +usart_dev *UART5 = &uart5; +#endif + +/* + * Routines + */ + +void usart_config_gpios_async(usart_dev *udev, + gpio_dev *rx_dev, uint8 rx, + gpio_dev *tx_dev, uint8 tx, + unsigned flags) { + gpio_set_mode(rx_dev, rx, GPIO_INPUT_FLOATING); + gpio_set_mode(tx_dev, tx, GPIO_AF_OUTPUT_PP); +} + +void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) { + uint32 integer_part; + uint32 fractional_part; + uint32 tmp; + + /* Figure out the clock speed, if the user doesn't give one. */ + if (clock_speed == 0) { + clock_speed = _usart_clock_freq(dev); + } + ASSERT(clock_speed); + + /* Convert desired baud rate to baud rate register setting. */ + integer_part = (25 * clock_speed) / (4 * baud); + tmp = (integer_part / 100) << 4; + fractional_part = integer_part - (100 * (tmp >> 4)); + tmp |= (((fractional_part * 16) + 50) / 100) & ((uint8)0x0F); + + dev->regs->BRR = (uint16)tmp; +} + +/** + * @brief Call a function on each USART. + * @param fn Function to call. + */ +void usart_foreach(void (*fn)(usart_dev*)) { + fn(USART1); + fn(USART2); + fn(USART3); +#ifdef STM32_HIGH_DENSITY + fn(UART4); + fn(UART5); +#endif +} + +/* + * Interrupt handlers. + */ + +void __irq_usart1(void) { + usart_irq(&usart1_rb, USART1_BASE); +} + +void __irq_usart2(void) { + usart_irq(&usart2_rb, USART2_BASE); +} + +void __irq_usart3(void) { + usart_irq(&usart3_rb, USART3_BASE); +} + +#ifdef STM32_HIGH_DENSITY +void __irq_uart4(void) { + usart_irq(&uart4_rb, UART4_BASE); +} + +void __irq_uart5(void) { + usart_irq(&uart5_rb, UART5_BASE); +} +#endif diff --git a/libmaple/stm32f1/value/isrs.S b/libmaple/stm32f1/value/isrs.S new file mode 100644 index 0000000..858016b --- /dev/null +++ b/libmaple/stm32f1/value/isrs.S @@ -0,0 +1,270 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 Perry Hung. + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* STM32F1 value line ISR weak declarations */ + + .thumb + +/* Default handler for all non-overridden interrupts and exceptions */ + .globl __default_handler + .type __default_handler, %function + +__default_handler: + b . + + .weak __msp_init + .globl __msp_init + .set __msp_init, __default_handler + .weak __exc_reset + .globl __exc_reset + .set __exc_reset, __default_handler + .weak __exc_nmi + .globl __exc_nmi + .set __exc_nmi, __default_handler + .weak __exc_hardfault + .globl __exc_hardfault + .set __exc_hardfault, __default_handler + .weak __exc_memmanage + .globl __exc_memmanage + .set __exc_memmanage, __default_handler + .weak __exc_busfault + .globl __exc_busfault + .set __exc_busfault, __default_handler + .weak __exc_usagefault + .globl __exc_usagefault + .set __exc_usagefault, __default_handler + .weak __stm32reservedexception7 + .globl __stm32reservedexception7 + .set __stm32reservedexception7, __default_handler + .weak __stm32reservedexception8 + .globl __stm32reservedexception8 + .set __stm32reservedexception8, __default_handler + .weak __stm32reservedexception9 + .globl __stm32reservedexception9 + .set __stm32reservedexception9, __default_handler + .weak __stm32reservedexception10 + .globl __stm32reservedexception10 + .set __stm32reservedexception10, __default_handler + .weak __exc_svc + .globl __exc_svc + .set __exc_svc, __default_handler + .weak __exc_debug_monitor + .globl __exc_debug_monitor + .set __exc_debug_monitor, __default_handler + .weak __stm32reservedexception13 + .globl __stm32reservedexception13 + .set __stm32reservedexception13, __default_handler + .weak __exc_pendsv + .globl __exc_pendsv + .set __exc_pendsv, __default_handler + .weak __exc_systick + .globl __exc_systick + .set __exc_systick, __default_handler + + .weak __irq_wwdg + .globl __irq_wwdg + .set __irq_wwdg, __default_handler + .weak __irq_pvd + .globl __irq_pvd + .set __irq_pvd, __default_handler + .weak __irq_tamper + .globl __irq_tamper + .set __irq_tamper, __default_handler + .weak __irq_rtc + .globl __irq_rtc + .set __irq_rtc, __default_handler + .weak __irq_flash + .globl __irq_flash + .set __irq_flash, __default_handler + .weak __irq_rcc + .globl __irq_rcc + .set __irq_rcc, __default_handler + .weak __irq_exti0 + .globl __irq_exti0 + .set __irq_exti0, __default_handler + .weak __irq_exti1 + .globl __irq_exti1 + .set __irq_exti1, __default_handler + .weak __irq_exti2 + .globl __irq_exti2 + .set __irq_exti2, __default_handler + .weak __irq_exti3 + .globl __irq_exti3 + .set __irq_exti3, __default_handler + .weak __irq_exti4 + .globl __irq_exti4 + .set __irq_exti4, __default_handler + .weak __irq_dma1_channel1 + .globl __irq_dma1_channel1 + .set __irq_dma1_channel1, __default_handler + .weak __irq_dma1_channel2 + .globl __irq_dma1_channel2 + .set __irq_dma1_channel2, __default_handler + .weak __irq_dma1_channel3 + .globl __irq_dma1_channel3 + .set __irq_dma1_channel3, __default_handler + .weak __irq_dma1_channel4 + .globl __irq_dma1_channel4 + .set __irq_dma1_channel4, __default_handler + .weak __irq_dma1_channel5 + .globl __irq_dma1_channel5 + .set __irq_dma1_channel5, __default_handler + .weak __irq_dma1_channel6 + .globl __irq_dma1_channel6 + .set __irq_dma1_channel6, __default_handler + .weak __irq_dma1_channel7 + .globl __irq_dma1_channel7 + .set __irq_dma1_channel7, __default_handler + .weak __irq_adc1 + .globl __irq_adc1 + .set __irq_adc1, __default_handler + .weak __stm32reservedexception14 + .globl __stm32reservedexception14 + .set __stm32reservedexception14, __default_handler + .weak __stm32reservedexception15 + .globl __stm32reservedexception15 + .set __stm32reservedexception15, __default_handler + .weak __stm32reservedexception16 + .globl __stm32reservedexception16 + .set __stm32reservedexception16, __default_handler + .weak __stm32reservedexception17 + .globl __stm32reservedexception17 + .set __stm32reservedexception17, __default_handler + .weak __irq_exti9_5 + .globl __irq_exti9_5 + .set __irq_exti9_5, __default_handler + .weak __irq_tim1_brk + .globl __irq_tim1_brk + .set __irq_tim1_brk, __default_handler + .weak __irq_tim1_up + .globl __irq_tim1_up + .set __irq_tim1_up, __default_handler + .weak __irq_tim1_trg_com + .globl __irq_tim1_trg_com + .set __irq_tim1_trg_com, __default_handler + .weak __irq_tim1_cc + .globl __irq_tim1_cc + .set __irq_tim1_cc, __default_handler + .weak __irq_tim2 + .globl __irq_tim2 + .set __irq_tim2, __default_handler + .weak __irq_tim3 + .globl __irq_tim3 + .set __irq_tim3, __default_handler + .weak __irq_tim4 + .globl __irq_tim4 + .set __irq_tim4, __default_handler + .weak __irq_i2c1_ev + .globl __irq_i2c1_ev + .set __irq_i2c1_ev, __default_handler + .weak __irq_i2c1_er + .globl __irq_i2c1_er + .set __irq_i2c1_er, __default_handler + .weak __irq_i2c2_ev + .globl __irq_i2c2_ev + .set __irq_i2c2_ev, __default_handler + .weak __irq_i2c2_er + .globl __irq_i2c2_er + .set __irq_i2c2_er, __default_handler + .weak __irq_spi1 + .globl __irq_spi1 + .set __irq_spi1, __default_handler + .weak __irq_spi2 + .globl __irq_spi2 + .set __irq_spi2, __default_handler + .weak __irq_usart1 + .globl __irq_usart1 + .set __irq_usart1, __default_handler + .weak __irq_usart2 + .globl __irq_usart2 + .set __irq_usart2, __default_handler + .weak __irq_usart3 + .globl __irq_usart3 + .set __irq_usart3, __default_handler + .weak __irq_exti15_10 + .globl __irq_exti15_10 + .set __irq_exti15_10, __default_handler + .weak __irq_rtcalarm + .globl __irq_rtcalarm + .set __irq_rtcalarm, __default_handler + .weak __irq_cec + .globl __irq_cec + .set __irq_cec, __default_handler + .weak __irq_tim12 + .globl __irq_tim12 + .set __irq_tim12, __default_handler + .weak __irq_tim13 + .globl __irq_tim13 + .set __irq_tim13, __default_handler + .weak __irq_tim14 + .globl __irq_tim14 + .set __irq_tim14, __default_handler + .weak __stm32reservedexception18 + .globl __stm32reservedexception18 + .set __stm32reservedexception18, __default_handler + .weak __stm32reservedexception19 + .globl __stm32reservedexception19 + .set __stm32reservedexception19, __default_handler + .weak __irq_fsmc + .globl __irq_fsmc + .set __irq_fsmc, __default_handler + .weak __stm32reservedexception20 + .globl __stm32reservedexception20 + .set __stm32reservedexception20, __default_handler + .weak __irq_tim5 + .globl __irq_tim5 + .set __irq_tim5, __default_handler + .weak __irq_spi3 + .globl __irq_spi3 + .set __irq_spi3, __default_handler + .weak __irq_uart4 + .globl __irq_uart4 + .set __irq_uart4, __default_handler + .weak __irq_uart5 + .globl __irq_uart5 + .set __irq_uart5, __default_handler + .weak __irq_tim6 + .globl __irq_tim6 + .set __irq_tim6, __default_handler + .weak __irq_tim7 + .globl __irq_tim7 + .set __irq_tim7, __default_handler + .weak __irq_dma2_channel1 + .globl __irq_dma2_channel1 + .set __irq_dma2_channel1, __default_handler + .weak __irq_dma2_channel2 + .globl __irq_dma2_channel2 + .set __irq_dma2_channel2, __default_handler + .weak __irq_dma2_channel3 + .globl __irq_dma2_channel3 + .set __irq_dma2_channel3, __default_handler + .weak __irq_dma2_channel4_5 + .globl __irq_dma2_channel4_5 + .set __irq_dma2_channel4_5, __default_handler + .weak __irq_dma2_channel5 /* on remap only */ + .globl __irq_dma2_channel5 + .set __irq_dma2_channel5, __default_handler diff --git a/libmaple/stm32f1/value/vector_table.S b/libmaple/stm32f1/value/vector_table.S new file mode 100644 index 0000000..76a2a6e --- /dev/null +++ b/libmaple/stm32f1/value/vector_table.S @@ -0,0 +1,116 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 Perry Hung. + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* STM32F1 value line vector table */ + + .section ".stm32.interrupt_vector" + + .globl __stm32_vector_table + .type __stm32_vector_table, %object + +__stm32_vector_table: +/* CM3 core interrupts */ + .long __msp_init + .long __exc_reset + .long __exc_nmi + .long __exc_hardfault + .long __exc_memmanage + .long __exc_busfault + .long __exc_usagefault + .long __stm32reservedexception7 + .long __stm32reservedexception8 + .long __stm32reservedexception9 + .long __stm32reservedexception10 + .long __exc_svc + .long __exc_debug_monitor + .long __stm32reservedexception13 + .long __exc_pendsv + .long __exc_systick +/* Peripheral interrupts */ + .long __irq_wwdg + .long __irq_pvd + .long __irq_tamper + .long __irq_rtc + .long __irq_flash + .long __irq_rcc + .long __irq_exti0 + .long __irq_exti1 + .long __irq_exti2 + .long __irq_exti3 + .long __irq_exti4 + .long __irq_dma1_channel1 + .long __irq_dma1_channel2 + .long __irq_dma1_channel3 + .long __irq_dma1_channel4 + .long __irq_dma1_channel5 + .long __irq_dma1_channel6 + .long __irq_dma1_channel7 + .long __irq_adc1 + .long __stm32reservedexception14 + .long __stm32reservedexception15 + .long __stm32reservedexception16 + .long __stm32reservedexception17 + .long __irq_exti9_5 + .long __irq_tim1_brk + .long __irq_tim1_up + .long __irq_tim1_trg_com + .long __irq_tim1_cc + .long __irq_tim2 + .long __irq_tim3 + .long __irq_tim4 + .long __irq_i2c1_ev + .long __irq_i2c1_er + .long __irq_i2c2_ev + .long __irq_i2c2_er + .long __irq_spi1 + .long __irq_spi2 + .long __irq_usart1 + .long __irq_usart2 + .long __irq_usart3 + .long __irq_exti15_10 + .long __irq_rtcalarm + .long __irq_cec + .long __irq_tim12 + .long __irq_tim13 + .long __irq_tim14 + .long __stm32reservedexception18 + .long __stm32reservedexception19 + .long __irq_fsmc + .long __stm32reservedexception20 + .long __irq_tim5 + .long __irq_spi3 + .long __irq_uart4 + .long __irq_uart5 + .long __irq_tim6 + .long __irq_tim7 + .long __irq_dma2_channel1 + .long __irq_dma2_channel2 + .long __irq_dma2_channel3 + .long __irq_dma2_channel4_5 + .long __irq_dma2_channel5 /* on remap only */ + + .size __stm32_vector_table, . - __stm32_vector_table diff --git a/libmaple/stm32f2/adc.c b/libmaple/stm32f2/adc.c new file mode 100644 index 0000000..a400d7b --- /dev/null +++ b/libmaple/stm32f2/adc.c @@ -0,0 +1,84 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/adc.c + * @brief STM32F2 ADC. + */ + +#include <libmaple/adc.h> +#include <libmaple/gpio.h> + +/* + * Devices + */ + +static adc_dev adc1 = { + .regs = ADC1_BASE, + .clk_id = RCC_ADC1, +}; +/** ADC1 device. */ +const adc_dev *ADC1 = &adc1; + +static adc_dev adc2 = { + .regs = ADC2_BASE, + .clk_id = RCC_ADC2, +}; +/** ADC2 device. */ +const adc_dev *ADC2 = &adc2; + +static adc_dev adc3 = { + .regs = ADC3_BASE, + .clk_id = RCC_ADC3, +}; +/** ADC3 device. */ +const adc_dev *ADC3 = &adc3; + +/* + * Common routines + */ + +void adc_set_prescaler(adc_prescaler pre) { + uint32 ccr = ADC_COMMON_BASE->CCR; + ccr &= ~ADC_CCR_ADCPRE; + ccr |= (uint32)pre; + ADC_COMMON_BASE->CCR = ccr; +} + +void adc_foreach(void (*fn)(const adc_dev*)) { + fn(ADC1); + fn(ADC2); + fn(ADC3); +} + +void adc_config_gpio(const adc_dev *ignored, gpio_dev *gdev, uint8 bit) { + gpio_set_modef(gdev, bit, GPIO_MODE_ANALOG, GPIO_MODEF_PUPD_NONE); +} + +void adc_enable_single_swstart(const adc_dev *dev) { + adc_init(dev); + adc_enable(dev); +} diff --git a/libmaple/stm32f2/dma.c b/libmaple/stm32f2/dma.c new file mode 100644 index 0000000..26e87b9 --- /dev/null +++ b/libmaple/stm32f2/dma.c @@ -0,0 +1,504 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/dma.c + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 DMA support. + */ + +#include <libmaple/dma.h> +#include <libmaple/bitband.h> +#include <libmaple/util.h> + +/* Hack to ensure inlining in dma_irq_handler() */ +#define DMA_GET_HANDLER(dev, tube) (dev->handlers[tube].handler) +#include "dma_private.h" + +/* + * Devices + */ + +static dma_dev dma1 = { + .regs = DMA1_BASE, + .clk_id = RCC_DMA1, + .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA1_STREAM0 }, + { .handler = NULL, .irq_line = NVIC_DMA1_STREAM1 }, + { .handler = NULL, .irq_line = NVIC_DMA1_STREAM2 }, + { .handler = NULL, .irq_line = NVIC_DMA1_STREAM3 }, + { .handler = NULL, .irq_line = NVIC_DMA1_STREAM4 }, + { .handler = NULL, .irq_line = NVIC_DMA1_STREAM5 }, + { .handler = NULL, .irq_line = NVIC_DMA1_STREAM6 }, + { .handler = NULL, .irq_line = NVIC_DMA1_STREAM7 }}, +}; +dma_dev *DMA1 = &dma1; + +static dma_dev dma2 = { + .regs = DMA2_BASE, + .clk_id = RCC_DMA2, + .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_STREAM0 }, + { .handler = NULL, .irq_line = NVIC_DMA2_STREAM1 }, + { .handler = NULL, .irq_line = NVIC_DMA2_STREAM2 }, + { .handler = NULL, .irq_line = NVIC_DMA2_STREAM3 }, + { .handler = NULL, .irq_line = NVIC_DMA2_STREAM4 }, + { .handler = NULL, .irq_line = NVIC_DMA2_STREAM5 }, + { .handler = NULL, .irq_line = NVIC_DMA2_STREAM6 }, + { .handler = NULL, .irq_line = NVIC_DMA2_STREAM7 }}, +}; +dma_dev *DMA2 = &dma2; + +/* + * Helpers for dealing with dma_request_src's bit encoding (see the + * comments in the dma_request_src definition). + */ + +/* rcc_clk_id of dma_dev which supports src. */ +static __always_inline rcc_clk_id src_clk_id(dma_request_src src) { + return (rcc_clk_id)(((uint32)src >> 3) & 0x3F); +} + +/* Bit vector of streams supporting src (e.g., bit 0 set => DMA_S0 support). */ +static __always_inline uint32 src_stream_mask(dma_request_src src) { + return ((uint32)src >> 10) & 0xFF; +} + +/* Channel corresponding to src. */ +static __always_inline dma_channel src_channel(dma_request_src src) { + return (dma_channel)(src & 0x7); +} + +/* + * Routines + */ + +/* For convenience */ +#define ASSERT_NOT_ENABLED(dev, tube) ASSERT(!dma_is_enabled(dev, tube)) + +/* Helpers for dma_tube_cfg() */ +static int preconfig_check(dma_dev *dev, dma_tube tube, dma_tube_config *cfg); +static int postconfig_check(dma_tube_reg_map *dummy, dma_tube_config *cfg); +static int config_fifo(dma_tube_reg_map *dummy, dma_tube_config *cfg); +static int config_src_dst(dma_tube_reg_map *dummy, dma_tube_config *cfg); +static void copy_regs(dma_tube_reg_map *src, dma_tube_reg_map *dst); + +int dma_tube_cfg(dma_dev *dev, dma_tube tube, dma_tube_config *cfg) { + dma_tube_reg_map dummy_regs; + dma_tube_reg_map *tregs = dma_tube_regs(dev, tube); + int ret; + + /* Initial error checking. */ + ret = preconfig_check(dev, tube, cfg); + if (ret < 0) { + return ret; + } + + /* Disable `tube' as per RM0033. */ + dma_disable(dev, tube); + dma_clear_isr_bits(dev, tube); + + /* Don't write to tregs until we've decided `cfg' is really OK, + * so as not to make a half-formed mess if we have to error out. */ + copy_regs(tregs, &dummy_regs); + + /* Try to reconfigure `tube', bailing on error. */ + ret = config_fifo(&dummy_regs, cfg); + if (ret < 0) { + return ret; + } + ret = config_src_dst(&dummy_regs, cfg); + if (ret < 0) { + return ret; + } + dummy_regs.SNDTR = cfg->tube_nr_xfers; + ret = postconfig_check(&dummy_regs, cfg); + if (ret < 0) { + return ret; + } + + /* Ok, we're good. Commit to the new configuration. */ + copy_regs(&dummy_regs, tregs); + return ret; +} + +void dma_set_priority(dma_dev *dev, dma_stream stream, dma_priority priority) { + dma_tube_reg_map *tregs = dma_tube_regs(dev, stream); + uint32 scr; + ASSERT_NOT_ENABLED(dev, stream); + scr = tregs->SCR; + scr &= ~DMA_SCR_PL; + scr |= (priority << 16); + tregs->SCR = scr; +} + +void dma_set_num_transfers(dma_dev *dev, dma_tube tube, uint16 num_transfers) { + dma_tube_reg_map *tregs = dma_tube_regs(dev, tube); + ASSERT_NOT_ENABLED(dev, tube); + tregs->SNDTR = num_transfers; +} + +/** + * @brief Set memory 0 or memory 1 address. + * + * This is a general function for setting one of the two memory + * addresses available on the double-buffered STM32F2 DMA controllers. + * + * @param dev DMA device + * @param tube Tube on dev. + * @param n If 0, set memory 0 address. If 1, set memory 1 address. + * @param address Address to set + */ +void dma_set_mem_n_addr(dma_dev *dev, dma_tube tube, int n, + __io void *address) { + dma_tube_reg_map *tregs = dma_tube_regs(dev, tube); + uint32 addr = (uint32)address; + + ASSERT_NOT_ENABLED(dev, tube); + if (n) { + tregs->SM1AR = addr; + } else { + tregs->SM0AR = addr; + } +} + +void dma_set_per_addr(dma_dev *dev, dma_tube tube, __io void *address) { + dma_tube_reg_map *tregs = dma_tube_regs(dev, tube); + ASSERT_NOT_ENABLED(dev, tube); + tregs->SPAR = (uint32)address; +} + +/** + * @brief Enable a stream's FIFO. + * + * You may only call this function when the stream is disabled. + * + * @param dev DMA device + * @param tube Stream whose FIFO to enable. + */ +void dma_enable_fifo(dma_dev *dev, dma_tube tube) { + ASSERT_NOT_ENABLED(dev, tube); + bb_peri_set_bit(&(dma_tube_regs(dev, tube)->SFCR), DMA_SFCR_DMDIS_BIT, 1); +} + +/** + * @brief Disable a stream's FIFO. + * + * You may only call this function when the stream is disabled. + * + * @param dev DMA device + * @param tube Stream whose FIFO to disable. + */ +void dma_disable_fifo(dma_dev *dev, dma_tube tube) { + ASSERT_NOT_ENABLED(dev, tube); + bb_peri_set_bit(&(dma_tube_regs(dev, tube)->SFCR), DMA_SFCR_DMDIS_BIT, 0); +} + +void dma_attach_interrupt(dma_dev *dev, dma_tube tube, + void (*handler)(void)) { + dev->handlers[tube].handler = handler; + nvic_irq_enable(dev->handlers[tube].irq_line); +} + +void dma_detach_interrupt(dma_dev *dev, dma_tube tube) { + nvic_irq_disable(dev->handlers[tube].irq_line); + dev->handlers[tube].handler = NULL; +} + +void dma_enable(dma_dev *dev, dma_tube tube) { + dma_tube_reg_map *tregs = dma_tube_regs(dev, tube); + bb_peri_set_bit(&tregs->SCR, DMA_SCR_EN_BIT, 1); +} + +void dma_disable(dma_dev *dev, dma_tube tube) { + dma_tube_reg_map *tregs = dma_tube_regs(dev, tube); + bb_peri_set_bit(&tregs->SCR, DMA_SCR_EN_BIT, 0); + /* The stream might not get disabled immediately, so wait. */ + while (tregs->SCR & DMA_SCR_EN) + ; +} + +dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_tube tube) { + /* TODO: does it still make sense to have this function? We should + * probably just be returning the ISR bits, with some defines to + * pull the flags out. The lack of masked status bits is an + * annoyance that would require documentation to solve, though. */ + uint8 status_bits = dma_get_isr_bits(dev, tube); + dma_clear_isr_bits(dev, tube); + ASSERT(status_bits); /* Or something's very wrong */ + /* Don't change the order of these if statements. */ + if (status_bits & 0x0) { + return DMA_TRANSFER_FIFO_ERROR; + } else if (status_bits & 0x4) { + return DMA_TRANSFER_DME_ERROR; + } else if (status_bits & 0x8) { + return DMA_TRANSFER_ERROR; + } else if (status_bits & 0x20) { + return DMA_TRANSFER_COMPLETE; + } else if (status_bits & 0x10) { + return DMA_TRANSFER_HALF_COMPLETE; + } + + /* Something's wrong; one of those bits should have been set. Fail + * an assert, and mimic the error behavior in case of a high debug + * level. */ + ASSERT(0); + dma_disable(dev, tube); + return DMA_TRANSFER_ERROR; +} + +/* + * IRQ handlers + */ + +void __irq_dma1_stream0(void) { + dma_irq_handler(DMA1, DMA_S0); +} + +void __irq_dma1_stream1(void) { + dma_irq_handler(DMA1, DMA_S1); +} + +void __irq_dma1_stream2(void) { + dma_irq_handler(DMA1, DMA_S2); +} + +void __irq_dma1_stream3(void) { + dma_irq_handler(DMA1, DMA_S3); +} + +void __irq_dma1_stream4(void) { + dma_irq_handler(DMA1, DMA_S4); +} + +void __irq_dma1_stream5(void) { + dma_irq_handler(DMA1, DMA_S5); +} + +void __irq_dma1_stream6(void) { + dma_irq_handler(DMA1, DMA_S6); +} + +void __irq_dma1_stream7(void) { + dma_irq_handler(DMA1, DMA_S7); +} + +void __irq_dma2_stream0(void) { + dma_irq_handler(DMA2, DMA_S0); +} + +void __irq_dma2_stream1(void) { + dma_irq_handler(DMA2, DMA_S1); +} + +void __irq_dma2_stream2(void) { + dma_irq_handler(DMA2, DMA_S2); +} + +void __irq_dma2_stream3(void) { + dma_irq_handler(DMA2, DMA_S3); +} + +void __irq_dma2_stream4(void) { + dma_irq_handler(DMA2, DMA_S4); +} + +void __irq_dma2_stream5(void) { + dma_irq_handler(DMA2, DMA_S5); +} + +void __irq_dma2_stream6(void) { + dma_irq_handler(DMA2, DMA_S6); +} + +void __irq_dma2_stream7(void) { + dma_irq_handler(DMA2, DMA_S7); +} + +/* + * Auxiliary routines for dma_tube_cfg() + */ + +/* Is addr acceptable for use as DMA src/dst? */ +static int cfg_mem_ok(__io void *addr) { + enum dma_atype atype = _dma_addr_type(addr); + return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER; +} + +/* Is src -> dst a reasonable combination of [MEM,PER] -> [MEM,PER]? */ +static int cfg_dir_ok(dma_dev *dev, __io void *src, __io void *dst) { + switch (_dma_addr_type(dst)) { + case DMA_ATYPE_MEM: + /* Only DMA2 can do memory-to-memory */ + return ((_dma_addr_type(src) == DMA_ATYPE_PER) || + (dev->clk_id == RCC_DMA2)); + case DMA_ATYPE_PER: + /* Peripheral-to-peripheral is illegal */ + return _dma_addr_type(src) == DMA_ATYPE_PER; + default: /* Can't happen */ + ASSERT(0); + return 0; + } +} + +/* Initial sanity check for dma_tube_cfg() */ +static int preconfig_check(dma_dev *dev, dma_tube tube, + dma_tube_config *cfg) { + if (!(src_stream_mask(cfg->tube_req_src) & (1U << tube))) { + /* ->tube_req_src not supported by stream */ + return -DMA_TUBE_CFG_EREQ; + } + if (cfg->tube_nr_xfers > 65535) { + /* That's too many. */ + return -DMA_TUBE_CFG_ENDATA; + } + if (src_clk_id(cfg->tube_req_src) != dev->clk_id) { + /* ->tube_req_src not supported by dev */ + return -DMA_TUBE_CFG_EDEV; + } + if (!cfg_mem_ok(cfg->tube_src)) { + return -DMA_TUBE_CFG_ESRC; + } + if (!cfg_mem_ok(cfg->tube_dst)) { + return -DMA_TUBE_CFG_EDST; + } + if (!cfg_dir_ok(dev, cfg->tube_src, cfg->tube_dst)) { + return -DMA_TUBE_CFG_EDIR; + } + return DMA_TUBE_CFG_SUCCESS; +} + +static int config_fifo(dma_tube_reg_map *dummy, dma_tube_config *cfg) { + /* TODO: FIFO configuration based on cfg->target_data */ + uint32 sfcr = dummy->SFCR; + sfcr &= ~DMA_SFCR_FEIE; + sfcr |= (cfg->tube_flags & DMA_CFG_FIFO_ERR_IE) ? DMA_SFCR_FEIE : 0; + dummy->SFCR = sfcr; + return DMA_TUBE_CFG_SUCCESS; +} + +/* Helper for configuring (DMA_SxCR) */ +#define BITS_WE_CARE_ABOUT \ + (DMA_SCR_CHSEL | DMA_SCR_MBURST | DMA_SCR_PBURST | DMA_SCR_PINCOS | \ + DMA_SCR_MINC | DMA_SCR_PINC | DMA_SCR_CIRC | DMA_SCR_DIR | \ + DMA_SCR_PFCTRL | DMA_SCR_TCIE | DMA_SCR_HTIE | DMA_SCR_TEIE | \ + DMA_SCR_DMEIE) +static inline void config_scr(dma_tube_reg_map *dummy, dma_tube_config *cfg, + unsigned src_shift, uint32 src_inc, + unsigned dst_shift, uint32 dst_inc, + uint32 dir) { + /* These would go here if we supported them: MBURST, PBURST, + * PINCOS, PFCTRL. We explicitly choose low priority, and double + * buffering belongs elsewhere, I think. [mbolivar] */ + uint32 flags = cfg->tube_flags & BITS_WE_CARE_ABOUT; + uint32 scr = dummy->SCR; + scr &= ~(BITS_WE_CARE_ABOUT | DMA_SCR_PL); + scr |= (/* CHSEL */ + (src_channel(cfg->tube_req_src) << 25) | + /* MSIZE/PSIZE */ + (cfg->tube_src_size << src_shift) | + (cfg->tube_dst_size << dst_shift) | + /* MINC/PINC */ + ((cfg->tube_flags & DMA_CFG_SRC_INC) ? src_inc : 0) | + ((cfg->tube_flags & DMA_CFG_DST_INC) ? dst_inc : 0) | + /* DIR */ + dir | + /* Other flags carried by cfg->tube_flags */ + flags); + dummy->SCR = scr; +} +#undef BITS_WE_CARE_ABOUT + +/* Helper for when cfg->tube_dst is memory */ +static int config_to_mem(dma_tube_reg_map *dummy, dma_tube_config *cfg) { + uint32 dir = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ? + DMA_SCR_DIR_MEM_TO_MEM : DMA_SCR_DIR_PER_TO_MEM); + + if ((dir == DMA_SCR_DIR_MEM_TO_MEM) && (cfg->tube_flags & DMA_CFG_CIRC)) { + return -DMA_TUBE_CFG_ECFG; /* Can't do DMA_CFG_CIRC and mem->mem. */ + } + + config_scr(dummy, cfg, 11, DMA_SCR_PINC, 13, DMA_SCR_MINC, dir); + dummy->SPAR = (uint32)cfg->tube_src; + dummy->SM0AR = (uint32)cfg->tube_dst; + return DMA_TUBE_CFG_SUCCESS; +} + +/* Helper for when cfg->tube_src is peripheral */ +static int config_to_per(dma_tube_reg_map *dummy, dma_tube_config *cfg) { + config_scr(dummy, cfg, 13, DMA_SCR_MINC, 11, DMA_SCR_PINC, + DMA_SCR_DIR_MEM_TO_PER); + dummy->SM0AR = (uint32)cfg->tube_src; + dummy->SPAR = (uint32)cfg->tube_dst; + return DMA_TUBE_CFG_SUCCESS; +} + +/* Configures SCR, SPAR, SM0AR, and checks that the result is OK. */ +static int config_src_dst(dma_tube_reg_map *dummy, dma_tube_config *cfg) { + switch (_dma_addr_type(cfg->tube_dst)) { + case DMA_ATYPE_MEM: + return config_to_mem(dummy, cfg); + case DMA_ATYPE_PER: + return config_to_per(dummy, cfg); + case DMA_ATYPE_OTHER: + default: /* shut up, GCC */ + /* Can't happen */ + ASSERT(0); + return -DMA_TUBE_CFG_ECFG; + } +} + +/* Final checks we can only perform when fully configured */ +static int postconfig_check(dma_tube_reg_map *dummy, dma_tube_config *cfg) { + /* TODO add dma_get_[mem,per]_size() and use them here */ + /* msize and psize are in bytes here: */ + uint32 scr = dummy->SCR; + uint32 msize = 1U << ((scr >> 13) & 0x3); + uint32 psize = 1U << ((scr >> 11) & 0x3); + + /* Ensure NDT will work with PSIZE/MSIZE. + * + * RM0033 specifies that PSIZE, MSIZE, and NDT must be such that + * the last transfer completes; i.e. that if PSIZE < MSIZE, then + * NDT is a multiple of MSIZE/PSIZE. See e.g. Table 27. */ + if ((psize < msize) && (cfg->tube_nr_xfers % (msize / psize))) { + return -DMA_TUBE_CFG_ENDATA; + } + + /* Direct mode is only possible if MSIZE == PSIZE. */ + if ((msize != psize) && !(dummy->SFCR & DMA_SFCR_DMDIS)) { + return -DMA_TUBE_CFG_ESIZE; + } + + return DMA_TUBE_CFG_SUCCESS; +} + +/* Convenience for dealing with dummy registers */ +static void copy_regs(dma_tube_reg_map *src, dma_tube_reg_map *dst) { + dst->SCR = src->SCR; + dst->SNDTR = src->SNDTR; + dst->SPAR = src->SPAR; + dst->SM0AR = src->SM0AR; + dst->SFCR = src->SFCR; +} diff --git a/libmaple/stm32f2/exti.c b/libmaple/stm32f2/exti.c new file mode 100644 index 0000000..208415f --- /dev/null +++ b/libmaple/stm32f2/exti.c @@ -0,0 +1,33 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +#include <libmaple/exti.h> +#include <libmaple/syscfg.h> +#include "exti_private.h" + +void exti_select(exti_num num, exti_cfg cfg) { + exti_do_select(&SYSCFG_BASE->EXTICR[num / 4], num, cfg); +} diff --git a/libmaple/stm32f2/fsmc.c b/libmaple/stm32f2/fsmc.c new file mode 100644 index 0000000..ec41720 --- /dev/null +++ b/libmaple/stm32f2/fsmc.c @@ -0,0 +1,90 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/fsmc.c + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 FSMC support. + */ + +#include <libmaple/fsmc.h> +#include <libmaple/gpio.h> + +#define CONFIG_GPIO(dev, bit) \ + do { \ + gpio_set_modef(dev, bit, GPIO_MODE_AF, GPIO_MODEF_SPEED_HIGH); \ + gpio_set_af(dev, bit, GPIO_AF_FSMC_SDIO_OTG_FS); \ + } while (0) +void fsmc_sram_init_gpios(void) { + /* Data lines... */ + CONFIG_GPIO(GPIOD, 0); + CONFIG_GPIO(GPIOD, 1); + CONFIG_GPIO(GPIOD, 8); + CONFIG_GPIO(GPIOD, 9); + CONFIG_GPIO(GPIOD, 10); + CONFIG_GPIO(GPIOD, 14); + CONFIG_GPIO(GPIOD, 15); + CONFIG_GPIO(GPIOE, 7); + CONFIG_GPIO(GPIOE, 8); + CONFIG_GPIO(GPIOE, 9); + CONFIG_GPIO(GPIOE, 10); + CONFIG_GPIO(GPIOE, 11); + CONFIG_GPIO(GPIOE, 12); + CONFIG_GPIO(GPIOE, 13); + CONFIG_GPIO(GPIOE, 14); + CONFIG_GPIO(GPIOE, 15); + + /* Address lines... */ + CONFIG_GPIO(GPIOD, 11); + CONFIG_GPIO(GPIOD, 12); + CONFIG_GPIO(GPIOD, 13); + CONFIG_GPIO(GPIOF, 0); + CONFIG_GPIO(GPIOF, 1); + CONFIG_GPIO(GPIOF, 2); + CONFIG_GPIO(GPIOF, 3); + CONFIG_GPIO(GPIOF, 4); + CONFIG_GPIO(GPIOF, 5); + CONFIG_GPIO(GPIOF, 12); + CONFIG_GPIO(GPIOF, 13); + CONFIG_GPIO(GPIOF, 14); + CONFIG_GPIO(GPIOF, 15); + CONFIG_GPIO(GPIOG, 0); + CONFIG_GPIO(GPIOG, 1); + CONFIG_GPIO(GPIOG, 2); + CONFIG_GPIO(GPIOG, 3); + CONFIG_GPIO(GPIOG, 4); + CONFIG_GPIO(GPIOG, 5); + + /* And control lines... */ + CONFIG_GPIO(GPIOD, 4); + CONFIG_GPIO(GPIOD, 5); + CONFIG_GPIO(GPIOD, 7); + CONFIG_GPIO(GPIOG, 9); + CONFIG_GPIO(GPIOG, 10); + CONFIG_GPIO(GPIOG, 12); + CONFIG_GPIO(GPIOE, 0); + CONFIG_GPIO(GPIOE, 1); +} diff --git a/libmaple/stm32f2/gpio.c b/libmaple/stm32f2/gpio.c new file mode 100644 index 0000000..a26edaa --- /dev/null +++ b/libmaple/stm32f2/gpio.c @@ -0,0 +1,194 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/gpio.c + * @brief STM32F2 GPIO. + */ + +#include <libmaple/gpio.h> +#include <libmaple/rcc.h> +#include <libmaple/bitband.h> + +/* + * GPIO devices + */ + +gpio_dev gpioa = { + .regs = GPIOA_BASE, + .clk_id = RCC_GPIOA, + .exti_port = EXTI_PA, +}; +/** GPIO port A device. */ +gpio_dev* const GPIOA = &gpioa; + +gpio_dev gpiob = { + .regs = GPIOB_BASE, + .clk_id = RCC_GPIOB, + .exti_port = EXTI_PB, +}; +/** GPIO port B device. */ +gpio_dev* const GPIOB = &gpiob; + +gpio_dev gpioc = { + .regs = GPIOC_BASE, + .clk_id = RCC_GPIOC, + .exti_port = EXTI_PC, +}; +/** GPIO port C device. */ +gpio_dev* const GPIOC = &gpioc; + +gpio_dev gpiod = { + .regs = GPIOD_BASE, + .clk_id = RCC_GPIOD, + .exti_port = EXTI_PD, +}; +/** GPIO port D device. */ +gpio_dev* const GPIOD = &gpiod; + +gpio_dev gpioe = { + .regs = GPIOE_BASE, + .clk_id = RCC_GPIOE, + .exti_port = EXTI_PE, +}; +/** GPIO port E device. */ +gpio_dev* const GPIOE = &gpioe; + +gpio_dev gpiof = { + .regs = GPIOF_BASE, + .clk_id = RCC_GPIOF, + .exti_port = EXTI_PF, +}; +/** GPIO port F device. */ +gpio_dev* const GPIOF = &gpiof; + +gpio_dev gpiog = { + .regs = GPIOG_BASE, + .clk_id = RCC_GPIOG, + .exti_port = EXTI_PG, +}; +/** GPIO port G device. */ +gpio_dev* const GPIOG = &gpiog; + +gpio_dev gpioh = { + .regs = GPIOH_BASE, + .clk_id = RCC_GPIOH, + .exti_port = EXTI_PH, +}; +/** GPIO port G device. */ +gpio_dev* const GPIOH = &gpioh; + +gpio_dev gpioi = { + .regs = GPIOI_BASE, + .clk_id = RCC_GPIOI, + .exti_port = EXTI_PI, +}; +/** GPIO port G device. */ +gpio_dev* const GPIOI = &gpioi; + +/* + * GPIO routines + */ + +/** + * Initialize and reset all available GPIO devices. + */ +void gpio_init_all(void) { + gpio_init(GPIOA); + gpio_init(GPIOB); + gpio_init(GPIOC); + gpio_init(GPIOD); + gpio_init(GPIOE); + gpio_init(GPIOF); + gpio_init(GPIOG); + gpio_init(GPIOH); + gpio_init(GPIOI); +} + +/** + * @brief Set the mode of a GPIO pin. + * @param dev GPIO device. + * @param bit Bit on dev whose mode to set, 0--15. + * @param mode Mode to set the pin to. + * @param flags Flags to modify basic mode configuration + */ +void gpio_set_modef(gpio_dev *dev, + uint8 bit, + gpio_pin_mode mode, + unsigned flags) { + gpio_reg_map *regs = dev->regs; + unsigned shift = bit * 2; + uint32 tmp; + + /* Mode */ + tmp = regs->MODER; + tmp &= ~(0x3 << shift); + tmp |= mode << shift; + regs->MODER = tmp; + + /* Output type */ + bb_peri_set_bit(®s->OTYPER, bit, flags & 0x1); + + /* Speed */ + tmp = regs->OSPEEDR; + tmp &= ~(0x3 << shift); + tmp |= ((flags >> 1) & 0x3) << shift; + regs->OSPEEDR = tmp; + + /* Pull-up/pull-down */ + tmp = regs->PUPDR; + tmp &= ~(0x3 << shift); + tmp |= ((flags >> 3) & 0x3) << shift; + regs->PUPDR = tmp; +} + +/** + * @brief Set a pin's alternate function. + * + * The pin must have its mode set to GPIO_MODE_AF for this to take + * effect. + * + * @param dev Device whose pin to configure. + * @param bit Pin whose alternate function to set. + * @param af Alternate function to use for pin. + * @see gpio_set_modef() + */ +void gpio_set_af(gpio_dev *dev, uint8 bit, gpio_af af) { + __io uint32 *afr; + unsigned shift; + uint32 tmp; + if (bit >= 8) { + afr = &dev->regs->AFRH; + shift = 4 * (bit - 8); + } else{ + afr = &dev->regs->AFRL; + shift = 4 * bit; + } + tmp = *afr; + tmp &= ~(0xF << shift); + tmp |= (af << shift); + *afr = tmp; +} diff --git a/libmaple/stm32f2/include/series/adc.h b/libmaple/stm32f2/include/series/adc.h new file mode 100644 index 0000000..714179c --- /dev/null +++ b/libmaple/stm32f2/include/series/adc.h @@ -0,0 +1,331 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/adc.h + * @author Marti Bolivar <mbolivar@leaflabs.com>, + * @brief STM32F2 ADC support. + */ + +#ifndef _LIBMAPLE_STM32F2_ADC_H_ +#define _LIBMAPLE_STM32F2_ADC_H_ + +#include <libmaple/libmaple_types.h> + +/* + * Devices + */ + +extern const struct adc_dev *ADC1; +extern const struct adc_dev *ADC2; +extern const struct adc_dev *ADC3; + +/* + * Common register map + */ + +/** ADC common register map type */ +typedef struct adc_common_reg_map { + __io uint32 CSR; /**< Common status register */ + __io uint32 CCR; /**< Common control register */ + __io uint32 CDR; /**< + * @brief Common regular data register + * for dual and triple modes */ +} adc_common_reg_map; + +/* + * Register map base pointers + */ + +/** ADC1 register map base pointer. */ +#define ADC1_BASE ((struct adc_reg_map*)0x40012000) +/** ADC2 register map base pointer. */ +#define ADC2_BASE ((struct adc_reg_map*)0x40012100) +/** ADC3 register map base pointer. */ +#define ADC3_BASE ((struct adc_reg_map*)0x40012200) +/** ADC common register map base pointer. */ +#define ADC_COMMON_BASE ((struct adc_common_reg_map*)0x40012300) + +/* + * Register bit definitions + */ + +/* Status register */ + +/** Overrun bit. */ +#define ADC_SR_OVR_BIT 5 +/** Overrun. */ +#define ADC_SR_OVR (1U << ADC_SR_OVR_BIT) + +/* Control register 1 */ + +/** Overrun interrupt enable bit. */ +#define ADC_CR1_OVRIE_BIT 26 + +/** Overrun interrupt error enable. */ +#define ADC_CR1_OVRIE (1U << ADC_CR1_OVRIE_BIT) +/** Conversion resolution. */ +#define ADC_CR1_RES (0x3U << 24) +/** Conversion resolution: 12 bit (at least 15 ADCCLK cycles). */ +#define ADC_CR1_RES_12BIT (0x0U << 24) +/** Conversion resolution: 10 bit (at least 13 ADCCLK cycles). */ +#define ADC_CR1_RES_10BIT (0x1U << 24) +/** Conversion resolution: 8 bit (at least 11 ADCCLK cycles). */ +#define ADC_CR1_RES_8BIT (0x2U << 24) +/** Conversion resolution: 6 bit (at least 9 ADCCLK cycles). */ +#define ADC_CR1_RES_6BIT (0x3U << 24) + +/* Control register 2 */ + +#define ADC_CR2_SWSTART_BIT 30 +#define ADC_CR2_JSWSTART_BIT 22 +#define ADC_CR2_ALIGN_BIT 11 +#define ADC_CR2_EOCS_BIT 10 +#define ADC_CR2_DDS_BIT 9 +#define ADC_CR2_DMA_BIT 8 +#define ADC_CR2_CONT_BIT 1 +#define ADC_CR2_ADON_BIT 0 + +#define ADC_CR2_SWSTART (1U << ADC_CR2_SWSTART_BIT) +#define ADC_CR2_EXTEN (0x3 << 28) +#define ADC_CR2_EXTEN_DISABLED (0x0 << 28) +#define ADC_CR2_EXTEN_RISE (0x1 << 28) +#define ADC_CR2_EXTEN_FALL (0x2 << 28) +#define ADC_CR2_EXTEN_RISE_FALL (0x3 << 28) +#define ADC_CR2_EXTSEL (0xF << 24) +#define ADC_CR2_EXTSEL_TIM1_CC1 (0x0 << 24) +#define ADC_CR2_EXTSEL_TIM1_CC2 (0x1 << 24) +#define ADC_CR2_EXTSEL_TIM1_CC3 (0x2 << 24) +#define ADC_CR2_EXTSEL_TIM2_CC2 (0x3 << 24) +#define ADC_CR2_EXTSEL_TIM2_CC3 (0x4 << 24) +#define ADC_CR2_EXTSEL_TIM2_CC4 (0x5 << 24) +#define ADC_CR2_EXTSEL_TIM1_TRGO (0x6 << 24) +#define ADC_CR2_EXTSEL_TIM3_CC1 (0x7 << 24) +#define ADC_CR2_EXTSEL_TIM3_TRGO (0x8 << 24) +#define ADC_CR2_EXTSEL_TIM4_CC4 (0x9 << 24) +#define ADC_CR2_EXTSEL_TIM5_CC1 (0xA << 24) +#define ADC_CR2_EXTSEL_TIM5_CC2 (0xB << 24) +#define ADC_CR2_EXTSEL_TIM5_CC3 (0xC << 24) +#define ADC_CR2_EXTSEL_TIM8_CC1 (0xD << 24) +#define ADC_CR2_EXTSEL_TIM8_TRGO (0xE << 24) +#define ADC_CR2_EXTSEL_TIM1_EXTI11 (0xF << 24) +#define ADC_CR2_JSWSTART (1U << ADC_CR2_JSWSTART_BIT) +#define ADC_CR2_JEXTEN (0x3 << 20) +#define ADC_CR2_JEXTEN_DISABLED (0x0 << 20) +#define ADC_CR2_JEXTEN_RISE (0x1 << 20) +#define ADC_CR2_JEXTEN_FALL (0x2 << 20) +#define ADC_CR2_JEXTEN_RISE_FALL (0x3 << 20) +#define ADC_CR2_JEXTSEL (0xF << 16) +#define ADC_CR2_JEXTSEL_TIM1_CC4 (0x0 << 16) +#define ADC_CR2_JEXTSEL_TIM1_TRGO (0x1 << 16) +#define ADC_CR2_JEXTSEL_TIM2_CC1 (0x2 << 16) +#define ADC_CR2_JEXTSEL_TIM2_TRGO (0x3 << 16) +#define ADC_CR2_JEXTSEL_TIM3_CC2 (0x4 << 16) +#define ADC_CR2_JEXTSEL_TIM3_CC4 (0x5 << 16) +#define ADC_CR2_JEXTSEL_TIM4_CC1 (0x6 << 16) +#define ADC_CR2_JEXTSEL_TIM4_CC2 (0x7 << 16) +#define ADC_CR2_JEXTSEL_TIM4_CC3 (0x8 << 16) +#define ADC_CR2_JEXTSEL_TIM4_TRGO (0x9 << 16) +#define ADC_CR2_JEXTSEL_TIM5_CC4 (0xA << 16) +#define ADC_CR2_JEXTSEL_TIM5_TRGO (0xB << 16) +#define ADC_CR2_JEXTSEL_TIM8_CC2 (0xC << 16) +#define ADC_CR2_JEXTSEL_TIM8_CC3 (0xD << 16) +#define ADC_CR2_JEXTSEL_TIM8_CC4 (0xE << 16) +#define ADC_CR2_JEXTSEL_TIM1_EXTI15 (0xF << 16) +#define ADC_CR2_ALIGN (1U << ADC_CR2_ALIGN_BIT) +#define ADC_CR2_ALIGN_RIGHT (0U << ADC_CR2_ALIGN_BIT) +#define ADC_CR2_ALIGN_LEFT (1U << ADC_CR2_ALIGN_BIT) +#define ADC_CR2_EOCS (1U << ADC_CR2_EOCS_BIT) +#define ADC_CR2_EOCS_SEQUENCE (0U << ADC_CR2_EOCS_BIT) +#define ADC_CR2_EOCS_CONVERSION (1U << ADC_CR2_EOCS_BIT) +#define ADC_CR2_DDS (1U << ADC_CR2_DDS_BIT) +#define ADC_CR2_DMA (1U << ADC_CR2_DMA_BIT) +#define ADC_CR2_CONT (1U << ADC_CR2_CONT_BIT) +#define ADC_CR2_ADON (1U << ADC_CR2_ADON_BIT) + +/* Common status register */ + +#define ADC_CSR_OVR3_BIT 21 +#define ADC_CSR_STRT3_BIT 20 +#define ADC_CSR_JSTRT3_BIT 19 +#define ADC_CSR_JEOC3_BIT 18 +#define ADC_CSR_EOC3_BIT 17 +#define ADC_CSR_AWD3_BIT 16 +#define ADC_CSR_OVR2_BIT 13 +#define ADC_CSR_STRT2_BIT 12 +#define ADC_CSR_JSTRT2_BIT 11 +#define ADC_CSR_JEOC2_BIT 10 +#define ADC_CSR_EOC2_BIT 9 +#define ADC_CSR_AWD2_BIT 8 +#define ADC_CSR_OVR1_BIT 5 +#define ADC_CSR_STRT1_BIT 4 +#define ADC_CSR_JSTRT1_BIT 3 +#define ADC_CSR_JEOC1_BIT 2 +#define ADC_CSR_EOC1_BIT 1 +#define ADC_CSR_AWD1_BIT 0 + +#define ADC_CSR_OVR3 (1U << ADC_CSR_OVR3_BIT) +#define ADC_CSR_STRT3 (1U << ADC_CSR_STRT3_BIT) +#define ADC_CSR_JSTRT3 (1U << ADC_CSR_JSTRT3_BIT) +#define ADC_CSR_JEOC3 (1U << ADC_CSR_JEOC3_BIT) +#define ADC_CSR_EOC3 (1U << ADC_CSR_EOC3_BIT) +#define ADC_CSR_AWD3 (1U << ADC_CSR_AWD3_BIT) +#define ADC_CSR_OVR2 (1U << ADC_CSR_OVR2_BIT) +#define ADC_CSR_STRT2 (1U << ADC_CSR_STRT2_BIT) +#define ADC_CSR_JSTRT2 (1U << ADC_CSR_JSTRT2_BIT) +#define ADC_CSR_JEOC2 (1U << ADC_CSR_JEOC2_BIT) +#define ADC_CSR_EOC2 (1U << ADC_CSR_EOC2_BIT) +#define ADC_CSR_AWD2 (1U << ADC_CSR_AWD2_BIT) +#define ADC_CSR_OVR1 (1U << ADC_CSR_OVR1_BIT) +#define ADC_CSR_STRT1 (1U << ADC_CSR_STRT1_BIT) +#define ADC_CSR_JSTRT1 (1U << ADC_CSR_JSTRT1_BIT) +#define ADC_CSR_JEOC1 (1U << ADC_CSR_JEOC1_BIT) +#define ADC_CSR_EOC1 (1U << ADC_CSR_EOC1_BIT) +#define ADC_CSR_AWD1 (1U << ADC_CSR_AWD1_BIT) + +/* Common control register */ + +#define ADC_CCR_TSVREFE_BIT 23 +#define ADC_CCR_VBATE_BIT 22 +#define ADC_CCR_DDS_BIT 13 + +#define ADC_CCR_TSVREFE (1U << ADC_CCR_TSVREFE_BIT) +#define ADC_CCR_VBATE (1U << ADC_CCR_VBATE_BIT) +#define ADC_CCR_ADCPRE (0x3 << 16) +#define ADC_CCR_ADCPRE_PCLK2_DIV_2 (0x0 << 16) +#define ADC_CCR_ADCPRE_PCLK2_DIV_4 (0x1 << 16) +#define ADC_CCR_ADCPRE_PCLK2_DIV_6 (0x2 << 16) +#define ADC_CCR_ADCPRE_PCLK2_DIV_8 (0x3 << 16) +#define ADC_CCR_DMA (0x3 << 14) +#define ADC_CCR_DMA_DIS (0x0 << 14) +#define ADC_CCR_DMA_MODE_1 (0x1 << 14) +#define ADC_CCR_DMA_MODE_2 (0x2 << 14) +#define ADC_CCR_DMA_MODE_3 (0x3 << 14) +#define ADC_CCR_DDS (1U << ADC_CCR_DDS_BIT) +#define ADC_CCR_DELAY (0xF << 8) +#define ADC_CCR_DELAY_5 (0x0 << 8) +#define ADC_CCR_DELAY_6 (0x1 << 8) +#define ADC_CCR_DELAY_7 (0x2 << 8) +#define ADC_CCR_DELAY_8 (0x3 << 8) +#define ADC_CCR_DELAY_9 (0x4 << 8) +#define ADC_CCR_DELAY_10 (0x5 << 8) +#define ADC_CCR_DELAY_11 (0x6 << 8) +#define ADC_CCR_DELAY_12 (0x7 << 8) +#define ADC_CCR_DELAY_13 (0x8 << 8) +#define ADC_CCR_DELAY_14 (0x9 << 8) +#define ADC_CCR_DELAY_15 (0xA << 8) +#define ADC_CCR_DELAY_16 (0xB << 8) +#define ADC_CCR_DELAY_17 (0xC << 8) +#define ADC_CCR_DELAY_18 (0xD << 8) +#define ADC_CCR_DELAY_19 (0xE << 8) +#define ADC_CCR_DELAY_20 (0xF << 8) +/** Multi ADC mode selection. */ +#define ADC_CCR_MULTI 0x1F +/** All ADCs independent. */ +#define ADC_CCR_MULTI_INDEPENDENT 0x0 +/** Dual mode: combined regular simultaneous/injected simultaneous. */ +#define ADC_CCR_MULTI_DUAL_REG_SIM_INJ_SIM 0x1 +/** Dual mode: combined regular simultaneous/alternate trigger. */ +#define ADC_CCR_MULTI_DUAL_REG_SIM_ALT_TRIG 0x2 +/** Dual mode: injected simultaneous mode only. */ +#define ADC_CCR_MULTI_DUAL_INJ_SIM 0x5 +/** Dual mode: regular simultaneous mode only. */ +#define ADC_CCR_MULTI_DUAL_REG_SIM 0x6 +/** Dual mode: interleaved mode only. */ +#define ADC_CCR_MULTI_DUAL_INTER 0x7 +/** Dual mode: alternate trigger mode only. */ +#define ADC_CCR_MULTI_DUAL_ALT_TRIG 0x9 +/** Triple mode: combined regular simultaneous/injected simultaneous. */ +#define ADC_CCR_MULTI_TRIPLE_REG_SIM_INJ_SIM 0x10 +/** Triple mode: combined regular simultaneous/alternate trigger. */ +#define ADC_CCR_MULTI_TRIPLE_REG_SIM_ALT_TRIG 0x11 +/** Triple mode: injected simultaneous mode only. */ +#define ADC_CCR_MULTI_TRIPLE_INJ_SIM 0x12 +/** Triple mode: regular simultaneous mode only. */ +#define ADC_CCR_MULTI_TRIPLE_REG_SIM 0x15 +/** Triple mode: interleaved mode only. */ +#define ADC_CCR_MULTI_TRIPLE_INTER 0x17 +/** Triple mode: alternate trigger mode only. */ +#define ADC_CCR_MULTI_TRIPLE_ALT_TRIG 0x19 + +/* Common regular data register for dual and triple modes */ + +#define ADC_CDR_DATA2 0xFFFF0000 +#define ADC_CDR_DATA1 0xFFFF + +/* + * Other types + */ + +/** + * @brief STM32F2 external event selectors for regular group + * conversion. + * @see adc_set_extsel() + */ +typedef enum adc_extsel_event { + ADC_EXT_EV_TIM1_CC1 = ADC_CR2_EXTSEL_TIM1_CC1, + ADC_EXT_EV_TIM1_CC2 = ADC_CR2_EXTSEL_TIM1_CC2, + ADC_EXT_EV_TIM1_CC3 = ADC_CR2_EXTSEL_TIM1_CC3, + ADC_EXT_EV_TIM2_CC2 = ADC_CR2_EXTSEL_TIM2_CC2, + ADC_EXT_EV_TIM2_CC3 = ADC_CR2_EXTSEL_TIM2_CC3, + ADC_EXT_EV_TIM2_CC4 = ADC_CR2_EXTSEL_TIM2_CC4, + ADC_EXT_EV_TIM1_TRGO = ADC_CR2_EXTSEL_TIM1_TRGO, + ADC_EXT_EV_TIM3_CC1 = ADC_CR2_EXTSEL_TIM3_CC1, + ADC_EXT_EV_TIM3_TRGO = ADC_CR2_EXTSEL_TIM3_TRGO, + ADC_EXT_EV_TIM4_CC4 = ADC_CR2_EXTSEL_TIM4_CC4, + ADC_EXT_EV_TIM5_CC1 = ADC_CR2_EXTSEL_TIM5_CC1, + ADC_EXT_EV_TIM5_CC2 = ADC_CR2_EXTSEL_TIM5_CC2, + ADC_EXT_EV_TIM5_CC3 = ADC_CR2_EXTSEL_TIM5_CC3, + ADC_EXT_EV_TIM8_CC1 = ADC_CR2_EXTSEL_TIM8_CC1, + ADC_EXT_EV_TIM8_TRGO = ADC_CR2_EXTSEL_TIM8_TRGO, + ADC_EXT_EV_TIM1_EXTI11 = ADC_CR2_EXTSEL_TIM1_EXTI11, +} adc_extsel_event; + +/** + * @brief STM32F2 sample times, in ADC clock cycles. + */ +typedef enum adc_smp_rate { + ADC_SMPR_3, /**< 3 ADC cycles */ + ADC_SMPR_15, /**< 15 ADC cycles */ + ADC_SMPR_28, /**< 28 ADC cycles */ + ADC_SMPR_56, /**< 56 ADC cycles */ + ADC_SMPR_84, /**< 84 ADC cycles */ + ADC_SMPR_112, /**< 112 ADC cycles */ + ADC_SMPR_144, /**< 144 ADC cycles */ + ADC_SMPR_480, /**< 480 ADC cycles */ +} adc_smp_rate; + +/** + * @brief STM32F2 ADC prescalers, as divisors of PCLK2. + */ +typedef enum adc_prescaler { + ADC_PRE_PCLK2_DIV_2 = ADC_CCR_ADCPRE_PCLK2_DIV_2, /** PCLK2 divided by 2 */ + ADC_PRE_PCLK2_DIV_4 = ADC_CCR_ADCPRE_PCLK2_DIV_4, /** PCLK2 divided by 4 */ + ADC_PRE_PCLK2_DIV_6 = ADC_CCR_ADCPRE_PCLK2_DIV_6, /** PCLK2 divided by 6 */ + ADC_PRE_PCLK2_DIV_8 = ADC_CCR_ADCPRE_PCLK2_DIV_8, /** PCLK2 divided by 8 */ +} adc_prescaler; + +#endif diff --git a/libmaple/stm32f2/include/series/dac.h b/libmaple/stm32f2/include/series/dac.h new file mode 100644 index 0000000..0a578ca --- /dev/null +++ b/libmaple/stm32f2/include/series/dac.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/dac.h + * @brief STM32F2 DAC support + */ + +#ifndef _LIBMAPLE_STM32F2_DAC_H_ +#define _LIBMAPLE_STM32F2_DAC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/* + * Register map type + */ + +/** STM32F2 DAC register map type. */ +typedef struct dac_reg_map { + __io uint32 CR; /**< Control register */ + __io uint32 SWTRIGR; /**< Software trigger register */ + __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + holding register */ + __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + holding register */ + __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + holding register */ + __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + holding register */ + __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + holding register */ + __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + holding register */ + __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + holding register */ + __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + holding register */ + __io uint32 DHR8RD; /**< Dual DAC 8-bit right-aligned data holding + register */ + __io uint32 DOR1; /**< Channel 1 data output register */ + __io uint32 DOR2; /**< Channel 2 data output register */ + __io uint32 SR; /**< Status register */ +} dac_reg_map; + +/* + * Register bit definitions + */ + +/* Control register */ + +#define DAC_CR_DMAUDRIE1 (1U << 13) /* Channel 1 DMA underrun + * interrupt enable */ +#define DAC_CR_DMAUDRIE2 (1U << 29) /* Channel 2 DMA underrun + * interrupt enable */ + +/* Status register */ + +#define DAC_SR_DMAUDR1 (1U << 13) /* Channel 1 DMA underrun + * occurred */ +#define DAC_SR_DMAUDR2 (1U << 29) /* Channel 2 DMA underrun + * ocurred */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/dma.h b/libmaple/stm32f2/include/series/dma.h new file mode 100644 index 0000000..43bd1a2 --- /dev/null +++ b/libmaple/stm32f2/include/series/dma.h @@ -0,0 +1,810 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/dma.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 DMA series header + */ + +#ifndef _LIBMAPLE_STM32F2_DMA_H_ +#define _LIBMAPLE_STM32F2_DMA_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/dma_common.h> +#include <libmaple/libmaple_types.h> + +/* + * Register map and base pointers + */ + +/** + * @brief STM32F2 DMA register map type. + */ +typedef struct dma_reg_map { + /* Isn't it nice how on F1, it's CCR1, but on F2, it's S1CR? */ + + /* Global DMA registers */ + __io uint32 LISR; /**< Low interrupt status register */ + __io uint32 HISR; /**< High interrupt status register */ + __io uint32 LIFCR; /**< Low interrupt flag clear register */ + __io uint32 HIFCR; /**< High interrupt flag clear register */ + /* Stream 0 registers */ + __io uint32 S0CR; /**< Stream 0 control register */ + __io uint32 S0NDTR; /**< Stream 0 number of data register */ + __io uint32 S0PAR; /**< Stream 0 peripheral address register */ + __io uint32 S0M0AR; /**< Stream 0 memory 0 address register */ + __io uint32 S0M1AR; /**< Stream 0 memory 1 address register */ + __io uint32 S0FCR; /**< Stream 0 FIFO control register */ + /* Stream 1 registers */ + __io uint32 S1CR; /**< Stream 1 control register */ + __io uint32 S1NDTR; /**< Stream 1 number of data register */ + __io uint32 S1PAR; /**< Stream 1 peripheral address register */ + __io uint32 S1M0AR; /**< Stream 1 memory 0 address register */ + __io uint32 S1M1AR; /**< Stream 1 memory 1 address register */ + __io uint32 S1FCR; /**< Stream 1 FIFO control register */ + /* Stream 2 registers */ + __io uint32 S2CR; /**< Stream 2 control register */ + __io uint32 S2NDTR; /**< Stream 2 number of data register */ + __io uint32 S2PAR; /**< Stream 2 peripheral address register */ + __io uint32 S2M0AR; /**< Stream 2 memory 0 address register */ + __io uint32 S2M1AR; /**< Stream 2 memory 1 address register */ + __io uint32 S2FCR; /**< Stream 2 FIFO control register */ + /* Stream 3 registers */ + __io uint32 S3CR; /**< Stream 3 control register */ + __io uint32 S3NDTR; /**< Stream 3 number of data register */ + __io uint32 S3PAR; /**< Stream 3 peripheral address register */ + __io uint32 S3M0AR; /**< Stream 3 memory 0 address register */ + __io uint32 S3M1AR; /**< Stream 3 memory 1 address register */ + __io uint32 S3FCR; /**< Stream 3 FIFO control register */ + /* Stream 4 registers */ + __io uint32 S4CR; /**< Stream 4 control register */ + __io uint32 S4NDTR; /**< Stream 4 number of data register */ + __io uint32 S4PAR; /**< Stream 4 peripheral address register */ + __io uint32 S4M0AR; /**< Stream 4 memory 0 address register */ + __io uint32 S4M1AR; /**< Stream 4 memory 1 address register */ + __io uint32 S4FCR; /**< Stream 4 FIFO control register */ + /* Stream 5 registers */ + __io uint32 S5CR; /**< Stream 5 control register */ + __io uint32 S5NDTR; /**< Stream 5 number of data register */ + __io uint32 S5PAR; /**< Stream 5 peripheral address register */ + __io uint32 S5M0AR; /**< Stream 5 memory 0 address register */ + __io uint32 S5M1AR; /**< Stream 5 memory 1 address register */ + __io uint32 S5FCR; /**< Stream 5 FIFO control register */ + /* Stream 6 registers */ + __io uint32 S6CR; /**< Stream 6 control register */ + __io uint32 S6NDTR; /**< Stream 6 number of data register */ + __io uint32 S6PAR; /**< Stream 6 peripheral address register */ + __io uint32 S6M0AR; /**< Stream 6 memory 0 address register */ + __io uint32 S6M1AR; /**< Stream 6 memory 1 address register */ + __io uint32 S6FCR; /**< Stream 6 FIFO control register */ + /* Stream 7 registers */ + __io uint32 S7CR; /**< Stream 7 control register */ + __io uint32 S7NDTR; /**< Stream 7 number of data register */ + __io uint32 S7PAR; /**< Stream 7 peripheral address register */ + __io uint32 S7M0AR; /**< Stream 7 memory 0 address register */ + __io uint32 S7M1AR; /**< Stream 7 memory 1 address register */ + __io uint32 S7FCR; /**< Stream 7 FIFO control register */ +} dma_reg_map; + +/** DMA controller 1 register map base pointer */ +#define DMA1_BASE ((struct dma_reg_map*)0x40026000) +/** DMA controller 2 register map base pointer */ +#define DMA2_BASE ((struct dma_reg_map*)0x40026400) + +/** + * @brief STM32F2 DMA stream (i.e. tube) register map type. + * Provides access to an individual stream's registers. + * @see dma_tube_regs() + */ +typedef struct dma_tube_reg_map { + __io uint32 SCR; /**< Stream configuration register */ + __io uint32 SNDTR; /**< Stream number of data register */ + __io uint32 SPAR; /**< Stream peripheral address register */ + __io uint32 SM0AR; /**< Stream memory 0 address register */ + __io uint32 SM1AR; /**< Stream memory 1 address register */ + __io uint32 SFCR; /**< Stream FIFO control register */ +} dma_tube_reg_map; + +/** DMA1 stream 0 register map base pointer */ +#define DMA1S0_BASE ((struct dma_tube_reg_map*)0x40026010) +/** DMA1 stream 1 register map base pointer */ +#define DMA1S1_BASE ((struct dma_tube_reg_map*)0x40026028) +/** DMA1 stream 2 register map base pointer */ +#define DMA1S2_BASE ((struct dma_tube_reg_map*)0x40026040) +/** DMA1 stream 3 register map base pointer */ +#define DMA1S3_BASE ((struct dma_tube_reg_map*)0x40026058) +/** DMA1 stream 4 register map base pointer */ +#define DMA1S4_BASE ((struct dma_tube_reg_map*)0x40026070) +/** DMA1 stream 5 register map base pointer */ +#define DMA1S5_BASE ((struct dma_tube_reg_map*)0x40026088) +/** DMA1 stream 6 register map base pointer */ +#define DMA1S6_BASE ((struct dma_tube_reg_map*)0x400260A0) +/** DMA1 stream 7 register map base pointer */ +#define DMA1S7_BASE ((struct dma_tube_reg_map*)0x400260B8) + +/** DMA2 stream 0 register map base pointer */ +#define DMA2S0_BASE ((struct dma_tube_reg_map*)0x40026410) +/** DMA2 stream 1 register map base pointer */ +#define DMA2S1_BASE ((struct dma_tube_reg_map*)0x40026028) +/** DMA2 stream 2 register map base pointer */ +#define DMA2S2_BASE ((struct dma_tube_reg_map*)0x40026040) +/** DMA2 stream 3 register map base pointer */ +#define DMA2S3_BASE ((struct dma_tube_reg_map*)0x40026058) +/** DMA2 stream 4 register map base pointer */ +#define DMA2S4_BASE ((struct dma_tube_reg_map*)0x40026070) +/** DMA2 stream 5 register map base pointer */ +#define DMA2S5_BASE ((struct dma_tube_reg_map*)0x40026088) +/** DMA2 stream 6 register map base pointer */ +#define DMA2S6_BASE ((struct dma_tube_reg_map*)0x400260A0) +/** DMA2 stream 7 register map base pointer */ +#define DMA2S7_BASE ((struct dma_tube_reg_map*)0x400260B8) + +/* + * Register bit definitions + */ + +/* Low interrupt status register */ + +#define DMA_LISR_TCIF3_BIT 27 +#define DMA_LISR_HTIF3_BIT 26 +#define DMA_LISR_TEIF3_BIT 25 +#define DMA_LISR_DMEIF3_BIT 24 +#define DMA_LISR_FEIF3_BIT 22 +#define DMA_LISR_TCIF2_BIT 21 +#define DMA_LISR_HTIF2_BIT 20 +#define DMA_LISR_TEIF2_BIT 19 +#define DMA_LISR_DMEIF2_BIT 18 +#define DMA_LISR_FEIF2_BIT 16 +#define DMA_LISR_TCIF1_BIT 11 +#define DMA_LISR_HTIF1_BIT 10 +#define DMA_LISR_TEIF1_BIT 9 +#define DMA_LISR_DMEIF1_BIT 8 +#define DMA_LISR_FEIF1_BIT 6 +#define DMA_LISR_TCIF0_BIT 5 +#define DMA_LISR_HTIF0_BIT 4 +#define DMA_LISR_TEIF0_BIT 3 +#define DMA_LISR_DMEIF0_BIT 2 +#define DMA_LISR_FEIF0_BIT 0 + +#define DMA_LISR_TCIF3 (1U << DMA_LISR_TCIF3_BIT) +#define DMA_LISR_HTIF3 (1U << DMA_LISR_HTIF3_BIT) +#define DMA_LISR_TEIF3 (1U << DMA_LISR_TEIF3_BIT) +#define DMA_LISR_DMEIF3 (1U << DMA_LISR_DMEIF3_BIT) +#define DMA_LISR_FEIF3 (1U << DMA_LISR_FEIF3_BIT) +#define DMA_LISR_TCIF2 (1U << DMA_LISR_TCIF2_BIT) +#define DMA_LISR_HTIF2 (1U << DMA_LISR_HTIF2_BIT) +#define DMA_LISR_TEIF2 (1U << DMA_LISR_TEIF2_BIT) +#define DMA_LISR_DMEIF2 (1U << DMA_LISR_DMEIF2_BIT) +#define DMA_LISR_FEIF2 (1U << DMA_LISR_FEIF2_BIT) +#define DMA_LISR_TCIF1 (1U << DMA_LISR_TCIF1_BIT) +#define DMA_LISR_HTIF1 (1U << DMA_LISR_HTIF1_BIT) +#define DMA_LISR_TEIF1 (1U << DMA_LISR_TEIF1_BIT) +#define DMA_LISR_DMEIF1 (1U << DMA_LISR_DMEIF1_BIT) +#define DMA_LISR_FEIF1 (1U << DMA_LISR_FEIF1_BIT) +#define DMA_LISR_TCIF0 (1U << DMA_LISR_TCIF0_BIT) +#define DMA_LISR_HTIF0 (1U << DMA_LISR_HTIF0_BIT) +#define DMA_LISR_TEIF0 (1U << DMA_LISR_TEIF0_BIT) +#define DMA_LISR_DMEIF0 (1U << DMA_LISR_DMEIF0_BIT) +#define DMA_LISR_FEIF0 (1U << DMA_LISR_FEIF0_BIT) + +/* High interrupt status register */ + +#define DMA_HISR_TCIF7_BIT 27 +#define DMA_HISR_HTIF7_BIT 26 +#define DMA_HISR_TEIF7_BIT 25 +#define DMA_HISR_DMEIF7_BIT 24 +#define DMA_HISR_FEIF7_BIT 22 +#define DMA_HISR_TCIF6_BIT 21 +#define DMA_HISR_HTIF6_BIT 20 +#define DMA_HISR_TEIF6_BIT 19 +#define DMA_HISR_DMEIF6_BIT 18 +#define DMA_HISR_FEIF6_BIT 16 +#define DMA_HISR_TCIF5_BIT 11 +#define DMA_HISR_HTIF5_BIT 10 +#define DMA_HISR_TEIF5_BIT 9 +#define DMA_HISR_DMEIF5_BIT 8 +#define DMA_HISR_FEIF5_BIT 6 +#define DMA_HISR_TCIF4_BIT 5 +#define DMA_HISR_HTIF4_BIT 4 +#define DMA_HISR_TEIF4_BIT 3 +#define DMA_HISR_DMEIF4_BIT 2 +#define DMA_HISR_FEIF4_BIT 0 + +#define DMA_HISR_TCIF7 (1U << DMA_HISR_TCIF7_BIT) +#define DMA_HISR_HTIF7 (1U << DMA_HISR_HTIF7_BIT) +#define DMA_HISR_TEIF7 (1U << DMA_HISR_TEIF7_BIT) +#define DMA_HISR_DMEIF7 (1U << DMA_HISR_DMEIF7_BIT) +#define DMA_HISR_FEIF7 (1U << DMA_HISR_FEIF7_BIT) +#define DMA_HISR_TCIF6 (1U << DMA_HISR_TCIF6_BIT) +#define DMA_HISR_HTIF6 (1U << DMA_HISR_HTIF6_BIT) +#define DMA_HISR_TEIF6 (1U << DMA_HISR_TEIF6_BIT) +#define DMA_HISR_DMEIF6 (1U << DMA_HISR_DMEIF6_BIT) +#define DMA_HISR_FEIF6 (1U << DMA_HISR_FEIF6_BIT) +#define DMA_HISR_TCIF5 (1U << DMA_HISR_TCIF5_BIT) +#define DMA_HISR_HTIF5 (1U << DMA_HISR_HTIF5_BIT) +#define DMA_HISR_TEIF5 (1U << DMA_HISR_TEIF5_BIT) +#define DMA_HISR_DMEIF5 (1U << DMA_HISR_DMEIF5_BIT) +#define DMA_HISR_FEIF5 (1U << DMA_HISR_FEIF5_BIT) +#define DMA_HISR_TCIF4 (1U << DMA_HISR_TCIF4_BIT) +#define DMA_HISR_HTIF4 (1U << DMA_HISR_HTIF4_BIT) +#define DMA_HISR_TEIF4 (1U << DMA_HISR_TEIF4_BIT) +#define DMA_HISR_DMEIF4 (1U << DMA_HISR_DMEIF4_BIT) +#define DMA_HISR_FEIF4 (1U << DMA_HISR_FEIF4_BIT) + +/* Low interrupt flag clear register */ + +#define DMA_LIFCR_CTCIF3_BIT 27 +#define DMA_LIFCR_CHTIF3_BIT 26 +#define DMA_LIFCR_CTEIF3_BIT 25 +#define DMA_LIFCR_CDMEIF3_BIT 24 +#define DMA_LIFCR_CFEIF3_BIT 22 +#define DMA_LIFCR_CTCIF2_BIT 21 +#define DMA_LIFCR_CHTIF2_BIT 20 +#define DMA_LIFCR_CTEIF2_BIT 19 +#define DMA_LIFCR_CDMEIF2_BIT 18 +#define DMA_LIFCR_CFEIF2_BIT 16 +#define DMA_LIFCR_CTCIF1_BIT 11 +#define DMA_LIFCR_CHTIF1_BIT 10 +#define DMA_LIFCR_CTEIF1_BIT 9 +#define DMA_LIFCR_CDMEIF1_BIT 8 +#define DMA_LIFCR_CFEIF1_BIT 6 +#define DMA_LIFCR_CTCIF0_BIT 5 +#define DMA_LIFCR_CHTIF0_BIT 4 +#define DMA_LIFCR_CTEIF0_BIT 3 +#define DMA_LIFCR_CDMEIF0_BIT 2 +#define DMA_LIFCR_CFEIF0_BIT 0 + +#define DMA_LIFCR_CTCIF3 (1U << DMA_LIFCR_CTCIF3_BIT) +#define DMA_LIFCR_CHTIF3 (1U << DMA_LIFCR_CHTIF3_BIT) +#define DMA_LIFCR_CTEIF3 (1U << DMA_LIFCR_CTEIF3_BIT) +#define DMA_LIFCR_CDMEIF3 (1U << DMA_LIFCR_CDMEIF3_BIT) +#define DMA_LIFCR_CFEIF3 (1U << DMA_LIFCR_CFEIF3_BIT) +#define DMA_LIFCR_CTCIF2 (1U << DMA_LIFCR_CTCIF2_BIT) +#define DMA_LIFCR_CHTIF2 (1U << DMA_LIFCR_CHTIF2_BIT) +#define DMA_LIFCR_CTEIF2 (1U << DMA_LIFCR_CTEIF2_BIT) +#define DMA_LIFCR_CDMEIF2 (1U << DMA_LIFCR_CDMEIF2_BIT) +#define DMA_LIFCR_CFEIF2 (1U << DMA_LIFCR_CFEIF2_BIT) +#define DMA_LIFCR_CTCIF1 (1U << DMA_LIFCR_CTCIF1_BIT) +#define DMA_LIFCR_CHTIF1 (1U << DMA_LIFCR_CHTIF1_BIT) +#define DMA_LIFCR_CTEIF1 (1U << DMA_LIFCR_CTEIF1_BIT) +#define DMA_LIFCR_CDMEIF1 (1U << DMA_LIFCR_CDMEIF1_BIT) +#define DMA_LIFCR_CFEIF1 (1U << DMA_LIFCR_CFEIF1_BIT) +#define DMA_LIFCR_CTCIF0 (1U << DMA_LIFCR_CTCIF0_BIT) +#define DMA_LIFCR_CHTIF0 (1U << DMA_LIFCR_CHTIF0_BIT) +#define DMA_LIFCR_CTEIF0 (1U << DMA_LIFCR_CTEIF0_BIT) +#define DMA_LIFCR_CDMEIF0 (1U << DMA_LIFCR_CDMEIF0_BIT) +#define DMA_LIFCR_CFEIF0 (1U << DMA_LIFCR_CFEIF0_BIT) + +/* High interrupt flag clear regsister */ + +#define DMA_HIFCR_CTCIF7_BIT 27 +#define DMA_HIFCR_CHTIF7_BIT 26 +#define DMA_HIFCR_CTEIF7_BIT 25 +#define DMA_HIFCR_CDMEIF7_BIT 24 +#define DMA_HIFCR_CFEIF7_BIT 22 +#define DMA_HIFCR_CTCIF6_BIT 21 +#define DMA_HIFCR_CHTIF6_BIT 20 +#define DMA_HIFCR_CTEIF6_BIT 19 +#define DMA_HIFCR_CDMEIF6_BIT 18 +#define DMA_HIFCR_CFEIF6_BIT 16 +#define DMA_HIFCR_CTCIF5_BIT 11 +#define DMA_HIFCR_CHTIF5_BIT 10 +#define DMA_HIFCR_CTEIF5_BIT 9 +#define DMA_HIFCR_CDMEIF5_BIT 8 +#define DMA_HIFCR_CFEIF5_BIT 6 +#define DMA_HIFCR_CTCIF4_BIT 5 +#define DMA_HIFCR_CHTIF4_BIT 4 +#define DMA_HIFCR_CTEIF4_BIT 3 +#define DMA_HIFCR_CDMEIF4_BIT 2 +#define DMA_HIFCR_CFEIF4_BIT 0 + +#define DMA_HIFCR_CTCIF7 (1U << DMA_HIFCR_CTCIF7_BIT) +#define DMA_HIFCR_CHTIF7 (1U << DMA_HIFCR_CHTIF7_BIT) +#define DMA_HIFCR_CTEIF7 (1U << DMA_HIFCR_CTEIF7_BIT) +#define DMA_HIFCR_CDMEIF7 (1U << DMA_HIFCR_CDMEIF7_BIT) +#define DMA_HIFCR_CFEIF7 (1U << DMA_HIFCR_CFEIF7_BIT) +#define DMA_HIFCR_CTCIF6 (1U << DMA_HIFCR_CTCIF6_BIT) +#define DMA_HIFCR_CHTIF6 (1U << DMA_HIFCR_CHTIF6_BIT) +#define DMA_HIFCR_CTEIF6 (1U << DMA_HIFCR_CTEIF6_BIT) +#define DMA_HIFCR_CDMEIF6 (1U << DMA_HIFCR_CDMEIF6_BIT) +#define DMA_HIFCR_CFEIF6 (1U << DMA_HIFCR_CFEIF6_BIT) +#define DMA_HIFCR_CTCIF5 (1U << DMA_HIFCR_CTCIF5_BIT) +#define DMA_HIFCR_CHTIF5 (1U << DMA_HIFCR_CHTIF5_BIT) +#define DMA_HIFCR_CTEIF5 (1U << DMA_HIFCR_CTEIF5_BIT) +#define DMA_HIFCR_CDMEIF5 (1U << DMA_HIFCR_CDMEIF5_BIT) +#define DMA_HIFCR_CFEIF5 (1U << DMA_HIFCR_CFEIF5_BIT) +#define DMA_HIFCR_CTCIF4 (1U << DMA_HIFCR_CTCIF4_BIT) +#define DMA_HIFCR_CHTIF4 (1U << DMA_HIFCR_CHTIF4_BIT) +#define DMA_HIFCR_CTEIF4 (1U << DMA_HIFCR_CTEIF4_BIT) +#define DMA_HIFCR_CDMEIF4 (1U << DMA_HIFCR_CDMEIF4_BIT) +#define DMA_HIFCR_CFEIF4 (1U << DMA_HIFCR_CFEIF4_BIT) + +/* Stream configuration register */ + +#define DMA_SCR_CT_BIT 19 +#define DMA_SCR_DBM_BIT 18 +#define DMA_SCR_PINCOS_BIT 15 +#define DMA_SCR_MINC_BIT 10 +#define DMA_SCR_PINC_BIT 9 +#define DMA_SCR_CIRC_BIT 8 +#define DMA_SCR_PFCTRL_BIT 5 +#define DMA_SCR_TCIE_BIT 4 +#define DMA_SCR_HTIE_BIT 3 +#define DMA_SCR_TEIE_BIT 2 +#define DMA_SCR_DMEIE_BIT 1 +#define DMA_SCR_EN_BIT 0 + +#define DMA_SCR_CHSEL (0x7 << 25) +#define DMA_SCR_CHSEL_CH_0 (0x0 << 25) +#define DMA_SCR_CHSEL_CH_1 (0x1 << 25) +#define DMA_SCR_CHSEL_CH_2 (0x2 << 25) +#define DMA_SCR_CHSEL_CH_3 (0x3 << 25) +#define DMA_SCR_CHSEL_CH_4 (0x4 << 25) +#define DMA_SCR_CHSEL_CH_5 (0x5 << 25) +#define DMA_SCR_CHSEL_CH_6 (0x6 << 25) +#define DMA_SCR_CHSEL_CH_7 (0x7 << 25) +#define DMA_SCR_MBURST (0x3 << 23) +#define DMA_SCR_MBURST_SINGLE (0x0 << 23) +#define DMA_SCR_MBURST_INCR4 (0x1 << 23) +#define DMA_SCR_MBURST_INCR8 (0x2 << 23) +#define DMA_SCR_MBURST_INCR16 (0x3 << 23) +#define DMA_SCR_PBURST (0x3 << 21) +#define DMA_SCR_PBURST_SINGLE (0x0 << 21) +#define DMA_SCR_PBURST_INCR4 (0x1 << 21) +#define DMA_SCR_PBURST_INCR8 (0x2 << 21) +#define DMA_SCR_PBURST_INCR16 (0x3 << 21) +#define DMA_SCR_CT (1U << DMA_SCR_CT_BIT) +#define DMA_SCR_DBM (1U << DMA_SCR_DBM_BIT) +#define DMA_SCR_PL (0x3 << 16) +#define DMA_SCR_PL_LOW (0x0 << 16) +#define DMA_SCR_PL_MEDIUM (0x1 << 16) +#define DMA_SCR_PL_HIGH (0x2 << 16) +#define DMA_SCR_VERY_HIGH (0x3 << 16) +#define DMA_SCR_PINCOS (1U << DMA_SCR_PINCOS_BIT) +#define DMA_SCR_MSIZE (0x3 << 13) +#define DMA_SCR_MSIZE_8BITS (0x0 << 13) +#define DMA_SCR_MSIZE_16BITS (0x1 << 13) +#define DMA_SCR_MSIZE_32BITS (0x2 << 13) +#define DMA_SCR_PSIZE (0x3 << 11) +#define DMA_SCR_PSIZE_8BITS (0x0 << 11) +#define DMA_SCR_PSIZE_16BITS (0x1 << 11) +#define DMA_SCR_PSIZE_32BITS (0x2 << 11) +#define DMA_SCR_MINC (1U << DMA_SCR_MINC_BIT) +#define DMA_SCR_PINC (1U << DMA_SCR_PINC_BIT) +#define DMA_SCR_CIRC (1U << DMA_SCR_CIRC_BIT) +#define DMA_SCR_DIR (0x3 << 6) +#define DMA_SCR_DIR_PER_TO_MEM (0x0 << 6) +#define DMA_SCR_DIR_MEM_TO_PER (0x1 << 6) +#define DMA_SCR_DIR_MEM_TO_MEM (0x2 << 6) +#define DMA_SCR_PFCTRL (1U << DMA_SCR_PFCTRL_BIT) +#define DMA_SCR_TCIE (1U << DMA_SCR_TCIE_BIT) +#define DMA_SCR_HTIE (1U << DMA_SCR_HTIE_BIT) +#define DMA_SCR_TEIE (1U << DMA_SCR_TEIE_BIT) +#define DMA_SCR_DMEIE (1U << DMA_SCR_DMEIE_BIT) +#define DMA_SCR_EN (1U << DMA_SCR_EN_BIT) + +/* Stream FIFO control register */ + +#define DMA_SFCR_FEIE_BIT 7 +#define DMA_SFCR_DMDIS_BIT 2 + +#define DMA_SFCR_FEIE (1U << DMA_SFCR_FEIE_BIT) +#define DMA_SFCR_FS (0x7 << 3) +#define DMA_SFCR_FS_ZERO_TO_QUARTER (0x0 << 3) +#define DMA_SFCR_FS_QUARTER_TO_HALF (0x1 << 3) +#define DMA_SFCR_FS_HALF_TO_THREE_QUARTERS (0x2 << 3) +#define DMA_SFCR_FS_THREE_QUARTERS_TO_FULL (0x3 << 3) +#define DMA_SFCR_FS_EMPTY (0x4 << 3) +#define DMA_SFCR_FS_FULL (0x5 << 3) +#define DMA_SFCR_DMDIS (1U << DMA_SFCR_DMDIS_BIT) +#define DMA_SFCR_FTH (0x3 << 0) +#define DMA_SFCR_FTH_QUARTER_FULL (0x0 << 3) +#define DMA_SFCR_FTH_HALF_FULL (0x1 << 3) +#define DMA_SFCR_FTH_THREE_QUARTERS_FULL (0x2 << 3) +#define DMA_SFCR_FTH_FULL (0x3 << 3) + +/* + * Devices + */ + +extern dma_dev *DMA1; +extern dma_dev *DMA2; + +/* + * Other types needed by, or useful for, <libmaple/dma.h> + */ + +/** + * @brief DMA streams + * This is also the dma_tube type for STM32F2. + * @see dma_tube + */ +typedef enum dma_stream { + DMA_S0 = 0, + DMA_S1 = 1, + DMA_S2 = 2, + DMA_S3 = 3, + DMA_S4 = 4, + DMA_S5 = 5, + DMA_S6 = 6, + DMA_S7 = 7, +} dma_stream; + +/** STM32F2 dma_tube (=dma_stream) */ +#define dma_tube dma_stream + +/** + * @brief STM32F2 configuration flags for dma_tube_config. + * @see struct dma_tube_config + */ +typedef enum dma_cfg_flags { + /* NB: flags that aren't SCR bits are treated specially. */ + + /** + * Source address increment mode + * + * If this flag is set, the source address is incremented (by the + * source size) after each DMA transfer. + */ + DMA_CFG_SRC_INC = 1U << 31, + + /** + * Destination address increment mode + * + * If this flag is set, the destination address is incremented (by + * the destination size) after each DMA transfer. + */ + DMA_CFG_DST_INC = 1U << 30, + + /** + * Circular mode + * + * This mode is not available for memory-to-memory transfers. + */ + DMA_CFG_CIRC = DMA_SCR_CIRC, + + /** Transfer complete interrupt enable */ + DMA_CFG_CMPLT_IE = DMA_SCR_TCIE, + /** Transfer half-complete interrupt enable */ + DMA_CFG_HALF_CMPLT_IE = DMA_SCR_HTIE, + /** Transfer error interrupt enable */ + DMA_CFG_ERR_IE = DMA_SCR_TEIE, + /** Direct mode error interrupt enable */ + DMA_CFG_DM_ERR_IE = DMA_SCR_DMEIE, + /** FIFO error interrupt enable */ + DMA_CFG_FIFO_ERR_IE = (1U << 29), +} dma_cfg_flags; + +/** + * @brief STM32F2 DMA request sources. + * + * IMPORTANT: + * + * 1. On STM32F2, a particular dma_request_src is always tied to a + * single DMA controller, but often can be supported by multiple + * streams. For example, DMA requests from ADC1 (DMA_REQ_SRC_ADC1) can + * only be handled by DMA2, but they can go to either stream 0 or + * stream 4 (though not any other stream). If you try to use a request + * source with the wrong DMA controller or the wrong stream on + * STM32F2, dma_tube_cfg() will fail. + * + * 2. A single stream can only handle a single request source at a + * time. If you change a stream's request source later, it will stop + * serving requests from the old source. However, for some streams, + * some sources conflict with one another (when they correspond to the + * same channel on that stream), and on STM32F2, Terrible Super-Bad + * Things will happen if two conflicting request sources are active at + * the same time. + * + * @see struct dma_tube_config + * @see dma_tube_cfg() + */ +typedef enum dma_request_src { + /* These are constructed like so (though this may change, so user + * code shouldn't depend on it): + * + * Bits 0--2: Channel associated with request source + * + * Bits 3--9: rcc_clk_id of DMA controller associated with request source + * + * Bits 10--17: Bit mask of streams which can handle that request + * source. (E.g., bit 10 set means stream 0 can + * handle the source, bit 11 set means stream 1 can, + * etc.) + * + * Among other things, this is used for error checking in + * dma_tube_cfg(). If you change this bit encoding, you need to + * update the helper functions in stm32f2/dma.c. + */ +#define _DMA_STM32F2_REQ_SRC(stream_mask, clk_id, channel) \ + (((stream_mask) << 10) | ((clk_id) << 3) | (channel)) +#define _DMA_S(n) (1U << (n)) + + /* DMA1 request sources */ +#define _DMA_1_REQ_SRC(stream_mask, channel) \ + _DMA_STM32F2_REQ_SRC(stream_mask, RCC_DMA1, channel) + + /* Channel 0 */ + DMA_REQ_SRC_SPI3_RX = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(2), 0), + DMA_REQ_SRC_SPI2_RX = _DMA_1_REQ_SRC(_DMA_S(3), 0), + DMA_REQ_SRC_SPI2_TX = _DMA_1_REQ_SRC(_DMA_S(4), 0), + DMA_REQ_SRC_SPI3_TX = _DMA_1_REQ_SRC(_DMA_S(5) | _DMA_S(7), 0), + + /* Channel 1 */ + DMA_REQ_SRC_I2C1_RX = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(5), 1), + DMA_REQ_SRC_TIM7_UP = _DMA_1_REQ_SRC(_DMA_S(2) | _DMA_S(4), 1), + DMA_REQ_SRC_I2C1_TX = _DMA_1_REQ_SRC(_DMA_S(6) | _DMA_S(7), 1), + + /* Channel 2 */ + DMA_REQ_SRC_TIM4_CH1 = _DMA_1_REQ_SRC(_DMA_S(0), 2), + DMA_REQ_SRC_TIM4_CH2 = _DMA_1_REQ_SRC(_DMA_S(3), 2), + DMA_REQ_SRC_TIM4_UP = _DMA_1_REQ_SRC(_DMA_S(6), 2), + DMA_REQ_SRC_TIM4_CH3 = _DMA_1_REQ_SRC(_DMA_S(7), 2), + + /* Channel 3 */ + DMA_REQ_SRC_TIM2_UP = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(7), 3), + DMA_REQ_SRC_TIM2_CH3 = _DMA_1_REQ_SRC(_DMA_S(1), 3), + DMA_REQ_SRC_I2C3_RX = _DMA_1_REQ_SRC(_DMA_S(2), 3), + DMA_REQ_SRC_I2C3_TX = _DMA_1_REQ_SRC(_DMA_S(4), 3), + DMA_REQ_SRC_TIM2_CH1 = _DMA_1_REQ_SRC(_DMA_S(5), 3), + DMA_REQ_SRC_TIM2_CH2 = _DMA_1_REQ_SRC(_DMA_S(6), 3), + DMA_REQ_SRC_TIM2_CH4 = _DMA_1_REQ_SRC(_DMA_S(6) | _DMA_S(7), 3), + + /* Channel 4 */ + DMA_REQ_SRC_UART5_RX = _DMA_1_REQ_SRC(_DMA_S(0), 4), + DMA_REQ_SRC_USART3_RX = _DMA_1_REQ_SRC(_DMA_S(1), 4), + DMA_REQ_SRC_UART4_RX = _DMA_1_REQ_SRC(_DMA_S(2), 4), + DMA_REQ_SRC_USART3_TX = _DMA_1_REQ_SRC(_DMA_S(3), 4), + DMA_REQ_SRC_UART4_TX = _DMA_1_REQ_SRC(_DMA_S(4), 4), + DMA_REQ_SRC_USART2_RX = _DMA_1_REQ_SRC(_DMA_S(5), 4), + DMA_REQ_SRC_USART2_TX = _DMA_1_REQ_SRC(_DMA_S(6), 4), + DMA_REQ_SRC_UART5_TX = _DMA_1_REQ_SRC(_DMA_S(7), 4), + + /* Channel 5 */ + DMA_REQ_SRC_TIM3_CH4 = _DMA_1_REQ_SRC(_DMA_S(2), 5), + DMA_REQ_SRC_TIM3_UP = _DMA_1_REQ_SRC(_DMA_S(2), 5), + DMA_REQ_SRC_TIM3_CH1 = _DMA_1_REQ_SRC(_DMA_S(4), 5), + DMA_REQ_SRC_TIM3_TRIG = _DMA_1_REQ_SRC(_DMA_S(4), 5), + DMA_REQ_SRC_TIM3_CH2 = _DMA_1_REQ_SRC(_DMA_S(5), 5), + DMA_REQ_SRC_TIM3_CH3 = _DMA_1_REQ_SRC(_DMA_S(7), 5), + + /* Channel 6 */ + DMA_REQ_SRC_TIM5_CH3 = _DMA_1_REQ_SRC(_DMA_S(0), 6), + DMA_REQ_SRC_TIM5_UP = _DMA_1_REQ_SRC(_DMA_S(0) | _DMA_S(6), 6), + DMA_REQ_SRC_TIM5_CH4 = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6), + DMA_REQ_SRC_TIM5_TRIG = _DMA_1_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6), + DMA_REQ_SRC_TIM5_CH1 = _DMA_1_REQ_SRC(_DMA_S(2), 6), + DMA_REQ_SRC_TIM5_CH2 = _DMA_1_REQ_SRC(_DMA_S(4), 6), + + /* Channel 7 */ + DMA_REQ_SRC_TIM6_UP = _DMA_1_REQ_SRC(_DMA_S(1), 7), + DMA_REQ_SRC_I2C2_RX = _DMA_1_REQ_SRC(_DMA_S(2) | _DMA_S(3), 7), + DMA_REQ_SRC_USART3_TX_ALTERNATE = _DMA_1_REQ_SRC(_DMA_S(4), 7), + DMA_REQ_SRC_DAC1 = _DMA_1_REQ_SRC(_DMA_S(5), 7), + DMA_REQ_SRC_DAC2 = _DMA_1_REQ_SRC(_DMA_S(6), 7), + DMA_REQ_SRC_I2C2_TX = _DMA_1_REQ_SRC(_DMA_S(7), 7), +#undef _DMA_1_REQ_SRC + + /* DMA2 request sources */ +#define _DMA_2_REQ_SRC(stream_mask, channel) \ + _DMA_STM32F2_REQ_SRC(stream_mask, RCC_DMA2, channel) + + /* Channel 0 */ + DMA_REQ_SRC_ADC1 = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(4), 0), + /* You can use these "DMA_REQ_SRC_TIMx_CHx_ALTERNATE" if you know + * what you're doing, but the other ones (for channels 6 and 7), + * are better, in that they don't conflict with one another. */ + DMA_REQ_SRC_TIM8_CH1_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0), + DMA_REQ_SRC_TIM8_CH2_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0), + DMA_REQ_SRC_TIM8_CH3_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(2), 0), + DMA_REQ_SRC_TIM1_CH1_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(6), 0), + DMA_REQ_SRC_TIM1_CH2_ALTERNATE = _DMA_2_REQ_SRC(_DMA_S(6), 0), + DMA_REQ_SRC_TIM1_CH3_ALTENRATE = _DMA_2_REQ_SRC(_DMA_S(6), 0), + + /* Channel 1 */ + DMA_REQ_SRC_DCMI = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(7), 1), + DMA_REQ_SRC_ADC2 = _DMA_2_REQ_SRC(_DMA_S(2) | _DMA_S(3), 1), + + /* Channel 2 */ + DMA_REQ_SRC_ADC3 = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(1), 2), + DMA_REQ_SRC_CRYP_OUT = _DMA_2_REQ_SRC(_DMA_S(5), 2), + DMA_REQ_SRC_CRYP_IN = _DMA_2_REQ_SRC(_DMA_S(6), 2), + DMA_REQ_SRC_HASH_IN = _DMA_2_REQ_SRC(_DMA_S(7), 2), + + /* Channel 3 */ + DMA_REQ_SRC_SPI1_RX = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(2), 3), + DMA_REQ_SRC_SPI1_TX = _DMA_2_REQ_SRC(_DMA_S(3) | _DMA_S(5), 3), + + /* Channel 4 */ + DMA_REQ_SRC_USART1_RX = _DMA_2_REQ_SRC(_DMA_S(2) | _DMA_S(5), 4), + DMA_REQ_SRC_SDIO = _DMA_2_REQ_SRC(_DMA_S(3) | _DMA_S(6), 4), + DMA_REQ_SRC_USART1_TX = _DMA_2_REQ_SRC(_DMA_S(7), 4), + + /* Channel 5 */ + DMA_REQ_SRC_USART6_RX = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(2), 5), + DMA_REQ_SRC_USART6_TX = _DMA_2_REQ_SRC(_DMA_S(6) | _DMA_S(7), 5), + + /* Channel 6 */ + DMA_REQ_SRC_TIM1_TRIG = _DMA_2_REQ_SRC(_DMA_S(0) | _DMA_S(4), 6), + DMA_REQ_SRC_TIM1_CH1 = _DMA_2_REQ_SRC(_DMA_S(1) | _DMA_S(3), 6), + DMA_REQ_SRC_TIM1_CH2 = _DMA_2_REQ_SRC(_DMA_S(3), 6), + DMA_REQ_SRC_TIM1_CH4 = _DMA_2_REQ_SRC(_DMA_S(4), 6), + DMA_REQ_SRC_TIM1_COM = _DMA_2_REQ_SRC(_DMA_S(4), 6), + DMA_REQ_SRC_TIM1_UP = _DMA_2_REQ_SRC(_DMA_S(5), 6), + DMA_REQ_SRC_TIM1_CH3 = _DMA_2_REQ_SRC(_DMA_S(6), 6), + + /* Channel 7 */ + DMA_REQ_SRC_TIM8_UP = _DMA_2_REQ_SRC(_DMA_S(1), 7), + DMA_REQ_SRC_TIM8_CH1 = _DMA_2_REQ_SRC(_DMA_S(2), 7), + DMA_REQ_SRC_TIM8_CH2 = _DMA_2_REQ_SRC(_DMA_S(3), 7), + DMA_REQ_SRC_TIM8_CH3 = _DMA_2_REQ_SRC(_DMA_S(4), 7), + DMA_REQ_SRC_TIM8_CH4 = _DMA_2_REQ_SRC(_DMA_S(7), 7), + DMA_REQ_SRC_TIM8_TRIG = _DMA_2_REQ_SRC(_DMA_S(7), 7), + DMA_REQ_SRC_TIM8_COM = _DMA_2_REQ_SRC(_DMA_S(7), 7), +#undef _DMA_2_REQ_SRC +#undef _DMA_S +} dma_request_src; + +/* + * Tube conveniences + */ + +static inline dma_tube_reg_map* dma_tube_regs(dma_dev *dev, + dma_tube tube) { + ASSERT(DMA_S0 <= tube && tube <= DMA_S7); + switch (dev->clk_id) { + case RCC_DMA1: + return DMA1S0_BASE + (int)tube; + case RCC_DMA2: + return DMA2S0_BASE + (int)tube; + default: + /* Can't happen */ + ASSERT(0); + return 0; + } +} + +static inline uint8 dma_is_enabled(dma_dev *dev, dma_tube tube) { + return dma_tube_regs(dev, tube)->SCR & DMA_SCR_EN; +} + +/* F2-only; available because of double-buffering. */ +void dma_set_mem_n_addr(dma_dev *dev, dma_tube tube, int n, + __io void *address); + +/** + * @brief Set memory 0 address. + * Availability: STM32F2. + * + * @param dev DMA device + * @param tube Tube whose memory 0 address to set + * @param addr Address to use as memory 0 + */ +static __always_inline void +dma_set_mem0_addr(dma_dev *dev, dma_tube tube, __io void *addr) { + dma_set_mem_n_addr(dev, tube, 0, addr); +} + +/** + * @brief Set memory 1 address. + * Availability: STM32F2. + * + * @param dev DMA device + * @param tube Tube whose memory 1 address to set + * @param addr Address to use as memory 1 + */ +static __always_inline void +dma_set_mem1_addr(dma_dev *dev, dma_tube tube, __io void *addr) { + dma_set_mem_n_addr(dev, tube, 1, addr); +} + +/* Assume the user means SM0AR in a non-double-buffered configuration. */ +static __always_inline void +dma_set_mem_addr(dma_dev *dev, dma_tube tube, __io void *addr) { + dma_set_mem0_addr(dev, tube, addr); +} + +/* SM0AR and SM1AR are treated as though they have the same size */ +static inline dma_xfer_size dma_get_mem_size(dma_dev *dev, dma_tube tube) { + return (dma_xfer_size)(dma_tube_regs(dev, tube)->SCR >> 13); +} + +static inline dma_xfer_size dma_get_per_size(dma_dev *dev, dma_tube tube) { + return (dma_xfer_size)(dma_tube_regs(dev, tube)->SCR >> 11); +} + +void dma_enable_fifo(dma_dev *dev, dma_tube tube); +void dma_disable_fifo(dma_dev *dev, dma_tube tube); + +static __always_inline int dma_is_fifo_enabled(dma_dev *dev, dma_tube tube) { + return dma_tube_regs(dev, tube)->SFCR & DMA_SFCR_DMDIS; +} + +/* + * TODO: + * - Double-buffer configuration function + * - FIFO configuration function + * - MBURST/PBURST configuration function + */ + +/* + * ISR/IFCR conveniences. + */ + +/* (undocumented) helper for reading LISR/HISR and writing + * LIFCR/HIFCR. For these registers, + * + * S0, S4: bits start at bit 0 + * S1, S5: 6 + * S2, S6: 16 + * S3, S7: 22 + * + * I can't imagine why ST didn't just use a byte for each group. The + * bits fit, and it would have made functions like these simpler and + * faster. Oh well. */ +static __always_inline uint32 _dma_sr_fcr_shift(dma_tube tube) { + switch (tube) { + case DMA_S0: /* fall through */ + case DMA_S4: + return 0; + case DMA_S1: /* fall through */ + case DMA_S5: + return 6; + case DMA_S2: /* fall through */ + case DMA_S6: + return 16; + case DMA_S3: /* fall through */ + case DMA_S7: + return 22; + } + /* Can't happen */ + ASSERT(0); + return 0; +} + +static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_tube tube) { + dma_reg_map *regs = dev->regs; + __io uint32 *isr = tube > DMA_S3 ? ®s->HISR : ®s->LISR; + return (*isr >> _dma_sr_fcr_shift(tube)) & 0x3D; +} + +static inline void dma_clear_isr_bits(dma_dev *dev, dma_tube tube) { + dma_reg_map *regs = dev->regs; + __io uint32 *ifcr = tube > DMA_S3 ? ®s->HIFCR : ®s->LIFCR; + *ifcr = (0x3D << _dma_sr_fcr_shift(tube)); +} + +#undef _DMA_IRQ_BIT_SHIFT + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/exti.h b/libmaple/stm32f2/include/series/exti.h new file mode 100644 index 0000000..4643fcf --- /dev/null +++ b/libmaple/stm32f2/include/series/exti.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/exti.h + * @brief STM32F2 external interrupts + */ + +#ifndef _LIBMAPLE_STM32F2_EXTI_H_ +#define _LIBMAPLE_STM32F2_EXTI_H_ + +#ifdef __cpluspus +extern "C" { +#endif + +struct exti_reg_map; +#define EXTI_BASE ((struct exti_reg_map*)0x40013C00) + +#ifdef __cpluspus +} +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/flash.h b/libmaple/stm32f2/include/series/flash.h new file mode 100644 index 0000000..a3c3933 --- /dev/null +++ b/libmaple/stm32f2/include/series/flash.h @@ -0,0 +1,202 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/flash.h + * @brief STM32F2 Flash header. + * + * Provides register map, base pointer, and register bit definitions + * for the Flash controller on the STM32F2 series, along with + * series-specific configuration values. + */ + +#ifndef _LIBMAPLE_STM32F2_FLASH_H_ +#define _LIBMAPLE_STM32F2_FLASH_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/* + * Register map + */ + +/** @brief STM32F2 Flash register map type */ +typedef struct flash_reg_map { + __io uint32 ACR; /**< Access control register */ + __io uint32 KEYR; /**< Key register */ + __io uint32 OPTKEYR; /**< Option key register */ + __io uint32 SR; /**< Status register */ + __io uint32 CR; /**< Control register */ + __io uint32 OPTCR; /**< Option control register */ +} flash_reg_map; + +#define FLASH_BASE ((struct flash_reg_map*)0x40023C00) + +/* + * Register bit definitions + */ + +/* Access control register */ + +#define FLASH_ACR_DCRST_BIT 12 +#define FLASH_ACR_ICRST_BIT 11 +#define FLASH_ACR_DCEN_BIT 10 +#define FLASH_ACR_ICEN_BIT 9 +#define FLASH_ACR_PRFTEN_BIT 8 + +#define FLASH_ACR_DCRST (1U << FLASH_ACR_DCRST_BIT) +#define FLASH_ACR_ICRST (1U << FLASH_ACR_ICRST_BIT) +#define FLASH_ACR_DCEN (1U << FLASH_ACR_DCEN_BIT) +#define FLASH_ACR_ICEN (1U << FLASH_ACR_ICEN_BIT) +#define FLASH_ACR_PRFTEN (1U << FLASH_ACR_PRFTEN_BIT) +#define FLASH_ACR_LATENCY 0x7 +#define FLASH_ACR_LATENCY_0WS 0x0 +#define FLASH_ACR_LATENCY_1WS 0x1 +#define FLASH_ACR_LATENCY_2WS 0x2 +#define FLASH_ACR_LATENCY_3WS 0x3 +#define FLASH_ACR_LATENCY_4WS 0x4 +#define FLASH_ACR_LATENCY_5WS 0x5 +#define FLASH_ACR_LATENCY_6WS 0x6 +#define FLASH_ACR_LATENCY_7WS 0x7 + +/* Key register */ + +#define FLASH_KEYR_KEY1 0x45670123 +#define FLASH_KEYR_KEY2 0xCDEF89AB + +/* Option key register */ + +#define FLASH_OPTKEYR_OPTKEY1 0x08192A3B +#define FLASH_OPTKEYR_OPTKEY2 0x4C5D6E7F + +/* Status register */ + +#define FLASH_SR_BSY_BIT 16 +#define FLASH_SR_PGSERR_BIT 7 +#define FLASH_SR_PGPERR_BIT 6 +#define FLASH_SR_PGAERR_BIT 5 +#define FLASH_SR_WRPERR_BIT 4 +#define FLASH_SR_OPERR_BIT 1 +#define FLASH_SR_EOP_BIT 0 + +#define FLASH_SR_BSY (1U << FLASH_SR_BSY_BIT) +#define FLASH_SR_PGSERR (1U << FLASH_SR_PGSERR_BIT) +#define FLASH_SR_PGPERR (1U << FLASH_SR_PGPERR_BIT) +#define FLASH_SR_PGAERR (1U << FLASH_SR_PGAERR_BIT) +#define FLASH_SR_WRPERR (1U << FLASH_SR_WRPERR_BIT) +#define FLASH_SR_OPERR (1U << FLASH_SR_OPERR_BIT) +#define FLASH_SR_EOP (1U << FLASH_SR_EOP_BIT) + +/* Control register */ + +#define FLASH_CR_LOCK_BIT 31 +#define FLASH_CR_ERRIE_BIT 25 +#define FLASH_CR_EOPIE_BIT 24 +#define FLASH_CR_STRT_BIT 16 +#define FLASH_CR_MER_BIT 2 +#define FLASH_CR_SER_BIT 1 +#define FLASH_CR_PG_BIT 0 + +#define FLASH_CR_LOCK (1U << FLASH_CR_LOCK_BIT) +#define FLASH_CR_ERRIE (1U << FLASH_CR_ERRIE_BIT) +#define FLASH_CR_EOPIE (1U << FLASH_CR_EOPIE_BIT) +#define FLASH_CR_STRT (1U << FLASH_CR_STRT_BIT) + +#define FLASH_CR_PSIZE (0x3 << 8) +#define FLASH_CR_PSIZE_MUL8 (0x0 << 8) +#define FLASH_CR_PSIZE_MUL16 (0x1 << 8) +#define FLASH_CR_PSIZE_MUL32 (0x2 << 8) +#define FLASH_CR_PSIZE_MUL64 (0x3 << 8) + +#define FLASH_CR_SNB (0xF << 3) +#define FLASH_CR_SNB_0 (0x0 << 3) +#define FLASH_CR_SNB_1 (0x1 << 3) +#define FLASH_CR_SNB_2 (0x2 << 3) +#define FLASH_CR_SNB_3 (0x3 << 3) +#define FLASH_CR_SNB_4 (0x4 << 3) +#define FLASH_CR_SNB_5 (0x5 << 3) +#define FLASH_CR_SNB_6 (0x6 << 3) +#define FLASH_CR_SNB_7 (0x7 << 3) +#define FLASH_CR_SNB_8 (0x8 << 3) +#define FLASH_CR_SNB_9 (0x9 << 3) +#define FLASH_CR_SNB_10 (0xA << 3) +#define FLASH_CR_SNB_11 (0xB << 3) + +#define FLASH_CR_MER (1U << FLASH_CR_MER_BIT) +#define FLASH_CR_SER (1U << FLASH_CR_SER_BIT) +#define FLASH_CR_PG (1U << FLASH_CR_PG_BIT) + +/* Option control register */ + +#define FLASH_OPTCR_NRST_STDBY_BIT 7 +#define FLASH_OPTCR_NRST_STOP_BIT 6 +#define FLASH_OPTCR_WDG_SW_BIT 5 +#define FLASH_OPTCR_OPTSTRT_BIT 1 +#define FLASH_OPTCR_OPTLOCK_BIT 0 + +#define FLASH_OPTCR_NWRP (0x3FF << 16) + +/* Excluded: The many level 1 values */ +#define FLASH_OPTCR_RDP (0xFF << 8) +#define FLASH_OPTCR_RDP_LEVEL0 (0xAA << 8) +#define FLASH_OPTCR_RDP_LEVEL2 (0xCC << 8) + +#define FLASH_OPTCR_USER (0x7 << 5) +#define FLASH_OPTCR_nRST_STDBY (1U << FLASH_OPTCR_nRST_STDBY_BIT) +#define FLASH_OPTCR_nRST_STOP (1U << FLASH_OPTCR_nRST_STOP_BIT) +#define FLASH_OPTCR_WDG_SW (1U << FLASH_OPTCR_WDG_SW_BIT) + +#define FLASH_OPTCR_BOR_LEV (0x3 << 2) +#define FLASH_OPTCR_BOR_LEVEL3 (0x0 << 2) +#define FLASH_OPTCR_BOR_LEVEL2 (0x1 << 2) +#define FLASH_OPTCR_BOR_LEVEL1 (0x2 << 2) +#define FLASH_OPTCR_BOR_OFF (0x3 << 2) + +#define FLASH_OPTCR_OPTSTRT (1U << FLASH_OPTCR_OPTSTRT_BIT) +#define FLASH_OPTCR_OPTLOCK (1U << FLASH_OPTCR_OPTLOCK_BIT) + +/* + * Series-specific configuration values + */ + +/* Note that this value depends on a 2.7V--3.6V supply voltage */ +#define FLASH_SAFE_WAIT_STATES FLASH_WAIT_STATE_3 + +/* Flash memory features available via ACR. */ +enum { + FLASH_PREFETCH = 0x100, + FLASH_ICACHE = 0x200, + FLASH_DCACHE = 0x400, +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/gpio.h b/libmaple/stm32f2/include/series/gpio.h new file mode 100644 index 0000000..1496e8e --- /dev/null +++ b/libmaple/stm32f2/include/series/gpio.h @@ -0,0 +1,264 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +*****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/gpio.h + * @brief STM32F2 GPIO support. + */ + +#ifndef _LIBMAPLE_STM32F2_GPIO_H_ +#define _LIBMAPLE_STM32F2_GPIO_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/* + * GPIO register maps and devices + */ + +/** GPIO register map type */ +typedef struct gpio_reg_map { + __io uint32 MODER; /**< Mode register */ + __io uint32 OTYPER; /**< Output type register */ + __io uint32 OSPEEDR; /**< Output speed register */ + __io uint32 PUPDR; /**< Pull-up/pull-down register */ + __io uint32 IDR; /**< Input data register */ + __io uint32 ODR; /**< Output data register */ + __io uint32 BSRR; /**< Bit set/reset register */ + __io uint32 LCKR; /**< Configuration lock register */ + __io uint32 AFRL; /**< Alternate function low register */ + __io uint32 AFRH; /**< Alternate function high register */ +} gpio_reg_map; + +/** GPIO port A register map base pointer */ +#define GPIOA_BASE ((struct gpio_reg_map*)0x40020000) +/** GPIO port B register map base pointer */ +#define GPIOB_BASE ((struct gpio_reg_map*)0x40020400) +/** GPIO port C register map base pointer */ +#define GPIOC_BASE ((struct gpio_reg_map*)0x40020800) +/** GPIO port D register map base pointer */ +#define GPIOD_BASE ((struct gpio_reg_map*)0x40020C00) +/** GPIO port E register map base pointer */ +#define GPIOE_BASE ((struct gpio_reg_map*)0x40021000) +/** GPIO port F register map base pointer */ +#define GPIOF_BASE ((struct gpio_reg_map*)0x40021400) +/** GPIO port G register map base pointer */ +#define GPIOG_BASE ((struct gpio_reg_map*)0x40021800) +/** GPIO port H register map base pointer */ +#define GPIOH_BASE ((struct gpio_reg_map*)0x40021C00) +/** GPIO port I register map base pointer */ +#define GPIOI_BASE ((struct gpio_reg_map*)0x40022000) + +struct gpio_dev; +extern struct gpio_dev* const GPIOA; +extern struct gpio_dev gpioa; +extern struct gpio_dev* const GPIOB; +extern struct gpio_dev gpiob; +extern struct gpio_dev* const GPIOC; +extern struct gpio_dev gpioc; +extern struct gpio_dev* const GPIOD; +extern struct gpio_dev gpiod; +extern struct gpio_dev* const GPIOE; +extern struct gpio_dev gpioe; +extern struct gpio_dev* const GPIOF; +extern struct gpio_dev gpiof; +extern struct gpio_dev* const GPIOG; +extern struct gpio_dev gpiog; +extern struct gpio_dev* const GPIOH; +extern struct gpio_dev gpioh; +extern struct gpio_dev* const GPIOI; +extern struct gpio_dev gpioi; + +/* + * Register bit definitions + * + * Currently, we only provide masks to be used for shifting for some + * registers, rather than repeating the same values 16 times. + */ + +/* Mode register */ + +#define GPIO_MODER_INPUT 0x0 +#define GPIO_MODER_OUTPUT 0x1 +#define GPIO_MODER_AF 0x2 +#define GPIO_MODER_ANALOG 0x3 + +/* Output type register */ + +#define GPIO_OTYPER_PP 0x0 +#define GPIO_OTYPER_OD 0x1 + +/* Output speed register */ + +#define GPIO_OSPEEDR_LOW 0x0 +#define GPIO_OSPEEDR_MED 0x1 +#define GPIO_OSPEEDR_FAST 0x2 +#define GPIO_OSPEEDR_HIGH 0x3 + +/* Pull-up/pull-down register */ + +#define GPIO_PUPDR_NOPUPD 0x0 +#define GPIO_PUPDR_PU 0x1 +#define GPIO_PUPDR_PD 0x2 + +/* Alternate function register low */ + +#define GPIO_AFRL_AF0 (0xFU << 0) +#define GPIO_AFRL_AF1 (0xFU << 4) +#define GPIO_AFRL_AF2 (0xFU << 8) +#define GPIO_AFRL_AF3 (0xFU << 12) +#define GPIO_AFRL_AF4 (0xFU << 16) +#define GPIO_AFRL_AF5 (0xFU << 20) +#define GPIO_AFRL_AF6 (0xFU << 24) +#define GPIO_AFRL_AF7 (0xFU << 28) + +/* Alternate function register high */ + +#define GPIO_AFRH_AF8 (0xFU << 0) +#define GPIO_AFRH_AF9 (0xFU << 4) +#define GPIO_AFRH_AF10 (0xFU << 8) +#define GPIO_AFRH_AF11 (0xFU << 12) +#define GPIO_AFRH_AF12 (0xFU << 16) +#define GPIO_AFRH_AF13 (0xFU << 20) +#define GPIO_AFRH_AF14 (0xFU << 24) +#define GPIO_AFRH_AF15 (0xFU << 28) + +/* + * GPIO routines + */ + +/** + * @brief GPIO pin modes + */ +typedef enum gpio_pin_mode { + GPIO_MODE_INPUT = GPIO_MODER_INPUT, /**< Input mode */ + GPIO_MODE_OUTPUT = GPIO_MODER_OUTPUT, /**< Output mode */ + GPIO_MODE_AF = GPIO_MODER_AF, /**< Alternate function mode */ + GPIO_MODE_ANALOG = GPIO_MODER_ANALOG, /**< Analog mode */ +} gpio_pin_mode; + +/** + * @brief Additional flags to be used when setting a pin's mode. + * + * Beyond the basic modes (input, general purpose output, alternate + * function, and analog), there are three parameters that can affect a + * pin's mode: + * + * 1. Output type: push/pull or open-drain. This only has an effect + * for output modes. Choices are: GPIO_MODEF_TYPE_PP (the default) + * and GPIO_MODEF_TYPE_OD. + * + * 2. Output speed: specifies the frequency at which a pin changes + * state. This only has an effect for output modes. Choices are: + * GPIO_MODEF_SPEED_LOW (default), GPIO_MODEF_SPEED_MED, + * GPIO_MODEF_SPEED_FAST, and GPIO_MODEF_SPEED_HIGH. + * + * 3. Push/pull setting: All GPIO pins have weak pull-up and pull-down + * resistors that can be enabled when the pin's mode is + * set. Choices are: GPIO_MODEF_PUPD_NONE (default), + * GPIO_MODEF_PUPD_PU, and GPIO_MODEF_PUPD_PD. + */ +typedef enum gpio_mode_flags { + /* Output type in bit 0 */ + GPIO_MODEF_TYPE_PP = GPIO_OTYPER_PP, /**< Output push/pull (default). + Applies only when the mode + specifies output. */ + GPIO_MODEF_TYPE_OD = GPIO_OTYPER_OD, /**< Output open drain. + Applies only when the mode + specifies output. */ + + /* Speed in bits 2:1 */ + GPIO_MODEF_SPEED_LOW = GPIO_OSPEEDR_LOW << 1, /**< Low speed (default): + 2 MHz. */ + GPIO_MODEF_SPEED_MED = GPIO_OSPEEDR_MED << 1, /**< Medium speed: 25 MHz. */ + GPIO_MODEF_SPEED_FAST = GPIO_OSPEEDR_FAST << 1, /**< Fast speed: 50 MHz. */ + GPIO_MODEF_SPEED_HIGH = GPIO_OSPEEDR_HIGH << 1, /**< High speed: + 100 MHz on 30 pF, + 80 MHz on 15 pF. */ + + /* Pull-up/pull-down in bits 4:3 */ + GPIO_MODEF_PUPD_NONE = GPIO_PUPDR_NOPUPD << 3, /**< No pull-up/pull-down + (default). */ + GPIO_MODEF_PUPD_PU = GPIO_PUPDR_PU << 3, /**< Pull-up */ + GPIO_MODEF_PUPD_PD = GPIO_PUPDR_PD << 3, /**< Pull-down */ +} gpio_mode_flags; + +void gpio_set_modef(struct gpio_dev *dev, + uint8 bit, + gpio_pin_mode mode, + unsigned flags); + +/** + * @brief Set the mode of a GPIO pin. + * + * Calling this function is equivalent to calling gpio_set_modef(dev, + * pin, mode, GPIO_MODE_SPEED_HIGH). Note that this overrides the + * default speed. + * + * @param dev GPIO device. + * @param pin Pin on the device whose mode to set, 0--15. + * @param mode Mode to set the pin to. + */ +static inline void gpio_set_mode(struct gpio_dev *dev, + uint8 bit, + gpio_pin_mode mode) { + gpio_set_modef(dev, bit, mode, GPIO_MODEF_SPEED_HIGH); +} + +/** + * @brief GPIO alternate functions. + * Use these to select an alternate function for a pin. + * @see gpio_set_af() + */ +typedef enum gpio_af { + GPIO_AF_SYS = 0, /**< System. */ + GPIO_AF_TIM_1_2 = 1, /**< Timers 1 and 2. */ + GPIO_AF_TIM_3_4_5 = 2, /**< Timers 3, 4, and 5. */ + GPIO_AF_TIM_8_9_10_11 = 3, /**< Timers 8 through 11. */ + GPIO_AF_I2C = 4, /**< I2C 1, 2, and 3. */ + GPIO_AF_SPI_1_2 = 5, /**< SPI1, SPI2/I2S2. */ + GPIO_AF_SPI3 = 6, /**< SPI3/I2S3. */ + GPIO_AF_USART_1_2_3 = 7, /**< USART 1, 2, and 3. */ + GPIO_AF_USART_4_5_6 = 8, /**< UART 4 and 5, USART 6. */ + GPIO_AF_CAN_1_2_TIM_12_13_14 = 9, /**< + * CAN 1 and 2, timers 12, 13, and 14. */ + GPIO_AF_USB_OTG_FS_HS = 10, /**< USB OTG HS and FS. */ + GPIO_AF_ETH = 11, /**< Ethernet MII and RMII. */ + GPIO_AF_FSMC_SDIO_OTG_FS = 12, /**< FSMC, SDIO, and USB OTG FS. */ + GPIO_AF_DCMI = 13, /**< DCMI. */ + GPIO_AF_EVENTOUT = 15, /**< EVENTOUT. */ +} gpio_af; + +void gpio_set_af(struct gpio_dev *dev, uint8 bit, gpio_af af); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/nvic.h b/libmaple/stm32f2/include/series/nvic.h new file mode 100644 index 0000000..dc03806 --- /dev/null +++ b/libmaple/stm32f2/include/series/nvic.h @@ -0,0 +1,160 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/nvic.h + * @brief STM32F2 nested vectored interrupt controller (NVIC) header. + */ + +#ifndef _LIBMAPLE_STM32F2_NVIC_H_ +#define _LIBMAPLE_STM32F2_NVIC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +/** + * @brief STM32F2 interrupt vector table interrupt numbers. + */ +typedef enum nvic_irq_num { + NVIC_NMI = -14, /**< Non-maskable interrupt */ + NVIC_HARDFAULT = -13, /**< Hard fault (all class of fault) */ + NVIC_MEM_MANAGE = -12, /**< Memory management */ + NVIC_BUS_FAULT = -11, /**< Bus fault: prefetch fault, memory + access fault. */ + NVIC_USAGE_FAULT = -10, /**< Usage fault: Undefined instruction + or illegal state. */ + NVIC_SVC = -5, /**< System service call via SWI + instruction */ + NVIC_DEBUG_MON = -4, /**< Debug monitor */ + NVIC_PEND_SVC = -2, /**< Pendable request for system + service */ + NVIC_SYSTICK = -1, /**< System tick timer */ + NVIC_WWDG = 0, /**< Window watchdog interrupt */ + NVIC_PVD = 1, /**< PVD through EXTI line detection */ + NVIC_TAMP_STAMP = 2, /**< Tamper and TimeStamp */ + NVIC_RTC_WKUP = 3, /**< Real-time clock wakeup */ + NVIC_FLASH = 4, /**< Flash */ + NVIC_RCC = 5, /**< Reset and clock control */ + NVIC_EXTI0 = 6, /**< EXTI line 0 */ + NVIC_EXTI1 = 7, /**< EXTI line 1 */ + NVIC_EXTI2 = 8, /**< EXTI line 2 */ + NVIC_EXTI3 = 9, /**< EXTI line 3 */ + NVIC_EXTI4 = 10, /**< EXTI line 4 */ + NVIC_DMA1_STREAM0 = 11, /**< DMA1 stream 0 */ + NVIC_DMA1_STREAM1 = 12, /**< DMA1 stream 1 */ + NVIC_DMA1_STREAM2 = 13, /**< DMA1 stream 2 */ + NVIC_DMA1_STREAM3 = 14, /**< DMA1 stream 3 */ + NVIC_DMA1_STREAM4 = 15, /**< DMA1 stream 4 */ + NVIC_DMA1_STREAM5 = 16, /**< DMA1 stream 5 */ + NVIC_DMA1_STREAM6 = 17, /**< DMA1 stream 6 */ + NVIC_ADC = 18, /**< ADC */ + NVIC_CAN1_TX = 19, /**< CAN1 TX */ + NVIC_CAN1_RX0 = 20, /**< CAN1 RX0 */ + NVIC_CAN1_RX1 = 21, /**< CAN1 RX1 */ + NVIC_CAN1_SCE = 22, /**< CAN1 SCE */ + NVIC_EXTI_9_5 = 23, /**< EXTI lines [9:5] */ + NVIC_TIMER1_BRK_TIMER9 = 24, /**< Timer 1 break and timer 9 */ + NVIC_TIMER1_UP_TIMER10 = 25, /**< Timer 1 update and timer 10 */ + NVIC_TIMER1_TRG_COM_TIMER11 = 26, /**< Timer 1 trigger and commutation and + timer 11.*/ + NVIC_TIMER1_CC = 27, /**< Timer 1 capture and compare */ + NVIC_TIMER2 = 28, /**< Timer 2 */ + NVIC_TIMER3 = 29, /**< Timer 3 */ + NVIC_TIMER4 = 30, /**< Timer 4 */ + NVIC_I2C1_EV = 31, /**< I2C1 event */ + NVIC_I2C1_ER = 32, /**< I2C2 error */ + NVIC_I2C2_EV = 33, /**< I2C2 event */ + NVIC_I2C2_ER = 34, /**< I2C2 error */ + NVIC_SPI1 = 35, /**< SPI1 */ + NVIC_SPI2 = 36, /**< SPI2 */ + NVIC_USART1 = 37, /**< USART1 */ + NVIC_USART2 = 38, /**< USART2 */ + NVIC_USART3 = 39, /**< USART3 */ + NVIC_EXTI_15_10 = 40, /**< EXTI lines [15:10] */ + NVIC_RTCALARM = 41, /**< RTC alarms A and B through EXTI */ + NVIC_OTG_FS_WKUP = 42, /**< USB on-the-go full-speed wakeup + through EXTI*/ + NVIC_TIMER8_BRK_TIMER12 = 43, /**< Timer 8 break and timer 12 */ + NVIC_TIMER8_UP_TIMER13 = 44, /**< Timer 8 update and timer 13 */ + NVIC_TIMER8_TRG_COM_TIMER14 = 45, /**< Timer 8 trigger and commutation and + timer 14 */ + NVIC_TIMER8_CC = 46, /**< Timer 8 capture and compare */ + NVIC_DMA1_STREAM7 = 47, /**< DMA1 stream 7 */ + NVIC_FSMC = 48, /**< FSMC */ + NVIC_SDIO = 49, /**< SDIO */ + NVIC_TIMER5 = 50, /**< Timer 5 */ + NVIC_SPI3 = 51, /**< SPI3 */ + NVIC_UART4 = 52, /**< UART4 */ + NVIC_UART5 = 53, /**< UART5 */ + NVIC_TIMER6_DAC = 54, /**< Timer 6 and DAC underrun */ + NVIC_TIMER7 = 55, /**< Timer 7 */ + NVIC_DMA2_STREAM0 = 56, /**< DMA2 stream 0 */ + NVIC_DMA2_STREAM1 = 57, /**< DMA2 stream 1 */ + NVIC_DMA2_STREAM2 = 58, /**< DMA2 stream 2 */ + NVIC_DMA2_STREAM3 = 59, /**< DMA2 stream 3 */ + NVIC_DMA2_STREAM4 = 60, /**< DMA2 stream 4 */ + NVIC_ETH = 61, /**< Ethernet */ + NVIC_ETH_WKUP = 62, /**< Ethernet wakeup through EXTI */ + NVIC_CAN2_TX = 63, /**< CAN2 TX */ + NVIC_CAN2_RX0 = 64, /**< CAN2 RX0 */ + NVIC_CAN2_RX1 = 65, /**< CAN2 RX1 */ + NVIC_CAN2_SCE = 66, /**< CAN2 SCE */ + NVIC_OTG_FS = 67, /**< USB on-the-go full-speed */ + NVIC_DMA2_STREAM5 = 68, /**< DMA2 stream 5 */ + NVIC_DMA2_STREAM6 = 69, /**< DMA2 stream 6 */ + NVIC_DMA2_STREAM7 = 70, /**< DMA2 stream 7 */ + NVIC_USART6 = 71, /**< USART6 */ + NVIC_I2C3_EV = 72, /**< I2C3 event */ + NVIC_I2C3_ER = 73, /**< I2C3 error */ + NVIC_OTG_HS_EP1_OUT = 74, /**< USB on-the-go high-speed + endpoint 1 OUT */ + NVIC_OTG_HS_EP1_IN = 75, /**< USB on-the-go high-speed + endpoint 1 IN */ + NVIC_OTG_HS_WKUP = 76, /**< USB on-the-go high-speed wakeup + through EXTI*/ + NVIC_OTG_HS = 77, /**< USB on-the-go high-speed */ + NVIC_DCMI = 78, /**< DCMI */ + NVIC_CRYP = 79, /**< Cryptographic processor */ + NVIC_HASH_RNG = 80, /**< Hash and random number + generation */ + + /* Fake enumerator values, for compatiblity with F1. + * TODO decide if this is actually a good idea. */ + NVIC_TIMER6 = NVIC_TIMER6_DAC, /**< For compatibility with STM32F1. */ +} nvic_irq_num; + +static inline void nvic_irq_disable_all(void) { + NVIC_BASE->ICER[0] = 0xFFFFFFFF; + NVIC_BASE->ICER[1] = 0xFFFFFFFF; + NVIC_BASE->ICER[2] = 0xFFFFFFFF; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/pwr.h b/libmaple/stm32f2/include/series/pwr.h new file mode 100644 index 0000000..96353a4 --- /dev/null +++ b/libmaple/stm32f2/include/series/pwr.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/pwr.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 Power control (PWR) support. + */ + +#ifndef _LIBMAPLE_STM32F2_PWR_H_ +#define _LIBMAPLE_STM32F2_PWR_H_ + +/* + * Additional register bits + */ + +/* Control register */ + +/** + * @brief Flash power down in stop mode bit. + * Availability: STM32F2 */ +#define PWR_CR_FPDS_BIT 9 +/** + * @brief Flash power down in stop mode. + * Availability: STM32F2 */ +#define PWR_CR_FPDS (1U << PWR_CR_FPDS_BIT) + +/* PVD level selection */ +#define PWR_CR_PLS_2_0V (0x0 << 5) +#define PWR_CR_PLS_2_1V (0x1 << 5) +#define PWR_CR_PLS_2_3V (0x2 << 5) +#define PWR_CR_PLS_2_5V (0x3 << 5) +#define PWR_CR_PLS_2_6V (0x4 << 5) +#define PWR_CR_PLS_2_7V (0x5 << 5) +#define PWR_CR_PLS_2_8V (0x6 << 5) +#define PWR_CR_PLS_2_9V (0x7 << 5) + +/* Control/Status register */ + +/** Backup regulator enable bit. */ +#define PWR_CSR_BRE_BIT 9 +/** Backup regulator ready bit. */ +#define PWR_CSR_BRR_BIT 3 + +/** Backup regulator enable. */ +#define PWR_CSR_BRE (1U << PWR_CSR_BRE_BIT) +/** Backup regulator ready. */ +#define PWR_CSR_BRR (1U << PWR_CSR_BRR_BIT) + +#endif diff --git a/libmaple/stm32f2/include/series/rcc.h b/libmaple/stm32f2/include/series/rcc.h new file mode 100644 index 0000000..441a5a8 --- /dev/null +++ b/libmaple/stm32f2/include/series/rcc.h @@ -0,0 +1,951 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/rcc.h + * @brief STM32F2 reset and clock control (RCC) support. + */ + +#ifndef _LIBMAPLE_STM32F2_RCC_H_ +#define _LIBMAPLE_STM32F2_RCC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/libmaple_types.h> + +/* + * Register map + */ + +/** STM32F2 RCC register map type */ +typedef struct rcc_reg_map { + __io uint32 CR; /**< Clock control register */ + __io uint32 PLLCFGR; /**< PLL configuration register */ + __io uint32 CFGR; /**< Clock configuration register */ + __io uint32 CIR; /**< Clock interrupt register */ + __io uint32 AHB1RSTR; /**< AHB1 peripheral reset register */ + __io uint32 AHB2RSTR; /**< AHB2 peripheral reset register */ + __io uint32 AHB3RSTR; /**< AHB3 peripheral reset register */ + const uint32 RESERVED1; /**< Reserved */ + __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ + __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ + const uint32 RESERVED2; /**< Reserved */ + const uint32 RESERVED3; /**< Reserved */ + __io uint32 AHB1ENR; /**< AHB1 peripheral clock enable register */ + __io uint32 AHB2ENR; /**< AHB2 peripheral clock enable register */ + __io uint32 AHB3ENR; /**< AHB3 peripheral clock enable register */ + const uint32 RESERVED4; /**< Reserved */ + __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ + __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ + const uint32 RESERVED5; /**< Reserved */ + const uint32 RESERVED6; /**< Reserved */ + __io uint32 AHB1LPENR; /**< AHB1 peripheral clock enable in + low power mode register */ + __io uint32 AHB2LPENR; /**< AHB2 peripheral clock enable in + low power mode register */ + __io uint32 AHB3LPENR; /**< AHB3 peripheral clock enable in + low power mode register */ + const uint32 RESERVED7; /**< Reserved */ + __io uint32 APB1LPENR; /**< APB1 peripheral clock enable in + low power mode register */ + __io uint32 APB2LPENR; /**< APB2 peripheral clock enable in + low power mode register */ + const uint32 RESERVED8; /**< Reserved */ + const uint32 RESERVED9; /**< Reserved */ + __io uint32 BDCR; /**< Backup domain control register */ + __io uint32 CSR; /**< Clock control and status register */ + const uint32 RESERVED10; /**< Reserved */ + const uint32 RESERVED11; /**< Reserved */ + __io uint32 SSCGR; /**< Spread spectrum clock generation + register */ + __io uint32 PLLI2SCFGR; /**< PLLI2S configuration register */ +} rcc_reg_map; + +#define RCC_BASE ((struct rcc_reg_map*)0x40023800) + +/* + * Register bit definitions + */ + +/* Clock control register */ + +#define RCC_CR_PLLI2SRDY_BIT 27 +#define RCC_CR_PLLI2SON_BIT 26 +#define RCC_CR_PLLRDY_BIT 25 +#define RCC_CR_PLLON_BIT 24 +#define RCC_CR_CSSON_BIT 19 +#define RCC_CR_HSEBYP_BIT 18 +#define RCC_CR_HSERDY_BIT 17 +#define RCC_CR_HSEON_BIT 16 +#define RCC_CR_HSIRDY_BIT 1 +#define RCC_CR_HSION_BIT 0 + +#define RCC_CR_PLLI2SRDY (1U << RCC_CR_PLLI2SRDY_BIT) +#define RCC_CR_PLLI2SON (1U << RCC_CR_PLLI2SON_BIT) +#define RCC_CR_PLLRDY (1U << RCC_CR_PLLRDY_BIT) +#define RCC_CR_PLLON (1U << RCC_CR_PLLON_BIT) +#define RCC_CR_CSSON (1U << RCC_CR_CSSON_BIT) +#define RCC_CR_HSEBYP (1U << RCC_CR_HSEBYP_BIT) +#define RCC_CR_HSERDY (1U << RCC_CR_HSERDY_BIT) +#define RCC_CR_HSEON (1U << RCC_CR_HSEON_BIT) +#define RCC_CR_HSICAL (0xFF << 8) +#define RCC_CR_HSITRIM (0x1F << 3) +#define RCC_CR_HSIRDY (1U << RCC_CR_HSIRDY_BIT) +#define RCC_CR_HSION (1U << RCC_CR_HSION_BIT) + +/* PLL configuration register */ + +#define RCC_PLLCFGR_PLLSRC_BIT 22 + +#define RCC_PLLCFGR_PLLQ (0xF << 24) +#define RCC_PLLCFGR_PLLSRC (1U << RCC_PLLCFGR_PLLSRC_BIT) +#define RCC_PLLCFGR_PLLSRC_HSI (0x0 << RCC_PLLCFGR_PLLSRC_BIT) +#define RCC_PLLCFGR_PLLSRC_HSE (0x1 << RCC_PLLCFGR_PLLSRC_BIT) +#define RCC_PLLCFGR_PLLP (0x3 << 16) +#define RCC_PLLCFGR_PLLN (0x1FF << 6) +#define RCC_PLLCFGR_PLLM 0x1F + +/* Clock configuration register */ + +#define RCC_CFGR_I2SSRC_BIT 23 + +#define RCC_CFGR_MCO2 (0x3 << 30) +#define RCC_CFGR_MCO2_SYSCLK (0x0 << 30) +#define RCC_CFGR_MCO2_PLLI2S (0x1 << 30) +#define RCC_CFGR_MCO2_HSE (0x2 << 30) +#define RCC_CFGR_MCO2_PLL (0x3 << 30) + +#define RCC_CFGR_MCO2PRE (0x7 << 27) +#define RCC_CFGR_MCO2PRE_DIV_1 (0x0 << 27) +#define RCC_CFGR_MCO2PRE_DIV_2 (0x4 << 27) +#define RCC_CFGR_MCO2PRE_DIV_3 (0x5 << 27) +#define RCC_CFGR_MCO2PRE_DIV_4 (0x6 << 27) +#define RCC_CFGR_MCO2PRE_DIV_5 (0x7 << 27) + +#define RCC_CFGR_MCO1PRE (0x7 << 24) +#define RCC_CFGR_MCO1PRE_DIV_1 (0x0 << 24) +#define RCC_CFGR_MCO1PRE_DIV_2 (0x4 << 24) +#define RCC_CFGR_MCO1PRE_DIV_3 (0x5 << 24) +#define RCC_CFGR_MCO1PRE_DIV_4 (0x6 << 24) +#define RCC_CFGR_MCO1PRE_DIV_5 (0x7 << 24) + +#define RCC_CFGR_I2SSRC (1U << RCC_CFGR_I2SSRC_BIT) +#define RCC_CFGR_I2SSRC_PLLI2S (0 << RCC_CFGR_I2SSRC_BIT) +#define RCC_CFGR_I2SSRC_I2S_CKIN (1 << RCC_CFGR_I2SSRC_BIT) + +#define RCC_CFGR_MCO1 (0x3 << 21) +#define RCC_CFGR_MCO1_HSI (0x0 << 21) +#define RCC_CFGR_MCO1_LSE (0x1 << 21) +#define RCC_CFGR_MCO1_HSE (0x2 << 21) +#define RCC_CFGR_MCO1_PLL (0x3 << 21) + +#define RCC_CFGR_RTCPRE (0x1F << 16) + +/* Skipped: all the 0b0xx values meaning "not divided" */ +#define RCC_CFGR_PPRE2 (0x7 << 13) +#define RCC_CFGR_PPRE2_AHB_DIV_2 (0x4 << 13) +#define RCC_CFGR_PPRE2_AHB_DIV_4 (0x5 << 13) +#define RCC_CFGR_PPRE2_AHB_DIV_8 (0x6 << 13) +#define RCC_CFGR_PPRE2_AHB_DIV_16 (0x7 << 13) + +/* Skipped: all the 0b0xx values meaning "not divided" */ +#define RCC_CFGR_PPRE1 (0x7 << 10) +#define RCC_CFGR_PPRE1_AHB_DIV_2 (0x4 << 10) +#define RCC_CFGR_PPRE1_AHB_DIV_4 (0x5 << 10) +#define RCC_CFGR_PPRE1_AHB_DIV_8 (0x6 << 10) +#define RCC_CFGR_PPRE1_AHB_DIV_16 (0x7 << 10) + +/* Skipped: all the 0b0xxx values meaning "not divided" */ +#define RCC_CFGR_HPRE (0xF << 4) +#define RCC_CFGR_HPRE_SYSCLK_DIV_2 (0x8 << 4) +#define RCC_CFGR_HPRE_SYSCLK_DIV_4 (0x9 << 4) +#define RCC_CFGR_HPRE_SYSCLK_DIV_8 (0xA << 4) +#define RCC_CFGR_HPRE_SYSCLK_DIV_16 (0xB << 4) +#define RCC_CFGR_HPRE_SYSCLK_DIV_64 (0xC << 4) +#define RCC_CFGR_HPRE_SYSCLK_DIV_128 (0xD << 4) +#define RCC_CFGR_HPRE_SYSCLK_DIV_256 (0xE << 4) +#define RCC_CFGR_HPRE_SYSCLK_DIV_512 (0xF << 4) + +#define RCC_CFGR_SWS (0x3 << 2) +#define RCC_CFGR_SWS_HSI (0x0 << 2) +#define RCC_CFGR_SWS_HSE (0x1 << 2) +#define RCC_CFGR_SWS_PLL (0x2 << 2) + +#define RCC_CFGR_SW 0x3 +#define RCC_CFGR_SW_HSI 0x0 +#define RCC_CFGR_SW_HSE 0x1 +#define RCC_CFGR_SW_PLL 0x2 + +/* Clock interrupt register */ + +#define RCC_CIR_CSSC_BIT 23 + +#define RCC_CIR_PLLI2SRDYC_BIT 21 +#define RCC_CIR_PLLRDYC_BIT 20 +#define RCC_CIR_HSERDYC_BIT 19 +#define RCC_CIR_HSIRDYC_BIT 18 +#define RCC_CIR_LSERDYC_BIT 17 +#define RCC_CIR_LSIRDYC_BIT 16 + +#define RCC_CIR_PLLI2SRDYIE_BIT 13 +#define RCC_CIR_PLLRDYIE_BIT 12 +#define RCC_CIR_HSERDYIE_BIT 11 +#define RCC_CIR_HSIRDYIE_BIT 10 +#define RCC_CIR_LSERDYIE_BIT 9 +#define RCC_CIR_LSIRDYIE_BIT 8 + +#define RCC_CIR_CSSF_BIT 7 + +#define RCC_CIR_PLLI2SRDYF_BIT 5 +#define RCC_CIR_PLLRDYF_BIT 4 +#define RCC_CIR_HSERDYF_BIT 3 +#define RCC_CIR_HSIRDYF_BIT 2 +#define RCC_CIR_LSERDYF_BIT 1 +#define RCC_CIR_LSIRDYF_BIT 0 + +#define RCC_CIR_CSSC (1U << RCC_CIR_CSSC_BIT) + +#define RCC_CIR_PLLI2SRDYC (1U << RCC_CIR_PLLI2SRDYC_BIT) +#define RCC_CIR_PLLRDYC (1U << RCC_CIR_PLLRDYC_BIT) +#define RCC_CIR_HSERDYC (1U << RCC_CIR_HSERDYC_BIT) +#define RCC_CIR_HSIRDYC (1U << RCC_CIR_HSIRDYC_BIT) +#define RCC_CIR_LSERDYC (1U << RCC_CIR_LSERDYC_BIT) +#define RCC_CIR_LSIRDYC (1U << RCC_CIR_LSIRDYC_BIT) + +#define RCC_CIR_PLLI2SRDYIE (1U << RCC_CIR_PLLI2SRDYIE_BIT) +#define RCC_CIR_PLLRDYIE (1U << RCC_CIR_PLLRDYIE_BIT) +#define RCC_CIR_HSERDYIE (1U << RCC_CIR_HSERDYIE_BIT) +#define RCC_CIR_HSIRDYIE (1U << RCC_CIR_HSIRDYIE_BIT) +#define RCC_CIR_LSERDYIE (1U << RCC_CIR_LSERDYIE_BIT) +#define RCC_CIR_LSIRDYIE (1U << RCC_CIR_LSIRDYIE_BIT) + +#define RCC_CIR_CSSF (1U << RCC_CIR_CSSF_BIT) + +#define RCC_CIR_PLLI2SRDYF (1U << RCC_CIR_PLLI2SRDYF_BIT) +#define RCC_CIR_PLLRDYF (1U << RCC_CIR_PLLRDYF_BIT) +#define RCC_CIR_HSERDYF (1U << RCC_CIR_HSERDYF_BIT) +#define RCC_CIR_HSIRDYF (1U << RCC_CIR_HSIRDYF_BIT) +#define RCC_CIR_LSERDYF (1U << RCC_CIR_LSERDYF_BIT) +#define RCC_CIR_LSIRDYF (1U << RCC_CIR_LSIRDYF_BIT) + +/* AHB1 peripheral reset register */ + +#define RCC_AHB1RSTR_OTGHSRST_BIT 29 +#define RCC_AHB1RSTR_ETHMACRST_BIT 25 +#define RCC_AHB1RSTR_DMA2RST_BIT 22 +#define RCC_AHB1RSTR_DMA1RST_BIT 21 +#define RCC_AHB1RSTR_CRCRST_BIT 12 +#define RCC_AHB1RSTR_GPIOIRST_BIT 8 +#define RCC_AHB1RSTR_GPIOHRST_BIT 7 +#define RCC_AHB1RSTR_GPIOGRST_BIT 6 +#define RCC_AHB1RSTR_GPIOFRST_BIT 5 +#define RCC_AHB1RSTR_GPIOERST_BIT 4 +#define RCC_AHB1RSTR_GPIODRST_BIT 3 +#define RCC_AHB1RSTR_GPIOCRST_BIT 2 +#define RCC_AHB1RSTR_GPIOBRST_BIT 1 +#define RCC_AHB1RSTR_GPIOARST_BIT 0 + +#define RCC_AHB1RSTR_OTGHSRST (1U << RCC_AHB1RSTR_OTGHSRST_BIT) +#define RCC_AHB1RSTR_ETHMACRST (1U << RCC_AHB1RSTR_ETHMACRST_BIT) +#define RCC_AHB1RSTR_DMA2RST (1U << RCC_AHB1RSTR_DMA2RST_BIT) +#define RCC_AHB1RSTR_DMA1RST (1U << RCC_AHB1RSTR_DMA1RST_BIT) +#define RCC_AHB1RSTR_CRCRST (1U << RCC_AHB1RSTR_CRCRST_BIT) +#define RCC_AHB1RSTR_GPIOIRST (1U << RCC_AHB1RSTR_GPIOIRST_BIT) +#define RCC_AHB1RSTR_GPIOHRST (1U << RCC_AHB1RSTR_GPIOHRST_BIT) +#define RCC_AHB1RSTR_GPIOGRST (1U << RCC_AHB1RSTR_GPIOGRST_BIT) +#define RCC_AHB1RSTR_GPIOFRST (1U << RCC_AHB1RSTR_GPIOFRST_BIT) +#define RCC_AHB1RSTR_GPIOERST (1U << RCC_AHB1RSTR_GPIOERST_BIT) +#define RCC_AHB1RSTR_GPIODRST (1U << RCC_AHB1RSTR_GPIODRST_BIT) +#define RCC_AHB1RSTR_GPIOCRST (1U << RCC_AHB1RSTR_GPIOCRST_BIT) +#define RCC_AHB1RSTR_GPIOBRST (1U << RCC_AHB1RSTR_GPIOBRST_BIT) +#define RCC_AHB1RSTR_GPIOARST (1U << RCC_AHB1RSTR_GPIOARST_BIT) + +/* AHB2 peripheral reset register */ + +#define RCC_AHB2RSTR_OTGFSRST_BIT 7 +#define RCC_AHB2RSTR_RNGRST_BIT 6 +#define RCC_AHB2RSTR_HASHRST_BIT 5 +#define RCC_AHB2RSTR_CRYPRST_BIT 4 +#define RCC_AHB2RSTR_DCMIRST_BIT 0 + +#define RCC_AHB2RSTR_OTGFSRST (1U << RCC_AHB2RSTR_OTGFSRST_BIT) +#define RCC_AHB2RSTR_RNGRST (1U << RCC_AHB2RSTR_RNGRST_BIT) +#define RCC_AHB2RSTR_HASHRST (1U << RCC_AHB2RSTR_HASHRST_BIT) +#define RCC_AHB2RSTR_CRYPRST (1U << RCC_AHB2RSTR_CRYPRST_BIT) +#define RCC_AHB2RSTR_DCMIRST (1U << RCC_AHB2RSTR_DCMIRST_BIT) + +/* AHB3 peripheral reset register */ + +#define RCC_AHB3RSTR_FSMCRST_BIT 0 + +#define RCC_AHB3RSTR_FSMCRST (1U << RCC_AHB3RSTR_FSMCRST_BIT) + +/* APB1 peripheral reset register */ + +#define RCC_APB1RSTR_DACRST_BIT 29 +#define RCC_APB1RSTR_PWRRST_BIT 28 +#define RCC_APB1RSTR_CAN2RST_BIT 26 +#define RCC_APB1RSTR_CAN1RST_BIT 25 +#define RCC_APB1RSTR_I2C3RST_BIT 23 +#define RCC_APB1RSTR_I2C2RST_BIT 22 +#define RCC_APB1RSTR_I2C1RST_BIT 21 +#define RCC_APB1RSTR_UART5RST_BIT 20 +#define RCC_APB1RSTR_UART4RST_BIT 19 +#define RCC_APB1RSTR_UART3RST_BIT 18 +#define RCC_APB1RSTR_UART2RST_BIT 17 +#define RCC_APB1RSTR_SPI3RST_BIT 15 +#define RCC_APB1RSTR_SPI2RST_BIT 14 +#define RCC_APB1RSTR_WWDGRST_BIT 11 +#define RCC_APB1RSTR_TIM14RST_BIT 8 +#define RCC_APB1RSTR_TIM13RST_BIT 7 +#define RCC_APB1RSTR_TIM12RST_BIT 6 +#define RCC_APB1RSTR_TIM7RST_BIT 5 +#define RCC_APB1RSTR_TIM6RST_BIT 4 +#define RCC_APB1RSTR_TIM5RST_BIT 3 +#define RCC_APB1RSTR_TIM4RST_BIT 2 +#define RCC_APB1RSTR_TIM3RST_BIT 1 +#define RCC_APB1RSTR_TIM2RST_BIT 0 + +#define RCC_APB1RSTR_DACRST (1U << RCC_APB1RSTR_DACRST_BIT) +#define RCC_APB1RSTR_PWRRST (1U << RCC_APB1RSTR_PWRRST_BIT) +#define RCC_APB1RSTR_CAN2RST (1U << RCC_APB1RSTR_CAN2RST_BIT) +#define RCC_APB1RSTR_CAN1RST (1U << RCC_APB1RSTR_CAN1RST_BIT) +#define RCC_APB1RSTR_I2C3RST (1U << RCC_APB1RSTR_I2C3RST_BIT) +#define RCC_APB1RSTR_I2C2RST (1U << RCC_APB1RSTR_I2C2RST_BIT) +#define RCC_APB1RSTR_I2C1RST (1U << RCC_APB1RSTR_I2C1RST_BIT) +#define RCC_APB1RSTR_UART5RST (1U << RCC_APB1RSTR_UART5RST_BIT) +#define RCC_APB1RSTR_UART4RST (1U << RCC_APB1RSTR_UART4RST_BIT) +#define RCC_APB1RSTR_UART3RST (1U << RCC_APB1RSTR_UART3RST_BIT) +#define RCC_APB1RSTR_UART2RST (1U << RCC_APB1RSTR_UART2RST_BIT) +#define RCC_APB1RSTR_SPI3RST (1U << RCC_APB1RSTR_SPI3RST_BIT) +#define RCC_APB1RSTR_SPI2RST (1U << RCC_APB1RSTR_SPI2RST_BIT) +#define RCC_APB1RSTR_WWDGRST (1U << RCC_APB1RSTR_WWDGRST_BIT) +#define RCC_APB1RSTR_TIM14RST (1U << RCC_APB1RSTR_TIM14RST_BIT) +#define RCC_APB1RSTR_TIM13RST (1U << RCC_APB1RSTR_TIM13RST_BIT) +#define RCC_APB1RSTR_TIM12RST (1U << RCC_APB1RSTR_TIM12RST_BIT) +#define RCC_APB1RSTR_TIM7RST (1U << RCC_APB1RSTR_TIM7RST_BIT) +#define RCC_APB1RSTR_TIM6RST (1U << RCC_APB1RSTR_TIM6RST_BIT) +#define RCC_APB1RSTR_TIM5RST (1U << RCC_APB1RSTR_TIM5RST_BIT) +#define RCC_APB1RSTR_TIM4RST (1U << RCC_APB1RSTR_TIM4RST_BIT) +#define RCC_APB1RSTR_TIM3RST (1U << RCC_APB1RSTR_TIM3RST_BIT) +#define RCC_APB1RSTR_TIM2RST (1U << RCC_APB1RSTR_TIM2RST_BIT) + +/* APB2 peripheral reset register */ + +#define RCC_APB2RSTR_TIM11RST_BIT 18 +#define RCC_APB2RSTR_TIM10RST_BIT 17 +#define RCC_APB2RSTR_TIM9RST_BIT 16 +#define RCC_APB2RSTR_SYSCFGRST_BIT 14 +#define RCC_APB2RSTR_SPI1RST_BIT 12 +#define RCC_APB2RSTR_SDIORST_BIT 11 +#define RCC_APB2RSTR_ADCRST_BIT 8 +#define RCC_APB2RSTR_USART6RST_BIT 5 +#define RCC_APB2RSTR_USART1RST_BIT 4 +#define RCC_APB2RSTR_TIM8RST_BIT 1 +#define RCC_APB2RSTR_TIM1RST_BIT 0 + +#define RCC_APB2RSTR_TIM11RST (1U << RCC_APB2RSTR_TIM11RST_BIT) +#define RCC_APB2RSTR_TIM10RST (1U << RCC_APB2RSTR_TIM10RST_BIT) +#define RCC_APB2RSTR_TIM9RST (1U << RCC_APB2RSTR_TIM9RST_BIT) +#define RCC_APB2RSTR_SYSCFGRST (1U << RCC_APB2RSTR_SYSCFGRST_BIT) +#define RCC_APB2RSTR_SPI1RST (1U << RCC_APB2RSTR_SPI1RST_BIT) +#define RCC_APB2RSTR_SDIORST (1U << RCC_APB2RSTR_SDIORST_BIT) +#define RCC_APB2RSTR_ADCRST (1U << RCC_APB2RSTR_ADCRST_BIT) +#define RCC_APB2RSTR_USART6RST (1U << RCC_APB2RSTR_USART6RST_BIT) +#define RCC_APB2RSTR_USART1RST (1U << RCC_APB2RSTR_USART1RST_BIT) +#define RCC_APB2RSTR_TIM8RST (1U << RCC_APB2RSTR_TIM8RST_BIT) +#define RCC_APB2RSTR_TIM1RST (1U << RCC_APB2RSTR_TIM1RST_BIT) + +/* AHB1 peripheral clock enable register */ + +#define RCC_AHB1ENR_OTGHSULPIEN_BIT 30 +#define RCC_AHB1ENR_OTGHSEN_BIT 29 +#define RCC_AHB1ENR_ETHMACPTPEN_BIT 28 +#define RCC_AHB1ENR_ETHMACRXEN_BIT 27 +#define RCC_AHB1ENR_ETHMACTXEN_BIT 26 +#define RCC_AHB1ENR_ETHMACEN_BIT 25 +#define RCC_AHB1ENR_DMA2EN_BIT 22 +#define RCC_AHB1ENR_DMA1EN_BIT 21 +#define RCC_AHB1ENR_BKPSRAMEN_BIT 18 +#define RCC_AHB1ENR_CRCEN_BIT 12 +#define RCC_AHB1ENR_GPIOIEN_BIT 8 +#define RCC_AHB1ENR_GPIOHEN_BIT 7 +#define RCC_AHB1ENR_GPIOGEN_BIT 6 +#define RCC_AHB1ENR_GPIOFEN_BIT 5 +#define RCC_AHB1ENR_GPIOEEN_BIT 4 +#define RCC_AHB1ENR_GPIODEN_BIT 3 +#define RCC_AHB1ENR_GPIOCEN_BIT 2 +#define RCC_AHB1ENR_GPIOBEN_BIT 1 +#define RCC_AHB1ENR_GPIOAEN_BIT 0 + +#define RCC_AHB1ENR_OTGHSULPIEN (1U << RCC_AHB1ENR_OTGHSULPIEN_BIT) +#define RCC_AHB1ENR_OTGHSEN (1U << RCC_AHB1ENR_OTGHSEN_BIT) +#define RCC_AHB1ENR_ETHMACPTPEN (1U << RCC_AHB1ENR_ETHMACPTPEN_BIT) +#define RCC_AHB1ENR_ETHMACRXEN (1U << RCC_AHB1ENR_ETHMACRXEN_BIT) +#define RCC_AHB1ENR_ETHMACTXEN (1U << RCC_AHB1ENR_ETHMACTXEN_BIT) +#define RCC_AHB1ENR_ETHMACEN (1U << RCC_AHB1ENR_ETHMACEN_BIT) +#define RCC_AHB1ENR_DMA2EN (1U << RCC_AHB1ENR_DMA2EN_BIT) +#define RCC_AHB1ENR_DMA1EN (1U << RCC_AHB1ENR_DMA1EN_BIT) +#define RCC_AHB1ENR_BKPSRAMEN (1U << RCC_AHB1ENR_BKPSRAMEN_BIT) +#define RCC_AHB1ENR_CRCEN (1U << RCC_AHB1ENR_CRCEN_BIT) +#define RCC_AHB1ENR_GPIOIEN (1U << RCC_AHB1ENR_GPIOIEN_BIT) +#define RCC_AHB1ENR_GPIOHEN (1U << RCC_AHB1ENR_GPIOHEN_BIT) +#define RCC_AHB1ENR_GPIOGEN (1U << RCC_AHB1ENR_GPIOGEN_BIT) +#define RCC_AHB1ENR_GPIOFEN (1U << RCC_AHB1ENR_GPIOFEN_BIT) +#define RCC_AHB1ENR_GPIOEEN (1U << RCC_AHB1ENR_GPIOEEN_BIT) +#define RCC_AHB1ENR_GPIODEN (1U << RCC_AHB1ENR_GPIODEN_BIT) +#define RCC_AHB1ENR_GPIOCEN (1U << RCC_AHB1ENR_GPIOCEN_BIT) +#define RCC_AHB1ENR_GPIOBEN (1U << RCC_AHB1ENR_GPIOBEN_BIT) +#define RCC_AHB1ENR_GPIOAEN (1U << RCC_AHB1ENR_GPIOAEN_BIT) + +/* AHB2 peripheral clock enable register */ + +#define RCC_AHB2ENR_OTGFSEN_BIT 7 +#define RCC_AHB2ENR_RNGEN_BIT 6 +#define RCC_AHB2ENR_HASHEN_BIT 5 +#define RCC_AHB2ENR_CRYPEN_BIT 4 +#define RCC_AHB2ENR_DCMIEN_BIT 0 + +#define RCC_AHB2ENR_OTGFSEN (1U << RCC_AHB2ENR_OTGFSEN_BIT) +#define RCC_AHB2ENR_RNGEN (1U << RCC_AHB2ENR_RNGEN_BIT) +#define RCC_AHB2ENR_HASHEN (1U << RCC_AHB2ENR_HASHEN_BIT) +#define RCC_AHB2ENR_CRYPEN (1U << RCC_AHB2ENR_CRYPEN_BIT) +#define RCC_AHB2ENR_DCMIEN (1U << RCC_AHB2ENR_DCMIEN_BIT) + +/* AHB3 peripheral clock enable register */ + +#define RCC_AHB3ENR_FSMCEN_BIT 0 + +#define RCC_AHB3ENR_FSMCEN (1U << RCC_AHB3ENR_FSMCEN_BIT) + +/* APB1 peripheral clock enable register */ + +#define RCC_APB1ENR_DACEN_BIT 29 +#define RCC_APB1ENR_PWREN_BIT 28 +#define RCC_APB1ENR_CAN2EN_BIT 26 +#define RCC_APB1ENR_CAN1EN_BIT 25 +#define RCC_APB1ENR_I2C3EN_BIT 23 +#define RCC_APB1ENR_I2C2EN_BIT 22 +#define RCC_APB1ENR_I2C1EN_BIT 21 +#define RCC_APB1ENR_UART5EN_BIT 20 +#define RCC_APB1ENR_UART4EN_BIT 19 +#define RCC_APB1ENR_USART3EN_BIT 18 +#define RCC_APB1ENR_USART2EN_BIT 17 +#define RCC_APB1ENR_SPI3EN_BIT 15 +#define RCC_APB1ENR_SPI2EN_BIT 14 +#define RCC_APB1ENR_WWDGEN_BIT 11 +#define RCC_APB1ENR_TIM14EN_BIT 8 +#define RCC_APB1ENR_TIM13EN_BIT 7 +#define RCC_APB1ENR_TIM12EN_BIT 6 +#define RCC_APB1ENR_TIM7EN_BIT 5 +#define RCC_APB1ENR_TIM6EN_BIT 4 +#define RCC_APB1ENR_TIM5EN_BIT 3 +#define RCC_APB1ENR_TIM4EN_BIT 2 +#define RCC_APB1ENR_TIM3EN_BIT 1 +#define RCC_APB1ENR_TIM2EN_BIT 0 + +#define RCC_APB1ENR_DACEN (1U << RCC_APB1ENR_DACEN_BIT) +#define RCC_APB1ENR_PWREN (1U << RCC_APB1ENR_PWREN_BIT) +#define RCC_APB1ENR_CAN2EN (1U << RCC_APB1ENR_CAN2EN_BIT) +#define RCC_APB1ENR_CAN1EN (1U << RCC_APB1ENR_CAN1EN_BIT) +#define RCC_APB1ENR_I2C3EN (1U << RCC_APB1ENR_I2C3EN_BIT) +#define RCC_APB1ENR_I2C2EN (1U << RCC_APB1ENR_I2C2EN_BIT) +#define RCC_APB1ENR_I2C1EN (1U << RCC_APB1ENR_I2C1EN_BIT) +#define RCC_APB1ENR_UART5EN (1U << RCC_APB1ENR_UART5EN_BIT) +#define RCC_APB1ENR_UART4EN (1U << RCC_APB1ENR_UART4EN_BIT) +#define RCC_APB1ENR_USART3EN (1U << RCC_APB1ENR_USART3EN_BIT) +#define RCC_APB1ENR_USART2EN (1U << RCC_APB1ENR_USART2EN_BIT) +#define RCC_APB1ENR_SPI3EN (1U << RCC_APB1ENR_SPI3EN_BIT) +#define RCC_APB1ENR_SPI2EN (1U << RCC_APB1ENR_SPI2EN_BIT) +#define RCC_APB1ENR_WWDGEN (1U << RCC_APB1ENR_WWDGEN_BIT) +#define RCC_APB1ENR_TIM14EN (1U << RCC_APB1ENR_TIM14EN_BIT) +#define RCC_APB1ENR_TIM13EN (1U << RCC_APB1ENR_TIM13EN_BIT) +#define RCC_APB1ENR_TIM12EN (1U << RCC_APB1ENR_TIM12EN_BIT) +#define RCC_APB1ENR_TIM7EN (1U << RCC_APB1ENR_TIM7EN_BIT) +#define RCC_APB1ENR_TIM6EN (1U << RCC_APB1ENR_TIM6EN_BIT) +#define RCC_APB1ENR_TIM5EN (1U << RCC_APB1ENR_TIM5EN_BIT) +#define RCC_APB1ENR_TIM4EN (1U << RCC_APB1ENR_TIM4EN_BIT) +#define RCC_APB1ENR_TIM3EN (1U << RCC_APB1ENR_TIM3EN_BIT) +#define RCC_APB1ENR_TIM2EN (1U << RCC_APB1ENR_TIM2EN_BIT) + +/* APB2 peripheral clock enable register */ + +#define RCC_APB2ENR_TIM11EN_BIT 18 +#define RCC_APB2ENR_TIM10EN_BIT 17 +#define RCC_APB2ENR_TIM9EN_BIT 16 +#define RCC_APB2ENR_SYSCFGEN_BIT 14 +#define RCC_APB2ENR_SPI1EN_BIT 12 +#define RCC_APB2ENR_SDIOEN_BIT 11 +#define RCC_APB2ENR_ADC3EN_BIT 10 +#define RCC_APB2ENR_ADC2EN_BIT 9 +#define RCC_APB2ENR_ADC1EN_BIT 8 +#define RCC_APB2ENR_USART6EN_BIT 5 +#define RCC_APB2ENR_USART1EN_BIT 4 +#define RCC_APB2ENR_TIM8EN_BIT 1 +#define RCC_APB2ENR_TIM1EN_BIT 0 + +#define RCC_APB2ENR_TIM11EN (1U << RCC_APB2ENR_TIM11EN_BIT) +#define RCC_APB2ENR_TIM10EN (1U << RCC_APB2ENR_TIM10EN_BIT) +#define RCC_APB2ENR_TIM9EN (1U << RCC_APB2ENR_TIM9EN_BIT) +#define RCC_APB2ENR_SYSCFGEN (1U << RCC_APB2ENR_SYSCFGEN_BIT) +#define RCC_APB2ENR_SPI1EN (1U << RCC_APB2ENR_SPI1EN_BIT) +#define RCC_APB2ENR_SDIOEN (1U << RCC_APB2ENR_SDIOEN_BIT) +#define RCC_APB2ENR_ADC3EN (1U << RCC_APB2ENR_ADC3EN_BIT) +#define RCC_APB2ENR_ADC2EN (1U << RCC_APB2ENR_ADC2EN_BIT) +#define RCC_APB2ENR_ADC1EN (1U << RCC_APB2ENR_ADC1EN_BIT) +#define RCC_APB2ENR_USART6EN (1U << RCC_APB2ENR_USART6EN_BIT) +#define RCC_APB2ENR_USART1EN (1U << RCC_APB2ENR_USART1EN_BIT) +#define RCC_APB2ENR_TIM8EN (1U << RCC_APB2ENR_TIM8EN_BIT) +#define RCC_APB2ENR_TIM1EN (1U << RCC_APB2ENR_TIM1EN_BIT) + +/* AHB1 peripheral clock enable in low power mode register */ + +#define RCC_AHB1LPENR_OTGHSULPILPEN_BIT 30 +#define RCC_AHB1LPENR_OTGHSLPEN_BIT 29 +#define RCC_AHB1LPENR_ETHMACPTPLPEN_BIT 28 +#define RCC_AHB1LPENR_ETHMACRXLPEN_BIT 27 +#define RCC_AHB1LPENR_ETHMACTXLPEN_BIT 26 +#define RCC_AHB1LPENR_ETHMACLPEN_BIT 25 +#define RCC_AHB1LPENR_DMA2LPEN_BIT 22 +#define RCC_AHB1LPENR_DMA1LPEN_BIT 21 +#define RCC_AHB1LPENR_BKPSRAMLPEN_BIT 18 +#define RCC_AHB1LPENR_SRAM2LPEN_BIT 17 +#define RCC_AHB1LPENR_SRAM1LPEN_BIT 16 +#define RCC_AHB1LPENR_FLITFLPEN_BIT 15 +#define RCC_AHB1LPENR_CRCLPEN_BIT 12 +#define RCC_AHB1LPENR_GPIOILPEN_BIT 8 +#define RCC_AHB1LPENR_GPIOGLPEN_BIT 6 +#define RCC_AHB1LPENR_GPIOFLPEN_BIT 5 +#define RCC_AHB1LPENR_GPIOELPEN_BIT 4 +#define RCC_AHB1LPENR_GPIODLPEN_BIT 3 +#define RCC_AHB1LPENR_GPIOCLPEN_BIT 2 +#define RCC_AHB1LPENR_GPIOBLPEN_BIT 1 +#define RCC_AHB1LPENR_GPIOALPEN_BIT 0 + +#define RCC_AHB1LPENR_OTGHSULPILPEN (1U << RCC_AHB1LPENR_OTGHSULPILPEN_BIT) +#define RCC_AHB1LPENR_OTGHSLPEN (1U << RCC_AHB1LPENR_OTGHSLPEN_BIT) +#define RCC_AHB1LPENR_ETHMACPTPLPEN (1U << RCC_AHB1LPENR_ETHMACPTPLPEN_BIT) +#define RCC_AHB1LPENR_ETHMACRXLPEN (1U << RCC_AHB1LPENR_ETHMACRXLPEN_BIT) +#define RCC_AHB1LPENR_ETHMACTXLPEN (1U << RCC_AHB1LPENR_ETHMACTXLPEN_BIT) +#define RCC_AHB1LPENR_ETHMACLPEN (1U << RCC_AHB1LPENR_ETHMACLPEN_BIT) +#define RCC_AHB1LPENR_DMA2LPEN (1U << RCC_AHB1LPENR_DMA2LPEN_BIT) +#define RCC_AHB1LPENR_DMA1LPEN (1U << RCC_AHB1LPENR_DMA1LPEN_BIT) +#define RCC_AHB1LPENR_BKPSRAMLPEN (1U << RCC_AHB1LPENR_BKPSRAMLPEN_BIT) +#define RCC_AHB1LPENR_SRAM2LPEN (1U << RCC_AHB1LPENR_SRAM2LPEN_BIT) +#define RCC_AHB1LPENR_SRAM1LPEN (1U << RCC_AHB1LPENR_SRAM1LPEN_BIT) +#define RCC_AHB1LPENR_FLITFLPEN (1U << RCC_AHB1LPENR_FLITFLPEN_BIT) +#define RCC_AHB1LPENR_CRCLPEN (1U << RCC_AHB1LPENR_CRCLPEN_BIT) +#define RCC_AHB1LPENR_GPIOILPEN (1U << RCC_AHB1LPENR_GPIOILPEN_BIT) +#define RCC_AHB1LPENR_GPIOGLPEN (1U << RCC_AHB1LPENR_GPIOGLPEN_BIT) +#define RCC_AHB1LPENR_GPIOFLPEN (1U << RCC_AHB1LPENR_GPIOFLPEN_BIT) +#define RCC_AHB1LPENR_GPIOELPEN (1U << RCC_AHB1LPENR_GPIOELPEN_BIT) +#define RCC_AHB1LPENR_GPIODLPEN (1U << RCC_AHB1LPENR_GPIODLPEN_BIT) +#define RCC_AHB1LPENR_GPIOCLPEN (1U << RCC_AHB1LPENR_GPIOCLPEN_BIT) +#define RCC_AHB1LPENR_GPIOBLPEN (1U << RCC_AHB1LPENR_GPIOBLPEN_BIT) +#define RCC_AHB1LPENR_GPIOALPEN (1U << RCC_AHB1LPENR_GPIOALPEN_BIT) + +/* AHB2 peripheral clock enable in low power mode register */ + +#define RCC_AHB2LPENR_OTGFSLPEN_BIT 7 +#define RCC_AHB2LPENR_RNGLPEN_BIT 6 +#define RCC_AHB2LPENR_HASHLPEN_BIT 5 +#define RCC_AHB2LPENR_CRYPLPEN_BIT 4 +#define RCC_AHB2LPENR_DCMILPEN_BIT 0 + +#define RCC_AHB2LPENR_OTGFSLPEN (1U << RCC_AHB2LPENR_OTGFSLPEN_BIT) +#define RCC_AHB2LPENR_RNGLPEN (1U << RCC_AHB2LPENR_RNGLPEN_BIT) +#define RCC_AHB2LPENR_HASHLPEN (1U << RCC_AHB2LPENR_HASHLPEN_BIT) +#define RCC_AHB2LPENR_CRYPLPEN (1U << RCC_AHB2LPENR_CRYPLPEN_BIT) +#define RCC_AHB2LPENR_DCMILPEN (1U << RCC_AHB2LPENR_DCMILPEN_BIT) + +/* AHB3 peripheral clock enable in low power mode register */ + +#define RCC_AHB3LPENR_FSMCLPEN_BIT 0 + +#define RCC_AHB3LPENR_FSMCLPEN (1U << RCC_AHB3LPENR_FSMCLPEN_BIT) + +/* APB1 peripheral clock enable in low power mode register */ + +#define RCC_APB1LPENR_DACLPEN_BIT 29 +#define RCC_APB1LPENR_PWRLPEN_BIT 28 +#define RCC_APB1LPENR_CAN2LPEN_BIT 26 +#define RCC_APB1LPENR_CAN1LPEN_BIT 25 +#define RCC_APB1LPENR_I2C3LPEN_BIT 23 +#define RCC_APB1LPENR_I2C2LPEN_BIT 22 +#define RCC_APB1LPENR_I2C1LPEN_BIT 21 +#define RCC_APB1LPENR_UART5LPEN_BIT 20 +#define RCC_APB1LPENR_UART4LPEN_BIT 19 +#define RCC_APB1LPENR_USART3LPEN_BIT 18 +#define RCC_APB1LPENR_USART2LPEN_BIT 17 +#define RCC_APB1LPENR_SPI3LPEN_BIT 15 +#define RCC_APB1LPENR_SPI2LPEN_BIT 14 +#define RCC_APB1LPENR_WWDGLPEN_BIT 11 +#define RCC_APB1LPENR_TIM14LPEN_BIT 8 +#define RCC_APB1LPENR_TIM13LPEN_BIT 7 +#define RCC_APB1LPENR_TIM12LPEN_BIT 6 +#define RCC_APB1LPENR_TIM7LPEN_BIT 5 +#define RCC_APB1LPENR_TIM6LPEN_BIT 4 +#define RCC_APB1LPENR_TIM5LPEN_BIT 3 +#define RCC_APB1LPENR_TIM4LPEN_BIT 2 +#define RCC_APB1LPENR_TIM3LPEN_BIT 1 +#define RCC_APB1LPENR_TIM2LPEN_BIT 0 + +#define RCC_APB1LPENR_DACLPEN (1U << RCC_APB1LPENR_DACLPEN_BIT) +#define RCC_APB1LPENR_PWRLPEN (1U << RCC_APB1LPENR_PWRLPEN_BIT) +#define RCC_APB1LPENR_CAN2LPEN (1U << RCC_APB1LPENR_CAN2LPEN_BIT) +#define RCC_APB1LPENR_CAN1LPEN (1U << RCC_APB1LPENR_CAN1LPEN_BIT) +#define RCC_APB1LPENR_I2C3LPEN (1U << RCC_APB1LPENR_I2C3LPEN_BIT) +#define RCC_APB1LPENR_I2C2LPEN (1U << RCC_APB1LPENR_I2C2LPEN_BIT) +#define RCC_APB1LPENR_I2C1LPEN (1U << RCC_APB1LPENR_I2C1LPEN_BIT) +#define RCC_APB1LPENR_UART5LPEN (1U << RCC_APB1LPENR_UART5LPEN_BIT) +#define RCC_APB1LPENR_UART4LPEN (1U << RCC_APB1LPENR_UART4LPEN_BIT) +#define RCC_APB1LPENR_USART3LPEN (1U << RCC_APB1LPENR_USART3LPEN_BIT) +#define RCC_APB1LPENR_USART2LPEN (1U << RCC_APB1LPENR_USART2LPEN_BIT) +#define RCC_APB1LPENR_SPI3LPEN (1U << RCC_APB1LPENR_SPI3LPEN_BIT) +#define RCC_APB1LPENR_SPI2LPEN (1U << RCC_APB1LPENR_SPI2LPEN_BIT) +#define RCC_APB1LPENR_WWDGLPEN (1U << RCC_APB1LPENR_WWDGLPEN_BIT) +#define RCC_APB1LPENR_TIM14LPEN (1U << RCC_APB1LPENR_TIM14LPEN_BIT) +#define RCC_APB1LPENR_TIM13LPEN (1U << RCC_APB1LPENR_TIM13LPEN_BIT) +#define RCC_APB1LPENR_TIM12LPEN (1U << RCC_APB1LPENR_TIM12LPEN_BIT) +#define RCC_APB1LPENR_TIM7LPEN (1U << RCC_APB1LPENR_TIM7LPEN_BIT) +#define RCC_APB1LPENR_TIM6LPEN (1U << RCC_APB1LPENR_TIM6LPEN_BIT) +#define RCC_APB1LPENR_TIM5LPEN (1U << RCC_APB1LPENR_TIM5LPEN_BIT) +#define RCC_APB1LPENR_TIM4LPEN (1U << RCC_APB1LPENR_TIM4LPEN_BIT) +#define RCC_APB1LPENR_TIM3LPEN (1U << RCC_APB1LPENR_TIM3LPEN_BIT) +#define RCC_APB1LPENR_TIM2LPEN (1U << RCC_APB1LPENR_TIM2LPEN_BIT) + +/* APB2 peripheral clock enable in low power mode register */ + +#define RCC_APB2LPENR_TIM11LPEN_BIT 18 +#define RCC_APB2LPENR_TIM10LPEN_BIT 17 +#define RCC_APB2LPENR_TIM9LPEN_BIT 16 +#define RCC_APB2LPENR_SYSCFGLPEN_BIT 14 +#define RCC_APB2LPENR_SPI1LPEN_BIT 12 +#define RCC_APB2LPENR_SDIOLPEN_BIT 11 +#define RCC_APB2LPENR_ADC3LPEN_BIT 10 +#define RCC_APB2LPENR_ADC2LPEN_BIT 9 +#define RCC_APB2LPENR_ADC1LPEN_BIT 8 +#define RCC_APB2LPENR_USART6LPEN_BIT 5 +#define RCC_APB2LPENR_USART1LPEN_BIT 4 +#define RCC_APB2LPENR_TIM8LPEN_BIT 1 +#define RCC_APB2LPENR_TIM1LPEN_BIT 0 + +#define RCC_APB2LPENR_TIM11LPEN (1U << RCC_APB2LPENR_TIM11LPEN_BIT) +#define RCC_APB2LPENR_TIM10LPEN (1U << RCC_APB2LPENR_TIM10LPEN_BIT) +#define RCC_APB2LPENR_TIM9LPEN (1U << RCC_APB2LPENR_TIM9LPEN_BIT) +#define RCC_APB2LPENR_SYSCFGLPEN (1U << RCC_APB2LPENR_SYSCFGLPEN_BIT) +#define RCC_APB2LPENR_SPI1LPEN (1U << RCC_APB2LPENR_SPI1LPEN_BIT) +#define RCC_APB2LPENR_SDIOLPEN (1U << RCC_APB2LPENR_SDIOLPEN_BIT) +#define RCC_APB2LPENR_ADC3LPEN (1U << RCC_APB2LPENR_ADC3LPEN_BIT) +#define RCC_APB2LPENR_ADC2LPEN (1U << RCC_APB2LPENR_ADC2LPEN_BIT) +#define RCC_APB2LPENR_ADC1LPEN (1U << RCC_APB2LPENR_ADC1LPEN_BIT) +#define RCC_APB2LPENR_USART6LPEN (1U << RCC_APB2LPENR_USART6LPEN_BIT) +#define RCC_APB2LPENR_USART1LPEN (1U << RCC_APB2LPENR_USART1LPEN_BIT) +#define RCC_APB2LPENR_TIM8LPEN (1U << RCC_APB2LPENR_TIM8LPEN_BIT) +#define RCC_APB2LPENR_TIM1LPEN (1U << RCC_APB2LPENR_TIM1LPEN_BIT) + +/* Backup domain control register */ + +#define RCC_BDCR_BDRST_BIT 16 +#define RCC_BDCR_RTCEN_BIT 15 +#define RCC_BDCR_LSEBYP_BIT 2 +#define RCC_BDCR_LSERDY_BIT 1 +#define RCC_BDCR_LSEON_BIT 0 + +#define RCC_BDCR_BDRST (1U << RCC_BDCR_BDRST_BIT) +#define RCC_BDCR_RTCEN (1U << RCC_BDCR_RTCEN_BIT) +#define RCC_BDCR_RTCSEL (0x3 << 8) +#define RCC_BDCR_RTCSEL_NOCLOCK (0x0 << 8) +#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) +#define RCC_BDCR_RTCSEL_LSI (0x2 << 8) +#define RCC_BDCR_RTCSEL_HSE_DIV (0x3 << 8) +#define RCC_BDCR_LSEBYP (1U << RCC_BDCR_LSEBYP_BIT) +#define RCC_BDCR_LSERDY (1U << RCC_BDCR_LSERDY_BIT) +#define RCC_BDCR_LSEON (1U << RCC_BDCR_LSEON_BIT) + +/* Clock control and status register */ + +#define RCC_CSR_LPWRRSTF_BIT 31 +#define RCC_CSR_WWDGRSTF_BIT 30 +#define RCC_CSR_IWDGRSTF_BIT 29 +#define RCC_CSR_SFTRSTF_BIT 28 +#define RCC_CSR_PORRSTF_BIT 27 +#define RCC_CSR_PINRSTF_BIT 26 +#define RCC_CSR_BORRSTF_BIT 25 +#define RCC_CSR_RMVF_BIT 24 +#define RCC_CSR_LSIRDY_BIT 1 +#define RCC_CSR_LSION_BIT 0 + +#define RCC_CSR_LPWRRSTF (1U << RCC_CSR_LPWRRSTF_BIT) +#define RCC_CSR_WWDGRSTF (1U << RCC_CSR_WWDGRSTF_BIT) +#define RCC_CSR_IWDGRSTF (1U << RCC_CSR_IWDGRSTF_BIT) +#define RCC_CSR_SFTRSTF (1U << RCC_CSR_SFTRSTF_BIT) +#define RCC_CSR_PORRSTF (1U << RCC_CSR_PORRSTF_BIT) +#define RCC_CSR_PINRSTF (1U << RCC_CSR_PINRSTF_BIT) +#define RCC_CSR_BORRSTF (1U << RCC_CSR_BORRSTF_BIT) +#define RCC_CSR_RMVF (1U << RCC_CSR_RMVF_BIT) +#define RCC_CSR_LSIRDY (1U << RCC_CSR_LSIRDY_BIT) +#define RCC_CSR_LSION (1U << RCC_CSR_LSION_BIT) + +/* Spread spectrum clock generation register */ + +#define RCC_SSCGR_SSCGEN_BIT 31 +#define RCC_SSCGR_SPREADSEL_BIT 30 + +#define RCC_SSCGR_SSCGEN (1U << RCC_SSCGR_SSCGEN_BIT) +#define RCC_SSCGR_SPREADSEL (1U << RCC_SSCGR_SPREADSEL_BIT) +#define RCC_SSCGR_SPREADSEL_CENTER (0x0 << RCC_SSCGR_SPREADSEL_BIT) +#define RCC_SSCGR_SPREADSEL_DOWN (0x1 << RCC_SSCGR_SPREADSEL_BIT) +#define RCC_SSCGR_INCSTEP (0xFFF << 16) +#define RCC_SSCGR_MODPER 0xFFFF + +/* PLLI2S configuration register */ + +#define RCC_PLLI2SCFGR_PLLI2SR (0x7 << 28) +#define RCC_PLLI2SCFGR_PLLI2SN (0x1FF << 6) + +/* + * Clock sources, domains, and peripheral clock IDs. + */ + +/** + * @brief STM32F2 clock sources. + */ +typedef enum rcc_clk { + RCC_CLK_PLLI2S = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_PLLI2SON_BIT), /**< Dedicated PLL + for I2S. */ + RCC_CLK_PLL = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_PLLON_BIT), /**< Main PLL, clocked by + HSI or HSE. */ + RCC_CLK_HSE = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_HSEON_BIT), /**< High speed external. */ + RCC_CLK_HSI = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_HSION_BIT), /**< High speed internal. */ + RCC_CLK_LSE = (uint16)((offsetof(struct rcc_reg_map, BDCR) << 8) | + RCC_BDCR_LSEON_BIT), /**< Low-speed external + * (32.768 KHz). */ + RCC_CLK_LSI = (uint16)((offsetof(struct rcc_reg_map, CSR) << 8) | + RCC_CSR_LSION_BIT), /**< Low-speed internal + * (approximately 32 KHz). */ +} rcc_clk; + +/** + * @brief STM32F2 rcc_clk_id. + */ +typedef enum rcc_clk_id { + RCC_ADC1, + RCC_ADC2, + RCC_ADC3, + RCC_BKPSRAM, + RCC_CAN1, + RCC_CAN2, + RCC_CRC, + RCC_CRYP, + RCC_DAC, + RCC_DCMI, + RCC_DMA1, + RCC_DMA2, + RCC_ETHMAC, + RCC_ETHMACPTP, + RCC_ETHMACRX, + RCC_ETHMACTX, + RCC_FSMC, + RCC_GPIOA, + RCC_GPIOB, + RCC_GPIOC, + RCC_GPIOD, + RCC_GPIOE, + RCC_GPIOF, + RCC_GPIOG, + RCC_GPIOH, + RCC_GPIOI, + RCC_HASH, + RCC_I2C1, + RCC_I2C2, + RCC_I2C3, + RCC_OTGFS, + RCC_OTGHS, + RCC_OTGHSULPI, + RCC_PWR, + RCC_RNG, + RCC_SDIO, + RCC_SPI1, + RCC_SPI2, + RCC_SPI3, + RCC_SYSCFG, + RCC_TIMER1, + RCC_TIMER10, + RCC_TIMER11, + RCC_TIMER12, + RCC_TIMER13, + RCC_TIMER14, + RCC_TIMER2, + RCC_TIMER3, + RCC_TIMER4, + RCC_TIMER5, + RCC_TIMER6, + RCC_TIMER7, + RCC_TIMER8, + RCC_TIMER9, + RCC_USART1, + RCC_USART2, + RCC_USART3, + RCC_UART4, + RCC_UART5, + RCC_USART6, + RCC_WWDG, +} rcc_clk_id; + +/** + * @brief STM32F2 PLL entry clock source + * @see rcc_configure_pll() + */ +typedef enum rcc_pllsrc { + RCC_PLLSRC_HSI = 0, + RCC_PLLSRC_HSE = RCC_PLLCFGR_PLLSRC, +} rcc_pllsrc; + +/** + * @brief STM32F2 Peripheral clock domains. + */ +typedef enum rcc_clk_domain { + RCC_APB1, + RCC_APB2, + RCC_AHB1, + RCC_AHB2, + RCC_AHB3, +} rcc_clk_domain; + +/* + * Prescalers and dividers. + */ + +/** + * @brief STM32F2 Prescaler identifiers. + */ +typedef enum rcc_prescaler { + RCC_PRESCALER_MCO2, + RCC_PRESCALER_MCO1, + RCC_PRESCALER_RTC, + RCC_PRESCALER_APB2, + RCC_PRESCALER_APB1, + RCC_PRESCALER_AHB +} rcc_prescaler; + +/** + * @brief STM32F2 MCO2 prescaler dividers. + */ +typedef enum rcc_mco2_divider { + RCC_MCO2_DIV_1 = RCC_CFGR_MCO2PRE_DIV_1, + RCC_MCO2_DIV_2 = RCC_CFGR_MCO2PRE_DIV_2, + RCC_MCO2_DIV_3 = RCC_CFGR_MCO2PRE_DIV_3, + RCC_MCO2_DIV_4 = RCC_CFGR_MCO2PRE_DIV_4, + RCC_MCO2_DIV_5 = RCC_CFGR_MCO2PRE_DIV_5, +} rcc_mco2_divider; + +/** + * @brief STM32F2 MCO1 prescaler dividers. + */ +typedef enum rcc_mco1_divider { + RCC_MCO1_DIV_1 = RCC_CFGR_MCO1PRE_DIV_1, + RCC_MCO1_DIV_2 = RCC_CFGR_MCO1PRE_DIV_2, + RCC_MCO1_DIV_3 = RCC_CFGR_MCO1PRE_DIV_3, + RCC_MCO1_DIV_4 = RCC_CFGR_MCO1PRE_DIV_4, + RCC_MCO1_DIV_5 = RCC_CFGR_MCO1PRE_DIV_5, +} rcc_mco1_divider; + +/** + * @brief STM32F2 RTC prescaler dividers. + */ +typedef enum rcc_rtc_divider { /* FIXME [0.0.13] TODO */ + RCC_RTC_DIV_TODO = 0xFFFFFFFF, +} rcc_rtc_divider; + +/** + * @brief STM32F2 AP2 prescaler dividers. + */ +typedef enum rcc_apb2_divider { + RCC_APB2_HCLK_DIV_1 = 0, + RCC_APB2_HCLK_DIV_2 = RCC_CFGR_PPRE2_AHB_DIV_2, + RCC_APB2_HCLK_DIV_4 = RCC_CFGR_PPRE2_AHB_DIV_4, + RCC_APB2_HCLK_DIV_8 = RCC_CFGR_PPRE2_AHB_DIV_8, + RCC_APB2_HCLK_DIV_16 = RCC_CFGR_PPRE2_AHB_DIV_16, +} rcc_apb2_divider; + +/** + * @brief STM32F2 APB1 prescaler dividers. + */ +typedef enum rcc_apb1_divider { + RCC_APB1_HCLK_DIV_1 = 0, + RCC_APB1_HCLK_DIV_2 = RCC_CFGR_PPRE1_AHB_DIV_2, + RCC_APB1_HCLK_DIV_4 = RCC_CFGR_PPRE1_AHB_DIV_4, + RCC_APB1_HCLK_DIV_8 = RCC_CFGR_PPRE1_AHB_DIV_8, + RCC_APB1_HCLK_DIV_16 = RCC_CFGR_PPRE1_AHB_DIV_16, +} rcc_apb1_divider; + +/** + * @brief STM32F2 AHB prescaler dividers. + */ +typedef enum rcc_ahb_divider { + RCC_AHB_SYSCLK_DIV_1 = 0, + RCC_AHB_SYSCLK_DIV_2 = RCC_CFGR_HPRE_SYSCLK_DIV_2, + RCC_AHB_SYSCLK_DIV_4 = RCC_CFGR_HPRE_SYSCLK_DIV_4, + RCC_AHB_SYSCLK_DIV_8 = RCC_CFGR_HPRE_SYSCLK_DIV_8, + RCC_AHB_SYSCLK_DIV_16 = RCC_CFGR_HPRE_SYSCLK_DIV_16, + RCC_AHB_SYSCLK_DIV_64 = RCC_CFGR_HPRE_SYSCLK_DIV_64, + RCC_AHB_SYSCLK_DIV_128 = RCC_CFGR_HPRE_SYSCLK_DIV_128, + RCC_AHB_SYSCLK_DIV_256 = RCC_CFGR_HPRE_SYSCLK_DIV_256, + RCC_AHB_SYSCLK_DIV_512 = RCC_CFGR_HPRE_SYSCLK_DIV_512, +} rcc_ahb_divider; + +/** + * @brief STM32F2 PLL configuration values. + * Point to one of these with the "data" field in a struct rcc_pll_cfg. + * @see struct rcc_pll_cfg. + */ +typedef struct stm32f2_rcc_pll_data { + uint8 pllq; /**< + * @brief PLLQ value. + * Allowed values: 4, 5, ..., 15. */ + uint8 pllp; /**< + * @brief PLLP value. + * Allowed values: 2, 4, 6, 8. */ + uint16 plln; /**< + * @brief PLLN value. + * Allowed values: 192, 193, ..., 432. */ + uint8 pllm; /**< + * @brief PLLM value. + * Allowed values: 2, 3, ..., 63. */ +} stm32f2_rcc_pll_data; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/spi.h b/libmaple/stm32f2/include/series/spi.h new file mode 100644 index 0000000..7b9f94a --- /dev/null +++ b/libmaple/stm32f2/include/series/spi.h @@ -0,0 +1,88 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/spi.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 SPI/I2S series header. + */ + +#ifndef _LIBMAPLE_STM32F2_SPI_H_ +#define _LIBMAPLE_STM32F2_SPI_H_ + +#include <libmaple/gpio.h> /* for gpio_af */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Register map base pointers + */ + +struct spi_reg_map; + +#define SPI1_BASE ((struct spi_reg_map*)0x40013000) +#define SPI2_BASE ((struct spi_reg_map*)0x40003800) +#define SPI3_BASE ((struct spi_reg_map*)0x40003C00) + +/* + * Register bit definitions + */ + +/* Control register 2 */ + +#define SPI_CR2_FRF_BIT 4 + +#define SPI_CR2_FRF (1U << SPI_CR2_FRF_BIT) + +/* Status register */ + +#define SPI_SR_TIFRFE_BIT 8 + +#define SPI_SR_TIFRFE (1U << SPI_SR_TIFRFE_BIT) + +/* + * Device pointers + */ + +struct spi_dev; + +extern struct spi_dev *SPI1; +extern struct spi_dev *SPI2; +extern struct spi_dev *SPI3; + +/* + * Routines + */ + +gpio_af spi_get_af(struct spi_dev *dev); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/stm32.h b/libmaple/stm32f2/include/series/stm32.h new file mode 100644 index 0000000..180ab30 --- /dev/null +++ b/libmaple/stm32f2/include/series/stm32.h @@ -0,0 +1,77 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/stm32.h + * @brief STM32F2 chip- and series-specific definitions. + */ + +#ifndef _LIBMAPLE_STM32F2_STM32_H_ +#define _LIBMAPLE_STM32F2_STM32_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Chip configuration + */ + +#ifndef STM32_PCLK1 +#define STM32_PCLK1 30000000U +#endif + +#ifndef STM32_PCLK2 +#define STM32_PCLK2 60000000U +#endif + +#ifndef STM32_DELAY_US_MULT +#define STM32_DELAY_US_MULT 20 /* FIXME: dummy value. */ +#endif + +/* + * Series- and MCU-specific values + */ + +#define STM32_MCU_SERIES STM32_SERIES_F2 +#define STM32_NR_INTERRUPTS 81 +#define STM32_HAVE_FSMC 1 +#define STM32_HAVE_USB 1 +#define STM32_HAVE_DAC 1 + +#if defined(MCU_STM32F207IC) || defined(MCU_STM32F207IG) +# define STM32_NR_GPIO_PORTS 9 +# define STM32_TIMER_MASK 0x7FFE /* TIMER1-TIMER14. */ +# define STM32_SRAM_END ((void*)0x20020000) +#else +#warning "Unsupported or unspecified STM32F2 MCU." +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f2/include/series/timer.h b/libmaple/stm32f2/include/series/timer.h new file mode 100644 index 0000000..a7ac276 --- /dev/null +++ b/libmaple/stm32f2/include/series/timer.h @@ -0,0 +1,176 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011,2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/timer.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 timer support. + */ + +#ifndef _LIBMAPLE_STM32F2_TIMER_H_ +#define _LIBMAPLE_STM32F2_TIMER_H_ + +#include <libmaple/libmaple_types.h> +#include <libmaple/gpio.h> /* for gpio_af */ + +/* + * Register maps and base pointers + */ + +/** + * @brief STM32F2 general purpose timer register map type + * + * Note that not all general purpose timers have all of these + * registers. Consult your chip's reference manual for the details. + */ +typedef struct timer_gen_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 SMCR; /**< Slave mode control register */ + __io uint32 DIER; /**< DMA/Interrupt enable register */ + __io uint32 SR; /**< Status register */ + __io uint32 EGR; /**< Event generation register */ + __io uint32 CCMR1; /**< Capture/compare mode register 1 */ + __io uint32 CCMR2; /**< Capture/compare mode register 2 */ + __io uint32 CCER; /**< Capture/compare enable register */ + __io uint32 CNT; /**< Counter */ + __io uint32 PSC; /**< Prescaler */ + __io uint32 ARR; /**< Auto-reload register */ + const uint32 RESERVED1; /**< Reserved */ + __io uint32 CCR1; /**< Capture/compare register 1 */ + __io uint32 CCR2; /**< Capture/compare register 2 */ + __io uint32 CCR3; /**< Capture/compare register 3 */ + __io uint32 CCR4; /**< Capture/compare register 4 */ + const uint32 RESERVED2; /**< Reserved */ + __io uint32 DCR; /**< DMA control register */ + __io uint32 DMAR; /**< DMA address for full transfer */ + __io uint32 OR; /**< Option register. */ +} timer_gen_reg_map; + +struct timer_adv_reg_map; +struct timer_bas_reg_map; + +/** Timer 1 register map base pointer */ +#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40010000) +/** Timer 2 register map base pointer */ +#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000) +/** Timer 3 register map base pointer */ +#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400) +/** Timer 4 register map base pointer */ +#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800) +/** Timer 5 register map base pointer */ +#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00) +/** Timer 6 register map base pointer */ +#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000) +/** Timer 7 register map base pointer */ +#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400) +/** Timer 8 register map base pointer */ +#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40010400) +/** Timer 9 register map base pointer */ +#define TIMER9_BASE ((struct timer_gen_reg_map*)0x40014000) +/** Timer 10 register map base pointer */ +#define TIMER10_BASE ((struct timer_gen_reg_map*)0x40014400) +/** Timer 11 register map base pointer */ +#define TIMER11_BASE ((struct timer_gen_reg_map*)0x40014800) +/** Timer 12 register map base pointer */ +#define TIMER12_BASE ((struct timer_gen_reg_map*)0x40001800) +/** Timer 13 register map base pointer */ +#define TIMER13_BASE ((struct timer_gen_reg_map*)0x40001C00) +/** Timer 14 register map base pointer */ +#define TIMER14_BASE ((struct timer_gen_reg_map*)0x40002000) + +/* + * Register bit definitions + */ + +/* TIM2 option register */ + +/** Timer 2 option register internal trigger 1 remap */ +#define TIMER2_OR_ITR1_RMP (0x3 << 10) +/** Timer 2 OR internal trigger 1: TIM8_TRGOUT */ +#define TIMER2_OR_ITR1_RMP_TIM8_TRGOUT (0x0 << 10) +/** Timer 2 OR internal trigger 1: Ethernet PTP trigger output */ +#define TIMER2_OR_ITR1_RMP_PTP_TRGOUT (0x1 << 10) +/** Timer 2 OR internal trigger 1: USB OTG full speed start of frame */ +#define TIMER2_OR_ITR1_RMP_OTG_FS_SOF (0x2 << 10) +/** Timer 2 OR internal trigger 1: USB OTG high speed start of frame */ +#define TIMER2_OR_ITR1_RMP_OTG_HS_SOF (0x3 << 10) + +/* TIM5 option register */ + +/** + * Timer 5 option register input 4 remap. + * + * These bits control whether TIM5_CH4 is connected to a GPIO or a + * clock. Connecting to a GPIO is the normal mode, useful for e.g. PWM + * generation or input pulse duration measurement. Connecting to a + * clock is useful for calibrating that clock. + */ +#define TIMER5_OR_TI4_RMP (0x3 << 6) +/** + * Timer 5 OR input 4: Timer 5 channel 4 connected to GPIO. */ +#define TIMER5_OR_TI4_RMP_GPIO (0x0 << 6) +/** + * Timer 5 OR input 4: low speed internal clock (LSI) is connected to + * TIM5_CH4. */ +#define TIMER5_OR_TI4_RMP_LSI (0x1 << 6) +/** + * Timer 5 OR input 4: low speed external clock (LSE) is connected to + * TIM5_CH4. */ +#define TIMER5_OR_TI4_RMP_LSE (0x2 << 6) +/** + * Timer 5 OR input 4: real time clock (RTC) output is connected to + * TIM5_CH4. */ +#define TIMER5_OR_TI4_RMP_RTC (0x3 << 6) + +/* + * Device pointers + */ + +struct timer_dev; + +extern struct timer_dev *TIMER1; +extern struct timer_dev *TIMER2; +extern struct timer_dev *TIMER3; +extern struct timer_dev *TIMER4; +extern struct timer_dev *TIMER5; +extern struct timer_dev *TIMER6; +extern struct timer_dev *TIMER7; +extern struct timer_dev *TIMER8; +extern struct timer_dev *TIMER9; +extern struct timer_dev *TIMER10; +extern struct timer_dev *TIMER11; +extern struct timer_dev *TIMER12; +extern struct timer_dev *TIMER13; +extern struct timer_dev *TIMER14; + +/* + * Routines + */ + +gpio_af timer_get_af(struct timer_dev *dev); + +#endif diff --git a/libmaple/stm32f2/include/series/usart.h b/libmaple/stm32f2/include/series/usart.h new file mode 100644 index 0000000..8936efa --- /dev/null +++ b/libmaple/stm32f2/include/series/usart.h @@ -0,0 +1,111 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/include/series/usart.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 USART support. + */ + +#ifndef _LIBMAPLE_STM32F2_USART_H_ +#define _LIBMAPLE_STM32F2_USART_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include <libmaple/gpio.h> /* for gpio_af */ + +/* + * Register map base pointers. + */ + +struct usart_reg_map; + +/** USART1 register map base pointer */ +#define USART1_BASE ((struct usart_reg_map*)0x40011000) +/** USART2 register map base pointer */ +#define USART2_BASE ((struct usart_reg_map*)0x40004400) +/** USART3 register map base pointer */ +#define USART3_BASE ((struct usart_reg_map*)0x40004800) +/** UART4 register map base pointer */ +#define UART4_BASE ((struct usart_reg_map*)0x40004C00) +/** UART5 register map base pointer */ +#define UART5_BASE ((struct usart_reg_map*)0x40005000) +/** USART6 register map base pointer */ +#define USART6_BASE ((struct usart_reg_map*)0x40011400) + +/* + * F2-only register bit definitions. + */ + +/* Control register 1 */ + +/** + * @brief Oversampling mode bit. + * Availability: STM32F2. */ +#define USART_CR1_OVER8_BIT 15 + +/** + * @brief Oversampling mode. + * Availability: STM32F2. */ +#define USART_CR1_OVER8 (1U << USART_CR1_OVER8_BIT) + +/* Control register 3 */ + +/** One sample bit method enable bit. */ +#define USART_CR3_ONEBIT_BIT 11 + +/** One bit sample method enable. */ +#define USART_CR3_ONEBIT (1 << USART_CR3_ONEBIT_BIT) +/** Sample method: Three sample bit method. */ +#define USART_CR3_ONEBIT_3SAMPLE (0 << USART_CR3_ONEBIT_BIT) +/** Sample method: One sample bit method. */ +#define USART_CR3_ONEBIT_1SAMPLE (1 << USART_CR3_ONEBIT_BIT) + +/* + * Devices + */ + +struct usart_dev; +extern struct usart_dev *USART1; +extern struct usart_dev *USART2; +extern struct usart_dev *USART3; +extern struct usart_dev *UART4; +extern struct usart_dev *UART5; +extern struct usart_dev *USART6; + +/* + * Routines + */ + +gpio_af usart_get_af(struct usart_dev *dev); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmaple/stm32f2/isrs.S b/libmaple/stm32f2/isrs.S new file mode 100644 index 0000000..5baaf8b --- /dev/null +++ b/libmaple/stm32f2/isrs.S @@ -0,0 +1,322 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* STM32F2 ISR weak declarations */ + + .thumb + +/* Default handler, as with STM32F1 */ + .globl __default_handler + .type __default_handler, %function + +__default_handler: + b . + + .weak __exc_nmi + .globl __exc_nmi + .set __exc_nmi, __default_handler + .weak __exc_hardfault + .globl __exc_hardfault + .set __exc_hardfault, __default_handler + .weak __exc_memmanage + .globl __exc_memmanage + .set __exc_memmanage, __default_handler + .weak __exc_busfault + .globl __exc_busfault + .set __exc_busfault, __default_handler + .weak __exc_usagefault + .globl __exc_usagefault + .set __exc_usagefault, __default_handler + .weak __stm32reservedexception7 + .globl __stm32reservedexception7 + .set __stm32reservedexception7, __default_handler + .weak __stm32reservedexception8 + .globl __stm32reservedexception8 + .set __stm32reservedexception8, __default_handler + .weak __stm32reservedexception9 + .globl __stm32reservedexception9 + .set __stm32reservedexception9, __default_handler + .weak __stm32reservedexception10 + .globl __stm32reservedexception10 + .set __stm32reservedexception10, __default_handler + .weak __exc_svc + .globl __exc_svc + .set __exc_svc, __default_handler + .weak __exc_debug_monitor + .globl __exc_debug_monitor + .set __exc_debug_monitor, __default_handler + .weak __stm32reservedexception13 + .globl __stm32reservedexception13 + .set __stm32reservedexception13, __default_handler + .weak __exc_pendsv + .globl __exc_pendsv + .set __exc_pendsv, __default_handler + .weak __exc_systick + .globl __exc_systick + .set __exc_systick, __default_handler + .weak __irq_wwdg + .globl __irq_wwdg + .set __irq_wwdg, __default_handler + .weak __irq_pvd + .globl __irq_pvd + .set __irq_pvd, __default_handler + .weak __irq_tamp_stamp + .globl __irq_tamp_stamp + .set __irq_tamp_stamp, __default_handler + .weak __irq_rtc_wkup + .globl __irq_rtc_wkup + .set __irq_rtc_wkup, __default_handler + .weak __irq_flash + .globl __irq_flash + .set __irq_flash, __default_handler + .weak __irq_rcc + .globl __irq_rcc + .set __irq_rcc, __default_handler + .weak __irq_exti0 + .globl __irq_exti0 + .set __irq_exti0, __default_handler + .weak __irq_exti1 + .globl __irq_exti1 + .set __irq_exti1, __default_handler + .weak __irq_exti2 + .globl __irq_exti2 + .set __irq_exti2, __default_handler + .weak __irq_exti3 + .globl __irq_exti3 + .set __irq_exti3, __default_handler + .weak __irq_exti4 + .globl __irq_exti4 + .set __irq_exti4, __default_handler + .weak __irq_dma1_stream0 + .globl __irq_dma1_stream0 + .set __irq_dma1_stream0, __default_handler + .weak __irq_dma1_stream1 + .globl __irq_dma1_stream1 + .set __irq_dma1_stream1, __default_handler + .weak __irq_dma1_stream2 + .globl __irq_dma1_stream2 + .set __irq_dma1_stream2, __default_handler + .weak __irq_dma1_stream3 + .globl __irq_dma1_stream3 + .set __irq_dma1_stream3, __default_handler + .weak __irq_dma1_stream4 + .globl __irq_dma1_stream4 + .set __irq_dma1_stream4, __default_handler + .weak __irq_dma1_stream5 + .globl __irq_dma1_stream5 + .set __irq_dma1_stream5, __default_handler + .weak __irq_dma1_stream6 + .globl __irq_dma1_stream6 + .set __irq_dma1_stream6, __default_handler + .weak __irq_adc + .globl __irq_adc + .set __irq_adc, __default_handler + .weak __irq_can1_tx + .globl __irq_can1_tx + .set __irq_can1_tx, __default_handler + .weak __irq_can1_rx0 + .globl __irq_can1_rx0 + .set __irq_can1_rx0, __default_handler + .weak __irq_can1_rx1 + .globl __irq_can1_rx1 + .set __irq_can1_rx1, __default_handler + .weak __irq_can1_sce + .globl __irq_can1_sce + .set __irq_can1_sce, __default_handler + .weak __irq_exti9_5 + .globl __irq_exti9_5 + .set __irq_exti9_5, __default_handler + .weak __irq_tim1_brk_tim9 + .globl __irq_tim1_brk_tim9 + .set __irq_tim1_brk_tim9, __default_handler + .weak __irq_tim1_up_tim10 + .globl __irq_tim1_up_tim10 + .set __irq_tim1_up_tim10, __default_handler + .weak __irq_tim1_trg_com_tim11 + .globl __irq_tim1_trg_com_tim11 + .set __irq_tim1_trg_com_tim11, __default_handler + .weak __irq_tim1_cc + .globl __irq_tim1_cc + .set __irq_tim1_cc, __default_handler + .weak __irq_tim2 + .globl __irq_tim2 + .set __irq_tim2, __default_handler + .weak __irq_tim3 + .globl __irq_tim3 + .set __irq_tim3, __default_handler + .weak __irq_tim4 + .globl __irq_tim4 + .set __irq_tim4, __default_handler + .weak __irq_i2c1_ev + .globl __irq_i2c1_ev + .set __irq_i2c1_ev, __default_handler + .weak __irq_i2c1_er + .globl __irq_i2c1_er + .set __irq_i2c1_er, __default_handler + .weak __irq_i2c2_ev + .globl __irq_i2c2_ev + .set __irq_i2c2_ev, __default_handler + .weak __irq_i2c2_er + .globl __irq_i2c2_er + .set __irq_i2c2_er, __default_handler + .weak __irq_spi1 + .globl __irq_spi1 + .set __irq_spi1, __default_handler + .weak __irq_spi2 + .globl __irq_spi2 + .set __irq_spi2, __default_handler + .weak __irq_usart1 + .globl __irq_usart1 + .set __irq_usart1, __default_handler + .weak __irq_usart2 + .globl __irq_usart2 + .set __irq_usart2, __default_handler + .weak __irq_usart3 + .globl __irq_usart3 + .set __irq_usart3, __default_handler + .weak __irq_exti15_10 + .globl __irq_exti15_10 + .set __irq_exti15_10, __default_handler + .weak __irq_rtc_alarm + .globl __irq_rtc_alarm + .set __irq_rtc_alarm, __default_handler + .weak __irq_otg_fs_wkup + .globl __irq_otg_fs_wkup + .set __irq_otg_fs_wkup, __default_handler + .weak __irq_tim8_brk_tim12 + .globl __irq_tim8_brk_tim12 + .set __irq_tim8_brk_tim12, __default_handler + .weak __irq_tim8_up_tim13 + .globl __irq_tim8_up_tim13 + .set __irq_tim8_up_tim13, __default_handler + .weak __irq_tim8_trg_com_tim14 + .globl __irq_tim8_trg_com_tim14 + .set __irq_tim8_trg_com_tim14, __default_handler + .weak __irq_tim8_cc + .globl __irq_tim8_cc + .set __irq_tim8_cc, __default_handler + .weak __irq_dma1_stream7 + .globl __irq_dma1_stream7 + .set __irq_dma1_stream7, __default_handler + .weak __irq_fsmc + .globl __irq_fsmc + .set __irq_fsmc, __default_handler + .weak __irq_sdio + .globl __irq_sdio + .set __irq_sdio, __default_handler + .weak __irq_tim5 + .globl __irq_tim5 + .set __irq_tim5, __default_handler + .weak __irq_spi3 + .globl __irq_spi3 + .set __irq_spi3, __default_handler + .weak __irq_uart4 + .globl __irq_uart4 + .set __irq_uart4, __default_handler + .weak __irq_uart5 + .globl __irq_uart5 + .set __irq_uart5, __default_handler + .weak __irq_tim6_dac + .globl __irq_tim6_dac + .set __irq_tim6_dac, __default_handler + .weak __irq_tim7 + .globl __irq_tim7 + .set __irq_tim7, __default_handler + .weak __irq_dma2_stream0 + .globl __irq_dma2_stream0 + .set __irq_dma2_stream0, __default_handler + .weak __irq_dma2_stream1 + .globl __irq_dma2_stream1 + .set __irq_dma2_stream1, __default_handler + .weak __irq_dma2_stream2 + .globl __irq_dma2_stream2 + .set __irq_dma2_stream2, __default_handler + .weak __irq_dma2_stream3 + .globl __irq_dma2_stream3 + .set __irq_dma2_stream3, __default_handler + .weak __irq_dma2_stream4 + .globl __irq_dma2_stream4 + .set __irq_dma2_stream4, __default_handler + .weak __irq_eth + .globl __irq_eth + .set __irq_eth, __default_handler + .weak __irq_eth_wkup + .globl __irq_eth_wkup + .set __irq_eth_wkup, __default_handler + .weak __irq_can2_tx + .globl __irq_can2_tx + .set __irq_can2_tx, __default_handler + .weak __irq_can2_rx0 + .globl __irq_can2_rx0 + .set __irq_can2_rx0, __default_handler + .weak __irq_can2_rx1 + .globl __irq_can2_rx1 + .set __irq_can2_rx1, __default_handler + .weak __irq_can2_sce + .globl __irq_can2_sce + .set __irq_can2_sce, __default_handler + .weak __irq_otg_fs + .globl __irq_otg_fs + .set __irq_otg_fs, __default_handler + .weak __irq_dma2_stream5 + .globl __irq_dma2_stream5 + .set __irq_dma2_stream5, __default_handler + .weak __irq_dma2_stream6 + .globl __irq_dma2_stream6 + .set __irq_dma2_stream6, __default_handler + .weak __irq_dma2_stream7 + .globl __irq_dma2_stream7 + .set __irq_dma2_stream7, __default_handler + .weak __irq_usart6 + .globl __irq_usart6 + .set __irq_usart6, __default_handler + .weak __irq_i2c3_ev + .globl __irq_i2c3_ev + .set __irq_i2c3_ev, __default_handler + .weak __irq_i2c3_er + .globl __irq_i2c3_er + .set __irq_i2c3_er, __default_handler + .weak __irq_otg_hs_ep1_out + .globl __irq_otg_hs_ep1_out + .set __irq_otg_hs_ep1_out, __default_handler + .weak __irq_otg_hs_ep1_in + .globl __irq_otg_hs_ep1_in + .set __irq_otg_hs_ep1_in, __default_handler + .weak __irq_otg_hs_wkup + .globl __irq_otg_hs_wkup + .set __irq_otg_hs_wkup, __default_handler + .weak __irq_otg_hs + .globl __irq_otg_hs + .set __irq_otg_hs, __default_handler + .weak __irq_dcmi + .globl __irq_dcmi + .set __irq_dcmi, __default_handler + .weak __irq_cryp + .globl __irq_cryp + .set __irq_cryp, __default_handler + .weak __irq_hash_rng + .globl __irq_hash_rng + .set __irq_hash_rng, __default_handler diff --git a/libmaple/stm32f2/rcc.c b/libmaple/stm32f2/rcc.c new file mode 100644 index 0000000..7fc7eb0 --- /dev/null +++ b/libmaple/stm32f2/rcc.c @@ -0,0 +1,175 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/rcc.c + * @brief STM32F2 RCC. + */ + +#include <libmaple/rcc.h> +#include <libmaple/libmaple.h> + +#include "rcc_private.h" + +#define DEV_ENTRY(domain, dev) \ + {.clk_domain = RCC_##domain, .line_num = RCC_##domain##ENR_##dev##EN_BIT} + +const struct rcc_dev_info rcc_dev_table[] = { + /* AHB1 */ + [RCC_OTGHSULPI] = DEV_ENTRY(AHB1, OTGHSULPI), + [RCC_OTGHS] = DEV_ENTRY(AHB1, OTGHS), + [RCC_ETHMACPTP] = DEV_ENTRY(AHB1, ETHMACPTP), + [RCC_ETHMACRX] = DEV_ENTRY(AHB1, ETHMACRX), + [RCC_ETHMACTX] = DEV_ENTRY(AHB1, ETHMACTX), + [RCC_ETHMAC] = DEV_ENTRY(AHB1, ETHMAC), + [RCC_DMA2] = DEV_ENTRY(AHB1, DMA2), + [RCC_DMA1] = DEV_ENTRY(AHB1, DMA1), + [RCC_BKPSRAM] = DEV_ENTRY(AHB1, BKPSRAM), + [RCC_CRC] = DEV_ENTRY(AHB1, CRC), + [RCC_GPIOI] = DEV_ENTRY(AHB1, GPIOI), + [RCC_GPIOH] = DEV_ENTRY(AHB1, GPIOH), + [RCC_GPIOG] = DEV_ENTRY(AHB1, GPIOG), + [RCC_GPIOF] = DEV_ENTRY(AHB1, GPIOF), + [RCC_GPIOE] = DEV_ENTRY(AHB1, GPIOE), + [RCC_GPIOD] = DEV_ENTRY(AHB1, GPIOD), + [RCC_GPIOC] = DEV_ENTRY(AHB1, GPIOC), + [RCC_GPIOB] = DEV_ENTRY(AHB1, GPIOB), + [RCC_GPIOA] = DEV_ENTRY(AHB1, GPIOA), + + /* AHB2 */ + [RCC_OTGFS] = DEV_ENTRY(AHB2, OTGFS), + [RCC_RNG] = DEV_ENTRY(AHB2, RNG), + [RCC_HASH] = DEV_ENTRY(AHB2, HASH), + [RCC_CRYP] = DEV_ENTRY(AHB2, CRYP), + [RCC_DCMI] = DEV_ENTRY(AHB2, DCMI), + + /* AHB3 */ + [RCC_FSMC] = DEV_ENTRY(AHB3, FSMC), + + /* APB1 */ + [RCC_DAC] = DEV_ENTRY(APB1, DAC), + [RCC_PWR] = DEV_ENTRY(APB1, PWR), + [RCC_CAN2] = DEV_ENTRY(APB1, CAN2), + [RCC_CAN1] = DEV_ENTRY(APB1, CAN1), + [RCC_I2C3] = DEV_ENTRY(APB1, I2C3), + [RCC_I2C2] = DEV_ENTRY(APB1, I2C2), + [RCC_I2C1] = DEV_ENTRY(APB1, I2C1), + [RCC_UART5] = DEV_ENTRY(APB1, UART5), + [RCC_UART4] = DEV_ENTRY(APB1, UART4), + [RCC_USART3] = DEV_ENTRY(APB1, USART3), + [RCC_USART2] = DEV_ENTRY(APB1, USART2), + [RCC_SPI3] = DEV_ENTRY(APB1, SPI3), + [RCC_SPI2] = DEV_ENTRY(APB1, SPI2), + [RCC_WWDG] = DEV_ENTRY(APB1, WWDG), + [RCC_TIMER14] = DEV_ENTRY(APB1, TIM14), + [RCC_TIMER13] = DEV_ENTRY(APB1, TIM13), + [RCC_TIMER12] = DEV_ENTRY(APB1, TIM12), + [RCC_TIMER7] = DEV_ENTRY(APB1, TIM7), + [RCC_TIMER6] = DEV_ENTRY(APB1, TIM6), + [RCC_TIMER5] = DEV_ENTRY(APB1, TIM5), + [RCC_TIMER4] = DEV_ENTRY(APB1, TIM4), + [RCC_TIMER3] = DEV_ENTRY(APB1, TIM3), + [RCC_TIMER2] = DEV_ENTRY(APB1, TIM2), + + /* APB2 */ + [RCC_TIMER11] = DEV_ENTRY(APB2, TIM11), + [RCC_TIMER10] = DEV_ENTRY(APB2, TIM10), + [RCC_TIMER9] = DEV_ENTRY(APB2, TIM9), + [RCC_SYSCFG] = DEV_ENTRY(APB2, SYSCFG), + [RCC_SPI1] = DEV_ENTRY(APB2, SPI1), + [RCC_SDIO] = DEV_ENTRY(APB2, SDIO), + [RCC_ADC3] = DEV_ENTRY(APB2, ADC3), + [RCC_ADC2] = DEV_ENTRY(APB2, ADC2), + [RCC_ADC1] = DEV_ENTRY(APB2, ADC1), + [RCC_USART6] = DEV_ENTRY(APB2, USART6), + [RCC_USART1] = DEV_ENTRY(APB2, USART1), + [RCC_TIMER8] = DEV_ENTRY(APB2, TIM8), + [RCC_TIMER1] = DEV_ENTRY(APB2, TIM1), +}; + +void rcc_clk_enable(rcc_clk_id id) { + static __io uint32* enable_regs[] = { + [RCC_AHB1] = &RCC_BASE->AHB1ENR, + [RCC_AHB2] = &RCC_BASE->AHB2ENR, + [RCC_AHB3] = &RCC_BASE->AHB3ENR, + [RCC_APB1] = &RCC_BASE->APB1ENR, + [RCC_APB2] = &RCC_BASE->APB2ENR, + }; + rcc_do_clk_enable(enable_regs, id); +} + +void rcc_reset_dev(rcc_clk_id id) { + static __io uint32* reset_regs[] = { + [RCC_AHB1] = &RCC_BASE->AHB1RSTR, + [RCC_AHB2] = &RCC_BASE->AHB2RSTR, + [RCC_AHB3] = &RCC_BASE->AHB3RSTR, + [RCC_APB1] = &RCC_BASE->AHB3RSTR, + [RCC_APB2] = &RCC_BASE->AHB3RSTR, + }; + rcc_do_reset_dev(reset_regs, id); +} + +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { + static const uint32 masks[] = { + [RCC_PRESCALER_MCO2] = RCC_CFGR_MCO2PRE, + [RCC_PRESCALER_MCO1] = RCC_CFGR_MCO1PRE, + [RCC_PRESCALER_RTC] = RCC_CFGR_RTCPRE, + [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, + [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, + [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, + }; + rcc_do_set_prescaler(masks, prescaler, divider); +} + +/* pll_cfg->data must point to a struct stm32f2_rcc_pll_data. */ +void rcc_configure_pll(rcc_pll_cfg *pll_cfg) { + stm32f2_rcc_pll_data *data = pll_cfg->data; + uint32 pllcfgr; + + /* Check that the PLL is disabled. */ + ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL)); + + /* Sanity-check all the parameters */ + ASSERT_FAULT((data->pllq >= 4) && (data->pllq <= 15)); + ASSERT_FAULT((data->pllp >= 2) && (data->pllp <= 8)); + ASSERT_FAULT(!(data->pllp & 1)); + ASSERT_FAULT((data->plln >= 192) && (data->plln <= 432)); + ASSERT_FAULT((data->pllm >= 2) && (data->pllm <= 63)); + + /* Update RCC_PLLCFGR to reflect new values. */ + pllcfgr = RCC_BASE->PLLCFGR; + pllcfgr &= ~(RCC_PLLCFGR_PLLQ | + RCC_PLLCFGR_PLLP | + RCC_PLLCFGR_PLLN | + RCC_PLLCFGR_PLLM | + RCC_PLLCFGR_PLLSRC); + pllcfgr |= (pll_cfg->pllsrc | + (data->pllq << 24) | + (((data->pllp >> 1) - 1) << 16) | + (data->plln << 6) | + data->pllm); + RCC_BASE->PLLCFGR = pllcfgr; +} diff --git a/libmaple/stm32f2/rules.mk b/libmaple/stm32f2/rules.mk new file mode 100644 index 0000000..4c62cc2 --- /dev/null +++ b/libmaple/stm32f2/rules.mk @@ -0,0 +1,40 @@ +# Standard things +sp := $(sp).x +dirstack_$(sp) := $(d) +d := $(dir) +BUILDDIRS += $(BUILD_PATH)/$(d) + +# Local flags +CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) $(LIBMAPLE_PRIVATE_INCLUDES) -Wall -Werror + +# Local rules and targets +sSRCS_$(d) := isrs.S +sSRCS_$(d) += vector_table.S + +cSRCS_$(d) := adc.c +cSRCS_$(d) += dma.c +cSRCS_$(d) += exti.c +cSRCS_$(d) += fsmc.c +cSRCS_$(d) += gpio.c +cSRCS_$(d) += rcc.c +cSRCS_$(d) += spi.c +cSRCS_$(d) += syscfg.c +cSRCS_$(d) += timer.c +cSRCS_$(d) += usart.c + +sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%) +cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) + +OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \ + $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) +DEPS_$(d) := $(OBJS_$(d):%.o=%.d) + +$(OBJS_$(d)): TGT_ASFLAGS := +$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d)) + +TGT_BIN += $(OBJS_$(d)) + +# Standard things +-include $(DEPS_$(d)) +d := $(dirstack_$(sp)) +sp := $(basename $(sp)) diff --git a/libmaple/stm32f2/spi.c b/libmaple/stm32f2/spi.c new file mode 100644 index 0000000..cfd9995 --- /dev/null +++ b/libmaple/stm32f2/spi.c @@ -0,0 +1,88 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/spi.c + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 SPI/I2S. + */ + +#include <libmaple/spi.h> +#include "spi_private.h" + +/* + * Devices + */ + +static spi_dev spi1 = SPI_DEV(1); +static spi_dev spi2 = SPI_DEV(2); +static spi_dev spi3 = SPI_DEV(3); + +spi_dev *SPI1 = &spi1; +spi_dev *SPI2 = &spi2; +spi_dev *SPI3 = &spi3; + +/* + * Routines + */ + +void spi_config_gpios(spi_dev *dev, + uint8 as_master, + gpio_dev *nss_dev, + uint8 nss_bit, + gpio_dev *comm_dev, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit) { + gpio_af dev_af = spi_get_af(dev); + gpio_set_mode(nss_dev, nss_bit, GPIO_MODE_AF); + gpio_set_mode(comm_dev, sck_bit, GPIO_MODE_AF); + gpio_set_mode(comm_dev, miso_bit, GPIO_MODE_AF); + gpio_set_mode(comm_dev, mosi_bit, GPIO_MODE_AF); + gpio_set_af(nss_dev, nss_bit, dev_af); + gpio_set_af(comm_dev, sck_bit, dev_af); + gpio_set_af(comm_dev, miso_bit, dev_af); + gpio_set_af(comm_dev, mosi_bit, dev_af); +} + +void spi_foreach(void (*fn)(spi_dev*)) { + fn(SPI1); + fn(SPI2); + fn(SPI3); +} + +gpio_af spi_get_af(spi_dev *dev) { + switch (dev->clk_id) { + case RCC_SPI1: /* Fall through */ + case RCC_SPI2: + return GPIO_AF_SPI_1_2; + case RCC_SPI3: + return GPIO_AF_SPI3; + default: + ASSERT(0); /* Can't happen */ + return (gpio_af)-1; + } +} diff --git a/libmaple/stm32f2/syscfg.c b/libmaple/stm32f2/syscfg.c new file mode 100644 index 0000000..19e932e --- /dev/null +++ b/libmaple/stm32f2/syscfg.c @@ -0,0 +1,78 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/syscfg.c + * @brief SYSCFG routines. + */ + +#include <libmaple/syscfg.h> +#include <libmaple/bitband.h> +#include <libmaple/rcc.h> + +/** + * @brief Initialize the SYSCFG peripheral. + */ +void syscfg_init(void) { + rcc_clk_enable(RCC_SYSCFG); + rcc_reset_dev(RCC_SYSCFG); +} + +/** + * @brief Turn on the I/O compensation cell. + * + * It's only safe to do this when the supply voltage is between 2.4 V + * and 3.6 V. + */ +void syscfg_enable_io_compensation(void) { + bb_peri_set_bit(&SYSCFG_BASE->CMPCR, SYSCFG_CMPCR_CMP_PD_BIT, 1); + while (!(SYSCFG_BASE->CMPCR & SYSCFG_CMPCR_READY)) + ; +} + +/** + * @brief Turn off the I/O compensation cell. + */ +void syscfg_disable_io_compensation(void) { + bb_peri_set_bit(&SYSCFG_BASE->CMPCR, SYSCFG_CMPCR_CMP_PD_BIT, 0); +} + +/** + * @brief Set the memory to be mapped at address 0x00000000. + * + * This function can be used to override the BOOT pin + * configuration. Some restrictions apply; see your chip's reference + * manual for the details. + * + * @param mode Mode to set + * @see syscfg_mem_mode + */ +void syscfg_set_mem_mode(syscfg_mem_mode mode) { + uint32 memrmp = SYSCFG_BASE->MEMRMP; + memrmp &= ~SYSCFG_MEMRMP_MEM_MODE; + memrmp |= (uint32)mode; + SYSCFG_BASE->MEMRMP = memrmp; +} diff --git a/libmaple/stm32f2/timer.c b/libmaple/stm32f2/timer.c new file mode 100644 index 0000000..a85bea0 --- /dev/null +++ b/libmaple/stm32f2/timer.c @@ -0,0 +1,148 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/timer.c + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 timers. + */ + +#include <libmaple/timer.h> +#include "timer_private.h" + +/* + * Routines + */ + +/** + * @brief Get the GPIO alternate function corresponding to a timer. + * + * For example, if dev is TIMER1, this function returns + * GPIO_AF_TIM_1_2. This is useful for e.g. using gpio_set_af() to set + * a pin's alternate function to a timer. + * + * @param dev Timer device, must not be TIMER6 or TIMER7. + * @return gpio_af corresponding to dev + * @see gpio_set_af + * @see gpio_af + */ +gpio_af timer_get_af(timer_dev *dev) { + rcc_clk_id clk_id = dev->clk_id; + /* Timers 6 and 7 don't have any capture/compare, so they can't do + * PWM (and in fact have no AF values). */ + ASSERT(clk_id != RCC_TIMER6 && clk_id != RCC_TIMER7); + switch(dev->clk_id) { + case RCC_TIMER1: // fall-through + case RCC_TIMER2: + return GPIO_AF_TIM_1_2; + case RCC_TIMER3: // fall-through + case RCC_TIMER4: // ... + case RCC_TIMER5: + return GPIO_AF_TIM_3_4_5; + case RCC_TIMER8: // fall-through + case RCC_TIMER9: // ... + case RCC_TIMER10: // ... + case RCC_TIMER11: + return GPIO_AF_TIM_8_9_10_11; + case RCC_TIMER12: // fall-through + case RCC_TIMER13: // ... + case RCC_TIMER14: + return GPIO_AF_CAN_1_2_TIM_12_13_14; + default: + ASSERT(0); // Can't happen + return (gpio_af)-1; + } +} + +/* + * IRQ handlers + * + * Defer to the timer_private dispatch API. + */ + +void __irq_tim1_brk_tim9(void) { + dispatch_adv_brk(TIMER1); + dispatch_tim_9_12(TIMER9); +} + +void __irq_tim1_up_tim10(void) { + dispatch_adv_up(TIMER1); + dispatch_tim_10_11_13_14(TIMER10); +} + +void __irq_tim1_trg_com_tim11(void) { + dispatch_adv_trg_com(TIMER1); + dispatch_tim_10_11_13_14(TIMER11); +} + +void __irq_tim1_cc(void) { + dispatch_adv_cc(TIMER1); +} + +void __irq_tim2(void) { + dispatch_general(TIMER2); +} + +void __irq_tim3(void) { + dispatch_general(TIMER3); +} + +void __irq_tim4(void) { + dispatch_general(TIMER4); +} + +void __irq_tim5(void) { + dispatch_general(TIMER5); +} + +/* FIXME: this is also the DAC DMA underrun interrupt, so it needs a + * different name (and to be supported?). */ +void __irq_tim6(void) { + dispatch_basic(TIMER6); +} + +void __irq_tim7(void) { + dispatch_basic(TIMER7); +} + +void __irq_tim8_brk_tim12(void) { + dispatch_adv_brk(TIMER8); + dispatch_tim_9_12(TIMER12); +} + +void __irq_tim8_up_tim13(void) { + dispatch_adv_up(TIMER8); + dispatch_tim_10_11_13_14(TIMER13); +} + +void __irq_tim8_trg_com_tim14(void) { + dispatch_adv_trg_com(TIMER8); + dispatch_tim_10_11_13_14(TIMER14); +} + +void __irq_tim8_cc(void) { + dispatch_adv_cc(TIMER8); +} diff --git a/libmaple/stm32f2/usart.c b/libmaple/stm32f2/usart.c new file mode 100644 index 0000000..1472d13 --- /dev/null +++ b/libmaple/stm32f2/usart.c @@ -0,0 +1,204 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f2/usart.c + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief STM32F2 USART. + */ + +#include <libmaple/usart.h> +#include <libmaple/gpio.h> +#include "usart_private.h" + +/* + * Devices + */ + +static ring_buffer usart1_rb; +static usart_dev usart1 = { + .regs = USART1_BASE, + .rb = &usart1_rb, + .max_baud = 4500000UL, /* TODO: are these correct? */ + .clk_id = RCC_USART1, + .irq_num = NVIC_USART1, +}; +/** USART1 device */ +usart_dev *USART1 = &usart1; + +static ring_buffer usart2_rb; +static usart_dev usart2 = { + .regs = USART2_BASE, + .rb = &usart2_rb, + .max_baud = 2250000UL, /* TODO: are these correct? */ + .clk_id = RCC_USART2, + .irq_num = NVIC_USART2, +}; +/** USART2 device */ +usart_dev *USART2 = &usart2; + +static ring_buffer usart3_rb; +static usart_dev usart3 = { + .regs = USART3_BASE, + .rb = &usart3_rb, + .max_baud = 2250000UL, /* TODO: are these correct? */ + .clk_id = RCC_USART3, + .irq_num = NVIC_USART3, +}; +/** USART3 device */ +usart_dev *USART3 = &usart3; + +static ring_buffer uart4_rb; +static usart_dev uart4 = { + .regs = UART4_BASE, + .rb = &uart4_rb, + .max_baud = 2250000UL, /* TODO: are these correct? */ + .clk_id = RCC_UART4, + .irq_num = NVIC_UART4, +}; +/** UART4 device */ +usart_dev *UART4 = &uart4; + +static ring_buffer uart5_rb; +static usart_dev uart5 = { + .regs = UART5_BASE, + .rb = &uart5_rb, + .max_baud = 2250000UL, /* TODO: are these correct? */ + .clk_id = RCC_UART5, + .irq_num = NVIC_UART5, +}; +/** UART5 device */ +usart_dev *UART5 = &uart5; + +static ring_buffer usart6_rb; +static usart_dev usart6 = { + .regs = USART6_BASE, + .rb = &usart6_rb, + .max_baud = 4500000UL, /* TODO: are these correct? */ + .clk_id = RCC_USART6, + .irq_num = NVIC_USART6, +}; +usart_dev *USART6 = &usart6; + +/* + * Routines + */ + +void usart_config_gpios_async(usart_dev *udev, + gpio_dev *rx_dev, uint8 rx, + gpio_dev *tx_dev, uint8 tx, + unsigned flags) { + gpio_af af = usart_get_af(udev); + gpio_set_modef(rx_dev, rx, GPIO_MODE_AF, 0); + gpio_set_modef(tx_dev, tx, GPIO_MODE_AF, 0); + gpio_set_af(rx_dev, rx, af); + gpio_set_af(tx_dev, tx, af); +} + +void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) { + uint32 integer_part; + uint32 fractional_part; + uint32 tmp; + uint32 over8 = !!(dev->regs->CR1 & USART_CR1_OVER8); + + ASSERT(!over8); /* OVER8 is currently unsupported. */ + + /* Figure out the clock speed, if the user doesn't give one. */ + if (clock_speed == 0) { + clock_speed = _usart_clock_freq(dev); + } + ASSERT(clock_speed); + + /* Convert desired baud rate to baud rate register setting. */ + integer_part = (25 * clock_speed) / (2 * (2 - over8) * baud); + tmp = (integer_part / 100) << 4; + fractional_part = integer_part - (100 * (tmp >> 4)); + tmp |= ((fractional_part * 16 + 50) / 100) & (uint8)0x0F; + + dev->regs->BRR = tmp; +} + +/** + * @brief Call a function on each USART. + * @param fn Function to call. + */ +void usart_foreach(void (*fn)(usart_dev*)) { + fn(USART1); + fn(USART2); + fn(USART3); + fn(UART4); + fn(UART5); + fn(USART6); +} + +/** + * @brief Get GPIO alternate function mode for a USART. + * @param dev USART whose gpio_af to get. + * @return gpio_af corresponding to dev. + */ +gpio_af usart_get_af(usart_dev *dev) { + switch (dev->clk_id) { + case RCC_USART1: + case RCC_USART2: + case RCC_USART3: + return GPIO_AF_USART_1_2_3; + case RCC_UART4: + case RCC_UART5: + case RCC_USART6: + return GPIO_AF_USART_4_5_6; + default: + ASSERT(0); /* Can't happen */ + return (gpio_af)-1; + } +} + +/* + * Interrupt handlers. + */ + +void __irq_usart1(void) { + usart_irq(&usart1_rb, USART1_BASE); +} + +void __irq_usart2(void) { + usart_irq(&usart2_rb, USART2_BASE); +} + +void __irq_usart3(void) { + usart_irq(&usart3_rb, USART3_BASE); +} + +void __irq_uart4(void) { + usart_irq(&uart4_rb, UART4_BASE); +} + +void __irq_uart5(void) { + usart_irq(&uart5_rb, UART5_BASE); +} + +void __irq_usart6(void) { + usart_irq(&usart6_rb, USART6_BASE); +} diff --git a/libmaple/stm32f2/vector_table.S b/libmaple/stm32f2/vector_table.S new file mode 100644 index 0000000..147e516 --- /dev/null +++ b/libmaple/stm32f2/vector_table.S @@ -0,0 +1,135 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/* STM32F2 vector table */ + + .section ".stm32.interrupt_vector" + + .globl __stm32_vector_table + .type __stm32_vector_table, %object + +__stm32_vector_table: +/* CM3 core interrupts */ + .long __msp_init + .long __exc_reset + .long __exc_nmi + .long __exc_hardfault + .long __exc_memmanage + .long __exc_busfault + .long __exc_usagefault + .long __stm32reservedexception7 + .long __stm32reservedexception8 + .long __stm32reservedexception9 + .long __stm32reservedexception10 + .long __exc_svc + .long __exc_debug_monitor + .long __stm32reservedexception13 + .long __exc_pendsv + .long __exc_systick +/* Peripheral interrupts */ + .long __irq_wwdg + .long __irq_pvd + .long __irq_tamp_stamp + .long __irq_rtc_wkup + .long __irq_flash + .long __irq_rcc + .long __irq_exti0 + .long __irq_exti1 + .long __irq_exti2 + .long __irq_exti3 + .long __irq_exti4 + .long __irq_dma1_stream0 + .long __irq_dma1_stream1 + .long __irq_dma1_stream2 + .long __irq_dma1_stream3 + .long __irq_dma1_stream4 + .long __irq_dma1_stream5 + .long __irq_dma1_stream6 + .long __irq_adc + .long __irq_can1_tx + .long __irq_can1_rx0 + .long __irq_can1_rx1 + .long __irq_can1_sce + .long __irq_exti9_5 + .long __irq_tim1_brk_tim9 + .long __irq_tim1_up_tim10 + .long __irq_tim1_trg_com_tim11 + .long __irq_tim1_cc + .long __irq_tim2 + .long __irq_tim3 + .long __irq_tim4 + .long __irq_i2c1_ev + .long __irq_i2c1_er + .long __irq_i2c2_ev + .long __irq_i2c2_er + .long __irq_spi1 + .long __irq_spi2 + .long __irq_usart1 + .long __irq_usart2 + .long __irq_usart3 + .long __irq_exti15_10 + .long __irq_rtc_alarm + .long __irq_otg_fs_wkup + .long __irq_tim8_brk_tim12 + .long __irq_tim8_up_tim13 + .long __irq_tim8_trg_com_tim14 + .long __irq_tim8_cc + .long __irq_dma1_stream7 + .long __irq_fsmc + .long __irq_sdio + .long __irq_tim5 + .long __irq_spi3 + .long __irq_uart4 + .long __irq_uart5 + .long __irq_tim6_dac + .long __irq_tim7 + .long __irq_dma2_stream0 + .long __irq_dma2_stream1 + .long __irq_dma2_stream2 + .long __irq_dma2_stream3 + .long __irq_dma2_stream4 + .long __irq_eth + .long __irq_eth_wkup + .long __irq_can2_tx + .long __irq_can2_rx0 + .long __irq_can2_rx1 + .long __irq_can2_sce + .long __irq_otg_fs + .long __irq_dma2_stream5 + .long __irq_dma2_stream6 + .long __irq_dma2_stream7 + .long __irq_usart6 + .long __irq_i2c3_ev + .long __irq_i2c3_er + .long __irq_otg_hs_ep1_out + .long __irq_otg_hs_ep1_in + .long __irq_otg_hs_wkup + .long __irq_otg_hs + .long __irq_dcmi + .long __irq_cryp + .long __irq_hash_rng + + .size __stm32_vector_table, . - __stm32_vector_table diff --git a/libmaple/syscalls.c b/libmaple/syscalls.c deleted file mode 100644 index 8a57945..0000000 --- a/libmaple/syscalls.c +++ /dev/null @@ -1,167 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -/** - * @file syscalls.c - * @brief Low level system routines used by Newlib for basic I/O and - * memory allocation. - */ - -#include "libmaple.h" - -#include <sys/stat.h> -#include <errno.h> - -/* If CONFIG_HEAP_START (or CONFIG_HEAP_END) isn't defined, then - * assume _lm_heap_start (resp. _lm_heap_end) is appropriately set by - * the linker */ -#ifndef CONFIG_HEAP_START -extern char _lm_heap_start; -#define CONFIG_HEAP_START ((caddr_t)&_lm_heap_start) -#endif -#ifndef CONFIG_HEAP_END -extern char _lm_heap_end; -#define CONFIG_HEAP_END ((caddr_t)&_lm_heap_end) -#endif - -/* - * _sbrk -- Increment the program break. - * - * Get incr bytes more RAM (for use by the heap). malloc() and - * friends call this function behind the scenes. - */ -caddr_t _sbrk(int incr) { - static caddr_t pbreak = NULL; /* current program break */ - caddr_t ret; - - if (pbreak == NULL) { - pbreak = CONFIG_HEAP_START; - } - - if ((CONFIG_HEAP_END - pbreak < incr) || - (pbreak - CONFIG_HEAP_START < -incr)) { - errno = ENOMEM; - return (caddr_t)-1; - } - - ret = pbreak; - pbreak += incr; - return ret; -} - -int _open(const char *path, int flags, ...) { - return 1; -} - -int _close(int fd) { - return 0; -} - -int _fstat(int fd, struct stat *st) { - st->st_mode = S_IFCHR; - return 0; -} - -int _isatty(int fd) { - return 1; -} - -int isatty(int fd) { - return 1; -} - -int _lseek(int fd, off_t pos, int whence) { - return -1; -} - -unsigned char getch(void) { - return 0; -} - - -int _read(int fd, char *buf, size_t cnt) { - *buf = getch(); - - return 1; -} - -void putch(unsigned char c) { -} - -void cgets(char *s, int bufsize) { - char *p; - int c; - int i; - - for (i = 0; i < bufsize; i++) { - *(s+i) = 0; - } -// memset(s, 0, bufsize); - - p = s; - - for (p = s; p < s + bufsize-1;) { - c = getch(); - switch (c) { - case '\r' : - case '\n' : - putch('\r'); - putch('\n'); - *p = '\n'; - return; - - case '\b' : - if (p > s) { - *p-- = 0; - putch('\b'); - putch(' '); - putch('\b'); - } - break; - - default : - putch(c); - *p++ = c; - break; - } - } - return; -} - -int _write(int fd, const char *buf, size_t cnt) { - int i; - - for (i = 0; i < cnt; i++) - putch(buf[i]); - - return cnt; -} - -/* Override fgets() in newlib with a version that does line editing */ -char *fgets(char *s, int bufsize, void *f) { - cgets(s, bufsize); - return s; -} diff --git a/libmaple/systick.c b/libmaple/systick.c index 9bb5d50..80c0c47 100644 --- a/libmaple/systick.c +++ b/libmaple/systick.c @@ -25,11 +25,11 @@ *****************************************************************************/ /** - * @file systick.c - * @brief System timer interrupt handler and initialization routines + * @file libmaple/systick.c + * @brief System timer (SysTick). */ -#include "systick.h" +#include <libmaple/systick.h> volatile uint32 systick_uptime_millis; static void (*systick_user_callback)(void); diff --git a/libmaple/timer.c b/libmaple/timer.c index 83e9ace..24ae7fa 100644 --- a/libmaple/timer.c +++ b/libmaple/timer.c @@ -25,108 +25,150 @@ *****************************************************************************/ /** - * @file timer.c + * @file libmaple/timer.c * @author Marti Bolivar <mbolivar@leaflabs.com> - * @brief New-style timer interface + * @brief Portable timer routines. */ -#include "timer.h" +#include <libmaple/timer.h> +#include <libmaple/stm32.h> +#include "timer_private.h" -/* Just like the corresponding DIER bits: - * [0] = Update handler; - * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively; - * [5] = COM; - * [6] = TRG; - * [7] = BRK. */ -#define NR_ADV_HANDLERS 8 -/* Update, capture/compare 1,2,3,4; <junk>; trigger. */ -#define NR_GEN_HANDLERS 7 -/* Update only. */ -#define NR_BAS_HANDLERS 1 +static void disable_channel(timer_dev *dev, uint8 channel); +static void pwm_mode(timer_dev *dev, uint8 channel); +static void output_compare_mode(timer_dev *dev, uint8 channel); + +static inline void enable_irq(timer_dev *dev, uint8 interrupt); -static timer_dev timer1 = { - .regs = { .adv = TIMER1_BASE }, - .clk_id = RCC_TIMER1, - .type = TIMER_ADVANCED, - .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, -}; +/* + * Devices + * + * Defer to the timer_private API for declaring these. + */ + +#if STM32_HAVE_TIMER(1) +static timer_dev timer1 = ADVANCED_TIMER(1); /** Timer 1 device (advanced) */ timer_dev *TIMER1 = &timer1; - -static timer_dev timer2 = { - .regs = { .gen = TIMER2_BASE }, - .clk_id = RCC_TIMER2, - .type = TIMER_GENERAL, - .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, -}; +#endif +#if STM32_HAVE_TIMER(2) +static timer_dev timer2 = GENERAL_TIMER(2); /** Timer 2 device (general-purpose) */ timer_dev *TIMER2 = &timer2; - -static timer_dev timer3 = { - .regs = { .gen = TIMER3_BASE }, - .clk_id = RCC_TIMER3, - .type = TIMER_GENERAL, - .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, -}; +#endif +#if STM32_HAVE_TIMER(3) +static timer_dev timer3 = GENERAL_TIMER(3); /** Timer 3 device (general-purpose) */ timer_dev *TIMER3 = &timer3; - -static timer_dev timer4 = { - .regs = { .gen = TIMER4_BASE }, - .clk_id = RCC_TIMER4, - .type = TIMER_GENERAL, - .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, -}; +#endif +#if STM32_HAVE_TIMER(4) +static timer_dev timer4 = GENERAL_TIMER(4); /** Timer 4 device (general-purpose) */ timer_dev *TIMER4 = &timer4; - -#ifdef STM32_HIGH_DENSITY -static timer_dev timer5 = { - .regs = { .gen = TIMER5_BASE }, - .clk_id = RCC_TIMER5, - .type = TIMER_GENERAL, - .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, -}; +#endif +#if STM32_HAVE_TIMER(5) +static timer_dev timer5 = GENERAL_TIMER(5); /** Timer 5 device (general-purpose) */ timer_dev *TIMER5 = &timer5; - -static timer_dev timer6 = { - .regs = { .bas = TIMER6_BASE }, - .clk_id = RCC_TIMER6, - .type = TIMER_BASIC, - .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, -}; +#endif +#if STM32_HAVE_TIMER(6) +static timer_dev timer6 = BASIC_TIMER(6); /** Timer 6 device (basic) */ timer_dev *TIMER6 = &timer6; - -static timer_dev timer7 = { - .regs = { .bas = TIMER7_BASE }, - .clk_id = RCC_TIMER7, - .type = TIMER_BASIC, - .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, -}; +#endif +#if STM32_HAVE_TIMER(7) +static timer_dev timer7 = BASIC_TIMER(7); /** Timer 7 device (basic) */ timer_dev *TIMER7 = &timer7; - -static timer_dev timer8 = { - .regs = { .adv = TIMER8_BASE }, - .clk_id = RCC_TIMER8, - .type = TIMER_ADVANCED, - .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, -}; +#endif +#if STM32_HAVE_TIMER(8) +static timer_dev timer8 = ADVANCED_TIMER(8); /** Timer 8 device (advanced) */ timer_dev *TIMER8 = &timer8; #endif +#if STM32_HAVE_TIMER(9) +static timer_dev timer9 = RESTRICTED_GENERAL_TIMER(9, TIMER_DIER_TIE_BIT); +/** Timer 9 device (general-purpose) */ +timer_dev *TIMER9 = &timer9; +#endif +#if STM32_HAVE_TIMER(10) +static timer_dev timer10 = RESTRICTED_GENERAL_TIMER(10, TIMER_DIER_CC1IE_BIT); +/** Timer 10 device (general-purpose) */ +timer_dev *TIMER10 = &timer10; +#endif +#if STM32_HAVE_TIMER(11) +static timer_dev timer11 = RESTRICTED_GENERAL_TIMER(11, TIMER_DIER_CC1IE_BIT); +/** Timer 11 device (general-purpose) */ +timer_dev *TIMER11 = &timer11; +#endif +#if STM32_HAVE_TIMER(12) +static timer_dev timer12 = RESTRICTED_GENERAL_TIMER(12, TIMER_DIER_TIE_BIT); +/** Timer 12 device (general-purpose) */ +timer_dev *TIMER12 = &timer12; +#endif +#if STM32_HAVE_TIMER(13) +static timer_dev timer13 = RESTRICTED_GENERAL_TIMER(13, TIMER_DIER_CC1IE_BIT); +/** Timer 13 device (general-purpose) */ +timer_dev *TIMER13 = &timer13; +#endif +#if STM32_HAVE_TIMER(14) +static timer_dev timer14 = RESTRICTED_GENERAL_TIMER(14, TIMER_DIER_CC1IE_BIT); +/** Timer 14 device (general-purpose) */ +timer_dev *TIMER14 = &timer14; +#endif /* - * Convenience routines + * Routines */ -static void disable_channel(timer_dev *dev, uint8 channel); -static void pwm_mode(timer_dev *dev, uint8 channel); -static void output_compare_mode(timer_dev *dev, uint8 channel); - -static inline void enable_irq(timer_dev *dev, uint8 interrupt); +/** + * @brief Call a function on timer devices. + * @param fn Function to call on each timer device. + */ +void timer_foreach(void (*fn)(timer_dev*)) { +#if STM32_HAVE_TIMER(1) + fn(TIMER1); +#endif +#if STM32_HAVE_TIMER(2) + fn(TIMER2); +#endif +#if STM32_HAVE_TIMER(3) + fn(TIMER3); +#endif +#if STM32_HAVE_TIMER(4) + fn(TIMER4); +#endif +#if STM32_HAVE_TIMER(5) + fn(TIMER5); +#endif +#if STM32_HAVE_TIMER(6) + fn(TIMER6); +#endif +#if STM32_HAVE_TIMER(7) + fn(TIMER7); +#endif +#if STM32_HAVE_TIMER(8) + fn(TIMER8); +#endif +#if STM32_HAVE_TIMER(9) + fn(TIMER9); +#endif +#if STM32_HAVE_TIMER(10) + fn(TIMER10); +#endif +#if STM32_HAVE_TIMER(11) + fn(TIMER11); +#endif +#if STM32_HAVE_TIMER(12) + fn(TIMER12); +#endif +#if STM32_HAVE_TIMER(13) + fn(TIMER13); +#endif +#if STM32_HAVE_TIMER(14) + fn(TIMER14); +#endif +} /** * Initialize a timer, and reset its register map. @@ -191,20 +233,31 @@ void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) { } /** - * @brief Call a function on timer devices. - * @param fn Function to call on each timer device. + * @brief Determine whether a timer has a particular capture/compare channel. + * + * Different timers have different numbers of capture/compare channels + * (and some have none at all). Use this function to test whether a + * given timer/channel combination will work. + * + * @param dev Timer device + * @param channel Capture/compare channel, from 1 to 4 + * @return Nonzero if dev has channel, zero otherwise. */ -void timer_foreach(void (*fn)(timer_dev*)) { - fn(TIMER1); - fn(TIMER2); - fn(TIMER3); - fn(TIMER4); -#ifdef STM32_HIGH_DENSITY - fn(TIMER5); - fn(TIMER6); - fn(TIMER7); - fn(TIMER8); -#endif +int timer_has_cc_channel(timer_dev *dev, uint8 channel) { + /* On all currently supported series: advanced and "full-featured" + * general purpose timers have all four channels. Of the + * restricted general timers, timers 9 and 12 have channels 1 and + * 2; the others have channel 1 only. Basic timers have none. */ + rcc_clk_id id = dev->clk_id; + ASSERT((1 <= channel) && (channel <= 4)); + if (id <= RCC_TIMER5 || id == RCC_TIMER8) { + return 1; /* 1 and 8 are advanced, 2-5 are "full" general */ + } else if (id <= RCC_TIMER7) { + return 0; /* 6 and 7 are basic */ + } + /* The rest are restricted general. */ + return (((id == RCC_TIMER9 || id == RCC_TIMER12) && channel <= 2) || + channel == 1); } /** @@ -240,164 +293,6 @@ void timer_detach_interrupt(timer_dev *dev, uint8 interrupt) { } /* - * IRQ handlers - */ - -static inline void dispatch_adv_brk(timer_dev *dev); -static inline void dispatch_adv_up(timer_dev *dev); -static inline void dispatch_adv_trg_com(timer_dev *dev); -static inline void dispatch_adv_cc(timer_dev *dev); -static inline void dispatch_general(timer_dev *dev); -static inline void dispatch_basic(timer_dev *dev); - -void __irq_tim1_brk(void) { - dispatch_adv_brk(TIMER1); -} - -void __irq_tim1_up(void) { - dispatch_adv_up(TIMER1); -} - -void __irq_tim1_trg_com(void) { - dispatch_adv_trg_com(TIMER1); -} - -void __irq_tim1_cc(void) { - dispatch_adv_cc(TIMER1); -} - -void __irq_tim2(void) { - dispatch_general(TIMER2); -} - -void __irq_tim3(void) { - dispatch_general(TIMER3); -} - -void __irq_tim4(void) { - dispatch_general(TIMER4); -} - -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - -void __irq_tim5(void) { - dispatch_general(TIMER5); -} - -void __irq_tim6(void) { - dispatch_basic(TIMER6); -} - -void __irq_tim7(void) { - dispatch_basic(TIMER7); -} - -void __irq_tim8_brk(void) { - dispatch_adv_brk(TIMER8); -} - -void __irq_tim8_up(void) { - dispatch_adv_up(TIMER8); -} - -void __irq_tim8_trg_com(void) { - dispatch_adv_trg_com(TIMER8); -} - -void __irq_tim8_cc(void) { - dispatch_adv_cc(TIMER8); -} -#endif - -/* Note: the following dispatch routines make use of the fact that - * DIER interrupt enable bits and SR interrupt flags have common bit - * positions. Thus, ANDing DIER and SR lets us check if an interrupt - * is enabled and if it has occurred simultaneously. - */ - -/* A special-case dispatch routine for single-interrupt NVIC lines. - * This function assumes that the interrupt corresponding to `iid' has - * in fact occurred (i.e., it doesn't check DIER & SR). */ -static inline void dispatch_single_irq(timer_dev *dev, - timer_interrupt_id iid, - uint32 irq_mask) { - timer_bas_reg_map *regs = (dev->regs).bas; - void (*handler)(void) = dev->handlers[iid]; - if (handler) { - handler(); - regs->SR &= ~irq_mask; - } -} - -/* For dispatch routines which service multiple interrupts. */ -#define handle_irq(dier_sr, irq_mask, handlers, iid, handled_irq) do { \ - if ((dier_sr) & (irq_mask)) { \ - void (*__handler)(void) = (handlers)[iid]; \ - if (__handler) { \ - __handler(); \ - handled_irq |= (irq_mask); \ - } \ - } \ - } while (0) - -static inline void dispatch_adv_brk(timer_dev *dev) { - dispatch_single_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF); -} - -static inline void dispatch_adv_up(timer_dev *dev) { - dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF); -} - -static inline void dispatch_adv_trg_com(timer_dev *dev) { - timer_adv_reg_map *regs = (dev->regs).adv; - uint32 dsr = regs->DIER & regs->SR; - void (**hs)(void) = dev->handlers; - uint32 handled = 0; /* Logical OR of SR interrupt flags we end up - * handling. We clear these. User handlers - * must clear overcapture flags, to avoid - * wasting time in output mode. */ - - handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_COMIF, hs, TIMER_COM_INTERRUPT, handled); - - regs->SR &= ~handled; -} - -static inline void dispatch_adv_cc(timer_dev *dev) { - timer_adv_reg_map *regs = (dev->regs).adv; - uint32 dsr = regs->DIER & regs->SR; - void (**hs)(void) = dev->handlers; - uint32 handled = 0; - - handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); - - regs->SR &= ~handled; -} - -static inline void dispatch_general(timer_dev *dev) { - timer_gen_reg_map *regs = (dev->regs).gen; - uint32 dsr = regs->DIER & regs->SR; - void (**hs)(void) = dev->handlers; - uint32 handled = 0; - - handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); - handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled); - - regs->SR &= ~handled; -} - -static inline void dispatch_basic(timer_dev *dev) { - dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF); -} - -/* * Utilities */ @@ -417,64 +312,101 @@ static void output_compare_mode(timer_dev *dev, uint8 channel) { timer_cc_enable(dev, channel); } -static void enable_advanced_irq(timer_dev *dev, timer_interrupt_id id); -static void enable_nonmuxed_irq(timer_dev *dev); +static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id); +static void enable_bas_gen_irq(timer_dev *dev); static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid) { if (dev->type == TIMER_ADVANCED) { - enable_advanced_irq(dev, iid); + enable_adv_irq(dev, iid); } else { - enable_nonmuxed_irq(dev); + enable_bas_gen_irq(dev); } } -static void enable_advanced_irq(timer_dev *dev, timer_interrupt_id id) { - uint8 is_timer1 = dev->clk_id == RCC_TIMER1; - +/* Advanced control timers have several IRQ lines corresponding to + * different timer interrupts. + * + * Note: This function assumes that the only advanced timers are TIM1 + * and TIM8, and needs the obvious changes if that assumption is + * violated by a later STM32 series. */ +static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id) { + uint8 is_tim1 = dev->clk_id == RCC_TIMER1; + nvic_irq_num irq_num; switch (id) { case TIMER_UPDATE_INTERRUPT: - nvic_irq_enable(is_timer1 ? NVIC_TIMER1_UP : NVIC_TIMER8_UP); + irq_num = (is_tim1 ? + NVIC_TIMER1_UP_TIMER10 : + NVIC_TIMER8_UP_TIMER13); break; - case TIMER_CC1_INTERRUPT: - case TIMER_CC2_INTERRUPT: - case TIMER_CC3_INTERRUPT: + case TIMER_CC1_INTERRUPT: /* Fall through */ + case TIMER_CC2_INTERRUPT: /* ... */ + case TIMER_CC3_INTERRUPT: /* ... */ case TIMER_CC4_INTERRUPT: - nvic_irq_enable(is_timer1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC); + irq_num = is_tim1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC; break; - case TIMER_COM_INTERRUPT: + case TIMER_COM_INTERRUPT: /* Fall through */ case TIMER_TRG_INTERRUPT: - nvic_irq_enable(is_timer1 ? NVIC_TIMER1_TRG_COM : NVIC_TIMER8_TRG_COM); + irq_num = (is_tim1 ? + NVIC_TIMER1_TRG_COM_TIMER11 : + NVIC_TIMER8_TRG_COM_TIMER14); break; case TIMER_BREAK_INTERRUPT: - nvic_irq_enable(is_timer1 ? NVIC_TIMER1_BRK : NVIC_TIMER8_BRK); + irq_num = (is_tim1 ? + NVIC_TIMER1_BRK_TIMER9 : + NVIC_TIMER8_BRK_TIMER12); break; + default: + /* Can't happen, but placate the compiler */ + ASSERT(0); + return; } + nvic_irq_enable(irq_num); } -static void enable_nonmuxed_irq(timer_dev *dev) { +/* Basic and general purpose timers have a single IRQ line, which is + * shared by all interrupts supported by a particular timer. */ +static void enable_bas_gen_irq(timer_dev *dev) { + nvic_irq_num irq_num; switch (dev->clk_id) { case RCC_TIMER2: - nvic_irq_enable(NVIC_TIMER2); + irq_num = NVIC_TIMER2; break; case RCC_TIMER3: - nvic_irq_enable(NVIC_TIMER3); + irq_num = NVIC_TIMER3; break; case RCC_TIMER4: - nvic_irq_enable(NVIC_TIMER4); + irq_num = NVIC_TIMER4; break; -#ifdef STM32_HIGH_DENSITY case RCC_TIMER5: - nvic_irq_enable(NVIC_TIMER5); + irq_num = NVIC_TIMER5; break; case RCC_TIMER6: - nvic_irq_enable(NVIC_TIMER6); + irq_num = NVIC_TIMER6; break; case RCC_TIMER7: - nvic_irq_enable(NVIC_TIMER7); + irq_num = NVIC_TIMER7; + break; + case RCC_TIMER9: + irq_num = NVIC_TIMER1_BRK_TIMER9; + break; + case RCC_TIMER10: + irq_num = NVIC_TIMER1_UP_TIMER10; + break; + case RCC_TIMER11: + irq_num = NVIC_TIMER1_TRG_COM_TIMER11; + break; + case RCC_TIMER12: + irq_num = NVIC_TIMER8_BRK_TIMER12; + break; + case RCC_TIMER13: + irq_num = NVIC_TIMER8_UP_TIMER13; + break; + case RCC_TIMER14: + irq_num = NVIC_TIMER8_TRG_COM_TIMER14; break; -#endif default: ASSERT_FAULT(0); - break; + return; } + nvic_irq_enable(irq_num); } diff --git a/libmaple/timer_private.h b/libmaple/timer_private.h new file mode 100644 index 0000000..320c636 --- /dev/null +++ b/libmaple/timer_private.h @@ -0,0 +1,235 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011, 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/timer_private.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief Private, internal timer APIs. + */ + +#ifndef _LIBMAPLE_TIMER_PRIVATE_H_ +#define _LIBMAPLE_TIMER_PRIVATE_H_ + +/* + * Helper macros for declaring timer_devs of various timer_types + */ + +/* The indexes of user handlers in a timer_dev.handlers are just like + * the corresponding DIER bits, as follows: */ + +/* Advanced timers: + * [0] = Update handler; + * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively; + * [5] = COM; + * [6] = TRG; + * [7] = BRK. */ +#define NR_ADV_HANDLERS 8 +/* General purpose timers: + * [0] = update; + * [1,2,3,4] = capture/compare 1,2,3,4; + * [5] = <junk>; + * [6] = trigger. */ +#define NR_GEN_HANDLERS 7 +/* Basic timers: + * [0] = update. */ +#define NR_BAS_HANDLERS 1 + +/* For declaring advanced timers. */ +#define ADVANCED_TIMER(num) \ + { \ + .regs = { .adv = TIMER##num##_BASE }, \ + .clk_id = RCC_TIMER##num, \ + .type = TIMER_ADVANCED, \ + .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, \ + } + +/* For declaring full-featured general purpose timers. */ +#define GENERAL_TIMER(num) \ + { \ + .regs = { .gen = TIMER##num##_BASE }, \ + .clk_id = RCC_TIMER##num, \ + .type = TIMER_GENERAL, \ + .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, \ + } + +/* For declaring general purpose timers with limited interrupt + * capability (e.g. timers 9 through 14 on STM32F2 and XL-density + * STM32F1). */ +#define RESTRICTED_GENERAL_TIMER(num, max_dier_bit) \ + { \ + .regs = { .gen = TIMER##num##_BASE }, \ + .clk_id = RCC_TIMER##num, \ + .type = TIMER_GENERAL, \ + .handlers = { [max_dier_bit] = 0 }, \ + } + +/* For declaring basic timers (e.g. TIM6 and TIM7). */ +#define BASIC_TIMER(num) \ + { \ + .regs = { .bas = TIMER##num##_BASE }, \ + .clk_id = RCC_TIMER##num, \ + .type = TIMER_BASIC, \ + .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, \ + } + +/* + * IRQ handlers + * + * These decode TIMx_DIER and TIMx_SR, then dispatch to the user-level + * IRQ handlers. They also clean up TIMx_SR afterwards, so the user + * doesn't have to deal with register details. + * + * Notes: + * + * - These dispatch routines make use of the fact that DIER interrupt + * enable bits and SR interrupt flags have common bit positions. + * Thus, ANDing DIER and SR lets us check if an interrupt is enabled + * and if it has occurred simultaneously. + * + * - We force these routines to inline to avoid call overhead, but + * there aren't any measurements to prove that this is actually a + * good idea. Profile-directed optimizations are definitely wanted. */ + +/* A special-case dispatch routine for timers which only serve a + * single interrupt on a given IRQ line. + * + * This function still checks DIER & SR, as in some cases, a timer may + * only serve a single interrupt on a particular NVIC line, but that + * line may be shared with another timer. For example, the timer 1 + * update interrupt shares an IRQ line with the timer 10 interrupt on + * STM32F1 (XL-density), STM32F2, and STM32F4. */ +static __always_inline void dispatch_single_irq(timer_dev *dev, + timer_interrupt_id iid, + uint32 irq_mask) { + timer_bas_reg_map *regs = (dev->regs).bas; + if (regs->DIER & regs->SR & irq_mask) { + void (*handler)(void) = dev->handlers[iid]; + if (handler) { + handler(); + regs->SR &= ~irq_mask; + } + } +} + +/* Helper macro for dispatch routines which service multiple interrupts. */ +#define handle_irq(dier_sr, irq_mask, handlers, iid, handled_irq) do { \ + if ((dier_sr) & (irq_mask)) { \ + void (*__handler)(void) = (handlers)[iid]; \ + if (__handler) { \ + __handler(); \ + handled_irq |= (irq_mask); \ + } \ + } \ + } while (0) + +static __always_inline void dispatch_adv_brk(timer_dev *dev) { + dispatch_single_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF); +} + +static __always_inline void dispatch_adv_up(timer_dev *dev) { + dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF); +} + +static __always_inline void dispatch_adv_trg_com(timer_dev *dev) { + timer_adv_reg_map *regs = (dev->regs).adv; + uint32 dsr = regs->DIER & regs->SR; + void (**hs)(void) = dev->handlers; + uint32 handled = 0; /* Logical OR of SR interrupt flags we end up + * handling. We clear these. User handlers + * must clear overcapture flags, to avoid + * wasting time in output mode. */ + + handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_COMIF, hs, TIMER_COM_INTERRUPT, handled); + + regs->SR &= ~handled; +} + +static __always_inline void dispatch_adv_cc(timer_dev *dev) { + timer_adv_reg_map *regs = (dev->regs).adv; + uint32 dsr = regs->DIER & regs->SR; + void (**hs)(void) = dev->handlers; + uint32 handled = 0; + + handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); + + regs->SR &= ~handled; +} + +static __always_inline void dispatch_general(timer_dev *dev) { + timer_gen_reg_map *regs = (dev->regs).gen; + uint32 dsr = regs->DIER & regs->SR; + void (**hs)(void) = dev->handlers; + uint32 handled = 0; + + handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC4IF, hs, TIMER_CC4_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC3IF, hs, TIMER_CC3_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled); + + regs->SR &= ~handled; +} + +/* On F1 (XL-density), F2, and F4, TIM9 and TIM12 are restricted + * general-purpose timers with update, CC1, CC2, and TRG interrupts. */ +static __always_inline void dispatch_tim_9_12(timer_dev *dev) { + timer_gen_reg_map *regs = (dev->regs).gen; + uint32 dsr = regs->DIER & regs->SR; + void (**hs)(void) = dev->handlers; + uint32 handled = 0; + + handle_irq(dsr, TIMER_SR_TIF, hs, TIMER_TRG_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC2IF, hs, TIMER_CC2_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled); + + regs->SR &= ~handled; +} + +/* On F1 (XL-density), F2, and F4, timers 10, 11, 13, and 14 are + * restricted general-purpose timers with update and CC1 interrupts. */ +static __always_inline void dispatch_tim_10_11_13_14(timer_dev *dev) { + timer_gen_reg_map *regs = (dev->regs).gen; + uint32 dsr = regs->DIER & regs->SR; + void (**hs)(void) = dev->handlers; + uint32 handled = 0; + + handle_irq(dsr, TIMER_SR_CC1IF, hs, TIMER_CC1_INTERRUPT, handled); + handle_irq(dsr, TIMER_SR_UIF, hs, TIMER_UPDATE_INTERRUPT, handled); + + regs->SR &= ~handled; +} + +static __always_inline void dispatch_basic(timer_dev *dev) { + dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF); +} + +#endif diff --git a/libmaple/usart.c b/libmaple/usart.c index 0bdc37a..253cf9f 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -25,74 +25,13 @@ *****************************************************************************/ /** - * @file usart.c + * @file libmaple/usart.c * @author Marti Bolivar <mbolivar@leaflabs.com>, * Perry Hung <perry@leaflabs.com> - * @brief USART control routines + * @brief Portable USART routines */ -#include "usart.h" - -/* - * Devices - */ - -static ring_buffer usart1_rb; -static usart_dev usart1 = { - .regs = USART1_BASE, - .rb = &usart1_rb, - .max_baud = 4500000UL, - .clk_id = RCC_USART1, - .irq_num = NVIC_USART1 -}; -/** USART1 device */ -usart_dev *USART1 = &usart1; - -static ring_buffer usart2_rb; -static usart_dev usart2 = { - .regs = USART2_BASE, - .rb = &usart2_rb, - .max_baud = 2250000UL, - .clk_id = RCC_USART2, - .irq_num = NVIC_USART2 -}; -/** USART2 device */ -usart_dev *USART2 = &usart2; - -static ring_buffer usart3_rb; -static usart_dev usart3 = { - .regs = USART3_BASE, - .rb = &usart3_rb, - .max_baud = 2250000UL, - .clk_id = RCC_USART3, - .irq_num = NVIC_USART3 -}; -/** USART3 device */ -usart_dev *USART3 = &usart3; - -#ifdef STM32_HIGH_DENSITY -static ring_buffer uart4_rb; -static usart_dev uart4 = { - .regs = UART4_BASE, - .rb = &uart4_rb, - .max_baud = 2250000UL, - .clk_id = RCC_UART4, - .irq_num = NVIC_UART4 -}; -/** UART4 device */ -usart_dev *UART4 = &uart4; - -static ring_buffer uart5_rb; -static usart_dev uart5 = { - .regs = UART5_BASE, - .rb = &uart5_rb, - .max_baud = 2250000UL, - .clk_id = RCC_UART5, - .irq_num = NVIC_UART5 -}; -/** UART5 device */ -usart_dev *UART5 = &uart5; -#endif +#include <libmaple/usart.h> /** * @brief Initialize a serial port. @@ -105,27 +44,6 @@ void usart_init(usart_dev *dev) { } /** - * @brief Configure a serial port's baud rate. - * - * @param dev Serial port to be configured - * @param clock_speed Clock speed, in megahertz. - * @param baud Baud rate for transmit/receive. - */ -void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) { - uint32 integer_part; - uint32 fractional_part; - uint32 tmp; - - /* See ST RM0008 for the details on configuring the baud rate register */ - integer_part = (25 * clock_speed) / (4 * baud); - tmp = (integer_part / 100) << 4; - fractional_part = integer_part - (100 * (tmp >> 4)); - tmp |= (((fractional_part * 16) + 50) / 100) & ((uint8)0x0F); - - dev->regs->BRR = (uint16)tmp; -} - -/** * @brief Enable a serial port. * * USART is enabled in single buffer transmission mode, multibuffer @@ -138,7 +56,8 @@ void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) { */ void usart_enable(usart_dev *dev) { usart_reg_map *regs = dev->regs; - regs->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; + regs->CR1 = (USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE | + USART_CR1_M_8N1); regs->CR1 |= USART_CR1_UE; } @@ -147,7 +66,7 @@ void usart_enable(usart_dev *dev) { * @param dev Serial port to be disabled */ void usart_disable(usart_dev *dev) { - /* FIXME this misbehaves if you try to use PWM on TX afterwards */ + /* FIXME this misbehaves (on F1) if you try to use PWM on TX afterwards */ usart_reg_map *regs = dev->regs; /* TC bit must be high before disabling the USART */ @@ -162,20 +81,6 @@ void usart_disable(usart_dev *dev) { } /** - * @brief Call a function on each USART. - * @param fn Function to call. - */ -void usart_foreach(void (*fn)(usart_dev*)) { - fn(USART1); - fn(USART2); - fn(USART3); -#ifdef STM32_HIGH_DENSITY - fn(UART4); - fn(UART5); -#endif -} - -/** * @brief Nonblocking USART transmit * @param dev Serial port to transmit over * @param buf Buffer to transmit @@ -230,40 +135,3 @@ void usart_putudec(usart_dev *dev, uint32 val) { usart_putc(dev, digits[i]); } } - -/* - * Interrupt handlers. - */ - -static inline void usart_irq(usart_dev *dev) { -#ifdef USART_SAFE_INSERT - /* If the buffer is full and the user defines USART_SAFE_INSERT, - * ignore new bytes. */ - rb_safe_insert(dev->rb, (uint8)dev->regs->DR); -#else - /* By default, push bytes around in the ring buffer. */ - rb_push_insert(dev->rb, (uint8)dev->regs->DR); -#endif -} - -void __irq_usart1(void) { - usart_irq(USART1); -} - -void __irq_usart2(void) { - usart_irq(USART2); -} - -void __irq_usart3(void) { - usart_irq(USART3); -} - -#ifdef STM32_HIGH_DENSITY -void __irq_uart4(void) { - usart_irq(UART4); -} - -void __irq_uart5(void) { - usart_irq(UART5); -} -#endif diff --git a/libmaple/usart_private.c b/libmaple/usart_private.c new file mode 100644 index 0000000..0eaacdf --- /dev/null +++ b/libmaple/usart_private.c @@ -0,0 +1,41 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usart_private.c + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief Private USART routines. + */ + +#include "usart_private.h" +#include <libmaple/rcc.h> +#include <libmaple/stm32.h> + +uint32 _usart_clock_freq(usart_dev *dev) { + rcc_clk_domain domain = rcc_dev_clk(dev->clk_id); + return (domain == RCC_APB1 ? STM32_PCLK1 : + (domain == RCC_APB2 ? STM32_PCLK2 : 0)); +} diff --git a/libmaple/usart_private.h b/libmaple/usart_private.h new file mode 100644 index 0000000..8e8e11b --- /dev/null +++ b/libmaple/usart_private.h @@ -0,0 +1,53 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2012 LeafLabs, LLC. + * Copyright (c) 2010 Perry Hung. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usart_private.h + * @author Marti Bolivar <mbolivar@leaflabs.com> + * @brief Private USART header. + */ + +#ifndef _LIBMAPLE_USART_PRIVATE_H_ +#define _LIBMAPLE_USART_PRIVATE_H_ + +#include <libmaple/ring_buffer.h> +#include <libmaple/usart.h> + +static __always_inline void usart_irq(ring_buffer *rb, usart_reg_map *regs) { +#ifdef USART_SAFE_INSERT + /* If the buffer is full and the user defines USART_SAFE_INSERT, + * ignore new bytes. */ + rb_safe_insert(rb, (uint8)regs->DR); +#else + /* By default, push bytes around in the ring buffer. */ + rb_push_insert(rb, (uint8)regs->DR); +#endif +} + +uint32 _usart_clock_freq(usart_dev *dev); + +#endif diff --git a/libmaple/usb/README b/libmaple/usb/README index 2c55364..d0fca8d 100644 --- a/libmaple/usb/README +++ b/libmaple/usb/README @@ -1,35 +1,24 @@ -The USB submodule of libmaple is responsible for: - - Initializing the USB peripheral, scaling the peripheral clocks - appropriately, enabling the interrupt channels to USB, defining - the USB IRQ, resetting the USB DISC pin (used to tell the host - were alive). Additionally, the USB submodule defines the virtual - COM port interface that is exposed to user sketches via SerialUSB. - -To use it: - - SerialUSB.print/ln, available(), read(), write() implement the same - interface as Serial1/2/3. +The USB submodule of libmaple is a separate piece of the codebase for +reasons that are largely historical. Current Status: - Currently, the USB submodule relies on the low level core library - provided by ST to implement the USB transfer protocol for control - endpoint transfers. The high level virtual com port application - is unfortunately hard to untangle from this low level dependence, - and when a new USB core library is written (to nix ST dependence) - changes will likely have to be made to virtual com application - code. Ideally, the new core library should mimic the form of MyUSB - (LUFA), since this library (USB for AVR) is growing in popularity - and in example applications. + There's only support for the USB device peripheral found on + STM32F103s. - The virtual com port serves two important purposes. + We rely on the low level core library provided by ST to implement + the USB transfer protocol for control endpoint transfers. - 1) It allows serial data transfers between user sketches an a - host computer. + The virtual com port (which is exposed via + <libmaple/usb_cdcacm.h>) serves two important purposes. - 2) It allows the host machine to issue a system reset by - asserting the DTR signal. + 1) It allows serial data transfers between user sketches an a + host computer. + + 2) It allows the host PC to issue a system reset into the DFU + bootloader with the DTR + RTS + "1EAF" sequence (see + leaflabs.com/docs/bootloader.html for more information on + this). After reset, Maple will run the DFU bootloader for a few seconds, during which the user can begin a DFU upload operation (uploads @@ -38,11 +27,11 @@ Current Status: the chip in order to enable the bootloader. If you would like to develop your own USB application for whatever - reason (uses faster isochronous enpoints for streaming audio, or - implements the USB HID or Mass Storage specs for examples) then + reason (e.g. to use faster isochronous enpoints for streaming + audio, or implement the USB HID or Mass Storage specs), then ensure that you leave some hook for resetting Maple remotely in - order to spin up the DFU bootloader. Please make sure to give - yourself a unique vendor/product ID pair in your application, as + order to spin up the DFU bootloader. Please make sure to get + yourself a unique vendor/product ID pair for your application, as some operating systems will assign a host-side driver based on these tags. @@ -52,21 +41,23 @@ Current Status: be a burden from the host driver side, as Windows and *nix handle compound USB devices quite differently. - Be mindful that enabling the USB peripheral isnt "free." The + Be mindful that enabling the USB peripheral isn't "free." The device must respond to periodic bus activity (every few milliseconds) by servicing an ISR. Therefore, the USB application - should be disabled inside of timing critical applications. In - order to disconnect the device from the host, the USB_DISC pin can - be asserted (on Maple this is GPIO C12). Alternatively, the NVIC + should be disabled inside of timing critical applications. + + In order to disconnect the device from the host, a USB_DISC pin is + asserted (e.g. on Maple, this is PC12). Alternatively, the NVIC can be directly configured to disable the USB LP/HP IRQ's. The files inside of usb_lib were provided by ST and are subject to their own license, all other files were written by the LeafLabs team and fall under the MIT license. -Todo: +TODO: - - write custom low level USB stack to strip out any remaining - dependence on ST code - - add a high level USB application library that would allow users - to make their own HID/Mass Storage/Audio/Video devices. + - Generic USB driver core with series-provided backends, like + libopencm3 has. + - Strip out ST code. + - Integration with a high level USB library (like LUFA/MyUSB) to + allow users to write custom USB applications. diff --git a/libmaple/usb/rules.mk b/libmaple/usb/rules.mk new file mode 100644 index 0000000..e8ccc15 --- /dev/null +++ b/libmaple/usb/rules.mk @@ -0,0 +1,45 @@ +# Standard things +sp := $(sp).x +dirstack_$(sp) := $(d) +d := $(dir) +BUILDDIRS += $(BUILD_PATH)/$(d) + +# Local flags +CFLAGS_$(d) = -I$(d) -I$(d)/$(MCU_SERIES) -I$(d)/usb_lib $(LIBMAPLE_INCLUDES) $(LIBMAPLE_PRIVATE_INCLUDES) -Wall + +# Add usblib and series subdirectory to BUILDDIRS. +BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_SERIES) +BUILDDIRS += $(BUILD_PATH)/$(d)/usb_lib + +# Local rules and targets +sSRCS_$(d) := +cSRCS_$(d) := +# We currently only have F1 performance line support. Sigh. +ifeq ($(MCU_SERIES), stm32f1) +ifeq ($(MCU_F1_LINE), performance) +cSRCS_$(d) += $(MCU_SERIES)/usb.c +cSRCS_$(d) += $(MCU_SERIES)/usb_reg_map.c +cSRCS_$(d) += $(MCU_SERIES)/usb_cdcacm.c +cSRCS_$(d) += usb_lib/usb_core.c +cSRCS_$(d) += usb_lib/usb_init.c +cSRCS_$(d) += usb_lib/usb_mem.c +cSRCS_$(d) += usb_lib/usb_regs.c +endif +endif + +sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%) +cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) + +OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \ + $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) +DEPS_$(d) := $(OBJS_$(d):%.o=%.d) + +$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d)) +$(OBJS_$(d)): TGT_ASFLAGS := + +TGT_BIN += $(OBJS_$(d)) + +# Standard things +-include $(DEPS_$(d)) +d := $(dirstack_$(sp)) +sp := $(basename $(sp)) diff --git a/libmaple/usb/usb.c b/libmaple/usb/stm32f1/usb.c index 667b11f..0130bab 100644 --- a/libmaple/usb/usb.c +++ b/libmaple/usb/stm32f1/usb.c @@ -25,18 +25,22 @@ *****************************************************************************/ /** - * @file usb.c + * @file libmaple/usb/usb.c * @brief USB support. + * + * This is a mess. What we need almost amounts to a ground-up rewrite. */ -#include "usb.h" +#include <libmaple/usb.h> -#include "libmaple.h" -#include "rcc.h" +#include <libmaple/libmaple.h> +#include <libmaple/rcc.h> +/* Private headers */ #include "usb_reg_map.h" #include "usb_lib_globals.h" +/* usb_lib headers */ #include "usb_type.h" #include "usb_core.h" diff --git a/libmaple/usb/usb_cdcacm.c b/libmaple/usb/stm32f1/usb_cdcacm.c index b41753a..6ef4806 100644 --- a/libmaple/usb/usb_cdcacm.c +++ b/libmaple/usb/stm32f1/usb_cdcacm.c @@ -25,22 +25,26 @@ *****************************************************************************/ /** - * @file usb_cdcacm.c + * @file libmaple/usb/usb_cdcacm.c + * @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM). * - * @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM) state and - * routines. + * FIXME: this works on the STM32F1 USB peripherals, and probably no + * place else. Nonportable bits really need to be factored out, and + * the result made cleaner. */ -#include "usb_cdcacm.h" +#include <libmaple/usb_cdcacm.h> -#include "nvic.h" -#include "delay.h" +#include <libmaple/usb.h> +#include <libmaple/nvic.h> +#include <libmaple/delay.h> -#include "usb.h" +/* Private headers */ #include "usb_descriptors.h" #include "usb_lib_globals.h" #include "usb_reg_map.h" +/* usb_lib headers */ #include "usb_type.h" #include "usb_core.h" #include "usb_def.h" @@ -59,12 +63,8 @@ #if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \ defined(BOARD_maple_mini) || defined(BOARD_maple_native)) - -#warning ("Warning! USB VCOM relies on LeafLabs board-specific " \ - "configuration right now. If you want, you can pretend " \ - "you're one of our boards; i.e., #define BOARD_maple, " \ - "BOARD_maple_mini, etc. according to what matches your MCU " \ - "best." +#warning USB CDC ACM relies on LeafLabs board-specific configuration.\ + You may have problems on non-LeafLabs boards. #endif static void vcomDataTxCb(void); diff --git a/libmaple/usb/usb_descriptors.h b/libmaple/usb/stm32f1/usb_descriptors.h index 405588a..9bcb2b6 100644 --- a/libmaple/usb/usb_descriptors.h +++ b/libmaple/usb/stm32f1/usb_descriptors.h @@ -27,7 +27,7 @@ #ifndef _USB_DESCRIPTORS_H_ #define _USB_DESCRIPTORS_H_ -#include "libmaple.h" +#include <libmaple/libmaple.h> #define USB_DESCRIPTOR_TYPE_DEVICE 0x01 #define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02 diff --git a/libmaple/usb/usb_lib_globals.h b/libmaple/usb/stm32f1/usb_lib_globals.h index a494817..1cd2754 100644 --- a/libmaple/usb/usb_lib_globals.h +++ b/libmaple/usb/stm32f1/usb_lib_globals.h @@ -27,6 +27,7 @@ #ifndef _USB_LIB_GLOBALS_H_ #define _USB_LIB_GLOBALS_H_ +/* usb_lib headers */ #include "usb_type.h" #include "usb_core.h" diff --git a/libmaple/usb/usb_reg_map.c b/libmaple/usb/stm32f1/usb_reg_map.c index 75562e1..75562e1 100644 --- a/libmaple/usb/usb_reg_map.c +++ b/libmaple/usb/stm32f1/usb_reg_map.c diff --git a/libmaple/usb/usb_reg_map.h b/libmaple/usb/stm32f1/usb_reg_map.h index 5bf5d96..ce80842 100644 --- a/libmaple/usb/usb_reg_map.h +++ b/libmaple/usb/stm32f1/usb_reg_map.h @@ -24,8 +24,8 @@ * SOFTWARE. *****************************************************************************/ -#include "libmaple_types.h" -#include "util.h" +#include <libmaple/libmaple_types.h> +#include <libmaple/util.h> #ifndef _USB_REG_MAP_H_ #define _USB_REG_MAP_H_ diff --git a/libmaple/util.c b/libmaple/util.c index b15d658..2ee5ede 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -25,26 +25,18 @@ *****************************************************************************/ /** - * @file util.c - * @brief Utility procedures for debugging, mostly an error LED fade - * and messages dumped over a UART for failed asserts. + * @file libmaple/util.c + * @brief Utility procedures for debugging */ -#include "libmaple.h" -#include "usart.h" -#include "gpio.h" -#include "nvic.h" -#include "adc.h" -#include "timer.h" +#include <libmaple/libmaple.h> +#include <libmaple/usart.h> +#include <libmaple/gpio.h> +#include <libmaple/nvic.h> -/* Failed ASSERT()s send out a message using this USART config. */ -#ifndef ERROR_USART -#define ERROR_USART USART2 -#define ERROR_USART_CLK_SPEED STM32_PCLK1 -#define ERROR_USART_BAUD 9600 -#define ERROR_TX_PORT GPIOA -#define ERROR_TX_PIN 2 -#endif +/* (Undocumented) hooks used by Wirish to direct our behavior here */ +extern __weak void __lm_error(void); +extern __weak usart_dev* __lm_enable_error_usart(void); /* If you define ERROR_LED_PORT and ERROR_LED_PIN, then a failed * ASSERT() will also throb() an LED connected to that port and pin. @@ -53,105 +45,82 @@ #define HAVE_ERROR_LED #endif -/** - * @brief Disables all peripheral interrupts except USB and fades the - * error LED. - */ /* (Called from exc.S with global interrupts disabled.) */ -void __error(void) { - /* Turn off peripheral interrupts */ - nvic_irq_disable_all(); - - /* Turn off timers */ - timer_disable_all(); - - /* Turn off ADC */ - adc_disable_all(); - - /* Turn off all USARTs */ - usart_disable_all(); - - /* Turn the USB interrupt back on so the bootloader keeps on functioning */ - nvic_irq_enable(NVIC_USB_HP_CAN_TX); - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); - +__attribute__((noreturn)) void __error(void) { + if (__lm_error) { + __lm_error(); + } /* Reenable global interrupts */ nvic_globalirq_enable(); throb(); } -/** - * @brief Enable the error USART for writing. - * @sideeffect Configures ERROR_USART appropriately for writing. - */ -void _enable_error_usart() { - gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_AF_OUTPUT_PP); - usart_init(ERROR_USART); - usart_set_baud_rate(ERROR_USART, ERROR_USART_CLK_SPEED, ERROR_USART_BAUD); -} - -/** - * @brief Print an error message on a UART upon a failed assertion - * and throb the error LED, if there is one defined. +/* + * Print an error message on a UART upon a failed assertion (if one is + * available), and punt to __error(). + * * @param file Source file of failed assertion * @param line Source line of failed assertion * @param exp String representation of failed assertion * @sideeffect Turns of all peripheral interrupts except USB. */ void _fail(const char* file, int line, const char* exp) { - /* Initialize the error USART */ - _enable_error_usart(); - - /* Print failed assert message */ - usart_putstr(ERROR_USART, "ERROR: FAILED ASSERT("); - usart_putstr(ERROR_USART, exp); - usart_putstr(ERROR_USART, "): "); - usart_putstr(ERROR_USART, file); - usart_putstr(ERROR_USART, ": "); - usart_putudec(ERROR_USART, line); - usart_putc(ERROR_USART, '\n'); - usart_putc(ERROR_USART, '\r'); - + if (__lm_enable_error_usart) { + /* Initialize the error USART */ + usart_dev *err_usart = __lm_enable_error_usart(); + + /* Print failed assert message */ + usart_putstr(err_usart, "ERROR: FAILED ASSERT("); + usart_putstr(err_usart, exp); + usart_putstr(err_usart, "): "); + usart_putstr(err_usart, file); + usart_putstr(err_usart, ": "); + usart_putudec(err_usart, line); + usart_putc(err_usart, '\n'); + usart_putc(err_usart, '\r'); + } /* Shutdown and error fade */ __error(); } -/** - * @brief Provide an __assert_func handler to libc so that calls to assert() get - * redirected to _fail. +/* + * Provide an __assert_func handler to libc so that calls to assert() + * get redirected to _fail. */ void __assert_func(const char* file, int line, const char* method, const char* expression) { _fail(file, line, expression); } -/** - * @brief Provide an abort() implementation that aborts execution and enters an - * error state with the throbbing LED indicator. +/* + * Provide an abort() implementation that aborts execution and punts + * to __error(). */ void abort() { - /* Initialize the error USART */ - _enable_error_usart(); - - /* Print abort message. */ - usart_putstr(ERROR_USART, "ERROR: PROGRAM ABORTED VIA abort()\n\r"); + if (__lm_enable_error_usart) { + /* Initialize the error USART */ + usart_dev *err_usart = __lm_enable_error_usart(); + /* Print abort message. */ + usart_putstr(err_usart, "ERROR: PROGRAM ABORTED VIA abort()\r\n"); + } /* Shutdown and error fade */ __error(); } +/* This was public as of v0.0.12, so we've got to keep it public. */ /** * @brief Fades the error LED on and off * @sideeffect Sets output push-pull on ERROR_LED_PIN. */ -void throb(void) { +__attribute__((noreturn)) void throb(void) { #ifdef HAVE_ERROR_LED int32 slope = 1; uint32 CC = 0x0000; uint32 TOP_CNT = 0x0200; uint32 i = 0; - gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_OUTPUT_PP); + gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT); /* Error fade. */ while (1) { if (CC == TOP_CNT) { |