/* PMP7647
*MSP430F5132 - 12A MPPT CHARGER AND LED DRIVER(12 LEDS,700mA)*/

/* Formulae to calculate ADC readings of different system parameters :
 * Panel Voltage = 36.83 * PV - 63 ,
 * Battery Voltage = BV * 52.44 ,
 * Battery Current = BI * 82
 * Load Current = LI * 278.25
 * Load Voltage = LV * 13.61    */

//Header Files//
#include "msp430f5132.h"
#include "hal_tlv.h"
#define CALTDH0CTL1_256        *((unsigned int *)0x1A36)

#define TURN_OFF_BUCK_STAGE 	TD0CCTL1 = TD0CCTL2 = OUTMOD_0
#define TURN_ON_BUCK_STAGE 	TD0CCTL1 = OUTMOD_3; \
							TD0CCTL2 = OUTMOD_7;
#define TURN_ON_BOOST_STAGE TD1CCTL1 = OUTMOD_7
#define TURN_OFF_BOOST_STAGE TD1CCTL1 = OUTMOD_0

#define TURN_OFF_TIMER_A    TA0CTL &= ~MC_1

#define TURN_ON_TIMER_A    TA0CTL |= MC_1 ;\
							ms = sec = min = 0;

#define CC_LIMIT			615   								// 984 for 12A of 7647 board, 615 for 6A of 7646 board
#define CC_TO_CV_LIMIT		745									// boost voltage 14.2V
#define FLOAT_VOLTAGE		724 								//float voltage 13.8v

//Definitions//
#define PANEL_ENABLE		P3OUT &= ~BIT3						//RESET TO ENABLE PANEL***P3.3
#define PANEL_DISABLE		P3OUT |= BIT3						//SET TO DISABLE PANEL
#define LOAD_ENABLE			P3OUT &= ~BIT2						//RESET TO ENABLE LOAD***P3.2
#define LOAD_DISABLE		P3OUT |= BIT2						//SET TO DISABLE LOAD
#define GATE_DRIVE_ENABLE		PJOUT |= BIT6						//SET TO ENABLE OTHER IC'S***PJ.6
#define GATE_DRIVE_DISABLE 		PJOUT &= ~BIT6						//RESET TO DISABLE OTHER IC'S

//Index of respective elements in adc output array
#define P_V 		4
#define B_V			3
#define B_I			2
#define L_V			1
#define L_I			0


#define REF_AVG_LOAD_COUNTER 	4
#define REF_AVG_MPPT_COUNTER	64
#define REF_AVG_STANDBY_COUNTER	32 // 8 seconds in standby mode

#define MPPT_LOOP_EXIT_LIMIT 200 // 1 second

#define MINUTES				1 									//MINUTES to provide more flexibility in terms of durations

#define REF_LOAD_CURRENT_FULL_BRIGHTNESS		143		// (195 for 700mA , 5 offset for 7647 board) ,143 for 350mA 7646 board
#define REF_LOAD_CURRENT_HALF_BRIGHTNESS        75      //( 97 for 350mA , 5 offset for 7647 board) , 75 for 170mA 7646 board
#define REF_LOAD_CURRENT_LOW_BRIGHTNESS			10		// 30 for 100mA

#define SUFFICIENT_PANEL_VOLTAGE	490							//15V; To turn off the load; charge battery
#define PANEL_UPPER_LIMIT			842							// 24.6V to turn off the PWM to buck stage mosfet; protection purpose

#define DUTY_BUCK_LOWER_THRESHOLD					50		//97.5%
#define DUTY_BUCK_UPPER_THRESHOLD					1600

#define OC_TRIGGERED_COUNTER_THRESHOLD 1000 // 5 seconds delay , 5.2ms per average
#define OV_TRIGGERED_COUNTER_THRESHOLD 1000 // 5 seconds delay ,5.2ms per average

#define MPPT_STATE 0
#define STAND_BY_STATE 1
#define LOAD_MANAGEMENT_STATE 2
#define START_MPPT_STATE 3
#define START_STANDBY_STATE 4
#define START_LOAD_MANAGEMENT_STATE 5

//Variable declaration//
unsigned int 		ADC_Readings [5],
					System_reset_Mode_ON, Load_Monitor_Mode_ON,									// Flags for comparator ISR
					OC_Triggered = 0, OC_Triggered_Counter = 0,// Flags for over load current protection
					OV_Triggered = 0, OV_Triggered_Counter = 0,// Flags for over load voltage protection
					Load_On = 0,
					Charge_On = 0,
					CV_Mode = 0,
					cc_to_cv = 0,
					Wait_State=0,
					Wait_Counter=0,
					Battery_Low_Current_Counter=0;

