diff options
author | Dave Chapman <dave@dchapman.com> | 2008-05-03 07:49:39 +0000 |
---|---|---|
committer | Dave Chapman <dave@dchapman.com> | 2008-05-03 07:49:39 +0000 |
commit | 9c1ab1f0572da9d68f45fc8cb6c361cee0b33376 (patch) | |
tree | c4f03a1a217c7fdd6be4f781bec67bd2ecbaa2aa | |
parent | 2124a9fad02e79165a72ec5f8495862e9a57a954 (diff) | |
download | rockbox-9c1ab1f0572da9d68f45fc8cb6c361cee0b33376.tar.gz rockbox-9c1ab1f0572da9d68f45fc8cb6c361cee0b33376.zip |
Convert the TCC77x ADC driver to use interrupts - based on the technique used in the SH ADC driver.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17311 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/export/tcc77x.h | 1 | ||||
-rw-r--r-- | firmware/target/arm/tcc77x/adc-tcc77x.c | 83 | ||||
-rw-r--r-- | firmware/target/arm/tcc77x/system-tcc77x.c | 8 |
3 files changed, 69 insertions, 23 deletions
diff --git a/firmware/export/tcc77x.h b/firmware/export/tcc77x.h index bde8ca255f..5a6efb2543 100644 --- a/firmware/export/tcc77x.h +++ b/firmware/export/tcc77x.h | |||
@@ -82,6 +82,7 @@ | |||
82 | /* IRQ Controller */ | 82 | /* IRQ Controller */ |
83 | 83 | ||
84 | #define TIMER0_IRQ_MASK (1<<6) | 84 | #define TIMER0_IRQ_MASK (1<<6) |
85 | #define ADC_IRQ_MASK (1<<16) | ||
85 | 86 | ||
86 | #define IEN (*(volatile unsigned long *)0x80000100) | 87 | #define IEN (*(volatile unsigned long *)0x80000100) |
87 | #define CREQ (*(volatile unsigned long *)0x80000104) | 88 | #define CREQ (*(volatile unsigned long *)0x80000104) |
diff --git a/firmware/target/arm/tcc77x/adc-tcc77x.c b/firmware/target/arm/tcc77x/adc-tcc77x.c index d6d97aaf84..77ff348a45 100644 --- a/firmware/target/arm/tcc77x/adc-tcc77x.c +++ b/firmware/target/arm/tcc77x/adc-tcc77x.c | |||
@@ -24,48 +24,93 @@ | |||
24 | #include "string.h" | 24 | #include "string.h" |
25 | #include "adc.h" | 25 | #include "adc.h" |
26 | 26 | ||
27 | /* | 27 | /************************************************************************** |
28 | TODO: We probably want to do this on the timer interrupt once we get | 28 | ** The A/D conversion is done every tick, in three steps: |
29 | interrupts going - see the sh-adc.c implementation for an example which | 29 | ** |
30 | looks like it should work well with the TCC77x. | 30 | ** 1) On the tick interrupt, the conversion of channels 0-3 is started, and |
31 | */ | 31 | ** the A/D interrupt is enabled. |
32 | ** | ||
33 | ** 2) After the conversion is done, an interrupt | ||
34 | ** is generated at level 1, which is the same level as the tick interrupt | ||
35 | ** itself. This interrupt will be pending until the tick interrupt is | ||
36 | ** finished. | ||
37 | ** When the A/D interrupt is finally served, it will read the results | ||
38 | ** from the first conversion and start the conversion of channels 4-7. | ||
39 | ** | ||
40 | ** 3) When the conversion of channels 4-7 is finished, the interrupt is | ||
41 | ** triggered again, and the results are read. This time, no new | ||
42 | ** conversion is started, it will be done in the next tick interrupt. | ||
43 | ** | ||
44 | ** Thus, each channel will be updated HZ times per second. | ||
45 | ** | ||
46 | *************************************************************************/ | ||
32 | 47 | ||
48 | static int channel_group; | ||
33 | static unsigned short adcdata[8]; | 49 | static unsigned short adcdata[8]; |
34 | 50 | ||
35 | static void adc_do_read(void) | 51 | /* Tick task */ |
52 | static void adc_tick(void) | ||
36 | { | 53 | { |
54 | /* Start a conversion of channels 0-3. This will trigger an interrupt, | ||
55 | and the interrupt handler will take care of channels 4-7. */ | ||
56 | |||
37 | int i; | 57 | int i; |
38 | uint32_t adc_status; | ||
39 | 58 | ||
40 | PCLKCFG6 |= (1<<15); /* Enable ADC clock */ | 59 | PCLKCFG6 |= (1<<15); /* Enable ADC clock */ |
41 | 60 | ||
61 | channel_group = 0; | ||
62 | |||
42 | /* Start converting the first 4 channels */ | 63 | /* Start converting the first 4 channels */ |
43 | for (i = 0; i < 4; i++) | 64 | for (i = 0; i < 4; i++) |
44 | ADCCON = i; | 65 | ADCCON = i; |
45 | 66 | ||
46 | /* Wait for data to become stable */ | 67 | } |
47 | while ((ADCDATA & 0x1) == 0); | 68 | |
69 | /* IRQ handler */ | ||
70 | void ADC(void) | ||
71 | { | ||
72 | int num; | ||
73 | int i; | ||
74 | uint32_t adc_status; | ||
48 | 75 | ||
49 | /* Now read the values back */ | 76 | do |
50 | for (i=0;i < 4; i++) { | 77 | { |
51 | adc_status = ADCSTATUS; | 78 | adc_status = ADCSTATUS; |
52 | adcdata[(adc_status >> 16) & 0x7] = adc_status & 0x3ff; | 79 | num = (adc_status>>24) & 7; |
53 | } | 80 | if (num) adcdata[(adc_status >> 16) & 0x7] = adc_status & 0x3ff; |
81 | } while (num); | ||
82 | |||
54 | 83 | ||
55 | PCLKCFG6 &= ~(1<<15); /* Disable ADC clock */ | 84 | if (channel_group == 0) |
85 | { | ||
86 | /* Start conversion of channels 4-7 */ | ||
87 | for (i = 4; i < 8; i++) | ||
88 | ADCCON = i; | ||
89 | |||
90 | channel_group = 1; | ||
91 | } | ||
92 | else | ||
93 | { | ||
94 | PCLKCFG6 &= ~(1<<15); /* Disable ADC clock */ | ||
95 | } | ||
56 | } | 96 | } |
57 | 97 | ||
58 | unsigned short adc_read(int channel) | 98 | unsigned short adc_read(int channel) |
59 | { | 99 | { |
60 | adc_do_read(); | ||
61 | |||
62 | return adcdata[channel]; | 100 | return adcdata[channel]; |
63 | } | 101 | } |
64 | 102 | ||
65 | void adc_init(void) | 103 | void adc_init(void) |
66 | { | 104 | { |
67 | int i; | ||
68 | |||
69 | ADCCON = (1<<4); /* Leave standby mode */ | 105 | ADCCON = (1<<4); /* Leave standby mode */ |
70 | ADCCFG |= 0x00000003; /* Single-mode, auto power-down */ | 106 | |
107 | /* IRQ enable, auto power-down, single-mode */ | ||
108 | ADCCFG |= (1<<3) | (1<<1) | (1<<0); | ||
109 | |||
110 | /* Unmask ADC IRQ */ | ||
111 | IEN |= ADC_IRQ_MASK; | ||
112 | |||
113 | tick_add_task(adc_tick); | ||
114 | |||
115 | sleep(2); /* Ensure adc_data[] contains data before returning */ | ||
71 | } | 116 | } |
diff --git a/firmware/target/arm/tcc77x/system-tcc77x.c b/firmware/target/arm/tcc77x/system-tcc77x.c index 7323b0ce55..2628d9f0ed 100644 --- a/firmware/target/arm/tcc77x/system-tcc77x.c +++ b/firmware/target/arm/tcc77x/system-tcc77x.c | |||
@@ -21,7 +21,9 @@ | |||
21 | #include "system.h" | 21 | #include "system.h" |
22 | #include "panic.h" | 22 | #include "panic.h" |
23 | 23 | ||
24 | /* Externally defined interrupt handlers */ | ||
24 | extern void TIMER(void); | 25 | extern void TIMER(void); |
26 | extern void ADC(void); | ||
25 | 27 | ||
26 | void irq(void) | 28 | void irq(void) |
27 | { | 29 | { |
@@ -29,13 +31,11 @@ void irq(void) | |||
29 | CREQ = irq; /* Clears the corresponding IRQ status */ | 31 | CREQ = irq; /* Clears the corresponding IRQ status */ |
30 | 32 | ||
31 | if (irq & TIMER0_IRQ_MASK) | 33 | if (irq & TIMER0_IRQ_MASK) |
32 | { | ||
33 | TIMER(); | 34 | TIMER(); |
34 | } | 35 | else if (irq & ADC_IRQ_MASK) |
36 | ADC(); | ||
35 | else | 37 | else |
36 | { | ||
37 | panicf("Unhandled IRQ 0x%08X", irq); | 38 | panicf("Unhandled IRQ 0x%08X", irq); |
38 | } | ||
39 | } | 39 | } |
40 | 40 | ||
41 | void fiq_handler(void) | 41 | void fiq_handler(void) |