//
// AVR ADC common operations
// Homelab library
//
// Department of Mechatronics
// Tallinn University of Technology
// ITT Group
// © Copyrights 2009-2011
//

#include <avr/io.h>
#include "adc.h"
#include "bit.h"

//
// ADC initialization
//
void adc_init(adc_reference reference, adc_prescale prescale)
{
	// ADC setup, custom prescale	
	ADCSRA = bit_mask(ADEN) | (prescale & 0x07);
 
	// Choose reference voltage
	ADMUX = (reference & 0x03) << REFS0;
}

//
// ADC conversion waiting
//
inline void adc_wait_until_done(void)
{
	while (bit_is_set(ADCSRA, ADSC))
	{
		asm volatile ("nop");
  	}
}

//
// ADC channel value getting
//
void adc_set_channel(unsigned char channel)
{	
	// Specify channel	
	ADMUX = (ADMUX & 0xF0) | (channel & 0x0F);
}

//
// ADC channel value getting
//
unsigned short adc_get_value(unsigned char channel)
{	
	// Specify channel	
	adc_set_channel(channel);	
 
	// Take test sample to "warm up" converter
	// Usually the first sample is discarded
	adc_start_conversion();
	adc_wait_until_done();
 
	// Real sampling, sum up specifed number of samples
	adc_start_conversion();
	adc_wait_until_done();	
 
	// Return result
	return adc_get_result();
}

//
// ADC channel value sampling
//
unsigned short adc_get_average_value(unsigned char channel, unsigned char num_samples)
{	
	unsigned short result = 0;
	unsigned char i;
 
	// Specify channel	
	adc_set_channel(channel);
 
	// Take test sample to "warm up" converter
	// Usually the first sample is discarded
	adc_start_conversion();
	adc_wait_until_done();
 
	// Real sampling, sum up specifed number of samples
	for (i = 0; i < num_samples;i++)
	{
		adc_start_conversion();
		adc_wait_until_done();
 
		// Sum-up
		result += adc_get_result();
	}
 
	// Return averaged result
	return (result / num_samples);	
}

