¿Por qué mi OVERUN bit 1 cuando la función ADC se coloca dentro de una rutina de interrupción del temporizador?
Según la página 306 del Manual del usuario , el OVERUN
bit es 1 en modo ráfaga si los resultados de una o más conversiones se perdieron y se sobrescribieron 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 de ráfaga , y constantemente pongo el bit OVERUN 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 while
bucle principal. 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 ( ver aquí ). Por lo tanto, he decidido crear una interrupción de temporizador con un retraso predeterminado, que una vez completa, permite una lectura de ADC. He probado este código usando un LED simple. Un ejemplo similar se puede encontrar aquí .
He codificado algo similar y coloco la función ADC en el temporizador ISR, sin embargo, aquí es donde comienzan a ocurrir 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 único lugar donde estoy leyendo del registro ADC. Parece que la ubicación de este código está provocando la pérdida de conversiones (cuando se coloca en la rutina de interrupción).
¿Alguna sugerencia sobre por qué esto es así?
Está obteniendo excesos porque el ADC en modo de ráfaga ha completado múltiples conversiones entre las interrupciones del temporizador. - kkrambo
¿Significa el bit OVERUN 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?
EDITAR Se ha sugerido llamar a la interrupción ADC después de que se complete la interrupción del temporizador. ¿Debería ser correcto algo como este esqueleto de código?
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 OVERUN . ¿Alguna pista de por qué esto puede ser así?
debe usar la interrupción ADC para manejar la finalización de la conversión y leer los resultados. Cuando el ADC completa la conversión única, no comenzará 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 del 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 lee a una frecuencia mucho más alta que la de la interrupción del temporizador.
Probé esto configurando un bit en 'alto' en ambos ISR. El bit en el temporizador ISR se comporta como se esperaba y sube cada 1 ms, mientras que el del ADC sube a 'alto' cada 22 us.
Si desea tomar lecturas a una velocidad específica determinada por un temporizador, no debe usar el modo de ráfaga. En el modo de ráfaga, el ADC iniciará automáticamente la siguiente conversión cuando se complete la conversión anterior. Está obteniendo excesos porque el ADC en modo de ráfaga ha completado múltiples conversiones entre las interrupciones del temporizador. Y su software no leyó cada conversión entre las interrupciones del temporizador.
En su lugar, debe usar el modo de conversión simple (BURST = 0). Cuando ocurre la interrupción del temporizador, el controlador de interrupción del temporizador debe activar el ADC para iniciar una conversión. Probablemente no desee esperar a que se complete la conversión dentro del controlador de interrupción del temporizador. En su lugar, debe usar la interrupción ADC para manejar la finalización de la conversión y leer los resultados. Cuando el ADC completa la conversión única, no comenzará automáticamente otra conversión, sino que esperará a que la interrupción del temporizador active otra conversión.
Actualización: intentaré explicarlo más claramente:
Muestreo de múltiples canales: algunos ADC escanearán a través de todos los canales seleccionados en modo de conversión única. En ese caso, la técnica anterior seguiría siendo buena. Pero aparentemente, este ADC admite solo un canal en modo de conversión única y debe usar el modo de ráfaga para escanear a través de múltiples canales seleccionados. En este caso utilice los siguientes pasos.
Después de varias horas de pruebas, y con los útiles comentarios de kkrambo, descubrí lo siguiente.
Por lo tanto, habrá un error OVERRUN si la conversión del ADC se coloca directamente dentro del ISR del temporizador, ya que el ADC ha completado aproximadamente 50 conversiones entre las interrupciones del temporizador.
Esto también explica por qué no hay error OVERRUN cuando el ADC se coloca dentro de su propio ISR , ya que esto siempre completa las conversiones una vez cada 22 microsegundos.
La pregunta sigue siendo si las conversiones perdidas afectarán mi lectura general de RMS de la onda sinusoidal.
manyyack
rrz0