Usando el temporizador MSP430G2452 + ADC

4

Estoy tratando de construir un afinador de guitarra simple usando MSP430G2452. La señal de la guitarra vendrá a través de sus pastillas, a través de un amplificador y un filtro de 1kHz que construí usando LM358.

== Context ==

Ahora, mi concepto de detección de tono se basa libremente en cero cruces. Estoy contando la cantidad de picos que obtengo al hacer un seguimiento de 3 muestras a la vez. Si la muestra del medio es mayor que las dos en los lados, es un pico. De esta manera, cuento la ocurrencia de los picos y encuentro el tono (que puede ser el fundamental o uno de los armónicos).

He probado esto usando notas de guitarra grabadas y Python en mi PC, y parece funcionar en teoría.

== Ahora, mi problema ==

Quiero que el ADC se active a mi velocidad deseada, por ejemplo, 2kHz. Para esto, estoy usando una interrupción de temporizador que habilita e inicia la conversión de ADC. La interrupción ADC procesa mi muestra y vuelve a configurar el temporizador. Se supone que este proceso cíclico me da una muestra cada 1/2000 segundos.

Sin embargo, me he dado cuenta de que el temporizador no funciona como se espera para conteos muy bajos.

Digamos que tengo el reloj del temporizador a 12kHz (VLOCLK) y el recuento como 6 para obtener una interrupción cada 1/2000 seg. Configuré un LED para alternar en la interrupción del temporizador para poder verlo. Naturalmente, la frecuencia es tan rápida que el LED parece estar completamente encendido. Pero en cambio, el LED parpadea una vez a los 4 o 5 segundos. Parece que el temporizador está contando todo el camino hasta el valor más alto, y regresando al 6, y solo entonces se genera una interrupción.

Esto solo sucede si el valor del contador es demasiado bajo. Tengo un código en bruto a continuación. Esta es una versión un poco más antigua que la actual que tengo. Pero debería dar una buena idea de lo que estoy tratando de lograr. (En el código a continuación, el temporizador se ha configurado para interrumpir una vez por segundo, pero no funciona bien para los intervalos bajos que quiero)

#include <msp430g2452.h>

#define TIMER_COUNT 12000
volatile unsigned int value = 0;

void configClocks();
void configTimer();
void configADC();

void main(void)
{
    WDTCTL = WDTPW + WDTHOLD; //Stop Watchdog

    P1DIR = 0xFF;
    P1DIR &= ~BIT5;
    P1SEL |= BIT5;

    configClocks();
    configTimer();
    configADC();

    TACCR0 = TIMER_COUNT;
    TACTL |= MC_2;

    __enable_interrupt();

    while (1)
    {
    }
}

void configClocks()
{
    //Set basic clock
    DCOCTL = CALDCO_1MHZ; //DCO 1mhz
    BCSCTL1 = CALBC1_1MHZ; //Aclk 1mhz
    BCSCTL2 = SELM_0 + DIVM_0 + SELS + DIVS_0; //Master 1 Mhz, SMCLK = VLO = 12
}

void configTimer()
{
    TACTL = TASSEL_2 + ID_0 + MC_0; // SMLCK, No div, Stopped
    TACCTL0 = CCIE;
}

void configADC()
{
    ADC10CTL1 = INCH_5 + ADC10SSEL_1;
    ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE;
    ADC10AE0 |= BIT5;
}

// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
    P1OUT ^= 0x01;
    ADC10CTL0 |= ENC + ADC10SC;
}

//ADC10 interrupt routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
    value = ADC10MEM;
    P1OUT ^= BIT6;
    TACCR0 += TIMER_COUNT; //Set timer count
    //__bic_SR_register_on_exit(CPUOFF);        // Return to active mode
}

== Otro enfoque que estoy pensando ==

Podría haber algo que estoy pasando por alto, o mi idea en sí misma podría ser fundamentalmente defectuosa. El otro plan que pensé era tener todo dentro de un bucle while. Algo como abajo:

while (1)
{
    //delay for 1/2000 time
    //enable ADC
    //SLEEP (will be woken up by ADC interrupt
    value = ADC10MEM
    //do something meaningful with the value
}

Tengo el intento de encima de uno. Pero lo he puesto en el caso de que alguno de ustedes pueda capturar cualquier falla en el mismo, o indicarme una mejor manera de hacerlo.

    
pregunta AgilE

2 respuestas

1

El MSP430G2452 tiene tres errores del Temporizador A en ambas revisiones, cualquiera de los cuales podría estar afectándote. Se pueden leer en la Errata para el chip. Creo que tal vez el error TA12:

  

La interrupción se pierde (ACLK lento):
  El contador Timer_A se está ejecutando con un reloj lento (TACLK externo o ACLK) comparado con MCLK. El modo de comparación se selecciona para el canal de captura / comparación y el registro CCRx se incrementa en uno con la interrupción de comparación que se produce (si TAR = CCRx). Debido al rápido MCLK, el incremento del registro CCRx (CCRx = CCRx + 1) ocurre antes de que el contador Timer_A se haya incrementado nuevamente. Por lo tanto, la siguiente interrupción de comparación debe suceder de una vez con el siguiente incremento del contador Timer_A (si TAR = CCRx + 1). Esta interrupción se pierde.

     

Solución alternativa: cambie el modo de captura / comparación al modo de captura antes del incremento de registro CCRx. Vuelve al modo de comparación.

Incluso si este no es el caso, puedes solucionarlo fácilmente. Está utilizando el reloj maestro predeterminado de 1MHz. Puede cambiar esto a 2 MHz o 4 MHz con un simple cambio de código, momento en el que el mismo divisor producirá un VLO de 24KHz o 48Khz. Esto le permitiría establecer un conteo de temporizador un poco más alto, nuevamente 12 o 24, evitando el problema del conteo más bajo. Por supuesto, las pruebas son necesarias para estar seguros.

Tu plan alternativo también funciona. Si no está demasiado preocupado por la baja potencia, los retrasos simples funcionarán. Por supuesto, como esto se está ejecutando en el reloj maestro de 1Mhz, tendrá que calcular una demora adecuada y darse cuenta de que habrá una ligera desviación.

    
respondido por el Passerby
1

Parece que estás poniendo el temporizador en modo Continuo ( MC_2 ), en cuyo caso el temporizador contará hasta 65535 antes de que vuelva a 0. Se interrumpirá cuando llegue a 6 (o 12000 o lo que sea) el valor de TA0CCR0 es), pero no restablecerá el contador a 0 en ese caso, lo que significa que la primera interrupción puede ocurrir en 6 tics, pero el período de la interrupción será 65536.

Creo que quieres el modo Up ( MC_1 ), que restablecerá el contador cuando alcance el valor objetivo.

Es posible que también desees borrar el temporizador ( TACLR ) mientras lo enciendes, solo para que sepas que el temporizador comienza desde cero.

    
respondido por el Jander

Lea otras preguntas en las etiquetas