From 61db54f52f32e63c895d775982fbcdcb67f2dde6 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 22 Mar 2011 16:59:29 -0400 Subject: Initial timer refactor. Basic PWM works. Had some problems in testing that might be due to USART bugs. HardwareTimer has been removed from the build for now; I will re-implement it in terms of the new libmaple API, but consider it deprecated. Let's come up with something better. Servo is implemented in terms of HardwareTimer, so it also has been temporarily removed from the build. pwmWrite() likely got a little bit less inefficient due to indirection, but the PIN_MAPs shrank by a pointer per PinMapping. --- examples/test-session.cpp | 19 +-- examples/test-timers.cpp | 372 ++++++++++++++++++++++++++-------------------- 2 files changed, 216 insertions(+), 175 deletions(-) (limited to 'examples') diff --git a/examples/test-session.cpp b/examples/test-session.cpp index a147e06..9b4bce4 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -15,7 +15,6 @@ //#define COMM Serial2 //#define COMM Serial3 - #define ESC ((uint8)27) int rate = 0; @@ -610,17 +609,15 @@ void cmd_servo_sweep(void) { COMM.println("(reset serial port)"); } +static uint16 init_all_timers_prescale = 0; + +static void set_prescale(timer_dev *dev) { + timer_set_prescaler(dev, init_all_timers_prescale); +} + void init_all_timers(uint16 prescale) { - timer_init(TIMER1, prescale); - timer_init(TIMER2, prescale); - timer_init(TIMER3, prescale); - timer_init(TIMER4, prescale); -#ifdef STM32_HIGH_DENSITY - timer_init(TIMER5, prescale); - // timer_init(TIMER6, prescale); - // timer_init(TIMER7, prescale); - timer_init(TIMER8, prescale); -#endif + init_all_timers_prescale = prescale; + timer_foreach(set_prescale); } // Force init to be called *first*, i.e. before static object allocation. diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp index f3cfdcc..a4fbc8a 100644 --- a/examples/test-timers.cpp +++ b/examples/test-timers.cpp @@ -1,8 +1,7 @@ -// Program to test the wirish timers implementation +// Program to test the timer.h implementation's essential functionality. #include "wirish.h" - -#define LED_PIN BOARD_LED_PIN +#include "timer.h" void handler1(void); void handler2(void); @@ -27,208 +26,253 @@ uint16 val2 = 10000; uint16 val3 = 10000; uint16 val4 = 10000; -HardwareTimer Timers[] = {Timer1, Timer2, Timer3, Timer4}; +// FIXME high density timer test (especially basic timers + DAC) +timer_dev *timers[] = {TIMER1, TIMER2, TIMER3, TIMER4}; +voidFuncPtr handlers[] = {handler1, handler2, handler3, handler4}; + +void initTimer(timer_dev *dev); +void setTimerPeriod(timer_dev *dev, uint32 period_us); +void testSetTimerPeriod(uint32 period); +void testTimerChannels(timer_dev *dev); +int timerNumber(timer_dev *dev); -void setup() -{ - /* Set up the LED to blink */ - pinMode(LED_PIN, OUTPUT); +void setup() { + // Set up the LED to blink + pinMode(BOARD_LED_PIN, OUTPUT); // Setup the button as input pinMode(BOARD_BUTTON_PIN, INPUT); - // Wait for user to attach... - waitForButtonPress(0); - - // Send a message out SerialUSB - SerialUSB.println("Beginning timer test..."); - 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); - } + // Send a message out Serial2 + Serial2.begin(115200); + Serial2.println("*** Initializing timers..."); + Serial2.println("foo"); + timer_foreach(initTimer); + Serial2.println("*** Done. Beginning timer test."); } void loop() { - SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing setCount/getCount"); - SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount()); - SerialUSB.println("Timer1.setCount(1234)"); - Timer1.setCount(1234); - SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount()); - // This tests whether the pause/resume functions work; when BUT is held - // down Timer4 is in the "pause" state and the timer doesn't increment, so - // the final counts should reflect the ratio of time that BUT was held down - SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing Pause/Resume; button roughly controls Timer4"); + Serial2.println("-----------------------------------------------------"); + + Serial2.println("Testing timer_get_count()/timer_set_count()"); + Serial2.print("TIMER1 count = "); + Serial2.println(timer_get_count(TIMER1)); + Serial2.println("timer_set_count(TIMER1, 1234)"); + timer_set_count(TIMER1, 1234); + Serial2.print("timer_get_count(TIMER1) = "); + Serial2.println(timer_get_count(TIMER1)); + + Serial2.println("-----------------------------------------------------"); + Serial2.println("Testing pause/resume; button roughly controls TIMER4"); + // when BUT is held down, TIMER4 is in the "pause" state and the + // timer doesn't increment, so the final counts should reflect the + // ratio of time that BUT was held down. count3 = 0; count4 = 0; - Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer3.pause(); - Timer4.pause(); - Timer3.setCount(0); - Timer4.setCount(0); - Timer3.setOverflow(30000); - Timer4.setOverflow(30000); - Timer3.setCompare1(1000); - Timer4.setCompare1(1000); - Timer3.attachCompare1Interrupt(handler3b); - Timer4.attachCompare1Interrupt(handler4b); - Timer3.resume(); - Timer4.resume(); - SerialUSB.println("~4 seconds..."); - for(int i = 0; i<4000; i++) { - if(isButtonPressed()) { - Timer4.pause(); + timer_set_mode(TIMER3, TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer_pause(TIMER3); + timer_pause(TIMER4); + timer_set_count(TIMER3, 0); + timer_set_count(TIMER4, 0); + timer_set_reload(TIMER3, 30000); + timer_set_reload(TIMER4, 30000); + timer_set_compare(TIMER3, 1, 1000); + timer_set_compare(TIMER4, 1, 1000); + timer_attach_interrupt(TIMER3, TIMER_CC1_INTERRUPT, handler3b); + timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b); + timer_resume(TIMER3); + timer_resume(TIMER4); + + Serial2.println("Testing for ~4 seconds..."); + for(int i = 0; i < 4000; i++) { + if (isButtonPressed()) { + timer_pause(TIMER4); } else { - Timer4.resume(); + timer_resume(TIMER4); } delay(1); } - Timer3.setChannel1Mode(TIMER_DISABLED); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count3: "); SerialUSB.println(count3); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - - // These test the setPeriod auto-configure functionality - SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing setPeriod"); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setCompare1(1); - Timer4.setPeriod(10); - Timer4.pause(); - Timer4.setCount(0); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 10ms, wait 2 seconds..."); - count4 = 0; - Timer4.resume(); - delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/10ms = 200000)"); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setCompare1(1); - Timer4.pause(); - Timer4.setPeriod(30000); - Timer4.setCount(0); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); - count4 = 0; - Timer4.resume(); - delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/30000ms ~ 67)"); - - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setPeriod(300000); - Timer4.setCompare1(1); - Timer4.pause(); - Timer4.setCount(0); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 300000ms, wait 2 seconds..."); - count4 = 0; - Timer4.resume(); - delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/300000ms ~ 6.7)"); - - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setPrescaleFactor(33); - Timer4.setOverflow(65454); - Timer4.pause(); - Timer4.setCount(0); - Timer4.setCompare1(1); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + + timer_set_mode(TIMER3, TIMER_CH1, TIMER_DISABLED); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED); + + Serial2.print("TIMER3 count: "); + Serial2.println(timer_get_count(TIMER3)); + Serial2.print("TIMER4 count: "); + Serial2.println(timer_get_count(TIMER4)); + + Serial2.println("-----------------------------------------------------"); + Serial2.println("Testing setTimerPeriod()"); + testSetTimerPeriod(10); + testSetTimerPeriod(30000); + testSetTimerPeriod(300000); + testSetTimerPeriod(30000); + + Serial2.println("Sanity check (with hand-coded reload and prescaler for " + "72 MHz timers):"); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer_set_prescaler(TIMER4, 33); + timer_set_reload(TIMER4, 65454); + timer_pause(TIMER4); + timer_set_count(TIMER4, 0); + timer_set_compare(TIMER4, TIMER_CH1, 1); + timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b); + Serial2.println("Period 30000ms, wait 2 seconds..."); count4 = 0; - Timer4.resume(); + timer_resume(TIMER4); delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/30000ms ~ 67)"); - - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setCompare1(1); - Timer4.setPeriod(30000); - Timer4.pause(); - Timer4.setCount(0); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + timer_pause(TIMER4); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED); + Serial2.print("TIMER4 count: "); + Serial2.println(count4); + Serial2.println(" (Should be around 2sec/30000ms ~ 67)"); + + // Test all the individual timer channels + timer_foreach(testTimerChannels); +} + +void initTimer(timer_dev *dev) { + switch (dev->type) { + case TIMER_ADVANCED: + case TIMER_GENERAL: + Serial2.print("Initializing timer "); + Serial2.println(timerNumber(dev)); + for (int c = 1; c <= 4; c++) { + timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE); + } + Serial2.println("Done."); + break; + case TIMER_BASIC: + break; + } +} + +void testSetTimerPeriod(uint32 period) { + timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer_set_compare(TIMER4, TIMER_CH1, 1); + setTimerPeriod(TIMER4, period); + timer_pause(TIMER4); + timer_set_count(TIMER4, 0); + timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b); + Serial2.println("Period "); + Serial2.print(period); + Serial2.print(" ms. Waiting 2 seconds..."); count4 = 0; - Timer4.resume(); + timer_resume(TIMER4); delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/30000ms ~ 67)"); - - // This section is to touch every channel of every timer. The output - // ratios should reflect the ratios of the rate variables. Demonstrates - // that over time the actual timing rates get blown away by other system - // interrupts. - for(t=0; t<4; t++) { - toggleLED(); - delay(100); - SerialUSB.println("-----------------------------------------------------"); - SerialUSB.print("Testing Timer "); SerialUSB.println(t+1); + timer_pause(TIMER4); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED); + Serial2.print("TIMER4 count: "); + Serial2.println(timer_get_count(TIMER4)); + Serial2.print(" (Should be around 2 sec / "); + Serial2.print(period); + Serial2.print(" ms = "); + Serial2.print(double(2) / period * 1000); + Serial2.println(", modulo delays due to interrupts)"); +} + +int timerNumber(timer_dev *dev) { + switch (dev->clk_id) { + case RCC_TIMER1: + return 1; + case RCC_TIMER2: + return 2; + case RCC_TIMER3: + return 3; + case RCC_TIMER4: + return 4; +#ifdef STM32_HIGH_DENSITY + case RCC_TIMER5: + return 5; + case RCC_TIMER6: + return 6; + case RCC_TIMER7: + return 7; + case RCC_TIMER8: + return 8; +#endif + default: + ASSERT(0); + return 0; + } +} + +/* This function touches every channel of a given timer. The output + * ratios should reflect the ratios of the rate variables. It + * demonstrates that, over time, the actual timing rates get blown + * away by other system interrupts. */ +void testTimerChannels(timer_dev *dev) { + t = timerNumber(dev); + toggleLED(); + delay(100); + Serial2.println("-----------------------------------------------------"); + switch (dev->type) { + case TIMER_BASIC: + Serial2.print("NOT testing channels for basic timer "); + Serial2.println(t); + break; + case TIMER_ADVANCED: + case TIMER_GENERAL: + Serial2.print("Testing channels for timer "); + Serial2.println(t); + timer_pause(dev); count1 = count2 = count3 = count4 = 0; - Timers[t].setOverflow(0xFFFF); - Timers[t].setPrescaleFactor(1); - Timers[t].setCompare1(65535); - Timers[t].setCompare2(65535); - Timers[t].setCompare3(65535); - Timers[t].setCompare4(65535); - 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); - Timers[t].resume(); + timer_set_reload(dev, 0xFFFF); + timer_set_prescaler(dev, 1); + for (int c = 1; c <= 4; c++) { + timer_set_compare(dev, c, 65535); + timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE); + timer_attach_interrupt(dev, c, handlers[c - 1]); + } + timer_resume(dev); delay(3000); - 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); + for (int c = 1; c <= 4; c++) { + timer_set_mode(dev, c, TIMER_DISABLED); + } + Serial2.print("Channel 1 count: "); Serial2.println(count1); + Serial2.print("Channel 2 count: "); Serial2.println(count2); + Serial2.print("Channel 3 count: "); Serial2.println(count3); + Serial2.print("Channel 4 count: "); Serial2.println(count4); + break; + } +} + +// FIXME move this into the new wirish timer implementation +void setTimerPeriod(timer_dev *dev, uint32 period_us) { + if (!period_us) { + // FIXME handle this case + ASSERT(0); + return; } + uint32 cycles = period_us * CYCLES_PER_MICROSECOND; + uint16 pre = (uint16)((cycles >> 16) + 1); + timer_set_prescaler(dev, pre); + timer_set_reload(dev, cycles / pre - 1); } void handler1(void) { val1 += rate1; - Timers[t].setCompare1(val1); + timer_set_compare(timers[t], TIMER_CH1, val1); count1++; } void handler2(void) { val2 += rate2; - Timers[t].setCompare2(val2); + timer_set_compare(timers[t], TIMER_CH2, val2); count2++; } void handler3(void) { val3 += rate3; - Timers[t].setCompare3(val3); + timer_set_compare(timers[t], TIMER_CH3, val3); count3++; } void handler4(void) { val4 += rate4; - Timers[t].setCompare4(val4); + timer_set_compare(timers[t], TIMER_CH4, val4); count4++; } -- cgit v1.2.3