BeRTOS
adc_at91.c
Go to the documentation of this file.
00001 
00047 #include "adc_at91.h"
00048 
00049 #include <cpu/irq.h>
00050 
00051 #include "cfg/cfg_adc.h"
00052 #include "cfg/cfg_proc.h"
00053 #include "cfg/cfg_signal.h"
00054 #include <cfg/macros.h>
00055 #include <cfg/compiler.h>
00056 
00057 // Define log settings for cfg/log.h.
00058 #define LOG_LEVEL         ADC_LOG_LEVEL
00059 #define LOG_FORMAT        ADC_LOG_FORMAT
00060 #include <cfg/log.h>
00061 
00062 #include <drv/adc.h>
00063 
00064 #include <io/arm.h>
00065 
00066 #if CONFIG_KERN
00067     #include <cfg/module.h>
00068     #include <kern/proc.h>
00069     #include <kern/signal.h>
00070 
00071 
00072     #if !CONFIG_KERN_SIGNALS
00073         #error Signals must be active to use ADC with kernel
00074     #endif
00075 
00076     /* Signal adc convertion end */
00077     #define SIG_ADC_COMPLETE SIG_USER0
00078 
00079     /* ADC waiting process */
00080     static struct Process *adc_process;
00081 
00086     static DECLARE_ISR(adc_conversion_end_irq)
00087     {
00088         sig_post(adc_process, SIG_ADC_COMPLETE);
00089 
00090         /* Inform hw that we have served the IRQ */
00091         AIC_EOICR = 0;
00092     }
00093 
00094     static void adc_enable_irq(void)
00095     {
00096 
00097         // Disable all interrupt
00098         ADC_IDR = 0xFFFFFFFF;
00099 
00100         //Register interrupt vector
00101         AIC_SVR(ADC_ID) = adc_conversion_end_irq;
00102         AIC_SMR(ADC_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED;
00103         AIC_IECR = BV(ADC_ID);
00104 
00105         //Enable data ready irq
00106         ADC_IER = BV(ADC_DRDY);
00107     }
00108 
00109 #endif /* CONFIG_KERN */
00110 
00111 
00116 void adc_hw_select_ch(uint8_t ch)
00117 {
00118     //Disable all channels
00119     ADC_CHDR = ADC_CH_MASK;
00120     //Enable select channel
00121     ADC_CHER = BV(ch);
00122 }
00123 
00124 
00130 uint16_t adc_hw_read(void)
00131 {
00132     #if CONFIG_KERN
00133         /* Ensure ADC is not already in use by another process */
00134         ASSERT(adc_process == NULL);
00135         adc_process = proc_current();
00136     #endif
00137 
00138     // Start convertion
00139     ADC_CR = BV(ADC_START);
00140 
00141     #if CONFIG_KERN
00142         // Ensure IRQs enabled.
00143         IRQ_ASSERT_ENABLED();
00144         sig_wait(SIG_ADC_COMPLETE);
00145 
00146         /* Prevent race condition in case of preemptive kernel */
00147         uint16_t ret = ADC_LCDR;
00148         MEMORY_BARRIER;
00149         adc_process = NULL;
00150         return ret;
00151     #else
00152         //Wait in polling until is done
00153         while (!(ADC_SR & BV(ADC_DRDY)));
00154 
00155         //Return the last converted data
00156         return(ADC_LCDR);
00157     #endif
00158 }
00159 
00163 void adc_hw_init(void)
00164 {
00165     //Init ADC pins.
00166     ADC_INIT_PINS();
00167 
00168     /*
00169      * Set adc mode register:
00170      * - Disable hardware trigger and enable software trigger.
00171      * - Select normal mode.
00172      * - Set ADC_BITS bit convertion resolution.
00173      *
00174      * \{
00175      */
00176     ADC_MR = 0;
00177     #if ADC_BITS == 10
00178         ADC_MR &= ~BV(ADC_LOWRES);
00179     #elif ADC_BITS == 8
00180         ADC_MR |= BV(ADC_LOWRES);
00181     #else
00182         #error No select bit resolution is supported to this CPU
00183     #endif
00184     /* \} */
00185 
00186     LOG_INFO("Computed ADC_CLOCK %ld\n", ADC_COMPUTED_CLOCK);
00187     LOG_INFO("prescaler[%ld], stup[%ld], shtim[%ld]\n",ADC_COMPUTED_PRESCALER, ADC_COMPUTED_STARTUPTIME,  ADC_COMPUTED_SHTIME);
00188 
00189 
00190     //Apply computed prescaler value
00191     ADC_MR &= ~ADC_PRESCALER_MASK;
00192     ADC_MR |= ((ADC_COMPUTED_PRESCALER << ADC_PRESCALER_SHIFT) & ADC_PRESCALER_MASK);
00193     LOG_INFO("prescaler[%ld]\n", (ADC_COMPUTED_PRESCALER << ADC_PRESCALER_SHIFT) & ADC_PRESCALER_MASK);
00194 
00195     //Apply computed start up time
00196     ADC_MR &= ~ADC_STARTUP_MASK;
00197     ADC_MR |= ((ADC_COMPUTED_STARTUPTIME << ADC_STARTUP_SHIFT) & ADC_STARTUP_MASK);
00198     LOG_INFO("sttime[%ld]\n", (ADC_COMPUTED_STARTUPTIME << ADC_STARTUP_SHIFT) & ADC_STARTUP_MASK);
00199 
00200     //Apply computed sample and hold time
00201     ADC_MR &= ~ADC_SHTIME_MASK;
00202     ADC_MR |= ((ADC_COMPUTED_SHTIME << ADC_SHTIME_SHIFT) & ADC_SHTIME_MASK);
00203     LOG_INFO("shtime[%ld]\n", (ADC_COMPUTED_SHTIME << ADC_SHTIME_SHIFT) & ADC_SHTIME_MASK);
00204 
00205     #if CONFIG_KERN
00206         //Register and enable irq for adc.
00207         adc_enable_irq();
00208     #endif
00209 
00210 }