This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software: Code Composer Studio
Gentlemen,
The program I am working on will run for a minute or more and then just stop responding to the pause button in debug mode. After another minute or two it will start working normally for a while and then repeat the process.
Older version seem to run normally when the programming pod is disconnected. Newer versions of the program will also stop running in normal mode as well and again after a minute or two the microcontroller will start up again and work as it should for a minute or two and then stop.
This program does not currently use any low power modes.and there is no external crystal. The clock setup was copied from other designs using the same microcontroller so I am mystified.
Thanks, Harvey
/*********************************************************************************************
*
* Daughter Card: Top Cell Card, Revision 0
*
* File Name: main.c
* Project: PowerCortex
* Module: DCM
* Product: PowerCortex - M Series
* Company: 1100 Energy Corporation
* Author(s): Harvey Novak
*
* Version: 1.00
* Release: 1
* Time: 5:03 PM
* Date: February 15, 2019
*
*
* Target Processor: MSP430F2132
* Description: 1)
* 2)
* 3)
* 4)
* 5)
*
* Notes:
* 1) This is a simple interface to the input power connector.
* 2) In the interest of brevity, everything has been crammed into one main.c. In production code, the various static globals, and their
* associated accessory routines, should be moved out into separate module files.
* 3) All routines that begin with SMBus_... are part of the TI SMBus library.
* 4) All variables that begin with "_" are global scope within this file.
*
* Software Changes/Improvements:
* 1) The integrator in the current sense routines needs to be improved.
* 2) Add temperature monitor when available!!!!
* 3) Add thermostat.
*
*
* Key Words:
* VM_1_OUT Ch A0 - Average DC_IN from voltmeter 1 voltage = sum/8.
* Ch A1 - Average DC_IN from voltmeter 2 voltage = sum/8.
* Analog_2 Ch A2 - Average of spare input A2 = sum/8.
* Analog_3 Ch A3 - Average of spare input A3 = sum/8.
* Analog_4 Ch A4 - Average of spare input A4 = sum/8.
* Analog_5 Ch A5 - Average of spare input A5 = sum/8.
*
* Packet_Timer
*
*
* Hardware Issues to Fix in Rev. 1:
* 1) UCLK, SOMI,SIMO, and STE are unconnected.
* 2) All DMN65D8L-7 FETs have gate and source pins swapped! Q10-13, Q16, Q18
* 3) All DMP6350S-7 FETs have sourc and drain pins swapped! Q1, Q3-8, Q17
* 4) The PCT2075D temperature sensor need to be repoitioned between the cells!
* 5) Diode D1 is in backwards. Symbol is drawn correctly but pins reversed in PCB artwork.
*
*********************************************************************************************/
#include <msp430.h>
//#include <msp430f2132.h>
#include "Definitions.h"
//#include <stdint.h>
//#include <stdlib.h>
// Top Cell Card
//
// General counters
//
BYTE LED_Flashes; // Number of flashes per flash sequence.
BYTE Flash_Count; // Temporary variable set throughout the code when MODE_STATE changes.
BYTE LED_Sequence_Count; // Number of flash sequencess before the LED is blanked.
BYTE Real_Data_Count; // Count of data sets collected by the ADC.
BYTE NAK_Count; // Count of NAK received from the F169 during transmissions.
BYTE Packet_Er_Cnt; // Count of transmission errors from Packet_Send.
BYTE Packet_Count; // 8-bit roll-over counter, used to allow F169 to recognize stale data.
BYTE icount; // Counter variable.
// Control Flag Registers
//
BYTE ADC_Flags; // Data acquisition control flags.
WORD Commands; // Commands to be processed.
BYTE System_Flags; // Miscellaneous system control flags.
BYTE Command_Flags; // Command processor flags.
WORD Gen_Msg_Flags1;
// Timers and Counters
//
WORD Wait_Timer;
WORD Watch_Dog;
WORD LED_Timer;
WORD Over_Current_Timer; // Cooling off period of the battery cells.
WORD Powerup_Timer; // Hold off connection to BAT_BUS until screws are tight and OS is stable.
WORD SMB_Timer_IR; // SMBus communications with the IR video driver timer.
WORD Packet_Timer; // Set the minimum time between packets to the potentiometer.
BYTE Pot_Timer; // SMBus packet timing.
WORD LED_Pause;
WORD LED_Reload_Off;
WORD LED_Reload_On;
// Top Cell Card
//
// ----- State Machines -----
BYTE Command_State; // Top level activity manager.
BYTE Sub_A_Cmd_State; // Packet sequencing second level state machine.
BYTE Sub_B_Cmd_State; // Packet sequencing second level state machine.
BYTE Sub_C_Cmd_State; // Packet sequencing second level state machine.
BYTE Pot_Wr_State; // Transmit a byte of data to one of the lower four EDCs.
BYTE Pot_Pkt_Wr_State; // Transmit a packet to one of the lower four EDCs.
BYTE ADC_data_state; // Collect from the ADC.
BYTE I_Monitor_state; // Monitor the current into or out of the cell string.
BYTE A0_Monitor_state; // Top cell voltage monitor.
BYTE LED_State; // Blink control of the LED.
// ----- Potentiometer SMBus Variables -----
//
// Potentiometer Access Control Register bit definitions.
// Bit 0 R/W When set a read data transaction is selected.
// " 1 A0 Pot address bit 0.
// " 2 A1 " " " 1.
// " 3 ID0 Device identification bit 0.
// " 4 ID1 " " " 1.
// " 5 ID2 " " " 2.
// " 6 ID3 " " " 3.
// " 7 ID4 " " " 4.
BYTE SMBus_Buffer; // Temporary storage of the byte to be transferred to or from one of the video drivers.
BYTE acked; // Last value of the SMBus acknowledge from the potentiometer.
BYTE Bit_Mask; // Use to peel off the bits of the byte sent to the potentiometer,.
WORD Data_Array_Ptr; // The data array index.
WORD Data_Array_Last; // The end of current block of data in the array to be sent.
BYTE Local_Data[3] = { POT_ACR_wr, POT_AR, POT_WCR };
// Top Cell Card
//
// Sensor data
//
WORD Analog_data; // ADC conversion temporary buffer
WORD BATTERY_BUS; // Ch A0 - Average voltage on the battery bus.
WORD CELL_POS; // Ch A1 - Average voltage on the top cell.
WORD MID_STRING; // Ch A2 - Average voltage at cell string center tap.
// I_Sense; // Ch A3 - Average current in or out of the cell string.
WORD VREF; // Ch A4 - Average voltage of the reference.
WORD Analog5; // Ch A5 - unused
WORD Ch_A0[9]; // Ch A0 BATTERY_BUS - array of last 8 samples and the sum.
WORD Ch_A1[9]; // Ch A1 CELL_POS - " " " " " " " " .
WORD Ch_A2[9]; // Ch A2 MID_STRING - " " " " " " " " .
WORD Ch_A3[9]; // Ch A3 I_Sense - " " " " " " " " .
WORD Ch_A4[9]; // Ch A4 VREF - " " " " " " " " .
WORD Ch_A5[9]; // Ch A5 Analog5 - " " " " " " " " .
BYTE ADC_POINTER; // Pointer into all six analog data arrays.
signed int I_Sense, TC_0Iio, Iio_Offset, Integrated_Energy;
/*
//
// Bus voltage related measurements and calculated variables.
//
float BB_A30; // Voltmeter reading when BAT_BUS_D30 was captured.
WORD BB_D30; // Value read for A/D when BAT_BUS voltage was set to ~30 Vdc.
float BB_A24; // Voltmeter reading when BAT_BUS_D30 was captured.
WORD BB_D24; // Value read for A/D when BAT_BUS voltage was set to ~30 Vdc.
float BB_m; // Calculated slope of the linear approximation for BAT_BUS.
float BB_b; // Calculated offset of the linear approximation for BAT_BUS.
float BB_f; // Calculated value of the BAT_BUS voltage from any integer value read from the A/D Converter.
float CP_A30; // Voltmeter reading when CELL_POS_D30 was captured.
WORD CP_D30; // Value read for A/D when CELL_POS voltage was set to ~30 Vdc.
float CP_A24; // Voltmeter reading when CELL_POS_D30 was captured.
WORD CP_D24; // Value read for A/D when CELL_POS voltage was set to ~30 Vdc.
float CP_m; // Calculated slope of the linear approximation for CELL_POS.
float CP_b; // Calculated offset of the linear approximation for CELL_POS.
float CP_f; // Calculated value of the CELL_POS voltage from any integer value read from the A/D Converter.
float MS_A30; // Voltmeter reading when MID_STRING_D30 was captured.
WORD MS_D30; // Value read for A/D when MID_STRING voltage was set to ~30 Vdc.
float MS_A24; // Voltmeter reading when MID_STRING_D30 was captured.
WORD MS_D24; // Value read for A/D when MID_STRING voltage was set to ~30 Vdc.
float MS_m; // Calculated slope of the linear approximation for MID_STRING.
float MS_b; // Calculated offset of the linear approximation for MID_STRING.
float MS_f; // Calculated value of the MID_STRING voltage from any integer value read from the A/D Converter.
*/
signed int Ipwr_Offset; // Variable used to compensate of the current sensor offset.
// Top Cell Card
//
//================================== Main ======================================
// TC_0Iio = 512 Go initialize to measure current offset.
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
//===================== Clock Initialization ====================
//
// We use the Digital Controlled Osc, set for 16 MHz, for MCLK.
// It uses a preset calibration constants stored in a protected segment of FLASH.
// If these constants have been erased, it traps the CPU in an endless loop
// to prevent problems.
//
if(CALBC1_16MHZ == 0xFF) // If calibration constant erased
{
while(1)
{
; // do not load, trap CPU!!
}
}
// This sequence is taken from the MSP430F249 Users Guide,
// pages 283-284. Preset constants are available for 1, 8, and 16 MHz.
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_16MHZ; // Set range
DCOCTL = CALDCO_16MHZ; // Set DCO step + modulation
// This selects the Very-Low-Power Low-Freq Osc for ACLK
BCSCTL3 = LFXT1S_2; // VLO for ACLK (~12Khz)
// Top Cell Card
//
//===================== Port Initialization =======================
// These initializations ONLY set up the I2C/SMB pins (P3.1 & P3.2) and
// the LED (P2.5). All other GPIO pins are left as digital In, and need to be
// configured for their specific use on the Buck Boost cards.
// LED0 is used as both a 3.3MOD power on indicator, and an SMB status query indicator
// (toggles with each received status request).
//
// ---- Port 1 Setup ------
// P1SEL = 0xFF ^ (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0); // Set all 8 to digital I/O
//
P1SEL = 0x00; // Set all 8 pins to normal digital I/O.
P1OUT = 0x00; // Clear output register.
P1DIR = (Warm_EN | Test1 | Str_En); // Set Port 1 output pins, the rest are inputs.
// P1REN = 0x00; // Disable internal pullup/pulldown resistors.
// ---- Port 2 Setup ------
P2SEL = 0x1F; // Set up bits 0 thru 4 for analog input and the upper 3 bits for standard digital I/O
P2OUT = (BIT5); // Preset P2.5 output to low (on)
P2DIR = (BIT5); // Reset P2.5 to digital out for /LED0
P2REN = 0x00; // Disable internal pullup/pulldown resistors.
// ---- Port 3 Setup ------
P3SEL = 0x00; // Set all 8 pins to normal digital I/O.
P3DIR = nI_Sense_Power; // Set all port 3 pins to inputs except 3.3 volts switch control.
P3SEL = (BIT2 | BIT1); // Set 1&2 to peripheral (USCI_A0: /SCL & /SDA)
P3OUT = 0x00; // Clear P3 Output register, hard pulldown when direction of pin set to output.
P3REN = 0x00; // Disable internal pullup/pulldown resistors.
LED_Pause = 0xFFFF; while(LED_Pause){ LED_Pause--; }
LED_Pause = 0xFFFF; while(LED_Pause){ LED_Pause--; }
//================================ Setup the ADC10 ================================
//
// These bits select the channel for a single-conversion sequence, beginning with the highest channel.
//
// Analog to Digital Converter (ADC) initialization.
ADC10CTL1 = 0; // Shutdown ADC10
ADC10CTL0 = 0;
ADC10AE0 |= 0x3F; // Set P3.0 and P2.4 through P2.0 pins as inputs to ADC.
ADC10CTL1 = INCH_5 + ADC10DIV_7 + CONSEQ_1; // Select maximum channel number in sequence (A5)
ADC10CTL0 = ADC10SHT_3 + ADC10ON; // Select Vcc as the positive referance voltage.
ADC10CTL0 |= (ADC10IE); // Start up ADC block conversion state machine.
ADC10CTL0 |= ( ENC + ADC10SC );
// Fresh start, initialize all the flags.
ADC_Flags = 0; // Clear ADC flags.
System_Flags = 0;
Command_Flags = 0; // Clear all commands.
Gen_Msg_Flags1 = 0;
// Initialize all the state machines.
Command_State = Cmd_Pot_Idle;
Sub_A_Cmd_State = Sub_A_Cmd1;
Sub_B_Cmd_State = Sub_B_Cmd1;
Sub_C_Cmd_State = Sub_C_Cmd1;
Pot_Wr_State = Pot_Write_Init;
Pot_Pkt_Wr_State = Pot_Pkt_Wr_Idle; //
ADC_data_state = Acquire_A5; // ADC data acquisition state machine.
I_Monitor_state = I_Mon_Zero; // Cell stack current monitor state.
A0_Monitor_state = A0_Initialize;
LED_State = LED_Wait_Off; // Start with the LED off.
Packet_Timer = 1000;
Pot_Timer = SMB_Dly4;
LED_Timer = 0x1000;
Wait_Timer = 10;
P3OUT &= ~nI_Sense_Power; // Turn on the power to the current sensor, U5.
// TC_0Iio = 515; // Enter the count read from the A/D Converter at zero current.
// Iio_Offset = TC_0Iio - 512; // Compute the current sensor offset.
/*
//
// Linear approximations of the Bus voltages.
//
// BATTERY_BUS
//
BB_m = ( BB_A30 - BB_A24 );
BB_m /= ( BB_D30 - BB_D24 );
BB_b = BB_A30 - ( BB_m * BB_D30 );
// CELL_POS
//
CP_m = ( CP_A30 - CP_A24 );
CP_m /= ( CP_D30 - CP_D24 );
CP_b = CP_A30 - ( CP_m * CP_D30 );
// MID_STRING
//
MS_m = ( MS_A30 - MS_A24 );
MS_m /= ( MS_D30 - MS_D24 );
MS_b = MS_A30 - ( MS_m * MS_D30 );
*/
// Watch Dog Timer startup.
// By default the clock source is divided by 32,768. At 16
WDTCTL = ( WDTPW + WDTCNTCL + WDTSSEL + WDTTMSEL ); // Clear the Watchdog timer.
WDTCTL = WDT_MDLY_32;
IE1 |= WDTIE; // Enable WDT interrupt.
Powerup_Timer = 5000; // Set delay timer.
System_Flags |= Turn_On_Delay; // Hold off connection to BAT_BUS until screws are tight and OS is stable.
_EINT(); // Enable all interrupts.
// Code must be added to read temperature sensors and turn on and off the heaters!
//
// P1OUT |= Warm_EN; // Turn heaters on.
// P1OUT &= ~Warm_EN; // Turn heaters off.
/*****************************************************************************
*
* Top of Main loop
*
*****************************************************************************/
while(1)
{
// P1OUT &= ~Test1; // Clear the Test1 pin low.
// P1OUT |= Test1; // Set the Test1 pin high.
if( Turn_On_Delay == ( Turn_On_Delay & System_Flags ) ) {
if( Powerup_Timer == 0 ) {
System_Flags &= ~Turn_On_Delay; // Enable full system operation.
Ipwr_Offset = I_Sense - 511; // Enter the count read from the A/D Converter at ~zero current.
}
P1OUT &= ~Test1; // Clear the Test1 pin low.
P1OUT |= Test1; // Set the Test1 pin high.
}
if( Blink_LED == ( Blink_LED & System_Flags ) ) {
switch(LED_State) // ***** Beginning of the M_LED manager state machine *****
{
case LED_Wait_Off:
if( LED_Timer == 0 ) {
P2OUT &= ~M_LED; // Turn on M_LED.
LED_Timer = LED_Reload_On;
LED_State = LED_Wait_On;
}
break;
case LED_Wait_On:
if( LED_Timer == 0 ) {
P2OUT |= M_LED; // Turn off M_LED.
LED_Timer = LED_Reload_Off;
LED_State = LED_Wait_Off;
}
break;
}
}
if( ADC_BCC == ( ADC_BCC & ADC_Flags ) ) {
ADC_Flags &= ~(ADC_BCC); // Clear Block Conversion Complete flag
/***************************************************************************
*
* Monitor the current into or out of the cell stack
*
*
*
***************************************************************************/
switch(I_Monitor_state) // ***** Beginning of ADC Data State Machine *****
{
case I_Mon_Zero: // Is the current greater than the zero threshold in either direction.
if( Integrated_Energy > 0) { Integrated_Energy--; } // Dissipate estimate of self heating.
if( Integrated_Energy > 0) { Integrated_Energy--; } // Dissipate estimate of self heating.
if( Integrated_Energy > 0) { Integrated_Energy--; } // Dissipate estimate of self heating.
if( I_Sense > I_Minimum_Pos + 1 ) { // If charging
System_Flags |= Blink_LED;
LED_Reload_On = 500;
LED_Reload_Off = 50;
I_Monitor_state = I_Pos_Safe;
}
else if( I_Sense < I_Minimum_Neg - 1 ) { // If discharging
System_Flags |= Blink_LED;
LED_Reload_On = 50;
LED_Reload_Off = 500;
I_Monitor_state = I_Neg_Safe;
}
break;
case I_Pos_Safe: // The current is within the safe charging limit.
if( Integrated_Energy > 0) { Integrated_Energy--; } // Dissipate estimate of self heating.
if( I_Sense > I_Safe_Pos ) {
LED_Reload_On = 250;
LED_Reload_Off = 50;
I_Monitor_state = I_Pos_Caution; // Go make sure current drops back to safe limits.
}
else if( I_Sense < I_Minimum_Pos ) {
System_Flags &= ~Blink_LED; // Shutdown blink.
P2OUT &= ~M_LED; // Turn on the LED.
I_Monitor_state = I_Mon_Zero; // Current = 0, go hang.
}
break;
case I_Neg_Safe: // The current is within the safe discharging limit.
if( Integrated_Energy > 0) { Integrated_Energy--; } // Dissipate estimate of self heating.
if( I_Sense < I_Safe_Neg ) {
LED_Reload_On = 50;
LED_Reload_Off = 250;
I_Monitor_state = I_Neg_Caution; // Go make sure current drops back to safe limits.
}
else if( I_Sense > I_Minimum_Neg ) {
System_Flags &= ~Blink_LED; // Shutdown blink.
P2OUT &= ~M_LED; // Turn on the LED.
I_Monitor_state = I_Mon_Zero; // Current = 0, go hang.
}
break;
case I_Pos_Caution: // Input current is above the safe limit but less than absolute maximum limit.
if( I_Sense < I_Safe_Pos ) {
LED_Reload_On = 500;
LED_Reload_Off = 50;
I_Monitor_state = I_Pos_Safe; // Okay to go back.
}
else if( I_Sense > I_Maximum_Pos ) {
P1OUT &= ~Str_En; // Disconnect the cell string.
LED_Reload_On = 50;
LED_Reload_Off = 50;
Over_Current_Timer = 3400; // Give the batteries a chance to cool before allowing a restart.
I_Monitor_state = I_Mon_Max; // Absolute maximum exceeded, go wait for the current to go to zero.
}
else{ // Estimate energy consumption and cut off if too much.
Integrated_Energy += ( I_Sense - I_Safe_Pos );
if( Integrated_Energy > Too_Hot ) {
P1OUT &= ~Str_En; // Disconnect the cell string.
LED_Reload_On = 50;
LED_Reload_Off = 50;
Over_Current_Timer = 3400; // Give the batteries a chance to cool before allowing a restart.
I_Monitor_state = I_Mon_Max; // Absolute maximum exceeded, go wait for the current to go to zero.
}
}
break;
case I_Neg_Caution: // Discharge current is above the safe limit but less than absolute maximum limit.
if( I_Sense > I_Safe_Neg ) {
LED_Reload_On = 50;
LED_Reload_Off = 500;
I_Monitor_state = I_Neg_Safe; // Okay to go back.
}
else if( I_Sense < I_Maximum_Neg ) {
P1OUT &= ~Str_En; // Disconnect the cell string.
LED_Reload_On = 50;
LED_Reload_Off = 50;
Over_Current_Timer = 3400; // Give the batteries a chance to cool before allowing a restart.
I_Monitor_state = I_Mon_Max; // Absolute maximum exceeded, go wait for the current to go to zero.
}
else{ // Estimate energy consumption and cut off if too much.
Integrated_Energy += ( I_Safe_Neg - I_Sense );
if( Integrated_Energy > Too_Hot ) {
P1OUT &= ~Str_En; // Disconnect the cell string.
LED_Reload_On = 50;
LED_Reload_Off = 50;
Over_Current_Timer = 3400; // Give the batteries a chance to cool before allowing a restart.
I_Monitor_state = I_Mon_Max; // Absolute maximum exceeded, go wait for the current to go to zero.
}
}
break;
case I_Mon_Max: // Input current has exceeded acceptable limits, try to recover.
if( ( I_Sense < 532 ) && ( I_Sense > 492 ) ) {
System_Flags &= ~Blink_LED; // Shutdown blink.
P2OUT &= ~M_LED; // Turn on the LED.
I_Monitor_state = I_Mon_Zero; // Current = 0, go hang.
}
break;
}
}
if( Turn_On_Delay != ( Turn_On_Delay & System_Flags ) ) {
/***************************************************************************
*
* Monitor voltage on BAT_BUS, ADC channel A0
*
*
***************************************************************************/
switch(A0_Monitor_state) // ***** Beginning of the battery bus voltage monitor state machine *****
{
case A0_Connected: // Input current is zero amps or close to it.
if( Wait_Timer == 0 ) {
if( CELL_POS < Vmin_Cell_Top ) { P1OUT &= ~Str_En; A0_Monitor_state = A0_Disconnected; } // Disconnect the cell string from BAT_BUS.
else if( BATTERY_BUS < Vmin_Cell_Top ) { P1OUT &= ~Str_En; A0_Monitor_state = A0_Disconnected; }
else if( Str_En != ( Str_En && P1OUT ) ) { A0_Monitor_state = A0_Disconnected; }
}
break;
case A0_Disconnected: // Check see if the voltage of the top cell is within +/- 3 ADC counts of the battery bus.
if( ( ( BATTERY_BUS + 6 ) > CELL_POS ) && ( ( BATTERY_BUS - 6 ) < CELL_POS ) ) {
P1OUT |= Str_En; // Connect the cell string to BAT_BUS.
Wait_Timer = 10;
A0_Monitor_state = A0_Connected;
}
else if( ( BATTERY_BUS < 20 ) && ( I_Monitor_state < I_Pos_Caution ) ) {
P1OUT |= Str_En; // Connect the cell string to BAT_BUS.
Wait_Timer = 10;
A0_Monitor_state = A0_Connected;
}
break;
case A0_Initialize: //
P1OUT &= ~Str_En; // Disconnect the cell string from BAT_BUS.
if( Over_Current_Timer == 0 ) {
P3OUT &= ~nI_Sense_Power; // Turn on the power to the current sensor, U5.
A0_Monitor_state = A0_Disconnected;
}
break;
default:
Gen_Msg_Flags1 |= Gen_Msg_0;
A0_Monitor_state = A0_Initialize;
break;
} // End switch, monitor of the voltage on the battery bus.
} // End turn-on delay.
/***************************************************************************
*
* Name: ADC Data State Machine
*
* Description: Collect all voltage, current, and temperature readings from ADC. This state
* machine also computes the average of the last 8 samples for each of the analog inputs.
*
* Data Collected:
* P2.0 A0 BAT_BUS*
* P2.1 A1 Cell_POS*
* P2.2 A2 MID_STRING*
* P2.3 A3 I_Sns_Volt
* P2.4 A4 VREF_2.5
* P3.0 A5 UCLK
* P3.6 A6 /I_Sns_PWR
* P3.7 A7 /OS_TEMP
***************************************************************************/
if( ADC_CC == ( ADC_CC & ADC_Flags ) ) {
ADC_Flags &= ~(ADC_CC); // Clear Conversion Complete flag
switch(ADC_data_state) // ***** Beginning of ADC Data State Machine *****
{
case Acquire_A5: // Analog input A5 - spare analog, currently assigned digital output UCLK.
Ch_A5[8] -= Ch_A5[ADC_POINTER]; // Subtract oldest sample from sum of all samples.
Ch_A5[ADC_POINTER] = Analog_data; // Save latest sample.
Ch_A5[8] += Ch_A5[ADC_POINTER]; // Add in latest sample.
Analog5 = Ch_A5[8] >> 3; // Average of spare input A5 = sum/8.
ADC10CTL0 |= ADC10SC; // Start next conversion.
ADC_data_state = Acquire_A4;
break;
case Acquire_A4: // Analog input A4 - VREF_2.5
Ch_A4[8] -= Ch_A4[ADC_POINTER]; // Subtract oldest sample from sum of all samples.
Ch_A4[ADC_POINTER] = Analog_data; // Save latest sample.
Ch_A4[8] += Ch_A4[ADC_POINTER]; // Add in latest sample.
VREF = Ch_A4[8] >> 3; // Ch A4 - Average voltage of the reference.
ADC10CTL0 |= ADC10SC; // Start next conversion.
ADC_data_state = Acquire_A3;
break;
case Acquire_A3: // Analog input A3 - I_Sns_Volt - Current into or out of the cell string.
Ch_A3[8] -= Ch_A3[ADC_POINTER]; // Subtract oldest sample from sum of all samples.
Ch_A3[ADC_POINTER] = Analog_data - Ipwr_Offset; // Save latest sample less the sensor offset.
Ch_A3[8] += Ch_A3[ADC_POINTER]; // Add in latest sample.
if( ( Ch_A3[ADC_POINTER] < 25 ) || ( Ch_A3[ADC_POINTER] > I_Maximum_Pos ) ) {
P1OUT &= ~Str_En; // Disconnect the cell string.
P3OUT |= nI_Sense_Power; // Reset the Fault flag of the current sensor by cycling power to U5.
LED_Reload_On = 50;
LED_Reload_Off = 50;
Over_Current_Timer = 34; // Give the batteries a chance to cool before allowing a restart.
I_Monitor_state = I_Mon_Max; // Absolute maximum exceeded, go wait for the current to go to zero.
A0_Monitor_state = A0_Initialize; // Go see if cell string can be reconnected to BAT_BUS.
}
I_Sense = Ch_A3[8] >> 3; // Ch A3 - Average current in or out of the cell string.
ADC10CTL0 |= ADC10SC; // Start next conversion.
ADC_data_state = Acquire_A2;
break;
case Acquire_A2: // Analog input A2 - MID_STRING*
Ch_A2[8] -= Ch_A2[ADC_POINTER]; // Subtract oldest sample from sum of all samples.
Ch_A2[ADC_POINTER] = Analog_data; // Save latest sample.
Ch_A2[8] += Ch_A2[ADC_POINTER]; // Add in latest sample.
MID_STRING = Ch_A2[8] >> 3; // Ch A2 - Average voltage at cell string center tap.
// MS_f = MS_m * MID_STRING + MS_b; // Calculate the adjusted floating point equivalent.
ADC10CTL0 |= ADC10SC; // Start next conversion.
ADC_data_state = Acquire_A1;
break;
case Acquire_A1: // Analog input A1 - Cell_POS*
Ch_A1[8] -= Ch_A1[ADC_POINTER]; // Subtract oldest sample from sum of all samples.
Ch_A1[ADC_POINTER] = Analog_data; // Save latest sample.
Ch_A1[8] += Ch_A1[ADC_POINTER]; // Add in latest sample.
CELL_POS = Ch_A1[8] >> 3; // Ch A1 - Average voltage on the top cell.
// CP_f = CP_m * CELL_POS + CP_b; // Calculate the adjusted floating point equivalent.
ADC10CTL0 |= ADC10SC; // Start next conversion.
ADC_data_state = Acquire_A0;
break;
case Acquire_A0: // Analog input A0 - BAT_BUS*
Ch_A0[8] -= Ch_A0[ADC_POINTER]; // Subtract oldest sample from sum of all samples.
Ch_A0[ADC_POINTER] = Analog_data; // Save latest sample.
Ch_A0[8] += Ch_A0[ADC_POINTER]; // Add in latest sample.
BATTERY_BUS = Ch_A0[8] >> 3; // Ch A0 - Average voltage on the battery bus.
// BB_f = BB_m * BATTERY_BUS + BB_b; // Calculate the adjusted floating point equivalent.
// Housekeeping
//
ADC10CTL0 &= ~( ENC + ADC10SC ); // Disable ADC
if( ++ADC_POINTER > 7 ) { ADC_POINTER = 0; } // Point to next elements in the arrays.
if( ADC_REAL != ( ADC_REAL & ADC_Flags ) ) {
if( Real_Data_Count != 0) { Real_Data_Count--; }
else { ADC_Flags |= ADC_REAL; } // Tell the main loop data is now reliable.
}
ADC_Flags |= ADC_BCC; // Set data block complete flag.
ADC10CTL0 |= ( ENC + ADC10SC ); // Start new block conversion
if( Wait_Timer > 0 ) { Wait_Timer--; } // If not already 0, decrement the timer.
ADC_data_state = Acquire_A5; // Go get the next block of conversions
break;
default:
Gen_Msg_Flags1 |= Gen_Msg_0;
ADC_data_state = Acquire_A5;
break;
} // End switch ***** Bottom of ADC Data State Machine *****
} // End if ADC_CC and PACKET_DEFAULT
/***************************************************************************
*
* Potentiometer commands processor.
*
***************************************************************************/
switch(Command_State)
{
case Cmd_Pot_Idle:
if( Command_Flags != 0x00 ) {
if( Cmd_Set_Pot_WCR == ( Cmd_Set_Pot_WCR & Command_Flags ) ) { Command_State = Cmd_Pot_Set_WCR; }
else if( Cmd_Increment_Pot == ( Cmd_Increment_Pot & Command_Flags ) ) { Command_State = Cmd_Pot_Increment; }
else if( Cmd_Decrement_Pot == ( Cmd_Decrement_Pot & Command_Flags ) ) { Command_State = Cmd_Pot_Decrement; }
else if( Cmd_Set_Pot_DR == ( Cmd_Set_Pot_DR & Command_Flags ) ) { Command_State = Cmd_Pot_Set_DR; }
else{ Command_Flags = 0x00; }
}
break;
case Cmd_Pot_Set_WCR: // Set potentiometer to value of Wiper_Value.
switch(Sub_A_Cmd_State)
{
case Sub_A_Cmd1: // Send packet 1 of potentiometer command.
if( POT_WR_PKT != ( POT_WR_PKT & System_Flags ) ) { // Make sure the last packet transmit completed.
Data_Array_Ptr = 0;
Data_Array_Last = 2;
Local_Data[0] = POT_ACR_wr;
Local_Data[1] = POT_AR;
Local_Data[2] = POT_WCR;
System_Flags |= POT_WR_PKT; // Initiate packet write to potentiometer.
Sub_A_Cmd_State = Sub_A_Cmd2;
}
break;
case Sub_A_Cmd2: // Send packet 2 of potentiometer command.
if( POT_WR_PKT != ( POT_WR_PKT & System_Flags ) ) {
Data_Array_Ptr = 0;
Local_Data[1] = 0;
Local_Data[2] = 0;
System_Flags |= POT_WR_PKT; // Initiate packet write to potentiometer.
Sub_A_Cmd_State = Sub_A_Cmd3;
}
break;
case Sub_A_Cmd3: // Wait for second packet to complete.
if( POT_WR_PKT != ( POT_WR_PKT & System_Flags ) ) {
Sub_A_Cmd_State = Sub_A_Cmd1;
Command_Flags &= ~Cmd_Set_Pot_WCR; // Terminate this command.
Packet_Timer = 0x1000;
Command_State = Cmd_Pot_Idle; // Go wait for the next command.
}
break;
}
break;
case Cmd_Pot_Increment: // Increment potentiometer setting.
switch(Sub_B_Cmd_State)
{
case Sub_B_Cmd1:
if( POT_WR_PKT != ( POT_WR_PKT & System_Flags ) ) {
Data_Array_Ptr = 0;
Data_Array_Last = 2;
Local_Data[0] = POT_ACR_wr;
Local_Data[1] = POT_AR;
Local_Data[2] = POT_WCR;
System_Flags |= POT_WR_PKT; // Initiate packet write to potentiometer.
Sub_B_Cmd_State = Sub_B_Cmd2;
}
break;
case Sub_B_Cmd2:
if( POT_WR_PKT != ( POT_WR_PKT & System_Flags ) ) {
Data_Array_Ptr = 0;
Local_Data[1] = 0; // WCR address.
Local_Data[2] = 0xFF; // Increment command.
System_Flags |= POT_WR_PKT; // Initiate packet write to potentiometer.
Sub_B_Cmd_State = Sub_B_Cmd3;
}
break;
case Sub_B_Cmd3: // Wait for second packet to complete.
if( POT_WR_PKT != ( POT_WR_PKT & System_Flags ) ) {
Sub_B_Cmd_State = Sub_B_Cmd1;
Command_Flags &= ~Cmd_Increment_Pot; // Terminate this command.
Command_State = Cmd_Pot_Idle; // Go wait for the next command.
}
break;
}
break;
case Cmd_Pot_Decrement: // Decrement potentiometer setting.
switch(Sub_C_Cmd_State)
{
case Sub_C_Cmd1:
if( POT_WR_PKT != ( POT_WR_PKT & System_Flags ) ) {
Data_Array_Ptr = 0;
Data_Array_Last = 2;
Local_Data[0] = POT_ACR_wr;
Local_Data[1] = POT_AR;
Local_Data[2] = POT_WCR;
System_Flags |= POT_WR_PKT; // Initiate packet write to potentiometer.
Sub_C_Cmd_State = Sub_C_Cmd2;
}
break;
case Sub_C_Cmd2:
if( POT_WR_PKT != ( POT_WR_PKT & System_Flags ) ) {
Data_Array_Ptr = 0;
Local_Data[0] = 0x58; // Slave address for increment or decrement.
Local_Data[1] = 0; // WCR address.
Local_Data[2] = 0; // Decrement command.
System_Flags |= POT_WR_PKT; // Initiate packet write to potentiometer.
Sub_C_Cmd_State = Sub_C_Cmd1;
Command_Flags &= ~Cmd_Decrement_Pot; // Terminate this command.
Command_State = Cmd_Pot_Idle; // Go wait for the next command.
}
break;
}
break;
case Cmd_Pot_Set_DR: // Write a specific value to the potentiometer Data Register.
Command_Flags &= ~Cmd_Set_Pot_DR; // Terminate this command.
Command_State = Cmd_Pot_Idle; // Go wait for the next command.
break;
default:
Gen_Msg_Flags1 |= Gen_Msg_0; // Send went into the weeds message.
Command_State = Cmd_Pot_Idle; // Go wait for the next command.
break;
}
/*******************************************************************************************************************
*
* Description: Writes a byte of data to an I2C device. Assumes that the start bit has already been sent and SMBclk is low
* parameters: data - address of slave or register address
* return value: 1 if ack was received from slave - otherwise 0
*
* Just before the completion of the write sequence the SMBdata line is released immediately before the ACK and the
* SMBclk line is toggled high, then low after the ACK.
*******************************************************************************************************************/
if( POT_WRITE == ( POT_WRITE & System_Flags ) ) { // If a potentiometer SMBus byte write has been initiated then...
// P3OUT &= ~BIT3; // Clear P3 Output register, hard pulldown when direction of pin set to output.
// P3OUT |= BIT3; // Clear P3 Output register, hard pulldown when direction of pin set to output.
// This is a byte write operation to the potentiometer.
switch(Pot_Wr_State) // ***** Beginning of SMBus Byte Write State Machine *****
{
case Pot_Write_Init: // Initialize the byte write state machine.
Bit_Mask = 0x80;
Pot_Wr_State = Pot_Bit_Write;
break;
case Pot_Bit_Write:
if( --Pot_Timer == 0 ) {
if (Bit_Mask & SMBus_Buffer) { SMBdata_Set; } else{ SMBdata_Clr; }
Pot_Timer = SMB_Dly4;
Pot_Wr_State = Pot_Byte_Write;
}
break;
case Pot_Byte_Write:
if( --Pot_Timer == 0 ) {
SMBclk_Set; // Set BB_SCL IO pin to input mode and be pulled high by external resistor.
Pot_Timer = SMB_Dly4;
Pot_Wr_State = Pot_Clk_HiA;
}
break;
case Pot_Clk_HiA:
if( --Pot_Timer == 0 ) { Pot_Wr_State = Pot_Clk_LoA; Pot_Timer = SMB_Dly4; }
break;
case Pot_Clk_LoA:
if( --Pot_Timer == 0 ) {
SMBclk_Clr; // Force the BB_SCL line low.
Bit_Mask >>= 1;
if( Bit_Mask == 0 ) { Pot_Wr_State = Pot_End_Byte; } else{ Pot_Wr_State = Pot_Bit_Write; }
Pot_Timer = SMB_Dly4;
}
break;
case Pot_End_Byte: // Release SMBdata so the slave can acknowledge.
if( --Pot_Timer == 0 ) {
SMBdata_Set;
Pot_Timer = SMB_Dly4;
Pot_Wr_State = Pot_Clk_HiB;
}
break;
case Pot_Clk_HiB: // Toggle the BB_SCL line again to terminate the byte write sequence.
if( --Pot_Timer == 0 ) {
SMBclk_Set; // Set BB_SCL IO pin to input mode and be pulled high by external resistor.
Pot_Timer = SMB_Dly4;
Pot_Wr_State = Pot_Clk_LoB;
}
break;
case Pot_Clk_LoB:
if( --Pot_Timer == 0 ) {
SMBclk_Clr; // Force the BB_SCL line low.
// acked = (P1IN & TS_SDA); // Read the acknowledge from the slave.
// if( acked == 0 ) {
// }
Pot_Timer = SMB_Dly4;
Pot_Wr_State = Pot_Clk_End;
}
break;
case Pot_Clk_End:
System_Flags &= ~POT_WRITE; // Terminate the byte write operation.
Pot_Wr_State = Pot_Write_Init; // Rearm the state machine.
break;
default:
System_Flags &= ~POT_WRITE; // Terminate the byte write operation.
Gen_Msg_Flags1 |= Gen_Msg_0; // Send went into the weeds message.
Pot_Wr_State = Pot_Write_Init; // Go wait for the next command.
break;
} // Endswitch Pot_Wr_State.
} // Endif byte write.
if( POT_WRITE != ( POT_WRITE & System_Flags ) ) { // Wait here a potentiometer packet transmition flag.
/*******************************************************************************************************************
*
* Packet write operation to potentiometer.
*
* BB_SDA and BB_SCL must be deasserted at this point in time by both the potentiometer and the Master to assure
* a correct START sequence.
*
*******************************************************************************************************************/
switch(Pot_Pkt_Wr_State) // ***** Beginning of SMBus Packet Write State Machine *****
{
case Pot_Pkt_Wr_Idle: // Wait for packet start sequence.
if( POT_WR_PKT == ( POT_WR_PKT & System_Flags ) ) { Pot_Pkt_Wr_State = Pot_Pkt_Wr_St2; }
break;
case Pot_Pkt_Wr_St2: // Begin start sequence.
if( --Pot_Timer == 0 ) {
SMBdata_Clr; // Drop the data line.
Pot_Timer = SMB_Dly4;
Pot_Pkt_Wr_State = Pot_Pkt_Wr_Start;
}
break;
case Pot_Pkt_Wr_Start: // Drop the clock line.
if( --Pot_Timer == 0 ) {
SMBclk_Clr; // Force the BB_SCL line low.
Pot_Timer = SMB_Dly4;
Pot_Pkt_Wr_State = Pot_Pkt_Wr_Data;
}
break;
case Pot_Pkt_Wr_Data: // Transmit byte sequence.
if( ( Data_Array_Ptr <= Data_Array_Last ) && ( POT_WRITE != ( POT_WRITE & System_Flags ) ) ) {
SMBus_Buffer = Local_Data[Data_Array_Ptr]; // Copy the next data byte to be transmitted to the transmission buffer.
Data_Array_Ptr++; // Increment the array index.
System_Flags |= POT_WRITE; // Set the SMBus write byte flag.
}
else{ Pot_Pkt_Wr_State = Pot_Pkt_Wr_Stop1; }
break;
case Pot_Pkt_Wr_Stop1: // End data transfer with Stop Sequence.
if( --Pot_Timer == 0 ) {
SMBdata_Clr; // Drop the data line.
Pot_Timer = SMB_Dly4;
Pot_Pkt_Wr_State = Pot_Pkt_Wr_Stop2;
}
break;
case Pot_Pkt_Wr_Stop2: // Raise the clock line.
if( --Pot_Timer == 0 ) {
SMBclk_Set; // Set BB_SCL IO pin to input mode and be pulled high by external resistor.
Pot_Timer = SMB_Dly4;
Pot_Pkt_Wr_State = Pot_Pkt_Wr_Stop3;
}
break;
case Pot_Pkt_Wr_Stop3: // Raise the data line to complete the sequence.
if( --Pot_Timer == 0 ) {
SMBdata_Set; // The SMBus is now idle.
System_Flags &= ~POT_WR_PKT; // Disable potentiometer packet transmit.
Pot_Timer = SMB_Dly4;
Pot_Pkt_Wr_State = Pot_Pkt_Wr_Idle; // Rearm the state machine.
}
break;
default:
SMBclk_Set; // Set BB_SCL IO pin to input mode and be pulled high by external resistor.
SMBdata_Set; // The SMBus is now idle.
System_Flags &= ~POT_WR_PKT; // Disable potentiometer packet transmit.
Gen_Msg_Flags1 |= Gen_Msg_0; // Send went into the weeds message.
Pot_Pkt_Wr_State = Pot_Pkt_Wr_Idle; // Rearm the state machine.
break;
} // ***** End of SMBus Packet Write State Machine *****
} // End if packet send flag is set.
Watch_Dog = WATCH_TIME_OUT; // Restart the Watch dog timer
} // end While (1)
} //========================= End of Main ===========================================
//================ ISRs ===================================================
/* -----------------------------------------
* NAME: evADC_isr
*
* DESCRIPTION:
* Conversion done for the ADC
* set variest process flags
*
*
* ------------------------------------------*/
#pragma vector = ADC10_VECTOR
__interrupt void evADC_isr(void)
{
_DINT();
ADC_Flags |= ADC_CC; // Set conversion complete flag
ADC10CTL0 &= ~(ADC10IFG); // Clear ADC conversion complete interrupt flag
Analog_data = ADC10MEM; // Save data from ADC in temporary buffer
ADC10CTL0 &= ~ADC10SC; // Start next conversion.
_EINT();
}
/*********************************************************************************************
* NAME: evRTC_isr
*
* DESCRIPTION: Real time clock interrupt processor.
* This routine sets process flags to inform the main process
* of events and reinitializes the various counters.
*
*********************************************************************************************/
#pragma vector = WDT_VECTOR
__interrupt void evRTC_isr(void)
{
_DINT();
if( Watch_Dog != 0 ) { Watch_Dog--; } // If count reaches 0, halt countdown.
else { WDTCTL = 0x00 + WDTHOLD; } // Time-out, something bad has happened, try soft restart to recover.
if(Over_Current_Timer != 0) { Over_Current_Timer--; } // If count reaches 0, halt countdown.
if(LED_Timer != 0) { LED_Timer--; } // If count reaches 0, halt countdown.
if(Powerup_Timer != 0) { Powerup_Timer--; } // If count reaches 0, halt countdown.
IFG1 &= ~WDTIFG; // Reset timer flag, enable next interrupt.
_EINT();
}
**Attention** This is a public forum