aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/timers.h
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple/timers.h')
-rw-r--r--libmaple/timers.h335
1 files changed, 262 insertions, 73 deletions
diff --git a/libmaple/timers.h b/libmaple/timers.h
index cbdf088..99bcab6 100644
--- a/libmaple/timers.h
+++ b/libmaple/timers.h
@@ -82,7 +82,7 @@
extern "C"{
#endif
-typedef volatile uint32* TimerCCR;
+typedef volatile uint16* TimerCCR;
#define TIMER1_BASE 0x40012C00
#define TIMER2_BASE 0x40000000
@@ -96,47 +96,63 @@ typedef volatile uint32* TimerCCR;
#define ARPE BIT(7) // Auto-reload preload enable
#define NOT_A_TIMER 0
-#define TIMER_CCR(NUM,CHAN) TIMER ## NUM ## _CH ## CHAN ## _CRR
+#define TIMER_CCR(NUM,CHAN) (TIMER ## NUM ## _CH ## CHAN ## _CRR)
-#define TIMER1_CH1_CCR (TimerCCR)(TIMER1_BASE + 0x34)
-#define TIMER1_CH2_CCR (TimerCCR)(TIMER1_BASE + 0x38)
-#define TIMER1_CH3_CCR (TimerCCR)(TIMER1_BASE + 0x3C)
-#define TIMER1_CH4_CCR (TimerCCR)(TIMER1_BASE + 0x40)
+/* Timers 1-4 are present on the entire STM32 line. */
-#define TIMER2_CH1_CCR (TimerCCR)(TIMER2_BASE + 0x34)
-#define TIMER2_CH2_CCR (TimerCCR)(TIMER2_BASE + 0x38)
-#define TIMER2_CH3_CCR (TimerCCR)(TIMER2_BASE + 0x3C)
-#define TIMER2_CH4_CCR (TimerCCR)(TIMER2_BASE + 0x40)
+#define TIMER1_CH1_CCR ((TimerCCR)(TIMER1_BASE + 0x34))
+#define TIMER1_CH2_CCR ((TimerCCR)(TIMER1_BASE + 0x38))
+#define TIMER1_CH3_CCR ((TimerCCR)(TIMER1_BASE + 0x3C))
+#define TIMER1_CH4_CCR ((TimerCCR)(TIMER1_BASE + 0x40))
-#define TIMER3_CH1_CCR (TimerCCR)(TIMER3_BASE + 0x34)
-#define TIMER3_CH2_CCR (TimerCCR)(TIMER3_BASE + 0x38)
-#define TIMER3_CH3_CCR (TimerCCR)(TIMER3_BASE + 0x3C)
-#define TIMER3_CH4_CCR (TimerCCR)(TIMER3_BASE + 0x40)
+#define TIMER2_CH1_CCR ((TimerCCR)(TIMER2_BASE + 0x34))
+#define TIMER2_CH2_CCR ((TimerCCR)(TIMER2_BASE + 0x38))
+#define TIMER2_CH3_CCR ((TimerCCR)(TIMER2_BASE + 0x3C))
+#define TIMER2_CH4_CCR ((TimerCCR)(TIMER2_BASE + 0x40))
-#define TIMER4_CH1_CCR (TimerCCR)(TIMER4_BASE + 0x34)
-#define TIMER4_CH2_CCR (TimerCCR)(TIMER4_BASE + 0x38)
-#define TIMER4_CH3_CCR (TimerCCR)(TIMER4_BASE + 0x3C)
-#define TIMER4_CH4_CCR (TimerCCR)(TIMER4_BASE + 0x40)
+#define TIMER3_CH1_CCR ((TimerCCR)(TIMER3_BASE + 0x34))
+#define TIMER3_CH2_CCR ((TimerCCR)(TIMER3_BASE + 0x38))
+#define TIMER3_CH3_CCR ((TimerCCR)(TIMER3_BASE + 0x3C))
+#define TIMER3_CH4_CCR ((TimerCCR)(TIMER3_BASE + 0x40))
-/* Timer5 and Timer8 are in high-density devices only (such as Maple
- Native). Timer6 and Timer7 in these devices have no output compare
+#define TIMER4_CH1_CCR ((TimerCCR)(TIMER4_BASE + 0x34))
+#define TIMER4_CH2_CCR ((TimerCCR)(TIMER4_BASE + 0x38))
+#define TIMER4_CH3_CCR ((TimerCCR)(TIMER4_BASE + 0x3C))
+#define TIMER4_CH4_CCR ((TimerCCR)(TIMER4_BASE + 0x40))
+
+/* Timers 5 and 8 are in high-density devices only (such as Maple
+ Native). Timers 6 and 7 in these devices have no output compare
pins. */
-#define TIMER5_CH1_CCR (TimerCCR)(TIMER5_BASE + 0x34)
-#define TIMER5_CH2_CCR (TimerCCR)(TIMER5_BASE + 0x38)
-#define TIMER5_CH3_CCR (TimerCCR)(TIMER5_BASE + 0x3C)
-#define TIMER5_CH4_CCR (TimerCCR)(TIMER5_BASE + 0x40)
+#define TIMER5_CH1_CCR ((TimerCCR)(TIMER5_BASE + 0x34))
+#define TIMER5_CH2_CCR ((TimerCCR)(TIMER5_BASE + 0x38))
+#define TIMER5_CH3_CCR ((TimerCCR)(TIMER5_BASE + 0x3C))
+#define TIMER5_CH4_CCR ((TimerCCR)(TIMER5_BASE + 0x40))
-#define TIMER8_CH1_CCR (TimerCCR)(TIMER8_BASE + 0x34)
-#define TIMER8_CH2_CCR (TimerCCR)(TIMER8_BASE + 0x38)
-#define TIMER8_CH3_CCR (TimerCCR)(TIMER8_BASE + 0x3C)
-#define TIMER8_CH4_CCR (TimerCCR)(TIMER8_BASE + 0x40)
+#define TIMER8_CH1_CCR ((TimerCCR)(TIMER8_BASE + 0x34))
+#define TIMER8_CH2_CCR ((TimerCCR)(TIMER8_BASE + 0x38))
+#define TIMER8_CH3_CCR ((TimerCCR)(TIMER8_BASE + 0x3C))
+#define TIMER8_CH4_CCR ((TimerCCR)(TIMER8_BASE + 0x40))
-#define TIMER_DISABLED 0
-#define TIMER_PWM 1
-#define TIMER_OUTPUTCOMPARE 2
+/**
+ * Used to configure the behavior of a timer.
+ */
+typedef enum TimerMode {
+ TIMER_DISABLED, /**< In this mode, the timer stops counting,
+ interrupts are not called, and no state changes
+ are output. */
+ TIMER_PWM, /**< This is the default mode for pins after
+ initialization. */
+ TIMER_OUTPUTCOMPARE, /**< In this mode, the timer counts from 0 to
+ its reload value repeatedly; every time
+ the counter value reaches one of the
+ channel compare values, the corresponding
+ interrupt is fired. */
+} TimerMode;
typedef struct {
+ /* Fields up to ARR common to general purpose (2,3,4,5), advanced
+ control (1,8) and basic (6, 7) timers: */
volatile uint16 CR1;
uint16 RESERVED0;
volatile uint16 CR2;
@@ -161,8 +177,9 @@ typedef struct {
uint16 RESERVED10;
volatile uint16 ARR;
uint16 RESERVED11;
- volatile uint16 RCR;
- uint16 RESERVED12;
+ /* Basic timers have none of the following: */
+ volatile uint16 RCR; /* Advanced control timers only */
+ uint16 RESERVED12; /* Advanced control timers only */
volatile uint16 CCR1;
uint16 RESERVED13;
volatile uint16 CCR2;
@@ -171,25 +188,34 @@ typedef struct {
uint16 RESERVED15;
volatile uint16 CCR4;
uint16 RESERVED16;
- volatile uint16 BDTR; // Not used in general purpose timers
- uint16 RESERVED17; // Not used in general purpose timers
+ volatile uint16 BDTR; /* Advanced control timers only */
+ uint16 RESERVED17; /* Advanced control timers only */
volatile uint16 DCR;
uint16 RESERVED18;
volatile uint16 DMAR;
uint16 RESERVED19;
} timer_port;
-/* timer device numbers */
-enum {
- TIMER1,
- TIMER2,
- TIMER3,
- TIMER4,
- TIMER5, // High density only
- TIMER6, // High density only; no compare
- TIMER7, // High density only; no compare
- TIMER8, // High density only
-};
+/**
+ * Timer device numbers. See STM32 reference manual, chapters 13-15.
+ */
+/* several locations depend on TIMER1=0, etc.; don't change the
+ enumerator values to start at 1. */
+typedef enum {
+ TIMER1, /*< Advanced control timer TIM1 */
+ TIMER2, /*< General purpose timer TIM2 */
+ TIMER3, /*< General purpose timer TIM3 */
+ TIMER4, /*< General purpose timer TIM4 */
+#if NR_TIMERS >= 8
+ TIMER5, /*< General purpose timer TIM5; high density only */
+ /* FIXME maple native: put timers 6 and 7 back in and make the
+ corresponding changes to timers.c */
+ /* TIMER6, /\*< Basic timer TIM6; high density only *\/ */
+ /* TIMER7, /\*< Basic timer TIM7; high density only *\/ */
+ TIMER8, /*< Advanced control timer TIM8; high density only */
+#endif
+ TIMER_INVALID /* FIXME: this is starting to seem like a bad idea */
+} timer_dev_num;
/* timer descriptor */
struct timer_dev {
@@ -201,40 +227,203 @@ struct timer_dev {
extern struct timer_dev timer_dev_table[];
-/* Turn on timer with prescale as the divisor
- * void timer_init(uint32 timer, uint16 prescale)
- * timer -> {1-4}
- * prescale -> {1-65535}
+/**
+ * Initializes timer with prescale as the clock divisor.
+ *
+ * @param timer_num Timer number.
+ *
+ * @param prescale value in the range 1--65535 to use as a prescaler
+ * for timer counter increment frequency.
+ *
+ * @see timer_dev_num
+ * @see timer_set_prescaler()
+ * @see timer_set_mode()
+ */
+void timer_init(timer_dev_num timer_num, uint16 prescale);
+
+/**
+ * Quickly disable all timers. Calling this function is faster than,
+ * e.g., calling timer_set_mode() for all available timers/channels.
*/
-void timer_init(uint8, uint16);
void timer_disable_all(void);
-uint16 timer_get_count(uint8);
-void timer_set_count(uint8,uint16);
-void timer_pause(uint8);
-void timer_resume(uint8);
-void timer_set_prescaler(uint8 timer_num, uint16 prescale);
-void timer_set_reload(uint8 timer_num, uint16 max_reload);
-void timer_set_mode(uint8 timer_num, uint8 compare_num, uint8 mode);
-void timer_set_compare_value(uint8 timer_num, uint8 compare_num, uint16 value);
-void timer_attach_interrupt(uint8 timer_num, uint8 compare_num,
+
+/**
+ * Returns the timer's counter value. Due to function call overhead,
+ * this value is likely to be inaccurate if the counter is running
+ * with a low prescaler.
+ *
+ * @param timer_num the timer whose counter to return.
+ *
+ * @pre Timer has been initialized.
+ */
+uint16 timer_get_count(timer_dev_num timer_num);
+
+/**
+ * Sets the counter value for the given timer.
+ *
+ * @param timer_num the timer whose counter to set.
+ *
+ * @param value the new counter value.
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_set_count(timer_dev_num timer_num, uint16 value);
+
+/**
+ * Stops the timer's counter from incrementing. Does not modify the
+ * timer's mode or settings.
+ *
+ * @param timer_num the timer to pause.
+ *
+ * @see timer_resume()
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_pause(timer_dev_num timer_num);
+
+/**
+ * Starts the counter for the given timer. Does not modify the
+ * timer's mode or settings. The timer will begin counting on the
+ * first rising clock cycle after it has been re-enabled using this
+ * function.
+ *
+ * @param timer_num the timer to resume.
+ *
+ * @see timer_pause()
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_resume(timer_dev_num timer_num);
+
+/**
+ * Returns the prescaler for the given timer.
+ *
+ * @param timer_num the timer whose prescaler to return.
+ *
+ * @see timer_set_prescaler()
+ *
+ * @pre Timer has been initialized.
+ */
+uint16 timer_get_prescaler(timer_dev_num timer_num);
+
+/**
+ * Sets the prescaler for the given timer. This value goes into the
+ * PSC register, so it's 0-based (i.e., a prescale of 0 counts 1 tick
+ * per clock cycle). This prescale does not take effect until the
+ * next update event.
+ *
+ * @param timer_num the timer whose prescaler to set.
+ *
+ * @param prescale the new prescaler.
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale);
+
+/**
+ * Gets the reload value for the timer.
+ *
+ * @see timer_set_reload()
+ *
+ * @pre Timer has been initialized.
+ */
+uint16 timer_get_reload(timer_dev_num timer_num);
+
+/**
+ * Sets the reload value for the timer.
+ *
+ * After this function returns, the timer's counter will reset to 0
+ * after it has reached the value max_reload.
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_set_reload(timer_dev_num timer_num, uint16 max_reload);
+
+/* TODO: timer_get_mode */
+
+/**
+ * Set the mode of an individual timer channel.
+ *
+ * @see timer_disable_all()
+ * @see TimerMode
+ * @see timer_dev_num
+ * @pre Timer has been initialized.
+ */
+void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode);
+
+/**
+ * Get the compare value for the given timer channel.
+ * @see timer_set_compare_value()
+ * @see timer_dev_num
+ * @pre Timer has been initialized.
+ */
+uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel);
+
+/**
+ * Sets the compare value for a given timer channel. Useful for
+ * scheduling when interrupt handlers will be called.
+ *
+ * @see timer_attach_interrupt()
+ * @see timer_detach_interrupt()
+ * @see timer_set_reload()
+ * @see timer_dev_num
+ * @pre Timer has been initialized.
+ */
+void timer_set_compare_value(timer_dev_num timer_num, uint8 channel,
+ uint16 value);
+
+/**
+ * Detach the interrupt handler for the given timer channel, if any.
+ * After this function returns, any handler attached to the given
+ * channel will no longer be called.
+ *
+ * @see timer_attach_interrupt()
+ * @pre Timer has been initialized.
+ * @see timer_dev_num
+ */
+void timer_detach_interrupt(timer_dev_num timer_num, uint8 channel);
+
+/**
+ * Attach an interrupt handler for the given timer and channel. The
+ * given ISR, handler, will be called whenever the timer's counter
+ * reaches the compare value for the given timer and channel.
+ *
+ * @see timer_set_compare_value()
+ * @see timer_detach_interrupt()
+ * @see timer_set_mode()
+ * @see timer_dev_num
+ * @see voidFuncPtr
+ * @pre Timer has been initialized.
+ * @pre The channel's mode must be set to TIMER_OUTPUTCOMPARE, or the
+ * interrupt handler will not get called.
+ */
+void timer_attach_interrupt(timer_dev_num timer_num, uint8 channel,
voidFuncPtr handler);
-void timer_detach_interrupt(uint8 timer_num, uint8 compare_num);
-/* Turn on PWM with duty_cycle on the specified channel in timer.
- * This function takes in a pointer to the corresponding CCR
- * register for the pin cause it saves pwmWrite() a couple of
- * cycles.
+/**
+ * Programmatically generate an update event on the given timer. This
+ * updates the prescaler, reloads the compare value (in upcounting
+ * mode, etc.).
+ *
+ * @pre Timer has been initialized.
+ */
+void timer_generate_update(timer_dev_num timer_num);
+
+/**
+ * Turn on PWM with duty_cycle.
+ *
+ * @param ccr TIMERx_CHn_CCR, where x goes from 1 to NR_TIMERS,
+ * and n goes from 1 to 4.
+ *
+ * @param duty_cycle: A number between 0 and
+ * timer_get_compare_value(TIMERx, y), where x and y are as above.
*
- * void timer_pwm(uint8 channel, uint8 duty_cycle);
- * channel -> {TIMERx_CHn_CCR}
- * duty_cycle -> {0-65535}
+ * @pre Pin has been set to alternate function output.
*
- * PRECONDITIONS:
- * pin has been set to alternate function output
- * timer has been initialized
+ * @pre Timer has been initialized.
*/
-static inline void timer_pwm_write_ccr(TimerCCR CCR, uint16 duty_cycle) {
- *CCR = duty_cycle;
+static inline void timer_pwm_write_ccr(TimerCCR ccr, uint16 duty_cycle) {
+ *ccr = duty_cycle;
}
#ifdef __cplusplus