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.

CCS/MSP-EXP430FR6989: Implementing Capactive Touch On FR6989

Part Number: MSP-EXP430FR6989
Other Parts Discussed in Thread: ENERGIA

Tool/software: Code Composer Studio

Hi,

I bought a MSP-EXP430FR6989 launch pad and wanted to implement a couple of capacitive touch buttons to control it. It was not my focus to do this so I did not go for one of the captivate boards. Now I find myself a bit lost. The controller has capacitive touch I/O peripherals but there are no examples for capacitive touch in the driver lib or the registry level. The MSP430-Ware Capacitive touch libraries don't support anything but captivate and the older capsense library does not support the 6xxx series. It seems that this controller has been left high and dry between the ending support for the old system and the support for the new system.

Can somebody provide me with an example project? I don't want much, just an example that will switch on an led if I touch a piece of foil connected to a pin. I can modify from there, I just need a place to start.

Thanks in advance

Peter

  • Hi Peter,

    As you have already determined, we are strongly recommending customers starting a new capacitive touch project to base their project on our CapTIvate portfolio of devices. All of our support and continued innovation will be based on that family of devices.

    There are no examples provided in MSPWare for the older capsense solution but you may be able to find old reference designs that implement capacitive touch using the previous capsense solution. One I can think of off the top of my head is the Bluetooth and MSP430 Audio Sink Reference Design (www.ti.com/.../BT-MSPAUDSINK-RD which integrates some cap-touch buttons right on the PCB. This E2E post ( e2e.ti.com/.../2513409 ) explains where you can find the source code and you may be able to use that as a starting point to port that functionality over to your specific device.

    Best regards,

    Matt
  • May I propose to add information like that somewhere in the launchpad descriptions? When I decided which one to buy I looked into which of them would have the capabilities I wanted. From the description the one I bought checked all the boxes and there was no way to see that it was already on the way out and had limited support.

    I generally find it very difficult to compare different launchpads in terms of capabilities, connections and processor power. An overview table and a list of recommended applications would be of great help.

    As to your recommendations, the board you are proposing uses a different type of peripheral. The schematics show external pullup resistors. The FR6989 datasheet description reads: "All P1 to P10 and PJ Pins Support Capacitive Touch Capability Without Need for External Components" and the peripheral module description explains how "The module uses the integrated pullup and pulldown resistors and an external capacitor to form an oscillator". I read about the different types of capacitive touch technologies and remember that some of them need external components and some of them do not. The type of capacitive touch I/O interface used for the FR6989 is the type that does not.
  • I found another thread on the forums referring to code examples for a controller that uses the same type of Capacitive I/O sensing, the FR4133. There are actual code examples for that controller (labelled PINOSC in MSP430 Ware). The only necessary change was to change the used timer since the FR6989 has no connection between the Capacitive Touch I/O peripheral and Timer A0. I changed the timer to A2 and everything worked.

    The example in the attached file works with the launchpad. Just connect a wire of some kind to pin 1.4 and the LED should light up on wire touch. 

    #include <driverlib.h>
    #include "hal_LCD.h"
    
    /* Defines WDT SMCLK interval for sensor measurements*/
    #define WDT_meas_setting (DIV_SMCLK_512)
    /* Defines WDT ACLK interval for delay between measurement cycles*/
    #define WDT_delay_setting (DIV_ACLK_512)
    
    /* Sensor settings*/
    #define KEY_LVL     220                     // Defines threshold for a key press
    /*Set to ~ half the max delta expected*/
    
    /* Definitions for use with the WDT settings*/
    #define DIV_ACLK_32768  (WDT_ADLY_1000)     // ACLK/32768
    #define DIV_ACLK_8192   (WDT_ADLY_250)      // ACLK/8192
    #define DIV_ACLK_512    (WDT_ADLY_16)       // ACLK/512
    #define DIV_ACLK_64     (WDT_ADLY_1_9)      // ACLK/64
    #define DIV_SMCLK_32768 (WDT_MDLY_32)       // SMCLK/32768
    #define DIV_SMCLK_8192  (WDT_MDLY_8)        // SMCLK/8192
    #define DIV_SMCLK_512   (WDT_MDLY_0_5)      // SMCLK/512
    #define DIV_SMCLK_64    (WDT_MDLY_0_064)    // SMCLK/64
    
    #define LED   (0x01)                        // P1.0 LED output
    
    // Global variables for sensing
    unsigned int base_cnt, meas_cnt;
    int delta_cnt;
    char key_pressed;
    /* System Routines*/
    void measure_count(void);                   // Measures each capacitive sensor
    void pulse_LED(void);                       // LED gradient routine
    
    int main( void )
    {
    
        Init_LCD();
    
        unsigned int i,j;
        WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
        PM5CTL0 &= ~LOCKLPM5;
    
        SFRIE1 |= WDTIE;                          // enable WDT interrupt
        P1DIR |= LED;                             // P1.0 = LED
        P1OUT = 0x00;
    
        __bis_SR_register(GIE);                   // Enable interrupts
    
        measure_count();                          // Establish baseline capacitance
        base_cnt = meas_cnt;
    
        for(i=15; i>0; i--)                       // Repeat and avg base measurement
        {
            measure_count();
            base_cnt = (meas_cnt+base_cnt)/2;
        }
    
        /* Main loop starts here*/
        while (1)
        {
    
            j = KEY_LVL;
            key_pressed = 0;                        // Assume no keys are pressed
    
            measure_count();                        // Measure all sensors
    
            delta_cnt = base_cnt - meas_cnt;  // Calculate delta: c_change
    
            /* Handle baseline measurment for a base C decrease*/
            if (delta_cnt < 0)                    // If negative: result increased
            {                                     // beyond baseline, i.e. cap dec
                base_cnt = (base_cnt+meas_cnt) >> 1; // Re-average quickly
                delta_cnt = 0;                    // Zero out for pos determination
            }
            if (delta_cnt > j)                    // Determine if each key is pressed
            {                                     // per a preset threshold
                j = delta_cnt;
                key_pressed = 1;                    // key pressed
            }
            else
                key_pressed = 0;
    
            /* Delay to next sample */
            WDTCTL = WDT_delay_setting;             // WDT, ACLK, interval timer
    
            /* Handle baseline measurment for a base C increase*/
            if (!key_pressed)                       // Only adjust baseline down
            {                                       // if no keys are touched
                base_cnt = base_cnt - 1;        // Adjust baseline down, should be
            }                                       // slow to accomodate for genuine
            pulse_LED();                           // changes in sensor C
    
            __bis_SR_register(LPM3_bits);
        }
    }                                           // End Main
    
    /* Measure count result (capacitance) of each sensor*/
    /* Routine setup for four sensors, not dependent on NUM_SEN value!*/
    
    void measure_count(void)
    {
        TA2CTL = TASSEL_3 + MC_2;                   // TACLK, cont mode
        TA2CCTL1 = CM_3 + CCIS_2 + CAP;             // Pos&Neg,GND,Cap
    
        /*Configure Ports for relaxation oscillator*/
        CAPSIO0CTL |= CAPTIOEN + CAPSIOPOSEL0 + CAPSIOPISEL2; //P1.1
    
        /*Setup Gate Timer*/
        WDTCTL = WDT_meas_setting;              // WDT, ACLK, interval timer
        TA2CTL |= TACLR;                        // Clear Timer_A TAR
        __bis_SR_register(LPM0_bits+GIE);       // Wait for WDT interrupt
        TA2CCTL1 ^= CCIS0;                      // Create SW capture of CCR1
        meas_cnt = TA2CCR1;                      // Save result
        WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer
        CAPSIO0CTL = 0;
    }
    
    void pulse_LED(void)
    {
        if(key_pressed)
        {
            P1OUT ^= LED;
        }
        else
        {
            P1OUT &= ~LED;
        }
    }
    /* Watchdog Timer interrupt service routine*/
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=WDT_VECTOR
    __interrupt void watchdog_timer(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(WDT_VECTOR))) watchdog_timer (void)
    #else
    #error Compiler not supported!
    #endif
    {
        TA2CCTL1 ^= CCIS0;                        // Create SW capture of CCR1
        __bic_SR_register_on_exit(LPM3_bits);     // Exit LPM3 on reti
    }
    

  • Last update from me. While the earlier uploaded main file worked I found it a little bit difficult to understand. It contained two timers, a dozen different timer frequencies and settings and transitioned through 3 different low power mode. For idiots like me who use µCs in a "I wish TI would have a lovechild with Arduino that had all the TI processing power and the simpler Arduino interface" kind of way I stripped all of the complex stuff out (I know about Energia...it has the Arduino problem of limited access and configurations of peripherals. If I can't set frequency, phase and dutycycle of a PWM I am not interested. If you are also an idiot, like me, look into the Birchia SW libraries for the C2000 to see the perfect harmony between simplicity and power. Sadly they cost a lot of money and the license needs to be renewed annually). The program is now objectively worse. It uses way too much processing power, way too much actual power and could basically not do anything else because it uses run time and is on full power during the delays...but it is simple and easy to understand.

    #include <driverlib.h>
    
    /* Sensor settings*/
    #define KEY_LVL     220                     // Defines threshold for a key press
    /*Set to ~ half the max delta expected*/
    
    #define LED   (0x01)                        // P1.0 LED output
    
    // Global variables for sensing
    unsigned int base_cnt, meas_cnt;
    int delta_cnt;
    char key_pressed;
    /* System Routines*/
    void measure_count(void);                   // Measures each capacitive sensor
    void pulse_LED(void);                       // LED gradient routine
    
    volatile uint32_t n;
    
    int main( void )
    {
    
        unsigned int i,j;
        WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
        PM5CTL0 &= ~LOCKLPM5;
    
        P1DIR |= LED;                             // P1.0 = LED
        P1OUT = 0x00;
    
        measure_count();                          // Establish baseline capacitance
        base_cnt = meas_cnt;
    
        for(i=15; i>0; i--)                       // Repeat and avg base measurement
        {
            measure_count();
            base_cnt = (meas_cnt+base_cnt)/2;
        }
    
        /* Main loop starts here*/
        while (1)
        {
    
            j = KEY_LVL;
            key_pressed = 0;                        // Assume no keys are pressed
    
            measure_count();                        // Measure all sensors
    
            delta_cnt = base_cnt - meas_cnt;  // Calculate delta: c_change
    
            /* Handle baseline measurment for a base C decrease*/
            if (delta_cnt < 0)                    // If negative: result increased
            {                                     // beyond baseline, i.e. cap dec
                base_cnt = (base_cnt+meas_cnt) >> 1; // Re-average quickly
                delta_cnt = 0;                    // Zero out for pos determination
            }
            if (delta_cnt > j)                    // Determine if each key is pressed
            {                                     // per a preset threshold
                j = delta_cnt;
                key_pressed = 1;                    // key pressed
            }
            else
                key_pressed = 0;
    
            /* Handle baseline measurment for a base C increase*/
            if (!key_pressed)                       // Only adjust baseline down
            {                                       // if no keys are touched
                base_cnt = base_cnt - 1;        // Adjust baseline down, should be
            }                                       // slow to accomodate for genuine
            pulse_LED();                           // changes in sensor C
    
        }
    }                                           // End Main
    
    /* Measure count result (capacitance) of each sensor*/
    /* Routine setup for four sensors, not dependent on NUM_SEN value!*/
    
    void measure_count(void)
    {
        TA2CTL = TASSEL_3 + MC_2;               // TACLK, cont mode, TASSEL_3 ties the Timer clock to the output of the capacitive Touch IO oscilator
        TA2CCTL1 = CM_3 + CCIS_2 + CAP;         // Pos&Neg,GND,Cap
    
        /*Configure Ports for relaxation oscillator*/
        CAPSIO0CTL |= CAPTIOEN + CAPSIOPOSEL0 + CAPSIOPISEL2; //P1.4
    
        for(n=1; n>0; n--);
    
        TA2CCTL1 ^= CCIS0;                      // Create SW capture of CCR1, this is an arbitraty thing, just provides a starting point for the counter
    
        TA2CTL |= TACLR;                        // Clear Timer_A TAR
    
        for(n=50; n>0; n--);                    // Set a defined time interval for the counter. This is better than through a timer and interrupt to allow leaving of active mode and/or free up CPU for other tasks
    
        TA2CCTL1 ^= CCIS0;                      // Create SW capture of CCR1, this ends the counter
        meas_cnt = TA2CCR1;                     // Save result, at this point the register contains the number of oscillation cycles of the capacitive touch oscillator
    
        CAPSIO0CTL = 0;                         // Switch off oscillator
    }
    
    void pulse_LED(void)
    {
        if(key_pressed)
        {
            P1OUT ^= LED;
        }
        else
        {
            P1OUT &= ~LED;
        }
    }
    
     

    The way the capacitive touch I/O works is by changing the input clock of the timer to the resonating pin of the capacitive touch. It basically turns the sensor into a (really bad) oscillator. Then a second timer (or in my case a delay) provides a fixed time window. The timer runs in capture mode but all it captures are two SW signals (Start and End at the start and end of the measuring window). The relevant thing is the number of oscillations between those two SW signals. More capacitance means slower oscillation frequency and thus less steps of the timer. It is a little bit confusing because you would expect the timer in capture-mode to actually capture the sensor signal but it doesn't. It only captures SW triggers. 

**Attention** This is a public forum