Manejo de interrupciones durante la comunicación del dispositivo

2

Tengo la siguiente situación: Me dieron un AVR32UC3 (cosa muy bonita) y un dispositivo de medición. Estos dos se comunican a través de SPI, que funciona como se esperaba (después de jugar con los parámetros de SPI y así sucesivamente).

La estructura del programa es la siguiente:

  1. Inicia el dispositivo a través de SPI
  2. Iniciar la medición a través de SPI
  3. Espere a que se realice la medición (esto se señaliza a través de un GPIO - > Interrupt)
  4. Lea los datos de medición a través de SPI
  5. ve a 2

En este mismo momento, puedo adivinar aproximadamente cuánto tiempo tomará la medición (~ 3 ms). Actualmente ignoro la interrupción, estoy ocupado esperando en lugar de 3, luego leo los datos.

Ahora, para mi pregunta: me gustaría deshacerme de esa espera "ocupada". Por supuesto, si llega otra interrupción (de algún otro periférico), el código ejecutará esa interrupción de todos modos, pero el código de mi bucle principal no se procesará durante la espera. ¿Cómo puedo hacer esto "limpio" utilizando la propia interrupción?

La idea sería:

  • Configuración de la fuente de interrupción + condiciones
  • Comience la medición
  • Ocurre la interrupción
  • Recoger donde me fui

¿Cómo se ve el código fuente (pseudo-código) para algo como esto? ¿Cómo se hace esto CORRECTAMENTE?

    
pregunta Tom L.

2 respuestas

7

Podrías implementar una máquina de estado pequeña como esta:

// global, volatile (accessed from ISR) variable 
// (should also be 1-byte to prevent multibyte access issues on 8-bit system)
volatile CurrentState;

main() {
    Spi_Init();
    CurrentState = StartMeasurement;

    // your main loop
    while(true) {
        // other main processing here            

        // spi processing
        switch (CurrentState) {
           case StartMeasurement:
               Spi_StartMeasurement();
               CurrentState = WaitForResult;
               break;
           case WaitForResult:
               // nothing todo -> no blocking main -> this switch is just for clarification and can even be removed
               break;
           case ResultReady:
               Spi_GetResult();
               CurrentState = StartMeasurement;
               break;
           default:
               // CurrentState was set to invalid value -> error handling
               break;
        }
    }
}

ISR_ResultReady() {
    if (CurrentState == WaitForResult) {   // this should always be true but its cleaner to check it
        // signal main that result is ready
        CurrentState = ResultReady;
    }
}

Espero que tengas la idea. Hay formas más limpias y abstractas de hacer esto, pero para aplicaciones pequeñas también complica las cosas.

    
respondido por el Rev1.0

Lea otras preguntas en las etiquetas