AnalogRead interferes with Digital Interrupt
Posted: 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
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