BeRTOS
adc_lm3s.c
Go to the documentation of this file.
00001 
00047 #include "adc_lm3s.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 
00055 #include <cfg/macros.h>
00056 #include <cfg/compiler.h>
00057 #include <cfg/debug.h>
00058 
00059 // Define log settings for cfg/log.h.
00060 #define LOG_LEVEL         ADC_LOG_LEVEL
00061 #define LOG_FORMAT        ADC_LOG_FORMAT
00062 #include <cfg/log.h>
00063 
00064 #include <drv/adc.h>
00065 #include <drv/timer.h>
00066 #include <drv/clock_lm3s.h>
00067 
00068 #include <io/lm3s.h>
00069 
00070 /* Select witch ADC use */
00071 #if CPU_CM3_LM3S1968 || CPU_CM3_LM3S8962
00072     #define ADC_BASE            ADC0_BASE
00073     #define SYSCTL_RCGC_R       SYSCTL_RCGC0_R
00074     #define SYSCTL_RCGC_ADC     SYSCTL_RCGC0_ADC0
00075 #else
00076     #error Unknow ADC register for select cpu core
00077 #endif
00078 
00079 
00080 #if CONFIG_KERN
00081     #include <cfg/module.h>
00082 
00083     #include <kern/proc.h>
00084     #include <kern/signal.h>
00085 
00086     #include <drv/irq_cm3.h>
00087 
00088 
00089     #if !CONFIG_KERN_SIGNALS
00090         #error Signals must be active to use ADC with kernel
00091     #endif
00092 
00093     /* Signal adc convertion end */
00094     #define SIG_ADC_COMPLETE SIG_USER0
00095 
00096     /* ADC waiting process */
00097     static struct Process *adc_process;
00098 
00103     static DECLARE_ISR(adc_conversion_end_irq)
00104     {
00105         sig_post(adc_process, SIG_ADC_COMPLETE);
00106 
00107         /* Clear the status bit */
00108         HWREG(ADC_BASE + ADC_O_ISC) |= ADC_ISC_IN3;
00109 
00110     }
00111 
00112     static void adc_enable_irq(void)
00113     {
00114         /* Clear all pending irq */
00115         HWREG(ADC_BASE + ADC_O_ISC) = 0;
00116         /* Register the IRQ handler */
00117         sysirq_setHandler(INT_ADC3, adc_conversion_end_irq);
00118         /* Enable IRQ */
00119         HWREG(ADC_BASE + ADC_O_SSCTL3) |= ADC_SSCTL3_IE0;
00120         HWREG(ADC_BASE + ADC_O_IM) |= ADC_IM_MASK3;
00121     }
00122 
00123 #endif /* CONFIG_KERN */
00124 
00132 void adc_hw_select_ch(uint8_t ch)
00133 {
00134     /* Select channel that we want read */
00135     HWREG(ADC_BASE + ADC_O_SSMUX3) = ch;
00136     /* Make single acquisition */
00137     HWREG(ADC_BASE + ADC_O_SSCTL3) |= ADC_SSCTL3_END0;
00138     /* Enable sequence S03 (single sample on select channel) */
00139     HWREG(ADC_BASE + ADC_O_ACTSS) |= ADC_ACTSS_ASEN3;
00140 }
00141 
00147 uint16_t adc_hw_read(void)
00148 {
00149     #if CONFIG_KERN
00150         /* Ensure ADC is not already in use by another process */
00151         ASSERT(adc_process == NULL);
00152         adc_process = proc_current();
00153     #endif
00154 
00155     /* Start convertion */
00156     HWREG(ADC0_BASE + ADC_O_PSSI) |= ADC_PSSI_SS3;
00157 
00158     #if CONFIG_KERN
00159         /* Ensure IRQs enabled. */
00160         IRQ_ASSERT_ENABLED();
00161         sig_wait(SIG_ADC_COMPLETE);
00162 
00163         /* Prevent race condition in case of preemptive kernel */
00164         uint16_t ret = (uint16_t)HWREG(ADC_BASE + ADC_O_SSFIFO3);
00165         MEMORY_BARRIER;
00166         adc_process = NULL;
00167         return ret;
00168     #else
00169         /* Wait in polling until conversion is done */
00170         while (!(HWREG(ADC_BASE + ADC_O_SSFSTAT3) & ADC_SSFSTAT3_FULL));
00171 
00172         /* Return the last converted data */
00173         return (uint16_t)HWREG(ADC_BASE + ADC_O_SSFIFO3);
00174     #endif
00175 }
00176 
00180 void adc_hw_init(void)
00181 {
00182     /* Enable ADC0 clock */
00183     SYSCTL_RCGC_R |= SYSCTL_RCGC_ADC;
00184 
00185     /*
00186      * We wait some time because the clock is istable
00187      * and that could cause system hardfault
00188      */
00189     lm3s_busyWait(10);
00190 
00191     /* Disable all sequence */
00192     HWREG(ADC_BASE + ADC_O_ACTSS) = 0;
00193     /* Set trigger event to programmed (for all sequence) */
00194     HWREG(ADC_BASE + ADC_O_EMUX) = 0;
00195 
00196     #if CONFIG_KERN
00197         adc_enable_irq();
00198     #endif
00199 }