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/dox/adc.dox | 16 ++++++++--- os/hal/include/adc.h | 49 +++++++++++++++++++++++++++++++++- os/hal/platforms/STM32F1xx/adc_lld.c | 26 +++++++++--------- os/hal/platforms/STM32F1xx/adc_lld.h | 30 ++++++++++++++------- os/hal/platforms/STM32L1xx/adc_lld.c | 51 +++++++++++++++++++++++++++--------- os/hal/platforms/STM32L1xx/adc_lld.h | 34 ++++++++++++++++-------- os/hal/src/adc.c | 7 ++++- 7 files changed, 162 insertions(+), 51 deletions(-) (limited to 'os') diff --git a/os/hal/dox/adc.dox b/os/hal/dox/adc.dox index bb8ff014f..53bfb75d2 100644 --- a/os/hal/dox/adc.dox +++ b/os/hal/dox/adc.dox @@ -34,8 +34,9 @@ * @if LATEX_PDF * @dot digraph example { - size="5, 7"; rankdir="LR"; + size="5, 7"; + node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"]; edge [fontname=Helvetica, fontsize=8]; @@ -43,6 +44,7 @@ uninit [label="ADC_UNINIT", style="bold"]; ready [label="ADC_READY\nClock Enabled"]; active [label="ADC_ACTIVE\nConverting"]; + error [label="ADC_ERROR\nError"]; complete [label="ADC_COMPLETE\nComplete"]; uninit -> stop [label="\n adcInit()", constraint=false]; @@ -53,15 +55,19 @@ ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"]; active -> ready [label="\nadcStopConversion()\nsync return"]; active -> active [label="\nasync callback (half buffer)\nasync callback (full buffer circular)\n>acg_endcb<"]; - active -> complete [label="\nasync callback (full buffer)\n>acg_endcb<"]; + active -> complete [label="\n\nasync callback (full buffer)\n>end_cb<"]; + active -> error [label="\n\nasync callback (error)\n>error_cb<"]; complete -> active [label="\nadcStartConversionI()\nthen\ncallback return"]; complete -> ready [label="\ncallback return"]; + error -> active [label="\nadcStartConversionI()\nthen\ncallback return"]; + error -> ready [label="\ncallback return"]; } * @enddot * @else * @dot digraph example { rankdir="LR"; + node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"]; edge [fontname=Helvetica, fontsize=8]; @@ -69,6 +75,7 @@ uninit [label="ADC_UNINIT", style="bold"]; ready [label="ADC_READY\nClock Enabled"]; active [label="ADC_ACTIVE\nConverting"]; + error [label="ADC_ERROR\nError"]; complete [label="ADC_COMPLETE\nComplete"]; uninit -> stop [label="\n adcInit()", constraint=false]; @@ -79,9 +86,12 @@ ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"]; active -> ready [label="\nadcStopConversion()\nsync return"]; active -> active [label="\nasync callback (half buffer)\nasync callback (full buffer circular)\n>acg_endcb<"]; - active -> complete [label="\nasync callback (full buffer)\n>acg_endcb<"]; + active -> complete [label="\n\nasync callback (full buffer)\n>end_cb<"]; + active -> error [label="\n\nasync callback (error)\n>error_cb<"]; complete -> active [label="\nadcStartConversionI()\nthen\ncallback return"]; complete -> ready [label="\ncallback return"]; + error -> active [label="\nadcStartConversionI()\nthen\ncallback return"]; + error -> ready [label="\ncallback return"]; } * @enddot * @endif diff --git a/os/hal/include/adc.h b/os/hal/include/adc.h index 53c7c199a..cb392f4e2 100644 --- a/os/hal/include/adc.h +++ b/os/hal/include/adc.h @@ -80,7 +80,8 @@ typedef enum { ADC_STOP = 1, /**< Stopped. */ ADC_READY = 2, /**< Ready. */ ADC_ACTIVE = 3, /**< Converting. */ - ADC_COMPLETE = 4 /**< Conversion complete. */ + ADC_COMPLETE = 4, /**< Conversion complete. */ + ADC_ERROR = 5 /**< Conversion complete. */ } adcstate_t; #include "adc_lld.h" @@ -144,10 +145,30 @@ typedef enum { } \ } +/** + * @brief Wakes up the waiting thread with a timeout message. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +#define _adc_timeout_isr(adcp) { \ + if ((adcp)->thread != NULL) { \ + Thread *tp; \ + chSysLockFromIsr(); \ + tp = (adcp)->thread; \ + (adcp)->thread = NULL; \ + tp->p_u.rdymsg = RDY_TIMEOUT; \ + chSchReadyI(tp); \ + chSysUnlockFromIsr(); \ + } \ +} + #else /* !ADC_USE_WAIT */ #define _adc_reset_i(adcp) #define _adc_reset_s(adcp) #define _adc_wakeup_isr(adcp) +#define _adc_timeout_isr(adcp) #endif /* !ADC_USE_WAIT */ /** @@ -220,6 +241,32 @@ typedef enum { _adc_wakeup_isr(adcp); \ } \ } + +/** + * @brief Common ISR code, error event. + * @details This code handles the portable part of the ISR code: + * - Callback invocation. + * - Waiting thread timeout signaling, if any. + * - Driver state transitions. + * . + * @note This macro is meant to be used in the low level drivers + * implementation only. + * + * @param[in] adcp pointer to the @p ADCDriver object + * + * @notapi + */ +#define _adc_isr_error_code(adcp, err) { \ + adc_lld_stop_conversion(adcp); \ + if ((adcp)->grpp->error_cb != NULL) { \ + (adcp)->state = ADC_ERROR; \ + (adcp)->grpp->error_cb(adcp, err); \ + if ((adcp)->state == ADC_ERROR) \ + (adcp)->state = ADC_READY; \ + } \ + (adcp)->grpp = NULL; \ + _adc_timeout_isr(adcp); \ +} /** @} */ /*===========================================================================*/ diff --git a/os/hal/platforms/STM32F1xx/adc_lld.c b/os/hal/platforms/STM32F1xx/adc_lld.c index ac74251f8..84b194c0f 100644 --- a/os/hal/platforms/STM32F1xx/adc_lld.c +++ b/os/hal/platforms/STM32F1xx/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); + } } } @@ -146,7 +146,7 @@ void adc_lld_start(ADCDriver *adcp) { /* ADC setup, the calibration procedure has already been performed during initialization.*/ - adcp->adc->CR1 = ADC_CR1_SCAN; + adcp->adc->CR1 = 0; adcp->adc->CR2 = 0; } } diff --git a/os/hal/platforms/STM32F1xx/adc_lld.h b/os/hal/platforms/STM32F1xx/adc_lld.h index 1d1052f50..e3a327afa 100644 --- a/os/hal/platforms/STM32F1xx/adc_lld.h +++ b/os/hal/platforms/STM32F1xx/adc_lld.h @@ -108,15 +108,6 @@ #define STM32_ADC_ADC1_IRQ_PRIORITY 5 #endif -/** - * @brief ADC DMA error hook. - * @note The default action for DMA errors is a system halt because DMA - * error can only happen because programming errors. - */ -#if !defined(STM32_ADC_DMA_ERROR_HOOK) || defined(__DOXYGEN__) -#define STM32_ADC_DMA_ERROR_HOOK(adcp) chSysHalt() -#endif - /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ @@ -147,6 +138,15 @@ typedef uint16_t adcsample_t; */ typedef uint16_t adc_channels_num_t; +/** + * @brief Possible ADC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + ADC_ERR_DMAFAILURE = 0 /**< DMA operations failure. */ +} adcerror_t; + /** * @brief Type of a structure representing an ADC driver. */ @@ -162,6 +162,14 @@ typedef struct ADCDriver ADCDriver; */ typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n); +/** + * @brief ADC error callback type. + * + * @param[in] adcp pointer to the @p ADCDriver object triggering the + * callback + */ +typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err); + /** * @brief Conversion group configuration structure. * @details This implementation-dependent structure describes a conversion @@ -183,6 +191,10 @@ typedef struct { * @brief Callback function associated to the group or @p NULL. */ adccallback_t end_cb; + /** + * @brief Error callback or @p NULL. + */ + adcerrorcallback_t error_cb; /* End of the mandatory fields.*/ /** * @brief ADC CR1 register initialization data. 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; } diff --git a/os/hal/platforms/STM32L1xx/adc_lld.h b/os/hal/platforms/STM32L1xx/adc_lld.h index 2889387ab..0ca41c269 100644 --- a/os/hal/platforms/STM32L1xx/adc_lld.h +++ b/os/hal/platforms/STM32L1xx/adc_lld.h @@ -39,8 +39,7 @@ * @name Triggers selection * @{ */ -#define ADC_CR2_EXTSEL_SRC(n) ((n) << 17) /**< @brief Trigger source. */ -#define ADC_CR2_EXTSEL_SWSTART (7 << 17) /**< @brief Software trigger. */ +#define ADC_CR2_EXTSEL_SRC(n) ((n) << 24) /**< @brief Trigger source. */ /** @} */ /** @@ -136,15 +135,6 @@ #define STM32_ADC_ADC1_IRQ_PRIORITY 5 #endif -/** - * @brief ADC DMA error hook. - * @note The default action for DMA errors is a system halt because DMA - * error can only happen because programming errors. - */ -#if !defined(STM32_ADC_DMA_ERROR_HOOK) || defined(__DOXYGEN__) -#define STM32_ADC_DMA_ERROR_HOOK(adcp) chSysHalt() -#endif - /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ @@ -175,6 +165,16 @@ typedef uint16_t adcsample_t; */ typedef uint16_t adc_channels_num_t; +/** + * @brief Possible ADC failure causes. + * @note Error codes are architecture dependent and should not relied + * upon. + */ +typedef enum { + ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ + ADC_ERR_OVERFLOW = 1 /**< ADC overflow condition. */ +} adcerror_t; + /** * @brief Type of a structure representing an ADC driver. */ @@ -190,6 +190,14 @@ typedef struct ADCDriver ADCDriver; */ typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n); +/** + * @brief ADC error callback type. + * + * @param[in] adcp pointer to the @p ADCDriver object triggering the + * callback + */ +typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err); + /** * @brief Conversion group configuration structure. * @details This implementation-dependent structure describes a conversion @@ -211,6 +219,10 @@ typedef struct { * @brief Callback function associated to the group or @p NULL. */ adccallback_t end_cb; + /** + * @brief Error callback or @p NULL. + */ + adcerrorcallback_t error_cb; /* End of the mandatory fields.*/ /** * @brief ADC CR1 register initialization data. diff --git a/os/hal/src/adc.c b/os/hal/src/adc.c index c375818a6..08aa830f0 100644 --- a/os/hal/src/adc.c +++ b/os/hal/src/adc.c @@ -162,6 +162,8 @@ void adcStartConversion(ADCDriver *adcp, /** * @brief Starts an ADC conversion. * @details Starts an asynchronous conversion operation. + * @post The callbacks associated to the conversion group will be invoked + * on buffer fill and error events. * @note The buffer is organized as a matrix of M*N elements where M is the * channels number configured into the conversion group and N is the * buffer depth. The samples are sequentially written into the buffer @@ -185,7 +187,8 @@ void adcStartConversionI(ADCDriver *adcp, ((depth == 1) || ((depth & 1) == 0)), "adcStartConversionI"); chDbgAssert((adcp->state == ADC_READY) || - (adcp->state == ADC_COMPLETE), + (adcp->state == ADC_COMPLETE) || + (adcp->state == ADC_ERROR), "adcStartConversionI(), #1", "not ready"); adcp->samples = samples; @@ -268,6 +271,8 @@ void adcStopConversionI(ADCDriver *adcp) { * @retval RDY_RESET The conversion has been stopped using * @p acdStopConversion() or @p acdStopConversionI(), * the result buffer may contain incorrect data. + * @retval RDY_TIMEOUT The conversion has been stopped because an hardware + * error. * * @api */ -- cgit v1.2.3