Commit d22d7636f84b511ef601bdd87d76dff6d5bdca2a
authorMichel Pollet <buserror@gmail.com>
Thu, 29 Apr 2010 10:51:45 +0000 (11:51 +0100)
committerMichel Pollet <buserror@gmail.com>
Thu, 29 Apr 2010 10:51:45 +0000 (11:51 +0100)
Added (untested as of now) Input Pin Capture to the 16 bits
timers. The "edge" flag is also handled. The code is untested
for now, it will need an "example" board that will be
checked in later.

Signed-off-by: Michel Pollet <buserror@gmail.com>
6 files changed:
simavr/cores/sim_mega128.c
simavr/cores/sim_megax4.h
simavr/cores/sim_megax8.h
simavr/cores/sim_tiny2313.c
simavr/sim/avr_timer.c
simavr/sim/avr_timer.h

index bc5a22c50af55e6434b8943093156fe8acf0d441..d1c5b35743e503dcd7b827073f832f2f78d84f75 100644 (file)
@@ -271,6 +271,9 @@ struct mcu_t {
                .r_icrh = ICR1H,
                .r_tcnth = TCNT1H,
 
+               .ices = AVR_IO_REGBIT(TCCR1B, ICES1),
+               .icp = AVR_IO_REGBIT(PORTD, 4),
+
                .overflow = {
                        .enable = AVR_IO_REGBIT(TIMSK, TOIE1),
                        .raised = AVR_IO_REGBIT(TIFR, TOV1),
@@ -379,6 +382,9 @@ struct mcu_t {
                .r_icrh = ICR3H,
                .r_tcnth = TCNT3H,
 
+               .ices = AVR_IO_REGBIT(TCCR3B, ICES3),
+               .icp = AVR_IO_REGBIT(PORTE, 7),
+
                .overflow = {
                        .enable = AVR_IO_REGBIT(ETIMSK, TOIE3),
                        .raised = AVR_IO_REGBIT(ETIFR, TOV3),
index 2f59a2743c8b6feba850e25c9d42d41ee1d3c899..ae02e32e07c1b0179d04a9fda0c4846d1009dea8 100644 (file)
@@ -284,9 +284,12 @@ struct mcu_t SIM_CORENAME = {
                .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */  /* External clock T1 is not handled */},
 
                .r_tcnt = TCNT1L,
+               .r_tcnth = TCNT1H,
                .r_icr = ICR1L,
                .r_icrh = ICR1H,
-               .r_tcnth = TCNT1H,
+
+               .ices = AVR_IO_REGBIT(TCCR1B, ICES1),
+               .icp = AVR_IO_REGBIT(PORTD, 6),
 
                .overflow = {
                        .enable = AVR_IO_REGBIT(TIMSK1, TOIE1),
index 4ffe209c06044fae6b4a4823866801cfea2de0eb..6f6d006e4c17f8342804c5220e2418a9cdc2d435 100644 (file)
@@ -232,9 +232,12 @@ struct mcu_t SIM_CORENAME = {
                .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */  /* External clock T1 is not handled */},
 
                .r_tcnt = TCNT1L,
+               .r_tcnth = TCNT1H,
                .r_icr = ICR1L,
                .r_icrh = ICR1H,
-               .r_tcnth = TCNT1H,
+
+               .ices = AVR_IO_REGBIT(TCCR1B, ICES1),
+               .icp = AVR_IO_REGBIT(PORTB, 0),
 
                .overflow = {
                        .enable = AVR_IO_REGBIT(TIMSK1, TOIE1),
index c78ebaac26d31fc42eebb45927a7c9631e59236a..e0af609c28d5de3a6d596e11a0eeab4c6a8fb942 100644 (file)
@@ -167,6 +167,9 @@ static struct mcu_t {
                .r_icrh = ICR1H,
                .r_tcnth = TCNT1H,
 
+               .ices = AVR_IO_REGBIT(TCCR1B, ICES1),
+               .icp = AVR_IO_REGBIT(PORTD, 6),
+
                .overflow = {
                        .enable = AVR_IO_REGBIT(TIMSK, TOIE1),
                        .raised = AVR_IO_REGBIT(TIFR, TOV1),
index cb2c99f0d4c1625d24ba405f4615f40846842022..d20f313ec3e0a1fa97ce3ab7b4dbb1d27eee248e 100644 (file)
@@ -120,22 +120,27 @@ static avr_cycle_count_t avr_timer_tov(struct avr_t * avr, avr_cycle_count_t whe
        return when + p->tov_cycles;
 }
 
+static uint16_t _avr_timer_get_current_tcnt(avr_timer_t * p)
+{
+       avr_t * avr = p->io.avr;
+       if (p->tov_cycles) {
+               uint64_t when = avr->cycle - p->tov_base;
+
+               return (when * p->tov_top) / p->tov_cycles;
+       }
+       return 0;
+}
 
 static uint8_t avr_timer_tcnt_read(struct avr_t * avr, avr_io_addr_t addr, void * param)
 {
        avr_timer_t * p = (avr_timer_t *)param;
        // made to trigger potential watchpoints
 
-       if (p->tov_cycles) {
-               uint64_t when = avr->cycle - p->tov_base;
-
-               uint16_t tcnt = (when * p->tov_top) / p->tov_cycles;
-       //      printf("%s-%c when = %d tcnt = %d/%d\n", __FUNCTION__, p->name, (uint32_t)when, tcnt, p->tov_top);
+       uint16_t tcnt = _avr_timer_get_current_tcnt(p);
 
-               avr->data[p->r_tcnt] = tcnt;
-               if (p->r_tcnth)
-                       avr->data[p->r_tcnth] = tcnt >> 8;
-       }
+       avr->data[p->r_tcnt] = tcnt;
+       if (p->r_tcnth)
+               avr->data[p->r_tcnth] = tcnt >> 8;
        
        return avr_core_watch_read(avr, addr);
 }
@@ -291,6 +296,32 @@ static void avr_timer_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, v
        avr_timer_reconfigure(p);
 }
 
+static void avr_timer_irq_icp(struct avr_irq_t * irq, uint32_t value, void * param)
+{
+       avr_timer_t * p = (avr_timer_t *)param;
+       avr_t * avr = p->io.avr;
+
+       // input capture disabled when ICR is used as top
+       if (p->mode.top == avr_timer_wgm_reg_icr)
+               return;
+       int bing = 0;
+       if (avr_regbit_get(avr, p->ices)) { // rising edge
+               if (!irq->value && value)
+                       bing++;
+       } else {        // default, falling edge
+               if (irq->value && !value)
+                       bing++;
+       }
+       if (!bing)
+               return;
+       // get current TCNT, copy it to ICR, and raise interrupt
+       uint16_t tcnt = _avr_timer_get_current_tcnt(p);
+       avr->data[p->r_icr] = tcnt;
+       if (p->r_icrh)
+               avr->data[p->r_icrh] = tcnt >> 8;
+       avr_raise_interrupt(avr, &p->icr);
+}
+
 static void avr_timer_reset(avr_io_t * port)
 {
        avr_timer_t * p = (avr_timer_t *)port;
@@ -315,6 +346,15 @@ static void avr_timer_reset(avr_io_t * port)
                        avr_connect_irq(&port->irq[TIMER_IRQ_OUT_COMP + compi], req.irq[0]);
                }
        }
+       avr_ioport_getirq_t req = {
+               .bit = p->icp
+       };
+       if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) {
+               // cool, got an IRQ for the input capture pin
+//             printf("%s-%c ICP Connecting PIN IRQ %d\n", __FUNCTION__, p->name, req.irq[0]->irq);
+               avr_irq_register_notify(req.irq[0], avr_timer_irq_icp, p);
+       }
+
 }
 
 static avr_io_t        _io = {
@@ -330,6 +370,10 @@ void avr_timer_init(avr_t * avr, avr_timer_t * p)
        p->io.irq_count = TIMER_IRQ_COUNT;
        p->io.irq = avr_alloc_irq(0, p->io.irq_count);
        p->io.irq_ioctl_get = AVR_IOCTL_TIMER_GETIRQ(p->name);
+
+       // marking IRQs as "filtered" means they don't propagate if the
+       // new value raised is the same as the last one.. in the case of the
+       // pwm value it makes sense not to bother.
        p->io.irq[TIMER_IRQ_OUT_PWM0].flags |= IRQ_FLAG_FILTERED;
        p->io.irq[TIMER_IRQ_OUT_PWM1].flags |= IRQ_FLAG_FILTERED;
 
index a69fcb3d316ed2a95209f15c36ab8213f36c965e..755531e3dcc7e2fd1f76234be87bc5543d633f93 100644 (file)
@@ -95,6 +95,8 @@ typedef struct avr_timer_t {
        avr_regbit_t    cs[4];
        uint8_t                 cs_div[16];
        avr_regbit_t    as2;            // asynchronous clock 32khz
+       avr_regbit_t    icp;            // input capture pin, to link IRQs
+       avr_regbit_t    ices;           // input capture edge select
 
        struct {
                avr_int_vector_t        interrupt;              // interrupt vector