Page 1 of 1

Enabling interrupt causes device enumeration problem

Posted: Mon Nov 17, 2014 1:59 am
by alasdairc
I have a circuit based around an ATTINY84 and the V-USB stack which works perfectly on one computer but not another.

I have tracked the problem down to this function call and the ISR which it starts:

Code: Select all

void enableIRIn() {

  // setup pulse clock timer interrupt
  //Prescale /8 (16M/8 = 0.5 microseconds per tick)
  // Therefore, the timer interval can range from 0.5 to 128 microseconds
  // depending on the reset value (255 to 0)
  TCCR1A = 0;
  TCCR1B = _BV(WGM12) | _BV(CS10);
  OCR1A = F_CPU * USECPERTICK / 1000000;
  TCNT1 = 0;

  //Timer1 Overflow Interrupt Enable
  TIMSK1 = _BV(OCIE1A);

  // initialize state machine variables
  irparams.rcvstate = STATE_IDLE;
  irparams.rawlen = 0;

  // set pin modes
  IRREAD_DDR &= ~(1 << IRREAD_POS);
}


Code: Select all

ISR(TIM1_COMPA_vect)
{

  irparams.timer++; // One more 50us tick
  if (irparams.rawlen >= RAWBUF) {
    // Buffer overflow
    irparams.rcvstate = STATE_STOP;
  }
  switch(irparams.rcvstate) {
  case STATE_IDLE: // In the middle of a gap
    if (bit_is_clear(IRREAD_PIN, IRREAD_POS)) {
      if (irparams.timer < GAP_TICKS) {
        // Not big enough to be a gap.
        irparams.timer = 0;
      }
      else {
        // gap just ended, record duration and start recording transmission
        irparams.rawlen = 0;
        irparams.rawbuf[irparams.rawlen++] = irparams.timer;
        irparams.timer = 0;
        irparams.rcvstate = STATE_MARK;
      }
    }
    break;
  case STATE_MARK: // timing MARK
    if (bit_is_set(IRREAD_PIN, IRREAD_POS)) {   // MARK ended, record time
      irparams.rawbuf[irparams.rawlen++] = irparams.timer;
      irparams.timer = 0;
      irparams.rcvstate = STATE_SPACE;
    }
    break;
  case STATE_SPACE: // timing SPACE
    if (bit_is_clear(IRREAD_PIN, IRREAD_POS)) { // SPACE just ended, record it
      irparams.rawbuf[irparams.rawlen++] = irparams.timer;
      irparams.timer = 0;
      irparams.rcvstate = STATE_MARK;
    }
    else { // SPACE
      if (irparams.timer > GAP_TICKS) {
        // big SPACE, indicates gap between codes
        // Mark current code as ready for processing
        // Switch to STOP
        // Don't reset timer; keep counting space width
        irparams.rcvstate = STATE_STOP;
      }
    }
    break;
  case STATE_STOP: // waiting, measuring gap
    if (bit_is_clear(IRREAD_PIN, IRREAD_POS)) { // reset gap timer
      irparams.timer = 0;
    }
    break;
  }
}


I was presuming that perhaps the host computer was waiting too long, but then thinking about it, the InraRed ISR is triggering every 50us, while the usb polling only runs every 4ms, so in theory the IR receiver shouldn't be causing any issues. I also call usbPoll twice in the main loop.

If I clear the contents of ISR(TIM1_COMPA_vect), leaving just an empty function block then the device is recognized correctly.

Re: Enabling interrupt causes device enumeration problem

Posted: Mon Nov 17, 2014 2:01 am
by alasdairc
ATTINY84 is running at 12MHz with an external crystal.

I have 10uF electrolytic and 100nF ceramic cap between 5V and GND.

This device works perfectly with another host computer.

Re: Enabling interrupt causes device enumeration problem

Posted: Mon Nov 17, 2014 10:23 am
by blargg
V-USB is unreliable if you disable interrupts for more than 25 cycles (and Murphy's Law means that it'll seem to work on one computer rather than fail consistently on all). In your case you can make your ISR non-blocking by having it begin with an SEI to re-enable interrupts: ISR(TIM1_COMPA_vect,ISR_NOBLOCK). This ensures that interrupts are only disabled for a few cycles when your interrupt occurs. You must be sure you don't get another of your interrupts while your ISR is executing or it'll become be re-entered and likely screw up your state. Note that your interrupt can be delayed by 100us or more by the V-USB interrupt. You might be just as well off by polling the interrupt flag for your interrupt rather than using an ISR.

Re: Enabling interrupt causes device enumeration problem

Posted: Mon Nov 17, 2014 8:48 pm
by alasdairc
Hey there,

Thanks for the advice, this has completely solved the problem!

I've been struggling with this little circuit for a long time now, and can finally relax and just make use of it.

:D