int MPPT_Direction=1,LPM3_On = 0;
													// counters to count for 5hours (Programmable for any time), TIMER A
unsigned long		Panel_Voltage,
					Battery_Voltage,
					Load_Voltage,
					Battery_Charging_Current=0,
					Load_Current,														//inputs to the microcontroller
					Prev_Battery_Charging_Current=0,										//comparison purpose
					Prev_Load_Voltage,
					Duty_Buck = 400, // 80% duty cycle
					Ref_Load_Current = 0,													// to be initialised according to the output current
					Panel_Voltage_Buffer = 0,
					Battery_Voltage_Buffer = 0,
					Load_Voltage_Buffer = 0,
					Battery_Charging_Current_Buffer = 0,
					Load_Current_Buffer = 0,
					Duty_Boost = 100,
					MPPT_Loop=1,
					MPP_Loop_Exit_Counter=0,
					CC_Loop_Exit_Counter=0;

//Average counter and reference counter
unsigned int 		Avg_MPPT_Counter = 0,
					Avg_LOAD_Counter = 0;
int Present_State;

int ms=0,sec=0,min=0;

void Init_Clocks (void);
void SetVcoreUp (unsigned int level);
void init_IO (void);
void init_WDT (void);
void init_ADC (void);
void MPPT (void);
void init_TimerD_BUCK (void);
void init_TimerD_BOOST (void);
void init_TimerA (void);
void Load_Management (void);
void PI_Control (void);
void init_Comparator_LoadMonitor (void);
void init_Comparator_System_Reset (void);
void Battery_Charge_Profiling(void);
void init_WDTLowpowermode3 (void);
void Average_LOAD_ADC_Values(void);
void Average_MPPT_ADC_Values(void);
void Average_STANDBY_ADC_Values();

