From 0bf0705e3357e72047f08ae2fe047ca5a3abfdd7 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sat, 23 Jul 2011 16:32:03 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3175 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32F1xx/adc_lld.c | 229 +++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 os/hal/platforms/STM32F1xx/adc_lld.c (limited to 'os/hal/platforms/STM32F1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32F1xx/adc_lld.c b/os/hal/platforms/STM32F1xx/adc_lld.c new file mode 100644 index 000000000..8a8027e55 --- /dev/null +++ b/os/hal/platforms/STM32F1xx/adc_lld.c @@ -0,0 +1,229 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file STM32/adc_lld.c + * @brief STM32 ADC subsystem low level driver source. + * + * @addtogroup ADC + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief ADC1 driver identifier.*/ +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +ADCDriver ADCD1; +#endif + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Shared ADC DMA ISR service routine. + * + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(STM32_ADC_DMA_ERROR_HOOK) + if ((flags & DMA_ISR_TEIF1) != 0) { + STM32_ADC_DMA_ERROR_HOOK(spip); + } +#else + (void)flags; +#endif + if ((flags & DMA_ISR_HTIF1) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + if ((flags & DMA_ISR_TCIF1) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level ADC driver initialization. + * + * @notapi + */ +void adc_lld_init(void) { + +#if STM32_ADC_USE_ADC1 + /* Driver initialization.*/ + adcObjectInit(&ADCD1); + ADCD1.adc = ADC1; + ADCD1.dmachp = STM32_DMA1_CH1; + ADCD1.dmaccr = (STM32_ADC_ADC1_DMA_PRIORITY << 12) | + DMA_CCR1_EN | DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0 | + DMA_CCR1_MINC | DMA_CCR1_TCIE | DMA_CCR1_TEIE; + + /* Temporary activation.*/ + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; + ADC1->CR1 = 0; + ADC1->CR2 = ADC_CR2_ADON; + + /* Reset calibration just to be safe.*/ + ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL; + while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0) + ; + + /* Calibration.*/ + ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL; + while ((ADC1->CR2 & ADC_CR2_CAL) != 0) + ; + + /* Return the ADC in low power mode.*/ + ADC1->CR2 = 0; + RCC->APB2ENR &= ~RCC_APB2ENR_ADC1EN; +#endif +} + +/** + * @brief Configures and activates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start(ADCDriver *adcp) { + + /* If in stopped state then enables the ADC and DMA clocks.*/ + if (adcp->state == ADC_STOP) { +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) { + dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_1, + (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, (void *)adcp); + NVICEnableVector(DMA1_Channel1_IRQn, + CORTEX_PRIORITY_MASK(STM32_ADC_ADC1_IRQ_PRIORITY)); + dmaChannelSetPeripheral(adcp->dmachp, &ADC1->DR); + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; + } +#endif + + /* ADC setup, the calibration procedure has already been performed + during initialization.*/ + adcp->adc->CR1 = ADC_CR1_SCAN; + adcp->adc->CR2 = 0; + } +} + +/** + * @brief Deactivates the ADC peripheral. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop(ADCDriver *adcp) { + + /* If in ready state then disables the ADC clock.*/ + if (adcp->state == ADC_READY) { +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) { + ADC1->CR1 = 0; + ADC1->CR2 = 0; + NVICDisableVector(DMA1_Channel1_IRQn); + dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_1); + RCC->APB2ENR &= ~RCC_APB2ENR_ADC1EN; + } +#endif + } +} + +/** + * @brief Starts an ADC conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start_conversion(ADCDriver *adcp) { + uint32_t ccr, n; + const ADCConversionGroup *grpp = adcp->grpp; + + /* DMA setup.*/ + ccr = adcp->dmaccr; + if (grpp->circular) + ccr |= DMA_CCR1_CIRC; + if (adcp->depth > 1) { + /* If the buffer depth is greater than one then the half transfer interrupt + interrupt is enabled in order to allows streaming processing.*/ + ccr |= DMA_CCR1_HTIE; + n = (uint32_t)grpp->num_channels * (uint32_t)adcp->depth; + } + else + n = (uint32_t)grpp->num_channels; + dmaChannelSetup(adcp->dmachp, n, adcp->samples, ccr); + + /* ADC setup.*/ + adcp->adc->CR1 = grpp->cr1 | ADC_CR1_SCAN; + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_DMA | + ADC_CR2_CONT | ADC_CR2_ADON; + adcp->adc->SMPR1 = grpp->smpr1; + adcp->adc->SMPR2 = grpp->smpr2; + adcp->adc->SQR1 = grpp->sqr1; + adcp->adc->SQR2 = grpp->sqr2; + adcp->adc->SQR3 = grpp->sqr3; + + /* ADC start by writing ADC_CR2_ADON a second time.*/ + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_DMA | + ADC_CR2_CONT | ADC_CR2_ADON; +} + +/** + * @brief Stops an ongoing conversion. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop_conversion(ADCDriver *adcp) { + + dmaChannelDisable(adcp->dmachp); + adcp->adc->CR2 = 0; +} + +#endif /* HAL_USE_ADC */ + +/** @} */ -- cgit v1.2.3