From ae42ff1857ee56d67feca50d379c5f4b66d7fe69 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Wed, 21 Sep 2011 17:10:15 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3377 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 241 +++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 os/hal/platforms/STM32L1xx/adc_lld.c (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c new file mode 100644 index 000000000..9ccb198e4 --- /dev/null +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -0,0 +1,241 @@ +/* + 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 STM32L1xx/adc_lld.c + * @brief STM32L1xx 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 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 & STM32_DMA_ISR_TEIF) != 0) { + STM32_ADC_DMA_ERROR_HOOK(spip); + } +#else + (void)flags; +#endif + if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + if ((flags & STM32_DMA_ISR_TCIF) != 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.dmastp = STM32_DMA1_STREAM1; + ADCD1.dmamode = STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) | + STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_TEIE | STM32_DMA_CR_EN; + ADC->CCR = STM32_ADC_ADCPRE; +#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) { + bool_t b; + b = dmaStreamAllocate(adcp->dmastp, + STM32_ADC_ADC1_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, + (void *)adcp); + chDbgAssert(!b, "adc_lld_start(), #1", "stream already allocated"); + dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR); + rccEnableADC1(FALSE); + } +#endif + + /* ADC initial setup, just resetting control registers in this case.*/ + adcp->adc->CR1 = 0; + 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->CR2 = 0; + dmaStreamRelease(adcp->dmastp); + rccDisableADC1(FALSE); + } +#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 mode, n; + const ADCConversionGroup *grpp = adcp->grpp; + + /* DMA setup.*/ + mode = adcp->dmamode; + if (grpp->circular) + mode |= STM32_DMA_CR_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.*/ + mode |= STM32_DMA_CR_HTIE; + n = (uint32_t)grpp->num_channels * (uint32_t)adcp->depth; + } + else + n = (uint32_t)grpp->num_channels; + dmaStreamSetMemory0(adcp->dmastp, adcp->samples); + dmaStreamSetTransactionSize(adcp->dmastp, n); + dmaStreamSetMode(adcp->dmastp, mode); + + /* ADC setup.*/ + adcp->adc->SR = 0; + adcp->adc->CR1 = grpp->cr1 | ADC_CR1_SCAN; + adcp->adc->SMPR1 = grpp->smpr1; /* Writing SMPRx requires ADON=0. */ + adcp->adc->SMPR2 = grpp->smpr2; + adcp->adc->SMPR3 = grpp->smpr3; + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON; + adcp->adc->SQR1 = grpp->sqr1; + adcp->adc->SQR2 = grpp->sqr2; + adcp->adc->SQR3 = grpp->sqr3; + adcp->adc->SQR4 = grpp->sqr4; + adcp->adc->SQR5 = grpp->sqr5; + /* Must wait the ADC to be ready for conversion, see 9.3.6 "Timing diagram" + in the Reference Manual.*/ + while ((adcp->adc->SR & ADC_SR_ADONS) == 0) + ; + /* ADC start by raising ADC_CR2_SWSTART.*/ + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_SWSTART | 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) { + + dmaStreamDisable(adcp->dmastp); + adcp->adc->CR2 = 0; +} + +/** + * @brief Enables the TSVREFE bit. + * @details The TSVREFE bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + */ +void adcSTM32EnableTSVREFE(void) { + + ADC->CCR |= ADC_CCR_TSVREFE; +} + +/** + * @brief Disables the TSVREFE bit. + * @details The TSVREFE bit is required in order to sample the internal + * temperature sensor and internal reference voltage. + * @note This is an STM32-only functionality. + */ +void adcSTM32DisableTSVREFE(void) { + + ADC->CCR &= ~ADC_CCR_TSVREFE; +} + +#endif /* HAL_USE_ADC */ + +/** @} */ -- cgit v1.2.3 From 4a3e3fc01ec6dfb4a710db771bee262d5dc9327e Mon Sep 17 00:00:00 2001 From: gdisirio Date: Thu, 22 Sep 2011 14:53:42 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3381 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 51 +++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 13 deletions(-) (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c index 9ccb198e4..a2149b6ae 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.c +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -57,20 +57,20 @@ ADCDriver ADCD1; static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { /* DMA errors handling.*/ -#if defined(STM32_ADC_DMA_ERROR_HOOK) if ((flags & STM32_DMA_ISR_TEIF) != 0) { - STM32_ADC_DMA_ERROR_HOOK(spip); + /* DMA, this could help only if the DMA tries to access an unmapped + address space or violates alignment rules.*/ + _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE); } -#else - (void)flags; -#endif - if ((flags & STM32_DMA_ISR_HTIF) != 0) { - /* Half transfer processing.*/ - _adc_isr_half_code(adcp); - } - if ((flags & STM32_DMA_ISR_TCIF) != 0) { - /* Transfer complete processing.*/ - _adc_isr_full_code(adcp); + else { + if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } } } @@ -78,6 +78,29 @@ static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { /* Driver interrupt handlers. */ /*===========================================================================*/ +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +/** + * @brief ADC1 interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(UART5_IRQHandler) { + uint32_t sr; + + CH_IRQ_PROLOGUE(); + + sr = ADC1->SR; + ADC1->SR = 0; + if (sr & ADC_SR_OVR) { + /* ADC overflow condition, this could happen only if the DMA is unable + to read data fast enough.*/ + _adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW); + } + + CH_IRQ_EPILOGUE(); +} +#endif + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ @@ -145,6 +168,7 @@ void adc_lld_stop(ADCDriver *adcp) { if (adcp->state == ADC_READY) { #if STM32_ADC_USE_ADC1 if (&ADCD1 == adcp) { + ADC1->CR1 = 0; ADC1->CR2 = 0; dmaStreamRelease(adcp->dmastp); rccDisableADC1(FALSE); @@ -182,7 +206,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) { /* ADC setup.*/ adcp->adc->SR = 0; - adcp->adc->CR1 = grpp->cr1 | ADC_CR1_SCAN; + adcp->adc->CR1 = grpp->cr1 | ADC_CR1_OVRIE | ADC_CR1_SCAN; adcp->adc->SMPR1 = grpp->smpr1; /* Writing SMPRx requires ADON=0. */ adcp->adc->SMPR2 = grpp->smpr2; adcp->adc->SMPR3 = grpp->smpr3; @@ -211,6 +235,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) { void adc_lld_stop_conversion(ADCDriver *adcp) { dmaStreamDisable(adcp->dmastp); + adcp->adc->CR1 = 0; adcp->adc->CR2 = 0; } -- cgit v1.2.3 From c39d08fc2ae9c43f73114e24292520306bddde19 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 23 Sep 2011 15:48:55 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3384 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c index a2149b6ae..74c9a6ee3 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.c +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -84,7 +84,7 @@ static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { * * @isr */ -CH_IRQ_HANDLER(UART5_IRQHandler) { +CH_IRQ_HANDLER(ADC1_IRQHandler) { uint32_t sr; CH_IRQ_PROLOGUE(); @@ -96,6 +96,7 @@ CH_IRQ_HANDLER(UART5_IRQHandler) { to read data fast enough.*/ _adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW); } + /* TODO: Add here analog watchdog handling.*/ CH_IRQ_EPILOGUE(); } @@ -146,6 +147,8 @@ void adc_lld_start(ADCDriver *adcp) { chDbgAssert(!b, "adc_lld_start(), #1", "stream already allocated"); dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR); rccEnableADC1(FALSE); + NVICEnableVector(ADC1_IRQn, + CORTEX_PRIORITY_MASK(STM32_ADC_ADC1_IRQ_PRIORITY)); } #endif -- cgit v1.2.3 From 09d93604e7d02274f433d0854f9bfdfcab53cc9f Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 23 Sep 2011 20:38:42 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3386 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c index 74c9a6ee3..dfd1883f0 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.c +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -213,7 +213,8 @@ void adc_lld_start_conversion(ADCDriver *adcp) { adcp->adc->SMPR1 = grpp->smpr1; /* Writing SMPRx requires ADON=0. */ adcp->adc->SMPR2 = grpp->smpr2; adcp->adc->SMPR3 = grpp->smpr3; - adcp->adc->CR2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_CONT | ADC_CR2_ADON; + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_CONT | + ADC_CR2_ADON; adcp->adc->SQR1 = grpp->sqr1; adcp->adc->SQR2 = grpp->sqr2; adcp->adc->SQR3 = grpp->sqr3; @@ -224,7 +225,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) { while ((adcp->adc->SR & ADC_SR_ADONS) == 0) ; /* ADC start by raising ADC_CR2_SWSTART.*/ - adcp->adc->CR2 = grpp->cr2 | ADC_CR2_SWSTART | ADC_CR2_DMA | + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_SWSTART | ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_CONT | ADC_CR2_ADON; } -- cgit v1.2.3 From 5bf43b6500206391495dee6ea06c892dc450dcf2 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sat, 24 Sep 2011 06:53:13 +0000 Subject: STM32L driver tested and working. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3387 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c index dfd1883f0..eeae18f68 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.c +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -188,23 +188,24 @@ void adc_lld_stop(ADCDriver *adcp) { * @notapi */ void adc_lld_start_conversion(ADCDriver *adcp) { - uint32_t mode, n; + uint32_t mode, cr2; const ADCConversionGroup *grpp = adcp->grpp; /* DMA setup.*/ mode = adcp->dmamode; - if (grpp->circular) + cr2 = grpp->cr2; + if (grpp->circular) { mode |= STM32_DMA_CR_CIRC; + cr2 |= ADC_CR2_CONT; + } 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.*/ mode |= STM32_DMA_CR_HTIE; - n = (uint32_t)grpp->num_channels * (uint32_t)adcp->depth; } - else - n = (uint32_t)grpp->num_channels; dmaStreamSetMemory0(adcp->dmastp, adcp->samples); - dmaStreamSetTransactionSize(adcp->dmastp, n); + dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * + (uint32_t)adcp->depth); dmaStreamSetMode(adcp->dmastp, mode); /* ADC setup.*/ @@ -213,8 +214,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) { adcp->adc->SMPR1 = grpp->smpr1; /* Writing SMPRx requires ADON=0. */ adcp->adc->SMPR2 = grpp->smpr2; adcp->adc->SMPR3 = grpp->smpr3; - adcp->adc->CR2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_CONT | - ADC_CR2_ADON; + adcp->adc->CR2 = cr2 | ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_ADON; adcp->adc->SQR1 = grpp->sqr1; adcp->adc->SQR2 = grpp->sqr2; adcp->adc->SQR3 = grpp->sqr3; @@ -225,8 +225,8 @@ void adc_lld_start_conversion(ADCDriver *adcp) { while ((adcp->adc->SR & ADC_SR_ADONS) == 0) ; /* ADC start by raising ADC_CR2_SWSTART.*/ - adcp->adc->CR2 = grpp->cr2 | ADC_CR2_SWSTART | ADC_CR2_DMA | ADC_CR2_DDS | - ADC_CR2_CONT | ADC_CR2_ADON; + adcp->adc->CR2 = cr2 | ADC_CR2_SWSTART | ADC_CR2_DMA | ADC_CR2_DDS | + ADC_CR2_ADON; } /** -- cgit v1.2.3 From 7d30f4c821023de001cd4459c83a1fdae2f8cb07 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sat, 24 Sep 2011 15:04:39 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3399 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c index eeae18f68..bc04df615 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.c +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -188,15 +188,13 @@ void adc_lld_stop(ADCDriver *adcp) { * @notapi */ void adc_lld_start_conversion(ADCDriver *adcp) { - uint32_t mode, cr2; + uint32_t mode; const ADCConversionGroup *grpp = adcp->grpp; /* DMA setup.*/ mode = adcp->dmamode; - cr2 = grpp->cr2; if (grpp->circular) { mode |= STM32_DMA_CR_CIRC; - cr2 |= ADC_CR2_CONT; } if (adcp->depth > 1) { /* If the buffer depth is greater than one then the half transfer interrupt @@ -214,7 +212,8 @@ void adc_lld_start_conversion(ADCDriver *adcp) { adcp->adc->SMPR1 = grpp->smpr1; /* Writing SMPRx requires ADON=0. */ adcp->adc->SMPR2 = grpp->smpr2; adcp->adc->SMPR3 = grpp->smpr3; - adcp->adc->CR2 = cr2 | ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_ADON; + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_CONT | ADC_CR2_DMA | ADC_CR2_DDS | + ADC_CR2_ADON; adcp->adc->SQR1 = grpp->sqr1; adcp->adc->SQR2 = grpp->sqr2; adcp->adc->SQR3 = grpp->sqr3; @@ -225,8 +224,8 @@ void adc_lld_start_conversion(ADCDriver *adcp) { while ((adcp->adc->SR & ADC_SR_ADONS) == 0) ; /* ADC start by raising ADC_CR2_SWSTART.*/ - adcp->adc->CR2 = cr2 | ADC_CR2_SWSTART | ADC_CR2_DMA | ADC_CR2_DDS | - ADC_CR2_ADON; + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_SWSTART | ADC_CR2_CONT | ADC_CR2_DMA | + ADC_CR2_DDS | ADC_CR2_ADON; } /** -- cgit v1.2.3 From 0435bb5b4e1435924490f4a268dba5f75e998951 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Wed, 16 Nov 2011 18:03:48 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3499 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c index bc04df615..308fd90d0 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.c +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -219,7 +219,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) { adcp->adc->SQR3 = grpp->sqr3; adcp->adc->SQR4 = grpp->sqr4; adcp->adc->SQR5 = grpp->sqr5; - /* Must wait the ADC to be ready for conversion, see 9.3.6 "Timing diagram" + /* Must wait the ADC to be ready for conversion, see 10.3.6 "Timing diagram" in the Reference Manual.*/ while ((adcp->adc->SR & ADC_SR_ADONS) == 0) ; -- cgit v1.2.3 From 46870077b874696c09704da37dc4c33c8eb21402 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Thu, 24 Nov 2011 17:58:27 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3523 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 81 ++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 36 deletions(-) (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c index 308fd90d0..428d8e452 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.c +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -57,19 +57,23 @@ ADCDriver ADCD1; static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { /* DMA errors handling.*/ - if ((flags & STM32_DMA_ISR_TEIF) != 0) { + if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) { /* DMA, this could help only if the DMA tries to access an unmapped address space or violates alignment rules.*/ _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE); } else { - if ((flags & STM32_DMA_ISR_HTIF) != 0) { - /* Half transfer processing.*/ - _adc_isr_half_code(adcp); - } - if ((flags & STM32_DMA_ISR_TCIF) != 0) { - /* Transfer complete processing.*/ - _adc_isr_full_code(adcp); + /* It is possible that the conversion group has already be reset by the + ADC error handler, in this case this interrupt is spurious.*/ + if (adcp->grpp != NULL) { + if ((flags & STM32_DMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + if ((flags & STM32_DMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } } } } @@ -80,7 +84,7 @@ static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { #if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) /** - * @brief ADC1 interrupt handler. + * @brief ADC interrupt handler. * * @isr */ @@ -91,10 +95,13 @@ CH_IRQ_HANDLER(ADC1_IRQHandler) { sr = ADC1->SR; ADC1->SR = 0; - if (sr & ADC_SR_OVR) { + /* Note, an overflow may occur after the conversion ended before the driver + is able to stop the ADC, this is why the DMA channel is checked too.*/ + if ((sr & ADC_SR_OVR) && (dmaStreamGetTransactionSize(ADCD1.dmastp) > 0)) { /* ADC overflow condition, this could happen only if the DMA is unable to read data fast enough.*/ - _adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW); + if (ADCD1.grpp != NULL) + _adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW); } /* TODO: Add here analog watchdog handling.*/ @@ -119,11 +126,16 @@ void adc_lld_init(void) { ADCD1.adc = ADC1; ADCD1.dmastp = STM32_DMA1_STREAM1; ADCD1.dmamode = STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | - STM32_DMA_CR_TEIE | STM32_DMA_CR_EN; - ADC->CCR = STM32_ADC_ADCPRE; + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | + STM32_DMA_CR_EN; #endif + + /* The shared vector is initialized on driver initialization and never + disabled.*/ + NVICEnableVector(ADC1_IRQn, CORTEX_PRIORITY_MASK(STM32_ADC_IRQ_PRIORITY)); } /** @@ -141,20 +153,20 @@ void adc_lld_start(ADCDriver *adcp) { if (&ADCD1 == adcp) { bool_t b; b = dmaStreamAllocate(adcp->dmastp, - STM32_ADC_ADC1_IRQ_PRIORITY, + STM32_ADC_ADC1_DMA_IRQ_PRIORITY, (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, (void *)adcp); chDbgAssert(!b, "adc_lld_start(), #1", "stream already allocated"); dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR); rccEnableADC1(FALSE); - NVICEnableVector(ADC1_IRQn, - CORTEX_PRIORITY_MASK(STM32_ADC_ADC1_IRQ_PRIORITY)); } -#endif +#endif /* STM32_ADC_USE_ADC1 */ + - /* ADC initial setup, just resetting control registers in this case.*/ + /* ADC initial setup, starting the analog part here in order to reduce + the latency when starting a conversion.*/ adcp->adc->CR1 = 0; - adcp->adc->CR2 = 0; + adcp->adc->CR2 = ADC_CR2_ADON; } } @@ -167,15 +179,15 @@ void adc_lld_start(ADCDriver *adcp) { */ void adc_lld_stop(ADCDriver *adcp) { - /* If in ready state then disables the ADC clock.*/ + /* If in ready state then disables the ADC clock and analog part.*/ if (adcp->state == ADC_READY) { + dmaStreamRelease(adcp->dmastp); + adcp->adc->CR1 = 0; + adcp->adc->CR2 = 0; + #if STM32_ADC_USE_ADC1 - if (&ADCD1 == adcp) { - ADC1->CR1 = 0; - ADC1->CR2 = 0; - dmaStreamRelease(adcp->dmastp); + if (&ADCD1 == adcp) rccDisableADC1(FALSE); - } #endif } } @@ -208,24 +220,20 @@ void adc_lld_start_conversion(ADCDriver *adcp) { /* ADC setup.*/ adcp->adc->SR = 0; - adcp->adc->CR1 = grpp->cr1 | ADC_CR1_OVRIE | ADC_CR1_SCAN; - adcp->adc->SMPR1 = grpp->smpr1; /* Writing SMPRx requires ADON=0. */ + adcp->adc->SMPR1 = grpp->smpr1; adcp->adc->SMPR2 = grpp->smpr2; adcp->adc->SMPR3 = grpp->smpr3; - adcp->adc->CR2 = grpp->cr2 | ADC_CR2_CONT | ADC_CR2_DMA | ADC_CR2_DDS | - ADC_CR2_ADON; adcp->adc->SQR1 = grpp->sqr1; adcp->adc->SQR2 = grpp->sqr2; adcp->adc->SQR3 = grpp->sqr3; adcp->adc->SQR4 = grpp->sqr4; adcp->adc->SQR5 = grpp->sqr5; - /* Must wait the ADC to be ready for conversion, see 10.3.6 "Timing diagram" - in the Reference Manual.*/ - while ((adcp->adc->SR & ADC_SR_ADONS) == 0) - ; - /* ADC start by raising ADC_CR2_SWSTART.*/ - adcp->adc->CR2 = grpp->cr2 | ADC_CR2_SWSTART | ADC_CR2_CONT | ADC_CR2_DMA | - ADC_CR2_DDS | ADC_CR2_ADON; + + /* ADC configuration and start, the start is performed using the method + specified in the CR2 configuration, usually ADC_CR2_SWSTART.*/ + adcp->adc->CR1 = grpp->cr1 | ADC_CR1_OVRIE | ADC_CR1_SCAN; + adcp->adc->CR2 = grpp->cr2 | ADC_CR2_CONT | ADC_CR2_DMA | + ADC_CR2_DDS | ADC_CR2_ADON; } /** @@ -240,6 +248,7 @@ void adc_lld_stop_conversion(ADCDriver *adcp) { dmaStreamDisable(adcp->dmastp); adcp->adc->CR1 = 0; adcp->adc->CR2 = 0; + adcp->adc->CR2 = ADC_CR2_ADON; } /** -- cgit v1.2.3 From e6b38cdd3741b822c3be51aba268f90fc1771032 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Thu, 24 Nov 2011 21:00:24 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3524 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32L1xx/adc_lld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'os/hal/platforms/STM32L1xx/adc_lld.c') diff --git a/os/hal/platforms/STM32L1xx/adc_lld.c b/os/hal/platforms/STM32L1xx/adc_lld.c index 428d8e452..3d91a9991 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.c +++ b/os/hal/platforms/STM32L1xx/adc_lld.c @@ -162,10 +162,10 @@ void adc_lld_start(ADCDriver *adcp) { } #endif /* STM32_ADC_USE_ADC1 */ - /* ADC initial setup, starting the analog part here in order to reduce the latency when starting a conversion.*/ adcp->adc->CR1 = 0; + adcp->adc->CR2 = 0; adcp->adc->CR2 = ADC_CR2_ADON; } } -- cgit v1.2.3