git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3381 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
gdisirio 2011-09-22 14:53:42 +00:00
parent 40c7a8982a
commit 4a3e3fc01e
10 changed files with 182 additions and 52 deletions

View File

@ -34,8 +34,9 @@
* @if LATEX_PDF * @if LATEX_PDF
* @dot * @dot
digraph example { digraph example {
size="5, 7";
rankdir="LR"; rankdir="LR";
size="5, 7";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"]; node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8]; edge [fontname=Helvetica, fontsize=8];
@ -43,6 +44,7 @@
uninit [label="ADC_UNINIT", style="bold"]; uninit [label="ADC_UNINIT", style="bold"];
ready [label="ADC_READY\nClock Enabled"]; ready [label="ADC_READY\nClock Enabled"];
active [label="ADC_ACTIVE\nConverting"]; active [label="ADC_ACTIVE\nConverting"];
error [label="ADC_ERROR\nError"];
complete [label="ADC_COMPLETE\nComplete"]; complete [label="ADC_COMPLETE\nComplete"];
uninit -> stop [label="\n adcInit()", constraint=false]; uninit -> stop [label="\n adcInit()", constraint=false];
@ -53,15 +55,19 @@
ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"]; ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"];
active -> ready [label="\nadcStopConversion()\nsync return"]; active -> ready [label="\nadcStopConversion()\nsync return"];
active -> active [label="\nasync callback (half buffer)\nasync callback (full buffer circular)\n>acg_endcb<"]; 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 -> active [label="\nadcStartConversionI()\nthen\ncallback return"];
complete -> ready [label="\ncallback return"]; complete -> ready [label="\ncallback return"];
error -> active [label="\nadcStartConversionI()\nthen\ncallback return"];
error -> ready [label="\ncallback return"];
} }
* @enddot * @enddot
* @else * @else
* @dot * @dot
digraph example { digraph example {
rankdir="LR"; rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"]; node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
edge [fontname=Helvetica, fontsize=8]; edge [fontname=Helvetica, fontsize=8];
@ -69,6 +75,7 @@
uninit [label="ADC_UNINIT", style="bold"]; uninit [label="ADC_UNINIT", style="bold"];
ready [label="ADC_READY\nClock Enabled"]; ready [label="ADC_READY\nClock Enabled"];
active [label="ADC_ACTIVE\nConverting"]; active [label="ADC_ACTIVE\nConverting"];
error [label="ADC_ERROR\nError"];
complete [label="ADC_COMPLETE\nComplete"]; complete [label="ADC_COMPLETE\nComplete"];
uninit -> stop [label="\n adcInit()", constraint=false]; uninit -> stop [label="\n adcInit()", constraint=false];
@ -79,9 +86,12 @@
ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"]; ready -> active [label="\nadcStartConversion() (async)\nadcConvert() (sync)"];
active -> ready [label="\nadcStopConversion()\nsync return"]; active -> ready [label="\nadcStopConversion()\nsync return"];
active -> active [label="\nasync callback (half buffer)\nasync callback (full buffer circular)\n>acg_endcb<"]; 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 -> active [label="\nadcStartConversionI()\nthen\ncallback return"];
complete -> ready [label="\ncallback return"]; complete -> ready [label="\ncallback return"];
error -> active [label="\nadcStartConversionI()\nthen\ncallback return"];
error -> ready [label="\ncallback return"];
} }
* @enddot * @enddot
* @endif * @endif

View File