void main (void)
{
		WDTCTL = WDTPW + WDTHOLD; // Stop WDT

		_delay_cycles(2000000);

		Init_Clocks ();							  				// Initialize clocks for 25 MHz
		__bis_SR_register(GIE);        							// Enable Interrupts


		init_IO ();

		init_ADC ();

		init_TimerD_BUCK ();

		init_TimerD_BOOST ();

		init_TimerA ();

		// just for testing
		P3DIR |=BIT6;
		P3OUT |= BIT6;
		P2DIR |=BIT5;
		P2OUT |= BIT5;

		init_WDT ();// set the ADC sampling interval to 1.3ms

		GATE_DRIVE_DISABLE;
		TURN_OFF_BUCK_STAGE;
		TURN_OFF_BOOST_STAGE;
		LOAD_DISABLE;
	//	Present_State = START_LOAD_MANAGEMENT_STATE;
		Present_State = START_MPPT_STATE;

		while(1)
		{
				switch(Present_State)
				{
					case MPPT_STATE :
					if(Avg_MPPT_Counter == REF_AVG_MPPT_COUNTER)
					{

						Average_MPPT_ADC_Values();

						// Battery_Voltage = 512 corresponds to approximately 10.2v
						// (((panel_voltage+63)/36.83) > ((Battery_Voltage/ 50.25))) => this expression is to get actual values of BV and PV
						if(/*(Panel_Voltage > SUFFICIENT_PANEL_VOLTAGE) && (((Panel_Voltage+63)/36.83) > ((Battery_Voltage/ 50.25))) &&*/(Battery_Voltage > 512)&&(Panel_Voltage < PANEL_UPPER_LIMIT)&&(!Wait_State))
						{


							PANEL_ENABLE;

							TURN_ON_BUCK_STAGE;

							if(MPPT_Loop == 1)
								MPPT();
							else
								Battery_Charge_Profiling();

							// update timers
							TD0CCTL0 &= ~CCIFG; // wait till the timer completes its current cycle
							while(!(TD0CCTL0 & CCIFG));

							TD0CCR1 = Duty_Buck;
							TD0CCR2 = Duty_Buck - 60;

						}//end if

						// value 10 corresponds to approximately .12A
						if (((Battery_Charging_Current < 10)&&(!Wait_State))||(Panel_Voltage > PANEL_UPPER_LIMIT))
						{
							Battery_Low_Current_Counter++;
							if((Battery_Low_Current_Counter>10)||(Panel_Voltage > PANEL_UPPER_LIMIT))
							{
									TURN_OFF_BUCK_STAGE;
									PANEL_DISABLE;
									Duty_Buck=400; // 80%
									Wait_State =1;
									Wait_Counter =0;
									// if PV<upper limit , then BI is low bcz PV<15
									if(Panel_Voltage < PANEL_UPPER_LIMIT)
									{
										Present_State = START_STANDBY_STATE;
									}
							}
						}
						else if((Battery_Charging_Current > 9))
						{
							// reset counter once the battery current comes up
							Battery_Low_Current_Counter=0;
						}

						/* This block generates approximately 5 seconds delay
						 * Whenever battery current goes below a threshold value or panel voltage goes above upper limit
						 *  panel is switched off and restarted after 5 seconds*/
						if(Wait_State==1)
						{
							Wait_Counter++;
							if(Wait_Counter > 100)
							{
								Wait_State =0;
								Wait_Counter =0;
								Battery_Low_Current_Counter=0;
							}
						}
					}// end of MPPT state
					break;

					case STAND_BY_STATE :
						if(Avg_MPPT_Counter == REF_AVG_STANDBY_COUNTER)
						{
							Average_STANDBY_ADC_Values();

							if(Panel_Voltage > 490) // PV>15v
							{
							//	GATE_DRIVE_ENABLE;
							//	Present_State = START_MPPT_STATE;
								//system reset
								PMMCTL0 |=PMMSWBOR; // Brown out reset by software

							}
							else if(Panel_Voltage < 125) // PV<5v
							{
								//enable timer D for buck and boost
								TD0CTL0 |= MC_1;TD1CTL0 |= MC_1;
								LOAD_DISABLE;
								PANEL_DISABLE;
								GATE_DRIVE_ENABLE;
								Present_State = START_LOAD_MANAGEMENT_STATE;
								Load_On=0;
							}
							else
							{
								Present_State =STAND_BY_STATE;
								LPM3_On=1;
								__bis_SR_register(LPM3);
							}
						}// end of stand-by state block
						break;

					case START_MPPT_STATE :
					{
						//testing to indicate state change
						P2OUT |=BIT5;

						init_WDT(); // set the ADC sampling interval to 1.3ms
						// try to estimate initial duty cycle
					//	ratio =(((float)Battery_Voltage/ 52.44)/(((float)Panel_Voltage+63)/36.83));
					//	Duty_Buck=(1-ratio)*2000;

						Duty_Buck=400;
						MPPT_Direction=1;
						GATE_DRIVE_ENABLE;
						Present_State =MPPT_STATE;
					} // end of start mppt state
					break;

				case START_STANDBY_STATE :
					{
						//testing to indicate state change
						P2OUT &= ~BIT5;
						init_WDTLowpowermode3(); // change the ADC sampling interval from 1.3ms to .25s
						GATE_DRIVE_DISABLE;

						//for low standby current
						PANEL_ENABLE;
						LOAD_ENABLE;

						CBCTL1 &= ~CBON; // switch off the comparator to save power
						//disable timer D to save power
						TD0CTL0 &= ~MC_1;TD1CTL0 &= ~MC_1;

						Present_State = STAND_BY_STATE;
					}// end of start standby state
					break;


				case LOAD_MANAGEMENT_STATE :
					if(Avg_MPPT_Counter == REF_AVG_MPPT_COUNTER)
						Average_MPPT_ADC_Values();

					if(Avg_LOAD_Counter == REF_AVG_LOAD_COUNTER)
					{
						Average_LOAD_ADC_Values();
						// first check all the exit conditions
						if (Panel_Voltage > 490) // PV>15v
						{
							//system reset
							PMMCTL0 |=PMMSWBOR; // Brown out reset by software
						}
						else if(Panel_Voltage > 125) // PV>5v
						{
							GATE_DRIVE_DISABLE;
							Present_State = START_STANDBY_STATE;
							TURN_OFF_BOOST_STAGE;
							TURN_OFF_TIMER_A;
							Load_On=0;
							LOAD_DISABLE;
						}


						else
						{
							if (Battery_Voltage < 525) // BV < 10v
							{
								GATE_DRIVE_DISABLE;
								init_Comparator_System_Reset();
								__bis_SR_register(LPM4);
							}
							else if(Battery_Voltage < 545) // BV < 11v
							{
								Ref_Load_Current = REF_LOAD_CURRENT_LOW_BRIGHTNESS;
								TURN_OFF_TIMER_A;
							}

							if(OC_Triggered) // if over current has triggered wait for approximately 10s
							{
								OC_Triggered_Counter++;
								if(OC_Triggered_Counter == OC_TRIGGERED_COUNTER_THRESHOLD)
								{
									Duty_Boost = 100;
									TURN_ON_BOOST_STAGE;
									LOAD_ENABLE;
									Load_On=1;
									OC_Triggered=0;
									OC_Triggered_Counter=0;
								}
							}

							if(OV_Triggered) // if over voltage has triggered wait for approximately 10s
							{
								OV_Triggered_Counter++;
								if(OV_Triggered_Counter == OV_TRIGGERED_COUNTER_THRESHOLD)
								{
									Duty_Boost = 100;
									TURN_ON_BOOST_STAGE;
									LOAD_ENABLE;
									Load_On=1;
									OV_Triggered=0;
									OV_Triggered_Counter=0;
								}
							}

							if(Load_On)
								Load_Management();
						}
					}// end of load management state block
				break;

				case START_LOAD_MANAGEMENT_STATE :
				{
					//testing to indicate state change
					P2OUT |=BIT5;
					if(Battery_Voltage > 603)// BV>12v
					{
						GATE_DRIVE_ENABLE;
						PANEL_DISABLE;
						init_WDT(); // initialize ADC sampling interval to 1.3m
						init_Comparator_LoadMonitor();
						TURN_ON_TIMER_A;
						//	Ref_Load_Current = REF_LOAD_CURRENT_HALF_BRIGHTNESS;
						Ref_Load_Current = REF_LOAD_CURRENT_FULL_BRIGHTNESS;
						Load_On=1;
						Duty_Boost=100;
						TURN_ON_BOOST_STAGE;
						LOAD_ENABLE;
						Present_State = LOAD_MANAGEMENT_STATE;
					}
				}
					break;

			default :  break;

			}//end of switch block

	}//end of while

}//end main

