Quantcast
Channel: MSP430 Technical Forums
Viewing all 2077 articles
Browse latest View live

SubiCount: an improved tally counter

$
0
0

My day job is a rheumatologist and immunology researcher. An important but stupid-boring part of research involves an accurate counting of cells. Whether you work in  immunology, cancer biology, sperm counting, etc, an accurate cell count is essential for meaningful and reproducible results. There are electronic Coulter counters but they are expensive and unless you are constantly counting cells, it doesn't make sense because of the constant adjusting and cleaning involved.

 

When I was first shown how to count cells, I thought they were taking the new guy on a snipe hunt! You take a suspension of cells and put 10 microliters (ul) to a specially calibrated slide called a hemocytometer. It has a calibrated grid of lines and a precision ground spacing between the slide and coverslip so that the volume of fluid being examined is precisely known. You typically count the number of cells in a 1 x 1 x 0.1 mm (0.1 ul) volume. So for example if you count 100 cells, you have 100/0.1ul = 1 million cells/ml.

 

See http://en.wikipedia.org/wiki/Hemocytometer for pictures and an explanation. If you want accurate and reproducible results, you need to do a good job. Once you learn few rules, it is easy but at the same time mind numbing and tedious.

 

A friend of mine did research on subtizing (https://en.wikipedia.org/wiki/Subitizing). Whats that you say? If I flash up fingers for a fraction of a second, you don't count the individual fingers-- you instantly recognize the number. Most people can subitize up to ~5 or 6 items and as you can imagine, it is much faster than counting. I wanted to see if I could subitize to speed up counting. Enter the SubiCount.

 

The hardware is rather simple so I routed the board manually, i.e. without a schematic. Two transistors, two resistors and a bypass cap. The first version of the firmware was not particularly power efficient-- it was constantly in LPM3 with a timer driven interrupt routine. About 100 times per second, it would run a button debounce routine, take care of sending pulses to the tally counter, and fall back into LPM3. Pulses to the tally counter need to be sent at a controlled rate otherwise pulses get lost. The MSP430 keeps track of how many need to be streamed to the tally counter.

 

Problem was, it would do this 24/7 regardless of whether it was being used or not. Despite this, the two button cell batteries lasted three and a half months. For my project entry, I wanted to really leverage the low power aspect of the MSP430. I haven't had a chance to see what the new battery life is but I reckon it will likely be several years because it spends the bulk of its time in LPM4.

 

Here is a video of SubiCount in action:

https://www.youtube.com/watch?v=_fc95bzSDj4

 

My implementation was to stay in LPM4. From LPM4, pressing any of the buttons will trigger a PORT1 interrupt which puts the 430 into LPM3 and turns off the PORT1 interrupt. In LPM3, a timer driven interrupt routine is called 100 times per second to debounce buttons and send pulses to the tally counter. When all the pulses are sent and no button presses are active or pending, the PORT1 interrupt is turned back on and goes into LPM4.

 

Here is the code for main. It does nothing other than turning on global interrupts and going into LPM3.

int main(void)
{
    Grace_init();                   // Activate Grace-generated configuration
    
    // >>>>> Fill-in user code here <<<<<
    _BIS_SR(LPM3_bits + GIE);
    // never should get here
}

The meat is in two interrupt routines: one for PORT1 and another for TimerA0. I used GRACE so the code is in the automatically generated InterruptVectors_init.c file. Comments have been edited out for brevity:

#include <msp430.h>
/* SubiCount by Peter Kim 2013. Creative Commons License: Attribution-NonCommercial-ShareAlike 4.0 International */


/* USER CODE START (section: InterruptVectors_init_c_prologue) */
/* User defined includes, defines, global variables and functions */

#define MAXDEBOUNCE 2	//threshold for debounce
#define MAXRESET 300	// threshold for three button reset

int processKey(unsigned int pinValue, unsigned int *pkeyInteg, unsigned int *plastValue);

int i;

unsigned int oneKeyInteg = 0;
unsigned int twoKeyInteg = 0;
unsigned int threeKeyInteg = 0;
unsigned int resetInteg = 0;

unsigned int oneKeyLastVal = 0;
unsigned int twoKeyLastVal = 0;
unsigned int threeKeyLastVal = 0;

volatile unsigned int pulses;

int processKey(unsigned int pinValue, unsigned int *pkeyInteg, unsigned int *plastValue) {
/* Debounce routine adapted from http://www.kennethkuhn.com/electronics/debounce.c
*/
  int posEdge = 0;

  if (pinValue)  //pinValue inverted
  {
    if (*pkeyInteg > 0)
      (*pkeyInteg)--;
  }
  else if (*pkeyInteg < MAXDEBOUNCE)
    (*pkeyInteg)++;

  if (*pkeyInteg == 0)
    *plastValue = 0;
  else if (*pkeyInteg >= MAXDEBOUNCE && *plastValue == 0)
  {
		posEdge = 1;
		*plastValue = 1;
		*pkeyInteg = MAXDEBOUNCE;  /* defensive code if integrator got corrupted */
  }

  return(posEdge);
}

void InterruptVectors_graceInit(void)
{
}

#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR_HOOK(void)
{
    /* USER CODE START (section: PORT1_ISR_HOOK) */
	P1IFG &= ~(BIT3+BIT2+BIT1);	//clear interrupt flag
	P1IE &= ~(BIT3+BIT2+BIT1);		//clear P1.3 interrupt enable


	__bic_SR_register_on_exit(OSCOFF);	//put into LPM3
    /* USER CODE END (section: PORT1_ISR_HOOK) */
}

/*
 *  ======== Timer_A2 Interrupt Service Routine ======== 
 */
#pragma vector=TIMERA0_VECTOR
__interrupt void TIMERA0_ISR_HOOK(void)
{
    /* USER CODE START (section: TIMERA0_ISR_HOOK) */
	static int count =0; // to keep track of times here
	int P1;

	P1 = P1IN;

	if ( processKey(P1 & BIT1, &oneKeyInteg, &oneKeyLastVal) )
		pulses++;
	if ( processKey(P1 & BIT2, &twoKeyInteg, &twoKeyLastVal) ) {
		pulses += 2;
	}
	if ( processKey(P1 & BIT3, &threeKeyInteg, &threeKeyLastVal) ) {
		pulses += 3;
	}
	if ( (P1 & (BIT1|BIT2|BIT3)) == 0) {
		resetInteg++;
		if (resetInteg > MAXRESET) {
			resetInteg = 0;
			P1OUT |= BIT6; //turn on bit6, reset
			_delay_cycles(40000);
			P1OUT = BIT1|BIT2|BIT3; //need pull ups on
			pulses = 0;		//reset pulses count after reset
			return;
		}
	} else if (resetInteg)
		resetInteg--;

	if (count++ >7)
	{
		count = 0;
		if (P1OUT & BIT0)   //count pin high?
		{
			P1OUT &= ~BIT0; //then turn off
			pulses--;		//and decrement pulses
		} else if (pulses) {
			P1OUT |= BIT0;	//turn on count pin
		}
	}

	if (pulses == 0)	// done with pulses?
	{
		if ( (P1IN & BIT1+BIT2+BIT3) == BIT1+BIT2+BIT3 )	//are all buttons not pressed?
		{
			if (oneKeyLastVal==0 && twoKeyLastVal==0 && threeKeyLastVal==0)
			{
				P1IFG &= ~(BIT3+BIT2+BIT1);	//clear P1.3 int flag
				P1IE |= BIT3+BIT2+BIT1;		//enable P1.3 interrupt
				__bis_SR_register_on_exit(LPM4_bits + GIE);	//go into LPM4
			}
		}
	}
    /* USER CODE END (section: TIMERA0_ISR_HOOK) */
}
 

Here is the hand routed board:

cell count.png

 

And a hand drawn schematic:

schematic.jpg


[SOLVED] PWM Frequency in Energia

$
0
0

Hello!  

 

I am new to embedded programming and the forums.  For my first task I am trying to generate a clean square wave with a configurable frequency and I figured PWM would be a good way to do this.  Below is my code.  This works to an extent, but during the off time there are regular spikes to 3.6V at about 10kHz as seen in my scope plot.  The scope is a cheap Rigol DS1102.

 

How can I eliminate these spikes?  and is my approach the best approach or is there a better one that may not have the extra spikes?

 

thanks in advance for the help!

void setup() {
// declare pin 14 to be an output:
pinMode(GREEN_LED, OUTPUT);
}

void loop() {
// set the frequency:
analogFrequency(800);

//PWM (Pin, Duty Cycle) - Maximum = 100% = 255
analogWrite(GREEN_LED, 127);

}

800_Hz.png

 

 

MSP-EXP430G2 w/ crystal populated to pins XIN/XOUT

MSP430G2553

Energia 11

Windows 8.1 x64

Help with a busted 5529LP

$
0
0

Is there a way to can reflash the firmware of a 5529LP? That is, not your program, but the program of the entire thing: CDC ports, etc. Recently, I have been using a logic analyzer for testing and switching between computers. Today, CCS asked me to update the firmware of the Launchpad, and I did. Now, the Launchpad will not power on without external ground input (plug a wire that is connected to the computer's GND into one of the GND pins), and it always say "General USB Hub" instead of "MSP Tools" or whatever it used to say.

How to protect flash memory

$
0
0

hey can any please help me, I want to know that is the program in my msp430F5529  flash is protected.Can any one copy that program to another microcontrollor???

QtLedTest – Software to Evaluate OLED Displays

configuration data store in flash or SD card

$
0
0

hey guys I'm wrapping up my audible alarm product I am developing and have a question.

 

would it be better to have a configuration text file on the SD card that it reads, parses, and then plays the file (adding some delay I'm not sure how long, as well as the complexity of parsing a text file the customer will write so there is no guarantee of syntax or organization so the parser would have to be beefy)

I already have the SD card interface running (it plays the sounds off the card), and it has to have the SD card present to function.

 

however storing the data in flash would require them to plug the serial cable in and make changes in a terminal program (FTDI cable)  this would have faster runtime startup (it has to powerup from scratch, each time it plays a sound as it gets its VCC power from the input lines themselves), and not require them to format the text file properly to be understood by the micro.

 

I can see ups and downs either way.  I don't know the technical skill of the end user once the device is in the wild, writing a text file is technically easier than running a terminal program, but I don't know,  is there a best practice type thing to consider or am I just overthinking it?

 

overall this has been an interesting project that started as me redesigning an elevator chime for my father, and has turned into at least a hundred of these units for their factory, and a vendor wanting to market them to other facilities so there could be many more of them in the wild at some point :)

UV/uranium glass wearable

$
0
0

My sister is very artsy craftsy and loves bead jewellery. I'm going to see her in about 6 weeks and would like to make her a present. I have never made a wearable, but I have been thinking for a while about making something using UV LEDs and uranium glass beads or buttons for a cool glow in the dark effect. 

 

My initial thought was to make a pendant about 1" round with a coin cell on the back, a ring of UV LEDs around a microcontroller, and then string a button in the middle. Something like this: a MSP430G2231 with 8 LEDs connected to its IO pins and a tactile switch to turn it on/off/cycle through flash/fade modes.

 

pendant.png

 

What I'd really like to do though is string a 2-3 buttons on a necklace interspersed with UV LEDs and use conductive thread to connect them with a Gemma-type PCB/clasp on the back. Anybody have any experience with that sort of thing?

Ti Launchpad with msp430G2553

$
0
0
Hello!!
 
1. I have problems.
    I don't understand why measurement was influenced on temperature in this ENERGIA example source(Cap Touch Raw)
    So, I want to measure capacitance without temperature.
-------------------------------------------------------------------------------------------------------------------------------------
#include <CapTouch.h>
 
#define PROXIMITY_SENSOR P2_0
#define MIDDLE_LED P1_0
 
/* Create a CapTouch instance for the proximity sensor */
CapTouch proximity = CapTouch(PROXIMITY_SENSOR, TOUCH_PROXIMITY);
 
uint16_t measured, base;
/* Delta can be negative */
int16_t delta;
uint8_t state;
 
void setup() {
  /* Use middle LED as proximity indicator */
  pinMode(MIDDLE_LED, OUTPUT);
  /* Set the proximity threshold to 100 to increase range */ 
  proximity.setThreshold(100);
 
  Serial.begin(9600);
}
 
void loop() {
  state = proximity.isTouched();
  digitalWrite(MIDDLE_LED, state);  
  
  measured = proximity.getMeasured();
  base = proximity.getBaseline();
  delta = proximity.getDelta();
  
  Serial.print("State: ");
  Serial.print(state);  
  Serial.print("\tBase: ");
  Serial.print(base);  
  Serial.print("\tMeasured: ");
  Serial.print(measured);  
  Serial.print("\tDelta: ");
  Serial.println(delta);  
}
-----------------------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
 
 
2.  And Following source is that edited CCS example source. This isn't influenced on temperature.
     What's different?
-----------------------------------------------------------------------------------------------------------------------------------------------
 
#include <msp430.h>
#include <stdio.h>
 
/* Define User Configuration values */
/*----------------------------------*/
/* 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)
 
/*Set to ~ half the max delta expected*/
 
/* Definitions for use with the WDT settings*/
#define DIV_ACLK_512    (WDT_ADLY_16)       // ACLK/512 --Auxiliary Clock(see basic clock module)
#define DIV_SMCLK_512   (WDT_MDLY_0_5)      // SMCLK/512 --Sub-System Master (Clock See Basic Clock Module)
 
#define LED_1   (0x01)                      // P1.0 LED output
#define LED_2   (0x40)                      // P1.6 LED output
 
// Global variables for sensing
unsigned int base_cnt, meas_cnt; //set int base_cnt,int meas_cnt
 
 
char buffer[32]; //set char buffer
long temp; //set long IntDegF
long IntDegC; //set long IntDegC
volatile unsigned int timer_count=0;
 
/* System Routines*/
void measure_count(void);                   // Measures each capacitive sensor
void pulse_LED(void);                       // LED gradient routine
void init_uart(void);
void init_timer();
void init_adc();
void start_conversion();
 
/* Main Function*/
int main(void)
{
  unsigned int i;
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  if (CALBC1_1MHZ==0xFF) // If calibration constant erased
 
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz (Basic Clock System Control 1)
  DCOCTL =  CALDCO_1MHZ; // DCOCTL Calibration Data for 1MHz
  BCSCTL3 |= LFXT1S_2;                      // LFXT1 = VLO (Basic Clock System Control 3)
 
  IE1 |= WDTIE;                             // enable IE1 to WDT interrupt
  P2SEL = 0x00;                             // port2 selection, No XTAL
  P1DIR = LED_1 + LED_2;                    // P1.0 & P1.6 = LEDs (Port 1 Direction)
  P1OUT = 0x00; // Port 1 output set 0
 
   __bis_SR_register(GIE);                  // set GIE Register, Enable interrupts
 
  measure_count();                          // Establish baseline capacitance
    base_cnt = meas_cnt; // count start?
 
  for(i=30; i>0; i--)                       // Repeat and avg base measurement
  {
    measure_count(); // count start,
  base_cnt = (meas_cnt+base_cnt)/2;
  }
  /* Main loop starts here*/
  while (1)
  {
    measure_count();                         // Measure all sensors
    /* Delay to next sample, sample more slowly if no keys are pressed*/
 
    WDTCTL = WDT_delay_setting;             // WDT, ACLK, interval timer
 
    /* Handle baseline measurment for a base C increase*/
                                          // 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
     init_uart();
     init_timer();
     init_adc();
 
  // enable interrupts and put the CPU to sleep
  _bis_SR_register(GIE+LPM0_bits); //set GIE
 }
}                                           // End Main
 
/* Measure count result (capacitance) of each sensor*/
/* Routine setup for four sensors, not dependent on NUM_SEN value!*/
void measure_count(void)
{
 
  TA0CTL = TASSEL_3+MC_2;                   // TACLK, cont mode
  TA0CCTL1 = CM_3+CCIS_2+CAP;               // Pos&Neg,GND,Cap
 
    /*Configure Ports for relaxation oscillator*/
    /*The P2SEL2 register allows Timer_A to receive it's clock from a GPIO*/
    /*See the Application Information section of the device datasheet for info*/
    P2DIR &= ~ BIT5;                        // P2.5 is the input used here
    P2SEL &= ~ BIT5;
    P2SEL2 |= BIT5;
 
    /*Setup Gate Timer*/
    WDTCTL = WDT_meas_setting;              // WDT, ACLK, interval timer
    TA0CTL |= TACLR;                        // Clear Timer_A TAR
    __bis_SR_register(LPM0_bits+GIE);       // Wait for WDT interrupt
    TA0CCTL1 ^= CCIS0;                      // Create SW capture of CCR1
    meas_cnt = TACCR1;                      // Save result
    WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer
    P2SEL2 &= ~BIT5;
 
    __delay_cycles(100000);
}
 
void pulse_LED(void)
{
    P1OUT ^= LED_1 + LED_2;
  }
void init_uart(void){
P1SEL  = BIT1 + BIT2; // P1.1 = RXD, P1.2 = TXD
P1SEL2 = BIT1 + BIT2; // P1.1 = RXD, P1.2 = TXD
UCA0CTL1|=UCSSEL_2;    // SMCLK
UCA0BR0 = 104; // see baud rate divider above
UCA0BR1 = 0;
UCA0MCTL = UCBRS0; // modulation UCBRSx = 1
UCA0CTL1 &= ~UCSWRST; // ** initialize USCI state machine **
IE2 |= UCA0TXIE; // Enable USCI_A0 TX interrupt
}
 
void init_timer() {
TA0CTL |= TACLR; // reset timer
TA0CTL  = TASSEL_2 // SMCLK
+ID_0 // input divider = 1
+MC_2; // continuous mode, interrupt disabled
TA0CCTL0 = OUTMOD_2 // compare mode
+CCIE // interrupt enabled
+CCIFG;
}
 
void init_adc(){
// :NOTE: On-board heat sensor is used.
ADC10CTL1 = INCH_10 // temperature sensor input to ADC
+SHS_0 // use ADC10SC bit to trigger sampling
+ADC10DIV_3 // clock divider = 4
+ADC10SSEL_3 // clock source = SMCLK
+CONSEQ_0; // single channel, single conversion
ADC10DTC1 = 1; // one block per transfer
 
ADC10CTL0 = SREF_1 // reference voltages are Vss and Vcc
+ADC10SHT_3 // 64 ADC10 clocks for sample and hold time (slowest)
+REFON // reference generator on
+ADC10ON // turn on ADC10
+ENC; // enable (but not yet start) conversions
}
 
void start_conversion()
{
if ((ADC10CTL1 & ADC10BUSY) == 0){ // if not already converting
P1OUT ^= 0x40;
ADC10CTL0 |= ADC10SC;
//ADC10SA = (unsigned) & latest_adc_result;
temp = ADC10MEM;
IntDegC = ((270664L*temp)-181698560L)>>16;
//IntDegC = ((temp - 673) * 4225) / 1024;
}
}
 
/* Watchdog Timer interrupt service routine*/
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
  TA0CCTL1 ^= CCIS0;                        // Create SW capture of CCR1
 // IE2 |= UCA0TXIE;
  __bic_SR_register_on_exit(LPM3_bits);     // Exit LPM3 on reti
}
 
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer0_A0(void) {
//timer_count++;
//if (timer_count > 32) {
//timer_count = 0;
start_conversion();
//IE2 |= UCA0TXIE;
}
 
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void){
P1OUT |= 0x01;
unsigned int i = 0; // iterator pointers
 
sprintf(buffer,"count :" "%d, %d \n\r", (unsigned int)(meas_cnt), (long)(IntDegC/10));
 
while(buffer[i] != '\0'){
while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = buffer[i++];
 
__delay_cycles(10);
}
buffer[i++] ^=0;
P1OUT &= ~0x01;
IE2 &= ~UCA0TXIFG;
}
---------------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
3.   Especially, what is difference in this source of bold 
     One is edited CCS file and the other is .cpp file linked on ENERGIA example.
     Both are measuring capacitance but, CCS is stable and ENERGIA is unstable and influence on temperature. 
