Simplifying MSP430G2 Programming

I just started playing with TI’s MSP430 LaunchPad (MSP-EXP430G2) a few weeks ago and have found it surprisingly capable so far. But having to remember all those register names is not an easy task, especially if you do not use it often. So, inspired by this article (Header file brings Arduino sketches to the TI Launchpad) on Hack A Day, I decided to write a few functions that can simplify some of the more mundane tasks.

Here are some of the most used functions I have come up so far. Even though these functions were written specifically for the MSP430G2231 chip I have at hand, they can work with any MSP430G2 value line chips that support the specified functionality.

Here is the code listing for MSP430G2231Library.h (compiled using TI’s Code Composer Studio 5.1):

#ifndef MSP430G2231LIBRARY_H_
#define MSP430G2231LIBRARY_H_

#include <msp430.h>

#define HIGH 1
#define LOW  0
#define OUTPUT 1
#define INPUT 0

#define REF_INT_1_5 0
#define REF_INT_2_5 1
#define REF_EXT_VCC 2

/**
 * Stop the Watch Dog Timer
 */
void inline stopWatchDogTimer() {
	WDTCTL = WDTPW + WDTHOLD;
}

/**
 * Initialize DCO to the calibrated 1Mhz
 */
void inline initDCO1Mhz() {
	BCSCTL2 = SELM_0 + DIVM_0 + DIVS_0;

	if (CALBC1_1MHZ != 0xFF) {
		DCOCTL = 0x00;
		BCSCTL1 = CALBC1_1MHZ;
		DCOCTL = CALDCO_1MHZ;
	}

	BCSCTL1 |= XT2OFF + DIVA_0;
	BCSCTL3 = XT2S_0 + LFXT1S_0 + XCAP_1;
}

/**
 * Initialize DCO according to DCO and RSEL
 * Example: DCO = DCO1 + DCO2 + DCO3
 * 			RSEL= RSEL0 + RSEL1 + RSEL2 + RSEL3
 */
void inline initDCO(int DCO, int RSEL) {
	DCOCTL = DCO;
	BCSCTL1 = XT2OFF + DIVA_0 + RSEL;
	BCSCTL2 = SELM_0 + DIVM_0 + DIVS_0;
	BCSCTL3 = XT2S_0 + LFXT1S_0 + XCAP_1;
}

/**
 * Initialize the external crystal oscillator
 * (32768 Hz)
 */
void inline initCrystalOSC() {
	BCSCTL2 = SELM_3 + DIVM_0 + SELS + DIVS_0;
	BCSCTL1 = XT2OFF + DIVA_0;
	BCSCTL3 = XT2S_0 + LFXT1S_0 + XCAP_1;
}

/**
 * Set the pin mode
 * portNo: port (1 or 2)
 * pinNo: pin number in the port specified
 * pinMode: INPUT/OUTPUT
 */
void pinMode(int portNo, int pinNo, int pinMode) {
	if (portNo == 1) {
		if (pinMode)
			P1DIR |= (1 << pinNo);
		else
			P1DIR &= ~(1 << pinNo);
	} else if (portNo == 2) {
		if (pinMode)
			P2DIR |= (1 << pinNo);
		else
			P2DIR &= ~(1 << pinNo);
	}
}

/**
 * Write HIGH or LOW to a pin previously set as output
 * portNo: port (1 or 2)
 * pinNo: pin number in the port specified
 * value: HIGH/LOW
 */
void digitalWrite(int portNo, int pinNo, int value) {
	if (portNo == 1) {
		if (value)
			P1OUT |= 1 << pinNo;
		else
			P1OUT &= ~(1 << pinNo);
	} else if (portNo == 2) {
		if (value)
			P2OUT |= 1 << pinNo;
		else
			P2OUT &= ~(1 << pinNo);
	}
}

/**
 * Read logic level from pin
 * portNo: port (1 or 2)
 * pinNo: pin number in the port specified
 */
int digitalRead(int portNo, int pinNo) {
    int result;

    result = 0;

    if (portNo == 1) {
        result = (P1IN & (1 << pinNo)) >> pinNo;
    } else if (portNo == 2) {
        result = (P2IN & (1 << pinNo)) >> pinNo;
    }

    return result;
}

/**
 * Initialize ADC10 for continues sampling
 * referenceType: REF_INT_1_5, REF_INT_2_5 or REF_EXT_VCC
 * ADCPin: the pin number for ADC operations
 */
void initADC10(int referenceType, int ADCPin) {
	int refType, refSelect;

	if (referenceType == REF_INT_2_5) {
		refType = REF2_5V;
		refSelect = SREF_1;
	} else if (referenceType == REF_INT_1_5) {
		refType = 0;
		refSelect = SREF_1;
	} else if (referenceType == REF_EXT_VCC) {
		refType = 0;
		refSelect = SREF_0;
	}

	ADC10CTL0 &= ~ENC;
	ADC10CTL0 = ADC10ON + REFON + refType + ADC10SHT_0 + refSelect;
	ADC10CTL1 = CONSEQ_2 + ADC10SSEL_0 + ADC10DIV_0 + SHS_0 + ADCPin * 0x1000u;
	ADC10AE0 = 0x2;
	__delay_cycles(30000);
	ADC10CTL0 |= ENC;
}

/**
 * Get the ADC result from ADCPin defined in 
 * initADC10.
 */
int readADC() {
	int t;

	ADC10CTL0 |= ENC + ADC10SC;
	while ((ADC10CTL0 & ADC10IFG) == 0);
	t = ADC10MEM;

	ADC10CTL0 &= ~ADC10SC;
	ADC10CTL0 |= ADC10IFG;

	return t;
}
#endif /* MSP430G2231LIBRARY_H_ */

The code above includes DCO/Crystal initialization routines. It also includes a few Arduino like functions (pinMode, digitalRead and digitalWrite). But I decided to go with the Port.Bit format instead of just a pin number since the Port.Bit information is printed on the launchpad itself and it is easier to reference that way. Finally, I included a couple of ADC routines that work with both the internal and external voltage references. The ADC routines shown above handles only one channel at a time for the time being.

I am planning on expanding this code to include more features in the near future.

Be Sociable, Share!

Leave a Reply