aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/timers.c
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@mit.edu>2010-12-08 23:39:37 -0500
committerMarti Bolivar <mbolivar@mit.edu>2010-12-08 23:39:37 -0500
commitb67d281d85bd59a9738a9a43c4db1027f81d9208 (patch)
tree1940b4743a945160d21eb37c8578fa46e9118d4e /libmaple/timers.c
parentb34f826ae1470aaa791bd8ed8dd66ccd4d96d82c (diff)
downloadlibrambutan-b67d281d85bd59a9738a9a43c4db1027f81d9208.tar.gz
librambutan-b67d281d85bd59a9738a9a43c4db1027f81d9208.zip
Servo library tested and debugged.
Some additional HardwareTimer methods introduced to make this convenient; ancillary libmaple/timers.h changes resulted.
Diffstat (limited to 'libmaple/timers.c')
-rw-r--r--libmaple/timers.c84
1 files changed, 63 insertions, 21 deletions
diff --git a/libmaple/timers.c b/libmaple/timers.c
index c369d1f..29aeeba 100644
--- a/libmaple/timers.c
+++ b/libmaple/timers.c
@@ -73,16 +73,20 @@ struct timer_dev timer_dev_table[] = {
/* This function should probably be rewriten to take (timer_num, mode)
* and have prescaler set elsewhere. The mode can be passed through to
* set_mode at the end */
-void timer_init(uint8 timer_num, uint16 prescale) {
+void timer_init(timer_dev_num timer_num, uint16 prescale) {
/* TODO: doesn't catch 6+7 */
- ASSERT((timer_num != TIMER6) && (timer_num != TIMER7));
timer_port *timer = timer_dev_table[timer_num].base;
uint8 is_advanced = 0;
- if((timer_num == TIMER1) || (timer_num == TIMER8)) {
+ if (timer_num == TIMER1) {
is_advanced = 1;
}
+#if NR_TIMERS >= 8
+ if (timer_num == TIMER8) {
+ is_advanced = 1;
+ }
+#endif
rcc_clk_enable(timer_dev_table[timer_num].rcc_dev_num);
@@ -125,48 +129,61 @@ void timer_init(uint8 timer_num, uint16 prescale) {
}
/* Stops the counter; the mode and settings are not modified */
-void timer_pause(uint8 timer_num) {
+void timer_pause(timer_dev_num timer_num) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->CR1 &= ~(0x0001); // CEN
}
/* Starts the counter; the mode and settings are not modified */
-void timer_resume(uint8 timer_num) {
+void timer_resume(timer_dev_num timer_num) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->CR1 |= 0x0001; // CEN
}
+/* Returns the current timer counter value. Probably very inaccurate
+ * if the counter is running with a low prescaler. */
+uint16 timer_get_count(timer_dev_num timer_num) {
+ timer_port *timer = timer_dev_table[timer_num].base;
+
+ return timer->CNT;
+}
+
/* This function sets the counter value via register for the specified
* timer. Can't think of specific usecases except for resetting to
* zero but it's easy to implement and allows for "creative"
* programming */
-void timer_set_count(uint8 timer_num, uint16 value) {
+void timer_set_count(timer_dev_num timer_num, uint16 value) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->CNT = value;
}
-/* Returns the current timer counter value. Probably very inaccurate
- * if the counter is running with a low prescaler. */
-uint16 timer_get_count(uint8 timer_num) {
+/* Get the prescaler buffer value (remember, the actual prescaler
+ * doesn't get set until an update event). */
+uint16 timer_get_prescaler(timer_dev_num timer_num) {
timer_port *timer = timer_dev_table[timer_num].base;
-
- return timer->CNT;
+ return timer->PSC;
}
/* Sets the prescaler */
-void timer_set_prescaler(uint8 timer_num, uint16 prescale) {
+void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->PSC = prescale;
}
+/* Get the reload value for the entire timer. */
+uint16 timer_get_reload(timer_dev_num timer_num) {
+ timer_port *timer = timer_dev_table[timer_num].base;
+ return timer->ARR;
+}
+
/* This sets the "reload" or "overflow" value for the entire timer. We
* should probably settle on either "reload" or "overflow" to prevent
* confusion? */
-void timer_set_reload(uint8 timer_num, uint16 max_reload) {
+void timer_set_reload(timer_dev_num timer_num, uint16 max_reload) {
timer_port *timer = timer_dev_table[timer_num].base;
timer->ARR = max_reload;
@@ -211,7 +228,7 @@ void timer_disable_all(void) {
}
/* Sets the mode of individual timer channels, including a DISABLE mode */
-void timer_set_mode(uint8 timer_num, uint8 channel, TimerMode mode) {
+void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode) {
timer_port *timer = timer_dev_table[timer_num].base;
ASSERT(channel >= 1);
@@ -286,18 +303,36 @@ void timer_set_mode(uint8 timer_num, uint8 channel, TimerMode mode) {
}
}
+uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel_num) {
+ /* faster: just read TIMERx_CHy_CCR (see timers.h) */
+ ASSERT(channel_num > 0 && channel_num <= 4);
+ timer_port *timer = timer_dev_table[timer_num].base;
+ switch(channel_num) {
+ case 1:
+ return timer->CCR1;
+ case 2:
+ return timer->CCR2;
+ case 3:
+ return timer->CCR3;
+ case 4:
+ return timer->CCR4;
+ default: /* in case ASSERT is disabled */
+ return 0;
+ }
+}
+
/* This sets the compare value (aka the trigger) for a given timer
* channel */
-void timer_set_compare_value(uint8 timer_num,
- uint8 compare_num,
+void timer_set_compare_value(timer_dev_num timer_num,
+ uint8 channel_num,
uint16 value) {
+ ASSERT(channel_num > 0 && channel_num <= 4);
+
/* The faster version of this function is the inline
timer_pwm_write_ccr */
timer_port *timer = timer_dev_table[timer_num].base;
- ASSERT(compare_num > 0 && compare_num <= 4);
-
- switch(compare_num) {
+ switch(channel_num) {
case 1:
timer->CCR1 = value;
break;
@@ -315,7 +350,7 @@ void timer_set_compare_value(uint8 timer_num,
/* Stores a pointer to the passed usercode interrupt function and configures
* the actual ISR so that it will actually be called */
-void timer_attach_interrupt(uint8 timer_num,
+void timer_attach_interrupt(timer_dev_num timer_num,
uint8 compare_num,
voidFuncPtr handler) {
ASSERT(compare_num > 0 && compare_num <= 4);
@@ -327,7 +362,7 @@ void timer_attach_interrupt(uint8 timer_num,
nvic_irq_enable(timer_dev_table[timer_num].nvic_dev_num);
}
-void timer_detach_interrupt(uint8 timer_num, uint8 compare_num) {
+void timer_detach_interrupt(timer_dev_num timer_num, uint8 compare_num) {
ASSERT(compare_num > 0 && compare_num <= 4);
timer_port *timer = timer_dev_table[timer_num].base;
@@ -336,6 +371,13 @@ void timer_detach_interrupt(uint8 timer_num, uint8 compare_num) {
timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums
}
+void timer_generate_update(timer_dev_num timer_num) {
+ /* cause update event by setting UG bit in EGR. updates prescaler
+ ratio etc. */
+ timer_port *timer = timer_dev_table[timer_num].base;
+ timer->EGR |= 0x1;
+}
+
/* The following are the actual interrupt handlers; 1 for each timer which must
* determine which actual compare value (aka channel) was triggered.
*