-------------------------------------------------------------------------------------------------------------------------------------------
#include <msp430.h>
#include <stdio.h>
 
/* Define User Configuration values */
/*----------------------------------*/
/* 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)
 
/*Set to ~ half the max delta expected*/
 
/* Definitions for use with the WDT settings*/
#define DIV_ACLK_512    (WDT_ADLY_16)       // ACLK/512 --Auxiliary Clock(see basic clock module)
#define DIV_SMCLK_512   (WDT_MDLY_0_5)      // SMCLK/512 --Sub-System Master (Clock See Basic Clock Module)
 
#define LED_1   (0x01)                      // P1.0 LED output
#define LED_2   (0x40)                      // P1.6 LED output
 
// Global variables for sensing
unsigned int base_cnt, meas_cnt; //set int base_cnt,int meas_cnt
 
 
char buffer[32]; //set char buffer
long temp; //set long IntDegF
long IntDegC; //set long IntDegC
volatile unsigned int timer_count=0;
 
/* System Routines*/
void measure_count(void);                   // Measures each capacitive sensor
void pulse_LED(void);                       // LED gradient routine
void init_uart(void);
void init_timer();
void init_adc();
void start_conversion();
 
/* Main Function*/
int main(void)
{
  unsigned int i;
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  if (CALBC1_1MHZ==0xFF) // If calibration constant erased
 
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz (Basic Clock System Control 1)
  DCOCTL =  CALDCO_1MHZ; // DCOCTL Calibration Data for 1MHz
  BCSCTL3 |= LFXT1S_2;                      // LFXT1 = VLO (Basic Clock System Control 3)
 
  IE1 |= WDTIE;                             // enable IE1 to WDT interrupt
  P2SEL = 0x00;                             // port2 selection, No XTAL
  P1DIR = LED_1 + LED_2;                    // P1.0 & P1.6 = LEDs (Port 1 Direction)
  P1OUT = 0x00; // Port 1 output set 0
 
   __bis_SR_register(GIE);                  // set GIE Register, Enable interrupts
 
  measure_count();                          // Establish baseline capacitance
    base_cnt = meas_cnt; // count start?
 
  for(i=30; i>0; i--)                       // Repeat and avg base measurement
  {
    measure_count(); // count start,
  base_cnt = (meas_cnt+base_cnt)/2;
  }
  /* Main loop starts here*/
  while (1)
  {
    measure_count();                         // Measure all sensors
    /* Delay to next sample, sample more slowly if no keys are pressed*/
 
    WDTCTL = WDT_delay_setting;              // WDT, ACLK, interval timer
 
    /* Handle baseline measurment for a base C increase*/
                                            // 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
     init_uart();
     init_timer();
     init_adc();
 
  // enable interrupts and put the CPU to sleep
  _bis_SR_register(GIE+LPM0_bits); //set GIE
 }
}                                           // End Main
 
