diff options
author | Marti Bolivar <mbolivar@mit.edu> | 2010-12-14 15:41:17 -0500 |
---|---|---|
committer | Marti Bolivar <mbolivar@mit.edu> | 2010-12-14 15:41:17 -0500 |
commit | 74c8937446e1be4e0d21f69a8c098e2caf7814d5 (patch) | |
tree | 1c7b8e4d93a9512ee54cdd6c5bb7ede064f96b3e /libmaple | |
parent | 5ceac644e90c929e77f05d357d1d35d45e673fac (diff) | |
parent | b67d281d85bd59a9738a9a43c4db1027f81d9208 (diff) | |
download | librambutan-74c8937446e1be4e0d21f69a8c098e2caf7814d5.tar.gz librambutan-74c8937446e1be4e0d21f69a8c098e2caf7814d5.zip |
Merge branch 'master' into newdoc
Diffstat (limited to 'libmaple')
-rw-r--r-- | libmaple/gpio.h | 26 | ||||
-rw-r--r-- | libmaple/timers.c | 84 | ||||
-rw-r--r-- | libmaple/timers.h | 210 |
3 files changed, 218 insertions, 102 deletions
diff --git a/libmaple/gpio.h b/libmaple/gpio.h index 49360ee..53f77c4 100644 --- a/libmaple/gpio.h +++ b/libmaple/gpio.h @@ -42,15 +42,18 @@ * Alternate function open-drain * * - After reset, the alternate functions are not active and IO prts - * are set to Input Floating mode */ + * are set to Input Floating mode, EXCEPT for the Serial Wire and JTAG + * ports, which are in alternate function mode by default. */ -#define GPIOA_BASE (GPIO_Port*)0x40010800 -#define GPIOB_BASE (GPIO_Port*)0x40010C00 -#define GPIOC_BASE (GPIO_Port*)0x40011000 -#define GPIOD_BASE (GPIO_Port*)0x40011400 -#define GPIOE_BASE (GPIO_Port*)0x40011800 // High-density devices only -#define GPIOF_BASE (GPIO_Port*)0x40011C00 // High-density devices only -#define GPIOG_BASE (GPIO_Port*)0x40012000 // High-density devices only +#define AFIO_MAPR ((volatile uint32*)0x40010004) + +#define GPIOA_BASE ((GPIO_Port*)0x40010800) +#define GPIOB_BASE ((GPIO_Port*)0x40010C00) +#define GPIOC_BASE ((GPIO_Port*)0x40011000) +#define GPIOD_BASE ((GPIO_Port*)0x40011400) +#define GPIOE_BASE ((GPIO_Port*)0x40011800) // High-density devices only +#define GPIOF_BASE ((GPIO_Port*)0x40011C00) // High-density devices only +#define GPIOG_BASE ((GPIO_Port*)0x40012000) // High-density devices only #define GPIO_SPEED_50MHZ (0x3) @@ -109,6 +112,13 @@ static inline uint32 gpio_read_bit(GPIO_Port *port, uint8 gpio_pin) { return (port->IDR & BIT(gpio_pin) ? 1 : 0); } +/* For pins configured as output push-pull, reading the ODR returns + * the last value written in push-pull mode. + */ +static inline void gpio_toggle_pin(GPIO_Port *port, uint8 gpio_pin) { + port->ODR = port->ODR ^ BIT(gpio_pin); +} + #ifdef __cplusplus } // extern "C" #endif diff --git a/libmaple/timers.c b/libmaple/timers.c index 3a2cad7..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 channel, +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(channel > 0 && channel <= 4); - - switch(channel) { + 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. * diff --git a/libmaple/timers.h b/libmaple/timers.h index f5694ac..7589283 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,41 +96,43 @@ 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 TIMER1_BASE + 0x34 -#define TIMER1_CH2_CCR TIMER1_BASE + 0x38 -#define TIMER1_CH3_CCR TIMER1_BASE + 0x3C -#define TIMER1_CH4_CCR TIMER1_BASE + 0x40 +/* Timers 1-4 are present on the entire STM32 line. */ -#define TIMER2_CH1_CCR TIMER2_BASE + 0x34 -#define TIMER2_CH2_CCR TIMER2_BASE + 0x38 -#define TIMER2_CH3_CCR TIMER2_BASE + 0x3C -#define TIMER2_CH4_CCR 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 TIMER3_BASE + 0x34 -#define TIMER3_CH2_CCR TIMER3_BASE + 0x38 -#define TIMER3_CH3_CCR TIMER3_BASE + 0x3C -#define TIMER3_CH4_CCR 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 TIMER4_BASE + 0x34 -#define TIMER4_CH2_CCR TIMER4_BASE + 0x38 -#define TIMER4_CH3_CCR TIMER4_BASE + 0x3C -#define TIMER4_CH4_CCR 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 TIMER5_BASE + 0x34 -#define TIMER5_CH2_CCR TIMER5_BASE + 0x38 -#define TIMER5_CH3_CCR TIMER5_BASE + 0x3C -#define TIMER5_CH4_CCR 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 TIMER8_BASE + 0x34 -#define TIMER8_CH2_CCR TIMER8_BASE + 0x38 -#define TIMER8_CH3_CCR TIMER8_BASE + 0x3C -#define TIMER8_CH4_CCR 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)) /** * Used to configure the behavior of a timer. @@ -149,6 +151,8 @@ typedef enum TimerMode { } 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; @@ -173,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; @@ -183,8 +188,8 @@ 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; @@ -192,18 +197,23 @@ typedef struct { } timer_port; /** - * All possible timer device numbers. + * 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, - TIMER2, - TIMER3, - TIMER4, - TIMER5, // High density only - TIMER6, // High density only; no compare - TIMER7, // High density only; no compare - TIMER8, // High density only -} timer_num_t; + 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 */ + /* 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 { @@ -216,7 +226,7 @@ struct timer_dev { extern struct timer_dev timer_dev_table[]; /** - * Turn on timer with prescale as the clock divisor. + * Initializes timer with prescale as the clock divisor. * * @param timer Timer number. Valid values are TIMER1, TIMER2, * TIMER3, TIMER4, and (on high-density devices) TIMER5, TIMER8. @@ -227,7 +237,7 @@ extern struct timer_dev timer_dev_table[]; * @see timer_set_prescaler() * @see timer_set_mode() */ -void timer_init(uint8 timer, uint16 prescale); +void timer_init(timer_dev_num, uint16); /** * Quickly disable all timers. Calling this function is faster than, @@ -241,8 +251,10 @@ void timer_disable_all(void); * with a low prescaler. * * @param timer the timer whose counter to return. + * + * @pre Timer has been initialized. */ -uint16 timer_get_count(uint8 timer); +uint16 timer_get_count(timer_dev_num); /** * Sets the counter value for the given timer. @@ -250,8 +262,10 @@ uint16 timer_get_count(uint8 timer); * @param timer the timer whose counter to set. * * @param value the new counter value. + * + * @pre Timer has been initialized. */ -void timer_set_count(uint8 timer, uint16 value); +void timer_set_count(timer_dev_num,uint16); /** * Stops the timer's counter from incrementing. Does not modify the @@ -260,8 +274,10 @@ void timer_set_count(uint8 timer, uint16 value); * @param timer the timer to pause. * * @see timer_resume() + * + * @pre Timer has been initialized. */ -void timer_pause(uint8 timer); +void timer_pause(timer_dev_num); /** * Starts the counter for the given timer. Does not modify the @@ -272,28 +288,45 @@ void timer_pause(uint8 timer); * @param timer the timer to resume. * * @see timer_pause() + * + * @pre Timer has been initialized. */ -void timer_resume(uint8 timer); +void timer_resume(timer_dev_num); /** - * Sets the prescaler for the given timer. The prescaler acts as a - * clock divider of the STM32 72MHz system clock, in that the timer's - * counter will subsequently increment with frequency equal to 72MHz / - * prescale. + * Returns the prescaler for the given timer. + * + * @see timer_set_prescaler() * - * Note that the timer will continue with its current prescaler until - * the next time its counter reaches its overflow value, starting a - * counting cycle. The new prescale value will be in effect for that - * subsequent counting cycle. + * @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 the timer whose prescaler to set. * - * @param prescale the new prescaler, from 1--65,535. + * @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. */ -void timer_set_prescaler(uint8 timer, uint16 prescale); +uint16 timer_get_reload(timer_dev_num timer_num); /** - * Sets the reload value for the entire timer. + * 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. @@ -301,8 +334,12 @@ void timer_set_prescaler(uint8 timer, uint16 prescale); * @param timer the timer whose reload to set. * * @param max_reload the new reload value. + * + * @pre Timer has been initialized. */ -void timer_set_reload(uint8 timer, uint16 max_reload); +void timer_set_reload(timer_dev_num timer_num, uint16 max_reload); + +/* TODO: timer_get_mode */ /** * Set the mode of an individual timer channel. @@ -320,8 +357,18 @@ void timer_set_reload(uint8 timer, uint16 max_reload); * @see TimerMode * * @see timer_disable_all() + * + * @pre Timer has been initialized. */ -void timer_set_mode(uint8 timer, uint8 channel, TimerMode mode); +void timer_set_mode(timer_dev_num timer_num, uint8 channel_num, uint8 mode); + +/** + * Get the compare value for the given timer channel. + * @see timer_set_compare_value() + * + * @pre Timer has been initialized. + */ +uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel_num); /** * Sets the compare value for a given timer channel. Useful for @@ -339,8 +386,27 @@ void timer_set_mode(uint8 timer, uint8 channel, TimerMode mode); * @see timer_detach_interrupt() * * @see timer_set_reload() + * + * @pre Timer has been initialized. + */ +void timer_set_compare_value(timer_dev_num timer_num, uint8 channel_num, + 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. + * + * @param timer the timer whose channel to detach the interrupt + * handler from. + * + * @param channel the channel from which to detach the interrupt handler. + * + * @see timer_attach_interrupt() + * + * @pre Timer has been initialized. */ -void timer_set_compare_value(uint8 timer, uint8 channel, uint16 compare); +void timer_detach_interrupt(timer_dev_num timer_num, uint8 channel_num); /** * Attach an interrupt handler for the given timer and channel. The @@ -365,22 +431,20 @@ void timer_set_compare_value(uint8 timer, uint8 channel, uint16 compare); * @see timer_detach_interrupt() * * @see timer_set_mode() + * + * @pre Timer has been initialized. */ -void timer_attach_interrupt(uint8 timer, uint8 channel, voidFuncPtr handler); +void timer_attach_interrupt(timer_dev_num timer_num, uint8 channel_num, + voidFuncPtr handler); /** - * 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. - * - * @param timer the timer whose channel to detach the interrupt - * handler from. + * Programmatically generate an update event on the given timer. This + * updates the prescaler, reloads the compare value (in upcounting + * mode, etc.). * - * @param channel the channel from which to detach the interrupt handler. - * - * @see timer_attach_interrupt() + * @pre Timer has been initialized. */ -void timer_detach_interrupt(uint8 timer, uint8 channel); +void timer_generate_update(timer_dev_num timer_num); /** * Turn on PWM with duty_cycle. |