1541 lines
43 KiB
C
1541 lines
43 KiB
C
/* 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 <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#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);
|
|
}
|
|
|
|
static void test_timer_b_compare_latch_0_up()
|
|
{
|
|
dev = create_timer("");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Up 16 bit, SMCLK, clear */
|
|
write_timer(dev, TxCTL, MC0 | TACLR | TASSEL1);
|
|
|
|
write_timer(dev, TxCCR(0), 2);
|
|
write_timer(dev, TxCCR(2), 5);
|
|
// When CLLD=0, new data is transferred from TBCCRx to TBCLx immediately
|
|
// when TBCCRx is written to.
|
|
write_timer(dev, TxCCTL(0), CCIE);
|
|
write_timer(dev, TxCCTL(2), CCIE);
|
|
step_smclk(dev, 2);
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCCR[0] is immediately transferred to TBCL[0].
|
|
write_timer(dev, TxCCR(0), 10);
|
|
|
|
// Because now TBCL[0] is 10, no overflow interrupt should happen at TBR=2
|
|
step_smclk(dev, 1);
|
|
assert(read_timer(dev, TxR) == 3);
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[2] is 5, comparator interrupt should happen at TBR=5.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(2));
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[2] is 8, comparator interrupt should happen again at TBR=8.
|
|
write_timer(dev, TxCCR(2), 8);
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(2));
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[0] is 10, overflow interrupt should happen again at TBR=10.
|
|
step_smclk(dev, 2);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
assert(read_timer(dev, TxR) == 0);
|
|
}
|
|
|
|
static void test_timer_b_compare_latch_1_up()
|
|
{
|
|
dev = create_timer("3");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Up 16 bit, SMCLK, clear */
|
|
write_timer(dev, TxCTL, MC0 | TACLR | TASSEL1);
|
|
|
|
write_timer(dev, TxCCR(0), 5);
|
|
write_timer(dev, TxCCR(1), 2);
|
|
// When CLLD=1, new data is transferred from TBCCRx to TBCLx when TBR
|
|
// counts to 0.
|
|
write_timer(dev, TxCCTL(0), CLLD0 | CCIE);
|
|
write_timer(dev, TxCCTL(1), CLLD0 | CCIE);
|
|
step_smclk(dev, 2);
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCCR[0] will be transferred to TBCL[0] when next TBR=0.
|
|
write_timer(dev, TxCCR(0), 10);
|
|
// TBCCR[1] will be transferred to TBCL[1] when next TBR=0.
|
|
write_timer(dev, TxCCR(1), 2);
|
|
|
|
// Because TBCL[1] keeps 2, compare interrupt should happen at TBR=2.
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(1));
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[0] keeps 5, compare interrupt should happen at TBR=5, then TBR=0.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(0));
|
|
|
|
// Now TBCL[1] becomes 2, compare interrupt should happen again at TBR=2.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(1));
|
|
assert(check_noirq(dev));
|
|
|
|
// Now TBCL[0] becomes 10, no compare interrupt should happen at TBR=5.
|
|
step_smclk(dev, 7);
|
|
assert(check_noirq(dev));
|
|
|
|
// Then compare interrupt should happen at TBR=10, then TBR=0.
|
|
step_smclk(dev, 1);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(0));
|
|
assert(read_timer(dev, TxR) == 0);
|
|
}
|
|
|
|
static void test_timer_b_compare_latch_2_continuous()
|
|
{
|
|
dev = create_timer("7");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Continuous 8 bit, SMCLK, clear */
|
|
write_timer(dev, TxCTL, MC1 | CNTL1 | CNTL0 | TACLR | TASSEL1);
|
|
write_timer(dev, TxR, 0x00fe);
|
|
|
|
write_timer(dev, TxCCR(6), 2);
|
|
// When CLLD=2, new data is transferred from TBCCRx to TBCLx when TBR
|
|
// counts to 0 for continuous mode.
|
|
write_timer(dev, TxCCTL(6), CLLD1 | CCIE);
|
|
|
|
// TBCCR[6] will be transferred to TBCL[6] when next TBR=0.
|
|
write_timer(dev, TxCCR(6), 5);
|
|
step_smclk(dev, 2);
|
|
assert(read_timer(dev, TxR) == 0);
|
|
|
|
// Now TBCL[6] becomes 5, compare interrupt should not happen at TBR=2.
|
|
step_smclk(dev, 3);
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[6] is 5, compare interrupt should happen at TBR=5.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(6));
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCCR[6] will be transferred to TBCL[6] when next TBR=0,
|
|
// no compare interrupt should happen at TBR=5.
|
|
write_timer(dev, TxCCR(6), 10);
|
|
step_smclk(dev, 0x100);
|
|
assert(check_noirq(dev));
|
|
assert(read_timer(dev, TxR) > 5);
|
|
|
|
// Now TBCL[6] becomes 10, compare interrupt should happen.
|
|
step_smclk(dev, 5);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(6));
|
|
assert(check_noirq(dev));
|
|
}
|
|
|
|
static void test_timer_b_compare_latch_2_up()
|
|
{
|
|
dev = create_timer("5");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Up 16 bit, SMCLK, clear */
|
|
write_timer(dev, TxCTL, MC0 | TACLR | TASSEL1);
|
|
|
|
write_timer(dev, TxCCR(0), 5);
|
|
write_timer(dev, TxCCR(4), 2);
|
|
// When CLLD=2, new data is transferred from TBCCRx to TBCLx when TBR
|
|
// counts to 0.
|
|
write_timer(dev, TxCCTL(0), CLLD0 | CCIE);
|
|
write_timer(dev, TxCCTL(4), CLLD0 | CCIE);
|
|
step_smclk(dev, 2);
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCCR[0] will be transferred to TBCL[0] when next TBR=0.
|
|
write_timer(dev, TxCCR(0), 10);
|
|
// TBCCR[4] will be transferred to TBCL[4] when next TBR=0.
|
|
write_timer(dev, TxCCR(4), 2);
|
|
|
|
// Because TBCL[4] keeps 2, compare interrupt should happen at TBR=2.
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(4));
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[0] keeps 5, compare interrupt should happen at TBR=5, then TBR=0.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(0));
|
|
|
|
// Now TBCL[4] becomes 2, compare interrupt should happen again at TBR=2.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(4));
|
|
assert(check_noirq(dev));
|
|
|
|
// Now TBCL[0] becomes 10, no compare interrupt should happen at TBR=5.
|
|
step_smclk(dev, 7);
|
|
assert(check_noirq(dev));
|
|
|
|
// Then compare interrupt should happen at TBR=10, then TBR=0.
|
|
step_smclk(dev, 1);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(0));
|
|
assert(read_timer(dev, TxR) == 0);
|
|
}
|
|
|
|
static void test_timer_b_compare_latch_2_updown()
|
|
{
|
|
dev = create_timer("7");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Up/Down 16 bit, SMCLK, interrupt enable, clear */
|
|
write_timer(dev, TxCTL, MC1 | MC0 | TACLR | TAIE | TASSEL1);
|
|
|
|
write_timer(dev, TxCCR(0), 10);
|
|
write_timer(dev, TxCCTL(0), CCIE);
|
|
write_timer(dev, TxCCR(5), 5);
|
|
// When CLLD=2, new data is transferred from TBCCRx to TBCLx when TBR
|
|
// counts to the old TBCL0 value or to 0 for up/down mode.
|
|
write_timer(dev, TxCCTL(5), CLLD1 | CCIE);
|
|
step_smclk(dev, 4);
|
|
assert(check_noirq(dev));
|
|
assert(read_timer(dev, TxR) == 4);
|
|
|
|
// TBCCR[5] will be transferred to TBCL[5] when next TBR=5.
|
|
write_timer(dev, TxCCR(5), 8);
|
|
|
|
// Because TBCL[0] is 5, compare interrupt should happen at TBR=TBCL[5]=5.
|
|
step_smclk(dev, 2);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(5));
|
|
assert(check_noirq(dev));
|
|
|
|
// Now TBCL[5] becomes 8, compare interrupt should happen at TBR=8.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(5));
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[0]=10, compare interrupt should happen at TBR=10.
|
|
step_smclk(dev, 2);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(0));
|
|
assert(read_timer(dev, TxR) == 9);
|
|
|
|
// Because TBCL[5] is still 8, compare interrupt should happen again at TBR=8.
|
|
step_smclk(dev, 2);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(5));
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[5] is still 8, no compare interrupt should happen.
|
|
step_smclk(dev, 6);
|
|
assert(read_timer(dev, TxR) == 1);
|
|
|
|
// TBCCR[5] will be transferred to TBCL[5] when next TBR=0.
|
|
write_timer(dev, TxCCR(5), 2);
|
|
|
|
// Compare interrupt should happen at TBR=0.
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TBIV_TBIFG);
|
|
assert(check_noirq(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(0));
|
|
assert(read_timer(dev, TxR) == 0);
|
|
|
|
// Now TBCL[5] becomes 2, compare interrupt should happen at TBR=2.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(5));
|
|
assert(check_noirq(dev));
|
|
assert(read_timer(dev, TxR) == 3);
|
|
}
|
|
|
|
static void test_timer_b_compare_latch_3_up()
|
|
{
|
|
dev = create_timer("5");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Up 16 bit, SMCLK, clear */
|
|
write_timer(dev, TxCTL, MC0 | TACLR | TASSEL1);
|
|
|
|
write_timer(dev, TxCCR(0), 10);
|
|
write_timer(dev, TxCCTL(0), CCIE);
|
|
write_timer(dev, TxCCR(2), 5);
|
|
// When CLLD=3, new data is transferred from TBCCRx to TBCLx when TBR
|
|
// counts to the old TBCL0 value.
|
|
write_timer(dev, TxCCTL(2), CLLD1 | CLLD0 | CCIE);
|
|
step_smclk(dev, 4);
|
|
assert(check_noirq(dev));
|
|
assert(read_timer(dev, TxR) == 4);
|
|
|
|
// TBCCR[2] will be transferred to TBCL[2] when next TBR=5.
|
|
write_timer(dev, TxCCR(2), 8);
|
|
|
|
// Because TBCL[0] is 5, compare interrupt should happen at TBR=TBCL[2]=5.
|
|
step_smclk(dev, 2);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(2));
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCCR[2] will be transferred to TBCL[2] when next TBR=8.
|
|
write_timer(dev, TxCCR(2), 2);
|
|
|
|
// Now TBCL[2] becomes 8, compare interrupt should happen at TBR=8.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(2));
|
|
assert(check_noirq(dev));
|
|
|
|
// Because TBCL[0] is 10, compare interrupt should happen at TBR=10.
|
|
step_smclk(dev, 2);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(0));
|
|
assert(read_timer(dev, TxR) == 0);
|
|
|
|
// Because TBCL[2] is 2, compare interrupt should happen again at TBR=2.
|
|
step_smclk(dev, 3);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(2));
|
|
assert(check_noirq(dev));
|
|
}
|
|
|
|
static void test_timer_b_grouping_1()
|
|
{
|
|
dev = create_timer("7");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Continuous mode, SMCLK, pair grouping */
|
|
write_timer(dev, TxCTL, MC1 | TASSEL1 | TBCLGRP0);
|
|
write_timer(dev, TxCCR(0), 2);
|
|
write_timer(dev, TxCCR(1), 4);
|
|
write_timer(dev, TxCCR(2), 5);
|
|
write_timer(dev, TxCCR(3), 6);
|
|
write_timer(dev, TxCCR(4), 7);
|
|
write_timer(dev, TxCCR(5), 8);
|
|
write_timer(dev, TxCCR(6), 9);
|
|
/* Load TBCL when TBR reaches old TBCL value, compare interrupt */
|
|
write_timer(dev, TxCCTL(0), CLLD1 | CLLD0 | CCIE);
|
|
write_timer(dev, TxCCR(0), 10);
|
|
// Both CCR[1] and CCR[2] are set.
|
|
write_timer(dev, TxCCTL(1), CLLD1 | CLLD0 | CCIE);
|
|
write_timer(dev, TxCCTL(2), CCIE);
|
|
write_timer(dev, TxCCR(1), 12);
|
|
write_timer(dev, TxCCR(2), 13);
|
|
// CCR[3] is set but CCR[4] keep unset.
|
|
write_timer(dev, TxCCTL(3), CLLD1 | CLLD0 | CCIE);
|
|
write_timer(dev, TxCCTL(4), CCIE);
|
|
write_timer(dev, TxCCR(3), 14);
|
|
// Both CCR[5] and CCR[6] are set, but CCTL[5] has CCLD=0.
|
|
write_timer(dev, TxCCTL(5), CCIE);
|
|
write_timer(dev, TxCCTL(6), CLLD1 | CLLD0 | CCIE);
|
|
write_timer(dev, TxCCR(5), 16);
|
|
write_timer(dev, TxCCR(6), 17);
|
|
|
|
step_smclk(dev, 2);
|
|
|
|
// TBCL[0] becomes 10.
|
|
assert(read_timer(dev, TxR) == 2);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCL[1] and TBCL[2] becomes 12 and 13.
|
|
assert(read_timer(dev, TxR) == 3);
|
|
step_smclk(dev, 2);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(1));
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCL[3] and TBCL[4] keep previous value.
|
|
// because TBCCR[4] has no valid value set.
|
|
assert(read_timer(dev, TxR) == 5);
|
|
step_smclk(dev, 2);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(3));
|
|
assert(check_noirq(dev));
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(4));
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCL[5] and TBCL[6] is already 16 and 17 because TBCTL[5]
|
|
// has CLLD=0 set, thus no interrupts at TBR=8,9.
|
|
assert(read_timer(dev, TxR) == 8);
|
|
step_smclk(dev, 1);
|
|
assert(check_noirq(dev));
|
|
step_smclk(dev, 1);
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCL[0] will match.
|
|
step_smclk(dev, 1);
|
|
assert(check_irq0(dev));
|
|
assert(read_timer(dev, TxCCTL(0)) & CCIFG);
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
assert_not(read_timer(dev, TxCCTL(0)) & CCIFG);
|
|
|
|
// TBCL[1]will match.
|
|
step_smclk(dev, 2);
|
|
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);
|
|
// Because TBCL[2] is also loaded as group with TBCL[1].
|
|
step_smclk(dev, 1);
|
|
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);
|
|
|
|
// TBCL[3] and TBCL[4] didn't updated since TBCCR[4] has
|
|
// no value set, thus no compare interrupts at TBR=14,15.
|
|
assert(read_timer(dev, TxR) == 14);
|
|
step_smclk(dev, 1);
|
|
assert(check_noirq(dev));
|
|
step_smclk(dev, 1);
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCL[5] and TBCL[6] have set to 16 and 17, thus two compare
|
|
// interrupts at TBR=16,17
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_timer(dev, TxCCTL(5)) & CCIFG);
|
|
assert(read_iv(dev) == TxIV_TxIFG(5));
|
|
assert(check_noirq(dev));
|
|
assert_not(read_timer(dev, TxCCTL(5)) & CCIFG);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_timer(dev, TxCCTL(6)) & CCIFG);
|
|
assert(read_iv(dev) == TxIV_TxIFG(6));
|
|
assert(check_noirq(dev));
|
|
assert_not(read_timer(dev, TxCCTL(6)) & CCIFG);
|
|
}
|
|
|
|
static void test_timer_b_grouping_2()
|
|
{
|
|
dev = create_timer("7");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Continuous mode, SMCLK, triplet grouping */
|
|
write_timer(dev, TxCTL, MC1 | TASSEL1 | TBCLGRP1);
|
|
write_timer(dev, TxCCR(0), 2);
|
|
write_timer(dev, TxCCR(1), 4);
|
|
write_timer(dev, TxCCR(2), 5);
|
|
write_timer(dev, TxCCR(3), 6);
|
|
write_timer(dev, TxCCR(4), 7);
|
|
write_timer(dev, TxCCR(5), 8);
|
|
write_timer(dev, TxCCR(6), 9);
|
|
/* Load TBCL when TBR reaches old TBCL value, compare interrupt */
|
|
write_timer(dev, TxCCTL(0), CLLD1 | CLLD0 | CCIE);
|
|
write_timer(dev, TxCCR(0), 10);
|
|
// All CCR[1], CCR[2], and CCR[3] are set.
|
|
write_timer(dev, TxCCTL(1), CLLD1 | CLLD0 | CCIE);
|
|
write_timer(dev, TxCCTL(2), CCIE);
|
|
write_timer(dev, TxCCTL(3), CCIE);
|
|
write_timer(dev, TxCCR(1), 12);
|
|
write_timer(dev, TxCCR(2), 6);
|
|
write_timer(dev, TxCCR(3), 5);
|
|
// CCR[4] and CCR[6] are set but CCR[5] keep unset.
|
|
write_timer(dev, TxCCTL(4), CLLD1 | CLLD0 | CCIE);
|
|
write_timer(dev, TxCCTL(5), CCIE);
|
|
write_timer(dev, TxCCTL(6), CCIE);
|
|
write_timer(dev, TxCCR(4), 14);
|
|
write_timer(dev, TxCCR(6), 8);
|
|
|
|
step_smclk(dev, 2);
|
|
|
|
// TBCL[0] becomes 10.
|
|
assert(read_timer(dev, TxR) == 2);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCL[1], TBCL[2], and TBCL[3] becomes 12, 6, and 5.
|
|
assert(read_timer(dev, TxR) == 3);
|
|
step_smclk(dev, 2);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(1));
|
|
assert(check_noirq(dev));
|
|
assert(read_timer(dev, TxR) == 5);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(3));
|
|
assert(check_noirq(dev));
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(2));
|
|
assert(check_noirq(dev));
|
|
|
|
|
|
// TBCL[4], TBCL[5] and TBC[6] keep previous value.
|
|
// because TBCCR[5] has no valid value set.
|
|
assert(read_timer(dev, TxR) == 7);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(4));
|
|
assert(check_noirq(dev));
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(5));
|
|
assert(check_noirq(dev));
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(6));
|
|
assert(check_noirq(dev));
|
|
|
|
// TBCL[0] is updated to 10 and TBCL[1] has 12.
|
|
assert(read_timer(dev, TxR) == 10);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
assert(check_noirq(dev));
|
|
step_smclk(dev, 2);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(1));
|
|
assert(check_noirq(dev));
|
|
}
|
|
|
|
static void test_timer_b_grouping_3()
|
|
{
|
|
dev = create_timer("7");
|
|
config_timer(dev, "type", "B");
|
|
|
|
/* Continuous mode, SMCLK, triplet grouping */
|
|
write_timer(dev, TxCTL, MC1 | TASSEL1 | TBCLGRP1 | TBCLGRP0);
|
|
write_timer(dev, TxCCR(0), 3);
|
|
write_timer(dev, TxCCR(1), 2);
|
|
write_timer(dev, TxCCR(2), 4);
|
|
write_timer(dev, TxCCR(3), 5);
|
|
write_timer(dev, TxCCR(4), 6);
|
|
write_timer(dev, TxCCR(5), 7);
|
|
write_timer(dev, TxCCR(6), 8);
|
|
/* Load TBCL when TBR reaches old TBCL value, compare interrupt */
|
|
write_timer(dev, TxCCTL(0), CCIE);
|
|
write_timer(dev, TxCCTL(1), CLLD1 | CLLD0 | CCIE);
|
|
write_timer(dev, TxCCTL(6), CCIE);
|
|
write_timer(dev, TxCCR(0), 9);
|
|
write_timer(dev, TxCCR(1), 10);
|
|
write_timer(dev, TxCCR(2), 11);
|
|
write_timer(dev, TxCCR(3), 12);
|
|
write_timer(dev, TxCCR(4), 13);
|
|
write_timer(dev, TxCCR(5), 14);
|
|
write_timer(dev, TxCCR(6), 15);
|
|
|
|
step_smclk(dev, 2);
|
|
|
|
// TBCL[1] becomes 10.
|
|
assert(read_timer(dev, TxR) == 2);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(1));
|
|
assert(check_noirq(dev));
|
|
|
|
// The least valued TBCL is TBCL[9].
|
|
step_smclk(dev, 6);
|
|
assert(read_timer(dev, TxR) == 9);
|
|
assert(check_noirq(dev));
|
|
step_smclk(dev, 1);
|
|
assert(check_irq0(dev));
|
|
ack_irq0(dev);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(1));
|
|
step_smclk(dev, 4);
|
|
assert(check_noirq(dev));
|
|
assert(read_timer(dev, TxCCTL(2)) & CCIFG);
|
|
assert(read_timer(dev, TxCCTL(3)) & CCIFG);
|
|
assert(read_timer(dev, TxCCTL(4)) & CCIFG);
|
|
assert(read_timer(dev, TxCCTL(5)) & CCIFG);
|
|
step_smclk(dev, 1);
|
|
assert(check_irq1(dev));
|
|
assert(read_iv(dev) == TxIV_TxIFG(6));
|
|
assert(check_noirq(dev));
|
|
}
|
|
|
|
|
|
/*
|
|
* 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);
|
|
RUN_TEST(test_timer_b_compare_latch_0_up);
|
|
RUN_TEST(test_timer_b_compare_latch_1_up);
|
|
RUN_TEST(test_timer_b_compare_latch_2_continuous);
|
|
RUN_TEST(test_timer_b_compare_latch_2_up);
|
|
RUN_TEST(test_timer_b_compare_latch_2_updown);
|
|
RUN_TEST(test_timer_b_compare_latch_3_up);
|
|
RUN_TEST(test_timer_b_grouping_1);
|
|
RUN_TEST(test_timer_b_grouping_2);
|
|
RUN_TEST(test_timer_b_grouping_3);
|
|
}
|