El problema era virtualmente no descargable, la interrupción que estaba cambiando una variable al azar no lo haría, sin un patrón aparente; la variable dentro del código de interrupción cambiaría pero, fuera de ella, el cambio se revertirá esencialmente al estado anterior. Es una variable regular, por lo que no tiene doble buffer. Marcarlo como volátil no tuvo ningún efecto (además de hacer que el código se ejecute más lento). Ya he resuelto el problema, pero los fenómenos siguen existiendo. Además, mi chip es Atmega644 y el lenguaje es C.
He reducido el problema a un código siguiente: la interrupción se activó durante la ejecución del código que también estaba escribiendo en esa variable. Verificó el estado del pasador y, dependiendo de ello, establecería o eliminaría un poco de esa variable. Resolví el problema poniendo ese código en la interrupción también, lo que dejaba un código que no se puede interrumpir en un solo lugar donde se escribía esa variable, solo se leía.
El código es sustancialmente largo, por lo que solo proporciono fragmentos relevantes (el resto del código ni siquiera trata las variables relacionadas):
#define BIT(x) (1<<(x))
#define BITSET(x,y) ((x)|=(y))
#define BITCLR(x,y) ((x)&=~(y))
//Interrupt snippet:
if ( PINB & BIT(PINB0) )
BITSET( display, BIT(DSPL_PWR) );
if ( PINB & BIT(PINB1) )
BITSET( display, BIT(DSPL_ACT) );
//Main code:
if ( PIND & BIT(PIND2) )
BITSET( display, BIT(DSPL_ACC) );
else
BITCLR( display, BIT(DSPL_ACC) );
<...>
leds_display = 0x00;
switch ( roll )
{
case 0:
leds_display |= display & BIT(DSPL_PWR);
break;
//etc.
}
PORTA = leds_display;
Sin embargo, eso no es más que una muleta. Funciona de esa manera, pero debería haber funcionado como era. Cambiar una variable es una operación atómica, por lo que no se puede interrumpir en mitad de la acción. Mi conjetura fue que se debió a la magia de optimización, pero entonces volatile habría cambiado el comportamiento. E incluso entonces, incluso sin un marcador volátil, el código puede haber ignorado el cambio la primera vez que se ejecutó (no es crítico para que esté actualizado en tiempo real), pero la siguiente iteración habría reconocido el cambio. Esto me deja perplejo sobre la naturaleza de los fenómenos.
¿Alguien sabe algo al respecto? ¿O es solo un error del compilador?