ChibiOS/RT
2.5.1
adc.h
Go to the documentation of this file.
00001 /*
00002     ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
00003                  2011,2012 Giovanni Di Sirio.
00004 
00005     This file is part of ChibiOS/RT.
00006 
00007     ChibiOS/RT is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 3 of the License, or
00010     (at your option) any later version.
00011 
00012     ChibiOS/RT is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 */
00020 
00021 /**
00022  * @file    adc.h
00023  * @brief   ADC Driver macros and structures.
00024  *
00025  * @addtogroup ADC
00026  * @{
00027  */
00028 
00029 #ifndef _ADC_H_
00030 #define _ADC_H_
00031 
00032 #if HAL_USE_ADC || defined(__DOXYGEN__)
00033 
00034 /*===========================================================================*/
00035 /* Driver constants.                                                         */
00036 /*===========================================================================*/
00037 
00038 /*===========================================================================*/
00039 /* Driver pre-compile time settings.                                         */
00040 /*===========================================================================*/
00041 
00042 /**
00043  * @name    ADC configuration options
00044  * @{
00045  */
00046 /**
00047  * @brief   Enables synchronous APIs.
00048  * @note    Disabling this option saves both code and data space.
00049  */
00050 #if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
00051 #define ADC_USE_WAIT                TRUE
00052 #endif
00053 
00054 /**
00055  * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
00056  * @note    Disabling this option saves both code and data space.
00057  */
00058 #if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
00059 #define ADC_USE_MUTUAL_EXCLUSION    TRUE
00060 #endif
00061 /** @} */
00062 
00063 /*===========================================================================*/
00064 /* Derived constants and error checks.                                       */
00065 /*===========================================================================*/
00066 
00067 #if ADC_USE_WAIT && !CH_USE_SEMAPHORES
00068 #error "ADC driver requires CH_USE_SEMAPHORES when ADC_USE_WAIT is enabled"
00069 #endif
00070 
00071 /*===========================================================================*/
00072 /* Driver data structures and types.                                         */
00073 /*===========================================================================*/
00074 
00075 /**
00076  * @brief   Driver state machine possible states.
00077  */
00078 typedef enum {
00079   ADC_UNINIT = 0,                           /**< Not initialized.           */
00080   ADC_STOP = 1,                             /**< Stopped.                   */
00081   ADC_READY = 2,                            /**< Ready.                     */
00082   ADC_ACTIVE = 3,                           /**< Converting.                */
00083   ADC_COMPLETE = 4,                         /**< Conversion complete.       */
00084   ADC_ERROR = 5                             /**< Conversion complete.       */
00085 } adcstate_t;
00086 
00087 #include "adc_lld.h"
00088 
00089 /*===========================================================================*/
00090 /* Driver macros.                                                            */
00091 /*===========================================================================*/
00092 
00093 /**
00094  * @name    Low Level driver helper macros
00095  * @{
00096  */
00097 #if ADC_USE_WAIT || defined(__DOXYGEN__)
00098 /**
00099  * @brief   Resumes a thread waiting for a conversion completion.
00100  *
00101  * @param[in] adcp      pointer to the @p ADCDriver object
00102  *
00103  * @notapi
00104  */
00105 #define _adc_reset_i(adcp) {                                                \
00106   if ((adcp)->thread != NULL) {                                             \
00107     Thread *tp = (adcp)->thread;                                            \
00108     (adcp)->thread = NULL;                                                  \
00109     tp->p_u.rdymsg  = RDY_RESET;                                            \
00110     chSchReadyI(tp);                                                        \
00111   }                                                                         \
00112 }
00113 
00114 /**
00115  * @brief   Resumes a thread waiting for a conversion completion.
00116  *
00117  * @param[in] adcp      pointer to the @p ADCDriver object
00118  *
00119  * @notapi
00120  */
00121 #define _adc_reset_s(adcp) {                                                \
00122   if ((adcp)->thread != NULL) {                                             \
00123     Thread *tp = (adcp)->thread;                                            \
00124     (adcp)->thread = NULL;                                                  \
00125     chSchWakeupS(tp, RDY_RESET);                                            \
00126   }                                                                         \
00127 }
00128 
00129 /**
00130  * @brief   Wakes up the waiting thread.
00131  *
00132  * @param[in] adcp      pointer to the @p ADCDriver object
00133  *
00134  * @notapi
00135  */
00136 #define _adc_wakeup_isr(adcp) {                                             \
00137   chSysLockFromIsr();                                                       \
00138   if ((adcp)->thread != NULL) {                                             \
00139     Thread *tp;                                                             \
00140     tp = (adcp)->thread;                                                    \
00141     (adcp)->thread = NULL;                                                  \
00142     tp->p_u.rdymsg = RDY_OK;                                                \
00143     chSchReadyI(tp);                                                        \
00144   }                                                                         \
00145   chSysUnlockFromIsr();                                                     \
00146 }
00147 
00148 /**
00149  * @brief   Wakes up the waiting thread with a timeout message.
00150  *
00151  * @param[in] adcp      pointer to the @p ADCDriver object
00152  *
00153  * @notapi
00154  */
00155 #define _adc_timeout_isr(adcp) {                                            \
00156   chSysLockFromIsr();                                                       \
00157   if ((adcp)->thread != NULL) {                                             \
00158     Thread *tp;                                                             \
00159     tp = (adcp)->thread;                                                    \
00160     (adcp)->thread = NULL;                                                  \
00161     tp->p_u.rdymsg = RDY_TIMEOUT;                                           \
00162     chSchReadyI(tp);                                                        \
00163   }                                                                         \
00164   chSysUnlockFromIsr();                                                     \
00165 }
00166 
00167 #else /* !ADC_USE_WAIT */
00168 #define _adc_reset_i(adcp)
00169 #define _adc_reset_s(adcp)
00170 #define _adc_wakeup_isr(adcp)
00171 #define _adc_timeout_isr(adcp)
00172 #endif /* !ADC_USE_WAIT */
00173 
00174 /**
00175  * @brief   Common ISR code, half buffer event.
00176  * @details This code handles the portable part of the ISR code:
00177  *          - Callback invocation.
00178  *          .
00179  * @note    This macro is meant to be used in the low level drivers
00180  *          implementation only.
00181  *
00182  * @param[in] adcp      pointer to the @p ADCDriver object
00183  *
00184  * @notapi
00185  */
00186 #define _adc_isr_half_code(adcp) {                                          \
00187   if ((adcp)->grpp->end_cb != NULL) {                                       \
00188     (adcp)->grpp->end_cb(adcp, (adcp)->samples, (adcp)->depth / 2);         \
00189   }                                                                         \
00190 }
00191 
00192 /**
00193  * @brief   Common ISR code, full buffer event.
00194  * @details This code handles the portable part of the ISR code:
00195  *          - Callback invocation.
00196  *          - Waiting thread wakeup, if any.
00197  *          - Driver state transitions.
00198  *          .
00199  * @note    This macro is meant to be used in the low level drivers
00200  *          implementation only.
00201  *
00202  * @param[in] adcp      pointer to the @p ADCDriver object
00203  *
00204  * @notapi
00205  */
00206 #define _adc_isr_full_code(adcp) {                                          \
00207   if ((adcp)->grpp->circular) {                                             \
00208     /* Callback handling.*/                                                 \
00209     if ((adcp)->grpp->end_cb != NULL) {                                     \
00210       if ((adcp)->depth > 1) {                                              \
00211         /* Invokes the callback passing the 2nd half of the buffer.*/       \
00212         size_t half = (adcp)->depth / 2;                                    \
00213         size_t half_index = half * (adcp)->grpp->num_channels;              \
00214         (adcp)->grpp->end_cb(adcp, (adcp)->samples + half_index, half);     \
00215       }                                                                     \
00216       else {                                                                \
00217         /* Invokes the callback passing the whole buffer.*/                 \
00218         (adcp)->grpp->end_cb(adcp, (adcp)->samples, (adcp)->depth);         \
00219       }                                                                     \
00220     }                                                                       \
00221   }                                                                         \
00222   else {                                                                    \
00223     /* End conversion.*/                                                    \
00224     adc_lld_stop_conversion(adcp);                                          \
00225     if ((adcp)->grpp->end_cb != NULL) {                                     \
00226       (adcp)->state = ADC_COMPLETE;                                         \
00227       if ((adcp)->depth > 1) {                                              \
00228         /* Invokes the callback passing the 2nd half of the buffer.*/       \
00229         size_t half = (adcp)->depth / 2;                                    \
00230         size_t half_index = half * (adcp)->grpp->num_channels;              \
00231         (adcp)->grpp->end_cb(adcp, (adcp)->samples + half_index, half);     \
00232       }                                                                     \
00233       else {                                                                \
00234         /* Invokes the callback passing the whole buffer.*/                 \
00235         (adcp)->grpp->end_cb(adcp, (adcp)->samples, (adcp)->depth);         \
00236       }                                                                     \
00237       if ((adcp)->state == ADC_COMPLETE)                                    \
00238         (adcp)->state = ADC_READY;                                          \
00239     }                                                                       \
00240     else                                                                    \
00241       (adcp)->state = ADC_READY;                                            \
00242     (adcp)->grpp = NULL;                                                    \
00243     _adc_wakeup_isr(adcp);                                                  \
00244   }                                                                         \
00245 }
00246 
00247 /**
00248  * @brief   Common ISR code, error event.
00249  * @details This code handles the portable part of the ISR code:
00250  *          - Callback invocation.
00251  *          - Waiting thread timeout signaling, if any.
00252  *          - Driver state transitions.
00253  *          .
00254  * @note    This macro is meant to be used in the low level drivers
00255  *          implementation only.
00256  *
00257  * @param[in] adcp      pointer to the @p ADCDriver object
00258  * @param[in] err       platform dependent error code
00259  *
00260  * @notapi
00261  */
00262 #define _adc_isr_error_code(adcp, err) {                                    \
00263   adc_lld_stop_conversion(adcp);                                            \
00264   if ((adcp)->grpp->error_cb != NULL) {                                     \
00265     (adcp)->state = ADC_ERROR;                                              \
00266     (adcp)->grpp->error_cb(adcp, err);                                      \
00267     if ((adcp)->state == ADC_ERROR)                                         \
00268       (adcp)->state = ADC_READY;                                            \
00269   }                                                                         \
00270   (adcp)->grpp = NULL;                                                      \
00271   _adc_timeout_isr(adcp);                                                   \
00272 }
00273 /** @} */
00274 
00275 /*===========================================================================*/
00276 /* External declarations.                                                    */
00277 /*===========================================================================*/
00278 
00279 #ifdef __cplusplus
00280 extern "C" {
00281 #endif
00282   void adcInit(void);
00283   void adcObjectInit(ADCDriver *adcp);
00284   void adcStart(ADCDriver *adcp, const ADCConfig *config);
00285   void adcStop(ADCDriver *adcp);
00286   void adcStartConversion(ADCDriver *adcp,
00287                           const ADCConversionGroup *grpp,
00288                           adcsample_t *samples,
00289                           size_t depth);
00290   void adcStartConversionI(ADCDriver *adcp,
00291                            const ADCConversionGroup *grpp,
00292                            adcsample_t *samples,
00293                            size_t depth);
00294   void adcStopConversion(ADCDriver *adcp);
00295   void adcStopConversionI(ADCDriver *adcp);
00296 #if ADC_USE_WAIT
00297   msg_t adcConvert(ADCDriver *adcp,
00298                    const ADCConversionGroup *grpp,
00299                    adcsample_t *samples,
00300                    size_t depth);
00301 #endif
00302 #if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
00303   void adcAcquireBus(ADCDriver *adcp);
00304   void adcReleaseBus(ADCDriver *adcp);
00305 #endif /* ADC_USE_MUTUAL_EXCLUSION */
00306 #ifdef __cplusplus
00307 }
00308 #endif
00309 
00310 #endif /* HAL_USE_ADC */
00311 
00312 #endif /* _ADC_H_ */
00313 
00314 /** @} */