From f06fcac502619bc7f6155aa75947dc4340efccd5 Mon Sep 17 00:00:00 2001 From: bnewbold Date: Sat, 12 Jun 2010 22:54:11 -0400 Subject: good quality vga leaf logo; usb+systick disabled refactored timers and added interrupt behavior. see notes and comments... also includes a crude vga hack that doesn't use timers. --- libmaple/timers.c | 415 ++++++++++++++++++++++++++++++++++++++++++++++++++---- libmaple/timers.h | 21 ++- libmaple/util.c | 2 +- 3 files changed, 404 insertions(+), 34 deletions(-) (limited to 'libmaple') diff --git a/libmaple/timers.c b/libmaple/timers.c index b13cc3a..a772cf9 100644 --- a/libmaple/timers.c +++ b/libmaple/timers.c @@ -75,9 +75,17 @@ typedef struct { uint16 RESERVED19; } Timer; + +volatile static voidFuncPtr timer1_handlers[4]; +volatile static voidFuncPtr timer2_handlers[4]; +volatile static voidFuncPtr timer3_handlers[4]; +volatile static voidFuncPtr timer4_handlers[4]; + void timer_init(uint8 timer_num, uint16 prescale) { - Timer *timer; - uint32 is_advanced = 0; + // This initialization is very PWM-specific. That's a good default but it + // should probably call down to a set_mode function + + Timer *timer; uint8 is_advanced = 0; ASSERT(timer_num > 0 && timer_num <= 4); @@ -118,7 +126,7 @@ void timer_init(uint8 timer_num, uint16 prescale) { * we'll worry about that later. */ timer->CCR1 = 0x8FFF; // PWM start value timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register. - timer->CCER |= 0x001; // enable ch + timer->CCER |= 0x002; // enable ch timer->CCR2 = 0x8FFF; // PWM start value timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register. @@ -137,12 +145,13 @@ void timer_init(uint8 timer_num, uint16 prescale) { timer->BDTR = 0x8000; // moe enable } + timer->SR = 0; // clear it timer->DIER = 0; // disable update interrupt timer->EGR = 1; // Initialize update event and shadow registers timer->CR1 |= 1; // Enable timer } -void timers_set_prescaler(uint32 timer_num, uint16 prescale) { +void timer_set_count(uint8 timer_num, uint16 value) { Timer *timer; ASSERT(timer_num > 0 && timer_num <= 4); @@ -160,10 +169,10 @@ void timers_set_prescaler(uint32 timer_num, uint16 prescale) { timer = (Timer*)TIMER4_BASE; break; } - timer->PSC = prescale; + timer->CNT = value; } -void timers_set_reload(uint32 timer_num, uint16 max_reload) { +uint16 timer_get_count(uint8 timer_num) { Timer *timer; ASSERT(timer_num > 0 && timer_num <= 4); @@ -181,28 +190,61 @@ void timers_set_reload(uint32 timer_num, uint16 max_reload) { timer = (Timer*)TIMER4_BASE; break; } - timer->ARR = max_reload; + return timer->CNT; } +void timer_set_prescaler(uint8 timer_num, uint16 prescale) { + Timer *timer; + ASSERT(timer_num > 0 && timer_num <= 4); -void timers_disable(void) { + switch(timer_num) { + case 1: + timer = (Timer*)TIMER1_BASE; + break; + case 2: + timer = (Timer*)TIMER2_BASE; + break; + case 3: + timer = (Timer*)TIMER3_BASE; + break; + case 4: + timer = (Timer*)TIMER4_BASE; + break; + } + timer->PSC = prescale; +} + +void timer_set_reload(uint8 timer_num, uint16 max_reload) { Timer *timer; - int i; - Timer *timers[4] = { - (Timer*)TIMER1_BASE, - (Timer*)TIMER2_BASE, - (Timer*)TIMER3_BASE, - (Timer*)TIMER4_BASE, - }; - - for (i = 0; i < 4; i++) { - timer = timers[i]; - timer->CR1 = 0; - timer->CCER = 0; + ASSERT(timer_num > 0 && timer_num <= 4); + + switch(timer_num) { + case 1: + timer = (Timer*)TIMER1_BASE; + break; + case 2: + timer = (Timer*)TIMER2_BASE; + break; + case 3: + timer = (Timer*)TIMER3_BASE; + break; + case 4: + timer = (Timer*)TIMER4_BASE; + break; } + timer->ARR = max_reload; } -void timers_disable_channel(uint8 timer_num, uint8 channel) { + +void timer_disable_all(void) { + // Note: this must be very robust because it gets called from, eg, ASSERT + // TODO: rewrite? + Timer *timer; Timer *timers[4] = { (Timer*)TIMER1_BASE, + (Timer*)TIMER2_BASE, (Timer*)TIMER3_BASE, (Timer*)TIMER4_BASE, }; int i; + for (i = 0; i < 4; i++) { timer = timers[i]; timer->CR1 = 0; timer->CCER = + 0; } } + +void timer_set_mode(uint8 timer_num, uint8 channel, uint8 mode) { Timer *timer; switch (timer_num) { case 1: @@ -220,21 +262,338 @@ void timers_disable_channel(uint8 timer_num, uint8 channel) { default: ASSERT(0); } + switch(mode) { + case TIMER_DISABLED: + // Disable the channel + // Disable any interrupt + // Clear interrupt SR? (TODO) + switch (channel) { + case 1: + timer->DIER &= ~(1 << channel); // 1-indexed compare nums + timer->CCER &= ~(0x1); + break; + case 2: + timer->DIER &= ~(1 << channel); // 1-indexed compare nums + timer->CCER &= ~(0x10); + break; + case 3: + timer->DIER &= ~(1 << channel); // 1-indexed compare nums + timer->CCER &= ~(0x100); + break; + case 4: + timer->DIER &= ~(1 << channel); // 1-indexed compare nums + timer->CCER &= ~(0x1000); + break; + default: + ASSERT(0); + } + break; + case TIMER_PWM: + // Set CCMR mode + // Keep existing reload value + // Disable any interrupt + // Clear interrupt SR? (TODO) + // Enable channel + switch (channel) { + case 1: + timer->DIER &= ~(1 << channel); // 1-indexed compare nums + timer->CCMR1 &= ~(0xFF); + timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register. + timer->CCER |= 0x0001; // enable ch + break; + case 2: + timer->DIER &= ~(1 << channel); // 1-indexed compare nums + timer->CCMR1 &= ~(0xFF00); + timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register. + timer->CCER |= 0x0010; // enable ch + break; + case 3: + timer->DIER &= ~(1 << channel); // 1-indexed compare nums + timer->CCMR2 &= ~(0xFF); + timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register. + timer->CCER |= 0x0100; // enable ch + break; + case 4: + timer->DIER &= ~(1 << channel); // 1-indexed compare nums + timer->CCMR2 &= ~(0xFF00); + timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register. + timer->CCER |= 0x1000; // enable ch + break; + default: + ASSERT(0); + } + case TIMER_OUTPUTCOMPARE: + // Set CCMR mode + // Keep existing reload value + // Don't modify interrupt (needs to be attached to enable) + // Clear interrupt SR? (TODO) + // Enable channel + switch (channel) { + case 1: + timer->CCMR1 &= ~(0xFF); + timer->CCMR1 |= 0x0010; // PWM mode 1, enable preload register. + timer->CCER |= 0x001; // enable ch + break; + case 2: + timer->CCMR1 &= ~(0xFF00); + timer->CCMR1 |= 0x1000; // PWM mode 1, enable preload register. + timer->CCER |= 0x0010; // enable ch + break; + case 3: + timer->CCMR2 &= ~(0xFF); + timer->CCMR2 |= 0x0010; // PWM mode 1, enable preload register. + timer->CCER |= 0x0100; // enable ch + break; + case 4: + timer->CCMR2 &= ~(0xFF00); + timer->CCMR2 |= 0x1000; // PWM mode 1, enable preload register. + timer->CCER |= 0x1000; // enable ch + break; + default: + ASSERT(0); + } + break; + // TODO: others + default: + ASSERT(0); + } +} - switch (channel) { +void timer_set_compare_value(uint8 timer_num, uint8 compare_num, uint16 value) { + // The faster version of this function is the inline timer_pwm_write_ccr + + Timer *timer; TimerCCR *timer_ccr; ASSERT(timer_num > 0 && timer_num <= 4 + && compare_num > 0 && compare_num <= 4); + + switch(timer_num) { case 1: - timer->CCER &= ~(0x1); + timer = (Timer*)TIMER1_BASE; break; case 2: - timer->CCER &= ~(0x10); + timer = (Timer*)TIMER2_BASE; break; case 3: - timer->CCER &= ~(0x100); + timer = (Timer*)TIMER3_BASE; break; case 4: - timer->CCER &= ~(0x1000); + timer = (Timer*)TIMER4_BASE; break; - default: - ASSERT(0); + } + switch(compare_num) { + case 1: + timer->CCR1 = value; + break; + case 2: + timer->CCR2 = value; + break; + case 3: + timer->CCR3 = value; + break; + case 4: + timer->CCR4 = value; + break; + } +} + +void timer_attach_interrupt(uint8 timer_num, uint8 compare_num, voidFuncPtr handler) { + Timer *timer; + ASSERT(timer_num > 0 && timer_num <= 4 && compare_num > 0 && compare_num <= 4); + + switch(timer_num) { + case 1: + timer = (Timer*)TIMER1_BASE; + timer1_handlers[compare_num-1] = handler; + nvic_enable_interrupt(27); + timer->DIER |= (1 << compare_num); // 1-indexed compare nums + break; + case 2: + timer = (Timer*)TIMER2_BASE; + timer2_handlers[compare_num-1] = handler; + nvic_enable_interrupt(28); + timer->DIER |= (1 << compare_num); // 1-indexed compare nums + break; + case 3: + timer = (Timer*)TIMER3_BASE; + timer3_handlers[compare_num-1] = handler; + nvic_enable_interrupt(29); + timer->DIER |= (1 << compare_num); // 1-indexed compare nums + break; + case 4: + timer = (Timer*)TIMER4_BASE; + timer4_handlers[compare_num-1] = handler; + nvic_enable_interrupt(30); + timer->DIER |= (1 << compare_num); // 1-indexed compare nums + break; + } +} + +void timer_detach_interrupt(uint8 timer_num, uint8 compare_num) { + Timer *timer; + ASSERT(timer_num > 0 && timer_num <= 4 && compare_num > 0 && compare_num <= 4); + + switch(timer_num) { + case 1: + timer = (Timer*)TIMER1_BASE; + timer1_handlers[compare_num-1] = 0; + timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums + break; + case 2: + timer = (Timer*)TIMER2_BASE; + timer2_handlers[compare_num-1] = 0; + timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums + break; + case 3: + timer = (Timer*)TIMER3_BASE; + timer3_handlers[compare_num-1] = 0; + timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums + break; + case 4: + timer = (Timer*)TIMER4_BASE; + timer4_handlers[compare_num-1] = 0; + timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums + break; + } +} + +void TIM1_CC_IRQHandler(void) { + // This is a rather long implementation... + Timer *timer = (Timer*)TIMER1_BASE; + uint16 sr_buffer; + sr_buffer = timer->SR; + + if(sr_buffer & 0x10){ // CC4 flag + timer->SR &= ~(0x10); + if(timer1_handlers[3]) { + timer1_handlers[3](); + } + } + if(sr_buffer & 0x8){ // CC3 flag + timer->SR &= ~(0x8); + if(timer1_handlers[2]) { + timer1_handlers[2](); + } + } + if(sr_buffer & 0x4){ // CC2 flag + timer->SR &= ~(0x4); + if(timer1_handlers[1]) { + timer1_handlers[1](); + } + } + if(sr_buffer & 0x2){ // CC1 flag + timer->SR &= ~(0x2); + if(timer1_handlers[0]) { + timer1_handlers[0](); + } + } + if(sr_buffer & 0x1){ // Update flag + timer->SR &= ~(0x1); + //timer->EGR = 1; + } +} +void TIM2_IRQHandler(void) { + // This is a rather long implementation... + Timer *timer = (Timer*)TIMER2_BASE; + uint16 sr_buffer; + sr_buffer = timer->SR; + + if(sr_buffer & 0x10){ // CC4 flag + timer->SR &= ~(0x10); + if(timer2_handlers[3]) { + timer2_handlers[3](); + } + } + if(sr_buffer & 0x8){ // CC3 flag + timer->SR &= ~(0x8); + if(timer2_handlers[2]) { + timer2_handlers[2](); + } + } + if(sr_buffer & 0x4){ // CC2 flag + timer->SR &= ~(0x4); + if(timer2_handlers[1]) { + timer2_handlers[1](); + } + } + if(sr_buffer & 0x2){ // CC1 flag + timer->SR &= ~(0x2); + if(timer2_handlers[0]) { + timer2_handlers[0](); + } + } + if(sr_buffer & 0x1){ // Update flag + timer->SR &= ~(0x1); + //timer->EGR = 1; } } +void TIM3_IRQHandler(void) { + // This is a rather long implementation... + Timer *timer = (Timer*)TIMER3_BASE; + uint16 sr_buffer; + sr_buffer = timer->SR; + + if(sr_buffer & 0x10){ // CC4 flag + timer->SR &= ~(0x10); + if(timer3_handlers[3]) { + timer3_handlers[3](); + } + } + if(sr_buffer & 0x8){ // CC3 flag + timer->SR &= ~(0x8); + if(timer3_handlers[2]) { + timer3_handlers[2](); + } + } + if(sr_buffer & 0x4){ // CC2 flag + timer->SR &= ~(0x4); + if(timer3_handlers[1]) { + timer3_handlers[1](); + } + } + if(sr_buffer & 0x2){ // CC1 flag + timer->SR &= ~(0x2); + if(timer3_handlers[0]) { + timer3_handlers[0](); + } + } + if(sr_buffer & 0x1){ // Update flag + timer->SR &= ~(0x1); + //timer->EGR = 1; + } +} + +void TIM4_IRQHandler(void) { + // This is a rather long implementation... + Timer *timer = (Timer*)TIMER4_BASE; + uint16 sr_buffer; + sr_buffer = timer->SR; + + if(sr_buffer & 0x10){ // CC4 flag + timer->SR &= ~(0x10); + if(timer4_handlers[3]) { + timer4_handlers[3](); + } + } + if(sr_buffer & 0x8){ // CC3 flag + timer->SR &= ~(0x8); + if(timer4_handlers[2]) { + timer4_handlers[2](); + } + } + if(sr_buffer & 0x4){ // CC2 flag + timer->SR &= ~(0x4); + if(timer4_handlers[1]) { + timer4_handlers[1](); + } + } + if(sr_buffer & 0x2){ // CC1 flag + timer->SR &= ~(0x2); + if(timer4_handlers[0]) { + timer4_handlers[0](); + } + } + if(sr_buffer & 0x1){ // Update flag + timer->SR &= ~(0x1); + //timer->EGR = 1; + } +} + diff --git a/libmaple/timers.h b/libmaple/timers.h index 1ee89a0..bcbd751 100644 --- a/libmaple/timers.h +++ b/libmaple/timers.h @@ -93,6 +93,9 @@ typedef volatile uint32* TimerCCR; #define ARPE BIT(7) // Auto-reload preload enable #define NOT_A_TIMER 0 +// just threw this in here cause I can, aw yeah +#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) @@ -114,16 +117,25 @@ typedef volatile uint32* TimerCCR; #define TIMER4_CH4_CCR (TimerCCR)(TIMER4_BASE + 0x40) +#define TIMER_DISABLED 0 +#define TIMER_PWM 1 +#define TIMER_OUTPUTCOMPARE 2 + /* Turn on timer with prescale as the divisor * void timer_init(uint32 timer, uint16 prescale) * timer -> {1-4} * prescale -> {1-65535} * */ void timer_init(uint8, uint16); -void timers_disable(void); -void timers_disable_channel(uint8, uint8); -void timers_set_prescaler(uint32 timer_num, uint16 prescale); -void timers_set_reload(uint32 timer_num, uint16 max_reload); +void timer_disable_all(void); +uint16 timer_get_count(uint8); +void timer_set_count(uint8,uint16); +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, 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 @@ -142,7 +154,6 @@ static inline void timer_pwm_write_ccr(TimerCCR CCR, uint16 duty_cycle) { *CCR = duty_cycle; } - #ifdef __cplusplus } // extern "C" #endif diff --git a/libmaple/util.c b/libmaple/util.c index a7eb831..36173ee 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -54,7 +54,7 @@ void _fail(const char* file, int line, const char* exp) { nvic_disable_interrupts(); /* Turn off timers */ - timers_disable(); + timer_disable_all(); /* Turn off ADC */ adc_disable(); -- cgit v1.2.3