This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Capacitive Touch Library (Capsense) crashing on some gate times / trouble with LPM3 in combination with Capio on MSP430FR5989

Other Parts Discussed in Thread: MSP430FR5989

Hello everyone,

I'm currently working with the capacitive touch library on an MSP430FR5989. So far I got everything to work (with some help of this forum) but there is one thing left that's bugging me:

If I use SMCLK as clock source for the gate timer (in my case TA0) everything works as expected, and i can pick any number of accumulation cycles and any clock divider. But if I try to use ACLK, I have to pick incredible high numbers of accumulation cycles in order to make it work. way higher than I actually want. If there are too few cycles the MSP will simply reset, putting 0x000A in SYSRSTIV, somewhere between entering LPM3 and leaving it again in the RO_PINOSC_HAL() function in CTS_HAL.c .

Additional info that might help solve this puzzle:

-ACLK is sourced by an external crystal, running at 32.768kHz.

-SMCLK is sourced by the DCO, running at 16MHz

-I am using ACLK and LPM3 to make the main loop run once a second, so LPM3 with ACLK works with Capio disabled.

-The resetting occurs with and without JTAG connection.

-The minimum number of accumulation cycles that works is 20000. Or 5000 with a timer predivider of 4, so not the number, but the actual time matters.

I  really want to use the LPM3 during measurement, as I need the power consumption to be as low as possible.

Any help would be greatly appreciated.

Best Regards,

