El programa MSP430 solo funciona durante el modo de depuración

7

Estoy intentando recuperar los valores del ADC en mi MSP430F5529 y enviarlos a mi computadora a través de USB, pero estoy empezando poco a poco. Todo lo que tengo ahora mismo es algo que recupera el valor de ADC y lo almacena en ADCResults, si el valor de lectura es más de la mitad de Vcc, entonces se enciende un LED.

Tengo el pin 6.0 conectado a un sensor de fuerza para que pueda ver cómo se apaga y enciende cuando lo aplasto o suelto.

El programa funciona perfectamente cuando lo ejecuto en modo de depuración, pero cuando trato de ejecutarlo fuera del modo de depuración (solo enciendo la placa desde la computadora después de que se descargue el código), no sucede nada cuando pongo el dedo en el sensor de fuerza.

Lo que es extremadamente extraño es si mantengo presionado reiniciar mientras coloco mi dedo en el sensor de fuerza (al poner mi dedo hacia abajo, el LED se enciende), y suelto el botón de reinicio, el LED permanece encendido hasta que vuelva a presionar reiniciar con mi dedo Apagado, por lo que parece que el restablecimiento está causando un problema, pero no estoy seguro de cómo.

Al principio pensé que el reinicio se estaba arrastrando constantemente alto (o bajo, lo que reinicie el dispositivo), pero eso no puede ser cierto porque entonces el programa debería funcionar si mantenía el reinicio presionado, ¡pero no!

Aquí está mi código:

#include "driverlib.h"

volatile uint16_t ADCResults = 0;

void main(void)
{
    //Stop Watchdog Timer
    WDT_A_hold(WDT_A_BASE);

    //P6.0 ADC option select
    GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

    GPIO_setAsOutputPin(
        GPIO_PORT_P1,
        GPIO_PIN0
        );

    //Initialize the ADC12_A_A Module
    /*
     * Base address of ADC12_A_A Module
     * Use internal ADC12_A_A bit as sample/hold signal to start conversion
     * USE MODOSC 5MHZ Digital Oscillator as clock source
     * Use default clock divider of 1
     */
    ADC12_A_init(ADC12_A_BASE,
                 ADC12_A_SAMPLEHOLDSOURCE_SC,
                 ADC12_A_CLOCKSOURCE_ADC12OSC,
                 ADC12_A_CLOCKDIVIDER_1);

    ADC12_A_enable(ADC12_A_BASE);

    /*
     * Base address of ADC12_A_A Module
     * For memory buffers 0-7 sample/hold for 64 clock cycles
     * For memory buffers 8-15 sample/hold for 4 clock cycles (default)
     * Disable Multiple Sampling
     */
    ADC12_A_setupSamplingTimer(ADC12_A_BASE,
                               ADC12_A_CYCLEHOLD_64_CYCLES,
                               ADC12_A_CYCLEHOLD_4_CYCLES,
                               ADC12_A_MULTIPLESAMPLESDISABLE);

    //Configure Memory Buffer
    /*
     * Base address of the ADC12_A_A Module
     * Configure memory buffer 0
     * Map input A0 to memory buffer 0
     * Vref+ = AVcc
     * Vr- = AVss
     * Memory buffer 0 is not the end of a sequence
     */
    ADC12_A_configureMemoryParam param = {0};
    param.memoryBufferControlIndex = ADC12_A_MEMORY_0;
    param.inputSourceSelect = ADC12_A_INPUT_A0;
    param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
    param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    ADC12_A_configureMemory(ADC12_A_BASE,&param);

    //Enable memory buffer 0 interrupt
    ADC12_A_clearInterrupt(ADC12_A_BASE,
                           ADC12IFG0);
    ADC12_A_enableInterrupt(ADC12_A_BASE,
                            ADC12IE0);

    while(1)
    {
        //Enable/Start sampling and conversion
        /*
         * Base address of ADC12_A_A Module
         * Start the conversion into memory buffer 0
         * Use the single-channel, single-conversion mode
         */
        ADC12_A_startConversion(ADC12_A_BASE,
                                ADC12_A_MEMORY_0,
                                ADC12_A_SINGLECHANNEL);

        //LPM0, ADC12_A_ISR will force exit
        __bis_SR_register(LPM0_bits + GIE);
        //for Debugger
        __no_operation();
    }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(ADC12_VECTOR)))