/* Measure count result (capacitance) of each sensor*/
/* Routine setup for four sensors, not dependent on NUM_SEN value!*/
void measure_count(void)
{
 
  TA0CTL = TASSEL_3+MC_2;                   // TACLK, cont mode
  TA0CCTL1 = CM_3+CCIS_2+CAP;               // Pos&Neg,GND,Cap
 
    /*Configure Ports for relaxation oscillator*/
    /*The P2SEL2 register allows Timer_A to receive it's clock from a GPIO*/
    /*See the Application Information section of the device datasheet for info*/
    P2DIR &= ~ BIT5;                        // P2.5 is the input used here
    P2SEL &= ~ BIT5;
    P2SEL2 |= BIT5;
 
    /*Setup Gate Timer*/
    WDTCTL = WDT_meas_setting;              // WDT, ACLK, interval timer
    TA0CTL |= TACLR;                        // Clear Timer_A TAR
    __bis_SR_register(LPM0_bits+GIE);       // Wait for WDT interrupt
    TA0CCTL1 ^= CCIS0;                      // Create SW capture of CCR1
    meas_cnt = TACCR1;                      // Save result
    WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer
    P2SEL2 &= ~BIT5;
 
    __delay_cycles(100000);
}
 
void pulse_LED(void)
{
    P1OUT ^= LED_1 + LED_2;
  }
