diff options
-rw-r--r-- | libmaple/include/libmaple/timer.h | 8 | ||||
-rw-r--r-- | libmaple/stm32f1/include/series/timer.h | 42 | ||||
-rw-r--r-- | libmaple/stm32f1/timer.c | 83 | ||||
-rw-r--r-- | libmaple/timer.c | 89 |
4 files changed, 180 insertions, 42 deletions
diff --git a/libmaple/include/libmaple/timer.h b/libmaple/include/libmaple/timer.h index e98759a..0a34066 100644 --- a/libmaple/include/libmaple/timer.h +++ b/libmaple/include/libmaple/timer.h @@ -37,18 +37,12 @@ extern "C"{ #endif +#include <series/timer.h> #include <libmaple/libmaple.h> #include <libmaple/rcc.h> #include <libmaple/nvic.h> #include <libmaple/bitband.h> -struct timer_adv_reg_map; -struct timer_gen_reg_map; -struct timer_bas_reg_map; -struct timer_dev; -/* Include the series header here, as it may need the above */ -#include <series/timer.h> - /* * Register maps */ diff --git a/libmaple/stm32f1/include/series/timer.h b/libmaple/stm32f1/include/series/timer.h index 9bd273e..2551f70 100644 --- a/libmaple/stm32f1/include/series/timer.h +++ b/libmaple/stm32f1/include/series/timer.h @@ -33,11 +33,10 @@ #ifndef _LIBMAPLE_STM32F1_TIMER_H_ #define _LIBMAPLE_STM32F1_TIMER_H_ -#include <libmaple/libmaple.h> -#include <series/timer.h> +#include <libmaple/libmaple_types.h> /* - * Register maps and devices + * Register maps and base pointers */ /** STM32F1 general purpose timer register map type */ @@ -64,6 +63,10 @@ typedef struct timer_gen_reg_map { __io uint32 DMAR; /**< DMA address for full transfer */ } timer_gen_reg_map; +struct timer_adv_reg_map; +struct timer_gen_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 */ @@ -72,7 +75,6 @@ typedef struct timer_gen_reg_map { #define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400) /** Timer 4 register map base pointer */ #define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800) -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) /** Timer 5 register map base pointer */ #define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00) /** Timer 6 register map base pointer */ @@ -81,7 +83,29 @@ typedef struct timer_gen_reg_map { #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 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; @@ -93,5 +117,13 @@ 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/timer.c b/libmaple/stm32f1/timer.c index 7506cb6..899abbc 100644 --- a/libmaple/stm32f1/timer.c +++ b/libmaple/stm32f1/timer.c @@ -30,14 +30,30 @@ * @brief STM32F1 timer support. */ +/* Notes: + * + * - We use STM32F1 density test macros throughout to avoid defining + * symbols or linking in code that would use timers that are + * unavailable in a given density. For example, TIM5 doesn't exist + * on medium-density, and TIM9 doesn't exist on high-density, so we + * don't define or use TIM5 when being compiled for medium-density, + * and similarly for TIM9 and high-density. + * + * This makes a mess, but helps avoid bloat and ensures backwards + * compatibility. Since the mess is manageable and there don't seem + * to be any plans on ST's part to add new STM32F1 lines or + * densities, we'll live with it. + */ + #include <libmaple/timer.h> #include "timer_private.h" /* * Devices + * + * Defer to the timer_private API. */ -/* Use timer_private macros to save typing. */ static DECLARE_ADVANCED_TIMER(timer1, 1); static DECLARE_GENERAL_TIMER(timer2, 2); static DECLARE_GENERAL_TIMER(timer3, 3); @@ -66,7 +82,35 @@ timer_dev *TIMER6 = &timer6; timer_dev *TIMER7 = &timer7; /** Timer 8 device (advanced) */ timer_dev *TIMER8 = &timer8; -#endif +#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */ + +#ifdef STM32_XL_DENSITY +/* TIM9 has UIE, CC1IE, CC2IE, TIE bits in DIER. */ +static DECLARE_RESTRICTED_GENERAL_TIMER(timer9, 9, TIMER_DIER_TIE_BIT); +/* TIM10 has UIE, CC1IE. */ +static DECLARE_RESTRICTED_GENERAL_TIMER(timer10, 10, TIMER_DIER_CC1IE_BIT); +/* TIM11 has UIE, CC1IE. */ +static DECLARE_RESTRICTED_GENERAL_TIMER(timer11, 11, TIMER_DIER_CC1IE_BIT); +/* TIM12 has UIE, CC1IE, CC2IE, TIE. */ +static DECLARE_RESTRICTED_GENERAL_TIMER(timer12, 12, TIMER_DIER_TIE_BIT); +/* TIM13 has UIE, CC1IE. */ +static DECLARE_RESTRICTED_GENERAL_TIMER(timer13, 13, TIMER_DIER_CC1IE_BIT); +/* TIM14 has UIE, CC1IE. */ +static DECLARE_RESTRICTED_GENERAL_TIMER(timer14, 14, TIMER_DIER_CC1IE_BIT); + +/** Timer 9 device (general-purpose) */ +timer_dev *TIMER9 = &timer9; +/** Timer 10 device (general-purpose) */ +timer_dev *TIMER10 = &timer10; +/** Timer 11 device (general-purpose) */ +timer_dev *TIMER11 = &timer11; +/** Timer 12 device (general-purpose) */ +timer_dev *TIMER12 = &timer12; +/** Timer 13 device (general-purpose) */ +timer_dev *TIMER13 = &timer13; +/** Timer 14 device (general-purpose) */ +timer_dev *TIMER14 = &timer14; +#endif /* STM32_XL_DENSITY */ /* * Routines @@ -87,22 +131,46 @@ void timer_foreach(void (*fn)(timer_dev*)) { fn(TIMER7); fn(TIMER8); #endif +#ifdef STM32_XL_DENSITY + fn(TIMER9); + fn(TIMER10); + fn(TIMER11); + fn(TIMER12); + fn(TIMER13); + fn(TIMER14); +#endif } /* * 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. */ void __irq_tim1_brk(void) { dispatch_adv_brk(TIMER1); +#ifdef STM32_XL_DENSITY + dispatch_tim_9_12(TIMER9); +#endif } void __irq_tim1_up(void) { dispatch_adv_up(TIMER1); +#ifdef STM32_XL_DENSITY + dispatch_tim_10_11_13_14(TIMER10); +#endif } void __irq_tim1_trg_com(void) { dispatch_adv_trg_com(TIMER1); +#ifdef STM32_XL_DENSITY + dispatch_tim_10_11_13_14(TIMER11); +#endif } void __irq_tim1_cc(void) { @@ -136,17 +204,26 @@ void __irq_tim7(void) { void __irq_tim8_brk(void) { dispatch_adv_brk(TIMER8); +#ifdef STM32_XL_DENSITY + dispatch_tim_9_12(TIMER12); +#endif } void __irq_tim8_up(void) { dispatch_adv_up(TIMER8); +#ifdef STM32_XL_DENSITY + dispatch_tim_10_11_13_14(TIMER13); +#endif } void __irq_tim8_trg_com(void) { dispatch_adv_trg_com(TIMER8); +#ifdef STM32_XL_DENSITY + dispatch_tim_10_11_13_14(TIMER14); +#endif } void __irq_tim8_cc(void) { dispatch_adv_cc(TIMER8); } -#endif +#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */ diff --git a/libmaple/timer.c b/libmaple/timer.c index d64e3e9..d204fef 100644 --- a/libmaple/timer.c +++ b/libmaple/timer.c @@ -152,66 +152,101 @@ static void output_compare_mode(timer_dev *dev, uint8 channel) { timer_cc_enable(dev, channel); } -/* FIXME: These IRQ enable routines fail for timers 9 through 14. - * We don't support those timers yet, so it's OK for now, but this - * really needs to get fixed. */ - -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; 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; default: ASSERT_FAULT(0); - break; + return; } + nvic_irq_enable(irq_num); } |