Andreas

  • Hi Andreas,


    I'll try to reproduce this on my end and get back to you shortly.

    Regards,
    Walter

  • Andreas,

    Which HAL implementation are you using? Can you share your structure.c and structure.h files, as well as your clock configuration?

    Thanks,
    Walter
  • Hello Walter,

    I used a custom HAL implementation, as the regular ones are not compatible to the FR5989.  Also enclosed are all the other parts of the code, neccessary to reproduce the Error.


     By now I found a workaround for my project: I figured  If timer B works with ACLK I could try to use it. So I edited the HAL once again, and using TB0 instead of TA0 apparently works. By using this workaround I can go on with the project.

    Yet I still want to find out what was causing this problem, and whether it is me using the clock/timer-system in some wrong way, or if it's an actual bug. I'll let you know if I find any new clues.

    Best Regards,

    Andreas Vetter

    HAL:

    #ifdef RO_PINOSC_TA0_TA2
    /*!
     *  ======== TI_CTS_RO_PINOSC_TA0_TA1_HAL ========
     *  @brief   RO method capacitance measurement using PinOsc IO, TimerA0, and
     *           TimerA1
     *
     *  \n       Schematic Description:
     *
     *  \n       element-----+->Px.y
     *
     *  \n       The TimerA1 interval represents the gate (measurement) time.  The
     *           number of oscillations that have accumulated in TA0R during the
     *           measurement time represents the capacitance of the element.
     *
     *  @param group  pointer to the sensor to be measured
     *  @param counts pointer to where the measurements are to be written
     *  @return  none
     */
    void TI_CTS_RO_PINOSC_TA0_TA2_HAL(const struct Sensor *group,uint16_t *counts)
    {
        uint8_t i;
        /*!
         *  Allocate Context Save Variables
         *  Status Register: GIE bit only
         *  TIMERA0: TA2CTL, TA2CCTL0, TA2CCR0
         *  TIMERA1: TA0CTL, TA0CCTL0, TA0CCR0
         *  Ports: PxSEL, PxSEL2
         */
        uint8_t contextSaveSR;
        uint16_t contextSaveTA2CTL,contextSaveTA2CCTL0,contextSaveTA2CCR0;
        uint16_t contextSaveTA0CTL,contextSaveTA0CCTL0,contextSaveTA0CCR0;
        //uint8_t contextSaveSel,contextSaveSel2;	// Auf den MSP430FR58xx/59xx nicht mehr benötigt.
        /*
         *  Perform context save of registers used except port registers which are
         *  saved and restored within the for loop as each element within the
         *  sensor is measured.
         */
        contextSaveSR = __get_SR_register();
        contextSaveTA2CTL = TA2CTL;
        contextSaveTA2CCTL0 = TA2CCTL0;
        contextSaveTA2CCR0 = TA2CCR0;
        contextSaveTA0CTL = TA0CTL;
        contextSaveTA0CCTL0 = TA0CCTL0;
        contextSaveTA0CCR0 = TA0CCR0;
        /*
         *  TimerA2 is the measurement timer and counts the number of relaxation
         *  oscillation cycles of the electrode which is routed to INCLK.  TA2 is
         *  in continuous mode and sourced from INCLK.
         */
        TA2CTL = TASSEL_3+MC_2;
        TA2CCTL0 = CM_3+CCIS_2+CAP;            // Setup for SW capture
        /*
         *  TimerA0 is the gate (measurement interval) timer.  The number of
         *  oscillations counted within the gate interval represents the measured
         *  capacitance.
         */
        TA0CCR0 = (group->accumulationCycles);
        // Establish source and scale of timerA0, but halt the timer.
        TA0CTL = (group->measGateSource) + (group->sourceScale);
        // Der Timer TA0 wird vorerst von Hand konfiguriert bis alles so funktioniert wie es soll.
        // TA0CTL = TASSEL__SMCLK + ID__1 + MC__STOP;	// SMCLK verwenden, durch 8 teilen, angehalten, Interrupts AUS
    
        TA0CCTL0 = CCIE;  // Enable Interrupt when timer counts to TA0CCR0.
    
        for (i = 0; i<(group->numElements); i++)
        {
            // Context Save Port Registers
            /*contextSaveSel = *((group->arrayPtr[i])->inputPxselRegister);
            contextSaveSel2 = *((group->arrayPtr[i])->inputPxsel2Register);
            // Configure Ports for relaxation oscillator
            *((group->arrayPtr[i])->inputPxselRegister)
            		&= ~((group->arrayPtr[i])->inputBits);
            *((group->arrayPtr[i])->inputPxsel2Register)
            		|= ((group->arrayPtr[i])->inputBits);*/   // Dieser Code-Block ist bei den neuen MSP430FR58xx/59xx nicht mehr nötig. Er wird durch die folgende Zeile ersetzt:
            CAPTIO0CTL =  ( ( 1 << 8 ) + ( ((group->arrayPtr[i])->portNumber) << 4 ) + ( ((group->arrayPtr[i])->pinNumber) << 1 ) );  // Für MSP430FR58xx/59xx notwendige Anpassung
            TA2CTL |= TACLR;
            TA2CTL &= ~TAIFG;
            TA0CTL |= (TACLR + MC_1 + TAIE);
            /*!
    		 *  The measGateSource represents the gate source for timer TIMERA0,
    		 *  which can be sourced from TACLK, ACLK, SMCLK, or INCLK.  The
    		 *  interrupt handler is defined in TIMER1_A2_VECTOR, which simply
    		 *  clears the low power mode bits in the Status Register before
    		 *  returning from the ISR.
    		 */
            if(group->measGateSource == TIMER_ACLK)
            {
                __bis_SR_register(LPM3_bits+GIE);  // Enable GIE and wait for ISR
            }
            else
            {
                __bis_SR_register(LPM0_bits+GIE);  // Enable GIE and wait for ISR
            }
            TA2CCTL0 ^= CCIS0;  // Create SW capture of TA2CCR into TA2CCR0.
            TA0CTL &= ~MC_1;    // Halt Timer
            if(TA2CTL & TAIFG)
            {
            	/*
    			 *  If a rollover in the timer has occurred then set counts to
    			 *  0.  This will prevent erroneous data from entering the baseline
    			 *  tracking algorithm.
    			 */
    			counts[i] = 0;
            }
            else
            {
                counts[i] = TA2CCR0;  // Save result
            }
            // Context Restore Port Registers
            /**((group->arrayPtr[i])->inputPxselRegister) = contextSaveSel;
            *((group->arrayPtr[i])->inputPxsel2Register) = contextSaveSel2; */ // Ebenfalls nicht mehr nötig, siehe oben.
            CAPTIO0CTL = 0; // Stattdessen wird hiermit der Pin in seinen Ausgangszustand zurückversetzt.
        } // End for Loop
        /*
         *  Context restore GIE within Status Register and all timer registers
         *  used.
         */
        if(!(contextSaveSR & GIE))
        {
            __bic_SR_register(GIE);
        }
        TA2CTL = contextSaveTA2CTL;
        TA2CCTL0 = contextSaveTA2CCTL0;
        TA2CCR0 = contextSaveTA2CCR0;
        TA0CTL = contextSaveTA0CTL;
        TA0CCTL0 = contextSaveTA0CCTL0;
        TA0CCR0 = contextSaveTA0CCR0;
    }
    #endif

    structure.c :

    #include "structure.h"
    
    const struct Element testElement1 = {
    
                   .inputPxselRegister = (unsigned char *)&P5SEL0,
                   .inputPxsel2Register = (unsigned char *)&P5SEL1,
                   .portNumber = 5,
                   .pinNumber = 0,
                   .inputBits = BIT0,
                   .maxResponse = 300,
                   .threshold = 25
    };
    
    const struct Element testElement2 = {
    
                   .inputPxselRegister = (unsigned char *)&P5SEL0,
                   .inputPxsel2Register = (unsigned char *)&P5SEL1,
                   .portNumber = 5,
                   .pinNumber = 1,
                   .inputBits = BIT1,
                   .maxResponse = 300,
                   .threshold = 25
    };
    
    const struct Element testElement3 = {
    
                  .inputPxselRegister = (unsigned char *)&P5SEL0,
                  .inputPxsel2Register = (unsigned char *)&P5SEL1,
                  .portNumber = 5,
                  .pinNumber = 2,
                  .inputBits = BIT2,
                  .maxResponse = 300,
                  .threshold = 25
    };
    
    const struct Element testElement4 = {
    
                  .inputPxselRegister = (unsigned char *)&P2SEL0,
                  .inputPxsel2Register = (unsigned char *)&P2SEL1,
                  .portNumber = 2,
                  .pinNumber = 7,
                  .inputBits = BIT7,
                  .maxResponse = 300,
                  .threshold = 25
    };
    
    const struct Element testElement5 = {
    
                  .inputPxselRegister = (unsigned char *)&P2SEL0,
                  .inputPxsel2Register = (unsigned char *)&P2SEL1,
                  .portNumber = 2,
                  .pinNumber = 6,
                  .inputBits = BIT6,
                  .maxResponse = 300,
                  .threshold = 25
    };
    
    
    const struct Element testElement6 = {
    
                  .inputPxselRegister = (unsigned char *)&P9SEL0,
                  .inputPxsel2Register = (unsigned char *)&P9SEL1,
                  .portNumber = 9,
                  .pinNumber = 7,
                  .inputBits = BIT7,
                  .maxResponse = 300,
                  .threshold = 25
    };
    /*
    const struct Element testElement6 = {
    
                  .inputPxselRegister = (unsigned char *)&P2SEL0,
                  .inputPxsel2Register = (unsigned char *)&P2SEL1,
                  .portNumber = 2,
                  .pinNumber = 5,
                  .inputBits = BIT5,
                  .maxResponse = 300,
                  .threshold = 25
    };
    
    const struct Element testElement7 = {
    
                  .inputPxselRegister = (unsigned char *)&P2SEL0,
                  .inputPxsel2Register = (unsigned char *)&P2SEL1,
                  .portNumber = 2,
                  .pinNumber = 4,
                  .inputBits = BIT4,
                  .maxResponse = 300,
                  .threshold = 25
    };
    
    const struct Element testElement8 = {
    
                  .inputPxselRegister = (unsigned char *)&P1SEL0,
                  .inputPxsel2Register = (unsigned char *)&P1SEL1,
                  .portNumber = 1,
                  .pinNumber = 7,
                  .inputBits = BIT7,
                  .maxResponse = 300,
                  .threshold = 25
    };
    */
    
    //*** Sensor   *******************************************************/
    // This defines the grouping of sensors, the method to measure change in
    // capacitance, and the function of the group
    
    
    const struct Sensor buttonSammlung =
    {
      .halDefinition = RO_PINOSC_TA0_TA2,
      .numElements = TOTAL_NUMBER_OF_ELEMENTS,     //total number of elements that make up the wheel
      .baseOffset = 0,      //is a cumulative count of the number of elements defined
      	  	  	  	  	    //in this application.  Button1 has baseOffset = 0, Button2 has baseOffset = 1
      // Pointer to elements
      .arrayPtr[0] = &testElement1,  // point to first element
      .arrayPtr[1] = &testElement2,  // point to first element
      .arrayPtr[2] = &testElement3,  // point to first element
      .arrayPtr[3] = &testElement4,  // point to first element
      .arrayPtr[4] = &testElement5,  // point to first element
      .arrayPtr[5] = &testElement6,  // point to first element
      //.arrayPtr[5] = &testElement6,  // point to first element
      //.arrayPtr[6] = &testElement7,  // point to first element
      //.arrayPtr[7] = &testElement8,  // point to first element
    
      // Timer Information
      .measGateSource		= TIMER_ACLK,			// Auswahl: TIMER_SMCLK, TIMER_ACLK, TIMER_INCLK, TIMER_TxCLK
      .sourceScale			= TIMER_SOURCE_DIV_0,	// Auswahl: TIMER_SOURCE_DIV_0...3 -> Clock wird durch 1, 2, 4 oder 8 geteilt
      .accumulationCycles	= 100					// Bedeutung: Anzahl der Zyklen welche der Gate-Timer läuft während die Perioden des RO gezählt werden
      // Alle diese drei Parameter beeinflussen die Gate-Time, anhand der Wahl für measGateSource entscheidet sich ob während der Messung LPM0 (SMCLK) oder LPM3 (ACLK) gewählt wird.
    
      //.points = 24,
      //.sensorThreshold = 1
    };

    structure.h

    #ifndef CTS_STRUCTURE
    #define CTS_STRUCTURE
    
    //******************************************************************************
    // The following elements need to be configured by the user.
    //******************************************************************************
    
    #include "msp430.h"
    #include <stdint.h>
    
    /* Public Globals */
    extern const struct Element testElement1;
    extern const struct Element testElement2;
    extern const struct Element testElement3;
    extern const struct Element testElement4;
    extern const struct Element testElement5;
    extern const struct Element testElement6;
    extern const struct Element testElement7;
    extern const struct Element testElement8;
    
    extern const struct Sensor buttonSammlung;
    
    //****** RAM ALLOCATION ********************************************************
    // TOTAL_NUMBER_OF_ELEMENTS represents the total number of elements used, even if 
    // they are going to be segmented into seperate groups.  This defines the 
    // RAM allocation for the baseline tracking.  If only the TI_CAPT_Raw function
    // is used, then this definition should be removed to conserve RAM space.
    #define TOTAL_NUMBER_OF_ELEMENTS 6
    // If the RAM_FOR_FLASH definition is removed, then the appropriate HEAP size 
    // must be allocated. 2 bytes * MAXIMUM_NUMBER_OF_ELEMENTS_PER_SENSOR + 2 bytes
    // of overhead.
    #define RAM_FOR_FLASH
    //****** Structure Array Definition ********************************************
    // This defines the array size in the sensor strucure.  In the event that 
    // RAM_FOR_FLASH is defined, then this also defines the amount of RAM space
    // allocated (global variable) for computations.
    #define MAXIMUM_NUMBER_OF_ELEMENTS_PER_SENSOR  8
    //****** Choosing a  Measurement Method ****************************************
    // These variables are references to the definitions found in structure.c and
    // must be generated per the application.
    // possible values for the method field
    
    // OSCILLATOR DEFINITIONS
    //#define RO_COMPAp_TA0_WDTp  		64
    //#define RO_PINOSC_TA0_WDTp  		65
    //#define RO_PINOSC_TA0       		66
    //#define RO_COMPAp_TA1_WDTp  		67
    //#define RO_COMPB_TA0_WDTA			68
    //#define RO_COMPB_TA1_WDTA         69
    //#define RO_PINOSC_TA0_TA1			70
    #define RO_PINOSC_TA0_TA2			71
    
    // RC DEFINITIONS
    //#define RC_PAIR_TA0       		01
             
    // FAST RO DEFINITIONS
    //#define fRO_PINOSC_TA0_SW           25
    //#define fRO_COMPB_TA0_SW            26
    //#define fRO_COMPB_TA1_SW            27
    //#define fRO_COMPAp_TA0_SW            28
    //#define fRO_COMPAp_SW_TA0            29
    //#define fRO_COMPAp_TA1_SW            30
    
    //****** WHEEL and SLIDER ******************************************************
    // Are wheel or slider representations used?
    //#define WHEEL
    #define ILLEGAL_SLIDER_WHEEL_POSITION		0xFFFF
    //#define WHEEL
    
    //******************************************************************************
    // End of user configuration section.
    //******************************************************************************
    //******************************************************************************
    //******************************************************************************
    
    //possible timer source clock dividers, different from clock module dividers
    #define TIMER_TxCLK 	0x0000       
    #define TIMER_ACLK  	0x0100
    #define TIMER_SMCLK 	0x0200
    #define TIMER_INCLK 	0x0300
    
    #define TIMER_SOURCE_DIV_0 0x0000  // ID_0, IDX_0
    #define TIMER_SOURCE_DIV_1 0x0040
    #define TIMER_SOURCE_DIV_2 0x0080
    #define TIMER_SOURCE_DIV_3 0x00C0
    
    #define GATE_WDT_ACLK      0x0004
    #define GATE_WDT_SMCLK     0x0000
    #define GATE_WDTp_ACLK     0x0004
    #define GATE_WDTp_SMCLK    0x0000
    
    #define WDTp_GATE_32768    0x0000  // watchdog source/32768
    #define WDTp_GATE_8192     0x0001  // watchdog source/8192
    #define WDTp_GATE_512      0x0002  // watchdog source/512
    #define WDTp_GATE_64       0x0003  // watchdog source/64
    
    #define GATE_WDTA_SMCLK     0x0000
    #define GATE_WDTA_ACLK      0x0020
    #define GATE_WDTA_VLO       0x0040
    #define GATE_WDTA_XCLK      0x0060
    
    #define WDTA_GATE_2G       0x0000  // watchdog source/2G
    #define WDTA_GATE_128M     0x0001  // watchdog source/128M
    #define WDTA_GATE_8192K    0x0002  // watchdog source/8192K
    #define WDTA_GATE_512K     0x0003  // watchdog source/512K
    #define WDTA_GATE_32768    0x0004  // watchdog source/32768
    #define WDTA_GATE_8192     0x0005  // watchdog source/8192
    #define WDTA_GATE_512      0x0006  // watchdog source/512
    #define WDTA_GATE_64       0x0007  // watchdog source/64
    
    // The below variables are used to excluded portions of code not needed by
    // the method chosen by the user. Uncomment the type used prior to compilation.
    // Multiple types can be chosen as needed.
    // What Method(s) are used in this application?
    
    #ifdef RO_COMPAp_TA0_WDTp
        #define RO_TYPE
        #define RO_COMPAp_TYPE
        #define WDT_GATE
        #define HAL_DEFINITION
        //what devices have Pxsel2 ??
        // msp430f2112, 2122, 2132
        // msp430G2112, G2212, G2312, G2412, G2152, G2252, G2352, G2452
        // SEL2REGISTER
        #ifdef __MSP430F2112
          #define SEL2REGISTER
        #endif 
        #ifdef __MSP430F2122
          #define SEL2REGISTER
        #endif 
        #ifdef __MSP430F2132
          #define SEL2REGISTER
        #endif 
        #ifdef __MSP430G2112
          #define SEL2REGISTER
        #endif
        #ifdef __MSP430G2212
          #define SEL2REGISTER
        #endif      
        #ifdef __MSP430G2312
          #define SEL2REGISTER
        #endif  
        #ifdef __MSP430G2412
          #define SEL2REGISTER
        #endif  
        #ifdef __MSP430G2152
          #define SEL2REGISTER
        #endif 
        #ifdef __MSP430G2252
          #define SEL2REGISTER
        #endif 
        #ifdef __MSP430G2352
          #define SEL2REGISTER
        #endif 
        #ifdef __MSP430G2452
          #define SEL2REGISTER
        #endif 
    #endif
    
    #ifdef RO_PINOSC_TA0_WDTp
        #define RO_TYPE
        #define RO_PINOSC_TYPE
        #define WDT_GATE
        #define HAL_DEFINITION
    #endif
    
    #ifdef RO_PINOSC_TA0
        #define RO_TYPE
        #define RO_PINOSC_TYPE
        #define ACCUMULATE_TYPE
        #define HAL_DEFINITION
    #endif
    
    #ifdef RO_PINOSC_TA0_TA1
        #define RO_TYPE
        #define RO_PINOSC_TYPE
        #define ACCUMULATE_TYPE
        #define HAL_DEFINITION
    #endif
    
    #ifdef RO_PINOSC_TA0_TA2
        #define RO_TYPE
        #define RO_PINOSC_TYPE
        #define ACCUMULATE_TYPE
        #define HAL_DEFINITION
    #endif
    
    #ifdef RO_COMPAp_TA1_WDTp
        #define RO_TYPE
        #define RO_COMPAp_TYPE
        #define WDT_GATE
        #define HAL_DEFINITION
    #endif
    
    #ifdef RO_COMPB_TA0_WDTA
        #define RO_TYPE
        #define RO_COMPB_TYPE
        #define WDT_GATE
        #define HAL_DEFINITION
    #endif
    
    #ifdef RO_COMPB_TA1_WDTA
        #define RO_TYPE
        #define RO_COMPB_TYPE
        #define WDT_GATE
        #define HAL_DEFINITION
    #endif
    
    #ifdef RC_PAIR_TA0
        #define RC_TYPE
        #define RC_PAIR_TYPE
        #define ACCUMULATE_TYPE
        #define HAL_DEFINITION
    #endif
    
    #ifdef fRO_PINOSC_TA0_SW
    	#define RO_TYPE
        #define RO_PINOSC_TYPE
    	#define HAL_DEFINITION
    #endif
    
    #ifdef fRO_COMPB_TA0_SW
        #define RO_TYPE
        #define RO_COMPB_TYPE
    	#define HAL_DEFINITION
    #endif
    
    #ifdef fRO_COMPB_TA1_SW
        #define RO_TYPE
        #define RO_COMPB_TYPE
    	#define HAL_DEFINITION
    #endif
    
    #ifdef fRO_COMPAp_TA0_SW
        #define RO_TYPE
        #define RO_COMPAp_TYPE
    	#define HAL_DEFINITION
    #endif
    
    #ifdef fRO_COMPAp_TA1_SW
        #define RO_TYPE
        #define RO_COMPAp_TYPE
        #define HAL_DEFINITION
    #endif
    
    #ifdef fRO_COMPAp_SW_TA0
        #define RO_TYPE
        #define RO_COMPAp_TYPE
        #define HAL_DEFINITION
    #endif
    
    #ifdef SLIDER
    	#define SLIDER_WHEEL
    #endif
    
    #ifdef WHEEL
    	#define SLIDER_WHEEL
    #endif
    
    #define RO_MASK         0xC0        // 1100 0000
    #define RC_FRO_MASK     0x3F        // 0011 1111
    
    //******************************************************************************
    // The sensor structure identifies port or comparator input definitions for each
    // sensor.
    //******************************************************************************
    struct Element{
    
    #ifdef RO_PINOSC_TYPE
    // These register address definitions are needed for each sensor only
    // when using the PinOsc method
      uint8_t *inputPxselRegister;    // PinOsc: port selection address
      uint8_t *inputPxsel2Register;   // PinOsc: port selection 2 address
      uint8_t portNumber;				// Diese Zwei sind nachträglich hinzugefügt um das ganze auf
      uint8_t pinNumber;				// dem FRAM MSP lauffähig zu machen.
    #endif
      
    #ifdef RC_PAIR_TYPE
    // these fields are specific to the RC type. 
      uint8_t *inputPxoutRegister;    // RC: port output address: PxOUT
      volatile uint8_t *inputPxinRegister;     // RC: port input address: PxIN
      uint8_t *inputPxdirRegister;    // RC+PinOsc: port direction address
      uint8_t *referencePxoutRegister;// RC: port output address: PxOUT
      uint8_t *referencePxdirRegister;// RC: port direction address: PxDIR           
      uint8_t referenceBits;           // RC: port bit definition
    #endif
     		     
      uint16_t inputBits;                 // Comp_RO+FastRO+RC+PinOsc: bit 
                                          // definition
                                          //
                                          // for comparator input bit 
                                          // location in CACTL2 or CBCTL0
                                          
      uint16_t threshold;                   // specific threshold for each button
      uint16_t maxResponse;                 // Special Case: Slider max counts
    };
    
    //******************************************************************************
    // The following structure definitons are application independent and are not
    // intended to be modified.
    //
    // The CT_handler 'groups' the sensor based upon function and capacitive 
    // measurement method.
    //******************************************************************************
    
    struct Sensor{
      // the method acts as the switch to determine which HAL is called
      uint8_t halDefinition;           // COMPARATOR_TYPE (RO), RC, etc
                                       // RO_COMPA, RO_COMPB, RO_PINOSC
                                       // RC_GPIO, RC_COMPA, RC_COMPB
                                       // FAST_SCAN_RO
                                              
      uint8_t numElements;             // number of elements within group
      uint8_t baseOffset;              // the offset within the global 
                                       // base_cnt array
    
      struct Element const *arrayPtr[MAXIMUM_NUMBER_OF_ELEMENTS_PER_SENSOR];    
                                       // an array of pointers
    
    //******************************************************************************
    // Reference structure definitions for comparator types, for the RC method the 
    // reference is defined within the element.
      
    #ifdef RO_COMPAp_TYPE
      uint8_t * refPxoutRegister;      // RO+FastRO: port output address
      uint8_t * refPxdirRegister;      // RO+FastRO: port direction address
      uint8_t refBits;                 // RO+FastRO: port bit definition
      
      uint8_t * txclkDirRegister;      // PxDIR 
      uint8_t * txclkSelRegister;      // PxSEL
      uint8_t txclkBits;               // Bit field for register
      
      uint8_t *caoutDirRegister;      // PxDIR
      uint8_t *caoutSelRegister;      // PxSEL
      uint8_t caoutBits;               // Bit field for register
      
      // This is only applicable to the RO_COMPAp_TYPE
    #ifdef SEL2REGISTER
      uint8_t *caoutSel2Register;
      uint8_t *txclkSel2Register;
    #endif
      
      uint8_t refCactl2Bits;          // RO: CACTL2 input definition, 
                                              // CA0 (P2CA0),CA1(P2CA4),
                                              // CA2(P2CA0+P2CA4)
      uint8_t capdBits;
    #endif 
    
    #ifdef RO_COMPB_TYPE
      uint8_t *cboutTAxDirRegister;  // CBOUT_TA0CLK 
      uint8_t *cboutTAxSelRegister;  // CBOUT_TA0CLK
      uint8_t cboutTAxBits;           // Bit field for register  
      uint16_t cbpdBits;
    #endif
    
    //*****************************************************************************
    // Timer definitions
    //  The basic premise is to count a number of clock cycles within a time
    //  period, where either the clock source or the timer period is a function
    //  of the element capacitance.
    // 
    // RC Method:
    //          Period: accumulationCycles * charge and discharge time of RC 
    //          circuit where C is capacitive touch element
    //
    //          clock source: measGateSource/sourceScale
    // RO Method:
    //          Period: accumulationCycles*measGateSource/sourceScale 
    //                  (with WDT sourceScale = 1, accumulationCycles is WDT control
    //                   register settings)
    //
    //          clock source: relaxation oscillator where freq is a function of C
    //
    // fRO Method:
    //          Period: accumulationCycles * 1/freq, freq is a function of C
    //
    //          clock source: measGateSource/sourceScale
         
      uint16_t measGateSource;         // RC+FastRO: measurement timer source,
                                       // {ACLK, TACLK, SMCLK}
                                       // Comp_RO+PinOsc: gate timer source, 
                                       // {ACLK, TACLK, SMCLK} 
      uint16_t sourceScale;            // Comp_RO+FastRO+PinOsc: gate timer,
                                       // TA/TB/TD, scale: 1,1/2,1/4,1/8
                                       // RC+FastRO: measurement timer, TA/TB/TD
                                       // scale: 16, 8, 4, 2, 1, ½, ¼, 1/8  
        
      uint16_t accumulationCycles;
    //*****************************************************************************
    // Other definitions
    
    #ifdef SLIDER_WHEEL  
      uint8_t points;                   // Special Case: Number of points
                                        // along slider or wheel  
      uint8_t sensorThreshold;
    #endif                               
    
    };
    
    //******************************************************************************
    // The scheduler structure manages each handler group (CT_Handler object) using
    // one timer resource.
    // TBD
    //******************************************************************************
    struct CT_scheduler{
      void *callBacks;                       
      // pointer to function in the main application (can be an array of functions 
      // if multiple groups). The order is important! The pointer here must point
      // to the first CT_Handler object!
      
      struct CT_Handler *handler;             // order of this and *call_backs 
                                              // must be the same.
      
      uint8_t Enable;                   // Each bit in this value will show
                                              // if the given group element
                                              // is being sheduled & measured.
      
      uint8_t delayTimer;              // delay timer, {SW,WDT, TimerA, 
                                              // TimerB, TimerD}
            
      uint8_t delayTimerSrc;          // delay timer source, 
                                              // {ACLK, TACLK, SMCLK}
            
      uint8_t delayTimerScale;        // delay time scale (/1,/2,/4,/8)
            
      uint8_t delayTime;               // wdt: delay {32768,8192,512,64}
     		                          // RO+FastRO+PinOsc(TimerA,B,D): 
                                              // delay time {257+x*256}
     		                        
    };
    
    #ifndef TOTAL_NUMBER_OF_ELEMENTS
     #warning "WARNING: TOTAL_NUMBER_OF_ELEMENTS is not defined in structure.h. Only TI_CAPT_RAW function is enabled."
    #endif
    
    #ifndef RAM_FOR_FLASH
     #warning "WARNING: The HEAP must be set appropriately.  Please refer to SLAA490 for details."
    #endif
    
    #ifndef HAL_DEFINITION
     #warning "WARNING: At least one HAL definition must be made in structure.h."
    #endif
    
    #endif

    ISRs :

    #pragma vector=TIMER0_B1_VECTOR
    __interrupt void TIMER0_B1_ISR(void)
    {
      switch(__even_in_range(TB0IV,TB0IV_TBIFG))
      {
        case TB0IV_NONE:    break;              // No interrupt
        case TB0IV_TB0CCR1: break;              // TB0CCR1 interrupt
        case TB0IV_TB0CCR2: break;              // TB0CCR2 interrupt
        case TB0IV_TB0CCR3: break;              // TB0CCR3 interrupt
        case TB0IV_TB0CCR4: break;              // TB0CCR4 interrupt
        case TB0IV_TB0CCR5: break;              // TB0CCR5 interrupt
        case TB0IV_TB0CCR6: break;              // TB0CCR6 interrupt
        case TB0IV_TB0IFG:                      // overflow
        {
        	timer_++;
        	//millisekunden += 1;
        	//if(millisekunden == 1000)
        	//{
        		millisekunden = 0;
        		LED_TOGGLE(4);
        		pseudoStatusReg |= (1<<0);
        		LPM3_EXIT;
        	//}
        	timeout_at_command_++;
        }
        break;
        default: break;
      }
    }
    
    
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void TIMER0_A0_ISR(void)
    {
      switch(__even_in_range(TA0IV,TA0IV_TAIFG))
      {
        case TA0IV_NONE:	break;              // No interrupt
        case TA0IV_TA0CCR1:	break;
        case TA0IV_TA0CCR2:	break;
        case TA0IV_3:		break;
        case TA0IV_4:		break;
        case TA0IV_5:		break;
        case TA0IV_6:		break;
        case TA0IV_TAIFG:						// TB0CCR1 interrupt
        {
        	LED_TOGGLE(1);
        	LPM3_EXIT;
        	break;
        }
        default:			break;
      }
    }

    timer config:

    void initSystemClock(void){
    	// Achtung! Bei Veränderungen hier, auch den Abschnitt "clock-selection" in system.h anpassen!
    	WDTCTL = ( WDTPW | WDTHOLD );	// Stop watchdog timer
    	// Clocks konfigurieren:
    	//CSCTL0_H = CSKEY >> 8;			// CSCTL entsperren
    	CSCTL0 = CSKEY;
    	CSCTL1 = 0x0048;				// F_DCO = 16MHz	// F_DCO sollte nicht auf 24 MHz gestellt werden, da sonnst MCLK über einen
    														// Prescaler heruntergesetzt werden muss. Die CPU kann MAXIMAL 16MHz !!!
    														// Um keine waitstates (Warten auf den FRAM) aktivieren zu müssen sollte die
    														// Frequenz maximal 8MHz betragen. Die Peripherie darf schneller sein.
    	CSCTL2 = 0x0033;				// SMCLK_SRC = DCO; MCLK_SRC = DCO; ACLK = LFXT (wenn vorhanden, sonst VLO)
    	CSCTL3 = 0x0001;				// Taktquellen für ACLK durch 1 , für SMCLK durch 1 und für MCLK durch 2 teilen.
    									// => ACLK = 32,768kHz , MCLK = 8MHz , SMCLK = 16MHz
    	//Quarz wird in initSystemPorts() gestartet.
    	CSCTL0_H = 0;					// CSCTL wieder sperren.
    }
    
    
    
    // This is the working Timer, it uses ACLK to repeat the measurements periodically:
    
    void initTimerB(void)
    { 
    	TB0CCR0 = 16384;			// (ACLK/1) / (34-1) ~ 993 => ca alle 1,007ms wird der Interrupt ausgelöst.
    	TB0CTL  = 0x0112;		// 8 Bit Zähler, ACLK/1 , hochzählen (aktiviert), Interrupts aktiviert
    	//TB0CTL 	= 0x1112;	// 16 Bit Zähler, ACLK/1, hochzählen (aktiviert), Interrupts aktiviert
    }
    

  • Hello Walter,

    I kept looking for the mess up with the timers, and tried to create a minimal working example of the error. Doing this I discovered something for which I have no explanation. It basically looks like a missed interrupt. I'm not sure if it's this is causing my reset problem. I'll enclose the complete source code. At the bottom of it are my thoughts on what it should do, and the results I actually got.

    Best Regards,

    Andreas Vetter

    0218.main.c
    #include <msp430.h> // includes msp430fr5989.h
    
    #define XT1_PORT_DIR	PJDIR
    #define XT1_PORT_SEL0	PJSEL0
    #define XT1_IN_MASK     BIT4
    #define XT1_OUT_MASK    BIT5
    
    #define LED1_OUT		P4OUT
    #define LED2_OUT		P4OUT
    #define LED1			BIT2
    #define LED2			BIT1
    
    // These two ISRs should catch any Timer A0 interrupt.
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void TIMER0_A0_ISR(void)
    {						// TA0 CCR0 interrupt
        	LED1_OUT ^= LED1;
        	_BIC_SR_IRQ(LPM3_bits);
    }
    
    #pragma vector=TIMER0_A1_VECTOR
    
    __interrupt void TIMER0_A1_ISR(void)
    {
      switch(__even_in_range(TA0IV,TA0IV_TAIFG))
      {
        case 0x00:	break;	// no interrupt pending
        case 0x02:	break;	// TA0 CCR1 interrupt
        case 0x04:	break;	// TA0 CCR2 interrupt
        case 0x06:	break;	// TA0 CCR3 interrupt
        case 0x08:	break;	// TA0 CCR4 interrupt
        case 0x0A:	break;	// TA0 CCR5 interrupt
        case 0x0C:	break;	// TA0 CCR6 interrupt
        case 0x0E:			// TA0 overflow interrupt
        {
        	LED2_OUT ^= LED2;
        	_BIC_SR_IRQ(LPM3_bits);
        	break;
        }
        default:			break;
      }
    }
    
    
    int main(void) {
    
    	WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    
    	XT1_PORT_DIR |= ( XT1_IN_MASK | XT1_OUT_MASK );	// enable XTAL1
    	XT1_PORT_SEL0 |= ( XT1_IN_MASK | XT1_OUT_MASK );
    	P4DIR |= ( LED1 | LED2 );	// enable LEDs
    	PM5CTL0 &= ~LOCKLPM5;
    
    	TA0IV = 0x00;
    	TA0IV = 0x00;
    
    // ** Clock: *********************************************************************************************************************
    	CSCTL0 = CSKEY;
    	CSCTL1 = 0x0048;				// F_DCO = 16MHz
    	CSCTL2 = 0x0033;				// SMCLK_SRC = DCO; MCLK_SRC = DCO; ACLK = LFXT
    	CSCTL3 = 0x0001;				// Divide Sources for ACLK by 1 , for SMCLK by 1 und f�r MCLK durch 2 teilen.
    									// => ACLK = 32,768kHz , MCLK = 8MHz , SMCLK = 16MHz
    	CSCTL0_H = 0;					// lock CSCTL
    
    // ** Timer: *********************************************************************************************************************
    #define USE_ACLK
    
    #ifdef USE_ACLK
    	TA0CCR0 = 10000;
    	TA0CTL = 0x01C0;	// Use ACLK as timer source, divide by 8
    						// TA0CTL: SMCLK -> |= 0x0200; ACLK -> |= 0x0100;  Divider :  1 -> |= 0x000; 2 -> |= 0x0040; 4 -> |= 0x0080; 8 -> |= 0x00C0
    #endif
    #ifdef USE_SMCLK
    	TA0CCR0 = 000;
    	TA0CTL = 0x02C0;	// Use SMCLK as Timer Source, divide by 8
    #endif
    	TA0CCTL0 = CCIE;	// Enable Interrupt when timer counts to TA0CCR0.
    // *******************************************************************************************************************************
    
    
    // *******************************************************************************************************************************
    // **** MAIN LOOP ****************************************************************************************************************
    	while(1)
    	{
            TA0CTL |= (TACLR + MC_1 + TAIE);	// Reset and start the Timer;
    #ifdef USE_ACLK
            __bis_SR_register(LPM0_bits+GIE);	// This could be LPM3, but everything is supposed to be exactly the same, to allow for comparison.
    #endif
    #ifdef USE_SMCLK
            __bis_SR_register(LPM0_bits+GIE);
    #endif
    	}
    // *** END OF MAIN LOOP **********************************************************************************************************
    // *******************************************************************************************************************************
    
    	return 0;
    }
    
    /* 	What should happen?
     * 		The timer should count up to the value stored in TA0CCR0 and then set the TA0CCR0 CCIFG interrupt flag. On the next cycle of the TA0 clock source TA0R should be reset, and TA0IFG (overflow)
     * 		should be set. So basically two interrupts with one clock delay between them -> both LEDs should blink. Given the SMCLK frequency of 16MHz, the timer predivider of 8, and the TA0CCR0 value
     * 		of 10000 the interrupt frequency is expected to be 200Hz. With a ACLK frequency of 32768kHz the interrupt frequency should be about 0.41Hz .
     *
     * 		With a timer frequency of 2MHz one cycle should be 0.5�s. According to datasheet LPM0 wakeup-time is 0.4�s + (1.5/f_DCO)
     * 		which gives in this case a wakeup-time of 0.5�s. As this wakeup-time is specified for a operating voltage of at leas 2.2V the actual value might be greater as I am using 1.8V.
     * 		Therefore the delay between the two toggles should be at least 1�s, possibly more.
     *
     * 	What does happen?
     * 		When using SMCLK both LEDs toggle with about 3�s delay between the two different LEDs. The toggle period is 5ms for both LEDs, which means the interrupts occur with a frequency of 200Hz.
     * 		This is just as expected.
     *
     * 		When using ACLK LED1 toggles with a frequecy below 1Hz as expected, LED2 does nothing.
     *
     */
    
    

  • In LPM0, there is no wakeup time. The DCO is running all the time. When an interrupt occurs, the CPU will execute it with the next DCO clock edge without any wakeup time. Wakeup time only applies if NOBODY is using the DCO anymore. That means not only the CPU but also SMCLK (if sourced by DCO) and any module using SMCLK. If the timer runs form SMCLK and SMCLK form DCO, even LPM3 or 4 won't stop the DCO, as the continued usage of SMCLK overrides this LPM (unconditional clock request)
    Only If the timer runs from REFO/VLO/XT, then entering LPM3 will stop the DCO and introduce wakeup time.

    In your code, if USE_SMCLK is define, you set TY0CCTL0=000; Apparently a typo?

    If running from SMCLK, the interrupt for TAIFG is triggered while you are still inside the CCR0.CCIFG ISR. That means, as soon as the first ISR exits, the second is started. Both LEDs toggle, with the execution time of the first ISR as delay (which is larger than the one timer tick between the interrupts).
    However, when running from ACLK, this timer tick equals ~5000 MCLK cycles. The CCR0.CCIFG ISR exits LPM. So on its return, the second interrupt hasn't yet triggered. So main execution continues. And resets the timer. The second interrupt can never come as the timer can never overflow - it is reset each timer by main before this happens.
    You're not missing an interrupt, the code flow is preventing this interrupt.

    As for your original code, i didn't analyze it (it's much too large to do so in the small gaps I have in my real work), but it is not unlikely that a similar mistake in the timeline of events causes your problems.
    I fin doubt, make a graph where you enter when something happens and how long it takes to be handled. Racing conditions are one of the main reasons for unexplainable behavior. (right after stack overflows)

**Attention** This is a public forum