void init_uart(void){
P1SEL  = BIT1 + BIT2; // P1.1 = RXD, P1.2 = TXD
P1SEL2 = BIT1 + BIT2; // P1.1 = RXD, P1.2 = TXD
UCA0CTL1|=UCSSEL_2;     // SMCLK
UCA0BR0 = 104; // see baud rate divider above
UCA0BR1 = 0;
UCA0MCTL = UCBRS0; // modulation UCBRSx = 1
UCA0CTL1 &= ~UCSWRST; // ** initialize USCI state machine **
IE2 |= UCA0TXIE; // Enable USCI_A0 TX interrupt
}
 
void init_timer() {
TA0CTL |= TACLR; // reset timer
TA0CTL  = TASSEL_2 // SMCLK
+ID_0 // input divider = 1
+MC_2; // continuous mode, interrupt disabled
TA0CCTL0 = OUTMOD_2 // compare mode
+CCIE // interrupt enabled
+CCIFG;
}
 
void init_adc(){
// :NOTE: On-board heat sensor is used.
ADC10CTL1 = INCH_10 // temperature sensor input to ADC
+SHS_0 // use ADC10SC bit to trigger sampling
+ADC10DIV_3 // clock divider = 4
+ADC10SSEL_3 // clock source = SMCLK
+CONSEQ_0; // single channel, single conversion
ADC10DTC1 = 1; // one block per transfer
 
ADC10CTL0 = SREF_1 // reference voltages are Vss and Vcc
+ADC10SHT_3 // 64 ADC10 clocks for sample and hold time (slowest)
+REFON // reference generator on
+ADC10ON // turn on ADC10
+ENC; // enable (but not yet start) conversions
}
 
