[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
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -60,7 +61,7 @@ struct timer {
|
|||
|
||||
int size;
|
||||
int clock_input;
|
||||
int go_down;
|
||||
bool go_down;
|
||||
|
||||
address_t base_addr;
|
||||
address_t iv_addr;
|
||||
|
@ -126,7 +127,7 @@ static void timer_reset(struct simio_device *dev)
|
|||
|
||||
tr->tactl = 0;
|
||||
tr->tar = 0;
|
||||
tr->go_down = 0;
|
||||
tr->go_down = false;
|
||||
memset(tr->ccrs, 0, sizeof(tr->ccrs));
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -400,9 +407,10 @@ static void tar_step(struct timer *tr)
|
|||
switch ((tr->tactl >> 4) & 3) {
|
||||
case 0: break;
|
||||
case 1:
|
||||
if (tr->tar == tr->ccrs[0]) {
|
||||
if (tr->tar == tr->ccrs[0] || tr->go_down) {
|
||||
tr->tar = 0;
|
||||
tr->tactl |= TAIFG;
|
||||
tr->go_down = false;
|
||||
} else {
|
||||
tr->tar++;
|
||||
}
|
||||
|
@ -416,9 +424,9 @@ static void tar_step(struct timer *tr)
|
|||
|
||||
case 3:
|
||||
if (tr->tar >= tr->ccrs[0])
|
||||
tr->go_down = 1;
|
||||
tr->go_down = true;
|
||||
if (!tr->tar)
|
||||
tr->go_down = 0;
|
||||
tr->go_down = false;
|
||||
|
||||
if (tr->go_down) {
|
||||
tr->tar--;
|
||||
|
|
|
@ -348,6 +348,94 @@ static void test_timer_up()
|
|||
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()
|
||||
{
|
||||
dev = create_timer("");
|
||||
|
@ -594,6 +682,8 @@ int main(int argc, char **argv)
|
|||
RUN_TEST(test_timer_up_stop);
|
||||
RUN_TEST(test_timer_updown_stop);
|
||||
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_capture);
|
||||
RUN_TEST(test_timer_compare);
|
||||
|
|
Loading…
Reference in New Issue