¿Por qué mi bit OVERUN 1 cuando la función ADC se coloca dentro de una rutina de interrupción de temporizador?
Según Manual de Usuario Página 306 , el OVERUN
el bit es 1 en modo ráfaga si los resultados de una o más conversiones se perdieron y sobrescribió antes de la conversión que produjo el resultado en los bits de RESULTADO. Este bit se borra leyendo este registro.
Estoy configurando el registro ADC para leer en dos canales usando el modo ráfaga , y constantemente obteniendo el bit OVERUN establecido en 1 en el depurador. El código es el siguiente:
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;
}
Esto funciona perfectamente SI este código se coloca dentro de una rutina de servicio de interrupción de ADC, o simplemente se coloca en el bucle principal while
. Sin embargo, esto no es lo que necesito.
Como quiero encontrar el RMS de una onda sinusoidal, necesito tomar lecturas de ADC en intervalos de tiempo específicos ( vea aquí ). Por lo tanto, he decidido crear una interrupción de temporizador con un retraso predeterminado, que una vez completado, permite una lectura de ADC. He probado este código utilizando un simple LED. Puede encontrar un ejemplo similar aquí .
He codificado algo similar y coloco la función ADC en el temporizador ISR, sin embargo, aquí es donde comienzan los problemas. Constantemente obtengo el bit OVERRUN establecido en 1, lo que significa que estoy perdiendo conversiones.
El código es el siguiente:
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
}
A continuación se muestra una instantánea de mi herramienta de depuración:
Simplemente no puedo ver por qué estoy perdiendo conversiones, si este es el lugar solo que estoy leyendo del registro de ADC. Parece que la ubicación de este código está resultando en la pérdida de conversiones (cuando se coloca en la rutina de interrupción).
¿Alguna sugerencia sobre por qué esto es así?
Está obteniendo excedentes porque el ADC en modo ráfaga ha completado múltiples conversiones entre las interrupciones del temporizador. - kkrambo
¿El bit OVERUN significa que simplemente estoy perdiendo la primera conversión y, por lo tanto, mi lectura de RMS no se verá afectada, O estoy perdiendo conversiones durante la ejecución del programa?
EDIT Se ha sugerido que se llame a la interrupción ADC una vez que se complete la interrupción del temporizador. ¿Debería ser correcto algo como este código de esqueleto?
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
}
La estructura de código anterior no da un error de REBORDE . ¿Alguna sugerencia de por qué esto puede ser así?
debe usar la interrupción ADC para controlar la finalización de la conversión y leer los resultados. Cuando el ADC completa la conversión única, no iniciará automáticamente otra conversión, sino que esperará a que la interrupción del temporizador active otra conversión. -kkrambo
El problema con esto es que: la rutina de interrupción de ADC se llama desde fuera de la rutina del temporizador ... de alguna manera. Parece que no puedo entender esto ya que no estoy seguro de si este es el comportamiento correcto. Esto significa que aunque no hay un bit de saturación del registro ADC cuando se coloca dentro de su propia interrupción, se está leyendo a una frecuencia mucho mayor que la de la interrupción del temporizador.
Probé esto configurando un bit a 'alto' en ambos ISR. El bit en el temporizador ISR se comporta como se espera y sube cada 1 ms, mientras que el ADC va a 'alto' cada 22 us.