void start_conversion()
{
if ((ADC10CTL1 & ADC10BUSY) == 0){ // if not already converting
P1OUT ^= 0x40;
ADC10CTL0 |= ADC10SC;
//ADC10SA = (unsigned) & latest_adc_result;
temp = ADC10MEM;
IntDegC = ((270664L*temp)-181698560L)>>16;
//IntDegC = ((temp - 673) * 4225) / 1024;
}
}
 
/* Watchdog Timer interrupt service routine*/
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
  TA0CCTL1 ^= CCIS0;                        // Create SW capture of CCR1
 // IE2 |= UCA0TXIE;
  __bic_SR_register_on_exit(LPM3_bits);     // Exit LPM3 on reti
}
 
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer0_A0(void) {
//timer_count++;
//if (timer_count > 32) {
//timer_count = 0;
start_conversion();
//IE2 |= UCA0TXIE;
}
 
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void){
P1OUT |= 0x01;
unsigned int i = 0; // iterator pointers
 
sprintf(buffer,"count :" "%d, %d \n\r", (unsigned int)(meas_cnt), (long)(IntDegC/10));
 
while(buffer[i] != '\0'){
while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = buffer[i++];
 
__delay_cycles(10);
}
buffer[i++] ^=0;
P1OUT &= ~0x01;
IE2 &= ~UCA0TXIFG;
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
-----------------------------------------------------------------------------------------------------------------------------------------------------------
#include "Energia.h"
#include "CapTouch.h"
 
CapTouch::CapTouch(uint8_t pin, uint8_t sensorType)
{
/* Find out if the pin is on a port we know of */
uint8_t port = digitalPinToPort(pin);
/* 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 */
bit = digitalPinToBitMask(pin);
 
/* Get the port function select register address */
sel = portSelRegister(port); 
 
type = sensorType;
 
/* Set initial threshold */
threshold = 250;
}
 
void CapTouch::setThreshold(uint16_t sensorThreshold)
{
threshold = sensorThreshold;
}
 
void CapTouch::setBaseLine() {
/* Set initial base line */
 
base = measure();
base = (base + measure()) / 2;
base = (base + measure()) / 2;
base = (base + measure()) / 2;
 
}
 
uint16_t CapTouch::getBaseline()
{
if(base == 0)
setBaseLine();
return base;
}
 
uint16_t CapTouch::getMeasured()
{
return measured;
}
 
int16_t CapTouch::getDelta()
{
return delta;
}
 
uint8_t CapTouch::isTouched() {
if(base == 0)
setBaseLine();
 
measured = measure();
delta = base - measured;
if(delta < 0) {
base = (base / 2) + (measured / 2);
}
 
if(delta < (int16_t) threshold) {
base--;
return 0;
}
 
return 1;
}
 
uint16_t CapTouch::measure()
{
uint8_t SelSave, Sel2Save;
uint16_t WDTCTLSave;
uint16_t TA0CTLSave, TA0CCTL1Save, TA0CCR1Save;
uint16_t delta_count;
int16_t ret_val;
 
/* TODO:
* The following delay is a work around for the CapTouch code
* not behaving when following a Serial.print call */
delay(1);
 
/* Save context */
WDTCTLSave = WDTCTL;
WDTCTLSave &= 0x00FF;
WDTCTLSave |= WDTPW;
TA0CTLSave = TA0CTL;
TA0CCTL1Save = TA0CCTL1;
TA0CCR1Save = TA0CCR1;
 
SelSave = *sel;
Sel2Save = *sel2;
 
/* Set bit in pin function select register to select PIN OSC */ 
*sel2 |= bit;
*sel &= bit;
 
/* 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 + ACLK + /512 for hires and /64 for lowres */
if(type == TOUCH_PROXIMITY) {
BCSCTL1 |= DIVA_1;
WDTCTL = (WDTPW + WDTTMSEL + GATE_WDT_ACLK + WDT_GATE_512);
} else {
WDTCTL = (WDTPW + WDTTMSEL + GATE_WDT_ACLK + WDT_GATE_64); 
}
 
/* Clear Timer_A TAR */
TA0CTL |= TACLR;
 
/* Wait for WDT interrupt in LPM3 and global interrupts enables */
if(type == TOUCH_PROXIMITY) {
__bis_status_register(LPM0_bits + GIE);
BCSCTL1 &= ~DIVA_1;
} else {
__bis_status_register(LPM3_bits + GIE);
}
 
/* Capture initiated by Software .
* Worse case count = min PIN OSC Freq / ACLK / WDT gate time
*                  = for hires   -> 1 MHz / (12 KHz / 512) = 42666
*                  = for regular -> 1 MHz / (12 KHz / 64 ) = 5333
* In this configuration a hires measurement takes ~43 ms and a lowres measurement takes ~5 ms */
TA0CCTL1 ^= CCIS0;
 
measured = TA0CCR1;
 
/* Stop watchdog timer */
WDTCTL = WDTPW + WDTHOLD;
/* Restore context */
*sel = SelSave;
*sel2 = Sel2Save;
WDTCTL = WDTCTLSave;
TA0CTL = TA0CTLSave;
TA0CCTL1 = TA0CCTL1Save;
TA0CCR1 = TA0CCR1Save;
 
return measured;
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Getting started with MSPGCC and a launchpad

$
0
0

Hi, this is my first post here, I've been reading the site for a while.

 

I wanted to get MSPGCC working over the break, and I noticed that the Wiki for mspgcc didn't have much of a place to start, in terms of a working makefile and simple example. Since I have a launchpad I figured I'd use that to test my install, and I wrote a short blog post about the process with a sample blink program and a makefile, that way hopefully it will ease the process for others.

 

Let me know if you have questions, the blog post is at http://wp.me/p1eEOJ-C

 

Although I'm using a Mac the process is the same in terms of setup and using for any platform.

 

Thanks!

3D printed G2LP and 5529LP bumpers/cases

$
0
0

Hi...I was experimenting with some cases and bumpers to protect LaunchPads as they float around on a desk or in a box of parts. The regular LaunchPad bumper is based on some existing concepts, which I used to create a new design in Autodesk Inventor. The 5529 bumper-case is the same basic idea but with a snap-on lid to protect those easily-bent pins on the top. I just moved to Dallas and need to dig out my 3D printer (among other things) in order to refine the designs a little, but should be able to post some STLs in here soon if there's interest.

 

 

Attached Thumbnails

  • Photo Jan 03, 10 08 39 PM.jpg
  • Photo Jan 03, 10 10 36 PM.jpg
  • Photo Jan 03, 10 09 28 PM.jpg

Getting Started with Energia

$
0
0

Successfully executed the Blink program in the Getting Started section of the Help menu in Energia.  Now that I've executed the program, how do I "undo" it?

 

I'm working with a Tiva C Series TM4C123G launchpad.

 

Thank you

msp430-elf-gcc and OSX

$
0
0

Hi guys,

 

TI/Redhat has released the beta version of CC6 with Gcc 4.8 (as mentioned http://forum.43oh.com/topic/4500-msp430-elf-gcc-red-hat-version-available-in-ccs6-beta/ )

 

I was not aware if anybody has tried to compile those sources on the OSX platform.. So I tried and followed this path:

 

1) Download source files and header files from the TI webpage (msp430-130423-272-source.tar.bz2, GCC_RH_20131206) and remove packages that are not yet supported by the platform (GDB):

tar xjf ../msp430-130423-272-source.tar.bz2
cd source/tools
rm -r gdb tk tcl itcl sim libgui

3) configure 

cd ../..
mkdir bin; cd bin
export PREFIX="/users/xxx/msp430/"
../sources/tools/configure --prefix=$PREFIX --target=msp430-elf --disable-werror

the --disable-werror surpresses warnings from clang

 

4) make

