Why is my OVERUN bit 1 when ADC function is placed inside a timer interrupt routine?
As per the User Manual Page 306, the OVERUN
bit is 1 in burst mode if the results of one or more conversions was (were) lost and overwritten before the conversion that produced the result in the RESULT bits. This bit is cleared by reading this register.
I am setting up the ADC register to read on two channels using burst mode, and constantly getting the OVERUN bit set to 1 in the debugger. The code is as follows:
unsigned long dummyRead;
unsigned long AD0GDR_Read = AD0GDR;
int channel = (AD0GDR_Read>>24) & 0xF; //Extract Channel Number
int currentResult = (AD0GDR_Read>>6) & 0x3FF; //Extract Conversion Result
if(channel == 0)
{
dummyRead = AD0DR0; //Read to Clear Done flag , Also clears AD0 interrupt
AD00Result = currentResult;
}
if(channel == 1)
{
dummyRead = AD0DR1; //Read to Clear Done flag , Also clears AD0 interrupt
AD01Result = currentResult;
}
This works perfectly IF this code is placed inside an ADC Interrupt Service Routine, or simply placed in the main while
loop. However, this is not what I need.
Since I want to find the RMS of a sine wave I need to take ADC readings at specific time intervals (see here). Thus I have decided to create a timer interrupt with a pre-determined delay, which once complete, allows for an ADC reading. I have tested this code using a simple LED. A similar example may be found here.
I have coded up something similar and place the ADC function in the Timer ISR, however here is where problems start to occur. I am constantly getting the OVERRUN bit set to 1, which means I am losing conversions.
Code is as follows:
void initTimer0(void)
{
T0CTCR = 0x0; //Set Timer Mode
T0PR = 50000-1; //Increment T0TC at every 50000 clock cycles
T0MR0 = 2 - 1; //Zero Indexed Count-hence subtracting 1
T0MCR = (1<<0) | (1<<1);//Set bit0 & bit1 to Interrupt & Reset TC on MR0
VICVectAddr4 = (unsigned )timer0ISR; //Pointer Interrupt Function (ISR)
VICVectCntl4 = (1<<5) | 4; //(bit 5 = 1)->to enable Vectored IRQ slot
VICIntEnable = (1<<4); // Enable timer0 interrupt
T0TCR = (1<<1); // Reset Timer
}
__irq void timer0ISR(void)
{
long int readVal;
readVal = T0IR; // Read current IR value
IO0PIN ^= (1<<10); // Toggle LED at Pin P0.10
ADC(); //code as above
T0IR = readVal; // Write back to IR to clear Interrupt Flag
VICVectAddr = 0x0; // End of interrupt execution
}
Below is a snapshot of my debugger tool:
I simply cannot see why I am losing conversions, if this is the only place I am reading from the ADC register. It seems as though the location of this code is resulting in the loss of conversions (when placed in interrupt routine).
Any suggestions on why this is so?
You are getting overruns because the ADC in burst mode has completed multiple conversions in between the timer interrupts. - kkrambo
Does the OVERUN bit mean I am simply losing the first conversion, and thus my RMS reading will not be affected, OR am I losing conversions throughout the execution of the program?
EDIT It has been suggested to call the ADC interrupt after the timer interrupt is complete. Should something like this code skeleton be correct?
void initTimer0(void)
{
VICVectAddr4 = (unsigned )timer0ISR; //Pointer Interrupt Function (ISR)
VICVectCntl4 = 0x00000025; //(bit 5 = 1)->to enable Vectored IRQ slot
VICIntEnable = (1<<5); // Enable timer1 interrupt
}
__irq void timer0ISR(void)
{
VICIntEnable |= (1<<18) ;
VICVectCntl0 = (1<<5) | 18 ;
VICVectAddr0 = (unsigned) AD0ISR;
}
__irq void AD0ISR(void) //AD0 Interrupt Function
{
//ADC function above
}
The above code structure does not give an OVERUN error. Any hints as to why this may be so?
you should use the ADC interrupt to handle completion of the conversion and read the results. When the ADC completes the single conversion it will not automatically start another conversion but instead it will wait for the timer interrupt to trigger another conversion. -kkrambo
The problem with this is that: the ADC interrupt routine gets called from outside the timer routine.. somehow. I cannot seem to understand this since I am not sure if this is the correct behavior. This means that even though there is no overrun bit from the ADC register when placed inside it's own interrupt, it is being read at a much higher frequency than that of the timer interrupt.
I tested this by setting one bit to 'high' in both ISR. The bit in the timer ISR behaves as expected and goes high every 1 ms, while that of the ADC goes to 'high' every 22 us.