void MPPT (void)
{
		if(Battery_Charging_Current<Prev_Battery_Charging_Current)
		{
				MPPT_Direction = MPPT_Direction * -1;
		}


		if(MPPT_Direction == 1)
		{
				Duty_Buck ++;
				if(Duty_Buck>DUTY_BUCK_UPPER_THRESHOLD)
				{
					Duty_Buck=DUTY_BUCK_UPPER_THRESHOLD;
				}
		}
		else
		{
			Duty_Buck --;
			if(Duty_Buck<DUTY_BUCK_LOWER_THRESHOLD)
			{
					Duty_Buck=DUTY_BUCK_LOWER_THRESHOLD;
			}
		}

		Prev_Battery_Charging_Current = Battery_Charging_Current;

		if(Battery_Charging_Current >= CC_LIMIT ||(Battery_Voltage >= CC_TO_CV_LIMIT))
		{
			MPP_Loop_Exit_Counter ++;
				if (MPP_Loop_Exit_Counter > MPPT_LOOP_EXIT_LIMIT)
				{
					MPPT_Loop = 0;
					MPP_Loop_Exit_Counter = 0;
					CC_Loop_Exit_Counter=0;
					if (Battery_Voltage > CC_TO_CV_LIMIT)
						CV_Mode = 1;
					else
						CV_Mode = 0;
				}
		}
		else
			MPP_Loop_Exit_Counter = 0;

}

void Battery_Charge_Profiling(void)
{
	if ((Battery_Voltage <= CC_TO_CV_LIMIT)&& (!CV_Mode))
	{
		if (Battery_Charging_Current < CC_LIMIT)
		{
			Duty_Buck--;
			if (Duty_Buck < DUTY_BUCK_LOWER_THRESHOLD)
			{
				Duty_Buck = DUTY_BUCK_LOWER_THRESHOLD;

				CC_Loop_Exit_Counter ++;
				if (CC_Loop_Exit_Counter > MPPT_LOOP_EXIT_LIMIT)
				{
					MPPT_Loop = 1;
					MPP_Loop_Exit_Counter = 0;
					CC_Loop_Exit_Counter = 0;
					Present_State = START_MPPT_STATE;
				}
			}
		}
	else
		{
			Duty_Buck ++;
			if (Duty_Buck > DUTY_BUCK_UPPER_THRESHOLD)
				Duty_Buck = DUTY_BUCK_UPPER_THRESHOLD;
			CC_Loop_Exit_Counter = 0;
		}
	}
	else
	{
		CV_Mode = 1;

      	if (Battery_Voltage < CC_TO_CV_LIMIT)
		{
			Duty_Buck--;
			if (Duty_Buck < DUTY_BUCK_LOWER_THRESHOLD)
				Duty_Buck = DUTY_BUCK_LOWER_THRESHOLD;
		}
		else
		{
			Duty_Buck ++;
			if (Duty_Buck > DUTY_BUCK_UPPER_THRESHOLD)
				Duty_Buck = DUTY_BUCK_UPPER_THRESHOLD;

		}

		if (Battery_Voltage < FLOAT_VOLTAGE - 20)
		{
			CC_Loop_Exit_Counter ++;
			if (CC_Loop_Exit_Counter > MPPT_LOOP_EXIT_LIMIT)
			{
				MPPT_Loop = 1;
				MPP_Loop_Exit_Counter = 0;
				CC_Loop_Exit_Counter = 0;
				Present_State = START_MPPT_STATE;
			}
		}
	}
}

