[simio] Fix timer capturing by software

This commit is contained in:
Tadashi G. Takaoka 2018-06-29 12:25:24 +09:00
parent d49dcefec6
commit 8db02ae3d4
2 changed files with 109 additions and 29 deletions

View File

@ -168,14 +168,40 @@ static int config_irq(int *irq, char **arg_text)
return 0; return 0;
} }
static void trigger_capture(struct timer *tr, int which, int oldval, int value)
{
uint16_t edge_flags = 0;
tr->ctls[which] &= ~CCI;
if (value)
tr->ctls[which] |= CCI;
if (oldval && !value)
edge_flags |= CM1;
if (!oldval && value)
edge_flags |= CM0;
printc_dbg("Timer channel %d: %s => %s\n",
which, oldval ? "H" : "L", value ? "H" : "L");
if ((tr->ctls[which] & edge_flags) && (tr->ctls[which] & CAP)) {
if (tr->ctls[which] & CCIFG) {
printc_dbg("Timer capture overflow\n");
tr->ctls[which] |= COV;
} else {
printc_dbg("Timer capture interrupt triggered\n");
tr->ccrs[which] = tr->tar;
tr->ctls[which] |= CCIFG;
}
}
}
static int config_channel(struct timer *tr, char **arg_text) static int config_channel(struct timer *tr, char **arg_text)
{ {
char *which_text = get_arg(arg_text); char *which_text = get_arg(arg_text);
char *value_text = get_arg(arg_text); char *value_text = get_arg(arg_text);
address_t which; address_t which;
address_t value; address_t value;
int oldval;
uint16_t edge_flags = 0;
if (!(which_text && value_text)) { if (!(which_text && value_text)) {
printc_err("timer: config: expected channel and value\n"); printc_err("timer: config: expected channel and value\n");
@ -199,29 +225,7 @@ static int config_channel(struct timer *tr, char **arg_text)
return -1; return -1;
} }
oldval = tr->ctls[which] & CCI; trigger_capture(tr, which, tr->ctls[which] & CCI, value);
tr->ctls[which] &= ~CCI;
if (value)
tr->ctls[which] |= CCI;
if (oldval && !value)
edge_flags |= CM1;
if (!oldval && value)
edge_flags |= CM0;
printc_dbg("Timer channel %d: %s => %s\n",
which, oldval ? "H" : "L", value ? "H" : "L");
if ((tr->ctls[which] & edge_flags) && (tr->ctls[which] & CAP)) {
if (tr->ctls[which] & CCIFG) {
printc_dbg("Timer capture overflow\n");
tr->ctls[which] |= COV;
} else {
printc_dbg("Timer capture interrupt triggered\n");
tr->ccrs[which] = tr->tar;
tr->ctls[which] |= CCIFG;
}
}
return 0; return 0;
} }
@ -311,9 +315,12 @@ static int timer_write(struct simio_device *dev,
if (addr >= tr->base_addr + 2 && if (addr >= tr->base_addr + 2 &&
addr < tr->base_addr + (tr->size << 1) + 2) { addr < tr->base_addr + (tr->size << 1) + 2) {
int index = ((addr & 0xf) - 2) >> 1; int index = ((addr & 0xf) - 2) >> 1;
uint16_t oldval = tr->ctls[index];
tr->ctls[index] = (data & 0xf9f7) | tr->ctls[index] = (data & 0xf9f7) | (oldval & 0x0608);
(tr->ctls[index] & 0x0608); /* Check capture initiated by Software */
if ((data & (CAP | CCIS1)) == (CAP | CCIS1))
trigger_capture(tr, index, oldval & CCI, data & CCIS0);
return 0; return 0;
} }

View File

@ -505,7 +505,79 @@ static void test_timer_divider()
assert(read_timer(dev, TxR) == 10); assert(read_timer(dev, TxR) == 10);
} }
static void test_timer_capture() 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(""); dev = create_timer("");
@ -685,6 +757,7 @@ int main(int argc, char **argv)
RUN_TEST(test_timer_up_change_period); RUN_TEST(test_timer_up_change_period);
RUN_TEST(test_timer_updown_change_period); RUN_TEST(test_timer_updown_change_period);
RUN_TEST(test_timer_divider); RUN_TEST(test_timer_divider);
RUN_TEST(test_timer_capture); RUN_TEST(test_timer_capture_by_software);
RUN_TEST(test_timer_capture_by_signal);
RUN_TEST(test_timer_compare); RUN_TEST(test_timer_compare);
} }