Electronic – Handling interrupts during device communication

interrupts

I have the following situation:
I was given a AVR32UC3 (pretty neat thing) and a measurement device. These two communicate via SPI, which works as expected (after fiddling with SPI params and so on).

The program structure is as follows:

  1. Init the device via SPI
  2. Start the measurement via SPI
  3. Wait for the measurement to be done (this is signaled via a GPIO –> Interrupt)
  4. Read the measurement data via SPI
  5. Go to 2

At this very moment, I can roughly guess how long the measurement will take (~3ms). I currently ignore the interrupt, do busy waiting instead of 3, then read the data.

Now for my question: I would like to get rid of that "busy" waiting. Of course, if another interrupt arrives (from some other peripheral) the code will execute that interrupt anyway but code in my main loop will not be processed during the busy waiting. How would I do this "clean" using the interrupt itself.

The idea would be:

  • Setup interrupt source + conditions
  • Start the measurement
  • Interrupt occurs
  • Pick up where I left

How does the source code (pseudo-code) for something like this look? How is this done PROPERLY?

Best Answer

You could implement a small state machine like this:

// 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;
    }
}

I hope you get the idea. There are cleaner, more abstract ways to do this, but for small applications it also overcomplicates things.