diff --git a/os/hal/platforms/STM32F0xx/adc_lld.h b/os/hal/platforms/STM32F0xx/adc_lld.h index ecf215160..f51b60716 100644 --- a/os/hal/platforms/STM32F0xx/adc_lld.h +++ b/os/hal/platforms/STM32F0xx/adc_lld.h @@ -77,7 +77,7 @@ /** * @brief ADC1 driver enable switch. * @details If set to @p TRUE the support for ADC1 is included. - * @note The default is @p TRUE. + * @note The default is @p FALSE. */ #if !defined(STM32_ADC_USE_ADC1) || defined(__DOXYGEN__) #define STM32_ADC_USE_ADC1 FALSE diff --git a/os/hal/platforms/STM32F0xx/hal_lld.h b/os/hal/platforms/STM32F0xx/hal_lld.h index 775892391..362a553d4 100644 --- a/os/hal/platforms/STM32F0xx/hal_lld.h +++ b/os/hal/platforms/STM32F0xx/hal_lld.h @@ -234,6 +234,10 @@ #define STM32_ADC3_DMA_MSK 0x00000000 #define STM32_ADC3_DMA_CHN 0x00000000 +#define STM32_HAS_ADC4 FALSE +#define STM32_ADC4_DMA_MSK 0x00000000 +#define STM32_ADC4_DMA_CHN 0x00000000 + /* CAN attributes.*/ #define STM32_HAS_CAN1 FALSE #define STM32_HAS_CAN2 FALSE diff --git a/os/hal/platforms/STM32F1xx/hal_lld_f100.h b/os/hal/platforms/STM32F1xx/hal_lld_f100.h index f143a838c..a9e6a06a5 100644 --- a/os/hal/platforms/STM32F1xx/hal_lld_f100.h +++ b/os/hal/platforms/STM32F1xx/hal_lld_f100.h @@ -339,6 +339,7 @@ #define STM32_HAS_ADC1 TRUE #define STM32_HAS_ADC2 FALSE #define STM32_HAS_ADC3 FALSE +#define STM32_HAS_ADC4 FALSE /* CAN attributes.*/ #define STM32_HAS_CAN1 FALSE diff --git a/os/hal/platforms/STM32F1xx/hal_lld_f103.h b/os/hal/platforms/STM32F1xx/hal_lld_f103.h index 159b95252..817505e7b 100644 --- a/os/hal/platforms/STM32F1xx/hal_lld_f103.h +++ b/os/hal/platforms/STM32F1xx/hal_lld_f103.h @@ -205,6 +205,7 @@ #define STM32_HAS_ADC1 TRUE #define STM32_HAS_ADC2 TRUE #define STM32_HAS_ADC3 FALSE +#define STM32_HAS_ADC4 FALSE /* CAN attributes.*/ #define STM32_HAS_CAN1 TRUE diff --git a/os/hal/platforms/STM32F1xx/hal_lld_f105_f107.h b/os/hal/platforms/STM32F1xx/hal_lld_f105_f107.h index b91fff389..6336acecb 100644 --- a/os/hal/platforms/STM32F1xx/hal_lld_f105_f107.h +++ b/os/hal/platforms/STM32F1xx/hal_lld_f105_f107.h @@ -222,6 +222,7 @@ #define STM32_HAS_ADC1 TRUE #define STM32_HAS_ADC2 TRUE #define STM32_HAS_ADC3 FALSE +#define STM32_HAS_ADC4 FALSE /* CAN attributes.*/ #define STM32_HAS_CAN1 TRUE diff --git a/os/hal/platforms/STM32F3xx/adc_lld.c b/os/hal/platforms/STM32F3xx/adc_lld.c new file mode 100644 index 000000000..85276bb1d --- /dev/null +++ b/os/hal/platforms/STM32F3xx/adc_lld.c @@ -0,0 +1,298 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 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 STM32F3xx/adc_lld.c + * @brief STM32F3xx 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 Stops an ongoing conversion, if any. + * + * @param[in] adc pointer to the ADC registers block + */ +static void adc_lld_stop_adc(ADC_TypeDef *adc) { + + if (adc->CR & ADC_CR_ADSTART) { + adc->CR |= ADC_CR_ADSTP; + while (adc->CR & ADC_CR_ADSTP) + ; + } +} + +/** + * @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 ((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 { + /* 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); + } + } + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__) +/** + * @brief ADC interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(ADC1_COMP_IRQHandler) { + uint32_t isr; + + CH_IRQ_PROLOGUE(); + + isr = ADC1->ISR; + ADC1->ISR = isr; + + /* It could be a spurious interrupt caused by overflows after DMA disabling, + just ignore it in this case.*/ + if (ADCD1.grpp != NULL) { + /* 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 ((isr & ADC_ISR_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 (isr & ADC_ISR_AWD) { + /* Analog watchdog error.*/ + _adc_isr_error_code(&ADCD1, ADC_ERR_AWD); + } + } + + CH_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* 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_DIR_P2M | + STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; +#endif + + /* The shared vector is initialized on driver initialization and never + disabled.*/ + nvicEnableVector(ADC1_COMP_IRQn, + CORTEX_PRIORITY_MASK(STM32_ADC_IRQ_PRIORITY)); + + /* Calibration procedure.*/ + rccEnableADC1(FALSE); + chDbgAssert(ADC1->CR == 0, "adc_lld_init(), #1", "invalid register state"); + ADC1->CR |= ADC_CR_ADCAL; + while (ADC1->CR & ADC_CR_ADCAL) + ; + rccDisableADC1(FALSE); +} + +/** + * @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_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); +#if STM32_ADCSW == STM32_ADCSW_HSI14 + /* Clock from HSI14, no need for jitter removal.*/ + ADC1->CFGR2 = 0x00001000; +#else +#if STM32_ADCPRE == STM32_ADCPRE_DIV2 + ADC1->CFGR2 = 0x00001000 | ADC_CFGR2_JITOFFDIV2; +#else + ADC1->CFGR2 = 0x00001000 | ADC_CFGR2_JITOFFDIV4; +#endif +#endif + } +#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->CR = ADC_CR_ADEN; + while (!(adcp->adc->ISR & ADC_ISR_ADRDY)) + ; + } +} + +/** + * @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 and analog part.*/ + if (adcp->state == ADC_READY) { + + dmaStreamRelease(adcp->dmastp); + + /* Disabling ADC.*/ + if (adcp->adc->CR & ADC_CR_ADEN) { + adc_lld_stop_adc(adcp->adc); + adcp->adc->CR |= ADC_CR_ADDIS; + while (adcp->adc->CR & ADC_CR_ADDIS) + ; + } + +#if STM32_ADC_USE_ADC1 + if (&ADCD1 == adcp) + 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; + 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; + } + dmaStreamSetMemory0(adcp->dmastp, adcp->samples); + dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels * + (uint32_t)adcp->depth); + dmaStreamSetMode(adcp->dmastp, mode); + dmaStreamEnable(adcp->dmastp); + + /* ADC setup, if it is defined a callback for the analog watch dog then it + is enabled.*/ + adcp->adc->ISR = adcp->adc->ISR; + adcp->adc->IER = ADC_IER_OVRIE | ADC_IER_AWDIE; + adcp->adc->TR = grpp->tr; + adcp->adc->SMPR = grpp->smpr; + adcp->adc->CHSELR = grpp->chselr; + + /* ADC configuration and start.*/ + adcp->adc->CFGR1 = grpp->cfgr1 | ADC_CFGR1_CONT | ADC_CFGR1_DMACFG | + ADC_CFGR1_DMAEN; + adcp->adc->CR |= ADC_CR_ADSTART; +} + +/** + * @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); + adc_lld_stop_adc(adcp->adc); +} + +#endif /* HAL_USE_ADC */ + +/** @} */ diff --git a/os/hal/platforms/STM32F3xx/adc_lld.h b/os/hal/platforms/STM32F3xx/adc_lld.h new file mode 100644 index 000000000..857ae5d25 --- /dev/null +++ b/os/hal/platforms/STM32F3xx/adc_lld.h @@ -0,0 +1,451 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 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 STM32F3xx/adc_lld.h + * @brief STM32F3xx ADC subsystem low level driver header. + * + * @addtogroup ADC + * @{ + */ + +#ifndef _ADC_LLD_H_ +#define _ADC_LLD_H_ + +#if HAL_USE_ADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Sampling rates + * @{ + */ +#define ADC_SMPR_SMP_1P5 0 /**< @brief 14 cycles conversion time */ +#define ADC_SMPR_SMP_2P5 1 /**< @brief 15 cycles conversion time. */ +#define ADC_SMPR_SMP_4P5 2 /**< @brief 17 cycles conversion time. */ +#define ADC_SMPR_SMP_7P5 3 /**< @brief 20 cycles conversion time. */ +#define ADC_SMPR_SMP_19P5 4 /**< @brief 32 cycles conversion time. */ +#define ADC_SMPR_SMP_61P5 5 /**< @brief 74 cycles conversion time. */ +#define ADC_SMPR_SMP_181P5 6 /**< @brief 194 cycles conversion time. */ +#define ADC_SMPR_SMP_601P5 7 /**< @brief 614 cycles conversion time. */ +/** @} */ + +/** + * @name Resolution + * @{ + */ +#define ADC_CFGR1_RES_12BIT (0 << 3) +#define ADC_CFGR1_RES_10BIT (1 << 3) +#define ADC_CFGR1_RES_8BIT (2 << 3) +#define ADC_CFGR1_RES_6BIT (3 << 3) +/** @} */ + +/** + * @name Threashold register initializer + * @{ + */ +#define ADC_TR(low, high) (((uint32_t)(high) << 16) | (uint32_t)(low)) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief ADC1 driver enable switch. + * @details If set to @p TRUE the support for ADC1 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC1) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC1 FALSE +#endif +/** + * @brief ADC1+ADC2 driver enable switch. + * @details If set to @p TRUE the support for ADC1+ADC2 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC12) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC12 FALSE +#endif +/** + * @brief ADC3 driver enable switch. + * @details If set to @p TRUE the support for ADC3 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC3) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC3 FALSE +#endif +/** + * @brief ADC3+ADC4 driver enable switch. + * @details If set to @p TRUE the support for ADC3+ADC4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_ADC_USE_ADC34) || defined(__DOXYGEN__) +#define STM32_ADC_USE_ADC34 FALSE +#endif + +/** + * @brief ADC1/ADC2 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC12_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC3/ADC4 DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_ADC_ADC34_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC34_DMA_PRIORITY 2 +#endif + +/** + * @brief ADC1/ADC2 interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC12_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_IRQ_PRIORITY 2 +#endif + +/** + * @brief ADC3/ADC4 interrupt priority level setting. + */ +#if !defined(STM32_ADC34_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC34_IRQ_PRIORITY 2 +#endif + +/** + * @brief ADC1/ADC2 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC12_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC12_DMA_IRQ_PRIORITY 2 +#endif + +/** + * @brief ADC3/ADC4 DMA interrupt priority level setting. + */ +#if !defined(STM32_ADC_ADC34_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_ADC_ADC34_DMA_IRQ_PRIORITY 2 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1 +#error "ADC1 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC12 && (!STM32_HAS_ADC1 || !STM32_HAS_ADC2) +#error "ADC12 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC3 && !STM32_HAS_ADC3 +#error "ADC3 not present in the selected device" +#endif + +#if STM32_ADC_USE_ADC34 && (!STM32_HAS_ADC3 || !STM32_HAS_ADC4) +#error "ADC34 not present in the selected device" +#endif + +#if !STM32_ADC_USE_ADC1 || !STM32_ADC_USE_ADC12 || \ + !STM32_ADC_USE_ADC3 || !STM32_ADC_USE_ADC34 +#error "ADC driver activated but no ADC peripheral assigned" +#endif + +#if STM32_ADC_USE_ADC1 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ADC_ADC12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1" +#endif + +#if STM32_ADC_USE_ADC1 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ADC_ADC12_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC1 DMA" +#endif + +#if STM32_ADC_USE_ADC1 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC12_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC1" +#endif + +#if STM32_ADC_USE_ADC12 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ADC_ADC12_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC12" +#endif + +#if STM32_ADC_USE_ADC12 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ADC_ADC12_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC12 DMA" +#endif + +#if STM32_ADC_USE_ADC12 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC12_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC12" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ADC_ADC34_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC3" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ADC_ADC34_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC3 DMA" +#endif + +#if STM32_ADC_USE_ADC3 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC34_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC3" +#endif + +#if STM32_ADC_USE_ADC34 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ADC_ADC34_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC34" +#endif + +#if STM32_ADC_USE_ADC34 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_ADC_ADC34_DMA_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to ADC34 DMA" +#endif + +#if STM32_ADC_USE_ADC34 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC34_DMA_PRIORITY) +#error "Invalid DMA priority assigned to ADC34" +#endif + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief ADC sample data type. + */ +typedef uint16_t adcsample_t; + +/** + * @brief Channels number in a conversion group. + */ +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. */ + ADC_ERR_AWD = 2 /**< Analog watchdog triggered. */ +} adcerror_t; + +/** + * @brief Type of a structure representing an ADC driver. + */ +typedef struct ADCDriver ADCDriver; + +/** + * @brief ADC notification callback type. + * + * @param[in] adcp pointer to the @p ADCDriver object triggering the + * callback + * @param[in] buffer pointer to the most recent samples data + * @param[in] n number of buffer rows available starting from @p buffer + */ +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 + * @param[in] err ADC error code + */ +typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err); + +/** + * @brief Conversion group configuration structure. + * @details This implementation-dependent structure describes a conversion + * operation. + * @note The use of this configuration structure requires knowledge of + * STM32 ADC cell registers interface, please refer to the STM32 + * reference manual for details. + */ +typedef struct { + /** + * @brief Enables the circular buffer mode for the group. + */ + bool_t circular; + /** + * @brief Number of the analog channels belonging to the conversion group. + */ + adc_channels_num_t num_channels; + /** + * @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 CFGR1 register initialization data. + */ + uint32_t cfgr1; + /** + * @brief ADC TR register initialization data. + */ + uint32_t tr; + /** + * @brief ADC SMPR register initialization data. + */ + uint32_t smpr; + /** + * @brief ADC CHSELR register initialization data. + * @details The number of bits at logic level one in this register must + * be equal to the number in the @p num_channels field. + */ + uint32_t chselr; +} ADCConversionGroup; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + uint32_t dummy; +} ADCConfig; + +/** + * @brief Structure representing an ADC driver. + */ +struct ADCDriver { + /** + * @brief Driver state. + */ + adcstate_t state; + /** + * @brief Current configuration data. + */ + const ADCConfig *config; + /** + * @brief Current samples buffer pointer or @p NULL. + */ + adcsample_t *samples; + /** + * @brief Current samples buffer depth or @p 0. + */ + size_t depth; + /** + * @brief Current conversion group pointer or @p NULL. + */ + const ADCConversionGroup *grpp; +#if ADC_USE_WAIT || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + Thread *thread; +#endif +#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) +#if CH_USE_MUTEXES || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the peripheral. + */ + Mutex mutex; +#elif CH_USE_SEMAPHORES + Semaphore semaphore; +#endif +#endif /* ADC_USE_MUTUAL_EXCLUSION */ +#if defined(ADC_DRIVER_EXT_FIELDS) + ADC_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the ADCx registers block. + */ + ADC_TypeDef *adc; + /** + * @brief Pointer to associated SMA channel. + */ + const stm32_dma_stream_t *dmastp; + /** + * @brief DMA mode bit mask. + */ + uint32_t dmamode; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Changes the value of the ADC CCR registers. + * @details Use this function in order to enable or disable the internal + * analog sources. See the documentation in the STM32F3xx Reference + * Manual. + */ +#define adcSTM32SetCCR(adc, ccr) ((adc)->CCR = (ccr)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__) +extern ADCDriver ADCD1; +#endif + +#if STM32_ADC_USE_ADC12 && !defined(__DOXYGEN__) +extern ADCDriver ADCD12; +#endif + +#if STM32_ADC_USE_ADC3 && !defined(__DOXYGEN__) +extern ADCDriver ADCD3; +#endif + +#if STM32_ADC_USE_ADC34 && !defined(__DOXYGEN__) +extern ADCDriver ADCD34; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void adc_lld_init(void); + void adc_lld_start(ADCDriver *adcp); + void adc_lld_stop(ADCDriver *adcp); + void adc_lld_start_conversion(ADCDriver *adcp); + void adc_lld_stop_conversion(ADCDriver *adcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ADC */ + +#endif /* _ADC_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/STM32F4xx/hal_lld.h b/os/hal/platforms/STM32F4xx/hal_lld.h index 6638b8f7f..3723f6e61 100644 --- a/os/hal/platforms/STM32F4xx/hal_lld.h +++ b/os/hal/platforms/STM32F4xx/hal_lld.h @@ -307,6 +307,10 @@ STM32_DMA_STREAM_ID_MSK(2, 1)) #define STM32_ADC3_DMA_CHN 0x00000022 +#define STM32_HAS_ADC4 FALSE +#define STM32_ADC4_DMA_MSK 0x00000000 +#define STM32_ADC4_DMA_CHN 0x00000000 + /* CAN attributes.*/ #define STM32_HAS_CAN1 TRUE #define STM32_HAS_CAN2 TRUE diff --git a/os/hal/platforms/STM32L1xx/hal_lld.h b/os/hal/platforms/STM32L1xx/hal_lld.h index 297b9553b..6305f9fed 100644 --- a/os/hal/platforms/STM32L1xx/hal_lld.h +++ b/os/hal/platforms/STM32L1xx/hal_lld.h @@ -182,6 +182,7 @@ #define STM32_HAS_ADC1 TRUE #define STM32_HAS_ADC2 FALSE #define STM32_HAS_ADC3 FALSE +#define STM32_HAS_ADC4 FALSE /* CAN attributes.*/ #define STM32_HAS_CAN1 FALSE