diff options
Diffstat (limited to 'examples/test-timers.cpp')
-rw-r--r-- | examples/test-timers.cpp | 537 |
1 files changed, 0 insertions, 537 deletions
diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp deleted file mode 100644 index e646916..0000000 --- a/examples/test-timers.cpp +++ /dev/null @@ -1,537 +0,0 @@ -// -// This is a mostly Wirish-free timer test. Wirish usage is minimized -// because this is a test of the C timer interface in -// <libmaple/timer.h>, so it's good if it can be made to work even -// when most or all of Wirish is missing. Because of that, you may -// need to customize the following output configuration: -// -// Output is printed: -// - on COMM_USART, -// - via TX pin on port COMM_USART_PORT, bit COMM_USART_TX_BIT -// - via RX pin on port COMM_USART_PORT, bit COMM_USART_RX_BIT -// - at COMM_USART_BAUD baud. -#define COMM_USART USART6 -#define COMM_USART_BAUD 115200 -#define COMM_USART_PORT GPIOG -#define COMM_USART_TX_BIT 14 -#define COMM_USART_RX_BIT 9 -// Other optional configuration below. - -#include <libmaple/libmaple.h> -#include <libmaple/gpio.h> -#include <libmaple/usart.h> -#include <libmaple/systick.h> -#include <libmaple/timer.h> -#include <wirish/boards.h> - -// -// Configuration -// - -// More output if true -static bool verbose = true; - -// Timers to test -// FIXME use feature test macros for smaller MCUs -static timer_dev *timers[] = { - // Available on all currently supported MCUs - TIMER1, TIMER2, TIMER3, TIMER4, - // Available on F1 (HD and up), F2 - TIMER5, TIMER6, TIMER7, TIMER8, - // Available on F1 (XL), F2 - TIMER9, TIMER10, TIMER11, TIMER12, TIMER13, TIMER14, -}; - -// -// Test routines -// - -typedef void (*timer_test_t)(timer_dev *); - -static void runTest(const char description[], timer_test_t test); -static void runTests(void); - -static void testGetAndSetCount(timer_dev*); -static void testPauseAndResume(timer_dev*); -static void testTimerChannels(timer_dev*); - -// -// Helpers -// - -static void initTimer(timer_dev *dev); -static int timerNumber(timer_dev *dev); -// Hack: a systick-based delay, useful until delay_us() is fixed -static void _delay(uint32 msec); -// Wirish-less USART initialization routine -static void init_usart(usart_dev *dev, gpio_dev *gdev, uint8 tx, uint8 rx); -// Return whether or not the timer has capture/compare channel `ch'. -// TODO: does something like this belong in the standard timer library? -static bool timer_has_cc_ch(timer_dev *dev, int ch); - -// Printing routines and variants for verbose mode -static void putstr(const char str[]); -static void println(void); -static void putstrln(const char str[]); -static void putudec(uint32 val); -static void puttimn(timer_dev *dev); -static void v_putstr(const char str[]); -static void v_println(); -static void v_putstrln(const char str[]); -static void v_putudec(uint32 val); -static void v_puttimn(timer_dev *dev); -// Used to visually separate output from different tests -static void printBanner(void); - -// -// Handler state -// - -static int count1 = 0; -static int count2 = 0; -static int count3 = 0; -static int count4 = 0; -static int timer_num; // Current timer we're considering - -// -// Timer capture/compare interrupt handlers -// -// These are shared between timers. The global variable timer_num -// controls which timer they affect. -// - -static void handler1(void); -static void handler2(void); -static void handler3(void); -static void handler4(void); -static voidFuncPtr handlers[] = {handler1, handler2, handler3, handler4}; - -// -// setup() and loop() -// - -void setup() { - init_usart(COMM_USART, COMM_USART_PORT, - COMM_USART_TX_BIT, COMM_USART_RX_BIT); - _delay(5); - println(); - printBanner(); - putstr("Initializing timers...\r\n"); - timer_foreach(initTimer); - putstr("Done. Running tests.\r\n"); - runTests(); - printBanner(); - putstr("Done testing timers.\r\n"); -} - -void loop() { -} - -// -// Test routine implementations -// - -static void runTests(void) { - runTest("timer_get_count()/timer_set_count()", testGetAndSetCount); - runTest("timer_pause()/timer_resume()", testPauseAndResume); - runTest("capture/compare channels and interrupts", - testTimerChannels); -} - -static void runTest(const char description[], timer_test_t test) { - printBanner(); - putstr("Testing "); - putstr(description); - putstrln("."); - timer_foreach(test); -} - -static void testGetAndSetCount(timer_dev *dev) { - unsigned before, after; - unsigned val_to_set = 1234; - - timer_pause(dev); - before = timer_get_count(dev); - timer_set_count(dev, val_to_set); - after = timer_get_count(dev); - timer_resume(dev); - - if (after != val_to_set) { - puttimn(dev); - putstr(": "); - putstr("*** FAIL: get/set count for "); - puttimn(dev); - putstr("."); - putstr("Start count = "); - putudec(before); - putstr(". Count set to "); - putudec(val_to_set); - putstr(", and now count is = "); - putudec(after); - println(); - } else if (verbose) { - puttimn(dev); - putstr(": "); - putstrln("[ok]"); - } -} - -// This hack works on all currently supported STM32 series, but you -// may need to do something smarter in the future. The assertions -// ensure that our assumptions hold for your target. -static timer_dev *getDifferentTimerOnSameBusAs(timer_dev *dev) { - rcc_clk_domain dev_domain = rcc_dev_clk(dev->clk_id); - ASSERT(RCC_APB1 == dev_domain || RCC_APB2 == dev_domain); - ASSERT(rcc_dev_clk(TIMER1->clk_id) == RCC_APB2); - ASSERT(rcc_dev_clk(TIMER2->clk_id) == RCC_APB1); - ASSERT(rcc_dev_clk(TIMER8->clk_id) == RCC_APB2); - ASSERT(rcc_dev_clk(TIMER3->clk_id) == RCC_APB1); - - if (dev->clk_id == RCC_TIMER1) { - return TIMER8; - } - if (dev->clk_id == RCC_TIMER2) { - return TIMER3; - } - return dev_domain == RCC_APB2 ? TIMER1 : TIMER2; -} - -// Rough test of pause and resume. -// -// Approximately half the time, dev is in the "pause" state and the -// timer doesn't increment, while another timer (`base_dev') on the -// same bus continues. dev and base_dev have identical start counts -// and prescalers. -// -// Since dev and base_dev share a bus (and thus a base clock), and we -// configure them to have the same prescaler and start count, the -// ratio of their end counts should be approximately 1 : 2. We check -// to make sure this is true, up to tolerance `epsilon'. -static void testPauseAndResume(timer_dev *dev) { - timer_dev *base_dev = getDifferentTimerOnSameBusAs(dev); - unsigned start_count = 0, reload = 65535; - // This prescaler should be enough to ensure that we don't - // overflow, while still giving us a reasonably large number of - // timer ticks. - uint16 prescaler = CYCLES_PER_MICROSECOND * 50; - double epsilon = .02; - - if (rcc_dev_clk(base_dev->clk_id) != rcc_dev_clk(dev->clk_id)) { - putstrln("*** ERROR: cannot run test. Bus info is messed up."); - return; - } - - // Pause and set up timers - timer_pause(base_dev); - timer_pause(dev); - timer_set_count(base_dev, start_count); - timer_set_count(dev, start_count); - timer_set_reload(base_dev, reload); - timer_set_reload(dev, reload); - timer_set_prescaler(base_dev, prescaler); - timer_set_prescaler(dev, prescaler); - timer_generate_update(base_dev); - timer_generate_update(dev); - - // Resume the timers and run the test - ASSERT(timer_get_count(base_dev) == start_count); - ASSERT(timer_get_count(dev) == start_count); - timer_resume(base_dev); - timer_resume(dev); - _delay(1000); - timer_pause(dev); - _delay(1000); - timer_pause(base_dev); - - // Check the results - unsigned dev_count = timer_get_count(dev); - unsigned base_count = timer_get_count(base_dev); - double count_ratio = ((double)dev_count / base_count); - bool fail = false; - if (count_ratio > 0.5 + epsilon || count_ratio < 0.5 - epsilon) { - fail = true; - } - if (fail || verbose) { - puttimn(dev); - putstr(" vs. "); - puttimn(base_dev); - putstr(": "); - if (fail) putstr("*** FAIL: "); - else putstr("[ok] "); - putstr("(dev = "); - putudec(dev_count); - putstr(") / (base = "); - putudec(base_count); - putstr(") = "); - // hack hack hack - putudec((int)count_ratio); - count_ratio -= (int)count_ratio; - putstr("."); - int cr_x_100 = (int)(count_ratio * 100); - int hundredths = cr_x_100 % 10; - cr_x_100 /= 10; - int tenths = cr_x_100 % 10; - putudec(tenths); - putudec(hundredths); - println(); - } -} - -// This function touches every capture/compare channel of a given -// timer. The channel counts should be equal within a timer -// regardless of other interrupts on the system (note that this -// doesn't really test timers with only a single capture/compare -// channel; for that, you'll want to do visual inspection of timers -// that share a bus, in verbose mode). -static void testTimerChannels(timer_dev *dev) { - switch (dev->type) { - case TIMER_BASIC: - v_putstr("Skipping basic timer "); - v_puttimn(dev); - v_println(); - return; - case TIMER_ADVANCED: - case TIMER_GENERAL: - // Set up - v_puttimn(dev); - v_println(); - v_putstr("\tchannels: "); - - timer_num = timerNumber(dev); - timer_pause(dev); - count1 = 0; - count2 = 0; - count3 = 0; - count4 = 0; - timer_set_reload(dev, 0xFFFF); - timer_set_prescaler(dev, 1); - for (int c = 1; c <= 4; c++) { - if (timer_has_cc_ch(dev, c)) { - v_putudec(c); - v_putstr("\t"); - timer_set_compare(dev, c, 0xFFFF); - timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE); - timer_attach_interrupt(dev, c, handlers[c - 1]); - } - } - v_println(); - - // Run test - timer_generate_update(dev); - timer_resume(dev); - _delay(250); - timer_pause(dev); - - // Print results - v_putstr("\tcounts: "); - bool fail = false; - bool mismatched[4] = {false, false, false, false}; - int counts[4]; - counts[0] = count1; - counts[1] = count2; - counts[2] = count3; - counts[3] = count4; - bool first = true; - int first_count = -1; - for (int c = 1; c <= 4; c++) { - if (timer_has_cc_ch(dev, c)) { - if (first) { - first_count = counts[c - 1]; - first = false; - } - if (!first && (counts[c - 1] != first_count)) { - mismatched[c - 1] = true; - fail = true; - } - v_putudec(counts[c - 1]); - v_putstr("\t"); - } - } - v_println(); - if (fail) { - for (int i = 0; i < 4; i++) { - if (mismatched[i]) { - putstr("*** FAIL: mismatch on "); - puttimn(dev); - putstr(", channel "); - putudec(i + 1); - putstr(": expected "); - putudec(first_count); - putstr(", got "); - putudec(counts[i]); - println(); - } - } - } else { - puttimn(dev); - putstrln(" [ok]"); - } - v_println(); - - // Clean up - for (int c = 1; c <= 4; c++) { - if (timer_has_cc_ch(dev, c)) { - timer_set_mode(dev, c, TIMER_DISABLED); - } - } - break; - } -} - -// -// Helper implementations -// - -static void _delay(uint32 msec) { - uint32 end = systick_uptime() + msec; - while (systick_uptime() < end) - ; -} - -static void init_usart(usart_dev *dev, gpio_dev *gdev, uint8 tx, uint8 rx) { - usart_config_gpios_async(dev, gdev, rx, gdev, tx, 0); - usart_init(dev); - usart_set_baud_rate(dev, USART_USE_PCLK, COMM_USART_BAUD); - usart_enable(dev); -} - -static bool timer_has_cc_ch(timer_dev *dev, int ch) { - ASSERT(1 <= ch && ch <= 4); - if (dev->type == TIMER_BASIC) - return false; - int tn = timerNumber(dev); - return (// TIM1-5 and 8 have all four channels - (tn <= 5 || tn == 8) || - // TIM9 and 12 only have channels 1 and 2 - ((tn == 9 || tn == 12) && ch <= 2) || - // All other general purpose timers only have channel 1 - (ch == 1)); -} - -static void putstr(const char str[]) { - usart_putstr(COMM_USART, str); -} - -static void println(void) { - putstr("\r\n"); -} - -static void putstrln(const char str[]) { - putstr(str); - println(); -} - -static void putudec(uint32 val) { - usart_putudec(COMM_USART, val); -} - -static void puttimn(timer_dev *dev) { - putstr("TIM"); - putudec(timerNumber(dev)); -} - -static void v_putstr(const char str[]) { - if (verbose) putstr(str); -} - -static void v_println() { - if (verbose) println(); -} - -__attribute__((unused)) /* (shut up, gcc) */ -static void v_putstrln(const char str[]) { - if (verbose) putstrln(str); -} - -static void v_putudec(uint32 val) { - if (verbose) putudec(val); -} - -static void v_puttimn(timer_dev *dev) { - if (verbose) puttimn(dev); -} - -// Used to visually separate output from different tests -static void printBanner(void) { - putstrln("-----------------------------------------------------"); -} - -static void initTimer(timer_dev *dev) { - v_puttimn(dev); - timer_init(dev); - switch (dev->type) { - case TIMER_ADVANCED: - case TIMER_GENERAL: - v_putstr(" channels "); - for (int c = 1; c <= 4; c++) { - if (timer_has_cc_ch(dev, c)) { - v_putudec(c); - v_putstr(" "); - timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE); - } - } - break; - case TIMER_BASIC: - break; - } - v_println(); -} - -static 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; - case RCC_TIMER5: return 5; - case RCC_TIMER6: return 6; - case RCC_TIMER7: return 7; - case RCC_TIMER8: return 8; - case RCC_TIMER9: return 9; - case RCC_TIMER10: return 10; - case RCC_TIMER11: return 11; - case RCC_TIMER12: return 12; - case RCC_TIMER13: return 13; - case RCC_TIMER14: return 14; - default: - ASSERT(0); - return 0; - } -} - -// -// IRQ Handlers -// - -static void handler1(void) { - count1++; -} - -static void handler2(void) { - count2++; -} - -static void handler3(void) { - count3++; -} - -static void handler4(void) { - count4++; -} - -// -// init() and main() -// - -__attribute__((constructor)) void premain() { - init(); -} - -int main(void) { - setup(); - - while (true) { - loop(); - } - return 0; -} |