@ -80,7 +80,8 @@ typedef enum {
ADC_STOP = 1, /**< Stopped. */ ADC_STOP = 1, /**< Stopped. */
ADC_READY = 2, /**< Ready. */ ADC_READY = 2, /**< Ready. */
ADC_ACTIVE = 3, /**< Converting. */ ADC_ACTIVE = 3, /**< Converting. */
ADC_COMPLETE = 4 /**< Conversion complete. */ ADC_COMPLETE = 4, /**< Conversion complete. */
ADC_ERROR = 5 /**< Conversion complete. */
} adcstate_t; } adcstate_t;
#include "adc_lld.h" #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 */ #else /* !ADC_USE_WAIT */
#define _adc_reset_i(adcp) #define _adc_reset_i(adcp)
#define _adc_reset_s(adcp) #define _adc_reset_s(adcp)
#define _adc_wakeup_isr(adcp) #define _adc_wakeup_isr(adcp)
#define _adc_timeout_isr(adcp)
#endif /* !ADC_USE_WAIT */ #endif /* !ADC_USE_WAIT */
/** /**
@ -220,6 +241,32 @@ typedef enum {
_adc_wakeup_isr(adcp); \ _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); \
}
/** @} */ /** @} */
/*===========================================================================*/ /*===========================================================================*/

View File

@ -57,13 +57,12 @@ ADCDriver ADCD1;
static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) {
/* DMA errors handling.*/ /* DMA errors handling.*/
#if defined(STM32_ADC_DMA_ERROR_HOOK)
if ((flags & STM32_DMA_ISR_TEIF) != 0) { 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 else {
(void)flags;
#endif
if ((flags & STM32_DMA_ISR_HTIF) != 0) { if ((flags & STM32_DMA_ISR_HTIF) != 0) {
/* Half transfer processing.*/ /* Half transfer processing.*/
_adc_isr_half_code(adcp); _adc_isr_half_code(adcp);
@ -72,6 +71,7 @@ static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) {
/* Transfer complete processing.*/ /* Transfer complete processing.*/
_adc_isr_full_code(adcp); _adc_isr_full_code(adcp);
} }
}
} }
/*===========================================================================*/ /*===========================================================================*/
@ -146,7 +146,7 @@ void adc_lld_start(ADCDriver *adcp) {
/* ADC setup, the calibration procedure has already been performed /* ADC setup, the calibration procedure has already been performed
during initialization.*/ during initialization.*/
adcp->adc->CR1 = ADC_CR1_SCAN; adcp->adc->CR1 = 0;
adcp->adc->CR2 = 0; adcp->adc->CR2 = 0;
} }
} }

View File