void Load_Management (void)
{
	if (Load_Current > (Ref_Load_Current  + 1) )
						{
								Duty_Boost --;
								if (Duty_Boost < 3) Duty_Boost = 3;
						}
						else if(Load_Current < (Ref_Load_Current - 1))
						{
								Duty_Boost ++;
								if (Duty_Boost > 1600) Duty_Boost = 1600; // max of 50v out
						}

		TD1CCR1 = Duty_Boost;
}

void Average_MPPT_ADC_Values()
{
	Avg_MPPT_Counter = 0;
	Panel_Voltage 	= Panel_Voltage_Buffer/REF_AVG_MPPT_COUNTER;
	Battery_Voltage = Battery_Voltage_Buffer/REF_AVG_MPPT_COUNTER;
	Load_Voltage 	= Load_Voltage_Buffer/REF_AVG_MPPT_COUNTER;
	Battery_Charging_Current = Battery_Charging_Current_Buffer/REF_AVG_MPPT_COUNTER;

	Load_Voltage_Buffer = 0;
	Panel_Voltage_Buffer = 0;
	Battery_Voltage_Buffer = 0;
	Battery_Charging_Current_Buffer = 0;
}

void Average_STANDBY_ADC_Values()
{
	Avg_MPPT_Counter = 0;
	Panel_Voltage 	= Panel_Voltage_Buffer/REF_AVG_STANDBY_COUNTER;
	Battery_Voltage = Battery_Voltage_Buffer/REF_AVG_STANDBY_COUNTER;
	Load_Voltage 	= Load_Voltage_Buffer/REF_AVG_STANDBY_COUNTER;
	Battery_Charging_Current = Battery_Charging_Current_Buffer/REF_AVG_STANDBY_COUNTER;

	Load_Voltage_Buffer = 0;
	Panel_Voltage_Buffer = 0;
	Battery_Voltage_Buffer = 0;
	Battery_Charging_Current_Buffer = 0;
}

void Average_LOAD_ADC_Values()
{
	Avg_LOAD_Counter = 0;
	Load_Current = Load_Current_Buffer/REF_AVG_LOAD_COUNTER;				// Copy ADC Readings for use
	Load_Current_Buffer = 0;
}
//WDT to restart ADC
void init_WDT (void)
{

		WDTCTL = WDT_MDLY_32;                     			// WDT 32ms from 1MHz, SMCLK, interval timer
		SFRIE1 |= WDTIE;                          			// Enable WDT interrupt
}

void init_WDTLowpowermode3 (void)
{
		WDTCTL = WDT_ADLY_250;                     			// WDT 250ms, ACLK, interval timer
		SFRIE1 |= WDTIE;                          				// Enable WDT interrupt
}

// Watchdog Timer interrupt service routine
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR(void)
{

		__data16_write_addr((unsigned short) &DMA0DA,(unsigned long) &ADC_Readings[0]);
		ADC10CTL0 |= ADC10ENC + ADC10SC+ ADC10ON;        			// Sampling and conversion start
}


void init_TimerD_BUCK (void)
	{
		struct s_TLV_Timer_D_Cal_Data * pTD0CAL;  				// Structure initialized in tlv.h
    	unsigned char bTD0CAL_bytes;

    	//Configure TimerD in Hi-Res Free Running Mode
    	Get_TLV_Info(TLV_TIMER_D_CAL, 0, &bTD0CAL_bytes, (unsigned int **) &pTD0CAL);
    															//Get TimerD0 Cal Values (instance 0)
    	if(bTD0CAL_bytes == 0x0)
    	{
    															// No TimerD free running cal data found
    	    while(1);                             				// Loop here
    	}

    	TD0CTL0 = TDSSEL_2;                       				// TDCLK = SMCLK = 25MHz = Hi-Res input clk select
    	TD0HCTL1 = pTD0CAL->TDH0CTL1_200;        	// Read the 200Mhz TimerD TLV Data
    	TD0CTL1 |= TDCLKM_1;
    	TD0HCTL0 = TDHEN + TDHM_0;                	// CALEN=0 => free running mode; High-resolution clock 8x Timer_D clock; High-resolution mode enable
    	// TDHM_0 => clk = 200 * 1  = 200 Mhz, TDHM_1 => clk = 200 * 2  = 400 Mhz

    	P2SEL |= BIT0;
    	P2DIR |= BIT0;
    	TD0CCR0 = 2000;											//TERMINAL COUNT for T0; 1137 FOR 180kHz FROM 200MHz; 2000 for 100kHz from 200MHz

   // 	TD0CCTL1 |= OUTMOD_3;									//SET-RESET
   // 	TD0CCTL2 |= OUTMOD_7;									//RESET-SET(delayed start)


		TD0CCR1 = Duty_Buck;
    	TD0CCR2 = Duty_Buck - 60;

    	TD0CTL0 |= MC_1 + TDCLR;

    	__delay_cycles(6000000);								//Delayed start of TD0.2

    										//increasing duty buck will actually decrease overall dutycycle
}

