aboutsummaryrefslogtreecommitdiffstats
path: root/examples/test-timers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/test-timers.cpp')
-rw-r--r--examples/test-timers.cpp537
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;
-}