Jump to content
dubnet

MSP430F149 Board

Recommended Posts

A while back @omnicron generously offered up some surplus boards sporting a MSP430F149 and a good mix of conditioned I/O on the board including a couple of 5.8psi pressure transducers.  I feel that this, along with the programming header on the board, makes it a good all-around board for general purpose projects. The board also supports a standby NiMH battery (6v, 1800mAh) with charging/discharging capability and voltage monitoring all controlled by the MCU.  The battery switches in via a relay upon primary power loss. One of the pushbuttons is configured in hardware to be used as a soft power on/off and requires just a little bit of code to work.

One of the concerns upon getting the board is that, even though it has a programming header, the fuse may have been blown to protect the original code.  With the fuse setup on the MSP430F149 that would be a show stopper and the board would have been a paper weight. Thankfully, when I connected my MSP-FET I was able to talk to the MCU as well as program it.

So what does one do when presented with a new piece of hardware?  Write code to flash LEDs and exercise the hardware, of course.  Since I wanted to make this a general purpose, “throw it at a project” kind of board, I wanted to write some functions to simplify the main program code.  So far I have routines for digital I/O, analog in, chip temperature and a function to display a binary result on the eight LEDs on the board.

One downside to the way this particular board was designed is the lack of easily accessible serial ports.  One way around this is to solder directly to the MCU pins to utilize the secondary serial ports , but that wasn't very attractive.  Looking at the schematic I found that by removing three passives from each of the two serial lines, I could repurpose what were originally a couple of digital outputs and have a serial port (UART only, no I2C on this MCU).  SPI is also possible using the same technique, but a little more cumbersome to implement. I haven't written the functions for serial yet and will probably wait until I actually need serial I/O.

The video demonstrates my demo code that utilizes soft power using the switch shown at the bottom left.  Default power up behavior is the 8 LEDs chasing up and down.  The next switch to the right of the power switch toggles the beeper which, when activated, sounds every time the LED furthest to the left (LSB) lights up.  The next switch to the right toggles the speed of the LEDs and the final button displays the chip temp in binary (75 degrees in this case), pauses to allow it to be read and then resumes the LED chasing. There… hardware reasonably exercised.  J

I have included pictures of the front and back of the board as well as a PDF schematic.

If you have the inclination I welcome feedback on the code and the resulting opportunity to learn to code more efficiently.

// Since I used portions of TI’s MSP430ware examples in two functions (chiptemp and analogIN) I am
//including the TI copyright notice below:

/* --COPYRIGHT--,BSD_EX
 * Copyright (c) 2012, Texas Instruments Incorporated
 * All rights reserved.
 *
 * 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.
 *
 *******************************************************************************
 * 
 *                       MSP430 CODE EXAMPLE DISCLAIMER
 *
 * MSP430 code examples are self-contained low-level programs that typically
 * demonstrate a single peripheral function or device feature in a highly
 * concise manner. For this the code may rely on the device's power-on default
 * register values and settings such as the clock configuration and care must
 * be taken when combining code from several examples to avoid potential side
 * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
 * for an API functional library-approach to peripheral configuration.
 *
 * --/COPYRIGHT--*/

#include <msp430.h> 

#define	  ana_ch_a			0x01		// Port 6.0, A0
#define	  ana_ch_b			0x02		// Port 6.1, A1
#define   ana_batt			0x03		// Port 6.2, A2
#define   ana_9v			0x04		// Port 6.3, A3
#define   ON				0x01
#define   OFF				0x00
#define   LED_1				0x01		// Port 2.0
#define   LED_2				0x02		// Port 2.1
#define   LED_3				0x03		// Port 2.2
#define   LED_4				0x04		// Port 2.3
#define   LED_5				0x05		// Port 2.4
#define   LED_6				0x06		// Port 2.5
#define   LED_7				0x07		// Port 2.6
#define   LED_8				0x08		// Port 2.7
#define   LED_9				0x09		// Port 3.0
#define   LED_10			0x0A		// Port 3.1
#define   valve_a			0x0B		// Port 3.2
#define   valve_b			0x0C		// Port 3.3
#define   pump_a			0x0D		// Port 3.4
#define   pump_b			0x0E		// Port 3.5
#define   charge			0x0F		// Port 3.6
#define   discharge			0x10		// Port 3.7
#define   beep				0x11		// Port 4.0
#define   chkbatt			0x12		// Port 4.1
#define   VCCEN				0x13		// Port 4.2