void init_TimerD_BOOST (void)
{
	struct s_TLV_Timer_D_Cal_Data * pTD1CAL;  // Structure initialized in tlv.h
	unsigned char bTD1CAL_bytes;

			P2SEL |= BIT2;
	    	P2DIR |= BIT2;
	    	TD1CTL0 |=  MC_1; // SMCLK , up mode
	    	TD1CTL1 |= TDCLKM_1;
	    	TD1HCTL0 |=TDHEN + TDHM_0;
	    	// TDHM_0 => clk = 200 * 1  = 200 Mhz, TDHM_1 => clk = 200 * 2  = 400 Mhz

	    	Get_TLV_Info(TLV_TIMER_D_CAL, 0, &bTD1CAL_bytes, (unsigned int **) &pTD1CAL);
	    					                                               //Get TimerD0 Cal Values (instance 0)
	    		if(bTD1CAL_bytes == 0x0)
	    		{
	    					    while(1);                             // Loop here
	    		}

	    	TD1HCTL1 = pTD1CAL->TDH0CTL1_200;
	    	TD1HCTL0 |=TDHRON; // HR ON
	    	TD1CTL0 |= TDCLR;
	    	//TD1CCTL1 = OUTMOD_7;
	    	TD1CCR0 = 2000;
	    	TD1CCR1 = Duty_Boost; // start from very low duty cycle
	    	TD1CTL0 |= MC_1 + TDCLR;
}

void init_TimerA (void)
{
		TA0CCR0 = 25000;								// To count 1ms
		TA0CTL |= TASSEL_2 + TAIE;
		TA0CCTL0 |= CCIE;

}

// Timer0 A0 interrupt service routine; count for any hours, specified in minutes
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{

		ms++;
			if(ms == 1000)
			{
				sec++;
				ms = 0;
			}

			if(sec == 60)
			{
				min++;
				ms = sec = 0;
			}
			if(min == MINUTES)
			{
				ms = sec = min = 0;

				if (Ref_Load_Current == REF_LOAD_CURRENT_FULL_BRIGHTNESS)
						Ref_Load_Current = REF_LOAD_CURRENT_HALF_BRIGHTNESS;
				else
						Ref_Load_Current = REF_LOAD_CURRENT_FULL_BRIGHTNESS;
			}
			TA0CCTL0 &= ~CCIFG;
			TA0CTL &= ~TAIFG;
}

void PI_Control (void)
	{

	}

/*Comparator generates interrupt when +ve terminal is higher than -ve one
 * So here ref voltage is given to -ve terminal and Panel voltage is given to +ve terminal
 *Configured to detect over current.
 * Generates interrupt when load current goes above approximately 800mA */
void init_Comparator_LoadMonitor (void)
{
	System_reset_Mode_ON=0;
	Load_Monitor_Mode_ON=1;
			// clear all registers
					CBCTL0 = CBCTL1 =CBCTL2 = CBCTL3 = CBINT =0;

			CBCTL0 |= CBIPEN + CBIPSEL_4; 			// Enable V+, input channel CB4
			CBCTL1 |= CBPWRMD_1;          			// normal power mode
			CBCTL2 |= CBRSEL;             			// VREF is applied to -terminal

			CBCTL3 |= BIT4;               			// Input Buffer Disable @P1.4/CB4

			CBCTL2 |= CBRS_1 + CBREF1_4 + CBREF0_4; // VCC applied to R-ladder; to be set after calculation

			__delay_cycles(7500);         			// delay for the reference to settle
			CBINT &= ~(CBIFG + CBIIFG);   			// Clear any errant interrupts
			CBINT  |= CBIE;               			// Enable CompB Interrupt on rising edge of CBIFG (CBIES=0)
			CBCTL1 |= CBON;               			// Turn On ComparatorB
}

