Improved STM32G0 ADC driver.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13792 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
Giovanni Di Sirio 2020-07-28 08:28:34 +00:00
parent f9237ecc1a
commit 1b1b98cedb
9 changed files with 873 additions and 14 deletions

View File

@ -44,7 +44,7 @@
#define ADC_SMPR_SMP_55P5 5U /**< @brief 68 cycles conversion time. */ #define ADC_SMPR_SMP_55P5 5U /**< @brief 68 cycles conversion time. */
#define ADC_SMPR_SMP_71P5 6U /**< @brief 84 cycles conversion time. */ #define ADC_SMPR_SMP_71P5 6U /**< @brief 84 cycles conversion time. */
#define ADC_SMPR_SMP_239P5 7U /**< @brief 252 cycles conversion time. */ #define ADC_SMPR_SMP_239P5 7U /**< @brief 252 cycles conversion time. */
#elif defined(STM32L0XX) || defined(STM32G0XX) #elif defined(STM32L0XX)
#define ADC_SMPR_SMP_1P5 0U /**< @brief 14 cycles conversion time */ #define ADC_SMPR_SMP_1P5 0U /**< @brief 14 cycles conversion time */
#define ADC_SMPR_SMP_3P5 1U /**< @brief 16 cycles conversion time. */ #define ADC_SMPR_SMP_3P5 1U /**< @brief 16 cycles conversion time. */
#define ADC_SMPR_SMP_7P5 2U /**< @brief 20 cycles conversion time. */ #define ADC_SMPR_SMP_7P5 2U /**< @brief 20 cycles conversion time. */
@ -172,12 +172,11 @@
/*===========================================================================*/ /*===========================================================================*/
/* Supported devices checks.*/ /* Supported devices checks.*/
#if !defined(STM32F0XX) && !defined(STM32L0XX) && !defined(STM32G0XX) #if !defined(STM32F0XX) && !defined(STM32L0XX)
#error "ADCv1 only supports F0, L0 and G0 STM32 devices" #error "ADCv1 only supports F0 and L0 STM32 devices"
#endif #endif
#if defined(STM32L0XX) || defined(STM32G0XX) || \ #if defined(STM32L0XX) || defined(__DOXYGEN__)
defined(__DOXYGEN__)
#define STM32_ADCV1_OVERSAMPLING TRUE #define STM32_ADCV1_OVERSAMPLING TRUE
#else #else
#define STM32_ADCV1_OVERSAMPLING FALSE #define STM32_ADCV1_OVERSAMPLING FALSE

View File

@ -0,0 +1,9 @@
ifeq ($(USE_SMART_BUILD),yes)
ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),)
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c
endif
else
PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv5/hal_adc_lld.c
endif
PLATFORMINC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv5

View File

