Das MSP430-Programm funktioniert nur im Debug-Modus

Ich versuche, die Werte vom ADC auf meinem MSP430F5529 abzurufen und sie über USB an meinen Computer zu senden, aber ich fange klein an. Alles, was ich gerade habe, ist etwas, das den ADC-Wert abruft und in ADCResults speichert. Wenn der gelesene Wert über der Hälfte von Vcc liegt, leuchtet eine LED auf.

Ich habe Pin 6.0 an einen Kraftsensor angeschlossen, damit ich sehen kann, wie er sich ein- und ausschaltet, wenn ich meinen Finger darauf lege oder loslasse.

Das Programm funktioniert perfekt, wenn ich es im Debug-Modus ausführe, aber wenn ich versuche, es außerhalb des Debug-Modus auszuführen (nur das Board vom Computer aus mit Strom zu versorgen, nachdem der Code darauf heruntergeladen wurde), passiert nichts, wenn ich meinen Finger auf den Kraftsensor lege.

Was extrem seltsam ist, wenn ich Reset gedrückt halte, während ich meinen Finger auf den Kraftsensor lege (wenn ich meinen Finger auflege, schaltet sich die LED ein) und die Reset-Taste loslassen, bleibt die LED an, bis ich mit meinem Finger wieder auf Reset drücke. Es scheint also, dass das Zurücksetzen ein Problem verursacht, aber ich bin mir nicht sicher, wie.

Zuerst dachte ich, Reset würde konstant hoch gezogen (oder niedrig, was auch immer das Gerät zurücksetzt), aber das kann nicht wahr sein, denn dann sollte das Programm funktionieren, wenn ich Reset gedrückt halte, aber das tut es nicht!

Hier ist mein Code:

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

AKTUALISIEREN

Ich habe versucht, die gleiche Funktionalität zu erstellen, ohne die Peripherietreiberbibliothek zu verwenden, und es scheint perfekt außerhalb des Debuggers zu funktionieren. Dies lässt mich glauben, dass etwas mit der Peripheral Driver Library von Texas Instruments nicht stimmt.

Hier ist der Code, der außerhalb des Debuggers gut zu funktionieren schien und die Peripheral Driver Library nicht verwendet.

