#include <avr/io.h>
#include <avr/interrupt.h>
+#include <util/atomic.h>
#include "lights.h"
static unsigned char adc_vals;
#define ADC1_GAIN20_OFFSET_SHIFT 6
static uint16_t adc1_gain20_offset;
+static unsigned char handler_running;
static void inline setup_mux(unsigned char n)
{
ADCSRA |= _BV(ADSC);
}
+/*
+ * Single synchronous ADC conversion.
+ * Has to be called with IRQs disabled (or with the ADC IRQ disabled).
+ */
+static uint16_t read_adc_sync()
+{
+ uint16_t rv;
+
+ ADCSRA |= _BV(ADSC); // start the conversion
+
+ // wait for the conversion to finish
+ while((ADCSRA & _BV(ADIF)) == 0)
+ ;
+
+ rv = ADCW;
+ ADCSRA |= _BV(ADIF); // clear the IRQ flag
+
+ return rv;
+}
+
void init_adc()
{
unsigned char i;
current_adc = NUM_ADCS;
+ handler_running = 0;
ADCSRA = _BV(ADEN) // enable
| _BV(ADPS1) | _BV(ADPS0) // CLK/8 = 125 kHz
// 1.1V, ADC1,1, gain 20
ADMUX = _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX0);
- ADCSRA |= _BV(ADSC);
/* Do first conversion and drop the result */
- while ((ADCSRA & _BV(ADIF)) == 0)
- ;
- ADCSRA |= _BV(ADIF); // clear the IRQ flag
+ read_adc_sync();
adc1_gain20_offset = 0;
for (i = 0; i < (1 << ADC1_GAIN20_OFFSET_SHIFT); i++) {
- ADCSRA |= _BV(ADSC);
-
- while ((ADCSRA & _BV(ADIF)) == 0)
- ;
- adc1_gain20_offset += ADCW
+ adc1_gain20_offset += read_adc_sync()
- (adc1_gain20_offset >> ADC1_GAIN20_OFFSET_SHIFT);
-
- ADCSRA |= _BV(ADIF); // clear the IRQ flag
}
ADCSRA |= _BV(ADIE); // enable IRQ
adc_sum = 0;
}
- if (current_adc < N_PWMLEDS)
- pwmled_adc(current_adc, adc_sum);
- if (current_adc == AMBIENT_ADC)
- ambient_adc(adc_sum);
- if (current_adc == BATTERY_ADC)
- battery_adc(adcval);
-
- start_next_adc();
+ if (handler_running & (1 << current_adc)) {
+ log_byte(0xB0 + current_adc);
+
+ // drop the result, what else to do?
+
+ start_next_adc();
+ } else {
+ unsigned char current_adc_copy = current_adc;
+ uint16_t adc_sum_copy = adc_sum;
+
+ start_next_adc();
+
+ handler_running |= (1 << current_adc_copy);
+ NONATOMIC_BLOCK(NONATOMIC_FORCEOFF) {
+ if (current_adc_copy < N_PWMLEDS)
+ pwmled_adc(current_adc_copy, adc_sum_copy);
+ if (current_adc_copy == AMBIENT_ADC)
+ ambient_adc(adc_sum_copy);
+ if (current_adc_copy == BATTERY_ADC)
+ battery_adc(adc_sum_copy);
+ }
+ handler_running &= ~(1 << current_adc_copy);
+ }
}