/* --------------------------------------------------------------------------
Name:       fadingLED.c
Function:   Flash and fade the LED at defined duty cycle.
Versions:
   1.0   2/24/2007   L Simone.  Created.  File compiled for FET.
					Less documented code demonstrating how digital output
					port can be used to simulate an analog signal
					(glowing and fading LED).
					
					Period = period of the ON/OFF cycle which simulates intensity
					ON_time = part of Period where LED is ON
					LED_cycle_ctr = counts entire Periods
					LED_Speed = Larger numbers = slower ramp up/down
----------------------------------------------------------------------------- */
#include <msp430x20x3.h>

#define  LED_PIN   BIT0          /* LED is on Port 1, bit 1 (aka BIT0)  */
#define  LED_ON   BIT0           /* LED is located at BIT0 on Port 1. 1 = ON  */
#define  LED_OFF  (~BIT0)

/* Redeclarations       */
extern void initialize_hardware(void);
extern void initialize_TimerA0(void);
extern void Turn_LED_ON(void);
extern void Turn_LED_OFF(void);


/* Global Variables */
unsigned int On_time = 2; 
unsigned int Period = 15;
unsigned int TimerA0_reload = 2000;    /* Provides ~2 msec intervals */
unsigned int Interrupt_ctr = 0;
unsigned int LED_cycle_ctr = 0;

void main(void)
{
  unsigned int LED_Speed = 2;
  signed char multiplier = 1;
 
  initialize_hardware();         /* Initialize ports, etc.     */
  initialize_TimerA0();          /* Configure TIMER_A0 to control LED flashing */
 
  
  /* Now that everything is ready to go, enable interrupts!  */
   __enable_interrupt();

  /* This is our endless main loop.  */
   do
  {
     /* Control how fast the intensity ramp slope is */
     if (LED_cycle_ctr > LED_Speed)
     {   
     
        /* Avoid data share problem */
        __disable_interrupt();
        On_time += multiplier;
         __enable_interrupt();
         
        /* Cheap and dirty way to ramp intensity up and down.  Use Period to count number of
        interrupts.  Use multiplier to change the On_time variable - this changes the percentage
        of the duty cycle which changes the intensity.  Higher duty cycle = higher intensity. */
          
         if (On_time >= Period)
          multiplier = -1;
        if (On_time == 0)
          multiplier = 1;

        LED_cycle_ctr = 0;
     }   

  }
  while (1);
  
}

/* -------------------------------------------------------------
Name:       Timer_A()
Function:   Timer A0 interrupt service routine
---------------------------------------------------------------- */
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  TACCR0 += TimerA0_reload;      /* Reload timer for next interrupt  */
  Interrupt_ctr++;

  if (Interrupt_ctr <= On_time)
     Turn_LED_ON();
  else if (Interrupt_ctr <= (Period - On_time))
     Turn_LED_OFF();
  else
  {
     Interrupt_ctr = 0;
     LED_cycle_ctr++;
  }
}


/* --------------------------------------------------------------------------
Name:       Turn_LED_ON()
Function:   Turn the LED ON.
----------------------------------------------------------------------------- */
void Turn_LED_ON(void)
{
  P1OUT |= LED_ON;
}

/* --------------------------------------------------------------------------
Name:       Turn_LED_OFF()
Function:   Turn the LED OFF.
----------------------------------------------------------------------------- */
void Turn_LED_OFF(void)
{
  P1OUT &= LED_OFF;
}

/* -------------------------------------------------------------
Name:       initialize_hardware()
Function:   Initialize all hardware settings
---------------------------------------------------------------- */
void initialize_hardware(void)
{
  WDTCTL = WDTPW + WDTHOLD;                  // Stop watchdog timer
  P1DIR |= 0x01;                            // Set P1.0 to output direction
}

/* -------------------------------------------------------------
Name:       initialize_TimerA0()
Function:   Initialize Timer in continuous mode to control flashing
            of the LED.  
---------------------------------------------------------------- */
void initialize_TimerA0(void)
{
   /* In the TimerA control register, configure the timer to use
   the subsystem clock source (SMCLK), and to use the continuous
   mode (Mode 2). */
   TACTL = TASSEL_2 + MC_2;            

   /* Enable TimerA0 interrupt via TimerA0 Control Register.
      This means an interrupt will occur when timer counts up and
      reaches value in TACCR0 */
   TACCTL0 = CCIE;                   

   /* Load an initial reload value into TACCR0 – Capture/Compare Register
   also known as the "period" register.  Period = ON time + OFF time. */
   TACCR0 = TimerA0_reload;          
}

