El código de ejemplo
- inicializa un temporizador asíncrono que se dispara cada segundo
- establece dos puertos como salidas (PA4, PA6 - LED conectados)
- el temporizador ISR conmuta el pin PA4
- establece permanentemente el pin PA6 en 1 en el ciclo while ()
Si el pin PA6 se conmuta usando
PORTA |= (1 << PA6);
todo funciona como se espera. El LED en el pin PA4 se alterna exactamente cada segundo. Sin embargo, si el puerto está configurado de esta manera
PORTA |= (1 << PinNumber);
el pin PA4 solo se alterna muy esporádicamente (se observa hasta 22 segundos entre alternaciones). Esto me indica que, por algún motivo, el controlador está "ocupado" o que el indicador ISR de desbordamiento no está configurado en absoluto.
EDITAR: Si agrego otro código de uso intensivo de ciclo como _delay_us (10); la situación mejora de tal manera que los archivos y menos interrupciones se perderán cuanto mayor sea el retraso. Esto tiene sentido si asumimos que la operación de cambio de pin está en algún punto bloqueando de alguna manera la entrada ISR.
Dado que la ejecución de ISR siempre debe tener prioridad sobre el código en el bucle principal, no entiendo por qué puede suceder esto y cómo exactamente hace una diferencia si el número pin se pasa como una constante o como una variable. / p>
Comprendo que el compilador probablemente pueda realizar una buena optimización si se usa una constante, pero el uso de una variable no debería dar como resultado algún código de bloqueo de ISR.
Esto está en GCC 4.8.1.
#include "stdlib.h"
#include "avr/interrupt.h"
uint8_t PinNumber;
// asynch ISR with external clock source, fires every second
ISR (TIMER2_OVF_vect) {
PORTA ^= (1 << PA4);
}
int main(void) {
DDRA |= (1 << PA6) | (1 << PA4); // set PA6 and PA4 as output
PinNumber = PA6; // variable that just holds PA6 for demonstration
cli(); // global interrupt disable during init
ASSR |= (1<<AS2); // Asynchronous Timer/Counter2 from external clock
TCNT2 = 0x00;
OCR2A = 0x00;
OCR2B = 0x00;
TCCR2A = 0x00;
TCCR2B = 0x05; // set divider for one second
TIMSK2 |= (1 << TOIE2); // enable TIMER2_OVF_vect
sei(); // global interrupt enable
while(1) {
//PORTA |= (1 << PinNumber); // this somehow causes the interrupt to "starve"
PORTA |= (1 << PA6); // this works as expected
}
}
EDITAR: El fondo práctico es que observamos que el ISR no se ejecuta correctamente cuando se cambian repetidamente varios puertos de salida, donde el número de pin es variable en el tiempo de ejecución.