make 
make install

5) headers

extract header files to your installation directory

 

Note that I haven't checked if the produces binaries are ok.

 

If anybody has worked out how to compile GDB with theses sources that would be great. So far I've figured out that the LDFLAGS must be set to  -L/opt/X11/lib to overcome errors that X11 was not found.

MSP430 launchPad G2553

$
0
0
I want to use a code in Energia when I was editing CCS example code 
But, i got a message like this.
-------------------------------------------------------------
sketch_jan06c.cpp: In function 'int main()':
sketch_jan06c.cpp:82:33: error: '_bis_SR_register' was not declared in this scope
-------------------------------------------------------------------------
How can i do?
 
 

#include <msp430.h>
#include <stdio.h>
 
/* Define User Configuration values */
/*----------------------------------*/
/* 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)
 
/*Set to ~ half the max delta expected*/
 
/* Definitions for use with the WDT settings*/
#define DIV_ACLK_512    (WDT_ADLY_16)       // ACLK/512 --Auxiliary Clock(see basic clock module)
#define DIV_SMCLK_512   (WDT_MDLY_0_5)      // SMCLK/512 --Sub-System Master (Clock See Basic Clock Module)
 
#define LED_1   (0x01)                      // P1.0 LED output
#define LED_2   (0x40)                      // P1.6 LED output
 