@ -0,0 +1,471 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file ADCv1/hal_adc_lld.c
* @brief STM32 ADC subsystem low level driver source.
*
* @addtogroup ADC
* @{
*/
#include "hal.h"
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
#define ADC1_DMA_CHANNEL \
STM32_DMA_GETCHANNEL(STM32_ADC_ADC1_DMA_STREAM, STM32_ADC1_DMA_CHN)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief ADC1 driver identifier.*/
#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__)
ADCDriver ADCD1;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief ADC voltage regulator enable.
*
* @param[in] adc pointer to the ADC registers block
*/
NOINLINE static void adc_lld_vreg_on(ADC_TypeDef *adc) {
osalDbgAssert(adc->CR == 0, "invalid register state");
#if defined(ADC_CR_ADVREGEN)
adc->CR = ADC_CR_ADVREGEN;
volatile uint32_t loop = (STM32_HCLK >> 20) << 4;
do {
loop--;
} while (loop > 0);
#else
#endif
}
/**
* @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)
;
adc->IER = 0;
}
}
/**
* @brief ADC DMA 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_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);
}
}
}
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__)
#if !defined(STM32_ADC1_HANDLER)
#error "STM32_ADC1_HANDLER not defined"
#endif
/**
* @brief ADC interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(STM32_ADC1_HANDLER) {
OSAL_IRQ_PROLOGUE();
adc_lld_serve_interrupt(&ADCD1);
#if defined(STM32_ADC_ADC1_IRQ_HOOK)
STM32_ADC_ADC1_IRQ_HOOK
#endif
OSAL_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 = NULL;
ADCD1.dmamode = STM32_DMA_CR_CHSEL(ADC1_DMA_CHANNEL) |
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;
/* The vector is initialized on driver initialization and never
disabled.*/
nvicEnableVector(12, STM32_ADC_ADC1_IRQ_PRIORITY);
#endif
/* Calibration procedure.*/
rccEnableADC1(true);
/* CCR setup.*/
ADC->CCR = STM32_ADC_PRESC << 18;
/* Regulator enabled and stabilized before calibration.*/
adc_lld_vreg_on(ADC1);
ADC1->CR |= ADC_CR_ADCAL;
while (ADC1->CR & ADC_CR_ADCAL)
;
ADC1->CR = 0;
rccDisableADC1();
}
/**
* @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) {
adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC1_DMA_STREAM,
STM32_ADC_ADC1_DMA_IRQ_PRIORITY,
(stm32_dmaisr_t)adc_lld_serve_rx_interrupt,
(void *)adcp);
osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream");
rccEnableADC1(true);
/* DMA setup.*/
dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR);
dmaSetRequestSource(adcp->dmastp, STM32_DMAMUX1_ADC1);
/* Clock settings.*/
adcp->adc->CFGR2 = STM32_ADC_ADC1_CKMODE;
}
#endif /* STM32_ADC_USE_ADC1 */
/* Regulator enabled and stabilized before calibration.*/
adc_lld_vreg_on(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) {
dmaStreamFreeI(adcp->dmastp);
adcp->dmastp = NULL;
/* Restoring CCR default.*/
ADC->CCR = STM32_ADC_PRESC << 18;
/* 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)
;
}
/* Regulator and anything else off.*/
adcp->adc->CR = 0;
#if STM32_ADC_USE_ADC1
if (&ADCD1 == adcp)
rccDisableADC1();
#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, cfgr1, cfgr2;
const ADCConversionGroup *grpp = adcp->grpp;
/* DMA setup.*/
mode = adcp->dmamode;
cfgr1 = grpp->cfgr1 | ADC_CFGR1_DMAEN;
cfgr2 = adcp->adc->CFGR2 & STM32_ADC_CKMODE_MASK;
if (grpp->circular) {
mode |= STM32_DMA_CR_CIRC;
cfgr1 |= ADC_CFGR1_DMACFG;
if (adcp->depth > 1) {
/* If circular buffer depth > 1, then the half transfer interrupt
is enabled in order to allow 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_AWD1IE | ADC_IER_AWD2IE | ADC_IER_AWD3IE;
adcp->adc->TR1 = grpp->tr1;
adcp->adc->TR2 = grpp->tr2;
adcp->adc->TR3 = grpp->tr3;
adcp->adc->SMPR = grpp->smpr;
adcp->adc->CHSELR = grpp->chselr;
/* ADC configuration and start.*/
adcp->adc->CFGR1 = cfgr1;
adcp->adc->CFGR2 = cfgr2 | grpp->cfgr2;
/* ADC conversion start.*/
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);
}
/**
* @brief ISR code.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_serve_interrupt(ADCDriver *adcp) {
uint32_t isr;
isr = adcp->adc->ISR & adcp->adc->IER;
adcp->adc->ISR = isr;
/* It could be a spurious interrupt caused by overflows after DMA disabling,
just ignore it in this case.*/
if (adcp->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(adcp->dmastp) > 0)) {
/* ADC overflow condition, this could happen only if the DMA is unable
to read data fast enough.*/
_adc_isr_error_code(adcp, ADC_ERR_OVERFLOW);
}
if (isr & ADC_ISR_AWD1) {
/* Analog watchdog 1 error.*/
_adc_isr_error_code(adcp, ADC_ERR_AWD1);
}
if (isr & ADC_ISR_AWD2) {
/* Analog watchdog 2 error.*/
_adc_isr_error_code(adcp, ADC_ERR_AWD2);
}
if (isr & ADC_ISR_AWD3) {
/* Analog watchdog 3 error.*/
_adc_isr_error_code(adcp, ADC_ERR_AWD3);
}
}
}
/**
* @brief Enables the VREFEN bit.
* @details The VREFEN bit is required in order to sample the VREF channel.
* @note This is an STM32-only functionality.
* @note This function is meant to be called after @p adcStart().
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adcSTM32EnableVREF(ADCDriver *adcp) {
(void)adcp;
ADC->CCR |= ADC_CCR_VREFEN;
}
/**
* @brief Disables the VREFEN bit.
* @details The VREFEN bit is required in order to sample the VREF channel.
* @note This is an STM32-only functionality.
* @note This function is meant to be called after @p adcStart().
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adcSTM32DisableVREF(ADCDriver *adcp) {
(void)adcp;
ADC->CCR &= ~ADC_CCR_VREFEN;
}
/**
* @brief Enables the TSEN bit.
* @details The TSEN bit is required in order to sample the internal
* temperature sensor and internal reference voltage.
* @note This is an STM32-only functionality.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adcSTM32EnableTS(ADCDriver *adcp) {
(void)adcp;
ADC->CCR |= ADC_CCR_TSEN;
}
/**
* @brief Disables the TSEN bit.
* @details The TSEN bit is required in order to sample the internal
* temperature sensor and internal reference voltage.
* @note This is an STM32-only functionality.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adcSTM32DisableTS(ADCDriver *adcp) {
(void)adcp;
ADC->CCR &= ~ADC_CCR_TSEN;
}
#if defined(ADC_CCR_VBATEN) || defined(__DOXYGEN__)
/**
* @brief Enables the VBATEN bit.
* @details The VBATEN bit is required in order to sample the VBAT channel.
* @note This is an STM32-only functionality.
* @note This function is meant to be called after @p adcStart().
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adcSTM32EnableVBAT(ADCDriver *adcp) {
(void)adcp;
ADC->CCR |= ADC_CCR_VBATEN;
}
/**
* @brief Disables the VBATEN bit.
* @details The VBATEN bit is required in order to sample the VBAT channel.
* @note This is an STM32-only functionality.
* @note This function is meant to be called after @p adcStart().
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adcSTM32DisableVBAT(ADCDriver *adcp) {
(void)adcp;
ADC->CCR &= ~ADC_CCR_VBATEN;
}
#endif /* defined(ADC_CCR_VBATEN) */
#endif /* HAL_USE_ADC */
/** @} */

