//------------------------------------------------------------------------------
// ADS1100_Demo.c - ADS1100 Bridge Sensor Readout Demo w/ MSP430F413
//
// Description: Program reads out an external ADS1100 Sigma-Delta ADC over the
// I2C interface. The differential input voltage is displayed as a signed number
// on a 3.5 digit LCD display. The displayed value is calculated using a 2-point
// calibration mechanism. During initial power-up (INFOA Flash memory is erased),
// two calibration data points are obtained (CalMin and CalMax) and stored in
// Flash memory. The range of CalMin to CalMax is projected into a display-value
// from 0 to CAL_MIN_MAX_SPAN. Button #1 is used to enter low-power mode,
// button #2 is used to re-calibrate. An external 32-kHz watch crystal is used
// for time interval generation and for driving the LCD.
//
// /|\ /|\ /|\
// | ADS1100 10k 10k MSP430F413
// | +-------+ | | +----------+
// +---|Vcc SDA|<-|---+>|P2.0 | +----------------------+
// o-------|VIN+ | | | S0-S23|--->| Varitronix 3.5 digit |
// o-------|VIN- | | | COM0|--->| Static LCD Display |
// +--|Vss SCL|<-+-----|P2.1 | +----------------------+
// \|/ +-------+ | |
// | XIN/XOUT|<---32.768KHz Watch Crystal
// | P1.6|<---Button #1 (low-active)
// | P1.7|<---Button #2 (low-active)
// +----------+
// Andreas Dannenberg
// Texas Instruments Inc.
// June 2004
// Built with IAR Embedded Workbench Version: 3.10A
//------------------------------------------------------------------------------
#include "msp430x41x.h"
#include "I2C_Master.h"
#define CAL_MIN_MAX_SPAN 1000 // Scale value for CalMin/CalMax
// Definitions for ADS1100 A/D converter
#define ADS1100_SA (0x48) // ADS1100 I2C Slave Address
#define ADS1100_GAIN1 (0x00) // PGA Gain X1
#define ADS1100_GAIN2 (0x01) // PGA Gain X2
#define ADS1100_GAIN4 (0x02) // PGA Gain X4
#define ADS1100_GAIN8 (0x03) // PGA Gain X8
#define ADS1100_128SPS (0x00) // 128 Samples/s
#define ADS1100_32SPS (0x04) // 32 Samples/s
#define ADS1100_16SPS (0x08) // 16 Samples/s
#define ADS1100_8SPS (0x0C) // 8 Samples/s
#define ADS1100_SC (0x10) // Single Conversion Mode
#define ADS1100_ST_BSY (0x80) // Start Conversion + Busy
// Circuit related definitions
#define BRIDGE_H (0x38) // IO pins for pos. bridge rail
#define BRIDGE_L (0x07) // IO pins for neg. bridge rail
enum
{
BT_ISR_NRM, // BT ISR - Wakeup
BT_ISR_CL1, // BT ISR - Show 'CAL'
BT_ISR_CL2, // BT ISR - Display 'LO'
BT_ISR_CH1, // BT ISR - Toggle CAL/HI
BT_ISR_CH2 // BT ISR - Toggle CAL/HI
};
enum
{
P1_ISR_NRM, // Port1 ISR - Normal Mode
P1_ISR_CL, // Port1 ISR - Cal Low Mode
P1_ISR_CH // Port1 ISR - Cal High Mode
};
const unsigned char LCD_Tab[] =
{
0x77, // Displays "0"
0x12, // Displays "1"
0x3d, // Displays "2"
0x3b, // Displays "3"
0x5a, // Displays "4"
0x6b, // Displays "5"
0x6f, // Displays "6"
0x13, // Displays "7"
0x7f, // Displays "8"
0x7b, // Displays "9"
0x5e, // Displays "H"
0x64, // Displays "L"
0x65, // Displays "C"
0x5f, // Displays "A"
0x00, // Displays Blank
0x00 // Displays Blank
};
// Global vars
static unsigned int BtIsrMode; // ISR Mode for Basic Timer
static unsigned int P1IsrMode; // ISR Mode for Port 1
static int CalMinTmp; // Vars to hold calib values
static int CalMaxTmp;
static int LastADCValue;
static char UpdateDisplay = 1; // Flag to request LCD update
#pragma dataseg = INFOA // Info Flash Memory Block A
__no_init static int CalMin;
__no_init static int CalMax;
#pragma dataseg = default
// Function prototypes
void Init_Sys(void);
void StoreCalInFlash(void);
void Disp_Signed_3_5(int Value);
void Disp_BCD_3_5(unsigned int Value);
//------------------------------------------------------------------------------
void main(void)
{
Init_Sys();
if (CalMin == CalMax) // Are constants in Flash OK?
{
BtIsrMode = BT_ISR_CL1; // Go to calibration mode
P1IsrMode = P1_ISR_CL;
}
else
{
BtIsrMode = BT_ISR_NRM; // Go to measurement mode
P1IsrMode = P1_ISR_NRM;
}
I2CWrite8(ADS1100_SA, ADS1100_8SPS + ADS1100_GAIN8); // Start conversions
__bis_SR_register(LPM3_bits + GIE); // Enter LPM3 w/ ints enabled
}
//------------------------------------------------------------------------------
void Init_Sys(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
FLL_CTL0 |= XCAP18PF; // Set load capacitance for xtal
LCDCTL = 0xc5; // Static LCD, segments = 0 - 23
BTCTL = BT_fLCD_DIV256+BTDIV+BT_fCLK2_DIV32; // 0.25s BT Int, Set LCD freq
IE2 |= BTIE; // Enable Basic Timer interrupt
P1OUT = 0; // P1OUTs = 0
P1DIR = 0x3f; // P1.7/P1.6 input, others outp
P1IES = 0xc0; // P1.7/P1.6 int on falling edge
P1IFG = 0;
P1IE = 0xc0; // Enable button intuerrupts
P2OUT = 0; // P2OUTs = 0
P2DIR = 0xfc; // Set port but I2C pins to outputs
P3OUT = 0; // P3OUTs = 0
P3DIR = 0xff; // Set port to outputs
P4OUT = 0; // P4OUTs = 0
P4DIR = 0xff; // Set port to outputs
P5OUT = 0; // P5OUTs = 0
P5DIR = 0xff; // Set port to outputs
P6OUT = BRIDGE_H; // Enable bridge supply voltage
P6DIR = 0xff; // Set port to outputs
}
//------------------------------------------------------------------------------
void StoreCalInFlash(void)
{
FCTL2 = FWKEY + FSSEL1 + FN1; // SMCLK/3 = ~333kHz
FCTL3 = FWKEY; // Clear LOCK
FCTL1 = FWKEY + ERASE; // Enable segment erase
*(unsigned int *)0x1080 = 0; // Dummy write, erase info A
FCTL1 = FWKEY + WRT; // Enable write
CalMin = CalMinTmp; // Program calibration constants
CalMax = CalMaxTmp;
FCTL1 = FWKEY; // Done. Clear WRT
FCTL3 = FWKEY + LOCK; // Done. Set LOCK
}
//------------------------------------------------------------------------------
void Disp_Signed_3_5(int Value)
{
unsigned int i;
unsigned int Output;
char fNeg = 0;
if (Value >= 2000) // Higher/equ w/ 2000?
{
Disp_BCD_3_5(0x0a1f); // Display 'HI'
return;
}
if (Value < -1999) // Less than -1999?
{
Disp_BCD_3_5(0x0b0f); // Display 'LO'
return;
}
if (Value < 0) // Test for new negative value
{
Value = -Value; // Negate value
fNeg = 1; // Set negative flag
}
for (i = 16, Output = 0; i; i--) // BCD Conversion, 16-Bit
{
Output = __bcd_add_short(Output, Output);
if (Value & 0x8000)
Output = __bcd_add_short(Output, 1);
Value <<= 1;
}
if (fNeg)
Output |= 0x2000;
Disp_BCD_3_5(Output);
}
//------------------------------------------------------------------------------
void Disp_BCD_3_5(unsigned int Value)
{
unsigned char *pLCD = (unsigned char *)&LCDM1; // 1st LCD mem location
unsigned char LCDSegInfo;
unsigned char LCDDigit;
do
{
LCDDigit = Value & 0x0f; // Get one LCD digit
LCDSegInfo = LCD_Tab[LCDDigit]; // Get LCD segment information
*pLCD++ = LCDSegInfo; // Segments a & b to LCD
LCDSegInfo >>= 1;
*pLCD++ = LCDSegInfo; // Segments c & d to LCD
LCDSegInfo >>= 1;
*pLCD++ = LCDSegInfo; // Segments e & f to LCD
LCDSegInfo >>= 1;
*pLCD++ = LCDSegInfo; // Segments g & h to LCD
Value >>= 4; // Process next digit
} while (pLCD < (unsigned char *)&LCDM13); // Updated all segments?
if (Value & 0x01) // Data >999?
LCDM12 |= 0x10; // B-C digit active
if (Value & 0x02) // Display neg sign?
LCDM8 |= 0x10; // "-" segment active
}
//------------------------------------------------------------------------------
#pragma vector = BASICTIMER_VECTOR
__interrupt void BT_ISR(void)
{
int CurrentADCValue;
switch (BtIsrMode)
{
case BT_ISR_NRM :
CurrentADCValue = I2CRead16(ADS1100_SA); // Get conversion result
if (UpdateDisplay || LastADCValue != CurrentADCValue)
{
UpdateDisplay = 0; // Reset flag
LastADCValue = CurrentADCValue; // Store new value
Disp_Signed_3_5(((long)CurrentADCValue - CalMin) * CAL_MIN_MAX_SPAN /
(CalMax - CalMin));
}
break;
case BT_ISR_CL1 :
Disp_BCD_3_5(0x0cdb); // Display 'CAL'
BtIsrMode = BT_ISR_CL2; // Next state
break;
case BT_ISR_CL2 :
Disp_BCD_3_5(0x0b0f); // Display 'LO'
BtIsrMode = BT_ISR_CL1; // Next state
break;
case BT_ISR_CH1 :
Disp_BCD_3_5(0x0cdb); // Display 'CAL'
BtIsrMode = BT_ISR_CH2; // Next state
break;
case BT_ISR_CH2 :
Disp_BCD_3_5(0x0a1f); // Display 'HI'
BtIsrMode = BT_ISR_CH1; // Next state
break;
}
}
//------------------------------------------------------------------------------
#pragma vector = PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
volatile unsigned int i; // 'volatile' to prevent opt.
switch (P1IsrMode)
{
case P1_ISR_NRM :
if (P1IFG & 0x40) // Test for on P1.6 (on/off)
{
IE2 ^= BTIE; // Toggle Basic Timer interrupt
P6OUT ^= BRIDGE_H; // Toggle Bridge Supply Voltage
LCDCTL ^= LCDON; // Toggle LCD on/off
if (LCDCTL & LCDON)
{
I2CWrite8(ADS1100_SA, ADS1100_8SPS + ADS1100_GAIN8); // Start conversions
UpdateDisplay = 1; // Request display update
}
else
{
I2CWrite8(ADS1100_SA, ADS1100_SC); // Disable conversions
IFG2 &= ~BTIFG; // Clear Basic Timer int flag
}
}
if (P1IFG & 0x80 && LCDCTL & LCDON) // Test for on P1.7 (calibration)
{
P1IsrMode = P1_ISR_CL; // Enter calibration mode (low)
BtIsrMode = BT_ISR_CL1;
}
break;
case P1_ISR_CL :
if (P1IFG & 0xc0) // Test for P1.6/P1.7
{
CalMinTmp = I2CRead16(ADS1100_SA); // Get 16-bit conversion result
P1IsrMode = P1_ISR_CH;
BtIsrMode = BT_ISR_CH1; // Enter calibration mode (high)
}
break;
case P1_ISR_CH :
if (P1IFG & 0xc0) // Test for P1.6/P1.7
{
CalMaxTmp = I2CRead16(ADS1100_SA); // Get 16-bit conversion result
if (CalMinTmp == CalMaxTmp) // Are calibr constants OK?
{
P1IsrMode = P1_ISR_CL; // No,
BtIsrMode = BT_ISR_CL1; // enter calibration mode (low)
}
else // Calibration OK
{
StoreCalInFlash(); // Yes, program constants and
P1IsrMode = P1_ISR_NRM; // enter normal mode
BtIsrMode = BT_ISR_NRM;
UpdateDisplay = 1; // Request display update
}
}
break;
}
for (i = 0x7fff; i; i--); // Delay for key-debounce
P1IFG = 0x00; // Clear all P1 int flags
}
|