void init_Comparator_System_Reset (void)
{
	System_reset_Mode_ON=1;
	Load_Monitor_Mode_ON=0;

	// clear all registers
				CBCTL0 = CBCTL1 =CBCTL2 = CBCTL3 = CBINT =0;

		CBCTL0 |= CBIPEN + CBIPSEL_0; 			// Enable V+, input channel CB0
		CBCTL1 |= CBPWRMD_1;          			// normal power mode
		CBCTL2 |= CBRSEL;             			// VREF is applied to -terminal

		CBCTL3 |= BIT0;               			// Input Buffer Disable @P1.4/CB4

		CBCTL2 |= CBRS_1 + CBREF1_10 + CBREF0_10; // VCC applied to R-ladder; to be set after calculation

		__delay_cycles(7500);         			// delay for the reference to settle
		CBINT &= ~(CBIFG + CBIIFG);   			// Clear any errant interrupts
		CBINT  |= CBIE;               			// Enable CompB Interrupt on rising edge of CBIFG (CBIES=0)
		CBCTL1 |= CBON;               			// Turn On ComparatorB


}

// Comp_B ISR - FOR SYSTEM RESET AND OVERCURRENT PROTECTION
#pragma vector=COMP_B_VECTOR
__interrupt void Comp_B_ISR (void)
{
	if(Load_Monitor_Mode_ON)
	{
		TURN_OFF_BOOST_STAGE;
		LOAD_DISABLE;
		Load_On = 0;

		CBINT &= ~CBIFG; 		// Clear Interrupt flag

		OC_Triggered = 1;
		OC_Triggered_Counter = 0;					//Take action for over current protection by setting a flag
	}
	else if(System_reset_Mode_ON)
	{
		CBINT &= ~CBIFG;
		PMMCTL0 |=PMMSWBOR; // Brown out reset by software
	}
}


// Clocks And Vcore
void Init_Clocks (void)
{

	SetVcoreUp (0x01);
	SetVcoreUp (0x02);
	SetVcoreUp (0x03);

	// Configure DCO = 25Mhz
	UCSCTL3 = SELREF_2;                       // Set DCO FLL reference = REFO
	UCSCTL4 |= SELA_2;                        // Set ACLK = REFO
	__bis_SR_register(SCG0);                  // Disable the FLL control loop
	UCSCTL0 = 0x0000;                         // Set lowest possible DCOx, MODx
	UCSCTL1 = DCORSEL_7;                      // Select DCO range 50MHz operation
	UCSCTL2 = FLLD_1 + 762;                   // Set DCO Multiplier for 25MHz
	                                          // (N + 1) * FLLRef = Fdco
	                                            // (762 + 1) * 32768 = 25MHz
	                                            // Set FLL Div = fDCOCLK/2
	__bic_SR_register(SCG0);                  // Enable the FLL control loop

	// Worst-case settling time for the DCO when the DCO range bits have been
	// changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
	// UG for optimization.
	// 32 x 32 x 25 MHz / 32,768 Hz ~ 780k MCLK cycles for DCO to settle
	__delay_cycles(782000);

	// Loop until Xt1 & DCO stabilizes - In this case only DCO has to stabilize
	do
	{
	    UCSCTL7 &= ~(XT1LFOFFG + XT1HFOFFG + DCOFFG);
	                                            // Clear XT1,DCO fault flags
	    SFRIFG1 &= ~OFIFG;                      // Clear fault flags
	}while (SFRIFG1&OFIFG);                   // Test oscillator fault flag

}

void SetVcoreUp (unsigned int level)
{
  // Open PMM registers for write
  PMMCTL0_H = PMMPW_H;
  // Set SVS/SVM high side new level
  SVSMHCTL = SVSHE + SVSHRVL0 * level + SVMHE + SVSMHRRL0 * level;
  // Set SVM low side to new level
  SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 * level;
  // Wait till SVM is settled
  while ((PMMIFG & SVSMLDLYIFG) == 0);
  // Clear already set flags
  PMMIFG &= ~(SVMLVLRIFG + SVMLIFG);
  // Set VCore to new level
  PMMCTL0_L = PMMCOREV0 * level;
  // Wait till new level reached
  if ((PMMIFG & SVMLIFG))
    while ((PMMIFG & SVMLVLRIFG) == 0);
  // Set SVS/SVM low side to new level
  SVSMLCTL = SVSLE + SVSLRVL0 * level + SVMLE + SVSMLRRL0 * level;
  // Lock PMM registers for write access
  PMMCTL0_H = 0x00;
}

