aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/timer.c
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@leaflabs.com>2012-04-09 16:38:01 -0400
committerMarti Bolivar <mbolivar@leaflabs.com>2012-04-11 16:56:57 -0400
commit08c56bb56a5ba4028ad761a8ff05ead0f54a549c (patch)
treee8d6b42d27e2a5912261c6cf2f2f77c5d2ac2933 /libmaple/timer.c
parent378a766ec86694a6be0f8e38976473646c82702c (diff)
downloadlibrambutan-08c56bb56a5ba4028ad761a8ff05ead0f54a549c.tar.gz
librambutan-08c56bb56a5ba4028ad761a8ff05ead0f54a549c.zip
STM32F1: Add support for timers 9 through 14.
This applies to XL-density STM32F1 devices. In stm32f1/timer.c, add timer_dev's for the new timers, using the timer_private API. These definitions are conditionally compiled based on the target density to avoid wasting space on smaller MCUs. Also add calls to the appropriate timer_private.h dispatch routines within the IRQ handlers for these timers. We need to change the IRQ handler names to reflect this eventually, but put that off for now, as it could break backwards compatibility in some exotic situations where the user refers to the libmaple IRQ handlers directly. In stm32f1/timer.h, add register map base pointers and device declarations for the new timers. timer_dev* declarations are compiled in only when the target MCU supports them, in keeping with the above stm32f1/timer.c changes. In libmaple/timer.c, update the (static) IRQ enable routines to account for the additional timers. This adds some code that's unnecessary on smaller STM32F1s, but it's minimal (40 extra bytes on my machine), so portability and readability win out. Size change, using GCC version "(Sourcery G++ Lite 2011.03-42) 4.5.2": Before: text data bss dec hex filename 615 0 0 615 267 build/home/mbolivar/leaf/libmaple/libmaple/timer.o After: text data bss dec hex filename 655 0 0 655 28f build/home/mbolivar/leaf/libmaple/libmaple/timer.o Signed-off-by: Marti Bolivar <mbolivar@leaflabs.com>
Diffstat (limited to 'libmaple/timer.c')
-rw-r--r--libmaple/timer.c89
1 files changed, 62 insertions, 27 deletions
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);
}