From: asterix Date: Wed, 30 Apr 2008 13:56:54 +0000 (+0000) Subject: Add adc driver. X-Git-Tag: 1.0.0~16 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=211f1718bc7a3553323733eea821a477decf0cc7;p=bertos.git Add adc driver. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1236 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/bertos/cpu/arm/drv/adc_arm.c b/bertos/cpu/arm/drv/adc_arm.c new file mode 100644 index 00000000..78878551 --- /dev/null +++ b/bertos/cpu/arm/drv/adc_arm.c @@ -0,0 +1,49 @@ +/** + * \file + * + * + * \brief Low-level ADC module for ARM (inplementation). + * + * + * \version $Id$ + * + * \author Daniele Basile + * + */ + +#include + +#if CPU_ARM_AT91 + #include "adc_at91.c" +/*#elif Add other ARM families here */ +#else + #error Unknown CPU +#endif diff --git a/bertos/cpu/arm/drv/adc_arm.h b/bertos/cpu/arm/drv/adc_arm.h new file mode 100644 index 00000000..63e7dafa --- /dev/null +++ b/bertos/cpu/arm/drv/adc_arm.h @@ -0,0 +1,49 @@ +/** + * \file + * + * + * \brief Low-level ADC module for ARM (interface). + * + * + * \version $Id$ + * + * \author Daniele Basile + * + */ + +#include + +#if CPU_ARM_AT91 + #include "adc_at91.h" +/*#elif Add other ARM families here */ +#else + #error Unknown CPU +#endif diff --git a/bertos/cpu/arm/drv/adc_at91.c b/bertos/cpu/arm/drv/adc_at91.c new file mode 100644 index 00000000..59fd1c68 --- /dev/null +++ b/bertos/cpu/arm/drv/adc_at91.c @@ -0,0 +1,198 @@ +/** + * \file + * + * + * + * \brief ADC hardware-specific implementation + * + * This ADC module should be use both whit kernel or none. + * If you are using a kernel, the adc drive does not wait the finish of + * conversion but use a singal every time a required conversion are + * ended. This signal wake up a process that return a result of + * conversion. Otherwise, if you not use a kernl, this module wait + * whit a loop the finishing of conversion. + * + * + * \version $Id$ + * + * \author Daniele Basile + */ + +#include "adc_at91.h" + +#include + +#include +#include + +#include + +#include "appconfig.h" + +#if CONFIG_KERNEL + #include + #include + #include + #include + + + #if !CONFIG_KERN_SIGNALS + #error Signals must be active to use ADC with kernel + #endif + + /* Signal adc convertion end */ + #define SIG_ADC_COMPLETE SIG_USER0 + + /* ADC waiting process */ + static struct Process *adc_process; + + /** + * ADC ISR. + * Simply signal the adc process that convertion is complete. + */ + static void ISR_FUNC adc_conversion_end_irq(void) + { + sig_signal(adc_process, SIG_ADC_COMPLETE); + + /* Inform hw that we have served the IRQ */ + AIC_EOICR = 0; + } + + static void adc_enable_irq(void) + { + + // Disable all interrupt + ADC_IDR = 0xFFFFFFFF; + + //Register interrupt vector + AIC_SVR(ADC_ID) = adc_conversion_end_irq; + AIC_SMR(ADC_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED; + AIC_IECR = BV(ADC_ID); + + //Enable data ready irq + ADC_IER = BV(ADC_DRDY); + } + +#endif /* CONFIG_KERNEL */ + + +/** + * Select mux channel \a ch. + * \todo only first 8 channels are selectable! + */ +INLINE void adc_hw_select_ch(uint8_t ch) +{ + //Disable all channels + ADC_CHDR = ADC_CH_MASK; + //Enable select channel + ADC_CHER = BV(ch); +} + + +/** + * Start an ADC convertion. + * If a kernel is present, preempt until convertion is complete, otherwise + * a busy wait on ADCS bit is done. + */ +INLINE uint16_t adc_hw_read(void) +{ + ASSERT(!(ADC_SR & ADC_EOC_MASK)); + + #if CONFIG_KERNEL + adc_process = proc_current(); + #endif + + // Start convertion + ADC_CR = BV(ADC_START); + + #if CONFIG_KERNEL + // Ensure IRQs enabled. + ASSERT(IRQ_ENABLED()); + sig_wait(SIG_ADC_COMPLETE); + #else + //Wait in polling until is done + while (!(ADC_SR & BV(ADC_DRDY))); + #endif + + //Return the last converted data + return(ADC_LCDR); +} + +/** + * Init ADC hardware. + */ +INLINE void adc_hw_init(void) +{ + //Init ADC pins. + ADC_INIT_PINS(); + + /* + * Set adc mode register: + * - Disable hardware trigger and enable software trigger. + * - Select normal mode. + * - Set ADC_BITS bit convertion resolution. + * + * \{ + */ + ADC_MR = 0; + #if ADC_BITS == 10 + ADC_MR &= ~BV(ADC_LOWRES); + #elif ADC_BITS == 8 + ADC_MR |= BV(ADC_LOWRES); + #else + #error No select bit resolution is supported to this CPU + #endif + /* \} */ + + TRACEMSG("prescaler[%ld], stup[%ld], shtim[%ld]\n",ADC_COMPUTED_PRESCALER,ADC_COMPUTED_STARTUPTIME,ADC_COMPUTED_SHTIME); + + + //Apply computed prescaler value + ADC_MR &= ~ADC_PRESCALER_MASK; + ADC_MR |= ((ADC_COMPUTED_PRESCALER << ADC_PRESCALER_SHIFT) & ADC_PRESCALER_MASK); + TRACEMSG("prescaler[%ld]\n", (ADC_COMPUTED_PRESCALER << ADC_PRESCALER_SHIFT) & ADC_PRESCALER_MASK); + + //Apply computed start up time + ADC_MR &= ~ADC_STARTUP_MASK; + ADC_MR |= ((ADC_COMPUTED_STARTUPTIME << ADC_STARTUP_SHIFT) & ADC_STARTUP_MASK); + TRACEMSG("sttime[%ld]\n", (ADC_COMPUTED_STARTUPTIME << ADC_STARTUP_SHIFT) & ADC_STARTUP_MASK); + + //Apply computed sample and hold time + ADC_MR &= ~ADC_SHTIME_MASK; + ADC_MR |= ((ADC_COMPUTED_SHTIME << ADC_SHTIME_SHIFT) & ADC_SHTIME_MASK); + TRACEMSG("shtime[%ld]\n", (ADC_COMPUTED_SHTIME << ADC_SHTIME_SHIFT) & ADC_SHTIME_MASK); + + #if CONFIG_KERNEL + //Register and enable irq for adc. + adc_enable_irq(); + #endif + +} diff --git a/bertos/cpu/arm/drv/adc_at91.h b/bertos/cpu/arm/drv/adc_at91.h new file mode 100644 index 00000000..49f0de31 --- /dev/null +++ b/bertos/cpu/arm/drv/adc_at91.h @@ -0,0 +1,93 @@ +/** + * \file + * + * + * \version $Id$ + * + * \brief ADC hardware-specific definition + * + * \version $Id$ + * \author Daniele Basile + */ + +#ifndef DRV_ADC_AT91_H +#define DRV_ADC_AT91_H + +#include + +#include "hw_cpu.h" +#include "appconfig.h" + +/** + * ADC config define. + */ +#define ADC_MUX_MAXCH 8 //Max number of channel for ADC. +#define ADC_BITS 10 //Bit resolution for ADC converter. + +/** + * Macro for computing correct value to write into ADC + * register. + */ +#define ADC_COMPUTED_PRESCALER ((CLOCK_FREQ/(2 * CONFIG_ADC_CLOCK)) - 1) +#define ADC_COMPUTED_STARTUPTIME (((CONFIG_ADC_STARTUP_TIME * CONFIG_ADC_CLOCK)/ 8000000UL) - 1) +#define ADC_COMPUTED_SHTIME (((CONFIG_ADC_SHTIME * CONFIG_ADC_CLOCK)/1000000000UL) - 1) + +/** + * Init pins macro for adc. + */ + +/** + * Define PIO controller for enable ADC function. + * \{ + */ +#if CPU_ARM_AT91SAM7X256 + #define ADC_PIO_DISABLE PIOB_PDR + #define ADC_PIO_EN_FUNC PIOB_ASR + +#elif CPU_ARM_AT91SAM7S256 + #define ADC_PIO_DISABLE PIOA_PDR + #define ADC_PIO_EN_FUNC PIOA_BSR + +#else + #error No ADC pins name definitions for selected ARM CPU +#endif +/*\}*/ + +/** + * Init the ADC pins. + * Implement it if necessary. + */ +#define ADC_INIT_PINS() \ + do { \ + } while (0) + + +#endif /* DRV_ADC_AT91_H */