¿Estoy usando ARM 7 LPC21xx ADC para registrarme correctamente?

3

¿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.

    
pregunta Rrz0

2 respuestas

3

Si desea tomar lecturas a una velocidad específica determinada por un temporizador, no debe usar el modo ráfaga. En modo ráfaga, el ADC iniciará automáticamente la siguiente conversión cuando se complete la conversión anterior. Se están excediendo porque el ADC en modo ráfaga ha completado múltiples conversiones entre las interrupciones del temporizador. Y su software no leyó cada conversión entre interrupciones de temporizador.

En su lugar, debe utilizar el modo de conversión única (BURST = 0). Cuando se produce la interrupción del temporizador, el controlador de interrupción del temporizador debe activar el ADC para iniciar una conversión. Probablemente no quiera esperar a que se complete la conversión dentro del controlador de interrupción del temporizador. En su lugar, debe utilizar la interrupción de 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.

Actualizar: Intentaré explicarlo más claramente:

  1. Habilite el temporizador y configure el período del temporizador para la muestra deseada tasa.
  2. Habilite el ISR del temporizador para que el controlador de interrupción del temporizador sea llamado a la frecuencia de muestreo deseada.
  3. Habilite el ADC en el modo de conversión única (NO modo de ráfaga) para que realice una sola conversión cada vez que se active (es decir, que se haya iniciado).
  4. Habilite el ISR de ADC para que se llame al controlador de interrupción de ADC cuando el ADC la conversión está completa.
  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 explorarán todos los canales seleccionados en modo de conversión única. En ese caso la técnica anterior aún sería buena. Pero al parecer, este ADC solo admite un canal en el modo de conversión única y debe usar el modo de ráfaga para explorar a través del canal seleccionado múltiple. En este caso, siga los siguientes pasos.

  1. Habilite el temporizador y configure el período del temporizador para la muestra deseada tasa.
  2. Habilite el ISR del temporizador para que el controlador de interrupción del temporizador sea llamado a la frecuencia de muestreo deseada.
  3. Habilite el ADC en modo ráfaga para que explore a través de múltiples canales.
  4. Habilite el ISR de ADC para que se llame al controlador de interrupción de ADC cuando el ADC la conversión está completa.
  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 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 se produzca el siguiente ISR del temporizador.
respondido por el kkrambo
1

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

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

Por lo tanto, habrá un error de OVERRUN si la conversión de ADC se coloca directamente dentro del ISR del temporizador ya que el ADC ha completado aproximadamente 50 conversiones entre interrupciones del temporizador.

Esto también explica por qué no hay error de REEMPLAZO 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.

    
respondido por el Rrz0

Lea otras preguntas en las etiquetas