aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple/timer.c')
-rw-r--r--libmaple/timer.c275
1 files changed, 6 insertions, 269 deletions
diff --git a/libmaple/timer.c b/libmaple/timer.c
index 90995e2..d64e3e9 100644
--- a/libmaple/timer.c
+++ b/libmaple/timer.c
@@ -25,103 +25,13 @@
*****************************************************************************/
/**
- * @file timer.c
+ * @file libmaple/timer.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
- * @brief New-style timer interface
+ * @brief Portable timer routines.
*/
#include <libmaple/timer.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 timer_dev timer1 = {
- .regs = { .adv = TIMER1_BASE },
- .clk_id = RCC_TIMER1,
- .type = TIMER_ADVANCED,
- .handlers = { [NR_ADV_HANDLERS - 1] = 0 },
-};
-/** 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 },
-};
-/** 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 },
-};
-/** 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 },
-};
-/** 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 },
-};
-/** 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 },
-};
-/** 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 },
-};
-/** 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 },
-};
-/** Timer 8 device (advanced) */
-timer_dev *TIMER8 = &timer8;
-#endif
-
-/*
- * Convenience 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);
@@ -191,23 +101,6 @@ 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.
- */
-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
-}
-
-/**
* @brief Attach a timer interrupt.
* @param dev Timer device
* @param interrupt Interrupt number to attach to; this may be any
@@ -240,164 +133,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,6 +152,10 @@ 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);
@@ -462,7 +201,6 @@ static void enable_nonmuxed_irq(timer_dev *dev) {
case RCC_TIMER4:
nvic_irq_enable(NVIC_TIMER4);
break;
-#ifdef STM32_HIGH_DENSITY
case RCC_TIMER5:
nvic_irq_enable(NVIC_TIMER5);
break;
@@ -472,7 +210,6 @@ static void enable_nonmuxed_irq(timer_dev *dev) {
case RCC_TIMER7:
nvic_irq_enable(NVIC_TIMER7);
break;
-#endif
default:
ASSERT_FAULT(0);
break;