//IO INITIALISATION//
void init_IO (void)
	{
		P1SEL |= BIT7;									//CONFIGURE TD0.1 , PW_H
		P1DIR |= BIT7;									//OUTPUT HIGH SIDE MOSFET
		P2SEL |= BIT0 + BIT2;							//CONFIGURE TD0.2 , TD1.1 FOR PW_L , PW_B
		P2DIR |= BIT0 + BIT2 + BIT4 + BIT5;							//OUTPUT LOW SIDE MOSFET , BOOST STAGE MOSFET

		P3DIR |= BIT2 + BIT3;
		PJDIR |= BIT6;									//CONFIGURE OUTPUT PORTS FOR ENABLE SIGNALS

		PMAPPWD = 0x02D52;      						// Enable Write-access to modify port mapping registers
		PMAPCTL = PMAPRECFG;    						// Allow reconfiguration during runtime
		P1MAP0|= PM_ANALOG;    							// Modify all PxMAPy registers
		P1MAP1|= PM_ANALOG;    							// Modify all PxMAPy registers
		P1MAP2|= PM_ANALOG;    							// Modify all PxMAPy registers
		P1MAP3|= PM_ANALOG;    							// Modify all PxMAPy registers
		P1MAP4|= PM_ANALOG;    							// Modify all PxMAPy registers
		PMAPPWD = 0;            						// Disable Write-Access to modify port mapping registers by writing incorrect key

		P1SEL |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4;   	// setting the port mapping register PxMAPy to PM_ANALOG together with PxSEL.y=1 when applying analog signals
		//PANEL_DISABLE;
		//LOAD_DISABLE;
		_BIS_SR(GIE); // enable global interrupts
	}


//ADC INITIALISATION//
void init_ADC (void)
{
		ADC10CTL0 = ADC10SHT_2 + ADC10MSC + ADC10ON;		// 8clk cycles, Single trigger, conversion disabled
		ADC10CTL1 = ADC10SHP + ADC10CONSEQ_1;     			// Sampling timer, Sequence of channels
		ADC10CTL2 |= ADC10RES;                    			// 10-bit conversion results
		ADC10MCTL0 = ADC10INCH_4 + ADC10SREF_1;				// A4,A3,A2,A1,A0(EoS), Vref+ = Vref, Vref- = gnd

		REFCTL0 |= REFVSEL_2+REFON;               			// Select internal ref = 2.5V
		//CONFIGURE DMA
		DMACTL0 = DMA0TSEL_24;                    			// ADC10IFG trigger

		__data16_write_addr((unsigned short) &DMA0SA,(unsigned long) &ADC10MEM0);
															// Source single address
		__data16_write_addr((unsigned short) &DMA0DA,(unsigned long) &ADC_Readings[0]);
															// Destination array address

		DMA0SZ = 0x05;                            			// 5 WORDS(Conversion Results) transferred
		DMA0CTL = DMADT_4 + DMADSTINCR_3 + DMAEN + DMAIE;	// Source unchanged, Destination increments, enabled, interrupts enabled
}

#pragma vector=DMA_VECTOR
__interrupt void DMA0_ISR (void)
{
  switch(__even_in_range(DMAIV,16))
  {
    case  0: break;                          	// No interrupt (No conversion)
    case  2:
												// Sequence of conversions complete, Interrupt due to channel 0
    ADC10CTL0 &= ~ADC10ENC;                     // Disabled Conversion
    Panel_Voltage_Buffer 	+= ADC_Readings [P_V];
    Battery_Voltage_Buffer += ADC_Readings [B_V];
    Battery_Charging_Current_Buffer += ADC_Readings [B_I];
    Load_Voltage_Buffer	+= ADC_Readings [L_V];
    Load_Current_Buffer	+= ADC_Readings [L_I];
    Avg_LOAD_Counter++;
	Avg_MPPT_Counter++;

	if(ADC_Readings [L_V] > 680) // load voltage > 50v => disable load
	{
		TURN_OFF_BOOST_STAGE;
		LOAD_DISABLE;
		Load_On = 0;
		OV_Triggered = 1;
		OV_Triggered_Counter = 0;					//Take action for over current protection by setting a flag
	}

	// to prevent boosting
	if(ADC_Readings [P_V] > PANEL_UPPER_LIMIT)
	{
		TURN_OFF_BUCK_STAGE;
		PANEL_DISABLE;
		Duty_Buck=400; // 80%
		Wait_State =1;
		Wait_Counter =0;
	}

	//reset counter if these are overflowing.This can happen when MCU is in LPM
	if(Avg_LOAD_Counter>REF_AVG_LOAD_COUNTER)
		{
			Avg_LOAD_Counter=0;
			Load_Current_Buffer =0;
		}

	if((Avg_MPPT_Counter==REF_AVG_STANDBY_COUNTER)&&(LPM3_On==1))
		{
			LPM3_On=0;
			ADC10CTL0 &= ~ADC10ON; // turn off ADC core to save power
			LPM3_EXIT;
		}


			 break;                             // DMA0IFG
    case  4: break;                          	// DMA1IFG
    case  6: break;                          	// DMA2IFG
    case  8: break;                          	// Reserved
    case 10: break;                          	// Reserved
    case 12: break;                          	// Reserved
    case 14: break;                          	// Reserved
    case 16: break;                          	// Reserved
    default: break;
  }
}
