* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
- * Copyright 2008 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
*
* -->
*
#include <drv/adc.h>
#include <drv/clock_stm32.h>
#include <drv/gpio_stm32.h>
-#include <drv/irq_cm3.h>
#include <io/stm32.h>
-
struct stm32_adc *adc = (struct stm32_adc *)ADC1_BASE;
+#if CONFIG_KERN
+ #include <cfg/module.h>
+
+ #include <kern/proc.h>
+ #include <kern/signal.h>
+
+ #include <drv/irq_cm3.h>
+
+
+ #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 DECLARE_ISR(adc_conversion_end_irq)
+ {
+ sig_post(adc_process, SIG_ADC_COMPLETE);
+
+ /* Clear the status bit */
+ adc->SR &= ~BV(SR_EOC);
+ }
+
+ static void adc_enable_irq(void)
+ {
+ /* Register the IRQ handler */
+ sysirq_setHandler(ADC_IRQHANDLER, adc_conversion_end_irq);
+ adc->CR1 |= BV(CR1_EOCIE);
+ }
+
+#endif /* CONFIG_KERN */
+
/**
* Select mux channel \a ch.
+ * Generally the stm32 cpu family allow us to program the order
+ * of adc channel that we want to read.
+ * In this driver implementation we put as fist channel to read the
+ * select ones.
*/
void adc_hw_select_ch(uint8_t ch)
{
- kprintf("Select[%d]\n", ch);
- adc->SQR1 |= (0x1 << SQR1_SQ_LEN_SHIFT);
+ /* We sample only from one channel */
+ adc->SQR1 |= BV(SQR1_SQ_LEN_SHIFT);
adc->SQR3 = (ch & SQR3_SQ_MASK);
}
-static DECLARE_ISR(adc_redyRead)
-{
- kputs("end\n");
-}
/**
* Start an ADC convertion.
* If a kernel is present, preempt until convertion is complete, otherwise
*/
uint16_t adc_hw_read(void)
{
- // Start convertion
- adc->CR2 |= CR2_EXTTRIG_SWSTRT_SET;
+ #if CONFIG_KERN
+ /* Ensure ADC is not already in use by another process */
+ ASSERT(adc_process == NULL);
+ adc_process = proc_current();
+ #endif
- while (!(adc->SR & BV(SR_EOC)));
+ /* Start convertion */
+ adc->CR2 |= CR2_EXTTRIG_SWSTRT_SET;
- //Return the last converted data
- return (adc->DR);
+ #if CONFIG_KERN
+ /* Ensure IRQs enabled. */
+ IRQ_ASSERT_ENABLED();
+ sig_wait(SIG_ADC_COMPLETE);
+
+ /* Prevent race condition in case of preemptive kernel */
+ uint16_t ret = adc->DR;
+ MEMORY_BARRIER;
+ adc_process = NULL;
+ return ret;
+ #else
+ /* Wait in polling until conversion is done */
+ while (!(adc->SR & BV(SR_EOC)));
+
+ /* Return the last converted data */
+ return (adc->DR);
+ #endif
}
/**
*/
void adc_hw_init(void)
{
- /* Enable clocking on AFIO */
- RCC->APB2ENR |= RCC_APB2_AFIO;
- RCC->APB2ENR |= RCC_APB2_GPIOC;
+ RCC->APB2ENR |= (RCC_APB2_GPIOA | RCC_APB2_GPIOB | RCC_APB2_GPIOC);
RCC->APB2ENR |= RCC_APB2_ADC1;
- /* Reset cr1 registry */
+ /* Reset registry */
adc->CR1 = 0;
adc->CR2 = 0;
+ adc->SQR1 = 0;
+ adc->SQR2 = 0;
+ adc->SQR3 = 0;
+
+ /* Calibrate ADC */
+ adc->CR2 |= BV(CR2_RTSCAL);
+ adc->CR2 |= BV(CR2_CAL);
+
+ /* Wait in polling until calibration is done */
+ while (adc->CR2 & BV(CR2_CAL));
/*
* Configure ADC
* - Regular mode
- * - scan mode
+ * - Wake up adc
+ * - Wake up temperature and Vrefint
*/
adc->CR2 |= (BV(CR2_ADON) | ADC_EXTERNALTRIGCONV_NONE | BV(CR2_TSVREFE));
- /*
- * Configure ADC settings
- * - align rigth
- * - enable adc
- */
- adc->SQR1 = 0;
- adc->SQR2 = 0;
- adc->SQR3 = 0;
-
- /* Set 17.1usec sampling time on channel 16 and 17 */
- adc->SMPR1 |= ((ADC_SAMPLETIME_239CYCLES5 << ADC_CHANNEL_16) |
- (ADC_SAMPLETIME_239CYCLES5 << ADC_CHANNEL_17));
-
- /* Register the IRQ handler */
- sysirq_setHandler(ADC_IRQHANDLER, adc_redyRead);
- //adc->CR1 |= BV(CR1_EOCIE);
+ /* Set 17.1usec sampling time*/
+ adc->SMPR1 |= ((ADC_SAMPLETIME_239CYCLES5 << SMPR1_CH17) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR1_CH16) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR1_CH15) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR1_CH14) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR1_CH13) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR1_CH12) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR1_CH11) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR1_CH10));
+
+ adc->SMPR2 |= ((ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH9) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH8) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH7) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH6) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH5) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH4) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH3) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH2) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH1) |
+ (ADC_SAMPLETIME_239CYCLES5 << SMPR2_CH0));
+
+ #if CONFIG_KERN
+ adc_enable_irq();
+ #endif
}