|
|
- /*******************************************************************************
- *
- * CapTouchBoosterPack_UserExperience.c
- * - MSP430 firmware application to demonstrate the capacitive touch
- * capability of the MSP430G2452 interfacing with the LaunchPad CapTouch
- * BoosterPack.
- *
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of Texas Instruments Incorporated nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- ******************************************************************************/
-
- /******************************************************************************
- * MSP430G2-LaunchPad CapTouch BoosterPack User Experience
- *
- * This application operates on the LaunchPad platform using the MSP430G2452
- * device and the CapTouch BoosterPack plugin board. The capacitive touch and
- * proximity sensing are enabled by the pin oscillator feature new to the
- * MSP430G2xx2 family devices. The User Experience application also utilizes
- * the cap touch library to realize & measure the capacitive touch and proximity
- * sensors. The cap touch library also provides layers of abstractions to
- * generate higher logical outputs such as logical touches, geometry (in this
- * hardware, a four-button wheel), and even gestures.
- *
- * The User Experience application starts up and remains in 'sleep' mode,
- * sampling the proximity sensor every ~8.3ms [VLO/100=12kHz/100=120Hz]. Upon
- * registering a valid proximity event [hand/finger/object hovering ~3-5cm from
- * the BoosterPack], the application wakes up to operate in the 'active' mode.
- *
- * In active mode, the application samples and registers individual finger touches
- * on the 16-position wheel or the center button as well as simple gestures
- * [Clockwise & Counter-clockwise] while the finger moves along and remains on
- * the wheel.
- *
- * a 9600 baud UART link is also implemented using SW TimerA to provide
- * application and cap touch data back to the PC via the UART-USB back channel.
- * The application sends UART data upon events such as wake up, sleep, touch,
- * or gesture.
- *
- * D. Dang
- * Texas Instruments, Inc.
- * Ver 0.90 Feb 2011
- ******************************************************************************/
-
-
-
- #include "CTS_Layer.h"
- #include "uart.h"
-
-
- #define WAKE_UP_UART_CODE 0xBE
- #define WAKE_UP_UART_CODE2 0xEF
- #define SLEEP_MODE_UART_CODE 0xDE
- #define SLEEP_MODE_UART_CODE2 0xAD
- #define MIDDLE_BUTTON_CODE 0x80
- #define INVALID_GESTURE 0xFD
- #define GESTURE_START 0xFC
- #define GESTURE_STOP 0xFB
- #define COUNTER_CLOCKWISE 1
- #define CLOCKWISE 2
- #define GESTURE_POSITION_OFFSET 0x20
- #define WHEEL_POSITION_OFFSET 0x30
-
- #define WHEEL_TOUCH_DELAY 12 //Delay between re-sendings of touches
- #define MAX_IDLE_TIME 200
- #define PROXIMITY_THRESHOLD 60
-
- unsigned int wheel_position=ILLEGAL_SLIDER_WHEEL_POSITION, last_wheel_position=ILLEGAL_SLIDER_WHEEL_POSITION;
- unsigned int deltaCnts[1];
- unsigned int prox_raw_Cnts;
-
-
-
-
- /*----------------- LED definition---------------------------------------------
- * There are 8 LEDs to represent different positions around the wheel. They are
- * controlled by 5 pins of Port 1 using a muxing scheme. The LEDs are divided
- * vertically into two groups of 4, in which each LED is paired up [muxed] with
- * the LED mirrored on the other side of the imaginary center vertical line via
- * the use of pin P1.3 and one specific port pin.
- * Specifically, the pairs are LEDs [0,7], [1,6], [2,5], [3,4], as shown in the
- * diagram below.
- * LED Position (degrees, clockwise)
- * --RIGHT SIDE--
- * 0 BIT4,!BIT3 45
- * 1 BIT5,!BIT3 80
- * 2 BIT6,!BIT3 100
- * 3 BIT7,!BIT3 135 *
- *
- * --LEFT SIDE--
- * 4 BIT3,(BIT4,5,6) 225
- * 5 BIT3,(BIT4,5,7) 260
- * 6 BIT3,(BIT4,6,7) 280
- * 7 BIT3,(BIT5,6,7) 315
- *----------------------------------------------------------------------------*/
- #define MASK7 BIT4
- #define MASK6 BIT5
- #define MASK5 BIT6
- #define MASK4 BIT7
-
- #define MASK3 (BIT3+BIT4+BIT5+BIT6)
- #define MASK2 (BIT3+BIT4+BIT5+BIT7)
- #define MASK1 (BIT3+BIT4+BIT6+BIT7)
- #define MASK0 (BIT3+BIT5+BIT6+BIT7)
-
- const unsigned char LedWheelPosition[16] =
- {
- MASK0, MASK0, MASK0 & MASK1, MASK1,
- MASK1 & MASK2, MASK2, MASK2 & MASK3, MASK3,
- MASK4, MASK4, MASK4 | MASK5, MASK5,
- MASK5 | MASK6, MASK6, MASK6 | MASK7, MASK7
- };
- const unsigned char startSequence[8] =
- {
- MASK0,
- MASK1,
- MASK2,
- MASK3,
- MASK4,
- MASK5,
- MASK6,
- MASK7
- };
- /*----------------- LED definition------------------------------*/
-
-
- void InitLaunchPadCore(void)
-
- {
- BCSCTL1 |= DIVA_0; // ACLK/(0:1,1:2,2:4,3:8)
- BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO
-
- // Port init
- P1OUT &= ~(BIT3+BIT4+BIT5+BIT6+BIT7+BIT0);
- P1DIR |= BIT3+BIT4+BIT5+BIT6+BIT7+BIT0;
- P2SEL = 0x00; // No XTAL
- P2DIR |= (BIT0+BIT4+BIT2+BIT3+BIT1+BIT5);
- P2OUT &= ~(BIT0+BIT4+BIT2+BIT3+BIT1+BIT5);
- }
-
- void SendByte(unsigned char touch)
- {
- TimerA_UART_init();
- TimerA_UART_tx(touch);
- TimerA_UART_shutdown();
- }
-
- /* ----------------CapTouchIdleMode-----------------------------------------
- * Device stays in LPM3 'sleep' mode, only Proximity Sensor is used to detect
- * any movement triggering device wake up
- * ------------------------------------------------------------------------*/
- void CapTouchIdleMode(void)
- {
- /* Send status via UART: 'sleep' = [0xDE, 0xAD] */
- SendByte(SLEEP_MODE_UART_CODE);
- SendByte(SLEEP_MODE_UART_CODE2);
-
- /* Set DCO to 1MHz */
- /* Set SMCLK to 1MHz / 8 = 125kHz */
- BCSCTL1 = CALBC1_1MHZ;
- DCOCTL = CALDCO_1MHZ;
- BCSCTL2 |= DIVS_3;
-
- P1OUT |= BIT0; // Turn on center LED
- deltaCnts[0] = 0;
-
- /* Sleeping in LPM3 with ACLK/100 = 12Khz/100 = 120Hz wake up interval */
- /* Measure proximity sensor count upon wake up */
- /* Wake up if proximity deltaCnts > THRESHOLD */
- do
- {
- TACCR0 = 100;
- TACTL = TASSEL_1 + MC_1;
- TACCTL0 |= CCIE;
- __bis_SR_register(LPM3_bits+GIE);
- TACCTL0 &= ~CCIE;
- TI_CAPT_Custom(&proximity_sensor,deltaCnts);
- }
- while (deltaCnts[0] <= PROXIMITY_THRESHOLD);
-
- P1OUT &= ~BIT0; // Turn off center LED
- }
-
- /* ----------------MeasureCapBaseLine--------------------------------------
- * Re-measure the baseline capacitance of the wheel elements & the center
- * button. To be called after each wake up event.
- * ------------------------------------------------------------------------*/
- void MeasureCapBaseLine(void)
- {
- P1OUT = BIT0;
- /* Set DCO to 8MHz */
- /* SMCLK = 8MHz/8 = 1MHz */
- BCSCTL1 = CALBC1_8MHZ;
- DCOCTL = CALDCO_8MHZ;
- BCSCTL2 |= DIVS_3;
-
- TI_CAPT_Init_Baseline(&wheel);
- TI_CAPT_Update_Baseline(&wheel,2);
- TI_CAPT_Init_Baseline(&middle_button);
- TI_CAPT_Update_Baseline(&middle_button,2);
- }
-
- /* ----------------LedStartUpSequence--------------------------------------
- * Display an LED lighting sequence to indicate the wake up event
- * ------------------------------------------------------------------------*/
- void LedStartUpSequence(void)
- {
- unsigned char i;
- TACCTL0 = CCIE; // CCR0 interrupt enabled
- TACTL |= TACLR;
- TACCR0 = TAR + 500; // 50ms
- TACTL = TASSEL_1 + MC_1; // ACLK, upmode
-
- /* Slow clockwise sequence */
- for(i=0; i<8; i++)
- {
- P1OUT = startSequence[i];
- __bis_SR_register(LPM3_bits+GIE);
-
- __delay_cycles(1000000);
- TACCR0 = TAR + 500; // 50ms
- }
-
- P1OUT = BIT0;
- /* Fast counter-clockwise sequence */
- while(i)
- {
- i--;
- P1OUT = startSequence[i];
- __bis_SR_register(LPM3_bits+GIE);
- TACCR0 = TAR + 500; // 50ms
- }
- TACCTL0 &= ~CCIE; // CCR0 interrupt disabled
- P1OUT = 0; // Turn off all LEDs
- }
-
- /* ----------------GetGesture----------------------------------------------
- * Determine immediate gesture based on current & previous wheel position
- * ------------------------------------------------------------------------*/
- unsigned char GetGesture(unsigned char wheel_position)
- {
- unsigned char gesture = INVALID_GESTURE, direction, ccw_check, cw_check;
- // ******************************************************************************
- // gesturing
- // determine if a direction/swipe is occuring
- // the difference between the initial position and
- // the current wheel position should not exceed 8
- // 0-1-2-3-4-5-6-7-8-9-A-B-C-D-E-F-0...
- //
- // E-F-0-1-2: cw, 4
- // 2-1-0-F-E: ccw, 4
- // A-B-C-D-E-F
-
- //if(initial_wheel_position == INVALID_WHEEL_POSITION)
- //{
- //gesture = 0;
- //initial_wheel_position = wheel_position;
- //}
- //else
-
- if(last_wheel_position != ILLEGAL_SLIDER_WHEEL_POSITION)
- {
- if(last_wheel_position > wheel_position)
- {
- // E-D-C-B-A: ccw, 4
- // counter clockwise: 0 < (init_wheel_position - wheel_position) < 8
- // gesture = init_wheel_position - wheel_position
- //
- // E-F-0-1-2: cw, 4
- // clockwise: 0 < (init_wheel_position+wheel_position)-16 <8
- //
- ccw_check = last_wheel_position - wheel_position;
- if(ccw_check < 8)
- {
- gesture = ccw_check;
- direction = COUNTER_CLOCKWISE;
- }
- else
- {
- // E-F-0-1-2: cw, 4
- // 16 - 14 + 2 = 4
- cw_check = 16 - last_wheel_position + wheel_position ;
- if(cw_check < 8)
- {
- gesture = cw_check;
- direction = CLOCKWISE;
- }
- }
- }
- else
- {
- // initial_wheel_position <= wheel_position
- //
- // 2-1-0-F-E: ccw, 4
- // counter clockwise:
- // 0 < (init_wheel_position+wheel_position)-16 <8
- // gesture = init_wheel_position - wheel_position
- //
- // 0-1-2-3-4: cw, 4
- // clockwise: 0 < (wheel_position - init_wheel_position) < 8
- //
- cw_check = wheel_position - last_wheel_position ;
- if(cw_check < 8)
- {
- gesture = cw_check;
- direction = CLOCKWISE;
- }
- else
- {
- // 2-1-0-F-E: ccw, 4
- // 16 + 2 - 14 = 4
- ccw_check = 16 + last_wheel_position - wheel_position ;
- if(ccw_check < 8)
- {
- gesture = ccw_check;
- direction = COUNTER_CLOCKWISE;
- }
- }
- }
- }
- if (gesture == INVALID_GESTURE)
- return gesture;
- if (direction == COUNTER_CLOCKWISE)
- return (gesture + 16);
- else
- return gesture;
- }
-
- /* ----------------CapTouchActiveMode----------------------------------------------
- * Determine immediate gesture based on current & previous wheel position
- *
- *
- *
- *
- *
- *
- *
- * -------------------------------------------------------------------------------*/
- void CapTouchActiveMode()
- {
- unsigned char idleCounter, activeCounter;
- unsigned char gesture, gestureDetected;
- unsigned char centerButtonTouched = 0;
- unsigned int wheelTouchCounter = WHEEL_TOUCH_DELAY - 1;
-
-
- gesture = INVALID_GESTURE; // Wipes out gesture history
-
- /* Send status via UART: 'wake up' = [0xBE, 0xEF] */
- SendByte(WAKE_UP_UART_CODE);
- SendByte(WAKE_UP_UART_CODE2);
-
- idleCounter = 0;
- activeCounter = 0;
- gestureDetected = 0;
-
- while (idleCounter++ < MAX_IDLE_TIME)
- {
- /* Set DCO to 8MHz */
- /* SMCLK = 8MHz/8 = 1MHz */
- BCSCTL1 = CALBC1_8MHZ;
- DCOCTL = CALDCO_8MHZ;
- BCSCTL2 |= DIVS_3;
- TACCTL0 &= ~CCIE;
-
- wheel_position = ILLEGAL_SLIDER_WHEEL_POSITION;
- wheel_position = TI_CAPT_Wheel(&wheel);
-
- /* Process wheel touch/position/gesture if a wheel touch is registered*/
- /* Wheel processing has higher priority than center button*/
-
- if(wheel_position != ILLEGAL_SLIDER_WHEEL_POSITION)
- {
- centerButtonTouched = 0;
-
- /* Adjust wheel position based: rotate CCW by 2 positions */
- if (wheel_position < 0x08)
- {
- wheel_position += 0x40 - 0x08;
- }
- else
- {
- wheel_position -= 0x08;
- /* Adjust wheel position based: rotate CCW by 2 positions */
- }
-
- wheel_position = wheel_position >>2; // divide by four
-
- gesture = GetGesture(wheel_position);
-
- /* Add hysteresis to reduce toggling between wheel positions if no gesture
- * has been TRULY detected. */
-
- if ( (gestureDetected==0) && ((gesture<=1) || (gesture==0x11) || (gesture==0x10)))
- {
- if (last_wheel_position != ILLEGAL_SLIDER_WHEEL_POSITION)
- wheel_position = last_wheel_position;
- gesture = 0;
- }
-
- /* Turn on corresponding LED(s) */
- P1OUT = (P1OUT & BIT0) | LedWheelPosition[wheel_position];
-
-
- if ((gesture != 0) && (gesture != 16) && (gesture != INVALID_GESTURE))
- { /* A gesture has been detected */
-
- if (gestureDetected ==0)
- { /* Starting of a new gesture sequence */
- gestureDetected = 1;
-
- /* Transmit gesture start status update & position via UART to PC */
- SendByte(GESTURE_START);
- SendByte(last_wheel_position + GESTURE_POSITION_OFFSET);
- }
-
- /* Transmit gesture & position via UART to PC */
- SendByte(gesture);
- SendByte(wheel_position + GESTURE_POSITION_OFFSET);
- }
- else
- if (gestureDetected==0)
- { /* If no gesture was detected, this is constituted as a touch/tap */
- if (++wheelTouchCounter >= WHEEL_TOUCH_DELAY)
- {
- /* Transmit wheel position [twice] via UART to PC */
- wheelTouchCounter = 0;
- SendByte(wheel_position + WHEEL_POSITION_OFFSET );
- SendByte(wheel_position + WHEEL_POSITION_OFFSET );
- }
- }
- else
- wheelTouchCounter = WHEEL_TOUCH_DELAY - 1;
-
- idleCounter = 0; // Reset idle counter
- activeCounter++;
- last_wheel_position = wheel_position;
- }
- else
- { /* no wheel position was detected */
-
- if(TI_CAPT_Button(&middle_button))
- { /* Middle button was touched */
- if (centerButtonTouched==0)
- {
- /* Transmit center button code [twice] via UART to PC */
- SendByte(MIDDLE_BUTTON_CODE);
- SendByte(MIDDLE_BUTTON_CODE);
-
- centerButtonTouched = 1;
-
- P1OUT = (P1OUT&BIT0) ^ BIT0; // Toggle Center LED
- }
- idleCounter = 0;
- }
- else
- { /* No touch was registered at all [Not wheel or center button */
- centerButtonTouched = 0;
- P1OUT &= BIT0;
- if ( (gesture == INVALID_GESTURE) || (gestureDetected ==0))
- { /* No gesture was registered previously */
- if (last_wheel_position != ILLEGAL_SLIDER_WHEEL_POSITION)
- {
- /* Transmit last wheel position [twice] via UART to PC */
- SendByte(last_wheel_position + WHEEL_POSITION_OFFSET );
- SendByte(last_wheel_position + WHEEL_POSITION_OFFSET );
- wheelTouchCounter = WHEEL_TOUCH_DELAY - 1;
- }
- }
-
- if (gestureDetected == 1)
- { /* A gesture was registered previously */
-
- /* Transmit status update: stop gesture tracking [twice] via UART to PC */
- SendByte(GESTURE_STOP);
- SendByte(GESTURE_STOP);
- }
-
- }
-
- // Reset all touch conditions, turn off LEDs,
- last_wheel_position= ILLEGAL_SLIDER_WHEEL_POSITION;
- gesture = INVALID_GESTURE;
- gestureDetected = 0;
-
- }
-
- /* ------------------------------------------------------------------------
- * Option:
- * Add delay/sleep cycle here to reduce active duty cycle. This lowers power
- * consumption but sacrifices wheel responsiveness. Additional timing
- * refinement must be taken into consideration when interfacing with PC
- * applications GUI to retain proper communication protocol.
- * -----------------------------------------------------------------------*/
-
- }
- }
-
-
- void main(void)
- {
-
- WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
-
- InitLaunchPadCore();
-
-
- /* Set DCO to 1MHz */
- /* Set SMCLK to 1MHz / 8 = 125kHz */
- BCSCTL1 = CALBC1_1MHZ;
- DCOCTL = CALDCO_1MHZ;
- BCSCTL2 |= DIVS_3;
- /* Establish baseline for the proximity sensor */
- TI_CAPT_Init_Baseline(&proximity_sensor);
- TI_CAPT_Update_Baseline(&proximity_sensor,5);
-
- while (1)
- {
- CapTouchIdleMode();
-
- MeasureCapBaseLine();
- LedStartUpSequence();
- CapTouchActiveMode();
- }
- }
|