//array and variables to support functions
const int BitValue[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
unsigned int var1;
unsigned int var2;
unsigned int var3;
unsigned int var4;
unsigned int a;
unsigned int b;
unsigned int c;
unsigned int ADCvalue;
int long IntDegF;

void PostLEDValue (unsigned int Var4);
void chiptemp(int long degree_f);
void analogIN(unsigned int var3);  			 				// values= ana_ch_a/b, ana_batt, ana_9v
void digitalWrite(unsigned int var1, unsigned int var2);	// values = LED_1-10, valve_a/b,  pump_a/b, beep, charge, discharge, chkbatt, VCCEN, and var2 = ON, OFF

volatile unsigned int i=0;
unsigned int led_count;
volatile unsigned int j;
unsigned int l=2;
unsigned int sw_press = 0;
unsigned int beep_status = 0;
unsigned int speed = 6000;
int long temp;

void main() {
	WDTCTL = WDTPW + WDTHOLD;
	DCOCTL = DCO0 + DCO1;  					
	BCSCTL1 = RSEL0 + RSEL1 + RSEL2;    	

	P1DIR |= 0x00;							
	P4DIR |= BIT0 + BIT1 + BIT2;			
	P4OUT |= 0x00;							
	P4OUT |= 0x04;							// Set P4.4 to 1 (VCCEN)
	P2DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7;
	P2OUT &=~(BIT0+BIT1+BIT2+BIT3+BIT4+BIT5+BIT6+BIT7);
	P2OUT |= (BIT0+BIT1+BIT2+BIT3+BIT4+BIT5+BIT6+BIT7)& 0xFF;
	P3DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7;
	P3OUT &=~(BIT0+BIT1+BIT2+BIT3+BIT4+BIT5+BIT6+BIT7);
	P3OUT |= (BIT0 + BIT1) & 0xF;

	P1IES |= 0x00;
	P1IFG |= 0x00;
	P1IE |= (BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7);
	_enable_interrupt();


//  MAIN CODE STARTS HERE ----------------------------------------------------------

l=2;
do {
	led_count = 11;
	do {
		led_count--;
				j = speed;                              // Delay 6000 or 1500
				do (j--);
				while (j != 0);
				if (led_count == 9){
					led_count = 8;}
				if (led_count == 7){
					led_count = 6;}
		digitalWrite(led_count, ON);
    	} while (led_count != 1);

	i = 45000; do (i--); while (i != 0);

	if (sw_press == 3) {						// Toggle beep at LSB transistion
		beep_status ^= 0x01;				
		sw_press = 0;
	}
	digitalWrite(beep, beep_status);

	i = 5000; do (i--); while (i != 0);       	// Delay 5000

	digitalWrite(beep, OFF);

	if(sw_press == 1) {							// Soft Power Down
		P4OUT ^= 0x04;
		sw_press = 0;}

	if (sw_press == 4 && speed == 6000) {		//Toggle LED chase speed
		speed = 1500;
		sw_press = 0;}

	if (sw_press == 4 && speed == 1500) {
		speed = 6000;
		sw_press = 0;}


	if (sw_press == 5) {
		sw_press = 0;
		chiptemp(0);}

	led_count = 0;
		  do {
			  led_count++;
			  	  j = speed;                  	// Delay 6000 or 1500
			  	  do (j--);
			  	  while (j != 0);
			  	  if (led_count == 7){
			  		  led_count = 8;}
			  	  if (led_count == 9){
			  		  led_count = 10;}
			  digitalWrite(led_count, OFF);
		    	} while (led_count != 10);

	i = 50000; do (i--); while (i != 0);         // Delay 50000

}
while (l != 0);
}

//  MAIN CODE ENDS HERE ------------------------------------------------------------------------------------

#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void){

	_disable_interrupt();

	if(P1IFG & BIT0) {
		sw_press = 1;
		P1IFG &= ~BIT0;
	}
	if(P1IFG & BIT1) {
		sw_press = 2;
		P1IFG &= ~BIT1;
	}
	if(P1IFG & BIT2) {
		sw_press = 3;
		P1IFG &= ~BIT2;
	}
	if(P1IFG & BIT3) {
		sw_press = 4;
		P1IFG &= ~BIT3;
	}
	if(P1IFG & BIT4) {
		sw_press = 5;
		P1IFG &= ~BIT4;}

	if(P1IFG & BIT5) {
		sw_press = 6;
		P1IFG &= ~BIT5;
	}
	if(P1IFG & BIT6) {
		sw_press = 7;
		P1IFG &= ~BIT6;
	}
	if(P1IFG & BIT7) {
		sw_press = 8;
		P1IFG &= ~BIT7;
	}
	_enable_interrupt();
}

#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void) {

	_disable_interrupt();
	temp = ADC12MEM0;                       
	_enable_interrupt();
}

// FUNCTIONS BEGIN HERE --------------------------------------------------------------------------------------------

