aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmaple/include/libmaple/timer.h8
-rw-r--r--libmaple/stm32f1/include/series/timer.h42
-rw-r--r--libmaple/stm32f1/timer.c83
-rw-r--r--libmaple/timer.c89
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);
}