diff options
author | Linus Nielsen Feltzing <linus@haxx.se> | 2004-01-13 11:36:23 +0000 |
---|---|---|
committer | Linus Nielsen Feltzing <linus@haxx.se> | 2004-01-13 11:36:23 +0000 |
commit | 5bd3297fd434cb4ca261b6f852d9adc0eb0f8843 (patch) | |
tree | 4fd63028f48bd8e117d0bed7af1a0f338b94f14b /firmware/drivers/adc.c | |
parent | 8815d8857380350fad13d0d2d5e13f1d82854007 (diff) | |
download | rockbox-5bd3297fd434cb4ca261b6f852d9adc0eb0f8843.tar.gz rockbox-5bd3297fd434cb4ca261b6f852d9adc0eb0f8843.zip |
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
Diffstat (limited to 'firmware/drivers/adc.c')
-rw-r--r-- | firmware/drivers/adc.c | 85 |
1 files changed, 37 insertions, 48 deletions
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 @@ | |||
22 | #include "thread.h" | 22 | #include "thread.h" |
23 | #include "adc.h" | 23 | #include "adc.h" |
24 | 24 | ||
25 | static int current_channel; | 25 | /* This driver updates the adcdata[] array by converting one A/D channel |
26 | group on each system tick. Each group is 4 channels, which means that | ||
27 | it takes 2 ticks to convert all 8 channels. */ | ||
28 | |||
29 | static int current_group; | ||
26 | static unsigned short adcdata[NUM_ADC_CHANNELS]; | 30 | static unsigned short adcdata[NUM_ADC_CHANNELS]; |
27 | static unsigned int adcreg[NUM_ADC_CHANNELS] = | ||
28 | { | ||
29 | ADDRAH_ADDR, ADDRBH_ADDR, ADDRCH_ADDR, ADDRDH_ADDR, | ||
30 | ADDRAH_ADDR, ADDRBH_ADDR, ADDRCH_ADDR, ADDRDH_ADDR | ||
31 | }; | ||
32 | 31 | ||
33 | static void adc_tick(void) | 32 | static void adc_tick(void) |
34 | { | 33 | { |
35 | /* Read the data that has bee converted since the last tick */ | 34 | /* Copy the data from the previous conversion */ |
36 | adcdata[current_channel] = | 35 | if(current_group) |
37 | *(unsigned short *)adcreg[current_channel] >> 6; | 36 | { |
37 | adcdata[4] = ADDRA >> 6; | ||
38 | adcdata[5] = ADDRB >> 6; | ||
39 | adcdata[6] = ADDRC >> 6; | ||
40 | adcdata[7] = ADDRD >> 6; | ||
41 | } | ||
42 | else | ||
43 | { | ||
44 | adcdata[0] = ADDRA >> 6; | ||
45 | adcdata[1] = ADDRB >> 6; | ||
46 | adcdata[2] = ADDRC >> 6; | ||
47 | adcdata[3] = ADDRD >> 6; | ||
48 | } | ||
38 | 49 | ||
39 | /* Start a conversion on the next channel */ | 50 | /* Start converting the next group */ |
40 | current_channel++; | 51 | current_group = !current_group; |
41 | if(current_channel == NUM_ADC_CHANNELS) | 52 | ADCSR = ADCSR_ADST | ADCSR_SCAN | (current_group?4:0) | 3; |
42 | current_channel = 0; | 53 | |
43 | ADCSR = ADCSR_ADST | current_channel; | 54 | /* The conversion will be ready when we serve the next tick interrupt. |
55 | No need to check ADCSR for finished conversion since the conversion | ||
56 | will be ready long before the next tick. */ | ||
44 | } | 57 | } |
45 | 58 | ||
46 | unsigned short adc_read(int channel) | 59 | unsigned short adc_read(int channel) |
@@ -48,44 +61,20 @@ unsigned short adc_read(int channel) | |||
48 | return adcdata[channel]; | 61 | return adcdata[channel]; |
49 | } | 62 | } |
50 | 63 | ||
51 | /* Batch convert 4 analog channels. If lower is true, convert AN0-AN3, | ||
52 | * otherwise AN4-AN7. | ||
53 | */ | ||
54 | static void adc_batch_convert(bool lower) | ||
55 | { | ||
56 | int reg = lower ? 0 : 4; | ||
57 | volatile unsigned short* ANx = ((unsigned short*) ADDRAH_ADDR); | ||
58 | int i; | ||
59 | |||
60 | ADCSR = ADCSR_ADST | ADCSR_SCAN | ADCSR_CKS | reg | 3; | ||
61 | |||
62 | /* Busy wait until conversion is complete. A bit ugly perhaps, but | ||
63 | * we should only need to wait about 4 * 14 µs */ | ||
64 | while(!(ADCSR & ADCSR_ADF)) | ||
65 | { | ||
66 | } | ||
67 | |||
68 | /* Stop scanning */ | ||
69 | ADCSR = 0; | ||
70 | |||
71 | for (i = 0; i < 4; i++) | ||
72 | { | ||
73 | /* Read converted values */ | ||
74 | adcdata[reg++] = ANx[i] >> 6; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | void adc_init(void) | 64 | void adc_init(void) |
79 | { | 65 | { |
80 | ADCR = 0x7f; /* No external trigger; other bits should be 1 according to the manual... */ | 66 | ADCR = 0x7f; /* No external trigger; other bits should be 1 according |
67 | to the manual... */ | ||
81 | 68 | ||
82 | current_channel = 0; | 69 | /* Make sure that there is no conversion running */ |
70 | ADCSR = 0; | ||
83 | 71 | ||
84 | /* Do a first scan to initialize all values */ | 72 | /* Start with converting group 0 by setting current_group to 1 */ |
85 | /* AN4 to AN7 */ | 73 | current_group = 1; |
86 | adc_batch_convert(false); | ||
87 | /* AN0 to AN3 */ | ||
88 | adc_batch_convert(true); | ||
89 | 74 | ||
90 | tick_add_task(adc_tick); | 75 | tick_add_task(adc_tick); |
76 | |||
77 | /* Wait until both groups have been converted before we continue, | ||
78 | so adcdata[] contains valid data */ | ||
79 | sleep(2); | ||
91 | } | 80 | } |