void digitalWrite(unsigned int var1, unsigned int var2){

a=0;
b=0;
c=0;

if (var1 <= 0x0A){		//Flip ON/OFF on LED outputs since they are active low.
	var2 ^= 0x01;}

if (var1 >= 0x10 && var1 <= 0x13){
	c = (var1-17);
		if (var2==1){
			a=P4OUT;
			a=a|(BitValue[c]);
			P4OUT=a;}
		if (var2==0){
			a=P4OUT;
			b=~(BitValue[c]);
			P4OUT = (a&b);}
}

if (var1 >= 0x09 && var1 <= 0x10){
	c = (var1-9);
		if (var2==1){
			a=P3OUT;
			a=a|(BitValue[c]);
			P3OUT=a;}
		if (var2==0){
			a=P3OUT;
			b=~(BitValue[c]);
			P3OUT = (a&b);}
}

if (var1 >= 0x01 && var1 <= 0x08){
	c = (var1-1);
		if (var2==1){
			a=P2OUT;
			a=a|(BitValue[c]);
			P2OUT=a;}
		if (var2==0){
			a=P2OUT;
			b=~(BitValue[c]);
			P2OUT = (a&b);}
}
}

void chiptemp (long int degree_f) {

ADC12CTL0 = SHT0_8 + REFON + ADC12ON;
ADC12CTL1 = SHP;
ADC12MCTL0 = SREF_1 + INCH_10;
ADC12IE = 0x001;
ADC12CTL0 |= ENC;
ADC12CTL0 |= ADC12SC;

i = 5000; do (i--); while (i != 0);

IntDegF = (temp - 2519) * 761;
IntDegF = IntDegF / 4096;
temp = 0;

degree_f = IntDegF;
PostLEDValue (degree_f);
}

void PostLEDValue (unsigned int var4){

led_count = 0;
  do {
  led_count++;
  j = 250; do (j--); while (j != 0);       // turn off LEDs
  if (led_count == 7){
	  led_count = 8;}
  if (led_count == 9){
	  led_count = 10;}
  digitalWrite(led_count, OFF);
  } while (led_count != 10);

if (var4 > 64){
	var4 = var4 - 64;
	digitalWrite(LED_8, ON);
}
if (var4 > 32) {
	var4 = var4 - 32;
	digitalWrite(LED_6, ON);
}
if (var4 > 16) {
	var4 = var4 - 16;
	digitalWrite(LED_5, ON);
}
if (var4 > 8) {
	var4 = var4 - 8;
	digitalWrite(LED_4, ON);
}
if (var4 > 4) {
	var4 = var4 - 4;
	digitalWrite(LED_3, ON);
}
if (var4 > 2) {
	var4 = var4 - 2;
	digitalWrite(LED_2, ON);
}
if (var4 == 1) {
	digitalWrite(LED_1, ON);
}

j = 20;							//delay to allow reading of LEDs
do {
i = 50000; do (i--); while (i != 0);
j--;
} while (j != 0);
}

void analogIN (unsigned int var3){

ADC12CTL0 = SHT0_8 + REFON + ADC12ON;
ADC12CTL1 = SHP;
if (var3==1){
	  ADC12MCTL0 = SREF_1 + INCH_0;
}
if (var3==2){
	  ADC12MCTL0 = SREF_1 + INCH_1;
}
if (var3==3){
	  ADC12MCTL0 = SREF_1 + INCH_2;
}
if (var3==4){
	  ADC12MCTL0 = SREF_1 + INCH_3;
}
ADC12MCTL0 = SREF_1 + INCH_10;
ADC12IE = 0x001;
ADC12CTL0 |= ENC;
ADC12CTL0 |= ADC12SC;

i = 5000; do (i--); while (i != 0);

ADCvalue = (temp/16);
PostLEDValue (ADCvalue);
}
-

 

 

clear_PCB_back_-_Copy.JPG

clear_PCB_front_-_Copy.JPG

Circuit Diagram.pdf

Demo_Program_Video.MOV

Share this post


Link to post
Share on other sites

HI @dubnet

It looks like you had fun with that :smile:.  The code is easy to read and looks good to me.  You can try using a switch statement in the ISR - something like this:


//-----------------------  G P I O _ P O R T 1 _ I S R  ------------------------

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

#pragma vector=PORT1_VECTOR

__interrupt

#elif defined(__GNUC__)

__attribute__((interrupt(PORT1_VECTOR)))

#endif

void GPIO_PORT1_ISR(void)

{

    switch(P1IV)

    {

		case  0: break;                              //no interrupt pending

		case  2: break;                              //P1.0

		case  4: break;                              //P1.1

		case  6:                                     //P1.2

			GPIO_toggleOutputOnPin(RED_LED);

			break;

		case  8:                                     //P1.3

			GPIO_toggleOutputOnPin(GREEN_LED);

			break;

		case 10: break;                              //P1.4

		case 12: break;                              //P1.5

		case 14: break;                              //P1.6

		case 16: break;                              //P1.7

		default: break;                              //should not get here

    }

}

The TI examples in their MSP430 training videos use this approach.

Share this post


Link to post
Share on other sites

@Fmilburn  Thanks for the feedback.  I did a little bit of research on the tradeoffs between the two methods, both from a readability standpoint and a performance standpoint.  It wins on the readability and can be faster executing in many cases than the if/then approach.  I will "switch" :laugh:  the code the next time I work on it. 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×