aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple
diff options
context:
space:
mode:
authorbnewbold <bnewbold@robocracy.org>2010-06-12 22:54:11 -0400
committerbnewbold <bnewbold@robocracy.org>2010-07-20 15:36:44 -0400
commitf06fcac502619bc7f6155aa75947dc4340efccd5 (patch)
treee2e727854044548072ae6555744d886e3d7300fd /libmaple
parent52cbd2f1a1557002f46355e0095400a09c267ff9 (diff)
downloadlibrambutan-f06fcac502619bc7f6155aa75947dc4340efccd5.tar.gz
librambutan-f06fcac502619bc7f6155aa75947dc4340efccd5.zip
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.
Diffstat (limited to 'libmaple')
-rw-r--r--libmaple/timers.c415
-rw-r--r--libmaple/timers.h21
-rw-r--r--libmaple/util.c2
3 files changed, 404 insertions, 34 deletions
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();