[simio] Fix timer capturing by software
This commit is contained in:
parent
d49dcefec6
commit
8db02ae3d4
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue