From: Michel Pollet Date: Thu, 29 Apr 2010 10:51:45 +0000 (+0100) Subject: ICP: Added Input capture pin support to timers X-Git-Tag: v1.0a4~8 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=d22d7636f84b511ef601bdd87d76dff6d5bdca2a;p=sx%2Fsimavr.git ICP: Added Input capture pin support to timers 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 --- diff --git a/simavr/cores/sim_mega128.c b/simavr/cores/sim_mega128.c index bc5a22c..d1c5b35 100644 --- a/simavr/cores/sim_mega128.c +++ b/simavr/cores/sim_mega128.c @@ -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), diff --git a/simavr/cores/sim_megax4.h b/simavr/cores/sim_megax4.h index 2f59a27..ae02e32 100644 --- a/simavr/cores/sim_megax4.h +++ b/simavr/cores/sim_megax4.h @@ -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), diff --git a/simavr/cores/sim_megax8.h b/simavr/cores/sim_megax8.h index 4ffe209..6f6d006 100644 --- a/simavr/cores/sim_megax8.h +++ b/simavr/cores/sim_megax8.h @@ -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), diff --git a/simavr/cores/sim_tiny2313.c b/simavr/cores/sim_tiny2313.c index c78ebaa..e0af609 100644 --- a/simavr/cores/sim_tiny2313.c +++ b/simavr/cores/sim_tiny2313.c @@ -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), diff --git a/simavr/sim/avr_timer.c b/simavr/sim/avr_timer.c index cb2c99f..d20f313 100644 --- a/simavr/sim/avr_timer.c +++ b/simavr/sim/avr_timer.c @@ -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; diff --git a/simavr/sim/avr_timer.h b/simavr/sim/avr_timer.h index a69fcb3..755531e 100644 --- a/simavr/sim/avr_timer.h +++ b/simavr/sim/avr_timer.h @@ -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