Instructables

Step 17: Writing the kernel of the sketch

Picture of Writing the kernel of the sketch
ISR(ANALOG_COMP_vect).png
Finally we have gotten to the kernel of the program!

As we saw before, I wanted a continuous acquisition and I wrote the ADC Interrupt Service Routine to store in the circular buffer the data continuously. It stops whenever it reaches the index that is equal to stopIndex. The buffer is implemented as circular employing the modulo operator.

//-----------------------------------------------------------------------------
// ADC Conversion Complete Interrupt
//-----------------------------------------------------------------------------
ISR(ADC_vect)
{
        // When ADCL is read, the ADC Data Register is not updated until ADCH
        // is read. Consequently, if the result is left adjusted and no more
        // than 8-bit precision is required, it is sufficient to read ADCH.
        // Otherwise, ADCL must be read first, then ADCH.
        ADCBuffer[ADCCounter] = ADCH;

        ADCCounter = ( ADCCounter + 1 ) % ADCBUFFERSIZE;

        if ( wait )
        {
                if ( stopIndex == ADCCounter )
                {
                        // Freeze situation
                        // Disable ADC and stop Free Running Conversion Mode
                        cbi( ADCSRA, ADEN );

                        freeze = true;
                }
        }
}

The Analog Comparator Interrupt Service Routine (that is called when a signal passes the threshold) disables itself and tells the ADC ISR to start the waiting phase and sets the stopIndex.

//-----------------------------------------------------------------------------
// Analog Comparator interrupt
//-----------------------------------------------------------------------------
ISR(ANALOG_COMP_vect)
{
        // Disable Analog Comparator interrupt
        cbi( ACSR,ACIE );

        // Turn on errorPin
        //digitalWrite( errorPin, HIGH );
        sbi( PORTB, PORTB5 );

        wait = true;
        stopIndex = ( ADCCounter + waitDuration ) % ADCBUFFERSIZE;
}


This was really easy after all that grounding!

 
Remove these adsRemove these ads by Signing Up
womai2 years ago
Two ideas to make the code more efficient (run faster):

The calculation

ADCCounter = ( ADCCounter + 1 ) % ADCBUFFERSIZE;

involves an integer division which tends to be time consuming (at least on a Microchip PIC - I do not know Atmel as well). Instead, try

if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0;

Second, you can completely avoid the time required to evaluate

if(wait)

and live without the wait variable if you simply set stopIndex to a value that the counter never reaches, as long as you aren't yet in the post-trigger phase. I.e. during initialization (when starting a new sweep) set

stopIndex = ADCBUFFERSIZE + 1;

and when the trigger event happens then just do as you did so far, but without the boolean wait variable:

ISR(ANALOG_COMP_vect)
{
// Disable Analog Comparator interrupt
cbi( ACSR,ACIE );

// Turn on errorPin
//digitalWrite( errorPin, HIGH );
sbi( PORTB, PORTB5 );

stopIndex = ( ADCCounter + waitDuration ) % ADCBUFFERSIZE;
}

and the ADC ISR routine becomes

ISR(ADC_vect)
{
if (++ADCCounter >= ADCBUFFERSIZE) ADCCounter = 0;

if ( stopIndex == ADCCounter )
{
cbi( ADCSRA, ADEN );
freeze = true;
}
}