X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Fcortex-m3%2Fdrv%2Fadc_stm32.c;h=10ee143e90912c3b596201766c68fceeaa38bc19;hb=666f80bddb3d83383dee8f572b626690e81e3b18;hp=ef183865ac63eea58e469aab3e4850fc0f377924;hpb=1cbb62896ac90d73f33e8339c334be09b931079c;p=bertos.git diff --git a/bertos/cpu/cortex-m3/drv/adc_stm32.c b/bertos/cpu/cortex-m3/drv/adc_stm32.c index ef183865..10ee143e 100644 --- a/bertos/cpu/cortex-m3/drv/adc_stm32.c +++ b/bertos/cpu/cortex-m3/drv/adc_stm32.c @@ -26,7 +26,7 @@ * 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/) * * --> * @@ -64,27 +64,65 @@ #include #include #include -#include #include - struct stm32_adc *adc = (struct stm32_adc *)ADC1_BASE; +#if CONFIG_KERN + #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 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 @@ -92,13 +130,32 @@ static DECLARE_ISR(adc_redyRead) */ 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 } /** @@ -106,36 +163,53 @@ uint16_t adc_hw_read(void) */ 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 }