5.2.2.1 Code Example

The following code example shows how to measure VDD using the Series Accumulation with Scaling mode and oversampling to achieve 16-bit resolution.
#define F_CPU 3333333ul

#include <avr/io.h>
#include <math.h>
#include <util/delay.h>

#define TIMEBASE_VALUE          ((uint8_t) ceil(F_CPU*0.000001))
#define ADC_MAX_VALUE           ((1 << 12) - 1)                 /* In single-ended mode, the max value is 4095 */
#define ADC_MAX_VALUE_16BIT     ((uint32_t) ADC_MAX_VALUE << 4)     /* Left shift 12-bit max value up to 16 bits */

/* Defines to easily configure ADC accumulation */
#define ADC_SAMPNUM_CONFIG  ADC_SAMPNUM_ACC256_gc
/* Left shifting (1 << SAMPNUM) results in the number of accumulated samples */
#define ADC_SAMPLES         (1 << ADC_SAMPNUM_CONFIG)

/* Volatile variables to improve debug experience */
static volatile uint16_t adc_reading;
static volatile float voltage;

/*********************************************************************************
ADC initialization
**********************************************************************************/
void adc_init()
{
	ADC0.CTRLA = ADC_ENABLE_bm;
	ADC0.CTRLB = ADC_PRESC_DIV2_gc; /* fCLK_ADC = 3.333333/2 MHz */
	ADC0.CTRLC = ADC_REFSEL_1024MV_gc | (TIMEBASE_VALUE << ADC_TIMEBASE_gp);
	ADC0.CTRLE = 17; /* (SAMPDUR + 0.5) * fCLK_ADC = 10.5 µs sample duration */
	ADC0.CTRLF = ADC_LEFTADJ_bm | ADC_SAMPNUM_CONFIG; /* Enable left adjust if accumulating < 16 samples */

	ADC0.MUXPOS = ADC_MUXPOS_VDDDIV10_gc; /* ADC channel VDD/10 */
	ADC0.COMMAND = ADC_MODE_SERIES_SCALING_gc; /* Series Accumulation with Scaling */
}

int main(void)
{
	adc_init();

	while(1)
	{
		ADC0.COMMAND |= ADC_START_IMMEDIATE_gc;
		while(!(ADC0.INTFLAGS & ADC_SAMPRDY_bm)); /* Wait until conversion is done */
		ADC0.INTFLAGS = ADC_SAMPRDY_bm; /* Clear Sample Ready interrupt flag */

		if(ADC0.INTFLAGS & ADC_RESRDY_bm) /* If result is ready */
		{
			adc_reading = ADC0.RESULT; /* Read 16 bit scaled or left adjusted result */
			/* Calculate VDD, VREF = 1.024V, 16-bit resolution.
			    Multiplied by 10 because the input channel is VDD/10. */
			voltage = (float)(adc_reading * 1.024 * 10) / ADC_MAX_VALUE_16BIT;
		}

		_delay_ms(10);
	}
}