Attiny861 does not want to wake on interrupt but simulation works

attinyavr

I successful managed to make a software UART without using the USI module and its interrupts.

The AVR code examples on Atmel and avrfreaks just do not work in either simulation or a real device so I got some help and made this soft UART.

Using Proteus I can send messages and receive them on my terminal window on a PC, I can send a character '1' to the Proteus simulation and it turns on an LED pin fine.

When I program the ATTiny861 I can receive messages at 9600bps perfectly but the interrupt procedure never ever fires, it should fire once on startup and then wait while CPU is idle for bit change on PIN.

int main(int argc, char **argv)
{
    USICR   =  0;             // Disable USI.
    MCUCR  |= (0<<ISC00);   
    MCUCR  |= (0<<ISC01);   
    GIFR    =  (1<<PCIF);     // Clear pin change interrupt flag.
    DDRA    = 0xFE;
    PORTA  |= (1<<PA0);       //int. Pull-up an  PA1
    PINA    = 0x00;
    PCMSK0 |= (1<<PCINT0);
    GIMSK  |= (1<<PCIE0);

    CLKPR = (1 << CLKPCE);
    CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);

    MCUCR = (1<<SE) | (0<<SM1) | (0<<SM0);   // Enable Sleepmode: Idle

    while(1){
      //send some startup messages ..

      sei();
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);
      sleep_mode();  
    }
}

ISR(PCINT_vect) // interrupt for change in porta0 
{
    // pin change interrupt handler
    GIMSK &=  ~(1<<PCIE0);  
    if (!( PINA & (1<<PA0) ))  
    {
        static char chr;
        get_char(&serial_pins, serial_pin_in, &chr);
        RxData = chr;
    }    

    PCMSK0 |= (1<<PCINT0);  //  tell pin change mask to listen to pin0
    GIMSK  |= (1<<PCIE0);   // enable PCINT interrupt in the general interrupt mask of the porta
    GIFR    = (1<<PCIF);    // Clear pin change interrupt flag.

    static char message[] PROGMEM = " INTERRUPTED MESSAGE ";
    put_flash_string(&serial_port, serial_pin_out, (PGM_P) message);
}

I have other libraries and code segments loaded and I know the put_flash_string function works fine. If i take out sleep_mode it will dump messages into the terminal, I can delay it and it also works. But for some unknown reason on my hardware ATTiny861 it just will not interrupt.

I have been looking at this code for two weeks now and I really need some help. Atmel as you might guess is just vague and not really helpful. I'm not sure what to check any more and why the Proteus simulation works and not my hardware.

Best Answer

It's not really possible to give you a definitive explanation of why your device "works" in simulation but not in hardware based on the information provided. I will offer some suggestions though.

  1. Did you know avr-gcc has built in support for sleep?
  2. There is a table on page 36 of the datasheet describing Wake-up Sources mapped per Sleep Mode. There is a caveat there for: "(1) for INT0 and INT1, only level interrupt." Follow that trail to page 51 which describes the Low Level interrupt:

Note that if a level triggered interrupt is used for wake-up from Power-down, the required level must be held long enough for the MCU to complete the wake-up to trigger the level interrupt. If the level disappears before the end of the Start-up Time, the MCU will still wake up, but no interrupt will be generated. The start-up time is defined by the SUT and CKSEL Fuses as described in “Clock System” on page 24.

The bit time at 9600 baud is about 100 microseconds. Depending on your clock speed and your clock fuse settings I wonder if you could be blowing this budget? Have you tried with lower baud rate settings (e.g. 300 baud)? Can you tell us how you are clocking the chip? If you're using an external crystal (and you probably should be for UART operation) then the start up time is at best 16000 clock cycles!

Aside: This is obviously not related to your problem, but a useful macro provided by avrlibc is _BV(x) which can be used instead of (1 << x)