AnalogRead interferes with Digital Interrupt

rodmcm
Posts: 16
Joined: Sat Sep 02, 2017 3:31 am

AnalogRead interferes with Digital Interrupt

Postby rodmcm » Wed Sep 12, 2018 11:11 pm

I have deduced that reading an analog under a timed interrupt interferes with my digital interrupt. A Google search shows others have had this problem as well.. I tried some of the workarounds but no success

Has anyone a proper solution for this.
The attached code is a much simplified program. If the analog read line is bypassed the frequency measurement works great. With it in I get a constant reading of 33333 Hz

Code: Select all

 
// Analog Measurement
volatile int SampleTotal=750;
volatile int ADCSampleCount=0;                      // counts samples in AnalogValue
volatile int ADCState;                              // state counter for sampling 1: sample, 2: finish
volatile uint8_t AnalogPin;                     
volatile int AnalogVal[750];
int ADCNo=1;
float Max1;
float Min1;

// frequency measurement
const byte        interruptPin = 25;              // Assign the interrupt pin
volatile uint64_t StartValue;                     // First interrupt value
volatile uint64_t PeriodCount;                    // period in counts of 0.000001 of a second
float             Freg;                           // frequency
int               RPM;                            // 4 cyclinder RPM - Freq x 120     

 // timer setups         
hw_timer_t * timer0 = NULL;                   // timer0 used for analogs pointer to a variable of type hw_timer_t
hw_timer_t * timer1 = NULL;                   // timer1 used for digital/freq measurement pointer to a variable of type hw_timer_t

portMUX_TYPE Freqmux = portMUX_INITIALIZER_UNLOCKED;   // allows for synchronising between the ISR and the main code ?????????
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; 



//-------------------------------------------------------------
// Digital Event Interrupt
// This event triggers on the falling value on the interrupt pin
// ISR located in IRAM
//-------------------------------------------------------------
void IRAM_ATTR handleInterrupt()
{
   portENTER_CRITICAL_ISR(&Freqmux);
    uint64_t TempVal= timerRead(timer1);        // value of timer at interrupt
    PeriodCount= TempVal - StartValue;          // period count between rising edges in 0.000001 of a second
    StartValue = TempVal;                       // puts latest reading as start for next calculation
    portEXIT_CRITICAL_ISR(&Freqmux);
}

//----------------------------------------------------------
// ADC Interrupt
// This interrupt is triggered by the timer0 and samples the
// analogs until the total sample is exceeded
// ISR located in IRAM
//------------------------------------------------------------

void IRAM_ATTR onTimer()
 {
   portENTER_CRITICAL_ISR(&mux);
   if ((ADCSampleCount<SampleTotal)&&(ADCState==1))       
      {
       AnalogVal[ADCSampleCount]=analogRead(AnalogPin);       
       ADCSampleCount++;
      }
     if (ADCSampleCount>=SampleTotal)
      {
       ADCSampleCount=0;                               // sets for next sample
       ADCState = 2;                                   // signals completion to main program
      }
   portEXIT_CRITICAL_ISR(&mux);
 } // end ISR


//-----------------------------------
// Clears the analog Array
//-------------------------------------
void ClearAnalogArray()
{
  for (int i=0;i<750;i++)
  AnalogVal[i]=0;
}

//--------------------------------------------
// Calculates max and min from 750 samples
//---------------------------------------------
void AnalogMaxMin()
{
  Max1=0;
  Min1=4095;
   for (int i=0;i<SampleTotal;i++)
 {
  if (AnalogVal[i]>Max1) Max1=AnalogVal[i];     
  if (AnalogVal[i]<Min1) Min1=AnalogVal[i];
 }
 Max1=3.0*Max1/4095;                       // just for a test
 Min1=3.0*Min1/4095;                       // just for a test

}


//-----------------------------------------------
//Gets frequency from interrupt reading
//----------------------------------------------
 void CalcFreq()
 {
  portENTER_CRITICAL(&Freqmux);
  Freg =1000000.00/PeriodCount;                       // PeriodCount in 0.000001 of a second
  portEXIT_CRITICAL(&Freqmux);
 }


//----------------------------------------------------------------
// Setup
//----------------------------------------------------------------
void setup()
{

 Serial.begin(115200);                          // Debug
 pinMode(interruptPin, INPUT_PULLUP);           // sets pin high
 
 // analog stuff
 analogSetWidth(12);
 analogSetAttenuation(ADC_11db);
 analogReadResolution(12);                       //0-4095
 ADCNo=1;                                        // Analog input counter                               
 AnalogPin=34;                                   // Analog Pin allocation
 ADCState=1;                                     //1 = sampling 2 = completed

// Analog Interrupt SetUp
 timer0 = timerBegin(0, 80, true);               // this returns a pointer to the hw_timer_t global variable
                                                 // 0 = first timer (analog)
                                                 // 80 is prescaler so 80MHZ divided by 80 = 1MHZ signal ie 0.000001 of a second
                                                 // true - counts up
  timerAttachInterrupt(timer0, &onTimer, true);  // attaches the timer to a pointer to the interrupt routine onTimer, true means rising edge
  timerAlarmWrite(timer0, 300, true);            // this attaches the timer to the interrupt every 300 counts (0.0003 second = 3/10mS)
                                                 // thus 750 counts = 0.225 sec
                                                 // true means the counter will reset after each interrupt
  timerAlarmEnable(timer0); 
  delay(200);
                                               
 // frequency interrupt setup
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING); // attaches pin to interrupt on Falling Edge
  timer1 = timerBegin(1, 80, true);                                               // this returns a pointer to the hw_timer_t global variable
                                                                                  // 1 = first timer(freq)
                                                                                  // 80 is prescaler so 80MHZ divided by 80 = 1MHZ signal ie 0.000001 of a second
                                                                                  // true - counts up
  timerStart(timer1);                                                             // Start the timer
  delay(200);   
 
  Serial.println(" Setup Complete");
}    // setup



//-----------------------------------------------------------------
// Main Program
//-----------------------------------------------------------------
void loop()
{
// Calculates values at end of analog sample 
//---------------------------------------------------------
 if (ADCState==2)                      //Samplng completed
   {   
   AnalogMaxMin();                     // Finds the Max and Min values
   Serial.print("Max V  :");Serial.println(Max1,2);
   Serial.print("Min V  :");Serial.println(Min1,2);
   CalcFreq();                          // Calculates the frequency
   Serial.print("Frequency   ");Serial.println(Freg,2);
   ClearAnalogArray();
   ADCState=1;                         //Reset sampling
   }  // sample completed 
} // end loop

Who is online

Users browsing this forum: No registered users and 6 guests