/* ---------------------------------------------------------------------
**	file: adc_driver.c
**	function: driver for ADC conversion on AVR
** author: Jakub Tiller
** last update: 03.12.2011
**
** If you need differential convertion, you need to use setup
** function of initialization of witch type of differential convertion
** you need. There are two options, the differential convertion
** between ADC1 and ADCx with the gain of 1x "adc_set_diff(ADCx)"
** and differential convertion between ADC1 and ADC0 
** with gain 10x or 200x "adc_set_diff_1_0_gain(g10 or g200)"
** ---------------------------------------------------------------------
*/

#include "adc_driver.h"

/* ---------------------------------------------------------------------
**	function: adc_init()
** initialization function of ADC
**
** inputs: 	none
** outputs: none
** ---------------------------------------------------------------------
*/
void adc_init(enum AREF_t AREF)
{
	long int prescaler;
	unsigned char i;

	prescaler = (F_CPU / 200) / kHz;

	for (i=7; prescaler < (1<<i); i--);
	
	ADCSRA |= ((1<<ADEN) | i);
	ADMUX|=(1<<REFS0)|(1<<REFS1);

	switch (AREF)
	{
		case INTERNAL:
			ADMUX |= (1 << REFS1) | (1 << REFS0);
			break;
		case EXT_AVCC:
			ADMUX |= (1 << REFS0);
			ADMUX &= ~(1 << REFS1); 
			break;
		case EXT_VREF:
			ADMUX &= ~((1 << REFS1) | (1 << REFS0)); 
			break;
	}	
	
}

/* ---------------------------------------------------------------------
**	function: adc_get(ADCx)
** get ADC of input voltage and return 10-bit results
**
** inputs: 	source of ADC
** outputs: value after ADC convertion
** ---------------------------------------------------------------------
*/
unsigned int adc_get(unsigned char ADCx)
{
	unsigned int ADCval = 0;
	
	ADMUX &= 0b11100000;
	ADMUX |= ADCx;
	ADCSRA |= (1<<ADSC);
	while(!(ADCSRA & (1<<ADIF)));
	ADCval = ADC;

	return(ADCval);	
}

#ifdef _SPRINTF
/* ---------------------------------------------------------------------
**	function: adc_get_Voltage(ADCx)
** get ADC value and return string in format: 0.000V
**
** inputs: 	source of ADC
** outputs: value after ADC convertion
** ---------------------------------------------------------------------
*/
char* adc_get_Voltage_str(unsigned char ADCx)
{
	float ADCval = 0;
	unsigned char d1;
	unsigned char d2;
		
	ADCval = adc_get(ADCx);
	ADCval *= VREF;
	ADCval /= 1023;

	d1 = ADCval;
	d2 = (ADCval - d1)*1000;

	sprintf(voltage, "%01d.%03d", d1, d2);

	return(voltage);	
}
#endif

/* ---------------------------------------------------------------------
**	function: adc_stop(void)
** Stop of ADC convertion
**
** inputs: 	none
** outputs: none
** ---------------------------------------------------------------------
*/
void adc_stop(void)
{
	ADCSRA &= ~(1<<ADEN);		
}

/* ---------------------------------------------------------------------
**	function: adc_set_diff(unsigned char ADCx)
** Setup of different voltage AD convertion
**
** inputs: 	ADCx input of positive
** outputs: none
** ---------------------------------------------------------------------
*/
void adc_set_diff(unsigned char ADCx)
{
	ADMUX &= 0b11100000;
	ADMUX |= (16 + ADCx);
	_delay_us(100);
}

/* ---------------------------------------------------------------------
**	function: adc_get_diff(unsigned char ADCx)
** Differential ADC with gain 1x,
** negative input is still ADC1
**
** inputs: 	ADCx input of positive
** outputs: value after ADC convertion
** ---------------------------------------------------------------------
*/
unsigned int adc_get_diff(void)
{
	unsigned int ADCval = 0;
	
	ADCSRA |= (1<<ADSC);
	while(!(1<<ADIF == (ADCSRA & 1<<ADIF)));
	ADCval = ADC;

	return(ADCval);	
}

/* ---------------------------------------------------------------------
**	function: adc_set_diff_1_0_gain(enum GAIN_t gain)
** Set differential convertion between ADC1 and
** ADC0 with 10x or 200x gain
**
** inputs: 	gain enum (g10 or g200)
** outputs: none
** ---------------------------------------------------------------------
*/
void adc_set_diff_1_0_gain(enum GAIN_t gain)
{
	ADMUX &= 0b11100000;
	
	switch (gain)
	{
	case g10: 
		ADMUX |= (8 | (1<<MUX0));
		break;
	case g200:
		ADMUX |= (8 | (1<<MUX1) | (1<<MUX0));
		break;
	}
	_delay_us(50);
		
}

/* ---------------------------------------------------------------------
**	function: adc_diff_1_0_gain(void)
** Differential ADC set gain (10x or 200x)
** between ADC1 and ADC0
**
** inputs: 	void
** outputs: value after ADC convertion
** ---------------------------------------------------------------------
*/
unsigned int adc_diff_1_0_gain(void)
{
	unsigned int ADCval = 0;
	
	ADCSRA |= (1<<ADSC);
	while(!(1<<ADIF == (ADCSRA & 1<<ADIF)));
	ADCval = ADC;

	return(ADCval);	
}
