From f49e7379d136ee4d72d44ec1527deb1fbb5c7a69 Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Tue, 15 Dec 2009 21:32:03 +0000 Subject: [PATCH] Added support for external interrupts (ie INT0 etc) Small module to implement the INT0 .. INT3 interrupts. These hook up in ioport pin IRQs to trigger the vectors. Added vectors for the existing cores. Signed-off-by: Michel Pollet --- simavr/cores/sim_mega644.c | 8 ++++ simavr/cores/sim_megax8.c | 1 + simavr/cores/sim_megax8.h | 6 +++ simavr/cores/sim_tinyx5.c | 1 + simavr/cores/sim_tinyx5.h | 14 ++++++ simavr/sim/avr_extint.c | 90 ++++++++++++++++++++++++++++++++++++++ simavr/sim/avr_extint.h | 75 +++++++++++++++++++++++++++++++ 7 files changed, 195 insertions(+) create mode 100644 simavr/sim/avr_extint.c create mode 100644 simavr/sim/avr_extint.h diff --git a/simavr/cores/sim_mega644.c b/simavr/cores/sim_mega644.c index f9945c2..5ff5423 100644 --- a/simavr/cores/sim_mega644.c +++ b/simavr/cores/sim_mega644.c @@ -23,6 +23,7 @@ #include "sim_avr.h" #include "sim_core_declare.h" #include "avr_eeprom.h" +#include "avr_extint.h" #include "avr_ioport.h" #include "avr_uart.h" #include "avr_timer8.h" @@ -40,6 +41,7 @@ static void reset(struct avr_t * avr); static struct mcu_t { avr_t core; avr_eeprom_t eeprom; + avr_extint_t extint; avr_ioport_t porta, portb, portc, portd; avr_uart_t uart0,uart1; avr_timer8_t timer0,timer2; @@ -54,6 +56,11 @@ static struct mcu_t { .reset = reset, }, AVR_EEPROM_DECLARE(EE_READY_vect), + .extint = { + AVR_EXTINT_DECLARE(0, 'D', PD2), + AVR_EXTINT_DECLARE(1, 'D', PD3), + AVR_EXTINT_DECLARE(2, 'B', PB3), + }, .porta = { .name = 'A', .r_port = PORTA, .r_ddr = DDRA, .r_pin = PINA, .pcint = { @@ -268,6 +275,7 @@ static void init(struct avr_t * avr) printf("%s init\n", avr->mmcu); avr_eeprom_init(avr, &mcu->eeprom); + avr_extint_init(avr, &mcu->extint); avr_ioport_init(avr, &mcu->porta); avr_ioport_init(avr, &mcu->portb); avr_ioport_init(avr, &mcu->portc); diff --git a/simavr/cores/sim_megax8.c b/simavr/cores/sim_megax8.c index 21ed0fb..3a22318 100644 --- a/simavr/cores/sim_megax8.c +++ b/simavr/cores/sim_megax8.c @@ -30,6 +30,7 @@ void mx8_init(struct avr_t * avr) printf("%s init\n", avr->mmcu); avr_eeprom_init(avr, &mcu->eeprom); + avr_extint_init(avr, &mcu->extint); avr_ioport_init(avr, &mcu->portb); avr_ioport_init(avr, &mcu->portc); avr_ioport_init(avr, &mcu->portd); diff --git a/simavr/cores/sim_megax8.h b/simavr/cores/sim_megax8.h index 4ab93a5..2e220b9 100644 --- a/simavr/cores/sim_megax8.h +++ b/simavr/cores/sim_megax8.h @@ -25,6 +25,7 @@ #include "sim_core_declare.h" #include "avr_eeprom.h" +#include "avr_extint.h" #include "avr_ioport.h" #include "avr_uart.h" #include "avr_timer8.h" @@ -40,6 +41,7 @@ void mx8_reset(struct avr_t * avr); struct mcu_t { avr_t core; avr_eeprom_t eeprom; + avr_extint_t extint; avr_ioport_t portb,portc,portd; avr_uart_t uart; avr_timer8_t timer0,timer2; @@ -65,6 +67,10 @@ struct mcu_t SIM_CORENAME = { .reset = mx8_reset, }, AVR_EEPROM_DECLARE(EE_READY_vect), + .extint = { + AVR_EXTINT_DECLARE(0, 'D', PD2), + AVR_EXTINT_DECLARE(1, 'D', PD3), + }, .portb = { .name = 'B', .r_port = PORTB, .r_ddr = DDRB, .r_pin = PINB, .pcint = { diff --git a/simavr/cores/sim_tinyx5.c b/simavr/cores/sim_tinyx5.c index 7b5e039..ff72f78 100644 --- a/simavr/cores/sim_tinyx5.c +++ b/simavr/cores/sim_tinyx5.c @@ -32,6 +32,7 @@ void tx5_init(struct avr_t * avr) printf("%s init\n", avr->mmcu); avr_eeprom_init(avr, &mcu->eeprom); + avr_extint_init(avr, &mcu->extint); avr_ioport_init(avr, &mcu->portb); avr_timer8_init(avr, &mcu->timer0); avr_timer8_init(avr, &mcu->timer1); diff --git a/simavr/cores/sim_tinyx5.h b/simavr/cores/sim_tinyx5.h index aeb9d8a..3b7f760 100644 --- a/simavr/cores/sim_tinyx5.h +++ b/simavr/cores/sim_tinyx5.h @@ -26,6 +26,7 @@ #include "sim_core_declare.h" #include "avr_eeprom.h" +#include "avr_extint.h" #include "avr_ioport.h" #include "avr_timer8.h" @@ -38,6 +39,7 @@ void tx5_reset(struct avr_t * avr); struct mcu_t { avr_t core; avr_eeprom_t eeprom; + avr_extint_t extint; avr_ioport_t portb; avr_timer8_t timer0, timer1; }; @@ -60,6 +62,18 @@ struct mcu_t SIM_CORENAME = { .reset = tx5_reset, }, AVR_EEPROM_DECLARE(EE_RDY_vect), + .extint = { + .eint[0] = { + .port_ioctl = AVR_IOCTL_IOPORT_GETIRQ('B'), + .port_pin = PB2, + .isc = { AVR_IO_REGBIT(MCUCR, ISC00), AVR_IO_REGBIT(MCUCR, ISC01) }, + .vector = { + .enable = AVR_IO_REGBIT(GIMSK, INT0), + .raised = AVR_IO_REGBIT(GIFR, INTF0), + .vector = INT0_vect, + }, + } + }, .portb = { .name = 'B', .r_port = PORTB, .r_ddr = DDRB, .r_pin = PINB, .pcint = { diff --git a/simavr/sim/avr_extint.c b/simavr/sim/avr_extint.c new file mode 100644 index 0000000..4d1ce65 --- /dev/null +++ b/simavr/sim/avr_extint.c @@ -0,0 +1,90 @@ +/* + avr_extint.c + + Copyright 2008, 2009 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + + +#include +#include +#include +#include "avr_extint.h" + + +static void avr_extint_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) +{ + avr_extint_t * p = (avr_extint_t *)param; + avr_t * avr = p->io.avr; + + uint8_t mode = avr_regbit_get_array(avr, p->eint[irq->irq].isc, 2); + int up = !irq->value && value; + int down = irq->value && !value; + switch (mode) { + case 0: + // unsuported + break; + case 1: + if (up || down) + avr_raise_interrupt(avr, &p->eint[irq->irq].vector); + break; + case 2: + if (down) + avr_raise_interrupt(avr, &p->eint[irq->irq].vector); + break; + case 3: + if (up) + avr_raise_interrupt(avr, &p->eint[irq->irq].vector); + break; + } +} + +static void avr_extint_reset(avr_io_t * port) +{ + avr_extint_t * p = (avr_extint_t *)port; + + for (int i = 0; i < EXTINT_COUNT; i++) { + avr_irq_register_notify(p->io.irq + i, avr_extint_irq_notify, p); + + if (p->eint[i].port_ioctl) { + avr_irq_t * irq = avr_io_getirq(p->io.avr, + p->eint[i].port_ioctl, p->eint[i].port_pin); + + avr_connect_irq(irq, p->io.irq + i); + } + } +} + +static avr_io_t _io = { + .kind = "extint", + .reset = avr_extint_reset, +}; + +void avr_extint_init(avr_t * avr, avr_extint_t * p) +{ + p->io = _io; + + // allocate this module's IRQ + p->io.irq_count = EXTINT_COUNT; + p->io.irq = avr_alloc_irq(0, p->io.irq_count); + p->io.irq_ioctl_get = AVR_IOCTL_EXTINT_GETIRQ(); + + avr_register_io(avr, &p->io); + for (int i = 0; i < EXTINT_COUNT; i++) + avr_register_vector(avr, &p->eint[i].vector); +} + diff --git a/simavr/sim/avr_extint.h b/simavr/sim/avr_extint.h new file mode 100644 index 0000000..c05a7eb --- /dev/null +++ b/simavr/sim/avr_extint.h @@ -0,0 +1,75 @@ +/* + avr_extint.h + + External Interupt Handling (for INT0-3) + + Copyright 2008, 2009 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#ifndef AVR_EXTINT_H_ +#define AVR_EXTINT_H_ + +#include "sim_avr.h" + + +enum { + EXTINT_IRQ_INT0 = 0, + EXTINT_IRQ_INT1, EXTINT_IRQ_INT2, EXTINT_IRQ_INT3, + EXTINT_COUNT +}; + +// Get the internal IRQ corresponding to the INT +#define AVR_IOCTL_EXTINT_GETIRQ() AVR_IOCTL_DEF('e','x','t','i') + +/* + * This module is just a "relay" for the pin change IRQ in the IO port + * module. We hook up to their IRQ and raise out interrupt vectors as needed + * + * "isc" is handled, apart from the "level" mode that doesn't make sense here (?) + */ +typedef struct avr_extint_t { + avr_io_t io; + + struct { + avr_regbit_t isc[2]; // interrupt sense control bits + avr_int_vector_t vector; // interrupt vector + + uint32_t port_ioctl; // ioctl to use to get port + uint8_t port_pin; // pin number in said port + } eint[EXTINT_COUNT]; + +} avr_extint_t; + +void avr_extint_init(avr_t * avr, avr_extint_t * p); + +// Declares a typical INT into a avr_extint_t in a core. +// this is a shortcut since INT declarations are pretty standard. +// The Tinies are slightly different. see sim_tinyx5.h +#define AVR_EXTINT_DECLARE(_index, _portname, _portpin) \ + .eint[_index] = { \ + .port_ioctl = AVR_IOCTL_IOPORT_GETIRQ(_portname), \ + .port_pin = _portpin, \ + .isc = { AVR_IO_REGBIT(EICRA, ISC##_index##0), AVR_IO_REGBIT(EICRA, ISC##_index##1) },\ + .vector = { \ + .enable = AVR_IO_REGBIT(EIMSK, INT##_index), \ + .raised = AVR_IO_REGBIT(EIFR, INTF##_index), \ + .vector = INT##_index##_vect, \ + },\ + } + +#endif /* AVR_EXTINT_H_ */ -- 2.39.5