/*This file is prepared for Doxygen automatic documentation generation.*/
//! \file *********************************************************************
//!
//! \brief Contains functions for initializing and controlling PWM output.
//!
//! - Compiler:           IAR EWAVR and GNU GCC for AVR
//! - Supported devices:  ATmega32U4
//!
//! \author               Atmel Corporation: http://www.atmel.com \n
//!                       Support and FAQ: http://support.atmel.no/
//!
//! ***************************************************************************

/* Copyright (c) 2009 Atmel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an Atmel
 * AVR product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY AND
 * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
 */

#include "config.h"
#include "enums.h"

#ifdef __GNUC__
   #include "lib_mcu/pwm/pwm.h"
   #include "lib_mcu/pll/pll_drv.h"
   #include "lib_mcu/timer/time.h"
#elif __ICCAVR__
   #include "PWM.h"
   #include "lib_mcu/timer/time.h"
   #include "lib_mcu/pll/pll_drv.h"
#else
   #error Current COMPILER not supported
#endif


#define DEBUG

//******************************************************************************
// Functions
//******************************************************************************
/*! \brief Stops PWM output
 *
 */
void PWM_Stop(void)
{
	OCR4B = 0;  // Reset compare level.
	TCCR4A = 0; // Set normal port operation, disable PWM modes.
	TCCR4B = 0; // Stop timer/counter4.
	TCCR4C = 0; // Set normal port operation.
	TCCR4D = 0; // No fault protection, normal waveform.
	OCR4C = 0;  // Reset compare.
	OCR4D = 0;  // Reset compare.
	DT4 = 0;    // No dead time values.
}


/*! \brief Initializes and starts PWM output
 *
 * Initializes timer4 for use as a PWM with a clock rate of 64 MHz.\n
 * Its comparator is connected to PB3 and will output high until timer4 reaches
 * the value of OCR4B. It is then dropped to 0.\n
 * The comparator outputs high again when the counter overflows, which will
 * happen at a rate of 250 kHz.
 */
void PWM_Start(void)
{

	// Clear OC4A on compare match, enable PWM on comparator OCR4A.
	TCCR4A = (1<<COM4A1)|(1<<PWM4A);
	
	// Non-inverted PWM, T/C stopped.
	TCCR4B = 0;
	
	// Copy shadow bits, disconnect OC4D.
	TCCR4C = (TCCR4A & 0xF0);
	
	// No fault protection, use phase & frequency correct PWM.
	TCCR4D = (0<<WGM41)|(1<WGM40);
	
	// Does not matter -- PWM6 mode not used.
	TCCR4E = 0;
	
	// Set reset compare level. (Offset is used, or JumperCheck() will fail.)
	OCR4A = PWM_OFFSET;

	// Does not matter -- OC4B is disabled.
	OCR4B = 0;
		
	// TOP value for PWM, f(PWM) = 64MHz / 255 = 251kHz.
	OCR4C = 0xFF;
	
	// Does not matter -- OC4D is disabled.
	OCR4D = 0;
	
	// No dead time values.
	DT4 = 0;
		
	// Set PWM port pin to output (PC7).
	DDRC |= (1<<PORTC7);

	// Enable PLL, use full speed mode.
//	PLLCSR = (1<<PLLE);

	//cgs update
#ifdef __GNUC__
	Enable_interrupt();
#else
	__enable_interrupt();
#endif

	// Use general timer and wait 1 ms for PLL lock to settle.
	Time_Set(TIMER_GEN,0,0,1);
	
	//cgs update
	Time_Start();	

	do{ 
	}while(Time_Left(TIMER_GEN));

	// Now wait for PLL to lock.
	do{ 
	}while((PLLCSR & (1<<PLOCK)) == 0);
	
	//SELECT 64MHz for PWM
	Pll_set_hs_tmr_pscal_1dot5();

	// CLK PCK = 64MHz / 1 = 64MHz.
	TCCR4B |= (0<<CS43)|(0<<CS42)|(0<<CS41)|(1<<CS40);
}


/*! \brief Increments the PWM duty cycle, if not already at max
 *
 * \retval TRUE Success, duty cycle could be incremented.
 * \retval FALSE Failure, duty cycle already at maximum.
 */
unsigned char PWM_IncrementDutyCycle(void){
	if (OCR4A < PWM_MAX) {
		OCR4A += 1;
		return(TRUE);
	} else {
		return(FALSE);
	}
}


/*! \brief Decrements the PWM duty cycle, if not already at zero.
 *
 * \retval TRUE Success, duty cycle could be decremented.
 * \retval FALSE Failure, duty cycle already at zero.
 */
unsigned char PWM_DecrementDutyCycle(void){
	if (OCR4A > 0)	{
		OCR4A -= 1;
		return(TRUE);
	} else {
		return(FALSE);
	}
}


