#include "adc.h" #define ADC_CONVERSION_TIMEOUT 1000U // The ADC needs a 50-200 kHz clock. At F_CPU = 8 MHz that is a /64 prescaler // (125 kHz); the old /2 ran it at 4 MHz, far out of spec. #define ADC_PRESCALER_64 ((1 << ADPS2) | (1 << ADPS1)) // The 1.1 V bandgap reference needs time to settle after the mux is switched. #define ADC_SETTLE_US 200 int8_t adc_Initialize(void) { // REFS VAL_0x01; ADLAR disabled; MUX adc0; ADMUX = 0x40; // ACME disabled; ADTS VAL_0x00; ADCSRB = 0x00; ADCSRA = (1 << ADEN) | ADC_PRESCALER_64; return 0; } void adc_Disable(void) { ADCSRA &= ~(1 << ADEN); } void adc_Enable(void) { ADCSRA |= (1 << ADEN); } void adc_StartConversion(uint8_t channel) { if (channel == 0) { ADMUX = 0b01000000; } else if (channel == ADC_CHANNEL_BANDGAP) { // ADMUX=0b01001110; ADMUX = (0x01 << REFS0) | (0 << ADLAR) | (0x0e << MUX0); } else { ADMUX &= ~0x0f; ADMUX |= channel; } _delay_us(ADC_SETTLE_US); ADCSRA |= (1 << ADSC); } bool adc_IsConversionDone(void) { return ((ADCSRA & (1 << ADIF))); } uint16_t adc_GetConversionResult(void) { // ADC reads ADCL then ADCH in the right order. Reading the two volatile // registers in one expression leaves the order unspecified, and taking ADCH // first breaks the data-register lock and corrupts the result. return ADC; } uint16_t adc_GetConversion(uint8_t channel) { adc_StartConversion(channel); // A conversion is 13 ADC clocks (~104 us at 125 kHz); bail out rather than // hang if the ADC is disabled or its clock is gated off. uint16_t attempts = 0; while (!adc_IsConversionDone()) { if (++attempts > ADC_CONVERSION_TIMEOUT) { return 0; } _delay_us(10); } uint16_t res = adc_GetConversionResult(); ADCSRA |= (1 << ADIF); return res; }