aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/platforms/STM32F1xx/adc_lld.c
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-07-23 16:32:03 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-07-23 16:32:03 +0000
commit0bf0705e3357e72047f08ae2fe047ca5a3abfdd7 (patch)
tree3c88f6cd973cb3f47338ec4eb49445f56bff71b2 /os/hal/platforms/STM32F1xx/adc_lld.c
parentb774805ce99c89b28972705ce86a8a9b9f7a2173 (diff)
downloadChibiOS-0bf0705e3357e72047f08ae2fe047ca5a3abfdd7.tar.gz
ChibiOS-0bf0705e3357e72047f08ae2fe047ca5a3abfdd7.tar.bz2
ChibiOS-0bf0705e3357e72047f08ae2fe047ca5a3abfdd7.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3175 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal/platforms/STM32F1xx/adc_lld.c')
-rw-r--r--os/hal/platforms/STM32F1xx/adc_lld.c229
1 files changed, 229 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 */
+
+/** @} */