Skip to content

Instantly share code, notes, and snippets.

@RickKimball
Created July 1, 2011 04:08
Show Gist options
  • Save RickKimball/1057857 to your computer and use it in GitHub Desktop.
Save RickKimball/1057857 to your computer and use it in GitHub Desktop.
MSP-EXP430FR5739 - Demo program modified for msp430-gcc uniarch
/*******************************************************************************
*
* FR_EXP.c
* User Experience Code for the MSP-EXP430FR5739
* C Functions File
*
* Copyright (C) 2010 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.
*
* Created: Version 1.0 04/13/2011
* Version 1.1 05/11/2011
*
******************************************************************************/
#include "msp430fr5739.h"
#include "FR_EXP.h"
extern volatile unsigned int ADCResult;
extern volatile unsigned char active;
extern volatile unsigned char ULP;
extern volatile unsigned char mode;
extern volatile unsigned char UserInput;
volatile unsigned char TX_Buffer[7] = {0,0,0,0,0,0,0};
volatile unsigned char ThreshRange[3]={0,0,0};
unsigned char counter =0;
unsigned int WriteCounter = 0;
unsigned int LEDCounter=0;
unsigned char ULPBreakSync =0;
unsigned int ModeAddress=0;
unsigned int CalValue =0;
unsigned int ADCTemp =0;
unsigned char temp = 0;
/**********************************************************************//**
* @brief Initializes system
*
* @param none
*
* @return none
*************************************************************************/
void SystemInit(void)
{
// Startup clock system in max. DCO setting ~8MHz
// This value is closer to 10MHz on untrimmed parts
CSCTL0_H = 0xA5; // Unlock register
CSCTL1 |= DCOFSEL0 + DCOFSEL1; // Set max. DCO setting
CSCTL2 = SELA_1 + SELS_3 + SELM_3; // set ACLK = vlo; MCLK = DCO
CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0; // set all dividers
CSCTL0_H = 0x01; // Lock Register
// Turn off temp.
REFCTL0 |= REFTCOFF;
REFCTL0 &= ~REFON;
// Enable switches
// P4.0 and P4.1 are configured as switches
// Port 4 has only two pins
P4OUT |= BIT0 +BIT1; // Configure pullup resistor
P4DIR &= ~(BIT0 + BIT1); // Direction = input
P4REN |= BIT0 + BIT1; // Enable pullup resistor
P4IES &= ~(BIT0+BIT1); // P4.0 Lo/Hi edge interrupt
P4IE = BIT0+BIT1; // P4.0 interrupt enabled
P4IFG = 0; // P4 IFG cleared
// Enable LEDs
P3OUT &= ~(BIT6+BIT7+BIT5+BIT4);
P3DIR |= BIT6+BIT7+BIT5+BIT4;
PJOUT &= ~(BIT0+BIT1+BIT2+BIT3);
PJDIR |= BIT0 +BIT1+BIT2+BIT3;
// Terminate Unused GPIOs
// P1.0 - P1.6 is unused
P1OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3 + BIT5 + BIT6 + BIT7);
P1DIR &= ~(BIT0 + BIT1 + BIT2 + BIT3 + BIT5 + BIT6 + BIT7);
P1REN |= (BIT0 + BIT1 + BIT2 + BIT3 + BIT5 + BIT6 + BIT7);
// P1.4 is used as input from NTC voltage divider
// Set it to output low
P1OUT &= ~BIT4;
P1DIR |= BIT4;
// P2.2 - P2.6 is unused
P2OUT &= ~(BIT2 + BIT3 + BIT4 + BIT5 + BIT6);
P2DIR &= ~(BIT2 + BIT3 + BIT4 + BIT5 + BIT6);
P2REN |= (BIT2 + BIT3 + BIT4 + BIT5 + BIT6);
// Configure UART pins P2.0 & P2.1
P2SEL1 |= BIT0 + BIT1;
P2SEL0 &= ~(BIT0 + BIT1);
// P2.7 is used to power the voltage divider for the NTC thermistor
P2OUT &= ~BIT7;
P2DIR |= BIT7;
// P3.0,P3.1 and P3.2 are accelerometer inputs
P3OUT &= ~(BIT0 + BIT1 + BIT2);
P3DIR &= ~(BIT0 + BIT1 + BIT2);
P3REN |= BIT0 + BIT1 + BIT2;
// PJ.0,1,2,3 are used as LEDs
// crystal pins for XT1 are unused
PJOUT &= ~(BIT4+BIT5);
PJDIR &= ~(BIT4+BIT5);
PJREN |= BIT4 + BIT5;
}
/**********************************************************************//**
* @brief Startup LED sequence
*
* @param none
*
* @return none
*************************************************************************/
void StartUpSequence(void)
{
unsigned char flag=4,up=1,counter = 0;
unsigned char LED_ArrayPJ[] = {0x01,0x02,0x04,0x08};
unsigned char LED_ArrayP3[] = {0x80,0x40,0x20,0x10};
while (counter <10)
{
counter++;
PJOUT &= ~(BIT0 +BIT1+BIT2+BIT3);
P3OUT &= ~(BIT4 +BIT5+BIT6+BIT7);
if(up)// from the outside - in
{
while(flag)
{
P3OUT = LED_ArrayP3[flag-1];
PJOUT = LED_ArrayPJ[flag-1];
LongDelay();
flag--;
}
up=0;
}
else
{
while(flag<4)
{
P3OUT = LED_ArrayP3[flag];
PJOUT = LED_ArrayPJ[flag];
LongDelay();
flag++;
}
up = 1;
}
}
// Exit Loop, Clear LEDs
PJOUT &= ~(BIT0 +BIT1+BIT2+BIT3);
P3OUT &= ~(BIT4 +BIT5+BIT6+BIT7);
}
/**********************************************************************//**
* @brief Mode 1
*
* @param none
*
* @return none
*************************************************************************/
void Mode1(void)
{
// Check FR_EXP.h for FRAM Scratch Pad locations
// Setup FRAM Test storage pointer for Modes 1&2
ModeAddress = FRAM_TEST_START-MEM_UNIT;
// One time initialization of header and footer transmit package
TX_Buffer[0] = 0xFA;
TX_Buffer[6] = 0xFE;
// Variable initialization
active = 1;
counter = 0;
WriteCounter=0;
LEDCounter = 0;
ULPBreakSync = 0;
while((mode == MAX_FRAM_WRITE) && (UserInput == 0))
{
// 512 byte FRAM Writes
// Update ModeAddress
if (ModeAddress < FRAM_TEST_END)
ModeAddress += MEM_UNIT;
else
ModeAddress = FRAM_TEST_START;
// Use updated mode address for FRAM Write
FRAM_Write(ModeAddress);
WriteCounter++;
LEDCounter++;
// Every function call writes 512 bytes
// Every 100KByte write, cycle the LED position
if (LEDCounter > 199)
{
LEDCounter = 0;
counter++;
if(counter == 8)
counter = 0;
}
// Check if LEDs need to be turned off to measure power
if((ULP ==1) && (UserInput == 0))
{
// P3.4- P3.7 are set as output, low
P3OUT &= ~(BIT4 + BIT5 + BIT6 + BIT7);
P3DIR |= BIT4 + BIT5 + BIT6 + BIT7;
// PJ.0,1,2,3 are set as output, low
PJOUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
PJDIR |= BIT0 + BIT1 + BIT2 + BIT3;
// send this one time to allow the GUI to freeze the update
if(!(ULPBreakSync))
{
TXBreak(mode);
ULPBreakSync++;
}
}
if((ULP ==0) && (UserInput == 0))
{
ULPBreakSync =0;
// Update the LED sequence
// only if no switch press occured (check again)
LEDSequenceWrite(counter);
// Send out UART Bytes every 100KB
if (WriteCounter > 199)
{
WriteCounter = 0;
// Transmit 7 Bytes
// Prepare mode-specific data
// Standard header and footer
TX_Buffer[1] = 0x01;
TX_Buffer[2] = counter;
TX_Buffer[3] = 0x00;
TX_Buffer[4] = 0x00;
TX_Buffer[5] = 0x00;
TXData();
}
}
}
//end of while()loop
}
/**********************************************************************//**
* @brief Mode 2
*
* @param none
*
* @return none
*************************************************************************/
void Mode2(void)
{
// Check FR_EXP.h for FRAM Scratch Pad locations
// Setup FRAM Test storage pointer for Modes 1&2
ModeAddress = FRAM_TEST_START-MEM_UNIT;
// One time initialization of header and footer transmit package
TX_Buffer[0] = 0xFA;
TX_Buffer[6] = 0xFE;
// Variable initialization
active = 1;
counter = 0;
WriteCounter =0;
LEDCounter = 0;
ULPBreakSync = 0;
// startup tick for ~12kBps writes
// ACLK = VLO = ~12.5KHz
// Every write = 512 bytes
// # of bytes/sec = 512*1/(TACCRx/fvlo)
TA0CCTL0 = CCIE; // TACCR0 interrupt enabled
TA0CCR0 = 350;
TA0CTL = TASSEL_1 + MC_1; // ACLK, up mode
// setup write mode
while((mode == SLOW_FRAM_WRITE) && (UserInput == 0))
{
// VLO stays on in LPM4
__bis_SR_register(LPM4_bits + GIE);
__no_operation();
// wakeup to write a segment
// Check status and Update MODE2_address
if (ModeAddress < FRAM_TEST_END)
ModeAddress += MEM_UNIT;
else
{ // end of memory - startover
ModeAddress = FRAM_TEST_START;
}
// Use updated mode address for FRAM Write
FRAM_Write(ModeAddress);
WriteCounter++;
LEDCounter++;
// Every 100KByte write, cycle the LED position
// 1 cycle = 512 bytes; 200 cycles = 100KB
if (LEDCounter > 199)
{
LEDCounter = 0;
counter++;
if (counter == 8)
counter = 0;
}
if((ULP == 1) && (UserInput == 0))
{
// P3.4- P3.7 are set as output, low
P3OUT &= ~(BIT4 + BIT5 + BIT6 + BIT7);
P3DIR |= BIT4 + BIT5 + BIT6 + BIT7;
// PJ.0,1,2,3 are set as output, low
PJOUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
PJDIR |= BIT0 + BIT1 + BIT2 + BIT3;
// Transmit break packet for GUI freeze
if(!(ULPBreakSync))
{
TXBreak(mode);
ULPBreakSync++;
}
}
if((ULP == 0) && (UserInput == 0))
{
ULPBreakSync =0;
// Update the LED sequence & UART output
// Only if S1 is not pressed; else quit
LEDSequenceWrite(counter);
// Send out UART bytes every 2KB
// No. of bytes = 4 * 512 = 2KB
if (WriteCounter>3)
{
WriteCounter = 0;
// Transmit 7 Bytes
// Prepare mode-specific data
// Standard header and footer
TX_Buffer[1] = 0x02;
TX_Buffer[2] = counter;
TX_Buffer[3] = 0x00;
TX_Buffer[4] = 0x00;
TX_Buffer[5] = 0x00;
TXData();
}
}
}
// end of while() loop
// Quitting; because user pressed a switch
TA0CTL = 0;
TA0CCTL0 = 0;
}
void Mode3(void)
{
// One time initialization of header and footer transmit package
TX_Buffer[0] = 0xFA;
TX_Buffer[6] = 0xFE;
// variable initialization
active = 1;
ADCTemp = 0;
temp = 0;
WriteCounter = 0;
ULPBreakSync = 0;
counter = 0;
// One time setup and calibration
SetupAccel();
CalValue = CalibrateADC();
while ((mode == ACCEL_MEAS) && (UserInput == 0))
{
// Take 1 ADC Sample
TakeADCMeas();
if (ADCResult >= CalValue)
{
temp = DOWN;
ADCTemp = ADCResult - CalValue;
}
else
{
temp = UP;
ADCTemp = CalValue - ADCResult;
}
if((ULP==1) && (UserInput == 0))
{
// P3.4- P3.7 are set as output, low
P3OUT &= ~(BIT4 + BIT5 + BIT6 + BIT7);
P3DIR |= BIT4 + BIT5 + BIT6 + BIT7;
// PJ.0,1,2,3 are set as output, low
PJOUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
PJDIR |= BIT0 + BIT1 + BIT2 + BIT3;
// Transmit break packet for GUI freeze
if(!(ULPBreakSync))
{
TXBreak(mode);
ULPBreakSync++;
}
}
if((ULP==0) && (UserInput == 0))
{
ULPBreakSync = 0;
WriteCounter++;
if(WriteCounter > 300)
{
LEDSequence(ADCTemp,temp);
// Every 300 samples
// Transmit 7 Bytes
// Prepare mode-specific data
// Standard header and footer
WriteCounter = 0;
TX_Buffer[1] = 0x03;
TX_Buffer[2] = counter;
TX_Buffer[3] = 0x00;
TX_Buffer[4] = 0x00;
TX_Buffer[5] = 0x00;
TXData();
}
}
}
// end while() loop
// turn off Accelerometer for low power
ShutDownAccel();
}
void Mode4(void)
{
// One time initialization of header and footer transmit package
TX_Buffer[0] = 0xFA;
TX_Buffer[6] = 0xFE;
// variable initialization
ADCTemp = 0;
temp = 0;
WriteCounter = 0;
active = 1;
ULPBreakSync = 0;
counter = 0;
// One time setup and calibration
SetupThermistor();
CalValue = CalibrateADC();
while((mode == TEMP_MEAS) && (UserInput == 0))
{
// Take 1 ADC Sample
TakeADCMeas();
if (ADCResult >= CalValue)
{
temp = DOWN;
ADCTemp = ADCResult - CalValue;
}
else
{
temp = UP;
ADCTemp = CalValue - ADCResult;
}
if((ULP==1) && (UserInput == 0))
{
// P3.4- P3.7 are set as output, low
P3OUT &= ~(BIT4 + BIT5 + BIT6 + BIT7);
P3DIR |= BIT4 + BIT5 + BIT6 + BIT7;
// PJ.0,1,2,3 are set as output, low
PJOUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
PJDIR |= BIT0 + BIT1 + BIT2 + BIT3;
// Transmit break packet for GUI freeze
if(!(ULPBreakSync))
{
TXBreak(mode);
ULPBreakSync++;
}
}
if((ULP==0) && (UserInput == 0))
{
ULPBreakSync = 0;
WriteCounter++;
if(WriteCounter > 300)
{
LEDSequence(ADCTemp,temp);
// Every 300 samples
// Transmit 7 Bytes
// Prepare mode-specific data
// Standard header and footer
WriteCounter = 0;
TX_Buffer[1] = 0x04;
TX_Buffer[2] = counter;
TX_Buffer[3] = 0x00;
TX_Buffer[4] = 0x00;
TX_Buffer[5] = 0x00;
TXData();
}
}
}
// turn off Thermistor bridge for low power
ShutDownTherm();
}
/**********************************************************************//**
* @brief Performs 512 byte FRAM Write
*
* @param StartAddress: For FRAM Write
*
* @return none
*************************************************************************/
void FRAM_Write(unsigned int StartAddress)
{
unsigned long *FRAM_write_ptr;
unsigned long data = 0x12345678;
unsigned int i=0;
//Incase FRAM Write Address is corrupted, exit loop
if((StartAddress >= FRAM_TEST_START) && (StartAddress < FRAM_TEST_END))
{
// Setup FRAM pointer
FRAM_write_ptr = (unsigned long *) StartAddress;
// Write 128 * 4 = 512 bytes
for ( i= 0; i<128; i++)
{
*FRAM_write_ptr++ = data;
}
}
}
/**********************************************************************//**
* @brief LED Toggle Sequence for FRAM Writes
*
* @param
* sequence flag
*
* @return none
*************************************************************************/
void LEDSequenceWrite(unsigned char flag)
{
// The LED sequence fills p based on flag value
unsigned char LED_ArrayPJ[] = {0x08,0x0C,0x0E,0x0F};
unsigned char LED_ArrayP3[] = {0x80,0xC0,0xE0,0xF0};
// LED Sequencing for FRAM writes
if (flag <4)
{
PJOUT &= ~(BIT0 +BIT1+BIT2+BIT3);
P3OUT &= ~(BIT4 +BIT5+BIT6+BIT7);
P3OUT |= LED_ArrayP3[flag];
}
else
{
PJOUT &= ~(BIT0 +BIT1+BIT2+BIT3);
P3OUT &= ~(BIT4 +BIT5+BIT6+BIT7);
// Keep the entire P3 array on
P3OUT |= LED_ArrayP3[3];
PJOUT |= LED_ArrayPJ[flag-4];
}
}
/**********************************************************************//**
* @brief Calibrate thermistor or accelerometer
*
* @param none
*
* @return none
*************************************************************************/
unsigned int CalibrateADC(void)
{
unsigned char CalibCounter =0;
unsigned int Value = 0;
// Disable interrupts & user input during calibration
DisableSwitches();
while(CalibCounter <50)
{
P3OUT ^= BIT4;
CalibCounter++;
while (ADC10CTL1 & BUSY);
ADC10CTL0 |= ADC10ENC | ADC10SC ; // Start conversion
__bis_SR_register(CPUOFF + GIE); // LPM0, ADC10_ISR will force exit
__no_operation();
Value += ADCResult;
}
Value = Value/50;
// Reenable switches after calibration
EnableSwitches();
return Value;
}
/**********************************************************************//**
* @brief Take ADC Measurement
*
* @param none
*
* @return none
*************************************************************************/
void TakeADCMeas(void)
{
while (ADC10CTL1 & BUSY);
ADC10CTL0 |= ADC10ENC | ADC10SC ; // Start conversion
__bis_SR_register(CPUOFF + GIE); // LPM0, ADC10_ISR will force exit
__no_operation(); // For debug only
}
/**********************************************************************//**
* @brief Initializes Accelerometer
*
* @param none
*
* @return none
*************************************************************************/
void SetupAccel(void)
{
//Setup accelerometer
// ~20KHz sampling
//Configure GPIO
ACC_PORT_SEL0 |= ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN; //Enable A/D channel inputs
ACC_PORT_SEL1 |= ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN;
ACC_PORT_DIR &= ~(ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN);
ACC_PWR_PORT_DIR |= ACC_PWR_PIN; //Enable ACC_POWER
ACC_PWR_PORT_OUT |= ACC_PWR_PIN;
// Allow the accelerometer to settle before sampling any data
__delay_cycles(100000);
__delay_cycles(100000);
//Single channel, once,
ADC10CTL0 &= ~ADC10ENC; // Ensure ENC is clear
ADC10CTL0 = ADC10ON + ADC10SHT_5;
ADC10CTL1 = ADC10SHS_0 + ADC10SHP + ADC10CONSEQ_0 + ADC10SSEL_0;
ADC10CTL2 = ADC10RES;
ADC10MCTL0 = ADC10SREF_0 + ADC10INCH_12;
ADC10IV = 0x00; // Clear all ADC12 channel int flags
ADC10IE |= ADC10IE0;
// Setup Thresholds for relative difference in accelerometer measurements
ThreshRange[0]=25;
ThreshRange[1]=50;
ThreshRange[2]=75;
}
/**********************************************************************//**
* @brief ShutDownAccel
*
* @param none
*
* @return none
*************************************************************************/
void ShutDownAccel(void)
{
ACC_PORT_SEL0 &= ~(ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN);
ACC_PORT_SEL1 &= ~(ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN);
ACC_PORT_DIR &= ~(ACC_X_PIN + ACC_Y_PIN + ACC_Z_PIN);
ACC_PWR_PORT_DIR &= ~ACC_PWR_PIN;
ACC_PWR_PORT_OUT &= ~ACC_PWR_PIN;
ADC10CTL0 &= ~(ADC10ENC + ADC10ON);
ADC10IE &= ~ADC10IE0;
ADC10IFG = 0;
}
/**********************************************************************//**
* @brief Setup thermistor
*
* @param none
*
* @return none
*************************************************************************/
void SetupThermistor(void)
{
// ~16KHz sampling
//Turn on Power
P2DIR |= BIT7;
P2OUT |= BIT7;
// Configure ADC
P1SEL1 |= BIT4;
P1SEL0 |= BIT4;
// Allow for settling delay
__delay_cycles(50000);
// Configure ADC
ADC10CTL0 &= ~ADC10ENC;
ADC10CTL0 = ADC10SHT_7 + ADC10ON; // ADC10ON, S&H=192 ADC clks
// ADCCLK = MODOSC = 5MHz
ADC10CTL1 = ADC10SHS_0 + ADC10SHP + ADC10SSEL_0;
ADC10CTL2 = ADC10RES; // 10-bit conversion results
ADC10MCTL0 = ADC10INCH_4; // A4 ADC input select; Vref=AVCC
ADC10IE = ADC10IE0; // Enable ADC conv complete interrupt
// Setup Thresholds for relative difference in Thermistor measurements
ThreshRange[0]=15;
ThreshRange[1]=25;
ThreshRange[2]=45;
}
/**********************************************************************//**
* @brief ShutDownTherm
*
* @param none
*
* @return none
*************************************************************************/
void ShutDownTherm(void)
{
// Turn off Vcc
P2DIR &= ~BIT7;
P2OUT &= ~BIT7;
// Turn off ADC Channel
P1SEL1 &= ~BIT4;
P1SEL0 &= ~BIT4;
// Turn off ADC
ADC10CTL0 &= ~(ADC10ENC + ADC10ON);
ADC10IE &= ~ADC10IE0;
ADC10IFG = 0;
}
/**********************************************************************//**
* @brief LED Toggle Sequence
*
* @param
* DiffValue Difference between calibrated and current measurement
* temp Direction of difference (positive or negative)
* @return none
*************************************************************************/
void LEDSequence(unsigned int DiffValue, unsigned char temp)
{
// The same scale is used for cold & hot and tilt up/down
// only the thresholds are different
P3OUT |= BIT4; // Light up the middle LEDs
PJOUT |= BIT3;
if(DiffValue < ThreshRange[0]) // Very close to CAL value
{
P3OUT |= BIT4;
PJOUT |= BIT3;
PJOUT &= ~(BIT0+BIT1+BIT2);
P3OUT &= ~(BIT7+BIT6+BIT5);
counter = 0x34;
}
if ((DiffValue >=ThreshRange[0]) && (DiffValue < ThreshRange[1]))
{
// Light up one LED
if(temp == UP) // Tilt up, temp up
{
PJOUT |= BIT2;
PJOUT &= ~(BIT1+BIT0);
P3OUT &= ~(BIT7+BIT6+BIT5);
counter = 5;
}
else // Tilt down, temp down
{
PJOUT &= ~(BIT0+BIT1+BIT2);
P3OUT |= BIT5;
P3OUT &= ~(BIT6+BIT7);
counter = 2;
}
}
if ((DiffValue >= ThreshRange[1]) && (DiffValue < ThreshRange[2]))
{
// Light up two LEDs
if(temp == UP) // Tilt up 2, temp up 2
{
PJOUT |= BIT2 + BIT1;
PJOUT &= ~(BIT0);
P3OUT &= ~(BIT7+BIT6+BIT5);
counter = 6;
}
else // Tilt down 2, temp down 2
{
PJOUT &= ~(BIT2+BIT1+BIT0);
P3OUT |= BIT5 + BIT6;
P3OUT &= ~(BIT7);
counter = 1;
}
}
if (DiffValue > ThreshRange[2])
{
// Light up three LEDs
if(temp == UP) // Tilt up 3, temp up 3
{
PJOUT |= BIT2 + BIT1 + BIT0;
P3OUT &= ~(BIT7+BIT6+BIT5);
counter = 7;
}
else // Tilt down 3, temp down 3
{
P3OUT |= BIT5+BIT6+BIT7;
PJOUT &= ~(BIT2+BIT1+BIT0);
counter = 0;
}
}
}
/**********************************************************************//**
* @brief Disables Switches
*
* @param none
*
* @return none
*************************************************************************/
void DisableSwitches(void)
{
// disable switches
P4IFG = 0; // P4 IFG cleared
P4IE &= ~(BIT0+BIT1); // P4.0 interrupt disabled
P4IFG = 0; // P4 IFG cleared
}
/**********************************************************************//**
* @brief Enables Switches
*
* @param none
*
* @return none
*************************************************************************/
void EnableSwitches(void)
{
P4IFG = 0; // P4 IFG cleared
P4IE = BIT0+BIT1; // P4.0 interrupt enabled
}
/**********************************************************************//**
* @brief Sets up the Timer A1 as debounce timer
*
* @param delay: pass 0/1 to decide between 250 and 750 ms debounce time
*
* @return none
*************************************************************************/
void StartDebounceTimer(unsigned char delay)
{
// default delay = 0
// Debounce time = 1500* 1/8000 = ~200ms
TA1CCTL0 = CCIE; // TACCR0 interrupt enabled
if(delay)
TA1CCR0 = 750;
else
TA1CCR0 = 1500;
TA1CTL = TASSEL_1 + MC_1; // ACLK, up mode
}
/**********************************************************************//**
* @brief Long Delay
*
* @param none
*
* @return none
*************************************************************************/
void LongDelay()
{
__delay_cycles(125000);
__delay_cycles(125000);
__no_operation();
}
/**********************************************************************//**
* @brief Transmit 7 bytes
*
* @param none
*
* @return none
*************************************************************************/
void TXData()
{
unsigned char counter = 0;
// Configure UART 0
UCA0CTL1 |= UCSWRST;
UCA0CTL1 = UCSSEL_2; // Set SMCLK as UCLk
UCA0BR0 = 52 ; // 9600 baud
// 8000000/(9600*16) - INT(8000000/(9600*16))=0.083
UCA0BR1 = 0;
// UCBRFx = 1, UCBRSx = 0x49, UCOS16 = 1 (Refer User Guide)
UCA0MCTLW = 0x4911 ;
UCA0CTL1 &= ~UCSWRST; // release from reset
while(counter<7)
{
while (!(UCA0IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = TX_Buffer[counter];
counter++;
}
}
/**********************************************************************//**
* @brief Transmit the break sequence
*
* @param mode at the time of ULP switch press
*
* @return none
*************************************************************************/
void TXBreak(unsigned char ModeSelect)
{
// One time initialization of header and footer transmit package
TX_Buffer[0] = 0xFA;
TX_Buffer[6] = 0xFE;
// Prepare the reset sequence
TX_Buffer[1] = 0x55;
TX_Buffer[2] = 0x55;
TX_Buffer[3] = 0x55;
TX_Buffer[4] = 0x55;
TX_Buffer[5] = ModeSelect/2;
TXData();
}
/*******************************************************************************
*
* main.c
* User Experience Code for the MSP-EXP430FR5739
*
*
* Copyright (C) 2010 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.
*
* Created: Version 1.0 04/13/2011
* Version 1.1 05/11/2011
******************************************************************************/
// Mode Definitions
#define MAX_FRAM_WRITE 2
#define SLOW_FRAM_WRITE 4
#define ACCEL_MEAS 6
#define TEMP_MEAS 8
// The FRAM section from 0xD000 - 0xF000 is used by all modes
// for performing writes to FRAM
// Do not use this section for code or data placement.
// It will get overwritten!
#define ADC_START_ADD 0xD400
#define ADC_END_ADD 0xF000
#define FRAM_TEST_START 0xD400
#define FRAM_TEST_END 0xF000
#define MEM_UNIT 0x200
// Pin Definitions
#define ACC_PWR_PIN BIT7
#define ACC_PWR_PORT_DIR P2DIR
#define ACC_PWR_PORT_OUT P2OUT
#define ACC_PORT_DIR P3DIR
#define ACC_PORT_OUT P3OUT
#define ACC_PORT_SEL0 P3SEL0
#define ACC_PORT_SEL1 P3SEL1
#define ACC_X_PIN BIT0
#define ACC_Y_PIN BIT1
#define ACC_Z_PIN BIT2
// Accelerometer Input Channel Definitions
#define ACC_X_CHANNEL ADC10INCH_12
#define ACC_Y_CHANNEL ADC10INCH_13
#define ACC_Z_CHANNEL ADC10INCH_14
#define DOWN 0
#define UP 1
// Function Declarations
extern void SystemInit(void);
extern void StartUpSequence(void);
extern void FRAM_Write(unsigned int StartAddress);
extern void Mode1(void);
extern void Mode2(void);
extern void Mode3(void);
extern void Mode4(void);
extern unsigned int CalibrateADC(void);
extern void TakeADCMeas(void);
extern void SetupAccel(void); // setup ADC for Acc
extern void ShutDownAccel(void);
extern void SetupThermistor(void);
extern void ShutDownTherm(void);
extern void LEDSequence(unsigned int, unsigned char);
extern void LEDSequenceWrite(unsigned char);
extern void DisableSwitches(void);
extern void EnableSwitches(void);
extern void StartDebounceTimer(unsigned char);
extern void LongDelay(void);
extern void TXData(void);
extern void TXBreak(unsigned char);
/*******************************************************************************
*
* main.c
* User Experience Code for the MSP-EXP430FR5739
*
*
* Copyright (C) 2010 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.
*
* Created: Version 1.0 04/13/2011
* Version 1.1 05/11/2011
*
******************************************************************************/
#include "msp430fr5739.h"
#include "FR_EXP.h"
#include <legacymsp430.h>
const unsigned char LED_Menu[] = {0x80,0xC0,0xE0,0xF0};
// These golabal variables are used in the ISRs and in FR_EXP.c
volatile unsigned char mode = 0;
volatile unsigned char UserInput = 0;
volatile unsigned char ULP =0;
volatile unsigned int *FRAMPtr = 0;
volatile unsigned char active = 0;
volatile unsigned char SwitchCounter=0;
volatile unsigned char Switch1Pressed=0;
volatile unsigned char Switch2Pressed=0;
volatile unsigned int ADCResult = 0;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
SystemInit(); // Init the Board
StartUpSequence(); // Light up LEDs
// Setup ADC data storage pointer for Modes 3&4
FRAMPtr = (unsigned int *) ADC_START_ADD;
while(1)
{
// Variable initialization
active = 0;
Switch2Pressed = 0;
ULP = 0;
// Wait in LPM4 for user input
__bis_SR_register(LPM4_bits + GIE); // Enter LPM4 w/interrupt
__no_operation(); // For debugger
// Wake up from LPM because user has entered a mode
switch(mode)
{
case MAX_FRAM_WRITE:
Mode1();
break;
case SLOW_FRAM_WRITE:
Mode2();
break;
case ACCEL_MEAS:
Mode3();
break;
case TEMP_MEAS:
Mode4();
break;
default:
// This is not a valid mode
// Blink LED1 to indicate invalid entry
// Switch S2 was pressed w/o mode select
while((mode > 0x08)&& (UserInput == 0))
{
P3OUT ^= BIT7;
LongDelay();
}
break;
}
}
}
// Interrupt Service Routines
/**********************************************************************//**
* @brief Port 4 ISR for Switch Press Detect
*
* @param none
*
* @return none
*************************************************************************/
#if 0
#pragma vector=PORT4_VECTOR
__interrupt void Port_4(void)
#else
interrupt(PORT4_VECTOR) Port_4(void)
#endif
{
// Clear all LEDs
PJOUT &= ~(BIT0 +BIT1+BIT2+BIT3);
P3OUT &= ~(BIT4 +BIT5+BIT6+BIT7);
//switch(__even_in_range(P4IV,P4IV_P4IFG1))
switch(P4IV)
{
case P4IV_P4IFG0:
DisableSwitches();
Switch2Pressed = 0;
UserInput = 1;
P4IFG &= ~BIT0; // Clear P4.0 IFG
P3OUT = LED_Menu[SwitchCounter];
SwitchCounter++;
if (SwitchCounter>3)
{
SwitchCounter =0;
Switch1Pressed++;
}
StartDebounceTimer(0); // Reenable switches after debounce
break;
case P4IV_P4IFG1:
DisableSwitches();
StartDebounceTimer(0); // Reenable switches after debounce
P4IFG &= ~BIT1; // Clear P4.1 IFG
// This is the second time Switch2 is pressed
// Was the code executing inside of the modes?
// ULP option on or off?
if ((Switch2Pressed > 0)&& (active == 1))
{
ULP ^= 0x01; // Toggle Display ON/OFF
break;
}
else
Switch2Pressed = 1;
UserInput = 0;
// If the counter value is 0 it indicates either Mode 4 or invalid entry
if((SwitchCounter == 0) && (Switch1Pressed >0))
mode = 4; // because counter rollsover after 3
if((SwitchCounter == 0) && (Switch1Pressed == 0))
mode = 5; // no switch1 press - invalid
if(SwitchCounter>3)
mode = 5; // too high! this is invalid entry
if((SwitchCounter>0) && (SwitchCounter<=3))// this entry is correct
mode = SwitchCounter; // store mode
mode = mode * 2; // make it an even number
// Reset variables
Switch1Pressed = 0;
SwitchCounter = 0;
__bic_SR_register_on_exit(LPM4_bits);// Exit LPM4
break;
default:
break;
}
}
/**********************************************************************//**
* @brief Timer A0 ISR for MODE2, Slow FRAM writes, 40ms timer
*
* @param none
*
* @return none
*************************************************************************/
#if 0
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
#else
interrupt(TIMER0_A0_VECTOR) Timer_A(void)
#endif
{
__bic_SR_register_on_exit(LPM4_bits);
}
/**********************************************************************//**
* @brief ADC10 ISR for MODE3 and MODE4
*
* @param none
*
* @return none
*************************************************************************/
#if 0
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
#else
interrupt(ADC10_VECTOR) ADC10_ISR(void)
#endif
{
//switch(__even_in_range(ADC10IV,ADC10IV_ADC10IFG))
switch(ADC10IV)
{
case ADC10IV_NONE: break; // No interrupt
case ADC10IV_ADC10OVIFG: break; // conversion result overflow
case ADC10IV_ADC10TOVIFG: break; // conversion time overflow
case ADC10IV_ADC10HIIFG: break; // ADC10HI
case ADC10IV_ADC10LOIFG: break; // ADC10LO
case ADC10IV_ADC10INIFG: break; // ADC10IN
case ADC10IV_ADC10IFG:
ADCResult = ADC10MEM0;
*FRAMPtr = ADCResult;
FRAMPtr++;
// Pointer round off, once 0x200 locations are written, the pointer
// rolls over
if (FRAMPtr > (unsigned int *)ADC_END_ADD)
FRAMPtr = (unsigned int *) ADC_START_ADD;
__bic_SR_register_on_exit(CPUOFF);
break; // Clear CPUOFF bit from 0(SR)
default: break;
}
}
/**********************************************************************//**
* @brief Timer A1 ISR for debounce Timer
*
* @param none
*
* @return none
*************************************************************************/
#if 0
#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0_ISR(void)
#else
interrupt(TIMER1_A0_VECTOR) Timer1_A0_ISR(void)
#endif
{
TA1CCTL0 = 0;
TA1CTL = 0;
EnableSwitches();
}
OBJECTS = main.o FR_EXP.o
CC = msp430-gcc
CFLAGS =-Os -Wall -g -mmcu=msp430fr5739
PATCHED_MSPDEBUG=${HOME}/mspdebug/mspdebug
all : $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o main.elf
%.o : %.c
$(CC) $(CFLAGS) -c $<
clean:
rm -fr $(OBJECTS) main.elf
install: all
$(PATCHED_MSPDEBUG) rf2500 "load main.elf"
size: all
msp430-size main.elf
@mikegi
Copy link

mikegi commented Oct 19, 2011

Just what I was looking for!

@dtkav
Copy link

dtkav commented Feb 12, 2013

Thank you for making this available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment