From dd52d66d034c943380d4a95d7677cff7772109df Mon Sep 17 00:00:00 2001 From: bnewbold Date: Fri, 2 Jul 2010 00:57:35 -0400 Subject: timers progress examples code cleanup, more descriptive comments, more notes --- examples/test-timers.cpp | 143 +++++++++++++---------------------------------- examples/vga-leaf.cpp | 138 ++++----------------------------------------- examples/vga-scope.cpp | 28 ---------- libmaple/timers.c | 57 +++++++++++++++---- notes/timers.txt | 73 ++++++++++++++---------- notes/vga.txt | 26 ++++++--- wirish/rules.mk | 1 + wirish/wirish.c | 6 +- wirish/wirish.h | 3 +- 9 files changed, 163 insertions(+), 312 deletions(-) diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp index c3e3cb9..374b903 100644 --- a/examples/test-timers.cpp +++ b/examples/test-timers.cpp @@ -2,7 +2,6 @@ // and turns on PWM on pin 2 #include "wirish.h" -#include "timers.h" #define LED_PIN 13 #define PWM_PIN 2 @@ -12,12 +11,8 @@ 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 t; int count1 = 0; int count2 = 0; @@ -25,13 +20,15 @@ int count3 = 0; int count4 = 0; uint16 rate1 = 1000; uint16 rate2 = 2000; -uint16 rate3 = 3000; -uint16 rate4 = 4000; +uint16 rate3 = 4000; +uint16 rate4 = 8000; uint16 val1 = 10000; uint16 val2 = 10000; uint16 val3 = 10000; uint16 val4 = 10000; +HardwareTimer Timers[] = {Timer1, Timer2, Timer3, Timer4}; + void setup() { /* Set up the LED to blink */ @@ -42,123 +39,59 @@ void setup() /* 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(); - + for(int t=0; t<4; t++) { + Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE); + Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE); + Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE); + Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE); + } } - 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 -------------------------------"); - } + for(t=0; t<4; t++) { + toggle ^= 1; digitalWrite(LED_PIN, toggle); + delay(1000); + SerialUSB.println("-----------------------------------------------------"); + SerialUSB.print("Testing Timer "); SerialUSB.println(t+1); + count1 = count2 = count3 = count4 = 0; + Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE); + Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE); + Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE); + Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE); + Timers[t].attachCompare1Interrupt(handler1); + Timers[t].attachCompare2Interrupt(handler2); + Timers[t].attachCompare3Interrupt(handler3); + Timers[t].attachCompare4Interrupt(handler4); + delay(5000); + Timers[t].setChannel1Mode(TIMER_DISABLED); + Timers[t].setChannel2Mode(TIMER_DISABLED); + Timers[t].setChannel3Mode(TIMER_DISABLED); + Timers[t].setChannel4Mode(TIMER_DISABLED); + SerialUSB.print("Count1: "); SerialUSB.println(count1); + SerialUSB.print("Count2: "); SerialUSB.println(count2); + SerialUSB.print("Count3: "); SerialUSB.println(count3); + SerialUSB.print("Count4: "); SerialUSB.println(count4); } - - 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); + Timers[t].setCompare1(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); + Timers[t].setCompare2(val2); count2++; } void handler3(void) { val3 += rate3; - timer_set_compare_value(timer,3,val3); + Timers[t].setCompare3(val3); count3++; } void handler4(void) { val4 += rate4; - timer_set_compare_value(timer,4,val4); + Timers[t].setCompare4(val4); count4++; } diff --git a/examples/vga-leaf.cpp b/examples/vga-leaf.cpp index c2e61ae..3374608 100644 --- a/examples/vga-leaf.cpp +++ b/examples/vga-leaf.cpp @@ -1,39 +1,11 @@ - #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 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) @@ -89,11 +61,14 @@ void setup() timer_set_count(4,0); } +void loop() { + // everything happens in the interrupts! +} + int toggle = 0; -uint16 x = 0; +uint16 x = 0; uint16 y = 0; uint8 v_active = 1; -GPIO_Port *portb = GPIOB_BASE; void isr_porch(void) { VGA_H_HIGH; @@ -139,9 +114,9 @@ uint8 logo[18][16] = { void isr_start(void) { if(!v_active) { return; } + VGA_R_LOW; 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; @@ -151,7 +126,6 @@ void isr_start(void) { VGA_B_LOW; } } - } void isr_stop(void) { if(!v_active) { return; } @@ -163,94 +137,6 @@ 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(); diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp index 1f597a4..3e7e75e 100644 --- a/examples/vga-scope.cpp +++ b/examples/vga-scope.cpp @@ -1,33 +1,6 @@ #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 ANALOG_PIN 18 #define VGA_R 5 // B6 @@ -152,7 +125,6 @@ void isr_update(void) { void loop() { //val = analogRead(ANALOG_PIN); - } diff --git a/libmaple/timers.c b/libmaple/timers.c index a772cf9..daf8b51 100644 --- a/libmaple/timers.c +++ b/libmaple/timers.c @@ -75,15 +75,17 @@ typedef struct { uint16 RESERVED19; } Timer; - +// These are the output compare interrupt functions that get called by the +// handlers below volatile static voidFuncPtr timer1_handlers[4]; volatile static voidFuncPtr timer2_handlers[4]; volatile static voidFuncPtr timer3_handlers[4]; volatile static voidFuncPtr timer4_handlers[4]; +// 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) { - // 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; @@ -151,9 +153,11 @@ void timer_init(uint8 timer_num, uint16 prescale) { timer->CR1 |= 1; // Enable timer } -void timer_set_count(uint8 timer_num, uint16 value) { - Timer *timer; - ASSERT(timer_num > 0 && timer_num <= 4); +// 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) { Timer *timer; +ASSERT(timer_num > 0 && timer_num <= 4); switch(timer_num) { case 1: @@ -172,6 +176,8 @@ void timer_set_count(uint8 timer_num, uint16 value) { 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) { Timer *timer; ASSERT(timer_num > 0 && timer_num <= 4); @@ -193,6 +199,7 @@ uint16 timer_get_count(uint8 timer_num) { return timer->CNT; } +// Does what it says void timer_set_prescaler(uint8 timer_num, uint16 prescale) { Timer *timer; ASSERT(timer_num > 0 && timer_num <= 4); @@ -214,6 +221,8 @@ void timer_set_prescaler(uint8 timer_num, uint16 prescale) { timer->PSC = prescale; } +// 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) { Timer *timer; ASSERT(timer_num > 0 && timer_num <= 4); @@ -235,15 +244,28 @@ void timer_set_reload(uint8 timer_num, uint16 max_reload) { timer->ARR = max_reload; } - +// This quickly disables all 4 timers, presumably as part of a system shutdown +// or similar to prevent interrupts and PWM output without 16 seperate function +// calls to timer_set_mode 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; } } + 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; + } +} +// Sets the mode of individual timer channels, including a DISABLE mode void timer_set_mode(uint8 timer_num, uint8 channel, uint8 mode) { Timer *timer; switch (timer_num) { @@ -359,6 +381,7 @@ void timer_set_mode(uint8 timer_num, uint8 channel, uint8 mode) { } } +// This sets the compare value (aka the trigger) for a given timer 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 @@ -395,6 +418,8 @@ void timer_set_compare_value(uint8 timer_num, uint8 compare_num, uint16 value) { } } +// 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, uint8 compare_num, voidFuncPtr handler) { Timer *timer; ASSERT(timer_num > 0 && timer_num <= 4 && compare_num > 0 && compare_num <= 4); @@ -455,12 +480,20 @@ void timer_detach_interrupt(uint8 timer_num, uint8 compare_num) { } } +// The following are the actual interrupt handlers; 1 for each timer which must +// determine which actual compare value (aka channel) was triggered. +// +// These ISRs get called when the timer interrupt is enabled, the timer is running, and +// the timer count equals any of the CCR registers /or/ has overflowed. +// +// This is a rather long implementation... void TIM1_CC_IRQHandler(void) { - // This is a rather long implementation... Timer *timer = (Timer*)TIMER1_BASE; uint16 sr_buffer; sr_buffer = timer->SR; + // Simply switch/case-ing here doesn't work because multiple + // CC flags may be high. if(sr_buffer & 0x10){ // CC4 flag timer->SR &= ~(0x10); if(timer1_handlers[3]) { diff --git a/notes/timers.txt b/notes/timers.txt index 3e6bb9c..3f5b9f4 100644 --- a/notes/timers.txt +++ b/notes/timers.txt @@ -12,54 +12,69 @@ 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? +Caveats +------------------------------------------------------------------------------ +There are probably subtle bugs with the way register settings get read in; eg, +it is often required to have the counter fully overflow before new settings +come into effect? +Getting really good timing is still an art, not a science here... usually you +need to fiddle with an oscilloscope and the exact overflow/compare numbers to +get just the right time values. +Any other interrupts (SysTick, USB, Serial, etc) can blow away all the nice +timing stuff. + Misc Notes ------------------------------------------------------------------------------ -implementation with case/switch in the interrupt handlers doesn't work; a lot +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 ------------------------------------------------------------------------------ +- document carefully (eg, determine clock-wise and overflow-wise behavior for + each function) +- track down and handle all pin conflicts +- implement the update interrupt as a "5th channel" +- "pulse in" stuff, both c and c++ - 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: +Inspired by Timer1 Library for arduino 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; + class HardwareTimer { - const static uint8_t NORMAL = 0; - const static uint8_t CTC = 4; + public: - 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(); + void pause(); + void resume(); + void setPrescaleFactor(uint8 factor); + void setOverflow(uint16 val); // truncates to overflow + void setCount(uint16 val); // truncates to overflow + uint16 getCount(); + uint16 setPeriod(uint32 microseconds); // tries to set prescaler and overflow wisely; returns overflow + void setMode(uint8 mode); + void setCompare1(uint16 val); // truncates to overflow + void setCompare2(uint16 val); // truncates to overflow + void setCompare3(uint16 val); // truncates to overflow + void setCompare4(uint16 val); // truncates to overflow + void attachCompare1Interrupt(void (*f)(void)); + void attachCompare2Interrupt(void (*f)(void)); + void attachCompare3Interrupt(void (*f)(void)); + void attachCompare4Interrupt(void (*f)(void)); + void detachCompare1Interrupt(); + void detachCompare2Interrupt(); + void detachCompare3Interrupt(); + void detachCompare4Interrupt(); }; - extern Timer1Class Timer1; + HardwareTimer Timer1 = HardwareTimer(1); + HardwareTimer Timer2 = HardwareTimer(2); + HardwareTimer Timer3 = HardwareTimer(3); + HardwareTimer Timer4 = HardwareTimer(4); Here's one of the more standard libaries out there: http://www.arduino.cc/playground/Code/Timer1 diff --git a/notes/vga.txt b/notes/vga.txt index 2230f57..d75281a 100644 --- a/notes/vga.txt +++ b/notes/vga.txt @@ -1,32 +1,42 @@ -classic digitalWrite() gives ~500ns pulse time (2MHz) +Notes on GPIO Writing +------------------------------------------------------------------------------ +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) +Writing to GPIO?_BASE is about 60ns (16.6MHz -> 18MHz) -pwm write 0x0001 is about 30ns (33MHz) +pwm write 0x0001 is about 30ns (33MHz) with prescaler as 1 (default) pwm write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!) -1/25.125MHz = 39.72ns +VGA Timing +------------------------------------------------------------------------------ +1/25.125MHz = 39.72ns (640x480 pixel clock) -crude 640x480 directions: - www.epanorama.net/documents/pc/vga_timing.html +Crude 640x480 directions: + From 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... + So... 2287 reload 271 1: Hsync high 407 2: Video on 2219 3: Video off 2287 4: Hsync low - vertically, it's + Vertically, it's 480 lines active video 11 lines front porch 2 lines Vsync (low) 31 lines back porch + +Currently, setting vs. clearing GPIO registers seems to take a different amount +of time? Or perhaps i'm not analyzing branching correctly. Regardless, if you +SET 100x times then UNSET on one line, then UNSET 100x then SET the next line, +the two changes in color will generally not line up. + diff --git a/wirish/rules.mk b/wirish/rules.mk index e74d15d..b2110bd 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -24,6 +24,7 @@ cppSRCS_$(d) := wirish_math.cpp \ comm/HardwareSerial.cpp \ comm/HardwareSPI.cpp \ usb_serial.cpp \ + HardwareTimer.cpp \ cxxabi-compat.cpp cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) diff --git a/wirish/wirish.c b/wirish/wirish.c index 520079c..e21f792 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 34464a2..13ff313 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -43,7 +43,8 @@ #ifdef __cplusplus #include "HardwareSPI.h" #include "HardwareSerial.h" -//#include "usb_serial.h" +#include "usb_serial.h" +#include "HardwareTimer.h" #endif #ifdef __cplusplus -- cgit v1.2.3