aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/test-timers.cpp174
-rw-r--r--examples/vga.cpp262
-rw-r--r--libmaple/timers.c415
-rw-r--r--libmaple/timers.h21
-rw-r--r--libmaple/util.c2
-rw-r--r--notes/timers.txt77
-rw-r--r--notes/vga.txt32
-rw-r--r--wirish/comm/HardwareSPI.cpp4
-rw-r--r--wirish/comm/HardwareSerial.cpp4
-rw-r--r--wirish/wirish.c6
-rw-r--r--wirish/wirish.h2
11 files changed, 957 insertions, 42 deletions
diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp
new file mode 100644
index 0000000..c3e3cb9
--- /dev/null
+++ b/examples/test-timers.cpp
@@ -0,0 +1,174 @@
+// Sample main.cpp file. Blinks an LED, sends a message out USART2
+// and turns on PWM on pin 2
+
+#include "wirish.h"
+#include "timers.h"
+
+#define LED_PIN 13
+#define PWM_PIN 2
+
+void handler1(void);
+void handler2(void);
+void handler3(void);
+void handler4(void);
+
+void setup_test_timer(void);
+
+int toggle = 0;
+int timer = 1;
+int state = 3;
+int last_but = 0;
+
+int count1 = 0;
+int count2 = 0;
+int count3 = 0;
+int count4 = 0;
+uint16 rate1 = 1000;
+uint16 rate2 = 2000;
+uint16 rate3 = 3000;
+uint16 rate4 = 4000;
+uint16 val1 = 10000;
+uint16 val2 = 10000;
+uint16 val3 = 10000;
+uint16 val4 = 10000;
+
+void setup()
+{
+ /* Set up the LED to blink */
+ pinMode(LED_PIN, OUTPUT);
+
+ pinMode(38, INPUT);
+
+ /* Send a message out USART2 */
+ //SerialUSB.begin(9600);
+ SerialUSB.println("Begining timer test...");
+
+ /* Send a message out the usb virtual serial port */
+ //SerialUSB.println("Hello!");
+
+ timer = 1;
+ setup_test_timer();
+
+}
+
+
+void loop() {
+ toggle ^= 1;
+ digitalWrite(LED_PIN, toggle);
+ delay(800);
+
+
+ if(digitalRead(38) && !last_but) {
+ state++;
+ switch(state){
+ case 1:
+ SerialUSB.println("Testing Timer1 ---------------------------");
+ timer = 1;
+ setup_test_timer();
+ break;
+ case 2:
+ SerialUSB.println("Testing Timer2 ---------------------------");
+ timer_set_mode(timer,1,TIMER_DISABLED);
+ timer_set_mode(timer,2,TIMER_DISABLED);
+ timer_set_mode(timer,3,TIMER_DISABLED);
+ timer_set_mode(timer,4,TIMER_DISABLED);
+ timer_set_count(1,0);
+ timer_set_count(2,0);
+ timer_set_count(3,0);
+ timer_set_count(4,0);
+ timer = 2;
+ setup_test_timer();
+ break;
+ case 3:
+ SerialUSB.println("Testing Timer3 ---------------------------");
+ timer_set_mode(timer,1,TIMER_DISABLED);
+ timer_set_mode(timer,2,TIMER_DISABLED);
+ timer_set_mode(timer,3,TIMER_DISABLED);
+ timer_set_mode(timer,4,TIMER_DISABLED);
+ timer = 3;
+ setup_test_timer();
+ break;
+ case 4:
+ SerialUSB.println("Testing Timer4 ---------------------------");
+ timer_set_mode(timer,1,TIMER_DISABLED);
+ timer_set_mode(timer,2,TIMER_DISABLED);
+ timer_set_mode(timer,3,TIMER_DISABLED);
+ timer_set_mode(timer,4,TIMER_DISABLED);
+ timer = 4;
+ setup_test_timer();
+ break;
+ default:
+ state = 0;
+ timer_set_mode(timer,1,TIMER_DISABLED);
+ timer_set_mode(timer,2,TIMER_DISABLED);
+ timer_set_mode(timer,3,TIMER_DISABLED);
+ timer_set_mode(timer,4,TIMER_DISABLED);
+ timer = 0;
+ SerialUSB.println("Restarting -------------------------------");
+ }
+ }
+
+ SerialUSB.print("Doing ------------------ "); SerialUSB.println(timer,DEC);
+ if(timer!=0) { SerialUSB.print("CNT: "); SerialUSB.println(timer_get_count(timer),DEC); }
+ SerialUSB.print("Count1 : "); SerialUSB.println(count1,DEC);
+ SerialUSB.print("Count2 : "); SerialUSB.println(count2,DEC);
+ SerialUSB.print("Count3 : "); SerialUSB.println(count3,DEC);
+ SerialUSB.print("Count4 : "); SerialUSB.println(count4,DEC);
+ SerialUSB.println();
+ /*
+ SerialUSB.print("Status : "); SerialUSB.println(get_sr(),HEX);
+ */
+ last_but = digitalRead(38);
+}
+
+void setup_test_timer(void) {
+ timer_set_prescaler(timer,10000);
+ timer_set_mode(timer,1,TIMER_OUTPUTCOMPARE);
+ timer_set_mode(timer,2,TIMER_OUTPUTCOMPARE);
+ timer_set_mode(timer,3,TIMER_OUTPUTCOMPARE);
+ timer_set_mode(timer,4,TIMER_OUTPUTCOMPARE);
+ val1 = val2 = val3 = val4 = 10000;
+ timer_set_compare_value(timer,1,val1);
+ timer_set_compare_value(timer,2,val2);
+ timer_set_compare_value(timer,3,val3);
+ timer_set_compare_value(timer,4,val4);
+ timer_attach_interrupt(timer,1,handler1);
+ timer_attach_interrupt(timer,2,handler2);
+ timer_attach_interrupt(timer,3,handler3);
+ timer_attach_interrupt(timer,4,handler4);
+ count1 = count2 = count3 = count4 = 0;
+}
+
+void handler1(void) {
+ val1 += rate1;
+ timer_set_compare_value(timer,1,val1);
+ count1++;
+ //SerialUSB.print("CC3 Inter: "); SerialUSB.print(get_sr(),HEX);
+ // SerialUSB.print(", "); SerialUSB.println(get_sr_buff(),HEX);
+}
+void handler2(void) {
+ val2 += rate2;
+ timer_set_compare_value(timer,2,val2);
+ count2++;
+}
+void handler3(void) {
+ val3 += rate3;
+ timer_set_compare_value(timer,3,val3);
+ count3++;
+}
+void handler4(void) {
+ val4 += rate4;
+ timer_set_compare_value(timer,4,val4);
+ count4++;
+}
+
+
+int main(void) {
+ init();
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
diff --git a/examples/vga.cpp b/examples/vga.cpp
new file mode 100644
index 0000000..c2e61ae
--- /dev/null
+++ b/examples/vga.cpp
@@ -0,0 +1,262 @@
+
+#include "wirish.h"
+
+/*
+D5 PB6 - TIM4_CH1 I2C1_SCL - - Y
+D6 PA8 - TIM1_CH1 - USART1_CK - Y
+D7 PA9 - TIM1_CH2 - USART1_TX - Y
+D8 PA10 - TIM1_CH3 - USART1_RX - Y
+D9 PB7 - TIM4_CH2 I2C1_SDA - - Y
+*/
+
+//gpio_write_bit(GPIOB_BASE, 6, 1); // VGA_R
+//gpio_write_bit(GPIOB_BASE, 6, 0);
+
+//(GPIOA_BASE)->BSRR = BIT(8);
+//asm volatile("nop");
+//(GPIOA_BASE)->BRR = BIT(8);
+/*
+ gpio_write_bit(GPIOB_BASE, 6, 1); // VGA_R
+ gpio_write_bit(GPIOB_BASE, 6, 0);
+ gpio_write_bit(GPIOA_BASE, 8, 1); // VGA_G
+ gpio_write_bit(GPIOA_BASE, 8, 0);
+ gpio_write_bit(GPIOA_BASE, 9, 1); // VGA_B
+ gpio_write_bit(GPIOA_BASE, 9, 0);
+ gpio_write_bit(GPIOA_BASE, 10, 1); // VGA_V
+ gpio_write_bit(GPIOA_BASE, 10, 0);
+ gpio_write_bit(GPIOB_BASE, 7, 1); // VGA_H
+ gpio_write_bit(GPIOB_BASE, 7, 0);
+*/
+
+#define LED_PIN 13
+#define VGA_R 5 // B6
+#define VGA_G 6 // A8
+#define VGA_B 7 // A9
+#define VGA_V 11 // A6
+#define VGA_H 12 // A7
+#define VGA_R_HIGH (GPIOB_BASE)->BSRR = BIT(6)
+#define VGA_R_LOW (GPIOB_BASE)->BRR = BIT(6)
+#define VGA_G_HIGH (GPIOA_BASE)->BSRR = BIT(8)
+#define VGA_G_LOW (GPIOA_BASE)->BRR = BIT(8)
+#define VGA_B_HIGH (GPIOA_BASE)->BSRR = BIT(9)
+#define VGA_B_LOW (GPIOA_BASE)->BRR = BIT(9)
+#define VGA_V_HIGH (GPIOA_BASE)->BSRR = BIT(6)
+#define VGA_V_LOW (GPIOA_BASE)->BRR = BIT(6)
+#define VGA_H_HIGH (GPIOA_BASE)->BSRR = BIT(7)
+#define VGA_H_LOW (GPIOA_BASE)->BRR = BIT(7)
+
+void isr_porch(void);
+void isr_start(void);
+void isr_stop(void);
+void isr_update(void);
+
+void setup()
+{
+ pinMode(LED_PIN, OUTPUT);
+ digitalWrite(LED_PIN, 1);
+ pinMode(VGA_R, OUTPUT);
+ pinMode(VGA_G, OUTPUT);
+ pinMode(VGA_B, OUTPUT);
+ pinMode(VGA_V, OUTPUT);
+ pinMode(VGA_H, OUTPUT);
+
+ /* Send a message out USART2 */
+ Serial2.begin(9600);
+ Serial2.println("Video time...");
+
+
+ digitalWrite(VGA_R, 0);
+ digitalWrite(VGA_G, 0);
+ digitalWrite(VGA_B, 0);
+ digitalWrite(VGA_H,1);
+ digitalWrite(VGA_V,1);
+
+ timer_set_prescaler(4,0);
+ timer_set_mode(4, 1, TIMER_OUTPUTCOMPARE);
+ timer_set_mode(4, 2, TIMER_OUTPUTCOMPARE);
+ timer_set_mode(4, 3, TIMER_OUTPUTCOMPARE);
+ timer_set_mode(4, 4, TIMER_OUTPUTCOMPARE);
+ timer_set_reload(4, 2287);
+ timer_set_compare_value(4,1,200);
+ timer_set_compare_value(4,2,300);
+ timer_set_compare_value(4,3,2170); // 2219 max...
+ timer_set_compare_value(4,4,1);
+ timer_attach_interrupt(4,1,isr_porch);
+ timer_attach_interrupt(4,2,isr_start);
+ timer_attach_interrupt(4,3,isr_stop);
+ timer_attach_interrupt(4,4,isr_update);
+
+ timer_set_count(4,0);
+}
+
+int toggle = 0;
+uint16 x = 0;
+uint16 y = 0;
+uint8 v_active = 1;
+GPIO_Port *portb = GPIOB_BASE;
+
+void isr_porch(void) {
+ VGA_H_HIGH;
+ y++;
+ if(y>=523) {
+ y=1;
+ v_active = 1;
+ return;
+ }
+ if(y>=492) {
+ VGA_V_HIGH;
+ return;
+ }
+ if(y>=490) {
+ VGA_V_LOW;
+ return;
+ }
+ if(y>=479) { // 479
+ v_active = 0;
+ return;
+ }
+}
+
+uint8 logo[18][16] = {
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
+ {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,},
+ {0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,},
+ {0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,},
+ {0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,},
+ {0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,},
+ {0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,0,},
+ {0,1,0,0,0,0,1,1,1,0,0,0,0,1,0,0,},
+ {0,1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,},
+ {1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,},
+ {1,0,0,0,0,1,0,1,0,1,0,0,0,0,1,0,},
+ {1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,},
+ {0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,},
+ {0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0,},
+ {0,0,0,0,1,1,1,0,1,1,1,0,0,0,0,0,},
+ {0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,},
+ {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, };
+
+void isr_start(void) {
+ if(!v_active) { return; }
+ VGA_R_HIGH;
+ //delayMicroseconds(2);
+ //gpio_write_bit(GPIOA_BASE, 8, 1); // VGA_G
+ for(x=0; x<32; x++) {
+ if(logo[y/28][x/2]) {
+ VGA_G_HIGH;
+ VGA_B_HIGH;
+ } else {
+ VGA_G_LOW;
+ VGA_B_LOW;
+ }
+ }
+
+}
+void isr_stop(void) {
+ if(!v_active) { return; }
+ VGA_R_LOW;
+ VGA_G_LOW;
+ VGA_B_LOW;
+}
+void isr_update(void) {
+ VGA_H_LOW;
+}
+
+void loop() {
+ /*
+ toggle ^= 1;
+ digitalWrite(LED_PIN, toggle);
+ delay(100);
+ Serial2.println("HIHIHI!");
+ */
+ //for(y=0; y<480; y++) {
+ /*
+ for(y=0; y<160; y++) {
+ VGA_R_LOW;
+ VGA_H_LOW;
+ delayMicroseconds(3);
+ VGA_H_HIGH;
+ VGA_R_HIGH;
+ delayMicroseconds(8);
+ VGA_G_HIGH;
+ delayMicroseconds(10);
+ VGA_B_HIGH;
+ delayMicroseconds(10);
+ VGA_R_LOW;
+ VGA_B_LOW;
+ VGA_G_LOW;
+ //VGA_G_HIGH;
+ }
+ for(y=0; y<160; y++) {
+ VGA_R_LOW;
+ VGA_H_LOW;
+ delayMicroseconds(3);
+ VGA_H_HIGH;
+ VGA_G_HIGH;
+ delayMicroseconds(8);
+ VGA_R_HIGH;
+ delayMicroseconds(10);
+ VGA_B_HIGH;
+ delayMicroseconds(10);
+ VGA_R_LOW;
+ VGA_B_LOW;
+ VGA_G_LOW;
+ //VGA_G_HIGH;
+ }
+ for(y=0; y<160; y++) {
+ VGA_R_LOW;
+ VGA_H_LOW;
+ delayMicroseconds(3);
+ VGA_H_HIGH;
+ VGA_B_HIGH;
+ delayMicroseconds(8);
+ VGA_G_HIGH;
+ delayMicroseconds(10);
+ VGA_R_HIGH;
+ delayMicroseconds(10);
+ VGA_R_LOW;
+ VGA_B_LOW;
+ VGA_G_LOW;
+ //VGA_G_HIGH;
+ }
+ for(y=0; y<11; y++) {
+ VGA_R_LOW;
+ VGA_H_LOW;
+ delayMicroseconds(3);
+ VGA_R_LOW;
+ VGA_H_HIGH;
+ delayMicroseconds(28);
+ }
+ VGA_V_LOW;
+ for(y=0; y<2; y++) {
+ VGA_R_LOW;
+ VGA_H_LOW;
+ delayMicroseconds(3);
+ VGA_R_LOW;
+ VGA_H_HIGH;
+ delayMicroseconds(28);
+ }
+ VGA_V_HIGH;
+ for(y=0; y<30; y++) {
+ VGA_R_LOW;
+ VGA_H_LOW;
+ delayMicroseconds(3);
+ VGA_R_LOW;
+ VGA_H_HIGH;
+ delayMicroseconds(28);
+ }
+ */
+
+}
+
+
+int main(void) {
+ init();
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
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();
diff --git a/notes/timers.txt b/notes/timers.txt
new file mode 100644
index 0000000..3e6bb9c
--- /dev/null
+++ b/notes/timers.txt
@@ -0,0 +1,77 @@
+
+Each timer (1-4) has 4 capture/compare channels (1-4). These are directly used
+by PWM but have a ton of other possible functionality. The STM32 implementation
+is particularly complicated with, eg, the ability to chain together timers
+
+Timer1 is an "advanced timer" with many more features. I think if we use just
+the "Capture and compare interrupt", and enable MOE during initialization
+everything will be ok. There are seperate Break, Update, and Trigger interrupts
+as well that we will ignore for now.
+
+Timer2,Ch 3+4 are D0 and D1, which conflict with Serial2. USART should work
+fine as long as pins aren't in output mode? and timers should work fine if
+Serial2 isn't in use?
+
+Misc Notes
+------------------------------------------------------------------------------
+implementation with case/switch in the interrupt handlers doesn't work; a lot
+of the time multiple interrupt flags are active at the same time (or become
+active?)
+
+TODO
+------------------------------------------------------------------------------
+- function to read out CCR registers
+- allow comparison output to the pin (a la PWM)
+- additional modes and configuration (up, down, up/down, etc)
+- Wirish (C++) higher level implementation
+- implement the update interrupt as a "5th channel"
+- track down and handle all pin conflicts
+- document
+
+Possible Wirish implementation
+------------------------------------------------------------------------------
+This recent implementation seems pretty clean:
+http://arduino.cc/pipermail/developers_arduino.cc/2010-June/002845.html
+
+ class Timer1Class {
+ public:
+ static void (*isrCompareA)(void);
+ static void (*isrCompareB)(void);
+
+ static const uint8_t PRESCALE1 = 1;
+ static const uint8_t PRESCALE8 = 2;
+ static const uint8_t PRESCALE64 = 3;
+ static const uint8_t PRESCALE256 = 4;
+ static const uint8_t PRESCALE1024 = 5;
+
+ const static uint8_t NORMAL = 0;
+ const static uint8_t CTC = 4;
+
+ void setPrescaleFactor(uint8_t factor);
+ void setMode(uint8_t mode);
+ uint16_t read();
+ void write(uint16_t val);
+ void writeCompareA(uint16_t val);
+ void writeCompareB(uint16_t val);
+ void attachCompareAInterrupt(void (*f)(void));
+ void attachCompareBInterrupt(void (*f)(void));
+ void detachCompareAInterrupt();
+ void detachCompareBInterrupt();
+ };
+
+ extern Timer1Class Timer1;
+
+Here's one of the more standard libaries out there:
+http://www.arduino.cc/playground/Code/Timer1
+
+ void initialize(long microseconds=1000000);
+ void start();
+ void stop();
+ void restart();
+ void setPeriod(long microseconds);
+ void pwm(char pin, int duty, long microseconds=-1);
+ void setPwmDuty(char pin, int duty);
+ void disablePwm(char pin);
+ void attachInterrupt(void (*isr)(), long microseconds=-1);
+ void detachInterrupt();
+
diff --git a/notes/vga.txt b/notes/vga.txt
new file mode 100644
index 0000000..2230f57
--- /dev/null
+++ b/notes/vga.txt
@@ -0,0 +1,32 @@
+
+classic digitalWrite() gives ~500ns pulse time (2MHz)
+
+gpio_write_bit() is about 360ns (2.78MHz)
+
+writing to GPIO?_BASE is about 60ns (16.6MHz -> 18MHz)
+
+pwm write 0x0001 is about 30ns (33MHz)
+pwm write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!)
+
+1/25.125MHz = 39.72ns
+
+crude 640x480 directions:
+ www.epanorama.net/documents/pc/vga_timing.html
+ 480 lines
+ 31.77 us horizontal line length -> 2287.44 clock cycles -> 2287
+ 3.77 us sync period -> 271 clocks -> 271
+ 1.89 us front porch? -> 136 clocks -> 136
+ 25.17 us video -> 1812.24 clocks -> 1812
+
+ so...
+ 2287 reload
+ 271 1: Hsync high
+ 407 2: Video on
+ 2219 3: Video off
+ 2287 4: Hsync low
+
+ vertically, it's
+ 480 lines active video
+ 11 lines front porch
+ 2 lines Vsync (low)
+ 31 lines back porch
diff --git a/wirish/comm/HardwareSPI.cpp b/wirish/comm/HardwareSPI.cpp
index 3dfe10a..eadcdd7 100644
--- a/wirish/comm/HardwareSPI.cpp
+++ b/wirish/comm/HardwareSPI.cpp
@@ -95,8 +95,8 @@ void HardwareSPI::begin(SPIFrequency freq, uint32 endianness, uint32 mode) {
}
/* Turn off PWM on shared pins */
- timers_disable_channel(3, 2);
- timers_disable_channel(3, 1);
+ timer_set_mode(3, 2, TIMER_DISABLED);
+ timer_set_mode(3, 1, TIMER_DISABLED);
}
endianness = (endianness == LSBFIRST) ? SPI_LSBFIRST : SPI_MSBFIRST;
diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp
index fc0d01e..7157e74 100644
--- a/wirish/comm/HardwareSerial.cpp
+++ b/wirish/comm/HardwareSerial.cpp
@@ -78,13 +78,13 @@ void HardwareSerial::begin(uint32 baud) {
gpio_set_mode(USART1_TX_PORT, USART1_TX_PIN, GPIO_MODE_AF_OUTPUT_PP);
gpio_set_mode(USART1_RX_PORT, USART1_RX_PIN, GPIO_MODE_INPUT_FLOATING);
/* Turn off any pwm */
- timers_disable_channel(1, 2);
+ timer_set_mode(1, 2, TIMER_DISABLED);
break;
case 2:
gpio_set_mode(USART2_TX_PORT, USART2_TX_PIN, GPIO_MODE_AF_OUTPUT_PP);
gpio_set_mode(USART2_RX_PORT, USART2_RX_PIN, GPIO_MODE_INPUT_FLOATING);
/* Turn off any pwm */
- timers_disable_channel(2, 3);
+ timer_set_mode(2, 3, TIMER_DISABLED);
break;
case 3:
gpio_set_mode(USART3_TX_PORT, USART3_TX_PIN, GPIO_MODE_AF_OUTPUT_PP);
diff --git a/wirish/wirish.c b/wirish/wirish.c
index e21f792..520079c 100644
--- a/wirish/wirish.c
+++ b/wirish/wirish.c
@@ -31,17 +31,17 @@
#include "systick.h"
#include "gpio.h"
#include "nvic.h"
-#include "usb.h"
+//#include "usb.h"
void init(void) {
rcc_init();
nvic_init();
- systick_init();
+// systick_init();
gpio_init();
adc_init();
timer_init(1, 1);
timer_init(2, 1);
timer_init(3, 1);
timer_init(4, 1);
- setupUSB();
+ //setupUSB();
}
diff --git a/wirish/wirish.h b/wirish/wirish.h
index 2541e5e..34464a2 100644
--- a/wirish/wirish.h
+++ b/wirish/wirish.h
@@ -43,7 +43,7 @@
#ifdef __cplusplus
#include "HardwareSPI.h"
#include "HardwareSerial.h"
-#include "usb_serial.h"
+//#include "usb_serial.h"
#endif
#ifdef __cplusplus