From b67d281d85bd59a9738a9a43c4db1027f81d9208 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 8 Dec 2010 23:39:37 -0500 Subject: Servo library tested and debugged. Some additional HardwareTimer methods introduced to make this convenient; ancillary libmaple/timers.h changes resulted. --- libmaple/timers.c | 84 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 21 deletions(-) (limited to 'libmaple/timers.c') 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. * -- cgit v1.2.3