]> www.fi.muni.cz Git - bike-lights.git/blobdiff - firmware/adc.c
Merge branch 'master' of ssh://anxur.fi.muni.cz/~kas/html/git/bike-lights
[bike-lights.git] / firmware / adc.c
index 4213ef56bc01b5114ee2c76f6ef16dfce1e7158d..9155f325ccfd2c857a93c503b2c2f6337a78ad04 100644 (file)
@@ -1,5 +1,6 @@
 #include <avr/io.h>
 #include <avr/interrupt.h>
+#include <util/atomic.h>
 
 #include "lights.h"
 
@@ -14,6 +15,7 @@ static unsigned char sum_shift;
 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)
 {
@@ -62,10 +64,31 @@ static void start_next_adc()
        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
@@ -79,24 +102,15 @@ void init_adc()
 
        // 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
@@ -143,13 +157,28 @@ ISR(ADC_vect) { // IRQ handler
                        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);
+       }
 }