simavr icon indicating copy to clipboard operation
simavr copied to clipboard

Pin change interrupts (PCINT) incorrectly fire when a timer compare event occurs

Open JarrettBillingsley opened this issue 5 years ago • 1 comments

Once again, this code:

	ldi	temp, _BV(DDB4) | _BV(DDB3)
	out	IO(DDRB), temp

	ldi	temp, 0
	out	IO(OCR1B), temp
	out	IO(OCR1A), temp
	ldi	temp, 255
	out	IO(OCR1C), temp

	; Enable PWM mode on timer 1
	ldi	temp, _BV(PWM1B) | _BV(COM1B1)
	out	IO(GTCCR), temp

	; Enable timer overflow interrupt
	in	temp, IO(TIMSK)
	ori	temp, _BV(TOIE1)
	out	IO(TIMSK), temp

	; Hardware bug requires COM1A0 to be enabled as well.
	; "3" means clock timer with CK/4 (16384 Hz sample rate)
	ldi	temp, _BV(PWM1A) | _BV(COM1A1) | _BV(COM1A0) | 3
	out	IO(TCCR1), temp

	; turn on pin change interrupt for PB1
	ldi	temp, _BV(PCINT1)
	out	IO(PCMSK), temp
	ldi	temp, _BV(PCIE)
	out	IO(GIMSK), temp

The output compare A is required to be enabled in this code because of a hardware bug in real ATTiny85. It uses PB1, but PB1 is set as an input with a pin change interrupt.

On real hardware, the pin change interrupt only (correctly) triggers on an external edge. However in simavr, the behavior of OCR1A toggles PB1's output value, which should be ignored, but instead triggers the interrupt as well.

JarrettBillingsley avatar May 05 '19 20:05 JarrettBillingsley

Quick patch:

diff --git a/simavr/sim/avr_ioport.c b/simavr/sim/avr_ioport.c
index e35b2de..287313d 100644
--- a/simavr/sim/avr_ioport.c
+++ b/simavr/sim/avr_ioport.c
@@ -154,7 +154,8 @@ avr_ioport_irq_notify(
        if (p->r_pcint) {
                // if the pcint bit is on, try to raise it
                int raise = avr->data[p->r_pcint] & mask;
-               if (raise)
+               int ddr = avr->data[p->r_ddr] & mask;
+               if (raise && ddr)
                        avr_raise_interrupt(avr, &p->pcint);
        }
 }

JarrettBillingsley avatar May 05 '19 20:05 JarrettBillingsley