3 votos

Uso de campos de bits en aplicaciones basadas en interrupciones

Cuando implemento aplicaciones basadas en interrupciones, suelo crear un campo de bits para realizar un seguimiento de las diferentes interrupciones. Por ejemplo:

volatile struct {
    unsigned char ISR0: 1;
    unsigned char ISR1: 1;
    ...
    unsigned char ISR7: 1;
} ISRstatus;

El resto de la aplicación podría tener la siguiente estructura:

ISR(ISR0) {
    // set status flag
    ISRstatus.ISR0 = 1;
}

void main() {
    while(1) {
        if (ISRstatus.ISR0){
            // serve interrupt
            /* ... */
            // clear status flag    
            ISRstatus.ISR0 = 0;
        } /* ... */
    }
}

Hace poco me encontré con algunos artículos que sugerían evitar los campos de bits debido a su comportamiento inesperado en diferentes compiladores y arquitecturas.

Suponiendo que mi compilador sea GCC, ¿es mala idea utilizar este enfoque?

0voto

Jeremy Puntos 424

Suponiendo que mi compilador sea GCC, ¿es mala idea utilizar este enfoque?

Cualquier enfoque creado por el hombre tendrá sus ventajas y sus inconvenientes. En este caso en particular se debe pensar en los casos en que el valor de isr0 puede cambiar de una manera coherente I. Yo afirmaría que usted no tiene tal caso aquí.

0voto

Alex Andronov Puntos 178

Muchas plataformas tienen formas de actualizar atómicamente bits individuales dentro de un byte, pero lo consiguen de diferentes maneras. Aunque la norma permite el uso de campos de bits dentro de volatile -el único contexto en el que sería útil sería cuando todas las escrituras en la estructura que contiene el campo de bits se realizan dentro del mismo "hilo" (o contexto de interrupción). Fuera de ese patrón de uso limitado, la única forma de conseguir la semántica conocida en la mayoría de las plataformas es utilizar la manipulación manual de bits junto con las formas específicas de las plataformas de conseguir la semántica requerida.

Por ejemplo, el Cortex-M3 admite instrucciones LDREX/STREX, que se asignan a intrínsecos del compilador. Si el código utiliza LDREX para leer una palabra, calcular un nuevo valor, y luego STREX para intentar escribir el nuevo valor en la misma palabra, el STREX tendrá éxito (e informará de éxito) si no se ha producido ninguna interrupción después del LDREX y nada podría haber perturbado la palabra en cuestión, o fallará (e informará de fallo) sin escribir nada. Si el código quiere poner el bit inferior en un uint32_t volatile foo podría hacer algo como:

void set_bit_in_foo(void)
{
  uint32_t old_value;
  do
    old_value = __LDREXW(&foo);
  while(!__STREXW(old_value | 1, &foo));
}

Si nada accede a foo entre el __LDREXW y el __STREXW y no se produce ninguna interrupción entre ellos, el nuevo valor se escribirá en foo et __STREXW devolverá 1. En caso contrario, __STREXW devolverá 1 y el código lo intentará de nuevo utilizando un valor actualizado de foo .

Otras plataformas tienen otras formas de permitir las actualizaciones atómicas. C11 intenta añadir características para actualizaciones atómicas para plataformas que las soportan, pero está pobremente especificado en algunos aspectos clave (una implementación que afirma ofrecer cualquier soporte para operaciones atómicas no puede rechazar programas que requieren funciones que la implementación no puede soportar de forma útil, sino que debe proporcionar implementaciones rotas para esas funciones).

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X