Skip to content

Instantly share code, notes, and snippets.

@robertinant
Created June 16, 2012 11:25
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save robertinant/2941071 to your computer and use it in GitHub Desktop.
Save robertinant/2941071 to your computer and use it in GitHub Desktop.
MSP430 Energia CapTouch library
/*
************************************************************************
* CapTouch.cpp
*
* Energia core files for MSP430
* Copyright (c) 2012 Robert Wessels. All right reserved.
*
*
***********************************************************************
Copyright (c) 2012 Robert Wessels. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Energia.h"
#include "CapTouch.h"
// Initialize Class Variables //////////////////////////////////////////////////
// Constructors ////////////////////////////////////////////////////////////////
CapTouch::CapTouch()
{
}
// Private Methods //////////////////////////////////////////////////////////////
CapTouch::pin* CapTouch::find(uint8_t pnum)
{
pin *q;
for(q = p; q != NULL; q = q->link)
if(q->pinNumber == pnum) break;
return q;
}
// Public Methods //////////////////////////////////////////////////////////////
void CapTouch::setThresholdHiRes(uint8_t pnum, uint16_t threshold)
{
pin *q = find(pnum);
q->threshold_hires = threshold;
}
void CapTouch::setThresholdLowRes(uint8_t pnum, uint16_t threshold)
{
pin *q = find(pnum);
q->threshold_lowres = threshold;
}
uint16_t CapTouch::getBaseCntHiRes(uint8_t pnum)
{
pin *q = find(pnum);
return q->baseCount_hires;
}
void CapTouch::add(uint8_t pnum)
{
volatile uint16_t *sel;
volatile uint16_t *sel2;
pin *q,*t;
/* We need to find out if the pin is PIN OSC capable before we add it to the list */
/* Find out if the pin is on a port we know of */
uint8_t port = digitalPinToPort(pnum);
/* Not a port we know of */
if (port == NOT_A_PORT) return;
/* Get the port function select 2 register address */
sel2 = portSel2Register(port);
/* If there is no sel2 register then this port does not have PIN OSC */
if (sel2 == NOT_A_PORT) return;
/* Get the bit mask for this pin */
uint8_t bit = digitalPinToBitMask(pnum);
/* Get the port function select register address */
sel = portSelRegister(port);
if (p == NULL) {
/* first element in the list */
p = new pin;
p->link = NULL;
t = p;
} else {
q = p;
while (q->link != NULL)
q = q->link;
t = new pin;
t->link = NULL;
q->link = t;
}
t->pinNumber = pnum;
t->sel = sel;
t->sel2 = sel2;
t->bit = bit;
/* set initial base line */
t->baseCount_lowres = measure(pnum, TOUCH_RAW);
t->baseCount_lowres = (t->baseCount_lowres + measure(pnum, TOUCH_RAW)) / 2;
t->baseCount_lowres = (t->baseCount_lowres + measure(pnum, TOUCH_RAW)) / 2;
t->baseCount_lowres = (t->baseCount_lowres + measure(pnum, TOUCH_RAW)) / 2;
t->baseCount_hires = measure(pnum, TOUCH_RAW_HIRES);
t->baseCount_hires = (t->baseCount_hires + measure(pnum, TOUCH_RAW_HIRES)) / 2;
t->baseCount_hires = (t->baseCount_hires + measure(pnum, TOUCH_RAW_HIRES)) / 2;
t->baseCount_hires = (t->baseCount_hires + measure(pnum, TOUCH_RAW_HIRES)) / 2;
t->threshold_hires = 150;
t->threshold_lowres = 150;
}
uint8_t CapTouch::count(void)
{
pin *q;
int c=0;
for (q=p ; q != NULL ; q = q->link)
c++;
return c;
}
uint16_t CapTouch::measure(uint8_t pnum, uint8_t mode)
{
pin *q;
uint8_t SRSave;
uint8_t SelSave, Sel2Save;
uint8_t BCSCTL1Save, DCOCTLSave, BCSCTL2Save;
uint16_t WDTCTLSave;
uint16_t TA0CTLSave, TA0CCTL1Save, TA0CCR1Save;
uint16_t delta_count, ret_val;
q = find(pnum);
if(!q) return 0;
/* Save context */
SRSave = __read_status_register();
WDTCTLSave = WDTCTL;
WDTCTLSave &= 0x00FF;
WDTCTLSave |= WDTPW;
TA0CTLSave = TA0CTL;
TA0CCTL1Save = TA0CCTL1;
TA0CCR1Save = TA0CCR1;
SelSave = *q->sel;
Sel2Save = *q->sel2;
/* Set bit in pin function select register to select PIN OSC */
*q->sel2 |= q->bit;
*q->sel &= ~q->bit;
BCSCTL1Save = BCSCTL1;
BCSCTL2Save = BCSCTL2;
DCOCTLSave = DCOCTL;
/* TODO: Is it better to use ACLK?
* Drop SMCLK down to 125 KHz to maximize the gate time.
* If we run @ 16 MHz then we can not configure a long enough gate time
* to do accurate measurement */
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
BCSCTL2 |= DIVS_3;
/* TA0 in continous mode and clock source as INCLK.
* INCLK comes from the PIN OSC cricuit. See PIN OSC clock tree
* in section "Pin Oscillator" of Users Guide.
* Pins without external load show typical oscillation frequencies of 1 MHz to 3 MHz. */
TA0CTL = TASSEL_3 + MC_2;
/* Capture mode, capture on rising and falling edge, input as GND
* Later on we will XOR with CCIS0 to induce a s/w capture. */
TA0CCTL1 = CM_3 + CCIS_2 + CAP;
/* Enable Watchdog interrupt */
IE1 |= WDTIE;
/* Interval mode + SMCLK + /8192 for hires and /512 for lowres */
if(mode == TOUCH_RAW_HIRES || mode == TOUCH_BUTTON_HIRES || mode == TOUCH_DELTA_HIRES)
WDTCTL = (WDTPW + WDTTMSEL + GATE_WDT_SMCLK + WDTp_GATE_8192);
else
WDTCTL = (WDTPW + WDTTMSEL + GATE_WDT_SMCLK + WDTp_GATE_512);
/* Clear Timer_A TAR */
TA0CTL |= TACLR;
/* Wait for WDT interrupt in LPM3 and global interrupts enables */
__bis_status_register(LPM0_bits + GIE);
/* Capture initiated by Software .
* Worse case count = min PIN OSC Freq / SMCLK / 8192
* = for hires -> 1 MHz / (125 KHz / 8192 ) = 65536
* = for regular -> 1 MHz / (125 KHz / 512 ) = 4096
* In this configuration a hires measurement takes ~65 ms and a lowres measurement takes ~4 ms */
TA0CCTL1 ^= CCIS0;
q->measuredCount = TA0CCR1;
/* Stop watchdog timer */
WDTCTL = WDTPW + WDTHOLD;
/* calculate the return for the various modes */
switch(mode) {
case TOUCH_RAW:
case TOUCH_RAW_HIRES:
ret_val = q->measuredCount;
break;
case TOUCH_BUTTON:
if(q->baseCount_lowres < q->measuredCount) {
q->baseCount_lowres = q->baseCount_lowres / 2 + q->measuredCount / 2;
ret_val = 0;
} else {
delta_count = q->baseCount_lowres - q->measuredCount;
ret_val = (delta_count > q->threshold_lowres) ? 1:0;
}
break;
case TOUCH_BUTTON_HIRES:
if(q->baseCount_hires < q->measuredCount) {
q->baseCount_hires = q->baseCount_hires / 2 + q->measuredCount / 2;
ret_val = 0;
} else {
delta_count = q->baseCount_hires - q->measuredCount;
ret_val = (delta_count > q->threshold_hires) ? 1:0;
}
break;
case TOUCH_DELTA:
ret_val = q->baseCount_lowres - q->measuredCount;
break;
case TOUCH_DELTA_HIRES:
if(q->baseCount_hires < q->measuredCount)
q->baseCount_hires = q->baseCount_hires / 2 + q->measuredCount / 2;
ret_val = q->baseCount_hires - q->measuredCount;
break;
default:
ret_val = 0;
break;
}
/* Restore context */
__bis_SR_register(SRSave);
*q->sel = SelSave;
*q->sel2 = Sel2Save;
WDTCTL = WDTCTLSave;
TA0CTL = TA0CTLSave;
TA0CCTL1 = TA0CCTL1Save;
TA0CCR1 = TA0CCR1Save;
BCSCTL1 = BCSCTL1Save;
BCSCTL2 = BCSCTL2Save;
DCOCTL = DCOCTLSave;
return ret_val;
}
CapTouch Touch = CapTouch();
/*
************************************************************************
* CapTouch.h
*
* Energia core files for MSP430
* Copyright (c) 2012 Robert Wessels. All right reserved.
*
*
***********************************************************************
Copyright (c) 2012 Robert Wessels. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef CapTouch_h
#define CapTouch_h
#include <inttypes.h>
#define GATE_WDT_ACLK 0x0004
#define GATE_WDT_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 TOUCH_RAW 0
#define TOUCH_BUTTON 1
#define TOUCH_DELTA 2
#define TOUCH_RAW_HIRES 3
#define TOUCH_BUTTON_HIRES 4
#define TOUCH_DELTA_HIRES 5
class CapTouch {
private:
struct pin {
uint8_t pinNumber;
uint8_t bit;
uint16_t threshold_lowres;
uint16_t threshold_hires;
uint16_t baseCount_lowres;
uint16_t baseCount_hires;
uint16_t measuredCount;
volatile uint16_t *sel;
volatile uint16_t *sel2;
pin *link;
} *p;
pin* find(uint8_t pnum);
public:
CapTouch();
void add(uint8_t pnum);
void setThresholdLowRes(uint8_t pnum, uint16_t threshold);
void setThresholdHiRes(uint8_t pnum, uint16_t threshold);
uint16_t getBaseCntHiRes(uint8_t pnum);
uint8_t count(void);
uint16_t measure(uint8_t pnum, uint8_t mode = TOUCH_RAW);
};
extern CapTouch Touch;
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment