/* MSPDebug - debugging tool for MSP430 MCUs * Copyright (C) 2009, 2010 Daniel Beer * Copyright (C) 2018 Tadashi G. Takaoka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "ctrlc.h" #include "simio.h" #include "stab.h" /* Module under test */ #include "simio_timer.c" /* * Helper functions for testing timer simio. */ static char **setup_args(const char *text) { static char args_buf[80]; static char *args; strncpy(args_buf, text, sizeof(args_buf)); args = args_buf; return &args; } static int* setup_clocks(int mclk, int smclk, int aclk) { static int clocks[SIMIO_NUM_CLOCKS]; clocks[SIMIO_MCLK] = mclk; clocks[SIMIO_SMCLK] = smclk; clocks[SIMIO_ACLK] = aclk; return clocks; } static struct simio_device *create_timer(const char *arg) { return simio_timer.create(setup_args(arg)); } static int config_timer(struct simio_device *dev, const char *param, const char *arg) { return simio_timer.config(dev, param, setup_args(arg)); } /* Register offset from base_addr */ #define TxCTL 0x00 #define TxR 0x10 #define TxCCTL(index) (0x02 + (index) * 2) #define TxCCR(index) (0x12 + (index) * 2) #define TxIV_TxIFG(index) ((index) * 2) static uint16_t read_timer(struct simio_device *dev, int offset) { struct timer *tmr = (struct timer *)dev; uint16_t data; assert(simio_timer.read(dev, tmr->base_addr + offset, &data) == 0); return data; } static void write_timer(struct simio_device *dev, int offset, uint16_t data) { struct timer *tmr = (struct timer *)dev; assert(simio_timer.write(dev, tmr->base_addr + offset, data) == 0); } static uint16_t read_iv(struct simio_device *dev) { struct timer *tmr = (struct timer *)dev; uint16_t iv; assert(simio_timer.read(dev, tmr->iv_addr, &iv) == 0); return iv; } static void step_smclk(struct simio_device *dev, int smclk) { uint16_t status_register = 0; simio_timer.step(dev, status_register, setup_clocks(0, smclk, 0)); } static void step_aclk(struct simio_device *dev, int aclk) { uint16_t status_register = 0; simio_timer.step(dev, status_register, setup_clocks(0, 0, aclk)); } static bool check_noirq(struct simio_device *dev) { return simio_timer.check_interrupt(dev) < 0; } static bool check_irq0(struct simio_device *dev) { struct timer *tmr = (struct timer *)dev; return simio_timer.check_interrupt(dev) == tmr->irq0; } static int check_irq1(struct simio_device *dev) { struct timer *tmr = (struct timer *)dev; return simio_timer.check_interrupt(dev) == tmr->irq1; } static void ack_irq0(struct simio_device *dev) { struct timer *tmr = (struct timer *)dev; simio_timer.ack_interrupt(dev, tmr->irq0); } /* * Working variables for tests. */ static struct simio_device *dev; /* * Set up and tear down for each test. */ static void set_up() { setup_args(""); setup_clocks(0, 0, 0); dev = NULL; } static void tear_down() { if (dev != NULL) { simio_timer.destroy(dev); dev = NULL; } } #define assert_not(e) assert(!(e)) /* * Set up for globals. */ static void set_up_globals() { ctrlc_init(); stab_init(); } /* * Tests for timer simio. */ static void test_create_no_option() { dev = create_timer(""); assert(dev != NULL); assert(dev->type != NULL); assert(strcmp(dev->type->name, "timer") == 0); // Check default values. struct timer *tmr = (struct timer *)dev; assert(tmr->size == 3); assert(tmr->timer_type == TIMER_TYPE_A); assert(tmr->base_addr == 0x0160); assert(tmr->iv_addr == 0x012e); assert(tmr->irq0 == 9); assert(tmr->irq1 == 8); } static void test_create_with_size_7() { dev = create_timer("7"); // Timer can have 7 comparators/captures at most. struct timer *tmr = (struct timer *)dev; assert(tmr->size == 7); } static void test_create_with_size_2() { dev = create_timer("2"); // Timer should have 2 comparators/captures at least. struct timer *tmr = (struct timer *)dev; assert(tmr->size == 2); } static void test_create_with_size_8() { dev = create_timer("8"); // Timer can't have 8 or more comparators/captures. assert(dev == NULL); } static void test_create_with_size_1() { dev = create_timer("1"); // Timer can't have 1 or no comparator/capture. assert(dev == NULL); } static void test_config_type_default() { dev = create_timer(""); // Default timer type is A. struct timer *tmr = (struct timer *)dev; assert(tmr->timer_type == TIMER_TYPE_A); } static void test_config_type_A() { dev = create_timer(""); // Timer can configured as type A. assert(config_timer(dev, "type", "A") == 0); struct timer *tmr = (struct timer *)dev; assert(tmr->timer_type == TIMER_TYPE_A); } static void test_config_type_B() { dev = create_timer(""); // Timer can configured as type B. struct timer *tmr = (struct timer *)dev; assert(config_timer(dev, "type", "B") == 0); assert(tmr->timer_type == TIMER_TYPE_B); } static void test_config_type_bad() { dev = create_timer(""); struct timer *tmr = (struct timer *)dev; // Timer can't configured other than A/B. assert(config_timer(dev, "type", "bad") != 0); } static void test_config_type_empty() { dev = create_timer(""); struct timer *tmr = (struct timer *)dev; // Timer type can't be empty. assert(config_timer(dev, "type", "") != 0); } static void test_address_space() { dev = create_timer("7"); struct timer *tmr = (struct timer *)dev; for (uint32_t a = 0; a < 0x10000; a += 2) { const address_t addr = (address_t)a; uint16_t data; // Timer has 16 word registers from its base address. if (addr >= tmr->base_addr && addr < tmr->base_addr + 0x20) { assert(simio_timer.read(dev, addr, &data) == 0); assert(simio_timer.write(dev, addr, data) == 0); } // Timer has 1 word register as vector register. else if (addr == tmr->iv_addr) { assert(simio_timer.read(dev, addr, &data) == 0); assert(simio_timer.write(dev, addr, data) == 0); } // Timer has no register other than above. else { assert(simio_timer.read(dev, addr, &data) != 0); assert(simio_timer.write(dev, addr, data) != 0); } } } static void test_timer_continuous() { dev = create_timer(""); /* Continuous mode, SMCLK, clear */ write_timer(dev, TxCTL, MC1 | TASSEL1 | TACLR); // When TxCCR[0]=0 in continuous mode, then counter stops. write_timer(dev, TxCCTL(0), 0); write_timer(dev, TxCCR(0), 0); assert(read_timer(dev, TxR) == 0); step_smclk(dev, 10); assert(read_timer(dev, TxR) == 10); step_aclk(dev, 10); assert(read_timer(dev, TxR) == 10); } static void test_timer_stop() { dev = create_timer(""); /* Stop mode, SMCLK, clear */ write_timer(dev, TxCTL, TASSEL1 | TACLR); // When TxCCR[0]>0 in stop mode, then counter stops. write_timer(dev, TxCCTL(0), 0); write_timer(dev, TxCCR(0), 100); assert(read_timer(dev, TxR) == 0); step_smclk(dev, 10); assert(read_timer(dev, TxR) == 0); } static void test_timer_up_stop() { dev = create_timer(""); /* Up mode, SMCLK, clear */ write_timer(dev, TxCTL, MC0 | TASSEL1 | TACLR); // When TxCCR[0]=0 in up mode, then counter stops. write_timer(dev, TxCCTL(0), 0); write_timer(dev, TxCCR(0), 0); assert(read_timer(dev, TxR) == 0); step_smclk(dev, 10); assert(read_timer(dev, TxR) == 0); } static void test_timer_updown_stop() { dev = create_timer(""); /* Up/Down mode, SMCLK, clear */ write_timer(dev, TxCTL, MC1 | MC0 | TASSEL1 | TACLR); // When TxCCR[0]=0 in up/down mode, then counter stops. write_timer(dev, TxCCTL(0), 0); write_timer(dev, TxCCR(0), 0); assert(read_timer(dev, TxR) == 0); step_smclk(dev, 10); assert(read_timer(dev, TxR) == 0); } static void test_timer_a_up() { dev = create_timer(""); /* Up mode, SMCLK, enable interrupt, clear */ write_timer(dev, TxCTL, MC0 | TASSEL1 | TACLR | TAIE); /* Enable compare interrupt */ write_timer(dev, TxCCTL(0), CCIE); write_timer(dev, TxCCR(0), 10); step_smclk(dev, 10); assert(read_timer(dev, TxR) == 10); // Compare interrupt and TAIFG interrupt both will happen. step_smclk(dev, 1); assert(read_timer(dev, TxR) == 0); assert(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCTL) & TAIFG); // Compare interrupt has priority. assert(check_irq0(dev)); ack_irq0(dev); assert_not(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCTL) & TAIFG); // Then TAIFG interrupt should happen. assert(check_irq1(dev)); assert(read_iv(dev) == TAIV_TAIFG); assert_not(read_timer(dev, TxCTL) & TAIFG); assert(check_noirq(dev)); } static void test_timer_a_up_change_period() { dev = create_timer(""); /* Up mode, SMCLK, enable interrupt, clear */ write_timer(dev, TxCTL, MC0 | TASSEL1 | TACLR | TAIE); write_timer(dev, TxCCTL(0), CCIE); write_timer(dev, TxCCR(0), 10); step_smclk(dev, 8); // Changing period to less than current count will roll down // counter to 0. assert(read_timer(dev, TxR) == 8); write_timer(dev, TxCCR(0), 5); assert(check_noirq(dev)); // TAIFG interrupt should happen. step_smclk(dev, 1); assert(read_timer(dev, TxR) == 0); assert(check_irq1(dev)); assert(read_timer(dev, TxCTL) & TAIFG); assert(read_iv(dev) == TAIV_TAIFG); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCTL) & TAIFG); step_smclk(dev, 4); assert(read_timer(dev, TxR) == 4); // Changing period to greater that current count will continue // counting to the new period. write_timer(dev, TxCCR(0), 8); step_smclk(dev, 4); assert(check_noirq(dev)); assert(read_timer(dev, TxR) == 8); // Compare interrupt should happen at new period TAR=8 step_smclk(dev, 1); assert(read_timer(dev, TxR) == 0); assert(check_irq0(dev)); assert(read_timer(dev, TxCCTL(0)) & CCIFG); ack_irq0(dev); assert_not(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCTL) & TAIFG); assert(check_irq1(dev)); assert(read_iv(dev) == TAIV_TAIFG); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCTL) & TAIFG); } static void test_timer_a_updown_change_period() { dev = create_timer(""); /* Up/Down mode, SMCLK, enable interrupt, clear */ write_timer(dev, TxCTL, MC1 | MC0 | TASSEL1 | TACLR | TAIE); write_timer(dev, TxCCTL(0), CCIE); write_timer(dev, TxCCR(0), 10); step_smclk(dev, 8); // While counting up, changing period to less than current // count will change the counting direction to down. assert(read_timer(dev, TxR) == 8); write_timer(dev, TxCCR(0), 5); assert(read_timer(dev, TxR) == 8); step_smclk(dev, 2); assert(read_timer(dev, TxR) == 6); assert(check_noirq(dev)); // While counting down, Changing period to greater that // current count will continue counting to 0. write_timer(dev, TxCCR(0), 8); step_smclk(dev, 6); assert(check_irq1(dev)); assert(read_iv(dev) == TAIV_TAIFG); assert(check_noirq(dev)); assert(read_timer(dev, TxR) == 0); // Then count up to TACCR[0] and compare interrupt should happen. step_smclk(dev, 8); assert(check_noirq(dev)); assert(read_timer(dev, TxR) == 8); step_smclk(dev, 1); assert(check_irq0(dev)); assert(read_timer(dev, TxCCTL(0)) & CCIFG); ack_irq0(dev); assert(check_noirq(dev)); assert(read_timer(dev, TxR) == 7); } static void test_timer_divider() { dev = create_timer(""); /* Continuous mode, SMCLK/1, clear */ write_timer(dev, TxCTL, MC1 | TASSEL1 | TACLR); assert(read_timer(dev, TxR) == 0); step_smclk(dev, 80); assert(read_timer(dev, TxR) == 80); step_aclk(dev, 100); assert(read_timer(dev, TxR) == 80); /* Continuous mode, SMCLK/2, clear */ write_timer(dev, TxCTL, MC1 | TASSEL1 | ID0 | TACLR); assert(read_timer(dev, TxR) == 0); step_smclk(dev, 80); assert(read_timer(dev, TxR) == 40); step_aclk(dev, 100); assert(read_timer(dev, TxR) == 40); /* Continuous mode, SMCLK/4, clear */ write_timer(dev, TxCTL, MC1 | TASSEL1 | ID1 | TACLR); assert(read_timer(dev, TxR) == 0); step_smclk(dev, 80); assert(read_timer(dev, TxR) == 20); step_aclk(dev, 100); assert(read_timer(dev, TxR) == 20); /* Continuous mode, SMCLK/2, clear */ write_timer(dev, TxCTL, MC1 | TASSEL1 | ID1 | ID0 | TACLR); assert(read_timer(dev, TxR) == 0); step_smclk(dev, 80); assert(read_timer(dev, TxR) == 10); step_aclk(dev, 100); assert(read_timer(dev, TxR) == 10); /* Continuous mode, ACLK/1, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | TACLR); assert(read_timer(dev, TxR) == 0); step_aclk(dev, 80); assert(read_timer(dev, TxR) == 80); step_smclk(dev, 100); assert(read_timer(dev, TxR) == 80); /* Continuous mode, ACLK/2, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | ID0 | TACLR); assert(read_timer(dev, TxR) == 0); step_aclk(dev, 80); assert(read_timer(dev, TxR) == 40); step_smclk(dev, 100); assert(read_timer(dev, TxR) == 40); /* Continuous mode, ACLK/4, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | ID1 | TACLR); assert(read_timer(dev, TxR) == 0); step_aclk(dev, 80); assert(read_timer(dev, TxR) == 20); step_smclk(dev, 100); assert(read_timer(dev, TxR) == 20); /* Continuous mode, ACLK/2, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | ID1 | ID0 | TACLR); assert(read_timer(dev, TxR) == 0); step_aclk(dev, 80); assert(read_timer(dev, TxR) == 10); step_smclk(dev, 100); assert(read_timer(dev, TxR) == 10); } static void test_timer_capture_by_software() { dev = create_timer(""); /* Continuous mode, ACLK, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | TACLR); /* Capture mode, input GND, both edge */ write_timer(dev, TxCCTL(0), CAP | CCIS1 | CM1 | CM0); step_aclk(dev, 10); // Rising edge. write_timer(dev, TxCCTL(0), read_timer(dev, TxCCTL(0)) | CCIS0); assert(read_timer(dev, TxCCTL(0)) & CCI); assert_not(read_timer(dev, TxCCTL(0)) & COV); assert(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCCR(0)) == 10); write_timer(dev, TxCCTL(0), read_timer(dev, TxCCTL(0)) & ~CCIFG); step_aclk(dev, 10); // Falling edge. write_timer(dev, TxCCTL(0), read_timer(dev, TxCCTL(0)) & ~CCIS0); assert_not(read_timer(dev, TxCCTL(0)) & CCI); assert_not(read_timer(dev, TxCCTL(0)) & COV); assert(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCCR(0)) == 20); // Keep CCIFG on and capture causes COV */ step_aclk(dev, 10); // Rising edge. write_timer(dev, TxCCTL(0), read_timer(dev, TxCCTL(0)) | CCIS0); assert(read_timer(dev, TxCCTL(0)) & CCI); assert(read_timer(dev, TxCCTL(0)) & COV); assert(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCCR(0)) == 20); /* Capture mode, input GND, rising edge */ write_timer(dev, TxCCTL(1), CAP | CCIS1 | CM0); // Rising edge. write_timer(dev, TxCCTL(1), read_timer(dev, TxCCTL(1)) | CCIS0); assert(read_timer(dev, TxCCTL(1)) & CCI); assert_not(read_timer(dev, TxCCTL(1)) & COV); assert(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_timer(dev, TxCCR(1)) == 30); write_timer(dev, TxCCTL(1), read_timer(dev, TxCCTL(1)) & ~CCIFG); step_aclk(dev, 10); // Falling edge. write_timer(dev, TxCCTL(1), read_timer(dev, TxCCTL(1)) & ~CCIS0); assert_not(read_timer(dev, TxCCTL(1)) & CCI); assert_not(read_timer(dev, TxCCTL(1)) & COV); assert_not(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_timer(dev, TxCCR(1)) == 30); /* Capture mode, input GND, falling edge */ write_timer(dev, TxCCTL(2), CAP | CCIS1 | CM1); // Rising edge. write_timer(dev, TxCCTL(2), read_timer(dev, TxCCTL(2)) | CCIS0); assert(read_timer(dev, TxCCTL(2)) & CCI); assert_not(read_timer(dev, TxCCTL(2)) & COV); assert_not(read_timer(dev, TxCCTL(2)) & CCIFG); assert(read_timer(dev, TxCCR(2)) == 0); step_aclk(dev, 10); // Falling edge. write_timer(dev, TxCCTL(2), read_timer(dev, TxCCTL(2)) & ~CCIS0); assert_not(read_timer(dev, TxCCTL(2)) & CCI); assert_not(read_timer(dev, TxCCTL(2)) & COV); assert(read_timer(dev, TxCCTL(2)) & CCIFG); assert(read_timer(dev, TxCCR(2)) == 50); } static void test_timer_capture_by_signal() { dev = create_timer(""); /* Continuous mode, ACLK, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | TACLR); /* Capture mode, input CCIxA, both edge */ write_timer(dev, TxCCTL(0), CAP | CM1 | CM0); step_aclk(dev, 10); // Rising edge. config_timer(dev, "set", "0 1"); assert(read_timer(dev, TxCCTL(0)) & CCI); assert_not(read_timer(dev, TxCCTL(0)) & COV); assert(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCCR(0)) == 10); write_timer(dev, TxCCTL(0), read_timer(dev, TxCCTL(0)) & ~CCIFG); step_aclk(dev, 10); // Falling edge. config_timer(dev, "set", "0 0"); assert_not(read_timer(dev, TxCCTL(0)) & CCI); assert_not(read_timer(dev, TxCCTL(0)) & COV); assert(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCCR(0)) == 20); // Keep CCIFG on and capture causes COV */ step_aclk(dev, 10); // Rising edge. config_timer(dev, "set", "0 1"); assert(read_timer(dev, TxCCTL(0)) & CCI); assert(read_timer(dev, TxCCTL(0)) & COV); assert(read_timer(dev, TxCCTL(0)) & CCIFG); assert(read_timer(dev, TxCCR(0)) == 20); /* Capture mode, input CCIxB, rising edge, enable interrupt */ write_timer(dev, TxCCTL(1), CAP | CCIS0 | CM0 | CCIE); // Rising edge. config_timer(dev, "set", "1 1"); assert(check_irq1(dev)); assert(read_timer(dev, TxCCTL(1)) & CCI); assert(read_timer(dev, TxCCTL(1)) & CCIFG); assert_not(read_timer(dev, TxCCTL(1)) & COV); assert(read_iv(dev) == TxIV_TxIFG(1)); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_timer(dev, TxCCR(1)) == 30); write_timer(dev, TxCCTL(1), read_timer(dev, TxCCTL(1)) & ~CCIFG); step_aclk(dev, 10); // Falling edge. config_timer(dev, "set", "1 0"); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(1)) & CCI); assert_not(read_timer(dev, TxCCTL(1)) & COV); assert_not(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_timer(dev, TxCCR(1)) == 30); /* Capture mode, input CCIxB falling edge, enable interrupt */ write_timer(dev, TxCCTL(2), CAP | CCIS0 | CM1 | CCIE); // Rising edge. config_timer(dev, "set", "2 1"); assert(check_noirq(dev)); assert(read_timer(dev, TxCCTL(2)) & CCI); assert_not(read_timer(dev, TxCCTL(2)) & COV); assert_not(read_timer(dev, TxCCTL(2)) & CCIFG); assert(read_timer(dev, TxCCR(2)) == 0); step_aclk(dev, 10); // Falling edge. config_timer(dev, "set", "2 0"); assert(check_irq1(dev)); assert_not(read_timer(dev, TxCCTL(2)) & CCI); assert_not(read_timer(dev, TxCCTL(2)) & COV); assert(read_timer(dev, TxCCTL(2)) & CCIFG); assert(read_iv(dev) == TxIV_TxIFG(2)); assert(check_noirq(dev)); assert(read_timer(dev, TxCCR(2)) == 50); } static void test_timer_a_compare() { dev = create_timer(""); /* Continuous mode, ACLK, interrupt enable, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | TACLR | TAIE); write_timer(dev, TxR, 0xffff); /* Compare mode, enable interrupts */ write_timer(dev, TxCCTL(0), CCIE); write_timer(dev, TxCCR(0), 200); write_timer(dev, TxCCTL(1), CCIE); write_timer(dev, TxCCR(1), 100); write_timer(dev, TxCCTL(2), CCIE); write_timer(dev, TxCCR(2), 200); // Timer_A overflow interrupt should happen. step_aclk(dev, 1); assert(check_irq1(dev)); // Timer_A overflow vector is 0x0a. assert(TAIV_TAIFG == 0x0a); assert(read_iv(dev) == TAIV_TAIFG); assert(check_noirq(dev)); assert(read_timer(dev, TxR) == 0); step_aclk(dev, 100); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(1)) & SCCI); // Set CCI of CCTL[1] to 1. config_timer(dev, "set", "1 1"); // Timer_A comparator interrupt should happen. step_aclk(dev, 1); assert(check_irq1(dev)); assert(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_iv(dev) == TxIV_TxIFG(1)); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_timer(dev, TxCCTL(1)) & SCCI); // Timer_A comparator interrupts should happen. step_aclk(dev, 100); assert(check_irq0(dev)); assert(read_timer(dev, TxCCTL(0)) & CCIFG); ack_irq0(dev); assert_not(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(0)) & CCIFG); // Lower priority interrupt. assert(check_irq1(dev)); assert(read_timer(dev, TxCCTL(2)) & CCIFG); assert(read_iv(dev) == TxIV_TxIFG(2)); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(2)) & CCIFG); // Set CCI of CCTL[1] to 0. config_timer(dev, "set", "1 0"); write_timer(dev, TxCCR(1), 300); step_aclk(dev, 100); // Timer_A comparator interrupt should happen. assert(check_irq1(dev)); assert(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_iv(dev) == TxIV_TxIFG(1)); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(1)) & CCIFG); assert_not(read_timer(dev, TxCCTL(1)) & SCCI); } static void test_timer_b_compare() { dev = create_timer(""); config_timer(dev, "type", "B"); /* Continuous mode, ACLK, interrupt enable, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | TACLR | TAIE); write_timer(dev, TxR, 0xffff); /* Compare mode, enable interrupts */ write_timer(dev, TxCCTL(0), CCIE); write_timer(dev, TxCCR(0), 200); write_timer(dev, TxCCTL(1), CCIE); write_timer(dev, TxCCR(1), 100); write_timer(dev, TxCCTL(2), CCIE); write_timer(dev, TxCCR(2), 200); // Timer_B overflow interrupt should happen. step_aclk(dev, 1); assert(check_irq1(dev)); // Timer_B overflow vector is 0x0e. assert(TBIV_TBIFG == 0x0e); assert(read_iv(dev) == TBIV_TBIFG); assert(check_noirq(dev)); assert(read_timer(dev, TxR) == 0); step_aclk(dev, 100); assert(check_noirq(dev)); // Set CCI of CCTL[1] to 1. config_timer(dev, "set", "1 1"); // Timer_B comparator interrupt should happen. step_aclk(dev, 1); assert(check_irq1(dev)); assert(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_iv(dev) == TxIV_TxIFG(1)); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(1)) & CCIFG); // Timer_B comparator interrupts should happen. step_aclk(dev, 100); assert(check_irq0(dev)); assert(read_timer(dev, TxCCTL(0)) & CCIFG); ack_irq0(dev); assert_not(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(0)) & CCIFG); // Lower priority interrupt. assert(check_irq1(dev)); assert(read_timer(dev, TxCCTL(2)) & CCIFG); assert(read_iv(dev) == TxIV_TxIFG(2)); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(2)) & CCIFG); // Set CCI of CCTL[1] to 0. config_timer(dev, "set", "1 0"); write_timer(dev, TxCCR(1), 300); step_aclk(dev, 100); // Timer_B comparator interrupt should happen. assert(check_irq1(dev)); assert(read_timer(dev, TxCCTL(1)) & CCIFG); assert(read_iv(dev) == TxIV_TxIFG(1)); assert(check_noirq(dev)); assert_not(read_timer(dev, TxCCTL(1)) & CCIFG); } static void test_timer_capture() { dev = create_timer(""); /* Continuous mode, ACLK, clear */ write_timer(dev, TxCTL, MC1 | TASSEL0 | TACLR); /* Capture mode, enable interrupts */ } static void test_timer_b_length_8() { dev = create_timer(""); config_timer(dev, "type", "B"); /* Continuous 8 bit, SMCLK, interrupt enable, clear */ write_timer(dev, TxCTL, MC1 | CNTL1 | CNTL0 | TACLR | TAIE | TASSEL1); write_timer(dev, TxR, 0x00ff); step_smclk(dev, 2); // Timer B can configured as 8 bit length. assert(check_irq1(dev)); assert(read_iv(dev) == TBIV_TBIFG); assert(read_timer(dev, TxR) == 1); } static void test_timer_b_length_10() { dev = create_timer(""); config_timer(dev, "type", "B"); /* Continuous 10 bit, ACLK, interrupt enable, clear */ write_timer(dev, TxCTL, MC1 | CNTL1 | TACLR | TAIE | TASSEL0); write_timer(dev, TxR, 0x03ff); step_aclk(dev, 3); // Timer B can configured as 10 bit length. assert(check_irq1(dev)); assert(read_iv(dev) == TBIV_TBIFG); assert(read_timer(dev, TxR) == 2); } static void test_timer_b_length_12() { dev = create_timer(""); config_timer(dev, "type", "B"); /* Continuous 12 bit, SMCLK, interrupt enable, clear */ write_timer(dev, TxCTL, MC1 | CNTL0 | TACLR | TAIE | TASSEL1); write_timer(dev, TxR, 0x0fff); step_smclk(dev, 4); // Timer B can configured as 12 bit length. assert(check_irq1(dev)); assert(read_iv(dev) == TBIV_TBIFG); assert(read_timer(dev, TxR) == 3); } static void test_timer_b_length_16() { dev = create_timer(""); config_timer(dev, "type", "B"); /* Continuous 16 bit, SMCLK, interrupt enable, clear */ write_timer(dev, TxCTL, MC1 | TACLR | TAIE | TASSEL1); write_timer(dev, TxR, 0xffff); step_smclk(dev, 5); // Timer B can configured as 16 bit length. assert(check_irq1(dev)); assert(read_iv(dev) == TBIV_TBIFG); assert(read_timer(dev, TxR) == 4); } /* * Test runner. */ static void run_test(void (*test)(), const char *test_name) { set_up(); test(); printf(" PASS %s\n", test_name); tear_down(); } #define RUN_TEST(test) run_test(test, #test) int main(int argc, char **argv) { set_up_globals(); RUN_TEST(test_create_no_option); RUN_TEST(test_create_with_size_7); RUN_TEST(test_create_with_size_2); RUN_TEST(test_create_with_size_8); RUN_TEST(test_create_with_size_1); RUN_TEST(test_config_type_default); RUN_TEST(test_config_type_A); RUN_TEST(test_config_type_B); RUN_TEST(test_config_type_bad); RUN_TEST(test_config_type_empty); RUN_TEST(test_address_space); RUN_TEST(test_timer_continuous); RUN_TEST(test_timer_stop); RUN_TEST(test_timer_up_stop); RUN_TEST(test_timer_updown_stop); RUN_TEST(test_timer_a_up); RUN_TEST(test_timer_a_up_change_period); RUN_TEST(test_timer_a_updown_change_period); RUN_TEST(test_timer_divider); RUN_TEST(test_timer_capture_by_software); RUN_TEST(test_timer_capture_by_signal); RUN_TEST(test_timer_a_compare); RUN_TEST(test_timer_b_compare); RUN_TEST(test_timer_b_length_8); RUN_TEST(test_timer_b_length_10); RUN_TEST(test_timer_b_length_12); RUN_TEST(test_timer_b_length_16); }