aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmaple/include/libmaple/timer.h233
-rw-r--r--libmaple/rules.mk2
-rw-r--r--libmaple/stm32f1/include/series/timer.h97
-rw-r--r--libmaple/stm32f1/rules.mk1
-rw-r--r--libmaple/stm32f1/timer.c152
-rw-r--r--libmaple/timer.c275
-rw-r--r--libmaple/timer_private.h168
7 files changed, 568 insertions, 360 deletions
diff --git a/libmaple/include/libmaple/timer.h b/libmaple/include/libmaple/timer.h
index fef34fc..0a046c9 100644
--- a/libmaple/include/libmaple/timer.h
+++ b/libmaple/include/libmaple/timer.h
@@ -42,8 +42,15 @@ extern "C"{
#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 and devices
+ * Register maps
*/
/** Advanced control timer register map type */
@@ -70,29 +77,10 @@ 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;
+/* timer_gen_reg_map: 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 {
@@ -110,25 +98,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
*/
@@ -163,19 +132,14 @@ 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[]; /**<
+ * @brief User IRQ handlers
+ * It's not a good idea to touch these
+ * directly.
+ * @see timer_attach_interrupt()
+ * @see timer_detach_interrupt() */
} timer_dev;
-extern timer_dev *TIMER1;
-extern timer_dev *TIMER2;
-extern timer_dev *TIMER3;
-extern timer_dev *TIMER4;
-#ifdef STM32_HIGH_DENSITY
-extern timer_dev *TIMER5;
-extern timer_dev *TIMER6;
-extern timer_dev *TIMER7;
-extern timer_dev *TIMER8;
-#endif
/*
* Register bit definitions
@@ -278,12 +242,15 @@ 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
@@ -291,12 +258,15 @@ extern timer_dev *TIMER8;
#define TIMER_DIER_UIE_BIT 0
#define TIMER_DIER_TDE BIT(TIMER_DIER_TDE_BIT)
+#define TIMER_DIER_COMDE BIT(TIMER_DIER_COMDE_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_BIE BIT(TIMER_DIER_BIE_BIT)
#define TIMER_DIER_TIE BIT(TIMER_DIER_TIE_BIT)
+#define TIMER_DIER_COMIE BIT(TIMER_DIER_COMIE_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)
@@ -333,14 +303,18 @@ extern timer_dev *TIMER8;
/* 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_BG BIT(TIMER_EGR_BG_BIT)
#define TIMER_EGR_TG BIT(TIMER_EGR_TG_BIT)
+#define TIMER_EGR_COMG BIT(TIMER_EGR_COMG_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)
@@ -397,44 +371,83 @@ extern timer_dev *TIMER8;
#define TIMER_CCMR2_OC4CE BIT(TIMER_CCMR2_OC4CE_BIT)
#define TIMER_CCMR2_OC4M (0x3 << 12)
-#define TIMER_CCMR2_IC2F (0xF << 12)
+#define TIMER_CCMR2_IC4F (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_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_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 BIT(TIMER_CCMR2_OC3CE_BIT)
#define TIMER_CCMR2_OC3M (0x3 << 4)
-#define TIMER_CCMR2_IC1F (0xF << 4)
+#define TIMER_CCMR2_IC3F (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_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
+
+/* Old, copy-paste error CCMR2 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
/* 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_CC3NP BIT(TIMER_CCER_CC3NP_BIT)
+#define TIMER_CCER_CC3NE BIT(TIMER_CCER_CC3NE_BIT)
#define TIMER_CCER_CC3P BIT(TIMER_CCER_CC3P_BIT)
#define TIMER_CCER_CC3E BIT(TIMER_CCER_CC3E_BIT)
+#define TIMER_CCER_CC2NP BIT(TIMER_CCER_CC2NP_BIT)
+#define TIMER_CCER_CC2NE BIT(TIMER_CCER_CC2NE_BIT)
#define TIMER_CCER_CC2P BIT(TIMER_CCER_CC2P_BIT)
#define TIMER_CCER_CC2E BIT(TIMER_CCER_CC2E_BIT)
+#define TIMER_CCER_CC1NP BIT(TIMER_CCER_CC1NP_BIT)
+#define TIMER_CCER_CC1NE BIT(TIMER_CCER_CC1NE_BIT)
#define TIMER_CCER_CC1P BIT(TIMER_CCER_CC1P_BIT)
#define TIMER_CCER_CC1E BIT(TIMER_CCER_CC1E_BIT)
@@ -463,24 +476,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
@@ -503,6 +516,45 @@ extern timer_dev *TIMER8;
#define TIMER_DCR_DBA_DCR 0x12
#define TIMER_DCR_DBA_DMAR 0x13
+/* Old, erroneous bit definitions from previous releases, kept for
+ * backwards compatibility: */
+/** 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
+
/*
* Convenience routines
*/
@@ -841,18 +893,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;
@@ -907,7 +960,7 @@ typedef enum 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
@@ -920,7 +973,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.
diff --git a/libmaple/rules.mk b/libmaple/rules.mk
index d118b16..2f5e066 100644
--- a/libmaple/rules.mk
+++ b/libmaple/rules.mk
@@ -20,6 +20,7 @@ cSRCS_$(d) += pwr.c
cSRCS_$(d) += rcc.c
cSRCS_$(d) += syscalls.c
cSRCS_$(d) += systick.c
+cSRCS_$(d) += timer.c
cSRCS_$(d) += usart.c
cSRCS_$(d) += usart_private.c
cSRCS_$(d) += util.c
@@ -29,7 +30,6 @@ cSRCS_$(d) += util.c
# cSRCS_$(d) += exti.c
# cSRCS_$(d) += i2c.c
# cSRCS_$(d) += spi.c
-# cSRCS_$(d) += timer.c
sSRCS_$(d) := exc.S
diff --git a/libmaple/stm32f1/include/series/timer.h b/libmaple/stm32f1/include/series/timer.h
new file mode 100644
index 0000000..3e2ab0f
--- /dev/null
+++ b/libmaple/stm32f1/include/series/timer.h
@@ -0,0 +1,97 @@
+/******************************************************************************
+ * 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 stm32f1/include/series/timer.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief STM32F1 timer sub-header.
+ */
+
+#ifndef _LIBMAPLE_STM32F1_TIMER_H_
+#define _LIBMAPLE_STM32F1_TIMER_H_
+
+#include <libmaple/libmaple.h>
+#include <series/timer.h>
+
+/*
+ * Register maps and devices
+ */
+
+/** 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;
+
+/** 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)
+#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 */
+#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
+
+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
+
+#endif
diff --git a/libmaple/stm32f1/rules.mk b/libmaple/stm32f1/rules.mk
index c0d6344..03fddb3 100644
--- a/libmaple/stm32f1/rules.mk
+++ b/libmaple/stm32f1/rules.mk
@@ -16,6 +16,7 @@ cSRCS_$(d) += bkp.c
cSRCS_$(d) += fsmc.c
cSRCS_$(d) += gpio.c
cSRCS_$(d) += rcc.c
+cSRCS_$(d) += timer.c
cSRCS_$(d) += usart.c
sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
diff --git a/libmaple/stm32f1/timer.c b/libmaple/stm32f1/timer.c
new file mode 100644
index 0000000..7506cb6
--- /dev/null
+++ b/libmaple/stm32f1/timer.c
@@ -0,0 +1,152 @@
+/******************************************************************************
+ * 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 support.
+ */
+
+#include <libmaple/timer.h>
+#include "timer_private.h"
+
+/*
+ * Devices
+ */
+
+/* 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);
+static DECLARE_GENERAL_TIMER(timer4, 4);
+
+/** Timer 1 device (advanced) */
+timer_dev *TIMER1 = &timer1;
+/** Timer 2 device (general-purpose) */
+timer_dev *TIMER2 = &timer2;
+/** Timer 3 device (general-purpose) */
+timer_dev *TIMER3 = &timer3;
+/** Timer 4 device (general-purpose) */
+timer_dev *TIMER4 = &timer4;
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+static DECLARE_GENERAL_TIMER(timer5, 5);
+static DECLARE_BASIC_TIMER(timer6, 6);
+static DECLARE_BASIC_TIMER(timer7, 7);
+static DECLARE_ADVANCED_TIMER(timer8, 8);
+
+/** Timer 5 device (general-purpose) */
+timer_dev *TIMER5 = &timer5;
+/** Timer 6 device (basic) */
+timer_dev *TIMER6 = &timer6;
+/** Timer 7 device (basic) */
+timer_dev *TIMER7 = &timer7;
+/** Timer 8 device (advanced) */
+timer_dev *TIMER8 = &timer8;
+#endif
+
+/*
+ * Routines
+ */
+
+/**
+ * @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);
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+ fn(TIMER5);
+ fn(TIMER6);
+ fn(TIMER7);
+ fn(TIMER8);
+#endif
+}
+
+/*
+ * IRQ handlers
+ */
+
+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
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;
diff --git a/libmaple/timer_private.h b/libmaple/timer_private.h
new file mode 100644
index 0000000..f882f51
--- /dev/null
+++ b/libmaple/timer_private.h
@@ -0,0 +1,168 @@
+/******************************************************************************
+ * 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_
+
+/*
+ * Devices
+ */
+
+/* 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
+
+#define DECLARE_ADVANCED_TIMER(name, num) \
+ timer_dev name = { \
+ .regs = { .adv = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_ADVANCED, \
+ .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, \
+ }
+
+#define DECLARE_GENERAL_TIMER(name, num) \
+ timer_dev name = { \
+ .regs = { .gen = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_GENERAL, \
+ .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, \
+ }
+
+#define DECLARE_BASIC_TIMER(name, num) \
+ timer_dev name = { \
+ .regs = { .bas = TIMER##num##_BASE }, \
+ .clk_id = RCC_TIMER##num, \
+ .type = TIMER_BASIC, \
+ .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, \
+ }
+
+/*
+ * IRQ handlers
+ */
+
+/* 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 __always_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 __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;
+}
+
+static __always_inline void dispatch_basic(timer_dev *dev) {
+ dispatch_single_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF);
+}
+
+#endif