From 5bd3297fd434cb4ca261b6f852d9adc0eb0f8843 Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Tue, 13 Jan 2004 11:36:23 +0000 Subject: Faster, simplified A/D driver. The previous batch convert in init_adc() produced garbage because of the fast conversion time, causing fake keypresses that made ask_resume() return prematurely. This should fix the intermittent resume problem reported by many users. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4222 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/adc.c | 85 ++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 48 deletions(-) (limited to 'firmware') diff --git a/firmware/drivers/adc.c b/firmware/drivers/adc.c index 107674348d..4c9206e62b 100644 --- a/firmware/drivers/adc.c +++ b/firmware/drivers/adc.c @@ -22,25 +22,38 @@ #include "thread.h" #include "adc.h" -static int current_channel; +/* 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 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) { - /* Read the data that has bee converted since the last tick */ - adcdata[current_channel] = - *(unsigned short *)adcreg[current_channel] >> 6; + /* 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; + } - /* Start a conversion on the next channel */ - current_channel++; - if(current_channel == NUM_ADC_CHANNELS) - current_channel = 0; - ADCSR = ADCSR_ADST | current_channel; + /* 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. */ } unsigned short adc_read(int channel) @@ -48,44 +61,20 @@ unsigned short adc_read(int channel) return adcdata[channel]; } -/* Batch convert 4 analog channels. If lower is true, convert AN0-AN3, - * otherwise AN4-AN7. - */ -static void adc_batch_convert(bool lower) -{ - int reg = lower ? 0 : 4; - volatile unsigned short* ANx = ((unsigned short*) ADDRAH_ADDR); - int i; - - ADCSR = ADCSR_ADST | ADCSR_SCAN | ADCSR_CKS | 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; - - 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... */ + ADCR = 0x7f; /* No external trigger; other bits should be 1 according + to the manual... */ - current_channel = 0; + /* Make sure that there is no conversion running */ + ADCSR = 0; - /* Do a first scan to initialize all values */ - /* AN4 to AN7 */ - adc_batch_convert(false); - /* AN0 to AN3 */ - adc_batch_convert(true); + /* Start with converting group 0 by setting current_group to 1 */ + current_group = 1; tick_add_task(adc_tick); + + /* Wait until both groups have been converted before we continue, + so adcdata[] contains valid data */ + sleep(2); } -- cgit v1.2.3