#endif
void ADC12_A_ISR(void)
{
    switch(__even_in_range(ADC12IV,34))
    {
    case  0: break;       //Vector  0:  No interrupt
    case  2: break;       //Vector  2:  ADC overflow
    case  4: break;       //Vector  4:  ADC timing overflow
    case  6:              //Vector  6:  ADC12IFG0
        //Is Memory Buffer 0 = A0 > 0.5AVcc?

          ADCResults = ADC12_A_getResults(ADC12_A_BASE,
                                        ADC12_A_MEMORY_0);
        if(ADCResults
           >= 0x7ff)
        {
            //set P1.0
            GPIO_setOutputHighOnPin(
                GPIO_PORT_P1,
                GPIO_PIN0
                );
        }
        else
        {
            //Clear P1.0 LED off
            GPIO_setOutputLowOnPin(
                GPIO_PORT_P1,
                GPIO_PIN0
                );
        }

        //Exit active CPU
        __bic_SR_register_on_exit(LPM0_bits);
    case  8: break;       //Vector  8:  ADC12IFG1
    case 10: break;       //Vector 10:  ADC12IFG2
    case 12: break;       //Vector 12:  ADC12IFG3
    case 14: break;       //Vector 14:  ADC12IFG4
    case 16: break;       //Vector 16:  ADC12IFG5
    case 18: break;       //Vector 18:  ADC12IFG6
    case 20: break;       //Vector 20:  ADC12IFG7
    case 22: break;       //Vector 22:  ADC12IFG8
    case 24: break;       //Vector 24:  ADC12IFG9
    case 26: break;       //Vector 26:  ADC12IFG10
    case 28: break;       //Vector 28:  ADC12IFG11
    case 30: break;       //Vector 30:  ADC12IFG12
    case 32: break;       //Vector 32:  ADC12IFG13
    case 34: break;       //Vector 34:  ADC12IFG14
    default: break;
    }
}

UPDATE

He intentado hacer la misma funcionalidad sin utilizar la biblioteca de controladores periféricos y parece funcionar perfectamente fuera del depurador. Esto me lleva a creer que algo anda mal con la biblioteca de controladores periféricos de Texas Instruments.

Aquí está el código que parecía funcionar bien fuera del depurador y no usa la biblioteca de controladores periféricos.

#include <msp430.h>

int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  ADC12CTL0 = ADC12SHT02 + ADC12ON;         // Sampling time, ADC12 on
  ADC12CTL1 = ADC12SHP;                     // Use sampling timer
  ADC12IE = 0x01;                           // Enable interrupt
  ADC12CTL0 |= ADC12ENC;
  P6SEL |= 0x01;                            // P6.0 ADC option select
  P1DIR |= 0x01;                            // P1.0 output

  while (1)
  {
    ADC12CTL0 |= ADC12SC;                   // Start sampling/conversion

    __bis_SR_register(LPM0_bits + GIE);     // LPM0, ADC12_ISR will force exit
    __no_operation();                       // For debugger
  }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12_ISR (void)
#else
#error Compiler not supported!
#endif
{
  switch(__even_in_range(ADC12IV,34))
  {
  case  0: break;                           // Vector  0:  No interrupt
  case  2: break;                           // Vector  2:  ADC overflow
  case  4: break;                           // Vector  4:  ADC timing overflow
  case  6:                                  // Vector  6:  ADC12IFG0
    if (ADC12MEM0 >= 0x7ff)                 // ADC12MEM = A0 > 0.5AVcc?
      P1OUT |= BIT0;                        // P1.0 = 1
    else
      P1OUT &= ~BIT0;                       // P1.0 = 0

    __bic_SR_register_on_exit(LPM0_bits);   // Exit active CPU
  case  8: break;                           // Vector  8:  ADC12IFG1
  case 10: break;                           // Vector 10:  ADC12IFG2
  case 12: break;                           // Vector 12:  ADC12IFG3
  case 14: break;                           // Vector 14:  ADC12IFG4
  case 16: break;                           // Vector 16:  ADC12IFG5
  case 18: break;                           // Vector 18:  ADC12IFG6
  case 20: break;                           // Vector 20:  ADC12IFG7
  case 22: break;                           // Vector 22:  ADC12IFG8
  case 24: break;                           // Vector 24:  ADC12IFG9
  case 26: break;                           // Vector 26:  ADC12IFG10
  case 28: break;                           // Vector 28:  ADC12IFG11
  case 30: break;                           // Vector 30:  ADC12IFG12
  case 32: break;                           // Vector 32:  ADC12IFG13
  case 34: break;                           // Vector 34:  ADC12IFG14
  default: break; 
  }
}
    
pregunta Aaron

3 respuestas

3

A veces, la razón de tal comportamiento es que las configuraciones de optimización son diferentes en el modo de depuración, y alguna variable que el compilador cree que no es necesaria se optimiza de inmediato.

