From 594032585a8c7cac0a9aab43a2fae7208c4315f1 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sat, 29 Dec 2018 17:33:15 +0000 Subject: Some progress on H7 ADC, not finished. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12492 110e8d01-0319-4d1e-a829-52ad28d1bb01 --- os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c | 71 ++++-- os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h | 343 ++++++++++------------------- 2 files changed, 171 insertions(+), 243 deletions(-) (limited to 'os/hal/ports/STM32/LLD/ADCv4') diff --git a/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c b/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c index 826e5f732..041904857 100644 --- a/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c +++ b/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.c @@ -207,6 +207,36 @@ static void adc_lld_serve_dma_interrupt(ADCDriver *adcp, uint32_t flags) { } } +/** + * @brief ADC BDMA 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_bdma_interrupt(ADCDriver *adcp, uint32_t flags) { + + /* DMA errors handling.*/ + if ((flags & STM32_BDMA_ISR_TEIF) != 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_BDMA_ISR_TCIF) != 0) { + /* Transfer complete processing.*/ + _adc_isr_full_code(adcp); + } + else if ((flags & STM32_BDMA_ISR_HTIF) != 0) { + /* Half transfer processing.*/ + _adc_isr_half_code(adcp); + } + } + } +} + /** * @brief ADC ISR service routine. * @@ -219,9 +249,8 @@ static void adc_lld_serve_interrupt(ADCDriver *adcp, uint32_t isr) { 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->data.dma) > 0)) { + is able to stop the ADC, this is why the state is checked too.*/ + if ((isr & ADC_ISR_OVR) && (adcp->state == ADC_ACTIVE)) { /* 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); @@ -325,12 +354,12 @@ void adc_lld_init(void) { #if STM32_ADC_DUAL_MODE ADCD1.adcs = ADC2; #endif - ADCD1.data.dma = STM32_DMA_STREAM(STM32_ADC_ADC12_DMA_CHANNEL); - ADCD1.dmamode = ADC_DMA_SIZE | - STM32_DMA_CR_PL(STM32_ADC_ADC12_DMA_PRIORITY) | - STM32_DMA_CR_DIR_P2M | - STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | - STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + ADCD1.data.dma = STM32_DMA_STREAM(STM32_ADC_ADC12_DMA_CHANNEL); + ADCD1.dmamode = ADC_DMA_SIZE | + STM32_DMA_CR_PL(STM32_ADC_ADC12_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; nvicEnableVector(STM32_ADC12_NUMBER, STM32_ADC_ADC12_IRQ_PRIORITY); #endif /* STM32_ADC_USE_ADC12 == TRUE */ @@ -344,16 +373,16 @@ void adc_lld_init(void) { #else ADCD3.adcc = ADC3_COMMON; #endif - ADCD3.adcm = ADC3; + ADCD3.adcm = ADC3; #if STM32_ADC_DUAL_MODE - ADCD3.adcs = ADC4; + ADCD3.adcs = ADC4; #endif - ADCD3.dmastp = STM32_DMA_STREAM(STM32_ADC_ADC3_DMA_STREAM); - ADCD3.dmamode = ADC_DMA_SIZE | - STM32_DMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) | - STM32_DMA_CR_DIR_P2M | - STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | - STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + ADCD3.data.bdma = STM32_BDMA_STREAM(STM32_ADC_ADC3_BDMA_CHANNEL); + ADCD3.dmamode = ADC_DMA_SIZE | + STM32_DMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) | + STM32_DMA_CR_DIR_P2M | + STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE | + STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; nvicEnableVector(STM32_ADC3_NUMBER, STM32_ADC_ADC3_IRQ_PRIORITY); #endif /* STM32_ADC_USE_ADC3 == TRUE */ @@ -405,10 +434,10 @@ void adc_lld_start(ADCDriver *adcp) { #if STM32_ADC_USE_ADC3 == TRUE if (&ADCD3 == adcp) { bool b; - b = dmaStreamAllocate(adcp->dmastp, - STM32_ADC_ADC3_IRQ_PRIORITY, - (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, - (void *)adcp); + b = bdmaStreamAllocate(adcp->data.bdma, + STM32_ADC_ADC3_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_bdma_interrupt, + (void *)adcp); osalDbgAssert(!b, "stream already allocated"); rccEnableADC3(true); } diff --git a/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h b/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h index a286714ab..e345bbcc3 100644 --- a/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h +++ b/os/hal/ports/STM32/LLD/ADCv4/hal_adc_lld.h @@ -56,6 +56,31 @@ #define ADC_CHANNEL_IN18 18U /**< @brief External analog input 18. */ /** @} */ +/** + * @name ADC channels selection masks + * @{ + */ +#define ADC_SELMASK_IN0 (1U << ADC_CHANNEL_IN0) +#define ADC_SELMASK_IN1 (1U << ADC_CHANNEL_IN1) +#define ADC_SELMASK_IN2 (1U << ADC_CHANNEL_IN2) +#define ADC_SELMASK_IN3 (1U << ADC_CHANNEL_IN3) +#define ADC_SELMASK_IN4 (1U << ADC_CHANNEL_IN4) +#define ADC_SELMASK_IN5 (1U << ADC_CHANNEL_IN5) +#define ADC_SELMASK_IN6 (1U << ADC_CHANNEL_IN6) +#define ADC_SELMASK_IN7 (1U << ADC_CHANNEL_IN7) +#define ADC_SELMASK_IN8 (1U << ADC_CHANNEL_IN8) +#define ADC_SELMASK_IN9 (1U << ADC_CHANNEL_IN9) +#define ADC_SELMASK_IN10 (1U << ADC_CHANNEL_IN10) +#define ADC_SELMASK_IN11 (1U << ADC_CHANNEL_IN11) +#define ADC_SELMASK_IN12 (1U << ADC_CHANNEL_IN12) +#define ADC_SELMASK_IN13 (1U << ADC_CHANNEL_IN13) +#define ADC_SELMASK_IN14 (1U << ADC_CHANNEL_IN14) +#define ADC_SELMASK_IN15 (1U << ADC_CHANNEL_IN15) +#define ADC_SELMASK_IN16 (1U << ADC_CHANNEL_IN16) +#define ADC_SELMASK_IN17 (1U << ADC_CHANNEL_IN17) +#define ADC_SELMASK_IN18 (1U << ADC_CHANNEL_IN18) +/** @} */ + /** * @name Sampling rates * @{ @@ -177,8 +202,8 @@ /** * @brief ADC3 DMA channel. */ -#if !defined(STM32_ADC_ADC3_DMA_CHANNEL) || defined(__DOXYGEN__) -#define STM32_ADC_ADC3_DMA_CHANNEL 1 +#if !defined(STM32_ADC_ADC3_BDMA_CHANNEL) || defined(__DOXYGEN__) +#define STM32_ADC_ADC3_BDMA_CHANNEL 1 #endif /** @@ -295,7 +320,7 @@ #endif #if STM32_ADC_USE_ADC3 && \ - !STM32_BDMA_IS_VALID_CHANNEL(STM32_ADC_ADC3_DMA_CHANNEL) + !STM32_BDMA_IS_VALID_CHANNEL(STM32_ADC_ADC3_BDMA_CHANNEL) #error "Invalid DMA channel assigned to ADC3" #endif @@ -317,7 +342,7 @@ #endif #if STM32_ADC_USE_ADC3 && \ - !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC34_IRQ_PRIORITY) + !OSAL_IRQ_IS_VALID_PRIORITY(STM32_ADC_ADC3_IRQ_PRIORITY) #error "Invalid IRQ priority assigned to ADC3" #endif @@ -404,219 +429,9 @@ typedef enum { } 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 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 CFGR register initialization data. - * @note The bits DMNGT are enforced internally to the driver, keep - * them to zero. - * @note The bits @p ADC_CFGR_CONT or @p ADC_CFGR_DISCEN must be - * specified in continuous mode or if the buffer depth is - * greater than one. - */ - uint32_t cfgr; -#if STM32_ADC_DUAL_MODE || defined(__DOXYGEN__) - /** - * @brief ADC CCR register initialization data. - * @note The bits CKMODE and DAMDF are enforced internally to the - * driver, keep them to zero. - * @note This field is only present in dual mode. - */ - uint32_t ccr; -#endif - /** - * @brief ADC PCSEL register initialization data. - */ - uint32_t pcsel; - /** - * @brief ADC LTR1 register initialization data. - */ - uint32_t ltr1; - /** - * @brief ADC HTR1 register initialization data. - */ - uint32_t htr1; - /** - * @brief ADC LTR2 register initialization data. - */ - uint32_t ltr2; - /** - * @brief ADC HTR2 register initialization data. - */ - uint32_t htr2; - /** - * @brief ADC LTR3 register initialization data. - */ - uint32_t ltr3; - /** - * @brief ADC HTR3 register initialization data. - */ - uint32_t htr3; - /** - * @brief ADC SMPRx registers initialization data. - */ - uint32_t smpr[2]; - /** - * @brief ADC SQRx register initialization data. - */ - uint32_t sqr[4]; -#if STM32_ADC_DUAL_MODE || defined(__DOXYGEN__) - /** - * @brief Slave ADC PCSEL register initialization data. - */ - uint32_t spcsel; - /** - * @brief Slave ADC LTR1 register initialization data. - */ - uint32_t sltr1; - /** - * @brief Slave ADC HTR1 register initialization data. - */ - uint32_t shtr1; - /** - * @brief Slave ADC LTR2 register initialization data. - */ - uint32_t sltr2; - /** - * @brief Slave ADC HTR2 register initialization data. - */ - uint32_t shtr2; - /** - * @brief Slave ADC LTR3 register initialization data. - */ - uint32_t sltr3; - /** - * @brief Slave ADC HTR3 register initialization data. - */ - uint32_t shtr3; - /** - * @brief Slave ADC SMPRx registers initialization data. - * @note This field is only present in dual mode. - */ - uint32_t ssmpr[2]; - /** - * @brief Slave ADC SQRx register initialization data. - * @note This field is only present in dual mode. - */ - uint32_t ssqr[4]; -#endif /* STM32_ADC_DUAL_MODE */ -} ADCConversionGroup; - -/** - * @brief Driver configuration structure. + * @brief Type of a DMA channel pointer choice. */ -typedef struct { - /** - * @brief ADC DIFSEL register initialization data. - */ - uint32_t difsel; -} 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_reference_t thread; -#endif -#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) - /** - * @brief Mutex protecting the peripheral. - */ - mutex_t mutex; -#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 master ADCx registers block. - */ - ADC_TypeDef *adcm; -#if STM32_ADC_DUAL_MODE || defined(__DOXYGEN__) - /** - * @brief Pointer to the slave ADCx registers block. - */ - ADC_TypeDef *adcs; -#endif /* STM32_ADC_DUAL_MODE */ - /** - * @brief Pointer to the common ADCx_y registers block. - */ - ADC_Common_TypeDef *adcc; - /** - * @brief Union of the DMA data streams. - */ - union { +typedef union { #if defined(STM32_ADC_DMA_REQUIRED) || defined(__DOXYGEN__) /** * @brief DMA stream. @@ -629,17 +444,101 @@ struct ADCDriver { */ const stm32_bdma_stream_t *bdma; #endif - } data; - /** - * @brief DMA mode bit mask. - */ - uint32_t dmamode; -}; +} adc_ldd_dma_reference_t; /*===========================================================================*/ /* Driver macros. */ /*===========================================================================*/ +/** + * @brief Low level fields of the ADC driver structure. + */ +#if (STM32_ADC_DUAL_MODE == TRUE) || defined(__DOXYGEN__) +#define adc_lld_driver_fields \ + /* Pointer to the master ADCx registers block.*/ \ + ADC_TypeDef *adcm; \ + /* Pointer to the slave ADCx registers block.*/ \ + ADC_TypeDef *adcs; \ + /* Pointer to the common ADCx_y registers block.*/ \ + ADC_Common_TypeDef *adcc; \ + /* Pointer to associated DMA channel.*/ \ + adc_ldd_dma_reference_t data; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode +#else +#define adc_lld_driver_fields \ + /* Pointer to the master ADCx registers block.*/ \ + ADC_TypeDef *adcm; \ + /* Pointer to the slave ADCx registers block.*/ \ + ADC_Common_TypeDef *adcc; \ + /* Pointer to associated DMA channel.*/ \ + adc_ldd_dma_reference_t data; \ + /* DMA mode bit mask.*/ \ + uint32_t dmamode +#endif + +/** + * @brief Low level fields of the ADC configuration structure. + */ +#define adc_lld_config_fields \ + /* ADC DIFSEL register initialization data.*/ \ + uint32_t difsel + +#if (STM32_ADC_DUAL_MODE == TRUE) || defined(__DOXYGEN__) +#define adc_lld_configuration_group_fields \ + /* ADC CFGR register initialization data. \ + NOTE: The bits DMAEN and DMACFG are enforced internally \ + to the driver, keep them to zero. \ + NOTE: The bits @p ADC_CFGR_CONT or @p ADC_CFGR_DISCEN must be \ + specified in continuous mode or if the buffer depth is \ + greater than one.*/ \ + uint32_t cfgr; \ + /* ADC CFGR2 register initialization data. \ + NOTE: Put this field to zero if not using oversampling.*/ \ + uint32_t cfgr2; \ + /* ADC CCR register initialization data*/ \ + uint32_t ccr; \ + /* ADC PCSEL register initialization data.*/ \ + uint32_t pcsel; \ + /* ADC LTR1 register initialization data.*/ \ + uint32_t ltr1; \ + /* ADC HTR1 register initialization data.*/ \ + uint32_t htr1; \ + /* ADC LTR2 register initialization data.*/ \ + uint32_t ltr2; \ + /* ADC HTR2 register initialization data.*/ \ + uint32_t htr2; \ + /* ADC LTR3 register initialization data.*/ \ + uint32_t ltr3; \ + /* ADC HTR3 register initialization data.*/ \ + uint32_t htr3; \ + /* ADC SMPRx registers initialization data.*/ \ + uint32_t smpr[2]; \ + /* ADC SQRx register initialization data.*/ \ + uint32_t sqr[4]; \ + /* Slave ADC SMPRx registers initialization data. \ + NOTE: This field is only present in dual mode.*/ \ + uint32_t ssmpr[2]; \ + /* Slave ADC SQRx register initialization data. \ + NOTE: This field is only present in dual mode.*/ \ + uint32_t ssqr[4] +#else /* STM32_ADC_DUAL_MODE == FALSE */ +#define adc_lld_configuration_group_fields \ + uint32_t cfgr; \ + uint32_t cfgr2; \ + uint32_t ccr; \ + uint32_t pcsel; \ + uint32_t difsel; \ + uint32_t ltr1; \ + uint32_t htr1; \ + uint32_t ltr2; \ + uint32_t htr2; \ + uint32_t ltr3; \ + uint32_t htr3; \ + uint32_t smpr[2]; \ + uint32_t sqr[4] +#endif /* STM32_ADC_DUAL_MODE == FALSE */ + /** * @name Sequences building helper macros * @{ -- cgit v1.2.3