summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2008-05-03 07:49:39 +0000
committerDave Chapman <dave@dchapman.com>2008-05-03 07:49:39 +0000
commit9c1ab1f0572da9d68f45fc8cb6c361cee0b33376 (patch)
treec4f03a1a217c7fdd6be4f781bec67bd2ecbaa2aa
parent2124a9fad02e79165a72ec5f8495862e9a57a954 (diff)
downloadrockbox-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.h1
-rw-r--r--firmware/target/arm/tcc77x/adc-tcc77x.c83
-rw-r--r--firmware/target/arm/tcc77x/system-tcc77x.c8
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
48static int channel_group;
33static unsigned short adcdata[8]; 49static unsigned short adcdata[8];
34 50
35static void adc_do_read(void) 51/* Tick task */
52static 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 */
70void 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
58unsigned short adc_read(int channel) 98unsigned short adc_read(int channel)
59{ 99{
60 adc_do_read();
61
62 return adcdata[channel]; 100 return adcdata[channel];
63} 101}
64 102
65void adc_init(void) 103void 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 */
24extern void TIMER(void); 25extern void TIMER(void);
26extern void ADC(void);
25 27
26void irq(void) 28void 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
41void fiq_handler(void) 41void fiq_handler(void)