Las soluciones para esto son agregar calificadores "volátiles" a dichas variables, o desactivar la optimización (o al menos apagarla).

No sé si esta es tu respuesta (el hilo se convierte en TL; DR), pero este dato debería aparecer como una posible solución para los motores de búsqueda.

    
respondido por el Scott Seidman
2

Descargo de responsabilidad: no soy un experto en MSP430.

Sugiero el uso de

ADC12_A_disableConversions()

después

ADC12_A_setupSamplingTimer() 

Extracto de MSP430 DriverLib for MSP430F5xx_6xx Devices

anular ADC12_A_startConversion (uint16_t baseAddress, uint16_t tartingMemoryBufferIndex, uint8_t conversionSequenceModeSelect)

  

Esta función habilita / inicia el proceso de conversión del ADC. Si la fuente de señal de muestra / retención elegida durante la inicialización fue ADC12OSC, entonces la conversión se inicia inmediatamente; de lo contrario, la fuente de señal de muestra / retención elegida inicia la conversión por un flanco ascendente de la señal. Tenga en cuenta que al seleccionar los modos de conversión, que para los modos secuenciados y / o repetidos, para que el proceso de muestra / retención y conversión continúe sin un desencadenante desde la fuente de señal de retención / muestra, las múltiples muestras deben habilitarse con la tecla ADC12_A_setupSamplingTimer () funciona. Tenga en cuenta que después de llamar a esta función, se debe llamar a ADC12_A_disableConversions () para reinicializar el ADC, reconfigurar un control de memoria intermedia, habilitar / deshabilitar el temporizador de muestreo o cambiar la tensión de referencia interna .

Nota: También hay algunos buenos cursos gratuitos en línea para aprender sobre el diseño de sistemas integrados. Uno de ellos utiliza MSP430. Tengo una lista de algunos de ellos a continuación.

Referencias:

respondido por el Mahendra Gunawardena
1

Me pregunto por qué funciona en modo de depuración, ha pasado un tiempo desde que trabajé con MSP430 y no estoy familiarizado con el driverlib. Pero:

GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

Seguramente no es la función que desea utilizar para cambiar este pin a una entrada analógica, ¿o sí? Lo intentaría:

GPIO_setAsPeripheralModuleFunctionIntputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

Pero como se ve en la descripción de las funciones de pines (gracias @ CL.) Queda claro que establecer el pin en la función periférica será suficiente y la dirección se ignora. Así que es engañoso, pero no es un factor decisivo.

Luego hay una pequeña cosa param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE; que probablemente debería ser param.endOfSequence = ADC12_A_ENDOFSEQUENCE; pero como solo haces una única conversión de canal, no debería importar (es un poco más claro). Y probablemente cambie ADC12IFG0 y ADC12IE0 a ADC12_A_IFG0 y ADC12_A_IE0 (pero solo se definen a los otros valores, por lo que no hay problema funcional)

Y le falta un break; después de su caso en la tabla de vectores de interrupción, pero eso tampoco afectará mucho al programa, solo es una fuente de futuros errores.

Por lo tanto, desde una perspectiva de firmware, solo tengo nitpicks menores.

Sobre la base de los comentarios, y leer la hoja de errata , me pregunto si un solo __no_operation(); después de __bic_SR_register_on_exit(LPM0_bits); en el ISR resolvería el problema. La errata no menciona explícitamente el caso presente aquí, pero hay problemas que involucran el establecimiento de modos de baja potencia, salir de los modos de baja potencia y dañar el contador del programa. Así que tal vez sea otro caso. Es posible que esos efectos no estén presentes durante la depuración, ya que el módulo de emulación interfiere con la ejecución normal del núcleo.

Pero también mencionó, que si borra la interrupción global, habilite su programa también funciona. Lo que me lleva a pensar que su programa se atasca en una interrupción pero no en el ADC. No es necesario que borre el indicador de interrupción del ADC, ya que esto se hace automáticamente al leer la memoria del ADC.

Solo otra nota sobre la programación, obtendría el análisis del valor ADC del ISR. Manténgalos lo más pequeños posible, solo lea el valor en su variable global y deje el modo de bajo consumo al salir. Haga todas las otras cosas en su aplicación principal. Hay casos en los que necesitarás una latencia de interrupción lo más corta posible y si haces cosas dentro del ISR bloquearás otras interrupciones (excepto que habilitas interrupciones anidadas, pero esas también son malas).

    
respondido por el Arsenal

Lea otras preguntas en las etiquetas