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

Estoy tratando de 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 en este momento 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 poder verlo apagarse y encenderse cuando pongo el dedo sobre él o lo suelto.

El programa funciona perfectamente cuando lo ejecuto en modo de depuración, pero cuando intento ejecutarlo fuera del modo de depuración (simplemente encendiendo la placa desde la computadora después de descargar el código), no sucede nada cuando pongo el dedo en el sensor de fuerza.

Lo que es extremadamente extraño es que si mantengo presionado el botón de reinicio mientras pongo el dedo en el sensor de fuerza (poner el dedo hacia abajo hace que el LED se encienda) y suelto el botón de reinicio, el LED permanece encendido hasta que vuelva a pulsar el botón de reinicio sin quitar el dedo. por lo que parece que el reinicio está causando un problema, pero no estoy seguro de cómo.

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

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;
    }
}

ACTUALIZAR

He intentado hacer la misma funcionalidad sin usar 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; 
  }
}
¿Estás haciendo esto en un LaunchPad o en alguna otra placa de desarrollo de TI? ¿O es algo que has diseñado?
No estoy lo suficientemente familiarizado con los MSP430 para estar seguro, pero: ¿podría ser que el WDT esté habilitado a la fuerza por un bit de configuración? Algunos uC le permiten forzar el WDT, que puede ser anulado por el módulo DBGU. Lo mismo ocurre con cualquier otra interrupción (de protección), si estuviera más familiarizado, revisaría su código, pero las interrupciones son una fuente muy común para este tipo de comportamiento. (Al igual que la interrupción de desbordamiento de división: no se activa en modo de depuración en muchos dispositivos, pero se activa de forma forzada cuando no está en modo de depuración).
@DigitalNinja Sí, estoy en un Launchpad, el MSP430F5529 Launchpad
@Asmyldof No estoy seguro de si el WDT lo está haciendo, el código claramente deshabilita el WDT pero todavía soy un novato, así que no tengo idea.
@Aaron Mejor espere a alguien con más experiencia, pero la mayoría de las MCU con las que he trabajado permiten que el dispositivo de programación configure un bit especial que bloquea el WDT, de modo que el software que lo apaga no tiene ningún efecto. Pero bien puede ser algo completamente diferente, solo pensé en poner mi 2ct hasta que un gurú inevitablemente pase rápidamente.
@Aaron La forma en que describió la operación con el botón de reinicio hace que parezca que simplemente se mantiene en reinicio. Lo saca del reinicio, ve que es su entrada y luego vuelve a estar en reinicio cuando quita la presión del botón. Al presionarlo de nuevo, aparece y se reinicializa el LED. Normalmente, el depurador se encarga del reinicio porque usa la línea de reinicio para la programación. ¿Ha verificado dos veces la configuración de su puente? Hay un puente para reinicio etiquetado (RST).
@Aaron Además, también tengo un LaunchPad que usé solo una vez, pero no tuve problemas para ejecutar el programa fuera del depurador. Estaba usando un MSP430 diferente con esta línea WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timerpara detener el perro guardián.
@Aaron, por lo general, desea dejar que el ADC se asiente antes de realizar la medición. No tengo nada con ADC en MSP430. Pero poco trabajo he hecho en un ARM Cortex-M4, dejé que el ADC se asentara antes de capturar la medida. Pero no pretendo ser un experto. Sugiero cambiar 7ff a un valor más bajo solo para depurar.
El MSP430 no funciona de esa manera @Asmyldof
@DigitalNinja OP's en la plataforma de lanzamiento F5529 y usando la biblioteca de controladores msp430. WDT_A_hold es una función para hacer lo mismo que modificar directamente el WDTCTL
OP este enlace convertidor analógico a digital podría ayudarlo.
No creo que el restablecimiento se retenga porque otros programas funcionan bien fuera del depurador, como un simple botón que controla el programa LED (el botón hace que el LED se encienda) funciona bien fuera del depurador
Para el ADC12_A_clearInterrupt()y ADC12_A_enableInterrupt(), no está usando los símbolos que la documentación dice que debe usar, pero esto en realidad no importa.
¿Puede poner un retraso y un parpadeo incondicional del otro LED en el bucle principal para ver si funciona?
sí, déjame probar eso ahora mismo y ver si entra en la red principal, te informaré pronto
@CL. se está metiendo en main, déjame ver si se detiene en alguna parte
@CL. Está llegando a todas partes en main, desde la primera línea después de WDTHold hasta dentro del bucle while, incluso después de __no_operation() en el bucle while, parece llegar a todos los puntos en el modo de depuración exterior principal.
@CL. Acabo de probar si entra en el ISR haciendo que el LED verde (el que no uso en este programa, se encienda directamente después de ADC12_A_getResultsque se llame. Lo enciendo sin importar qué (lo que significa que no es parte de la instrucción if), y se enciende bien Entonces sé que al menos está activando el ISR
@CL. Entonces, parece que el único punto en el programa en el que no parece entrar cuando no se está depurando es la declaración if, pero llega allí cuando depuro. A menos que el problema sea tomar muchas muestras cuando no está en modo de depuración (lo que significa que solo ingresa a la declaración if una vez), si solo ingresa a la declaración if una vez, explicaría este extraño comportamiento de reinicio donde funciona dependiendo del estado directamente cuando se levanta el reinicio.
@Aaron No estoy seguro de qué __bis_SR_register(LPM0_bits + GIE);está haciendo esta línea. Sin embargo, ¿no necesita borrar la interrupción antes de iniciar otra conversión? Como en, llamar ADC12_A_clearInterrupt(ADC12_A_BASE,ADC12IFG0);después de que se haya completado la conversión. Tal vez es por eso que solo lee el ADC una vez directamente después del reinicio.
@DigitalNinja No sé qué __bis_SR_register(LPM0_bits + GIE)está haciendo exactamente, ya que ya estaba en el código de ejemplo, pero creo que configura la MCU en modo de bajo consumo y habilita las interrupciones para sacarlo del modo de bajo consumo. Curiosamente, el código ingresa al ISR fuera del modo de depuración, pruebo esto haciendo que un LED cambie cada vez que ingresa al ISR y poniendo algunos ciclos de retraso para que pueda verlo parpadear. ¡Esto hace que todo el programa funcione correctamente!
@DigitalNinja Entonces, parece que crear un retraso permite que el programa funcione bien fuera del compilador, ¿qué nos dice esto sobre por qué no funcionará normalmente? ¿Por qué necesito un retraso? ¿Todo lo que hace __delay_cycles es un montón de NOP correctos? Bueno, ¿qué sucede durante esos NOP que hacen que el programa funcione correctamente?
@DigitalNinja He logrado un gran avance, he descubierto que si incluye + GIEen el argumento de la llamada __bic_SR_register_on_exitque se llama justo antes de que salga el ISR, ¡todo el programa funciona bien! Simplemente no sé qué están haciendo estas funciones.
@Aaron Buen trabajo. Supongo GIEque las interrupciones globales están habilitadas. Entonces parece que sin el + GIEen esa línea ( __bic_SR_register_on_exit), las interrupciones se deshabilitan. Agregarlo habilita las interrupciones y, por lo tanto, obtiene la siguiente interrupción de ADC al volver a ingresar al bucle principal.
@DigitalNinja Por favor, corríjame si me equivoco, pero todavía estoy confundido porque incluso sin + GIEque el programa funcionara, siempre que retrasara el ISR
@Aaron Sí, estaba pensando que, aunque + GIEno está en esa línea en el ISR, se llamaría en el ciclo principal ( __bis_SR_register(LPM0_bits + GIE)) y volvería a habilitar las interrupciones globales si se hubieran deshabilitado. Entonces, en realidad es solo la demora lo que lo arregló, como acabas de señalar. ¿Dónde pusiste el retraso en el ISR y cuánto es el retraso?
@Aaron Otro pensamiento es, ¿te importa el modo de bajo consumo? Si no, diría que simplemente elimine esas dos líneas que configuran los bits de baja potencia, y el problema podría desaparecer.
@DigitalNinja No sé a qué se refiere con main volver a habilitar la interrupción global, incluso si main llamó a la __bis_SR_register(LPM0_bits + GIE)línea después de que regresó el ISR y, por lo tanto, configuró el GIE, ¿por qué la demora haría que main lo volviera a habilitar pero no tuviera una causa de demora? main para no volver a habilitarlo. El retraso se ubicó directamente antes de la if(ADCResults >= 0x7ff)declaración dentro del ISR
@DigitalNinja Me importa el modo de bajo consumo, no porque lo necesite específicamente para esta aplicación, sino porque soy un novato y quiero la experiencia de trabajar con el modo de bajo consumo. Después de todo, es una práctica de programación adecuada para el diseño integrado.
Borrar el bit GIE deshabilitaría cualquier interrupción adicional. Y la interrupción de ADC ya se borra al leer el ADC12IVregistro.
@CL. No creo que entienda completamente lo que está diciendo, ¿por qué la demora dentro del ISR permite que el bucle principal vuelva a afirmar el bit GIE?
@Aaron Este hilo de comentarios se está volviendo muy largo... Solo quise decir que esta línea __bis_SR_register(LPM0_bits + GIE)habilita interrupciones globales en su ciclo principal, independientemente del retraso o de la otra línea en el ISR. No sé por qué un retraso allí lo soluciona. No creo que debas necesitarlo. Entonces, algo más está sucediendo, tal vez con la configuración de ADC. ¿Ha buscado ayuda en los foros de TI o ha cambiado su código para que coincida exactamente con un ejemplo?
¿Hiciste algún cambio del programa de ejemplo de TI?
@Aaron Intente cambiar este parámetro ADC12_A_CYCLEHOLD_64_CYCLESpara ADC12_A_setupSamplingTimerque también sea ADC12_A_CYCLEHOLD_4_CYCLESy elimine su código de retraso.
@DigitalNinja Estoy de acuerdo en que este comentario es enorme, pero solo quiero saber por qué ocurre este extraño comportamiento. No puedo entender por qué la demora está solucionando el problema.
@CL. sí, incluí algunas bibliotecas que el ejemplo no tiene, pero nunca hago referencia a ellas. Quiero dejar explícitamente claro que estas bibliotecas no son el caso porque SOLO verifiqué dos veces al cargar el proyecto de ejemplo (sin agregar nada en absoluto), y ocurren exactamente los mismos síntomas hasta que agrego el retraso o la + GIEllamada de ISR de __bic_SR_register_on_exit. Entonces sé que las bibliotecas adicionales no están causando el problema, simplemente no puedo entender por qué la demora tiene el mismo efecto que agregar+GIE
@DigitalNinja cambiando ese parámetro hace que el LED no se encienda ni siquiera DENTRO del depurador, y mucho menos fuera de él. No sé exactamente qué hace este parámetro, pero no ayuda porque ahora el programa ni siquiera funciona en modo de depuración.
Deberías preguntar en el foro de TI .
@Aaron fue solo una suposición descabellada. El hecho es que no debería necesitar un retraso allí. Si resuelve esto con la ayuda de TI, vuelva y publique la respuesta.
@DigitalNinja si lo descubro, definitivamente publicaré la respuesta. Gracias por el apoyo, con la ayuda de ustedes, al menos he reducido los síntomas y las posibles soluciones.
__bis_SR_register(LPM0_bits + GIE)establece el modo de bajo consumo 0 y los bits de activación de interrupción global en el registro especial que controla el modo de suspensión y las interrupciones globales. El retraso después de configurar la interrupción y el sueño es para evitar que se atasque en el sueño.

Respuestas (3)

A veces, el motivo de este comportamiento es que la configuración de optimización es diferente en el modo de depuración, y alguna variable que el compilador cree que no es necesaria se optimiza inmediatamente.

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

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

volatilecalificador estaba allí en el primer código, por lo que aunque a menudo es un problema, en este caso no
@Arsenal: esa es la variable que puede ver . Tal vez hay algo enterrado en una biblioteca que él no conoce. El primer paso para mí sería desactivar la optimización. Se necesitan diez minutos de lectura para descubrir cómo, lo haces y luego lo sabes.
@ScottSeidman Gracias por la sugerencia, las optimizaciones estaban desactivadas desde el principio, casi siempre trabajo con ellas desactivadas para empezar
La biblioteca envía todos los accesos al hardware a un puntero volátil que luego se desreferencia, no los he visto usar ninguna variable notable que pueda optimizarse.

Descargo de responsabilidad: no soy un experto en MSP430.

Sugiero el uso de

ADC12_A_disableConversions()

después

ADC12_A_setupSamplingTimer() 

Extracto deMSP430 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 muestreo/retención elegida durante la inicialización fue ADC12OSC, la conversión se inicia inmediatamente; de ​​lo contrario, la fuente de señal de muestreo/retención elegida inicia la conversión con un flanco ascendente de la señal. Al seleccionar los modos de conversión, tenga en cuenta que para los modos secuenciados y/o repetidos, para que el proceso de muestra/mantener y convertir continúe sin un disparador de la fuente de señal de muestra/mantenimiento, las muestras múltiples deben habilitarse usando el ADC12_A_setupSamplingTimer( ) función. Tenga en cuenta que después de llamar a esta función, ADC12_A_disableConversions()debe llamarse para reinicializar el ADC, reconfigurar un control de búfer de memoria, habilitar/deshabilitar el temporizador de muestreo o cambiar el voltaje de referencia interno.

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


Referencias:

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

GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

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

GPIO_setAsPeripheralModuleFunctionIntputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

Pero como se ve en la descripción de las funciones del pin (gracias @CL.) Queda claro que configurar el pin en la función periférica será suficiente y se ignorará la dirección. Por lo tanto, es engañoso, pero no 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 realiza una conversión de un solo canal, no debería importar (es solo un poco más claro). Y probablemente cambie ADC12IFG0y ADC12IE0a ADC12_A_IFG0y ADC12_A_IE0(pero solo se definen para 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 una fuente para futuros errores.

Entonces, desde la perspectiva del firmware, solo tengo pequeños detalles.

Basado en los comentarios, y leyendo la hoja de erratas , me hace preguntarme si una sola __no_operation();después __bic_SR_register_on_exit(LPM0_bits);de la ISR resolvería el problema. La fe de erratas no menciona explícitamente el caso presente aquí, pero hay problemas relacionados con la configuración de modos de bajo consumo, la salida de modos de bajo consumo y la corrupción del 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, 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 tiene que borrar el indicador de interrupción del ADC, ya que eso 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, simplemente lea el valor en su variable global y deje el modo de bajo consumo al salir. Haga todas las demás cosas en su aplicación principal. Hay casos en los que necesitará una latencia de interrupción lo más corta posible y si hace cosas dentro del ISR bloqueará otras interrupciones (excepto que habilite interrupciones anidadas, pero esas también son malas).

Como muestra la tabla de la página siguiente, basta con configurar el pin para la función del módulo (P6SEL.0 = 1); la dirección no importa.
Gracias por los consejos, @Arsenal, creo que he reducido el síntoma, pero no estoy seguro de cuál es la causa. Parece que solo lee el ADC una vez directamente después del reinicio
@Arsenal, ahora sé que el problema tiene que ver con los retrasos y las funciones intrínsecas, pero no sé lo suficiente sobre las funciones intrínsecas para solucionarlo.
@Aaron Cambié mi respuesta, tal vez ayude un poco, por diversión, también agregué algunas pautas generales para los ISR.
@Arsenal gracias, lo he investigado. Todavía estoy probando cosas nuevas y tengo un gran avance si quieres ver mi OP actualizado
@Aaron gracias por la actualización. Lo investigaré, en una primera vista parece que tendré que sumergirme en la biblioteca de TI y ver qué están haciendo.
@Aaron He mirado el código de la biblioteca periférica y no puedo encontrar algo que obviamente esté mal. Algunas cosas que hacen no son necesarias para un nuevo comienzo en la conversión, pero no debería impedir que funcione. Tal vez estoy demasiado cansado ahora. Lo único que realmente se destaca es que no toca el registro MCTL, lo que hace la biblioteca de controladores.
@Aaron Me doy por vencido, este problema me vuelve loco. Comencé una recompensa, tal vez alguien venga y lo resuelva. Si tiene noticias, actualice la publicación, si tiene una solución, publíquela como respuesta.