diff --git a/firmware/drivers/adc.c b/firmware/drivers/adc.c index 4c9206e62b..7be9baf5d5 100644 --- a/firmware/drivers/adc.c +++ b/firmware/drivers/adc.c @@ -22,38 +22,25 @@ #include "thread.h" #include "adc.h" -/* This driver updates the adcdata[] array by converting one A/D channel - group on each system tick. Each group is 4 channels, which means that - it takes 2 ticks to convert all 8 channels. */ - -static int current_group; +static int current_channel; static unsigned short adcdata[NUM_ADC_CHANNELS]; +static unsigned int adcreg[NUM_ADC_CHANNELS] = +{ + ADDRAH_ADDR, ADDRBH_ADDR, ADDRCH_ADDR, ADDRDH_ADDR, + ADDRAH_ADDR, ADDRBH_ADDR, ADDRCH_ADDR, ADDRDH_ADDR +}; static void adc_tick(void) { - /* Copy the data from the previous conversion */ - if(current_group) - { - adcdata[4] = ADDRA >> 6; - adcdata[5] = ADDRB >> 6; - adcdata[6] = ADDRC >> 6; - adcdata[7] = ADDRD >> 6; - } - else - { - adcdata[0] = ADDRA >> 6; - adcdata[1] = ADDRB >> 6; - adcdata[2] = ADDRC >> 6; - adcdata[3] = ADDRD >> 6; - } + /* Read the data that has bee converted since the last tick */ + adcdata[current_channel] = + *(unsigned short *)adcreg[current_channel] >> 6; - /* Start converting the next group */ - current_group = !current_group; - ADCSR = ADCSR_ADST | ADCSR_SCAN | (current_group?4:0) | 3; - - /* The conversion will be ready when we serve the next tick interrupt. - No need to check ADCSR for finished conversion since the conversion - will be ready long before the next tick. */ + /* Start a conversion on the next channel */ + current_channel++; + if(current_channel == NUM_ADC_CHANNELS) + current_channel = 0; + ADCSR = ADCSR_ADST | current_channel; } unsigned short adc_read(int channel) @@ -61,20 +48,44 @@ unsigned short adc_read(int channel) return adcdata[channel]; } -void adc_init(void) +/* Batch convert 4 analog channels. If lower is true, convert AN0-AN3, + * otherwise AN4-AN7. + */ +static void adc_batch_convert(bool lower) { - ADCR = 0x7f; /* No external trigger; other bits should be 1 according - to the manual... */ + int reg = lower ? 0 : 4; + volatile unsigned short* ANx = ((unsigned short*) ADDRAH_ADDR); + int i; - /* Make sure that there is no conversion running */ + ADCSR = ADCSR_ADST | ADCSR_SCAN | reg | 3; + + /* Busy wait until conversion is complete. A bit ugly perhaps, but + * we should only need to wait about 4 * 14 µs */ + while(!(ADCSR & ADCSR_ADF)) + { + } + + /* Stop scanning */ ADCSR = 0; - /* Start with converting group 0 by setting current_group to 1 */ - current_group = 1; + for (i = 0; i < 4; i++) + { + /* Read converted values */ + adcdata[reg++] = ANx[i] >> 6; + } +} + +void adc_init(void) +{ + ADCR = 0x7f; /* No external trigger; other bits should be 1 according to the manual... */ + + current_channel = 0; + + /* Do a first scan to initialize all values */ + /* AN4 to AN7 */ + adc_batch_convert(false); + /* AN0 to AN3 */ + adc_batch_convert(true); tick_add_task(adc_tick); - - /* Wait until both groups have been converted before we continue, - so adcdata[] contains valid data */ - sleep(2); }