View File

@ -0,0 +1,365 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file ADCv1/hal_adc_lld.h
* @brief STM32 ADC subsystem low level driver header.
*
* @addtogroup ADC
* @{
*/
#ifndef HAL_ADC_LLD_H
#define HAL_ADC_LLD_H
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Sampling rates
* @{
*/
#define ADC_SMPR_SMP_1P5 0U /**< @brief 14 cycles conversion time */
#define ADC_SMPR_SMP_3P5 1U /**< @brief 16 cycles conversion time. */
#define ADC_SMPR_SMP_7P5 2U /**< @brief 20 cycles conversion time. */
#define ADC_SMPR_SMP_12P5 3U /**< @brief 25 cycles conversion time. */
#define ADC_SMPR_SMP_19P5 4U /**< @brief 31 cycles conversion time. */
#define ADC_SMPR_SMP_39P5 5U /**< @brief 52 cycles conversion time. */
#define ADC_SMPR_SMP_79P5 6U /**< @brief 92 cycles conversion time. */
#define ADC_SMPR_SMP_160P5 7U /**< @brief 173 cycles conversion time. */
/** @} */
/**
* @name CFGR1 register configuration helpers
* @{
*/
#define ADC_CFGR1_RES_12BIT (0U << 3U)
#define ADC_CFGR1_RES_10BIT (1U << 3U)
#define ADC_CFGR1_RES_8BIT (2U << 3U)
#define ADC_CFGR1_RES_6BIT (3U << 3U)
#define ADC_CFGR1_EXTSEL_MASK (15U << 6U)
#define ADC_CFGR1_EXTSEL_SRC(n) ((n) << 6U)
#define ADC_CFGR1_EXTEN_MASK (3U << 10U)
#define ADC_CFGR1_EXTEN_DISABLED (0U << 10U)
#define ADC_CFGR1_EXTEN_RISING (1U << 10U)
#define ADC_CFGR1_EXTEN_FALLING (2U << 10U)
#define ADC_CFGR1_EXTEN_BOTH (3U << 10U)
/** @} */
/**
* @name CFGR2 register configuration helpers
* @{
*/
#define STM32_ADC_CKMODE_MASK (3U << 30U)
#define STM32_ADC_CKMODE_ADCCLK (0U << 30U)
#define STM32_ADC_CKMODE_PCLK_DIV2 (1U << 30U)
#define STM32_ADC_CKMODE_PCLK_DIV4 (2U << 30U)
#define STM32_ADC_CKMODE_PCLK (3U << 30U)
#define ADC_CFGR2_OVSR_MASK (7U << 2U)
#define ADC_CFGR2_OVSR_2X (0U << 2U)
#define ADC_CFGR2_OVSR_4X (1U << 2U)
#define ADC_CFGR2_OVSR_8X (2U << 2U)
#define ADC_CFGR2_OVSR_16X (3U << 2U)
#define ADC_CFGR2_OVSR_32X (4U << 2U)
#define ADC_CFGR2_OVSR_64X (5U << 2U)
#define ADC_CFGR2_OVSR_128X (6U << 2U)
#define ADC_CFGR2_OVSR_256X (7U << 2U)
#define ADC_CFGR2_OVSS_MASK (15 << 5U)
#define ADC_CFGR2_OVSS_SHIFT(n) ((n) << 5U)
/** @} */
/**
* @name Threashold registers initializer
* @{
*/
#define ADC_TR(low, high) (((uint32_t)(high) << 16U) | \
(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 clock source selection.
*/
#if !defined(STM32_ADC_ADC1_CKMODE) || defined(__DOXYGEN__)
#define STM32_ADC_ADC1_CKMODE STM32_ADC_CKMODE_ADCCLK
#endif
/**
* @brief ADC1 DMA priority (0..3|lowest..highest).
*/
#if !defined(STM32_ADC_ADC1_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC1_DMA_PRIORITY 2
#endif
/**
* @brief ADC interrupt priority level setting.
*/
#if !defined(STM32_ADC_ADC1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC1_IRQ_PRIORITY 2
#endif
/**
* @brief ADC1 DMA interrupt priority level setting.
*/
#if !defined(STM32_ADC_ADC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 2
#endif
/*
* @brief ADC prescaler setting.
* @note This setting has effect only in asynchronous clock mode (the
* default, @p STM32_ADC_CKMODE_ADCCLK).
*/
#if !defined(STM32_ADC_PRESCALER_VALUE) || defined(__DOXYGEN__)
#define STM32_ADC_PRESCALER_VALUE 2
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/* Supported devices checks.*/
#if !defined(STM32G0XX)
#error "ADCv5 only supports G0 STM32 devices"
#endif
/* Registry checks.*/
#if !defined(STM32_HAS_ADC1)
#error "STM32_HAS_ADC1 not defined in registry"
#endif
#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_HANDLER))
#error "STM32_ADC1_HANDLER not defined in registry"
#endif
#if (STM32_ADC_USE_ADC1 && !defined(STM32_ADC1_NUMBER))
#error "STM32_ADC1_NUMBER not defined in registry"
#endif
#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1
#error "ADC1 not present in the selected device"
#endif
/* Units checks.*/
#if STM32_ADC_USE_ADC1 && !STM32_HAS_ADC1
#error "ADC1 not present in the selected device"
#endif
/* At least one ADC must be assigned.*/
#if !STM32_ADC_USE_ADC1
#error "ADC driver activated but no ADC peripheral assigned"
#endif
/* ADC IRQ priority tests.*/
#if STM32_ADC_USE_ADC1 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to ADC1"
#endif
/* DMA IRQ priority tests.*/
#if STM32_ADC_USE_ADC1 && \
!OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC1_DMA_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to ADC1 DMA"
#endif
/* DMA priority tests.*/
#if STM32_ADC_USE_ADC1 && \
!STM32_DMA_IS_VALID_PRIORITY(STM32_ADC_ADC1_DMA_PRIORITY)
#error "Invalid DMA priority assigned to ADC1"
#endif
/* Check on the presence of the DMA streams settings in mcuconf.h.*/
#if STM32_ADC_USE_ADC1 && !defined(STM32_ADC_ADC1_DMA_STREAM)
#error "ADC DMA stream not defined"
#endif
/* ADC clock source checks.*/
#if STM32_ADC_PRESCALER_VALUE == 2
#define STM32_ADC_PRESC 1U
#elif STM32_ADC_PRESCALER_VALUE == 4
#define STM32_ADC_PRESC 2U
#elif STM32_ADC_PRESCALER_VALUE == 6
#define STM32_ADC_PRESC 3U
#elif STM32_ADC_PRESCALER_VALUE == 8
#define STM32_ADC_PRESC 4U
#elif STM32_ADC_PRESCALER_VALUE == 10
#define STM32_ADC_PRESC 5U
#elif STM32_ADC_PRESCALER_VALUE == 12
#define STM32_ADC_PRESC 6U
#elif STM32_ADC_PRESCALER_VALUE == 16
#define STM32_ADC_PRESC 7U
#elif STM32_ADC_PRESCALER_VALUE == 32
#define STM32_ADC_PRESC 8U
#elif STM32_ADC_PRESCALER_VALUE == 64
#define STM32_ADC_PRESC 9U
#elif STM32_ADC_PRESCALER_VALUE == 128
#define STM32_ADC_PRESC 10U
#elif STM32_ADC_PRESCALER_VALUE == 256
#define STM32_ADC_PRESC 11U
#else
#error "Invalid value assigned to STM32_ADC_PRESCALER_VALUE"
#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_AWD1 = 2, /**< Analog watchdog 1. */
ADC_ERR_AWD2 = 3, /**< Analog watchdog 2. */
ADC_ERR_AWD3 = 4 /**< Analog watchdog 3. */
} adcerror_t;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Low level fields of the ADC driver structure.
*/
#define adc_lld_driver_fields \
/* Pointer to the ADCx registers block.*/ \
ADC_TypeDef *adc; \
/* Pointer to associated DMA channel.*/ \
const stm32_dma_stream_t *dmastp; \
/* DMA mode bit mask.*/ \
uint32_t dmamode
/**
* @brief Low level fields of the ADC configuration structure.
*/
#define adc_lld_config_fields \
/* Dummy configuration, it is not needed.*/ \
uint32_t dummy
/**
* @brief Low level fields of the ADC configuration structure.
*/
#define adc_lld_configuration_group_fields \
/* ADC CFGR1 register initialization data. \
NOTE: The bits DMAEN and DMACFG are enforced internally \
to the driver, keep them to zero. \
NOTE: The bits @p ADC_CFGR1_CONT or @p ADC_CFGR1_DISCEN must be \
specified in continuous more or if the buffer depth is \
greater than one.*/ \
uint32_t cfgr1; \
/* ADC CFGR2 register initialization data. \
NOTE: CKMODE bits must not be specified in this field and left to \
zero.*/ \
uint32_t cfgr2; \
/* ADC TR1 register initialization data.*/ \
uint32_t tr1; \
/* ADC TR2 register initialization data.*/ \
uint32_t tr2; \
/* ADC TR3 register initialization data.*/ \
uint32_t tr3; \
/* ADC SMPR register initialization data.*/ \
uint32_t smpr; \
/* ADC CHSELR register initialization data. \
NOTE: 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
/**
* @brief Changes the value of the ADC CCR register.
* @details Use this function in order to enable or disable the internal
* analog sources. See the documentation in the STM32 Reference
* Manual.
* @note PRESC bits must not be specified and left to zero.
*/
#define adcSTM32SetCCR(ccr) (ADC->CCR = (ccr))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if STM32_ADC_USE_ADC1 && !defined(__DOXYGEN__)
extern ADCDriver ADCD1;
#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);
void adc_lld_serve_interrupt(ADCDriver *adcp);
void adcSTM32EnableVREF(ADCDriver *adcp);
void adcSTM32DisableVREF(ADCDriver *adcp);
void adcSTM32EnableTS(ADCDriver *adcp);
void adcSTM32DisableTS(ADCDriver *adcp);
#if defined(ADC_CCR_VBATEN)
void adcSTM32EnableVBAT(ADCDriver *adcp);
void adcSTM32DisableVBAT(ADCDriver *adcp);
#endif
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ADC */
#endif /* HAL_ADC_LLD_H */
/** @} */

View File

@ -0,0 +1,16 @@
STM32 ADCv1 driver.
Driver capability:
- Supports the STM32 "simple" ADC, the one found on small devices (G0).
The file registry must export:
STM32_HAS_ADC1 - ADC1 presence flag.
STM32_ADC_SUPPORTS_PRESCALER - Support of CCR PRESC field.
STM32_ADC_SUPPORTS_OVERSAMPLING - Support of oversampling-related fields.
STM32_ADC1_IRQ_SHARED_WITH_EXTI - TRUE if the IRQ is shared with EXTI.
STM32_ADC1_HANDLER - IRQ vector name.
STM32_ADC1_NUMBER - IRQ vector number.
STM32_ADC1_DMA_MSK - Mask of the compatible DMA channels.
STM32_ADC1_DMA_CHN - Mask of the channels mapping.

View File

@ -26,7 +26,7 @@ else
endif endif
# Drivers compatible with the platform. # Drivers compatible with the platform.
include $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv5/driver.mk
include $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/driver.mk
include $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/driver.mk
include $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/driver.mk include $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/driver.mk

View File

@ -92,9 +92,6 @@
/* ADC attributes.*/ /* ADC attributes.*/
#define STM32_HAS_ADC1 TRUE #define STM32_HAS_ADC1 TRUE
#define STM32_ADC_SUPPORTS_PRESCALER TRUE
#define STM32_ADC_SUPPORTS_OVERSAMPLING TRUE
#define STM32_HAS_ADC2 FALSE #define STM32_HAS_ADC2 FALSE
#define STM32_HAS_ADC3 FALSE #define STM32_HAS_ADC3 FALSE
#define STM32_HAS_ADC4 FALSE #define STM32_HAS_ADC4 FALSE
@ -272,9 +269,6 @@
/* ADC attributes.*/ /* ADC attributes.*/
#define STM32_HAS_ADC1 TRUE #define STM32_HAS_ADC1 TRUE
#define STM32_ADC_SUPPORTS_PRESCALER TRUE
#define STM32_ADC_SUPPORTS_OVERSAMPLING TRUE
#define STM32_HAS_ADC2 FALSE #define STM32_HAS_ADC2 FALSE
#define STM32_HAS_ADC3 FALSE #define STM32_HAS_ADC3 FALSE
#define STM32_HAS_ADC4 FALSE #define STM32_HAS_ADC4 FALSE

View File

@ -74,6 +74,7 @@
***************************************************************************** *****************************************************************************
*** Next *** *** Next ***
- NEW: Support for 3 analog watchdogs in STM32G0 ADC.
- NEW: Stand-alone ARMv6-M port. - NEW: Stand-alone ARMv6-M port.
- NEW: Stand-alone ARMv7-M port. - NEW: Stand-alone ARMv7-M port.
- NEW: Merged RT7. - NEW: Merged RT7.

View File

@ -67,7 +67,9 @@ const ADCConversionGroup portab_adcgrpcfg1 = {
.error_cb = adcerrorcallback, .error_cb = adcerrorcallback,
.cfgr1 = ADC_CFGR1_CONT | ADC_CFGR1_RES_12BIT, /* CFGR1 */ .cfgr1 = ADC_CFGR1_CONT | ADC_CFGR1_RES_12BIT, /* CFGR1 */
.cfgr2 = 0, /* CFGR2 */ .cfgr2 = 0, /* CFGR2 */
.tr = ADC_TR(0, 0), /* TR */ .tr1 = ADC_TR(0, 0), /* TR1 */
.tr2 = ADC_TR(0, 0), /* TR2 */
.tr3 = ADC_TR(0, 0), /* TR3 */
.smpr = ADC_SMPR_SMP_1P5, /* SMPR */ .smpr = ADC_SMPR_SMP_1P5, /* SMPR */
.chselr = ADC_CHSELR_CHSEL10 /* CHSELR */ .chselr = ADC_CHSELR_CHSEL10 /* CHSELR */
}; };
@ -87,7 +89,9 @@ const ADCConversionGroup portab_adcgrpcfg2 = {
ADC_CFGR1_EXTEN_RISING | ADC_CFGR1_EXTEN_RISING |
ADC_CFGR1_EXTSEL_SRC(0), /* CFGR1 */ ADC_CFGR1_EXTSEL_SRC(0), /* CFGR1 */
.cfgr2 = 0, /* CFGR2 */ .cfgr2 = 0, /* CFGR2 */
.tr = ADC_TR(0, 0), /* TR */ .tr1 = ADC_TR(0, 0), /* TR1 */
.tr2 = ADC_TR(0, 0), /* TR2 */
.tr3 = ADC_TR(0, 0), /* TR3 */
.smpr = ADC_SMPR_SMP_39P5, /* SMPR */ .smpr = ADC_SMPR_SMP_39P5, /* SMPR */
.chselr = ADC_CHSELR_CHSEL10 | ADC_CHSELR_CHSEL11 | .chselr = ADC_CHSELR_CHSEL10 | ADC_CHSELR_CHSEL11 |
ADC_CHSELR_CHSEL17 | ADC_CHSELR_CHSEL18 /* CHSELR */ ADC_CHSELR_CHSEL17 | ADC_CHSELR_CHSEL18 /* CHSELR */