[simio] Fix changing timer period
This commit is contained in:
parent
b323849d8a
commit
d49dcefec6
|
@ -16,6 +16,7 @@
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ struct timer {
|
||||||
|
|
||||||
int size;
|
int size;
|
||||||
int clock_input;
|
int clock_input;
|
||||||
int go_down;
|
bool go_down;
|
||||||
|
|
||||||
address_t base_addr;
|
address_t base_addr;
|
||||||
address_t iv_addr;
|
address_t iv_addr;
|
||||||
|
@ -126,7 +127,7 @@ static void timer_reset(struct simio_device *dev)
|
||||||
|
|
||||||
tr->tactl = 0;
|
tr->tactl = 0;
|
||||||
tr->tar = 0;
|
tr->tar = 0;
|
||||||
tr->go_down = 0;
|
tr->go_down = false;
|
||||||
memset(tr->ccrs, 0, sizeof(tr->ccrs));
|
memset(tr->ccrs, 0, sizeof(tr->ccrs));
|
||||||
memset(tr->ctls, 0, sizeof(tr->ctls));
|
memset(tr->ctls, 0, sizeof(tr->ctls));
|
||||||
}
|
}
|
||||||
|
@ -321,6 +322,12 @@ static int timer_write(struct simio_device *dev,
|
||||||
int index = ((addr & 0xf) - 2) >> 1;
|
int index = ((addr & 0xf) - 2) >> 1;
|
||||||
|
|
||||||
tr->ccrs[index] = data;
|
tr->ccrs[index] = data;
|
||||||
|
if (index == 0 && tr->ccrs[index] < tr->tar &&
|
||||||
|
(tr->tactl & (MC1 | MC0)) == MC0) {
|
||||||
|
/* When CCR[0] is set less than current TAR in up
|
||||||
|
* mode, TAR rolls to 0. */
|
||||||
|
tr->go_down = true;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,9 +407,10 @@ static void tar_step(struct timer *tr)
|
||||||
switch ((tr->tactl >> 4) & 3) {
|
switch ((tr->tactl >> 4) & 3) {
|
||||||
case 0: break;
|
case 0: break;
|
||||||
case 1:
|
case 1:
|
||||||
if (tr->tar == tr->ccrs[0]) {
|
if (tr->tar == tr->ccrs[0] || tr->go_down) {
|
||||||
tr->tar = 0;
|
tr->tar = 0;
|
||||||
tr->tactl |= TAIFG;
|
tr->tactl |= TAIFG;
|
||||||
|
tr->go_down = false;
|
||||||
} else {
|
} else {
|
||||||
tr->tar++;
|
tr->tar++;
|
||||||
}
|
}
|
||||||
|
@ -416,9 +424,9 @@ static void tar_step(struct timer *tr)
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
if (tr->tar >= tr->ccrs[0])
|
if (tr->tar >= tr->ccrs[0])
|
||||||
tr->go_down = 1;
|
tr->go_down = true;
|
||||||
if (!tr->tar)
|
if (!tr->tar)
|
||||||
tr->go_down = 0;
|
tr->go_down = false;
|
||||||
|
|
||||||
if (tr->go_down) {
|
if (tr->go_down) {
|
||||||
tr->tar--;
|
tr->tar--;
|
||||||
|
|
|
@ -348,6 +348,94 @@ static void test_timer_up()
|
||||||
assert(check_noirq(dev));
|
assert(check_noirq(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_timer_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_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()
|
static void test_timer_divider()
|
||||||
{
|
{
|
||||||
dev = create_timer("");
|
dev = create_timer("");
|
||||||
|
@ -594,6 +682,8 @@ int main(int argc, char **argv)
|
||||||
RUN_TEST(test_timer_up_stop);
|
RUN_TEST(test_timer_up_stop);
|
||||||
RUN_TEST(test_timer_updown_stop);
|
RUN_TEST(test_timer_updown_stop);
|
||||||
RUN_TEST(test_timer_up);
|
RUN_TEST(test_timer_up);
|
||||||
|
RUN_TEST(test_timer_up_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);
|
||||||
RUN_TEST(test_timer_compare);
|
RUN_TEST(test_timer_compare);
|
||||||
|
|
Loading…
Reference in New Issue