// Global variables for sensing
unsigned int base_cnt, meas_cnt; //set int base_cnt,int meas_cnt
 
 
char buffer[32]; //set char buffer
long temp; //set long IntDegF
long IntDegC; //set long IntDegC
volatile unsigned int timer_count=0;
 
/* System Routines*/
void measure_count(void);                   // Measures each capacitive sensor
void pulse_LED(void);                       // LED gradient routine
void init_uart(void);
void init_timer();
void init_adc();
void start_conversion();
 
/* Main Function*/
int main(void)
{
  unsigned int i;
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
  if (CALBC1_1MHZ==0xFF) // If calibration constant erased
 
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz (Basic Clock System Control 1)
  DCOCTL =  CALDCO_1MHZ; // DCOCTL Calibration Data for 1MHz
  BCSCTL3 |= LFXT1S_2;                      // LFXT1 = VLO (Basic Clock System Control 3)
 
  IE1 |= WDTIE;                             // enable IE1 to WDT interrupt
  P2SEL = 0x00;                             // port2 selection, No XTAL
  P1DIR = LED_1 + LED_2;                    // P1.0 & P1.6 = LEDs (Port 1 Direction)
  P1OUT = 0x00; // Port 1 output set 0
 
   __bis_SR_register(GIE);                  // set GIE Register, Enable interrupts
 
  measure_count();                          // Establish baseline capacitance
    base_cnt = meas_cnt; // count start?
 
  for(i=30; i>0; i--)                       // Repeat and avg base measurement
  {
    measure_count(); // count start,
  base_cnt = (meas_cnt+base_cnt)/2;
  }
  /* Main loop starts here*/
  while (1)
  {
    measure_count();                         // Measure all sensors
    /* Delay to next sample, sample more slowly if no keys are pressed*/
 
    WDTCTL = WDT_delay_setting;             // WDT, ACLK, interval timer
 
    /* Handle baseline measurment for a base C increase*/
                                          // 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
     init_uart();
     init_timer();
     init_adc();
 
  // enable interrupts and put the CPU to sleep
  _bis_SR_register(GIE+LPM0_bits); //set GIE
 }
}                                           // End Main
 
/* Measure count result (capacitance) of each sensor*/
/* Routine setup for four sensors, not dependent on NUM_SEN value!*/
void measure_count(void)
{
 
  TA0CTL = TASSEL_3+MC_2;                   // TACLK, cont mode
  TA0CCTL1 = CM_3+CCIS_2+CAP;               // Pos&Neg,GND,Cap
 
    /*Configure Ports for relaxation oscillator*/
    /*The P2SEL2 register allows Timer_A to receive it's clock from a GPIO*/
    /*See the Application Information section of the device datasheet for info*/
    P2DIR &= ~ BIT5;                        // P2.5 is the input used here
    P2SEL &= ~ BIT5;
    P2SEL2 |= BIT5;
 
    /*Setup Gate Timer*/
    WDTCTL = WDT_meas_setting;              // WDT, ACLK, interval timer
    TA0CTL |= TACLR;                        // Clear Timer_A TAR
    __bis_SR_register(LPM0_bits+GIE);       // Wait for WDT interrupt
    TA0CCTL1 ^= CCIS0;                      // Create SW capture of CCR1
    meas_cnt = TACCR1;                      // Save result
    WDTCTL = WDTPW + WDTHOLD;               // Stop watchdog timer
    P2SEL2 &= ~BIT5;
 
    __delay_cycles(100000);
}
 
void pulse_LED(void)
{
    P1OUT ^= LED_1 + LED_2;
  }
void init_uart(void){
P1SEL  = BIT1 + BIT2; // P1.1 = RXD, P1.2 = TXD
P1SEL2 = BIT1 + BIT2; // P1.1 = RXD, P1.2 = TXD
UCA0CTL1|=UCSSEL_2;    // SMCLK
UCA0BR0 = 104; // see baud rate divider above
UCA0BR1 = 0;
UCA0MCTL = UCBRS0; // modulation UCBRSx = 1
UCA0CTL1 &= ~UCSWRST; // ** initialize USCI state machine **
IE2 |= UCA0TXIE; // Enable USCI_A0 TX interrupt
}
 