@ -108,15 +108,6 @@
#define STM32_ADC_ADC1_IRQ_PRIORITY 5 #define STM32_ADC_ADC1_IRQ_PRIORITY 5
#endif #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. */ /* Derived constants and error checks. */
/*===========================================================================*/ /*===========================================================================*/
@ -147,6 +138,15 @@ typedef uint16_t adcsample_t;
*/ */
typedef uint16_t adc_channels_num_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. * @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); 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. * @brief Conversion group configuration structure.
* @details This implementation-dependent structure describes a conversion * @details This implementation-dependent structure describes a conversion
@ -183,6 +191,10 @@ typedef struct {
* @brief Callback function associated to the group or @p NULL. * @brief Callback function associated to the group or @p NULL.
*/ */
adccallback_t end_cb; adccallback_t end_cb;
/**
* @brief Error callback or @p NULL.
*/
adcerrorcallback_t error_cb;
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/
/** /**
* @brief ADC CR1 register initialization data. * @brief ADC CR1 register initialization data.

View File

@ -57,13 +57,12 @@ ADCDriver ADCD1;
static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) { static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) {
/* DMA errors handling.*/ /* DMA errors handling.*/
#if defined(STM32_ADC_DMA_ERROR_HOOK)
if ((flags & STM32_DMA_ISR_TEIF) != 0) { 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 else {
(void)flags;
#endif
if ((flags & STM32_DMA_ISR_HTIF) != 0) { if ((flags & STM32_DMA_ISR_HTIF) != 0) {
/* Half transfer processing.*/ /* Half transfer processing.*/
_adc_isr_half_code(adcp); _adc_isr_half_code(adcp);
@ -72,12 +71,36 @@ static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) {
/* Transfer complete processing.*/ /* Transfer complete processing.*/
_adc_isr_full_code(adcp); _adc_isr_full_code(adcp);
} }
}
} }
/*===========================================================================*/ /*===========================================================================*/
/* Driver interrupt handlers. */ /* 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. */ /* Driver exported functions. */
/*===========================================================================*/ /*===========================================================================*/
@ -145,6 +168,7 @@ void adc_lld_stop(ADCDriver *adcp) {
if (adcp->state == ADC_READY) { if (adcp->state == ADC_READY) {
#if STM32_ADC_USE_ADC1 #if STM32_ADC_USE_ADC1
if (&ADCD1 == adcp) { if (&ADCD1 == adcp) {
ADC1->CR1 = 0;
ADC1->CR2 = 0; ADC1->CR2 = 0;
dmaStreamRelease(adcp->dmastp); dmaStreamRelease(adcp->dmastp);
rccDisableADC1(FALSE); rccDisableADC1(FALSE);
@ -182,7 +206,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) {
/* ADC setup.*/ /* ADC setup.*/
adcp->adc->SR = 0; 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->SMPR1 = grpp->smpr1; /* Writing SMPRx requires ADON=0. */
adcp->adc->SMPR2 = grpp->smpr2; adcp->adc->SMPR2 = grpp->smpr2;
adcp->adc->SMPR3 = grpp->smpr3; adcp->adc->SMPR3 = grpp->smpr3;
@ -211,6 +235,7 @@ void adc_lld_start_conversion(ADCDriver *adcp) {
void adc_lld_stop_conversion(ADCDriver *adcp) { void adc_lld_stop_conversion(ADCDriver *adcp) {
dmaStreamDisable(adcp->dmastp); dmaStreamDisable(adcp->dmastp);
adcp->adc->CR1 = 0;
adcp->adc->CR2 = 0; adcp->adc->CR2 = 0;
} }

View File

@ -39,8 +39,7 @@
* @name Triggers selection * @name Triggers selection
* @{ * @{
*/ */
#define ADC_CR2_EXTSEL_SRC(n) ((n) << 17) /**< @brief Trigger source. */ #define ADC_CR2_EXTSEL_SRC(n) ((n) << 24) /**< @brief Trigger source. */
#define ADC_CR2_EXTSEL_SWSTART (7 << 17) /**< @brief Software trigger. */
/** @} */ /** @} */
/** /**
@ -136,15 +135,6 @@
#define STM32_ADC_ADC1_IRQ_PRIORITY 5 #define STM32_ADC_ADC1_IRQ_PRIORITY 5
#endif #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. */ /* Derived constants and error checks. */
/*===========================================================================*/ /*===========================================================================*/
@ -175,6 +165,16 @@ typedef uint16_t adcsample_t;
*/ */
typedef uint16_t adc_channels_num_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. * @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); 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. * @brief Conversion group configuration structure.
* @details This implementation-dependent structure describes a conversion * @details This implementation-dependent structure describes a conversion
@ -211,6 +219,10 @@ typedef struct {
* @brief Callback function associated to the group or @p NULL. * @brief Callback function associated to the group or @p NULL.
*/ */
adccallback_t end_cb; adccallback_t end_cb;
/**
* @brief Error callback or @p NULL.
*/
adcerrorcallback_t error_cb;
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/
/** /**
* @brief ADC CR1 register initialization data. * @brief ADC CR1 register initialization data.

View File

@ -162,6 +162,8 @@ void adcStartConversion(ADCDriver *adcp,
/** /**
* @brief Starts an ADC conversion. * @brief Starts an ADC conversion.
* @details Starts an asynchronous conversion operation. * @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 * @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 * channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially written into the buffer * buffer depth. The samples are sequentially written into the buffer
@ -185,7 +187,8 @@ void adcStartConversionI(ADCDriver *adcp,
((depth == 1) || ((depth & 1) == 0)), ((depth == 1) || ((depth & 1) == 0)),
"adcStartConversionI"); "adcStartConversionI");
chDbgAssert((adcp->state == ADC_READY) || chDbgAssert((adcp->state == ADC_READY) ||
(adcp->state == ADC_COMPLETE), (adcp->state == ADC_COMPLETE) ||
(adcp->state == ADC_ERROR),
"adcStartConversionI(), #1", "not ready"); "adcStartConversionI(), #1", "not ready");
adcp->samples = samples; adcp->samples = samples;
@ -268,6 +271,8 @@ void adcStopConversionI(ADCDriver *adcp) {
* @retval RDY_RESET The conversion has been stopped using * @retval RDY_RESET The conversion has been stopped using
* @p acdStopConversion() or @p acdStopConversionI(), * @p acdStopConversion() or @p acdStopConversionI(),
* the result buffer may contain incorrect data. * the result buffer may contain incorrect data.
* @retval RDY_TIMEOUT The conversion has been stopped because an hardware
* error.
* *
* @api * @api
*/ */

View File

@ -95,7 +95,12 @@
(backported to 2.2.4). (backported to 2.2.4).
- FIX: Fixed timeout problem in the lwIP interface layer (bug 3302420) - FIX: Fixed timeout problem in the lwIP interface layer (bug 3302420)
(backported to 2.2.4). (backported to 2.2.4).
- NEW: STM32L1xx sub-family support, all STM32 drivers adapted and retested - NEW: STM32L ADC driver implementation.
(TODO: To be tested.)
- NEW: Improved ADC driver model, now it is possible to handle error
conditions during the conversion process.
(TODO: Modify existing STM32 ADC implementation).
- NEW: STM32L1xx sub-family support, all STM32 drivers adapted and re-tested
on the new platform except ADC that will need a specific implementation. on the new platform except ADC that will need a specific implementation.
- NEW: Added new API chThdExitS() in order to allow atomic operations on - NEW: Added new API chThdExitS() in order to allow atomic operations on
thead exit (backported to 2.2.8). thead exit (backported to 2.2.8).

View File

@ -41,6 +41,12 @@ static void adccallback(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
} }
} }
static void adcerrorcallback(ADCDriver *adcp, adcerror_t err) {
(void)adcp;
(void)err;
}
/* /*
* ADC conversion group. * ADC conversion group.
* Mode: Streaming, continuous, 16 samples of 8 channels, SW triggered. * Mode: Streaming, continuous, 16 samples of 8 channels, SW triggered.
@ -50,6 +56,7 @@ static const ADCConversionGroup adcgrpcfg = {
TRUE, TRUE,
ADC_GRP1_NUM_CHANNELS, ADC_GRP1_NUM_CHANNELS,
adccallback, adccallback,
adcerrorcallback,
0, 0,
ADC_CR2_TSVREFE, ADC_CR2_TSVREFE,
0, 0,

View File

@ -41,6 +41,12 @@ static void adccallback(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
} }
} }
static void adcerrorcallback(ADCDriver *adcp, adcerror_t err) {
(void)adcp;
(void)err;
}
/* /*
* ADC conversion group. * ADC conversion group.
* Mode: Streaming, continuous, 16 samples of 8 channels, SW triggered. * Mode: Streaming, continuous, 16 samples of 8 channels, SW triggered.
@ -50,6 +56,7 @@ static const ADCConversionGroup adcgrpcfg = {
TRUE, TRUE,
ADC_GRP1_NUM_CHANNELS, ADC_GRP1_NUM_CHANNELS,
adccallback, adccallback,
adcerrorcallback,
0, 0, /* CR1, CR2 */ 0, 0, /* CR1, CR2 */
0, 0, 0, /* SMPR1...SMPR3 */ 0, 0, 0, /* SMPR1...SMPR3 */
ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS), ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),