attiny861 no quiere despertarse en caso de interrupción pero la simulación funciona

1

Logré hacer un UART de software sin usar el módulo USI y sus interrupciones.

Los ejemplos de código AVR en Atmel y avrfreaks simplemente no funcionan ni en la simulación ni en un dispositivo real, así que recibí ayuda e hice este UART suave.

Utilizando Proteus puedo enviar mensajes y recibirlos en mi ventana de terminal en una PC, puedo enviar un el carácter '1' a la simulación de Proteus y enciende un LED pin fine.

Cuando programo el ATTiny861 puedo recibir mensajes a 9600bps perfectamente, pero el procedimiento de interrupción nunca se dispara, debe dispararse una vez en el inicio y luego esperar mientras la CPU está inactiva para el cambio de bit en el 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);
}

Tengo otras bibliotecas y segmentos de código cargados y sé que la función put_flash_string funciona bien. Si saco sleep_mode, volcará los mensajes en el terminal, puedo retrasarlo y también funciona. Pero por alguna razón desconocida en mi hardware ATTiny861 simplemente no se interrumpirá.

Hace dos semanas que estoy viendo este código y realmente necesito ayuda. Atmel, como puedes imaginar, es vago y no es realmente útil. No estoy seguro de qué comprobar más y por qué funciona la simulación de Proteus y no mi hardware.

    
pregunta ppumkin

1 respuesta

1

Realmente no es posible darle una explicación definitiva de por qué su dispositivo "funciona" en simulación pero no en hardware según la información proporcionada. Sin embargo, voy a ofrecer algunas sugerencias.

  1. ¿Sabía que avr-gcc tiene soporte para el sueño ?
  2. Hay una tabla en la página 36 de la hoja de datos que describe las fuentes de activación asignadas por modo de suspensión. Hay una advertencia para: "(1) para INT0 e INT1, solo interrupción de nivel". Siga ese camino hasta la página 51 que describe la interrupción de nivel bajo:
  

Tenga en cuenta que si se utiliza una interrupción activada por nivel para la activación desde   Apagado, el nivel requerido debe mantenerse el tiempo suficiente para que la MCU   Completa el despertar para activar la interrupción de nivel. Si el nivel   desaparece antes de que finalice el Tiempo de puesta en marcha, la MCU seguirá   Despierta, pero no se generará ninguna interrupción. El tiempo de puesta en marcha es   definidos por los fusibles SUT y CKSEL como se describe en "Sistema de reloj" en   página 24.

El tiempo de bit a 9600 baudios es de unos 100 microsegundos. Dependiendo de la velocidad de tu reloj y la configuración de los fusibles de tu reloj, me pregunto si podrías estar perdiendo este presupuesto. ¿Has probado con ajustes de velocidad de transmisión más bajos (por ejemplo, 300 baudios)? ¿Puedes decirnos cómo estás sincronizando el chip? Si está usando un cristal externo (y probablemente debería estar en la operación UART), ¡la hora de inicio es, en el mejor de los casos, 16000 ciclos de reloj!

Aparte: esto obviamente no está relacionado con su problema, pero una macro útil proporcionada por avrlibc es _BV (x) que se puede usar en lugar de (1 < < x)

    
respondido por el vicatcu

Lea otras preguntas en las etiquetas