void init_timer() {
TA0CTL |= TACLR; // reset timer
TA0CTL  = TASSEL_2 // SMCLK
+ID_0 // input divider = 1
+MC_2; // continuous mode, interrupt disabled
TA0CCTL0 = OUTMOD_2 // compare mode
+CCIE // interrupt enabled
+CCIFG;
}
 
void init_adc(){
// :NOTE: On-board heat sensor is used.
ADC10CTL1 = INCH_10 // temperature sensor input to ADC
+SHS_0 // use ADC10SC bit to trigger sampling
+ADC10DIV_3 // clock divider = 4
+ADC10SSEL_3 // clock source = SMCLK
+CONSEQ_0; // single channel, single conversion
ADC10DTC1 = 1; // one block per transfer
 
ADC10CTL0 = SREF_1 // reference voltages are Vss and Vcc
+ADC10SHT_3 // 64 ADC10 clocks for sample and hold time (slowest)
+REFON // reference generator on
+ADC10ON // turn on ADC10
+ENC; // enable (but not yet start) conversions
}
 
void start_conversion()
{
if ((ADC10CTL1 & ADC10BUSY) == 0){ // if not already converting
P1OUT ^= 0x40;
ADC10CTL0 |= ADC10SC;
//ADC10SA = (unsigned) & latest_adc_result;
temp = ADC10MEM;
IntDegC = ((270664L*temp)-181698560L)>>16;
//IntDegC = ((temp - 673) * 4225) / 1024;
}
}
 
/* Watchdog Timer interrupt service routine*/
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
  TA0CCTL1 ^= CCIS0;                        // Create SW capture of CCR1
 // IE2 |= UCA0TXIE;
  __bic_SR_register_on_exit(LPM3_bits);     // Exit LPM3 on reti
}
 
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer0_A0(void) {
//timer_count++;
//if (timer_count > 32) {
//timer_count = 0;
start_conversion();
//IE2 |= UCA0TXIE;
}
 
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void){
P1OUT |= 0x01;
unsigned int i = 0; // iterator pointers
 
sprintf(buffer,"count :" "%d, %d \n\r", (unsigned int)(meas_cnt), (long)(IntDegC/10));
 
while(buffer[i] != '\0'){
while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = buffer[i++];
 
__delay_cycles(10);
}
buffer[i++] ^=0;
P1OUT &= ~0x01;
IE2 &= ~UCA0TXIFG;
}
 
 

MSP430 Application UART

$
0
0

I'm developping some codes with Energia or TI CCS for the TI LaunchPad MSP-EXP430G2, v1.4 and v1.5, with G2553 and G2452 chips. I organize DIY workshops.

 

I'm playing with various computers, I enumarate them: 1x W7Pro32, 1x W7Starter, 1x W8.1x64, 1x TP-Link TL-MR3020+OpenWrt, 1x TP-Link WR710N+OpenWrt.

 

Nothing is going right with serial, only my old W7Pro32 can read/write thru the USB serial ! Even my 2 OpenWrt TP-Link can't communicate !

 

If I play with some Arduino in place of TI LaunchPad, all USB serial is working fine (except the known reset problem of Arduino USB serial).

 

Yesterday evening, I played a lot with a TI LaunchPad and my W8.1x64. I discovered that sometimes, the serial USB could communicate ! That's after a lot of stress of the serial settings. I used PuTTY to receive something. The G2553 program was continualy sending 1 character every second. After changing the "Flow control" in PuTTY/Settings/Connection/Serial a lot of times, changing from XON/XOFF to RTS/CTS to /DTR/DSR, in any order, and typing a lot of ^S,^Q,... sentences, the TI Launchpad would finally communicate ! As soon as the USB serial communicates, I can deselect the "Flow control" (can be any) to "none". But never unplug the USB else...

 

What is wrong in the firmware ?

Variable Frequency Output

$
0
0

How to change the output frequency of the analogWrite() function in Energia??


Writing C Code in Energia

$
0
0

Hi Everyone!

 

I've just received a Tiva C launchpad and was wondering if you are able to write C code in Energia or if you have to use their Processing-based language?  And if not, is there a way to use just write C code on Mac OS X (with or without an IDE) and upload it to the device?  After a quick search of this forum and Google, most C compilers are meant for a  Windows environment and I haven't been able to find much information for OS X other than Energia or possibly embedXCode.

 

Thanks,

Miles

MSP-EXP430F5529LP Out-of-Box Demo for Energia?

$
0
0

Hi everyone,

has anyone successfully ported the Out-of-Box Demo (emulStorageKeyboard) that came with the F5529 Launchpad to Energia?

 

Especially the storage emulation part interests me, cause i intend to use the F5529 Launchpad with the CC3000 as an embedded Webserver and uploading images and html pages to the usb storage qould be quite comfortable.

 

best regards,

Nick

[ADMIN]MSP430G2553

Using interrupts

$
0
0

The documentation for the attachInterrupt function states:

 

 

Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost.

 

What about micros(), does it work?

 

I can understand these limitations for the lower end MSP430s but what about the 5529, Tiva-C and C2000?  Do they have the same limitations?  Any chance the interrupt handling could be enhanced on the higher end MCUs?

 

 

Also, any chance at timer interrupts in Energia or will that always need to be done something like this http://forum.stellarisiti.com/topic/1754-interrupt-handler-in-energia/

 

Thanks,

RF-BSL?

$
0
0

Hi - I've been trying to find the source of the RF-BSL used by the Chronos watch - probably looking in the wrong place as I'm a bit new to this...

 

Anyone know if it was released and if so, where can I find it? (the source, that is...)

 

Thanks

 

Nick

 

Viewing all 2077 articles
Browse latest View live