From 9c1ab1f0572da9d68f45fc8cb6c361cee0b33376 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Sat, 3 May 2008 07:49:39 +0000 Subject: 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 --- firmware/target/arm/tcc77x/adc-tcc77x.c | 83 +++++++++++++++++++++++------- firmware/target/arm/tcc77x/system-tcc77x.c | 8 +-- 2 files changed, 68 insertions(+), 23 deletions(-) (limited to 'firmware/target') 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 @@ #include "string.h" #include "adc.h" -/* - TODO: We probably want to do this on the timer interrupt once we get - interrupts going - see the sh-adc.c implementation for an example which - looks like it should work well with the TCC77x. -*/ +/************************************************************************** + ** The A/D conversion is done every tick, in three steps: + ** + ** 1) On the tick interrupt, the conversion of channels 0-3 is started, and + ** the A/D interrupt is enabled. + ** + ** 2) After the conversion is done, an interrupt + ** is generated at level 1, which is the same level as the tick interrupt + ** itself. This interrupt will be pending until the tick interrupt is + ** finished. + ** When the A/D interrupt is finally served, it will read the results + ** from the first conversion and start the conversion of channels 4-7. + ** + ** 3) When the conversion of channels 4-7 is finished, the interrupt is + ** triggered again, and the results are read. This time, no new + ** conversion is started, it will be done in the next tick interrupt. + ** + ** Thus, each channel will be updated HZ times per second. + ** + *************************************************************************/ +static int channel_group; static unsigned short adcdata[8]; -static void adc_do_read(void) +/* Tick task */ +static void adc_tick(void) { + /* Start a conversion of channels 0-3. This will trigger an interrupt, + and the interrupt handler will take care of channels 4-7. */ + int i; - uint32_t adc_status; PCLKCFG6 |= (1<<15); /* Enable ADC clock */ + channel_group = 0; + /* Start converting the first 4 channels */ for (i = 0; i < 4; i++) ADCCON = i; - /* Wait for data to become stable */ - while ((ADCDATA & 0x1) == 0); +} + +/* IRQ handler */ +void ADC(void) +{ + int num; + int i; + uint32_t adc_status; - /* Now read the values back */ - for (i=0;i < 4; i++) { + do + { adc_status = ADCSTATUS; - adcdata[(adc_status >> 16) & 0x7] = adc_status & 0x3ff; - } + num = (adc_status>>24) & 7; + if (num) adcdata[(adc_status >> 16) & 0x7] = adc_status & 0x3ff; + } while (num); + - PCLKCFG6 &= ~(1<<15); /* Disable ADC clock */ + if (channel_group == 0) + { + /* Start conversion of channels 4-7 */ + for (i = 4; i < 8; i++) + ADCCON = i; + + channel_group = 1; + } + else + { + PCLKCFG6 &= ~(1<<15); /* Disable ADC clock */ + } } unsigned short adc_read(int channel) { - adc_do_read(); - return adcdata[channel]; } void adc_init(void) { - int i; - ADCCON = (1<<4); /* Leave standby mode */ - ADCCFG |= 0x00000003; /* Single-mode, auto power-down */ + + /* IRQ enable, auto power-down, single-mode */ + ADCCFG |= (1<<3) | (1<<1) | (1<<0); + + /* Unmask ADC IRQ */ + IEN |= ADC_IRQ_MASK; + + tick_add_task(adc_tick); + + sleep(2); /* Ensure adc_data[] contains data before returning */ } 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 @@ #include "system.h" #include "panic.h" +/* Externally defined interrupt handlers */ extern void TIMER(void); +extern void ADC(void); void irq(void) { @@ -29,13 +31,11 @@ void irq(void) CREQ = irq; /* Clears the corresponding IRQ status */ if (irq & TIMER0_IRQ_MASK) - { TIMER(); - } + else if (irq & ADC_IRQ_MASK) + ADC(); else - { panicf("Unhandled IRQ 0x%08X", irq); - } } void fiq_handler(void) -- cgit v1.2.3