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

master
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
* @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

View File

@ -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); \
}
/** @} */
/*===========================================================================*/

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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.

View File

@ -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
*/

View File

@ -95,7 +95,12 @@
(backported to 2.2.4).
- FIX: Fixed timeout problem in the lwIP interface layer (bug 3302420)
(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.
- NEW: Added new API chThdExitS() in order to allow atomic operations on
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.
* Mode: Streaming, continuous, 16 samples of 8 channels, SW triggered.
@ -50,6 +56,7 @@ static const ADCConversionGroup adcgrpcfg = {
TRUE,
ADC_GRP1_NUM_CHANNELS,
adccallback,
adcerrorcallback,
0,
ADC_CR2_TSVREFE,
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.
* Mode: Streaming, continuous, 16 samples of 8 channels, SW triggered.
@ -50,6 +56,7 @@ static const ADCConversionGroup adcgrpcfg = {
TRUE,
ADC_GRP1_NUM_CHANNELS,
adccallback,
adcerrorcallback,
0, 0, /* CR1, CR2 */
0, 0, 0, /* SMPR1...SMPR3 */
ADC_SQR1_NUM_CH(ADC_GRP1_NUM_CHANNELS),