Code Example

The code example below shows an application example where an ADC reading of below 2000 or above 3000 is considered an invalid signal spike. The window comparator is used to filter these out by only triggering a SAMPRDY interrupt when the signal is within the thresholds. The voltage of the signal is calculated in the SAMPRDY Interrupt Service Routine (ISR).

#define F_CPU 3333333ul

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <math.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 */

/* 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_VDD_gc | (TIMEBASE_VALUE << ADC_TIMEBASE_gp);
	ADC0.CTRLE = 17; /* (SAMPDUR + 0.5) * fCLK_ADC = 10.5 µs sample duration */

	ADC0.MUXPOS = ADC_MUXPOS_AIN6_gc; /* ADC channel AIN6 -> PA6 */

	ADC0.WINHT = 3000; /* Window High Threshold */
	ADC0.WINLT = 2000; /* Window Low Threshold */
	/* Window Comparator mode: Inside. Use SAMPLE register as Window Comparator source */
	ADC0.CTRLD = ADC_WINCM_INSIDE_gc | ADC_WINSRC_SAMPLE_gc;
	ADC0.INTCTRL = ADC_WCMP_bm; /* Enable window compare interrupt */

	ADC0.COMMAND = ADC_MODE_SINGLE_12BIT_gc; /* Single 12-bit mode */
}

/***********************************************************************************
Window Compare interrupt:
In this example, when a sample is outside a certain window, this is considered an
invalid signal spike. The Window Compare interrupt only triggers when the signal
is detected to be inside the window. That way the spikes are disregarded.
***********************************************************************************/
ISR(ADC0_SAMPRDY_vect)
{
	ADC0.INTFLAGS = ADC_WCMP_bm;        /* Clear WCMP flag */

	adc_reading = ADC0.SAMPLE;           /* Read ADC sample */
	/* Calculate voltage on ADC pin, VDD = 3.3V, 12-bit resolution */
	voltage = (float)(adc_reading * 3.3) / ADC_MAX_VALUE;
}

int main(void)
{
	adc_init();
	sei(); /* Enable global interrupts */

	while(1)
	{
		/* Start a conversion once every 1 ms */
		ADC0.COMMAND |= ADC_START_IMMEDIATE_gc;
		_delay_ms(1);
	}
}