El problema era prácticamente imposible de depurar, la interrupción que cambiaba una variable al azar no lo hacen, sin patrón aparente; dentro de la variable de código de interrupción cambiaría pero fuera de ella el cambio se revierte esencialmente al estado anterior. Es una variable normal, por lo que no tiene doble búfer. Marcarla como volátil no tuvo ningún efecto (además de hacer que el código se ejecute más lentamente). Ya he solucionado el problema, pero el fenómeno sigue ahí. Además, mi chip es Atmega644 y el lenguaje es C.
He reducido el problema al siguiente código: la interrupción se disparaba durante la ejecución de un código que también escribía en esa variable. Comprobaba el estado del pin, y dependiendo de ello ponía o quitaba un bit de esa variable. Resolví el problema poniendo ese código en la interrupción también, lo que dejó el código interrumpible sin un solo lugar donde se escribiera esa variable - sólo se leía.
El código es sustancialmente largo, por lo que sólo proporciono fragmentos relevantes (el resto del código ni siquiera se ocupa de 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-arreglo. Funciona así, pero debería haber funcionado así. Cambiar una variable es una operación atómica, por lo que no se puede interrumpir a mitad de la acción. Mi suposición era que se debía a la magia de optimización, pero entonces volátil habría cambiado el comportamiento. E incluso entonces, incluso sin el marcador volátil, el código podría haber ignorado el cambio la primera vez que se ejecutó (no es crítico que esté actualizado en tiempo real), pero la siguiente iteración habría reconocido el cambio. Esto me deja perplejo sobre la naturaleza del fenómeno.
¿Alguien sabe algo al respecto? ¿O es sólo un error del compilador?
1 votos
Código, por favor...
2 votos
El cambio de una variable no es ciertamente atómico.
2 votos
Sin código, todo ese montón de palabras de ahí arriba es inútil. Puede ser cualquier cosa.
0 votos
Sinceramente, no puedo imaginar por qué alguien necesitaría un código real para ver el problema, pero ahí está.
0 votos
Aunque "volátil" suele ser necesario cuando se accede a la misma variable desde el código de interrupción y el principal si se realiza alguna optimización, definitivamente NO es una solución mágica que hace que todas las operaciones con variables sean atómicas.
2 votos
@RaidhoCoaxil Porque el problema puede ser totalmente diferente a lo que estás pensando.
0 votos
¿Y el micro que estás usando? ¿Compilador y versión?
0 votos
Entonces, ¿qué variable no se actualiza? ¿Es la
display
? ¿Cómo se declara?0 votos
@brhans He mencionado el modelo de controlador en el OP, es Atmega644; el compilador es ARMGCC 3.3.1.
0 votos
Antes de hacer varias afirmaciones audaces sobre los errores del compilador, ¿ha desensamblar el código ? Mirando el código publicado, yo descartaría esto como un problema estándar de lectura-modificación-escritura. Si fuera un error de optimización causado por la falta de volatilidad, el error habría sido consistente y no aparentemente aleatorio.