¿Estoy usando el registro ADC ARM 7 LPC21xx correctamente?

¿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 whilebucle 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:

ingrese la descripción de la imagen aquí

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.

Incluso puede usar la interrupción ADC. Aunque aún obtendría un error de desbordamiento en el modo de ráfaga, no será un problema si simplemente ignora el error de desbordamiento. Es solo para mostrarle que algunas lecturas se han sobrescrito y que está leyendo la última lectura.
El código anterior no produjo ningún error de desbordamiento cuando se colocó dentro de una interrupción ADC...

Respuestas (2)

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:

  1. Habilite el temporizador y configure el período del temporizador para la frecuencia de muestreo deseada.
  2. Habilite el temporizador ISR para que el controlador de interrupción del temporizador se llame a la frecuencia de muestreo deseada.
  3. Habilite el ADC en modo de conversión única (NO en modo de ráfaga) para que realice una conversión única cada vez que se activa (es decir, se inicia).
  4. Habilite el ISR de ADC para que se llame al controlador de interrupciones de ADC cuando se complete la conversión de ADC.
  5. Dentro del controlador de interrupción del temporizador, active el ADC para iniciar una conversión y luego salga. No intente leer los resultados de ADC dentro del temporizador ISR.
  6. Dentro del controlador de interrupciones de ADC, lea los resultados de la conversión de ADC.

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.

  1. Habilite el temporizador y configure el período del temporizador para la frecuencia de muestreo deseada.
  2. Habilite el temporizador ISR para que el controlador de interrupción del temporizador se llame a la frecuencia de muestreo deseada.
  3. Habilite el ADC en modo ráfaga para que escanee a través de múltiples canales.
  4. Habilite el ISR de ADC para que se llame al controlador de interrupciones de ADC cuando se complete la conversión de ADC.
  5. Dentro del controlador de interrupción del temporizador, active el ADC para iniciar una conversión y luego salga. No intente leer los resultados de ADC dentro del temporizador ISR.
  6. Dentro del controlador de interrupciones de ADC, lea los resultados de la conversión de ADC. Si esta conversión es para el último canal en el conjunto de exploración, detenga el ADC. El ADC se reiniciará cuando ocurra el próximo temporizador ISR.
Entonces, ¿debería llamar al ADC ISR desde dentro del temporizador ISR? No estoy seguro de cómo debo hacerlo. Hice una edición de mi pregunta con lo que he hecho en mi código. Por extraño que parezca, cuando coloco la interrupción ADC dentro de la interrupción del temporizador, el bit de anulación desaparece.
Sin embargo, se encuentra otro problema como se explicó anteriormente.
@Rrz0, No, no debe llamar al ADC ISR desde el temporizador ISR. Eso no es lo que escribí. Lo entendiste mal.
Gracias, eso es mucho más claro! Sin embargo, como se especifica en la pregunta, necesito habilitar el modo de ráfaga ya que estoy leyendo más de un registro. ¿O no se necesita el modo ráfaga para esto...? Podría tener un malentendido con respecto a la funcionalidad del modo de ráfaga.
@Rrz0, si necesita usar el modo de ráfaga para escanear a través de múltiples canales, debe iniciar la conversión de ADC en el temporizador ISR y detener las conversiones de ADC después de que se complete el último canal. Las conversiones de ADC se reiniciarán cuando ocurra el próximo temporizador ISR.

Después de varias horas de pruebas, y con los útiles comentarios de kkrambo, descubrí lo siguiente.

  • La rutina de servicio de interrupción del temporizador se lee una vez cada 1 ms, según mi temporizador calculado.
  • Si el modo de ráfaga está habilitado, el registro ADC dentro de su rutina de servicio de interrupción se lee cada 22 microsegundos, independientemente del ISR del temporizador , ya que es llamado por la CPU.

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.