#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; 
  }
}
Machst du das auf einem LaunchPad oder einem anderen TI-Entwicklungsboard? Oder ist das etwas, das Sie entworfen haben?
Ich bin mit MSP430s nicht vertraut genug, um sicher zu sein, aber: Könnte es sein, dass das WDT durch ein Konfigurationsbit zwangsweise aktiviert wird? Einige uC erlauben es Ihnen, den WDT zu erzwingen, der vom DBGU-Modul überschrieben werden kann. Dasselbe gilt für jeden anderen (Schutz-) Interrupt. Wenn ich besser vertraut wäre, würde ich Ihren Code überprüfen, aber Interrupts sind eine sehr häufige Quelle für diese Art von Verhalten. (Genau wie der Divisionsüberlauf-Interrupt: Wird auf vielen Geräten im Debug-Modus nicht ausgelöst, wird aber erzwungen, wenn er sich nicht im Debug-Modus befindet).
@DigitalNinja Ja, ich bin auf einem Launchpad, dem MSP430F5529 Launchpad
@Asmyldof Ich bin mir nicht sicher, ob das WDT es tut, der Code deaktiviert das WDT eindeutig, aber ich bin immer noch ein Neuling, also habe ich keine Ahnung.
@Aaron Warten Sie am besten auf jemanden mit mehr Erfahrung, aber die meisten MCUs, mit denen ich gearbeitet habe, ermöglichen das Setzen eines speziellen Bits durch das Programmiergerät, das das WDT einschaltet, sodass die Software, die es ausschaltet, keine Wirkung hat. Aber es kann auch etwas ganz anderes sein, dachte nur, ich stecke meine 2ct hinein, bis unweigerlich ein Guru vorbeikommt.
@Aaron Die Art und Weise, wie Sie den Vorgang mit der Reset-Taste beschrieben haben, lässt es so klingen, als würde er einfach nur zurückgesetzt gehalten. Sie bringen es aus dem Reset heraus, es sieht Ihre Eingabe und kehrt dann zum Reset zurück, wenn Sie den Knopfdruck entfernen. Durch erneutes Drücken wird es wieder herausgeholt und die LED neu initialisiert. Normalerweise übernimmt der Debugger das Zurücksetzen für Sie, da er die Reset-Leitung zum Programmieren verwendet. Hast du deine Jumperkonfiguration nochmal überprüft? Es gibt einen Jumper zum Zurücksetzen, der mit (RST) gekennzeichnet ist.
@Aaron Außerdem habe ich auch ein LaunchPad, das ich nur einmal verwendet habe, aber kein Problem hatte, das Programm außerhalb des Debuggers auszuführen. Ich habe einen anderen MSP430 mit dieser Leitung verwendet WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer, um den Watchdog zu stoppen.
@Aaron, normalerweise möchten Sie den ADC vor der Messung beruhigen lassen. Ich habe nichts mit ADC auf MSP430 zu tun. Aber ich habe wenig Arbeit an einem ARM Cortex-M4 geleistet, ich habe den ADC beruhigen lassen, bevor ich die Messung erfasst habe. Aber ich behaupte nicht, ein Experte zu sein. Ich schlage vor, 7ff nur zum Debuggen auf einen niedrigeren Wert zu ändern.
Der MSP430 funktioniert nicht so @Asmyldof
@ DigitalNinja OPs auf dem F5529-Launchpad und Verwendung der msp430-Treiberbibliothek. Der WDT_A_hold ist eine Funktion, die dasselbe tut wie das direkte Modifizieren des WDTCTL
OP dieser Link Analog-Digital-Konverter könnte Ihnen helfen.
Ich glaube nicht, dass der Reset gehalten wird, weil andere Programme außerhalb des Debuggers gut funktionieren, wie eine einfache Taste, die das LED-Programm steuert (Drucktaste lässt die LED aufleuchten), funktioniert außerhalb des Debuggers gut
Für die ADC12_A_clearInterrupt()und ADC12_A_enableInterrupt()verwenden Sie nicht die Symbole, die Sie laut Dokumentation verwenden sollten, aber das spielt eigentlich keine Rolle.
Kannst du eine Verzögerung und ein unbedingtes Blinken der anderen LED in die Hauptschleife einbauen, um zu sehen, ob sie überhaupt läuft?
Ja, lassen Sie mich das gleich ausprobieren und sehen, ob es in die Hauptrolle kommt, ich werde mich bald wieder melden
@CL. es geht in die Hauptleitung, lass mich sehen, ob es irgendwo stehen bleibt
@CL. Es kommt überall in main vor, von der ersten Zeile nach WDTHold bis in die While-Schleife, bis hin zu sogar nach __no_operation() in der While-Schleife, es scheint jeden Punkt im Main-Outside-Debug-Modus zu erreichen.
@CL. Ich habe gerade getestet, ob es in die ISR gelangt, indem ich die grüne LED (die ich in diesem Programm nicht verwende, direkt nach dem ADC12_A_getResultsAufruf einschalte. Ich schalte sie ein, egal was passiert (was bedeutet, dass sie nicht Teil der if-Anweisung ist). und es schaltet sich gut ein.Ich weiß also, dass es zumindest die ISR auslöst
@CL. Es sieht also so aus, als ob der einzige Punkt im Programm, in den es nicht zu gelangen scheint, wenn es nicht debuggt, die if-Anweisung ist, aber es kommt dort an, wenn ich debugge. Wenn das Problem nicht darin besteht, viele Samples zu nehmen, wenn Sie sich nicht im Debug-Modus befinden (was bedeutet, dass es nur einmal in die if-Anweisung gelangt), würde es dieses seltsame Reset-Verhalten erklären, wenn es nur einmal in die if-Anweisung gelangt, wo es abhängig vom Status direkt funktioniert wann Reset wird aufgehoben.
@Aaron Ich bin mir nicht sicher, was diese Zeile __bis_SR_register(LPM0_bits + GIE);tut. Müssen Sie den Interrupt jedoch nicht löschen, bevor Sie eine weitere Konvertierung starten? Rufen Sie wie in auf, ADC12_A_clearInterrupt(ADC12_A_BASE,ADC12IFG0);nachdem die Konvertierung abgeschlossen ist. Vielleicht liest es den ADC deshalb nur einmal direkt nach dem Zurücksetzen.
@DigitalNinja Ich weiß auch nicht __bis_SR_register(LPM0_bits + GIE)genau, was es tut, da es bereits im Beispielcode enthalten war, aber ich glaube, es setzt die MCU in den Energiesparmodus und ermöglicht Interrupts, sie aus dem Energiesparmodus zu nehmen. Interessanterweise gelangt der Code außerhalb des Debug-Modus in die ISR. Ich teste dies, indem ich bei jedem Eintritt in die ISR eine LED umschalte und einige Verzögerungszyklen einsetze, damit ich sie tatsächlich blinken sehen kann. Dadurch funktioniert das gesamte Programm korrekt!
@DigitalNinja Es scheint also, dass das Erstellen einer Verzögerung das Programm außerhalb des Compilers gut funktionieren lässt. Was sagt uns das darüber, warum es nicht normal funktioniert? Warum benötige ich eine Verzögerung? alles, was __delay_cycles tut, ist ein Haufen NOPs richtig? Nun, was passiert während dieser NOPs, die dazu führen, dass das Programm richtig funktioniert?
@DigitalNinja Ich habe einen gewissen Durchbruch erzielt. Ich habe festgestellt, dass das gesamte Programm einwandfrei funktioniert, wenn Sie + GIEdas Argument des Anrufs angeben, __bic_SR_register_on_exitder direkt vor dem Beenden der ISR aufgerufen wird! Ich weiß nur nicht, was diese Funktionen tun
@Aaron Gute Arbeit. Ich gehe davon aus , dass GIEglobale Interrupts aktiviert sind. Es scheint also, als würden Interrupts ohne das + GIEin dieser Zeile ( __bic_SR_register_on_exit) deaktiviert. Das Hinzufügen aktiviert Interrupts und daher erhalten Sie den nächsten ADC-Interrupt, wenn Sie wieder in die Hauptschleife eintreten.
@DigitalNinja Bitte korrigieren Sie mich, wenn ich falsch liege, aber ich bin immer noch verwirrt, weil + GIEdas Programm auch ohne funktionierte, solange ich eine Verzögerung in die ISR einfügte
@Aaron Ja, ich dachte nur, dass, obwohl das + GIEnicht in dieser Zeile in der ISR steht, es in der Hauptschleife ( __bis_SR_register(LPM0_bits + GIE)) aufgerufen und globale Interrupts wieder aktiviert würde, wenn sie deaktiviert worden wären. Also, es ist wirklich nur die Verzögerung, die es behoben hat, wie Sie gerade gesagt haben. Wo haben Sie die Verzögerung im ISR eingetragen und wie lang ist die Verzögerung?
@Aaron Ein weiterer Gedanke ist, interessiert dich der Energiesparmodus? Wenn nicht, würde ich sagen, entfernen Sie einfach diese beiden Zeilen, die die Low-Power-Bits setzen, und das Problem könnte verschwinden.
@DigitalNinja Ich weiß nicht, was Sie damit meinen, dass main den globalen Interrupt wieder aktiviert, selbst wenn main die __bis_SR_register(LPM0_bits + GIE)Leitung anrief, nachdem die ISR zurückgekehrt war und somit den GIE eingestellt hatte. Warum sollte die Verzögerung dazu führen, dass main sie erneut aktiviert, aber keine Verzögerung verursacht main, um es nicht wieder zu aktivieren. Die Verzögerung befand sich direkt vor der if(ADCResults >= 0x7ff)Anweisung im ISR
@DigitalNinja Der Energiesparmodus ist mir wichtig, nicht weil ich ihn speziell für diese Anwendung brauche, sondern weil ich ein Anfänger bin und die Erfahrung machen möchte, mit dem Energiesparmodus zu arbeiten. Schließlich handelt es sich um eine angemessene Programmierpraxis für eingebettetes Design
Das Löschen des GIE-Bits würde alle weiteren Interrupts deaktivieren . Und der ADC-Interrupt wird bereits durch das Lesen des ADC12IVRegisters gelöscht.
@CL. Ich glaube nicht, dass ich ganz verstehe, was Sie sagen. Warum ermöglicht die Verzögerung innerhalb der ISR der Hauptschleife, das GIE-Bit erneut zu bestätigen?
@Aaron Dieser Kommentarthread wird wirklich lang ... Ich meinte nur, dass diese Zeile __bis_SR_register(LPM0_bits + GIE)globale Interrupts in Ihrer Hauptschleife ermöglicht, unabhängig von der Verzögerung oder der anderen Zeile in der ISR. Ich weiß nicht, warum eine Verzögerung es behebt. Ich denke nicht, dass du es brauchen solltest. Es passiert also etwas anderes, vielleicht mit der ADC-Konfiguration. Haben Sie in den TI-Foren nach Hilfe gesucht oder Ihren Code so geändert, dass er genau einem Beispiel entspricht?
Haben Sie Änderungen gegenüber dem Beispielprogramm von TI vorgenommen?
@Aaron Versuchen Sie, diesen Parameter ADC12_A_CYCLEHOLD_64_CYCLESin ADC12_A_setupSamplingTimerzu ändern, ADC12_A_CYCLEHOLD_4_CYCLESund nehmen Sie Ihren Verzögerungscode heraus.
@DigitalNinja Ich stimme zu, dass dieser Kommentar riesig ist, aber ich möchte nur wissen, warum dieses seltsame Verhalten auftritt. Ich kann nicht herausfinden, warum die Verzögerung das Problem behebt.
@CL. Ja, ich habe einige Bibliotheken eingeschlossen, die das Beispiel nicht hat, aber ich verweise nie auf sie. Ich möchte ausdrücklich klarstellen, dass diese Bibliotheken nicht der Fall sind, weil ich NUR durch Laden des Beispielprojekts (ohne irgendetwas hinzugefügtes) überprüft habe und genau die gleichen Symptome auftreten, bis ich entweder die Verzögerung oder + GIEden ISR-Aufruf von hinzufüge __bic_SR_register_on_exit. Ich weiß also, dass die zusätzlichen Bibliotheken das Problem nicht verursachen, ich kann nur nicht herausfinden, warum die Verzögerung den gleichen Effekt hat wie das Hinzufügen+GIE
@DigitalNinja Das Ändern dieses Parameters führt dazu, dass die LED nicht einmal INNERHALB des Debuggers aufleuchtet, geschweige denn außerhalb. Ich weiß nicht genau, was dieser Parameter macht, aber es hilft nicht, weil das Programm jetzt nicht einmal im Debug-Modus funktioniert.
Du solltest im TI-Forum nachfragen .
@Aaron, es war nur eine wilde Vermutung. Tatsache ist, dass Sie dort keine Verzögerung benötigen sollten. Wenn Sie dies mit Hilfe von TI gelöst bekommen, kommen Sie bitte zurück und posten Sie die Antwort.
@DigitalNinja, wenn ich es herausfinde, werde ich definitiv die Antwort posten. Danke für die Unterstützung, mit eurer Hilfe habe ich die Symptome und möglichen Lösungen zumindest eingegrenzt
__bis_SR_register(LPM0_bits + GIE)setzt die Low-Power-Mode-0- und Global-Interrupt-Enable-Bits in das Spezialregister, das den Schlafmodus und globale Interrupts steuert. Die Verzögerung nach dem Einstellen des Interrupts und des Ruhezustands soll verhindern, dass Probleme im Ruhezustand stecken bleiben.

Antworten (3)

Manchmal liegt der Grund für ein solches Verhalten darin, dass die Optimierungseinstellungen im Debug-Modus anders sind und eine Variable, die der Compiler für unnötig hält, dann gleich optimiert wird.

Die Korrekturen dafür bestehen darin, "flüchtige" Qualifizierer zu solchen Variablen hinzuzufügen oder die Optimierung auszuschalten (oder zumindest abzusenken).

Ich weiß nicht, ob das Ihre Antwort ist (der Thread wurde TL;DR), aber dieser Leckerbissen sollte sicherlich als mögliche Lösung für die Suchmaschinen erscheinen.

volatileQualifier war im ersten Code dabei, also auch wenn oft ein Thema, in diesem Fall eher nicht
@Arsenal - das ist die Variable, die er sehen kann . Vielleicht ist in einer Bibliothek etwas vergraben, von dem er nichts weiß. Der erste Schritt für mich wäre, die Optimierung auszuschalten. Es dauert zehn Minuten zu lesen, um herauszufinden, wie man es macht, und dann weiß man es.
@ScottSeidman Danke für den Vorschlag, Optimierungen waren von Anfang an ausgeschaltet, ich arbeite so ziemlich immer mit ihnen, um zu beginnen
Die Bibliothek wirft jeden Zugriff auf die Hardware auf einen flüchtigen Zeiger, der dann dereferenziert wird. Ich habe nicht gesehen, dass sie eine nennenswerte Variable verwenden, die wegoptimiert werden könnte.

Haftungsausschluss: Ich bin kein Experte für MSP430.

Ich empfehle die Verwendung von

ADC12_A_disableConversions()

nach

ADC12_A_setupSamplingTimer() 

Ausschnitt ausMSP430 DriverLib for MSP430F5xx_6xx Devices


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

Diese Funktion aktiviert/startet den Konvertierungsprozess des ADC. Wenn die bei der Initialisierung gewählte Sample/Hold-Signalquelle ADC12OSC war, wird die Wandlung sofort gestartet, andernfalls startet die gewählte Sample/Hold-Signalquelle die Wandlung durch eine steigende Flanke des Signals. Denken Sie bei der Auswahl von Konvertierungsmodi daran, dass für sequenzierte und/oder wiederholte Modi mehrere Samples mit dem ADC12_A_setupSamplingTimer( ) Funktion. Beachten Sie, dass nach dem Aufruf dieser Funktion die ADC12_A_disableConversions()muss aufgerufen werden, um den ADC neu zu initialisieren, eine Speicherpuffersteuerung neu zu konfigurieren, den Abtastzeitgeber zu aktivieren/deaktivieren oder die interne Referenzspannung zu ändern.

Hinweis: Es gibt auch einige gute kostenlose Online-Kurse zum Erlernen des Designs eingebetteter Systeme. Einer von ihnen verwendet MSP430. Ich habe einige davon unten aufgeführt.


Verweise:

Ich frage mich, warum es im Debug-Modus funktioniert, es ist schon eine Weile her, seit ich mit MSP430 gearbeitet habe, und ich bin mit der Treiberbibliothek nicht vertraut. Aber:

GPIO_setAsPeripheralModuleFunctionOutputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

Sicherlich ist die Funktion, mit der Sie diesen Pin auf einen analogen Eingang umschalten möchten, nicht oder doch? Ich würde versuchen:

GPIO_setAsPeripheralModuleFunctionIntputPin(
        GPIO_PORT_P6,
        GPIO_PIN0
        );

Aber wie in der Beschreibung der Pin-Funktionen (Danke @CL.) zu sehen ist, wird klar, dass das Setzen des Pins auf die Peripheriefunktion tatsächlich ausreicht und die Richtung ignoriert wird. Es ist also nur irreführend, aber kein Deal Breaker.

Dann gibt es eine kleine Sache param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;, die wahrscheinlich sein sollte, param.endOfSequence = ADC12_A_ENDOFSEQUENCE;aber da Sie nur eine einzelne Kanalkonvertierung durchführen, sollte es keine Rolle spielen (es ist nur ein bisschen klarer). Und wahrscheinlich ändern ADC12IFG0und ADC12IE0zu ADC12_A_IFG0und ADC12_A_IE0(aber sie sind nur für die anderen Werte definiert, also kein funktionales Problem)

Und Ihnen fehlt break;in der Interrupt-Vektortabelle ein nach Ihrem Fall, aber das wird das Programm auch nicht sehr beeinflussen, sondern nur eine Quelle für zukünftige Fehler.

Aus Firmware-Sicht habe ich also nur kleinere Nitpicks.

Basierend auf den Kommentaren und dem Durchlesen des Errata-Blatts frage ich mich, ob eine Single __no_operation();nach dem __bic_SR_register_on_exit(LPM0_bits);in der ISR das Problem lösen würde. Die Errata erwähnt den hier vorliegenden Fall nicht explizit, aber es gibt Probleme beim Einstellen von Energiesparmodi, Verlassen von Energiesparmodi und Beschädigen des Programmzählers. Vielleicht ist es also ein anderer Fall. Diese Effekte sind während des Debuggens möglicherweise nicht vorhanden, da das Emulationsmodul die normale Ausführung des Kerns stört.

Aber Sie haben auch erwähnt, dass Ihr Programm auch funktioniert, wenn Sie die globale Interrupt-Freigabe löschen. Was mich zu der Annahme bringt, dass Ihr Programm in einem Interrupt hängen bleibt, aber nicht der ADC. Sie müssen das Interrupt-Flag des ADC nicht löschen, da dies automatisch beim Lesen des Speichers des ADC erfolgt.

Nur noch ein Hinweis zur Programmierung, ich würde die Analyse des ADC-Wertes aus dem ISR herausholen. Halten Sie sie so klein wie möglich, lesen Sie einfach den Wert in Ihre globale Variable ein und verlassen Sie den Energiesparmodus beim Beenden. Erledigen Sie alle anderen Dinge in Ihrer Hauptanwendung. Es gibt Fälle, in denen Sie eine möglichst kurze Interrupt-Latenz benötigen und wenn Sie Dinge innerhalb der ISR tun, blockieren Sie andere Interrupts (außer Sie aktivieren verschachtelte Interrupts, aber diese sind ebenfalls böse).

Wie die Tabelle auf der nächsten Seite zeigt, reicht es aus, den Pin für Modulfunktion (P6SEL.0 = 1) zu konfigurieren; die Richtung ist egal.
Danke für die Tipps, @Arsenal, ich glaube, ich habe das Symptom eingegrenzt, bin mir aber nicht sicher, was die Ursache ist. Es scheint, dass es den ADC nur einmal direkt nach dem Zurücksetzen liest
@Arsenal Ich weiß jetzt, dass das Problem mit Verzögerungen und intrinsischen Funktionen zu tun hat, aber ich weiß nicht genug über intrinsische Funktionen, um es zu beheben
@Aaron Ich habe meine Antwort geändert, vielleicht hilft es ein bisschen, zum Spaß habe ich auch einige allgemeine Richtlinien für ISRs hinzugefügt.
@Arsenal danke, ich habe es mir angesehen. Ich probiere immer noch neue Dinge aus und habe einen Durchbruch, wenn Sie mein aktualisiertes OP sehen möchten
@Aaron danke für das Update - ich werde es mir ansehen, auf den ersten Blick scheint es, als müsste ich in die TI-Bibliothek eintauchen und sehen, was sie tun.
@Aaron Ich habe mir den Code der Peripheriebibliothek angesehen und kann nichts finden, was offensichtlich falsch ist. Einige Dinge, die sie tun, werden für einen Neuanfang in der Konvertierung nicht benötigt, aber das sollte sie nicht davon abhalten, zu funktionieren. Vielleicht bin ich jetzt zu müde. Das Einzige, was wirklich auffällt, ist, dass Sie das MCTL-Register nicht berühren, was die Treiberbibliothek tut.
@Aaron Ich gebe irgendwie auf, dieses Problem macht mich verrückt. Ich habe ein Kopfgeld gestartet, vielleicht kommt jemand vorbei und löst es. Wenn Sie Neuigkeiten haben, aktualisieren Sie bitte den Beitrag, wenn Sie eine Lösung haben, posten Sie sie als Antwort.