Waking and Playing Sound on ATtiny85 on Button Press

Hello forums!

For my current project, I am trying to build a sort of 'easy button' that plays a short sound, then goes to sleep when a button is pressed. I have the sound playing properly, and the attiny85 does go to sleep at the end, but I'm having some trouble getting the chip to wake properly. Here is my code:

#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#define adc_disable()  (ADCSRA &= ~(1<<ADEN))
#define adc_enable()   (ADCSRA |= (1<<ADEN))

// Audio encoded as unsigned 8-bit, 8kHz sampling rate
const unsigned char sound[] PROGMEM = {
  0x7f, 0x80, 0x83, ... 0x30, 0x34, 0x00
};
unsigned int soundLen = 3347;
volatile unsigned int nextByte = 0;

void sleep() {
  
  //Shuts everything down
  sleep_enable();
  sleep_cpu();

  //Starts everything back up
  sleep_disable();
}

void setup() {
  //Set up registers for pin change interrupt on Pin 3
  GIMSK |= (1 << PCIE);         //Enable pin change interrupts
  PCMSK |= (1 << PCINT3);       //Enable interrupt on Pin 3
  
  // Enable 64 MHz PLL and use as source for Timer1
  PLLCSR = 1<<PCKE | 1<<PLLE;     
 
  // Set up Timer/Counter1 for PWM output
  TIMSK = 0;                              // Timer interrupts OFF
  TCCR1 = 1<<PWM1A | 2<<COM1A0 | 1<<CS10; // Enables PWM on OC1A, mode 2, and 1:1 prescaling.
  OCR1A = 128;                            // 50% duty cycle initially

  // Set up Timer/Counter0 for 8kHz interrupt to output samples.
  TCCR0A = 3<<WGM00;                      // Fast PWM
  TCCR0B = 1<<WGM02 | 2<<CS00;            // 1/8 prescale
  TIMSK = 1<<OCIE0A;                      // Enable compare match
  OCR0A = 124;                            // Divide by 1000

  pinMode(3, INPUT);            //Configure pin as an input
  digitalWrite(3, HIGH);        //Enable internal pullup resistor

  pinMode(1, OUTPUT);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}

void loop() { 
  
}

ISR(PCINT0_vect) {
  if(PINB & (1<<PB3)){
    
  } else {
    nextByte = 0;
  }
}

// Sample interrupt
ISR(TIMER0_COMPA_vect) {
  sei();
  nextByte++;
  if(nextByte >= soundLen){
    sleep();
  }
  char sample = pgm_read_byte(&sound[nextByte]);
  OCR1A = sample;
}

(Most of the code is based on an excellent tutorial here)

My schematic is very simple: A speaker connected from pin 1 to ground through a 220uF capacitor, and a button connecting ground to pin 3.

In my ISR on pin 3, I am attempting to check whether the button has been pressed or released. I only set nextByte back to 0 when I detect that the button has been pressed. If the button has been released, the code should go back to sleep on the next call of the clock ISR.

The problem is that the sound is playing both when the button is pressed and released. I don't think it's a button-bounce or electrical error, and I've verified that the attiny85 isn't resetting, so I spelled the ISR name correctly. What am I doing wrong?

I'm pretty sure that this line is going to be the culprit:

if(PINB & (1<<PB3)){

BJHenry:
I'm pretty sure that this line is going to be the culprit:

That line is supposed to just be a lower-level read of the pin, to determine whether the button was pressed or released. I've also tried

if(digitalRead(3) == HIGH)

and

if(digitalRead(3) == LOW)

(with respective changes to the if block), but to no avail.

Do you need this in setup()
sei();

GravelPunch:
That line is supposed to just be a lower-level read of the pin, to determine whether the button was pressed or released. I've also tried

if(digitalRead(3) == HIGH)

and

if(digitalRead(3) == LOW)

(with respective changes to the if block), but to no avail.

You're right, I hadn't seen it expressed like that before. But I tried it, and it does work.

I haven't had a chance to dig out my ATTiny85 to test this out, but I tried the same thing with a Uno- set up B3 as a pin change interrupt, used your ISR- and I got the same results as you. Same thing with using digitalRead.
Something I'd try next is to use a second microcontroller connected to the input pin of the ATTiny. Have the second micro toggle the pin one every second or so- this would be a sure indicator that switch bounce is/isn't a problem.

BJHenry:
You're right, I hadn't seen it expressed like that before. But I tried it, and it does work.

Have the second micro toggle the pin one every second or so- this would be a sure indicator that switch bounce is/isn't a problem.

I tried just touching a wire to the pin in question connected to ground. The same thing happens. If this is a button bounce problem, I don't think there's much I could to to fix it.

I did a little bit of debugging (attaching LEDs and turning them on and off in the ISR) and it's almost like the interrupt fires, then a little bit of time later, the pin starts being able to be read. This is weird. I wasn't able to find anything about it in the datasheet. Does anyone else know anything about this?

Quick update: I just tried something similar using INT0. The low-level detection worked great, but when I moved to falling edge, the same bug appeared; a falling-edge interrupt seemed to be firing on both edges. This is really weird now. I'm starting to think this is a hardware issue, either on my end and my button implementation or on Atmel's (but I think this is unlikely.)

nextByte++;

Won't this eventually overflow and wrap around to zero causing the sound to play again? What wakes the AVR? The interrupt?